Merged revisions 114195 via svnmerge from
[asterisk/asterisk.git] / res / res_agi.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 1999 - 2006, Digium, Inc.
5  *
6  * Mark Spencer <markster@digium.com>
7  *
8  * See http://www.asterisk.org for more information about
9  * the Asterisk project. Please do not directly contact
10  * any of the maintainers of this project for assistance;
11  * the project provides a web site, mailing lists and IRC
12  * channels for your use.
13  *
14  * This program is free software, distributed under the terms of
15  * the GNU General Public License Version 2. See the LICENSE file
16  * at the top of the source tree.
17  */
18
19 /*! \file
20  *
21  * \brief AGI - the Asterisk Gateway Interface
22  *
23  * \author Mark Spencer <markster@digium.com> 
24  */
25
26 #include "asterisk.h"
27
28 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
29
30 #include <math.h>
31 #include <signal.h>
32 #include <sys/time.h>
33 #include <sys/wait.h>
34 #include <sys/stat.h>
35 #include <pthread.h>
36
37 #include "asterisk/paths.h"     /* use many ast_config_AST_*_DIR */
38 #include "asterisk/network.h"
39 #include "asterisk/file.h"
40 #include "asterisk/channel.h"
41 #include "asterisk/pbx.h"
42 #include "asterisk/module.h"
43 #include "asterisk/astdb.h"
44 #include "asterisk/callerid.h"
45 #include "asterisk/cli.h"
46 #include "asterisk/image.h"
47 #include "asterisk/say.h"
48 #include "asterisk/app.h"
49 #include "asterisk/dsp.h"
50 #include "asterisk/musiconhold.h"
51 #include "asterisk/utils.h"
52 #include "asterisk/lock.h"
53 #include "asterisk/strings.h"
54 #include "asterisk/agi.h"
55 #include "asterisk/manager.h"
56 #include "asterisk/ast_version.h"
57 #include "asterisk/speech.h"
58 #include "asterisk/manager.h"
59
60 #define MAX_ARGS 128
61 #define AGI_NANDFS_RETRY 3
62 #define AGI_BUF_LEN 2048
63
64 static char *app = "AGI";
65
66 static char *eapp = "EAGI";
67
68 static char *deadapp = "DeadAGI";
69
70 static char *synopsis = "Executes an AGI compliant application";
71 static char *esynopsis = "Executes an EAGI compliant application";
72 static char *deadsynopsis = "Executes AGI on a hungup channel";
73
74 static char *descrip =
75 "  [E|Dead]AGI(command,args): Executes an Asterisk Gateway Interface compliant\n"
76 "program on a channel. AGI allows Asterisk to launch external programs\n"
77 "written in any language to control a telephony channel, play audio,\n"
78 "read DTMF digits, etc. by communicating with the AGI protocol on stdin\n"
79 "and stdout.\n"
80 "  This channel will stop dialplan execution on hangup inside of this\n"
81 "application, except when using DeadAGI.  Otherwise, dialplan execution\n"
82 "will continue normally.\n"
83 "  A locally executed AGI script will receive SIGHUP on hangup from the channel\n"
84 "except when using DeadAGI. This can be disabled by setting the AGISIGHUP channel\n"
85 "variable to \"no\" before executing the AGI application.\n"
86 "  Using 'EAGI' provides enhanced AGI, with incoming audio available out of band\n"
87 "on file descriptor 3\n\n"
88 "  Use the CLI command 'agi show' to list available agi commands\n"
89 "  This application sets the following channel variable upon completion:\n"
90 "     AGISTATUS      The status of the attempt to the run the AGI script\n"
91 "                    text string, one of SUCCESS | FAILURE | NOTFOUND | HANGUP\n";
92
93 static int agidebug = 0;
94
95 #define TONE_BLOCK_SIZE 200
96
97 /* Max time to connect to an AGI remote host */
98 #define MAX_AGI_CONNECT 2000
99
100 #define AGI_PORT 4573
101
102 enum agi_result {
103         AGI_RESULT_SUCCESS,
104         AGI_RESULT_SUCCESS_FAST,
105         AGI_RESULT_SUCCESS_ASYNC,
106         AGI_RESULT_FAILURE,
107         AGI_RESULT_NOTFOUND,
108         AGI_RESULT_HANGUP,
109 };
110
111 static agi_command *find_command(char *cmds[], int exact);
112
113 AST_THREADSTORAGE(agi_buf);
114 #define AGI_BUF_INITSIZE 256
115
116 int ast_agi_fdprintf(struct ast_channel *chan, int fd, char *fmt, ...)
117 {
118         int res = 0;
119         va_list ap;
120         struct ast_str *buf;
121
122         if (!(buf = ast_str_thread_get(&agi_buf, AGI_BUF_INITSIZE)))
123                 return -1;
124
125         va_start(ap, fmt);
126         res = ast_str_set_va(&buf, 0, fmt, ap);
127         va_end(ap);
128
129         if (res == -1) {
130                 ast_log(LOG_ERROR, "Out of memory\n");
131                 return -1;
132         }
133
134         if (agidebug) {
135                 if (chan) {
136                         ast_verbose("<%s>AGI Tx >> %s", chan->name, buf->str);
137                 } else {
138                         ast_verbose("AGI Tx >> %s", buf->str);
139                 }
140         }
141
142         return ast_carefulwrite(fd, buf->str, buf->used, 100);
143 }
144
145 /* linked list of AGI commands ready to be executed by Async AGI */
146 struct agi_cmd {
147         char *cmd_buffer;
148         char *cmd_id;
149         AST_LIST_ENTRY(agi_cmd) entry;
150 };
151
152 static void free_agi_cmd(struct agi_cmd *cmd)
153 {
154         ast_free(cmd->cmd_buffer);
155         ast_free(cmd->cmd_id);
156         ast_free(cmd);
157 }
158
159 /* AGI datastore destructor */
160 static void agi_destroy_commands_cb(void *data)
161 {
162         struct agi_cmd *cmd;
163         AST_LIST_HEAD(, agi_cmd) *chan_cmds = data;
164         AST_LIST_LOCK(chan_cmds);
165         while ( (cmd = AST_LIST_REMOVE_HEAD(chan_cmds, entry)) ) { 
166                 free_agi_cmd(cmd);
167         } 
168         AST_LIST_UNLOCK(chan_cmds);
169         AST_LIST_HEAD_DESTROY(chan_cmds);
170         ast_free(chan_cmds);
171 }
172
173 /* channel datastore to keep the queue of AGI commands in the channel */
174 static const struct ast_datastore_info agi_commands_datastore_info = {
175         .type = "AsyncAGI",
176         .destroy = agi_destroy_commands_cb
177 };
178
179 static const char mandescr_asyncagi[] =
180 "Description: Add an AGI command to the execute queue of the channel in Async AGI\n"
181 "Variables:\n"
182 "  *Channel: Channel that is currently in Async AGI\n"
183 "  *Command: Application to execute\n"
184 "   CommandID: comand id. This will be sent back in CommandID header of AsyncAGI exec event notification\n"
185 "\n";
186
187 static struct agi_cmd *get_agi_cmd(struct ast_channel *chan)
188 {
189         struct ast_datastore *store;
190         struct agi_cmd *cmd;
191         AST_LIST_HEAD(, agi_cmd) *agi_commands;
192
193         ast_channel_lock(chan);
194         store = ast_channel_datastore_find(chan, &agi_commands_datastore_info, NULL);
195         ast_channel_unlock(chan);
196         if (!store) {
197                 ast_log(LOG_ERROR, "Hu? datastore disappeared at Async AGI on Channel %s!\n", chan->name);
198                 return NULL;
199         }
200         agi_commands = store->data;
201         AST_LIST_LOCK(agi_commands);
202         cmd = AST_LIST_REMOVE_HEAD(agi_commands, entry);
203         AST_LIST_UNLOCK(agi_commands);
204         return cmd;
205 }
206
207 /* channel is locked when calling this one either from the CLI or manager thread */
208 static int add_agi_cmd(struct ast_channel *chan, const char *cmd_buff, const char *cmd_id)
209 {
210         struct ast_datastore *store;
211         struct agi_cmd *cmd;
212         AST_LIST_HEAD(, agi_cmd) *agi_commands;
213
214         store = ast_channel_datastore_find(chan, &agi_commands_datastore_info, NULL);
215         if (!store) {
216                 ast_log(LOG_WARNING, "Channel %s is not at Async AGI.\n", chan->name);
217                 return -1;
218         }
219         agi_commands = store->data;
220         cmd = ast_calloc(1, sizeof(*cmd));
221         if (!cmd) {
222                 return -1;
223         }
224         cmd->cmd_buffer = ast_strdup(cmd_buff);
225         if (!cmd->cmd_buffer) {
226                 ast_free(cmd);
227                 return -1;
228         }
229         cmd->cmd_id = ast_strdup(cmd_id);
230         if (!cmd->cmd_id) {
231                 ast_free(cmd->cmd_buffer);
232                 ast_free(cmd);
233                 return -1;
234         }
235         AST_LIST_LOCK(agi_commands);
236         AST_LIST_INSERT_TAIL(agi_commands, cmd, entry);
237         AST_LIST_UNLOCK(agi_commands);
238         return 0;
239 }
240
241 static int add_to_agi(struct ast_channel *chan)
242 {
243         struct ast_datastore *datastore;
244         AST_LIST_HEAD(, agi_cmd) *agi_cmds_list;
245
246         /* check if already on AGI */
247         ast_channel_lock(chan);
248         datastore = ast_channel_datastore_find(chan, &agi_commands_datastore_info, NULL);
249         ast_channel_unlock(chan);
250         if (datastore) {
251                 /* we already have an AGI datastore, let's just 
252                    return success */
253                 return 0;
254         }
255
256         /* the channel has never been on Async AGI,
257            let's allocate it's datastore */
258         datastore = ast_channel_datastore_alloc(&agi_commands_datastore_info, "AGI");
259         if (!datastore) {
260                 return -1;
261         }
262         agi_cmds_list = ast_calloc(1, sizeof(*agi_cmds_list));
263         if (!agi_cmds_list) {
264                 ast_log(LOG_ERROR, "Unable to allocate Async AGI commands list.\n");
265                 ast_channel_datastore_free(datastore);
266                 return -1;
267         }
268         datastore->data = agi_cmds_list;
269         AST_LIST_HEAD_INIT(agi_cmds_list);
270         ast_channel_lock(chan);
271         ast_channel_datastore_add(chan, datastore);
272         ast_channel_unlock(chan);
273         return 0;
274 }
275
276 /*!
277  * \brief CLI command to add applications to execute in Async AGI 
278  * \param e
279  * \param cmd 
280  * \param a
281  *
282  * \retval CLI_SUCCESS on success
283  * \retval NULL when init or tab completion is used
284 */
285 static char *handle_cli_agi_add_cmd(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
286 {
287         struct ast_channel *chan;
288         switch (cmd) {
289         case CLI_INIT:
290                 e->command = "agi exec";
291                 e->usage = "Usage: agi exec <channel name> <app and arguments> [id]\n"
292                            "       Add AGI command to the execute queue of the specified channel in Async AGI\n";
293                 return NULL;
294         case CLI_GENERATE:
295                 if (a->pos == 2)
296                         return ast_complete_channels(a->line, a->word, a->pos, a->n, 2);
297                 return NULL;
298         }
299
300         if (a->argc < 4)
301                 return CLI_SHOWUSAGE;
302         chan = ast_get_channel_by_name_locked(a->argv[2]);
303         if (!chan) {
304                 ast_log(LOG_WARNING, "Channel %s does not exists or cannot lock it\n", a->argv[2]);
305                 return CLI_FAILURE;
306         }
307         if (add_agi_cmd(chan, a->argv[3], (a->argc > 4 ? a->argv[4] : ""))) {
308                 ast_log(LOG_WARNING, "failed to add AGI command to queue of channel %s\n", chan->name);
309                 ast_channel_unlock(chan);
310                 return CLI_FAILURE;
311         }
312         ast_log(LOG_DEBUG, "Added AGI command to channel %s queue\n", chan->name);
313         ast_channel_unlock(chan);
314         return CLI_SUCCESS;
315 }
316
317 /*!
318  * \brief Add a new command to execute by the Async AGI application
319  * \param s
320  * \param m
321  *
322  * It will append the application to the specified channel's queue
323  * if the channel is not inside Async AGI application it will return an error
324  * \retval 0 on success or incorrect use
325  * \retval 1 on failure to add the command ( most likely because the channel 
326  * is not in Async AGI loop )
327 */
328 static int action_add_agi_cmd(struct mansession *s, const struct message *m)
329 {
330         const char *channel = astman_get_header(m, "Channel");
331         const char *cmdbuff = astman_get_header(m, "Command");
332         const char *cmdid   = astman_get_header(m, "CommandID");
333         struct ast_channel *chan;
334         char buf[256];
335         if (ast_strlen_zero(channel) || ast_strlen_zero(cmdbuff)) {
336                 astman_send_error(s, m, "Both, Channel and Command are *required*");
337                 return 0;
338         }
339         chan = ast_get_channel_by_name_locked(channel);
340         if (!chan) {
341                 snprintf(buf, sizeof(buf), "Channel %s does not exists or cannot get its lock", channel);
342                 astman_send_error(s, m, buf);
343                 return 0;
344         }
345         if (add_agi_cmd(chan, cmdbuff, cmdid)) {
346                 snprintf(buf, sizeof(buf), "Failed to add AGI command to channel %s queue", chan->name);
347                 astman_send_error(s, m, buf);
348                 ast_channel_unlock(chan);
349                 return 0;
350         }
351         astman_send_ack(s, m, "Added AGI command to queue");
352         ast_channel_unlock(chan);
353         return 0;
354 }
355
356 static int agi_handle_command(struct ast_channel *chan, AGI *agi, char *buf, int dead);
357 static void setup_env(struct ast_channel *chan, char *request, int fd, int enhanced, int argc, char *argv[]);
358 static enum agi_result launch_asyncagi(struct ast_channel *chan, char *argv[], int *efd)
359 {
360 /* This buffer sizes might cause truncation if the AGI command writes more data
361    than AGI_BUF_SIZE as result. But let's be serious, is there an AGI command 
362    that writes a response larger than 1024 bytes?, I don't think so, most of 
363    them are just result=blah stuff. However probably if GET VARIABLE is called 
364    and the variable has large amount of data, that could be a problem. We could 
365    make this buffers dynamic, but let's leave that as a second step.
366
367    AMI_BUF_SIZE is twice AGI_BUF_SIZE just for the sake of choosing a safe 
368    number. Some characters of AGI buf will be url encoded to be sent to manager 
369    clients.  An URL encoded character will take 3 bytes, but again, to cause 
370    truncation more than about 70% of the AGI buffer should be URL encoded for 
371    that to happen.  Not likely at all. 
372
373    On the other hand. I wonder if read() could eventually return less data than 
374    the amount already available in the pipe? If so, how to deal with that?  
375    So far, my tests on Linux have not had any problems.
376  */
377 #define AGI_BUF_SIZE 1024
378 #define AMI_BUF_SIZE 2048
379         struct ast_frame *f;
380         struct agi_cmd *cmd;
381         int res, fds[2];
382         int timeout = 100; 
383         char agi_buffer[AGI_BUF_SIZE + 1];
384         char ami_buffer[AMI_BUF_SIZE];
385         enum agi_result returnstatus = AGI_RESULT_SUCCESS_ASYNC;
386         AGI async_agi;
387
388         if (efd) {
389                 ast_log(LOG_WARNING, "Async AGI does not support Enhanced AGI yet\n");
390                 return AGI_RESULT_FAILURE;
391         }
392
393         /* add AsyncAGI datastore to the channel */
394         if (add_to_agi(chan)) {
395                 ast_log(LOG_ERROR, "failed to start Async AGI on channel %s\n", chan->name);
396                 return AGI_RESULT_FAILURE;
397         }       
398
399         /* this pipe allows us to create a "fake" AGI struct to use 
400            the AGI commands */
401         res = pipe(fds);
402         if (res) {
403                 ast_log(LOG_ERROR, "failed to create Async AGI pipe\n");
404                 /* intentionally do not remove datastore, added with 
405                    add_to_agi(), from channel. It will be removed when 
406                    the channel is hung up anyways */
407                 return AGI_RESULT_FAILURE;
408         }
409
410         /* handlers will get the pipe write fd and we read the AGI responses 
411            from the pipe read fd */
412         async_agi.fd = fds[1]; 
413         async_agi.ctrl = fds[1];
414         async_agi.audio = -1; /* no audio support */
415         async_agi.fast = 0;
416
417         /* notify possible manager users of a new channel ready to 
418            receive commands */  
419         setup_env(chan, "async", fds[1], 0, 0, NULL);
420         /* read the environment */
421         res = read(fds[0], agi_buffer, AGI_BUF_SIZE);
422         if (!res) {
423                 ast_log(LOG_ERROR, "failed to read from Async AGI pipe on channel %s\n", chan->name);
424                 returnstatus = AGI_RESULT_FAILURE;
425                 goto quit;
426         }
427         agi_buffer[res] = '\0';
428         /* encode it and send it thru the manager so whoever is going to take 
429            care of AGI commands on this channel can decide which AGI commands 
430            to execute based on the setup info */
431         ast_uri_encode(agi_buffer, ami_buffer, AMI_BUF_SIZE, 1);
432         manager_event(EVENT_FLAG_CALL, "AsyncAGI", "SubEvent: Start\r\nChannel: %s\r\nEnv: %s\r\n", chan->name, ami_buffer); 
433         while (1) {
434                 /* bail out if we need to hangup */
435                 if (ast_check_hangup(chan)) {
436                         ast_log(LOG_DEBUG, "ast_check_hangup returned true on chan %s\n", chan->name);
437                         break;
438                 }
439                 /* retrieve a command 
440                    (commands are added via the manager or the cli threads) */
441                 cmd = get_agi_cmd(chan);
442                 if (cmd) {
443                         /* OK, we have a command, let's call the 
444                            command handler. */
445                         res = agi_handle_command(chan, &async_agi, cmd->cmd_buffer, 0);
446                         if ((res < 0) || (res == AST_PBX_KEEPALIVE)) {
447                                 free_agi_cmd(cmd);
448                                 break;
449                         }
450                         /* the command handler must have written to our fake 
451                            AGI struct fd (the pipe), let's read the response */
452                         res = read(fds[0], agi_buffer, AGI_BUF_SIZE);
453                         if (!res) {
454                                 returnstatus = AGI_RESULT_FAILURE;
455                                 ast_log(LOG_ERROR, "failed to read from AsyncAGI pipe on channel %s\n", chan->name);
456                                 free_agi_cmd(cmd);
457                                 break;
458                         }
459                         /* we have a response, let's send the response thru the
460                            manager. Include the CommandID if it was specified 
461                            when the command was added */
462                         agi_buffer[res] = '\0';
463                         ast_uri_encode(agi_buffer, ami_buffer, AMI_BUF_SIZE, 1);
464                         if (ast_strlen_zero(cmd->cmd_id))
465                                 manager_event(EVENT_FLAG_CALL, "AsyncAGI", "SubEvent: Exec\r\nChannel: %s\r\nResult: %s\r\n", chan->name, ami_buffer);
466                         else
467                                 manager_event(EVENT_FLAG_CALL, "AsyncAGI", "SubEvent: Exec\r\nChannel: %s\r\nCommandID: %s\r\nResult: %s\r\n", chan->name, cmd->cmd_id, ami_buffer);
468                         free_agi_cmd(cmd);
469                 } else {
470                         /* no command so far, wait a bit for a frame to read */
471                         res = ast_waitfor(chan, timeout);
472                         if (res < 0) {
473                                 ast_log(LOG_DEBUG, "ast_waitfor returned <= 0 on chan %s\n", chan->name);
474                                 break;
475                         }
476                         if (res == 0)
477                                 continue;
478                         f = ast_read(chan);
479                         if (!f) {
480                                 ast_log(LOG_DEBUG, "No frame read on channel %s, going out ...\n", chan->name);
481                                 returnstatus = AGI_RESULT_HANGUP;
482                                 break;
483                         }
484                         /* is there any other frame we should care about 
485                            besides AST_CONTROL_HANGUP? */
486                         if (f->frametype == AST_FRAME_CONTROL && f->subclass == AST_CONTROL_HANGUP) {
487                                 ast_log(LOG_DEBUG, "Got HANGUP frame on channel %s, going out ...\n", chan->name);
488                                 ast_frfree(f);
489                                 break;
490                         }
491                         ast_frfree(f);
492                 }
493         }
494 quit:
495         /* notify manager users this channel cannot be 
496            controlled anymore by Async AGI */
497         manager_event(EVENT_FLAG_CALL, "AsyncAGI", "SubEvent: End\r\nChannel: %s\r\n", chan->name);
498
499         /* close the pipe */
500         close(fds[0]);
501         close(fds[1]);
502
503         /* intentionally don't get rid of the datastore. So commands can be 
504            still in the queue in case AsyncAGI gets called again.
505            Datastore destructor will be called on channel destroy anyway  */
506
507         return returnstatus;
508
509 #undef AGI_BUF_SIZE 
510 #undef AMI_BUF_SIZE 
511 }
512
513 /* launch_netscript: The fastagi handler.
514         FastAGI defaults to port 4573 */
515 static enum agi_result launch_netscript(char *agiurl, char *argv[], int *fds, int *efd, int *opid)
516 {
517         int s, flags, res, port = AGI_PORT;
518         struct pollfd pfds[1];
519         char *host, *c, *script = "";
520         struct sockaddr_in sin;
521         struct hostent *hp;
522         struct ast_hostent ahp;
523
524         /* agiusl is "agi://host.domain[:port][/script/name]" */
525         host = ast_strdupa(agiurl + 6); /* Remove agi:// */
526         /* Strip off any script name */
527         if ((c = strchr(host, '/'))) {
528                 *c = '\0';
529                 c++;
530                 script = c;
531         }
532         if ((c = strchr(host, ':'))) {
533                 *c = '\0';
534                 c++;
535                 port = atoi(c);
536         }
537         if (efd) {
538                 ast_log(LOG_WARNING, "AGI URI's don't support Enhanced AGI yet\n");
539                 return -1;
540         }
541         if (!(hp = ast_gethostbyname(host, &ahp))) {
542                 ast_log(LOG_WARNING, "Unable to locate host '%s'\n", host);
543                 return -1;
544         }
545         if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
546                 ast_log(LOG_WARNING, "Unable to create socket: %s\n", strerror(errno));
547                 return -1;
548         }
549         if ((flags = fcntl(s, F_GETFL)) < 0) {
550                 ast_log(LOG_WARNING, "Fcntl(F_GETFL) failed: %s\n", strerror(errno));
551                 close(s);
552                 return -1;
553         }
554         if (fcntl(s, F_SETFL, flags | O_NONBLOCK) < 0) {
555                 ast_log(LOG_WARNING, "Fnctl(F_SETFL) failed: %s\n", strerror(errno));
556                 close(s);
557                 return -1;
558         }
559         memset(&sin, 0, sizeof(sin));
560         sin.sin_family = AF_INET;
561         sin.sin_port = htons(port);
562         memcpy(&sin.sin_addr, hp->h_addr, sizeof(sin.sin_addr));
563         if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) && (errno != EINPROGRESS)) {
564                 ast_log(LOG_WARNING, "Connect failed with unexpected error: %s\n", strerror(errno));
565                 close(s);
566                 return AGI_RESULT_FAILURE;
567         }
568
569         pfds[0].fd = s;
570         pfds[0].events = POLLOUT;
571         while ((res = poll(pfds, 1, MAX_AGI_CONNECT)) != 1) {
572                 if (errno != EINTR) {
573                         if (!res) {
574                                 ast_log(LOG_WARNING, "FastAGI connection to '%s' timed out after MAX_AGI_CONNECT (%d) milliseconds.\n",
575                                         agiurl, MAX_AGI_CONNECT);
576                         } else
577                                 ast_log(LOG_WARNING, "Connect to '%s' failed: %s\n", agiurl, strerror(errno));
578                         close(s);
579                         return AGI_RESULT_FAILURE;
580                 }
581         }
582
583         if (ast_agi_fdprintf(NULL, s, "agi_network: yes\n") < 0) {
584                 if (errno != EINTR) {
585                         ast_log(LOG_WARNING, "Connect to '%s' failed: %s\n", agiurl, strerror(errno));
586                         close(s);
587                         return AGI_RESULT_FAILURE;
588                 }
589         }
590
591         /* If we have a script parameter, relay it to the fastagi server */
592         /* Script parameters take the form of: AGI(agi://my.example.com/?extension=${EXTEN}) */
593         if (!ast_strlen_zero(script))
594                 ast_agi_fdprintf(NULL, s, "agi_network_script: %s\n", script);
595
596         ast_debug(4, "Wow, connected!\n");
597         fds[0] = s;
598         fds[1] = s;
599         *opid = -1;
600         return AGI_RESULT_SUCCESS_FAST;
601 }
602
603 static enum agi_result launch_script(struct ast_channel *chan, char *script, char *argv[], int *fds, int *efd, int *opid)
604 {
605         char tmp[256];
606         int pid, toast[2], fromast[2], audio[2], res;
607         struct stat st;
608
609         if (!strncasecmp(script, "agi://", 6))
610                 return launch_netscript(script, argv, fds, efd, opid);
611         if (!strncasecmp(script, "agi:async", sizeof("agi:async")-1))
612                 return launch_asyncagi(chan, argv, efd);
613         
614         if (script[0] != '/') {
615                 snprintf(tmp, sizeof(tmp), "%s/%s", ast_config_AST_AGI_DIR, script);
616                 script = tmp;
617         }
618
619         /* Before even trying let's see if the file actually exists */
620         if (stat(script, &st)) {
621                 ast_log(LOG_WARNING, "Failed to execute '%s': File does not exist.\n", script);
622                 return AGI_RESULT_NOTFOUND;
623         }
624
625         if (pipe(toast)) {
626                 ast_log(LOG_WARNING, "Unable to create toast pipe: %s\n",strerror(errno));
627                 return AGI_RESULT_FAILURE;
628         }
629         if (pipe(fromast)) {
630                 ast_log(LOG_WARNING, "unable to create fromast pipe: %s\n", strerror(errno));
631                 close(toast[0]);
632                 close(toast[1]);
633                 return AGI_RESULT_FAILURE;
634         }
635         if (efd) {
636                 if (pipe(audio)) {
637                         ast_log(LOG_WARNING, "unable to create audio pipe: %s\n", strerror(errno));
638                         close(fromast[0]);
639                         close(fromast[1]);
640                         close(toast[0]);
641                         close(toast[1]);
642                         return AGI_RESULT_FAILURE;
643                 }
644                 res = fcntl(audio[1], F_GETFL);
645                 if (res > -1) 
646                         res = fcntl(audio[1], F_SETFL, res | O_NONBLOCK);
647                 if (res < 0) {
648                         ast_log(LOG_WARNING, "unable to set audio pipe parameters: %s\n", strerror(errno));
649                         close(fromast[0]);
650                         close(fromast[1]);
651                         close(toast[0]);
652                         close(toast[1]);
653                         close(audio[0]);
654                         close(audio[1]);
655                         return AGI_RESULT_FAILURE;
656                 }
657         }
658
659         if ((pid = ast_safe_fork(1)) < 0) {
660                 ast_log(LOG_WARNING, "Failed to fork(): %s\n", strerror(errno));
661                 return AGI_RESULT_FAILURE;
662         }
663         if (!pid) {
664                 /* Pass paths to AGI via environmental variables */
665                 setenv("AST_CONFIG_DIR", ast_config_AST_CONFIG_DIR, 1);
666                 setenv("AST_CONFIG_FILE", ast_config_AST_CONFIG_FILE, 1);
667                 setenv("AST_MODULE_DIR", ast_config_AST_MODULE_DIR, 1);
668                 setenv("AST_SPOOL_DIR", ast_config_AST_SPOOL_DIR, 1);
669                 setenv("AST_MONITOR_DIR", ast_config_AST_MONITOR_DIR, 1);
670                 setenv("AST_VAR_DIR", ast_config_AST_VAR_DIR, 1);
671                 setenv("AST_DATA_DIR", ast_config_AST_DATA_DIR, 1);
672                 setenv("AST_LOG_DIR", ast_config_AST_LOG_DIR, 1);
673                 setenv("AST_AGI_DIR", ast_config_AST_AGI_DIR, 1);
674                 setenv("AST_KEY_DIR", ast_config_AST_KEY_DIR, 1);
675                 setenv("AST_RUN_DIR", ast_config_AST_RUN_DIR, 1);
676
677                 /* Don't run AGI scripts with realtime priority -- it causes audio stutter */
678                 ast_set_priority(0);
679
680                 /* Redirect stdin and out, provide enhanced audio channel if desired */
681                 dup2(fromast[0], STDIN_FILENO);
682                 dup2(toast[1], STDOUT_FILENO);
683                 if (efd)
684                         dup2(audio[0], STDERR_FILENO + 1);
685                 else
686                         close(STDERR_FILENO + 1);
687
688                 /* Close everything but stdin/out/error */
689                 ast_close_fds_above_n(STDERR_FILENO + 1);
690
691                 /* Execute script */
692                 /* XXX argv should be deprecated in favor of passing agi_argX paramaters */
693                 execv(script, argv);
694                 /* Can't use ast_log since FD's are closed */
695                 ast_child_verbose(1, "Failed to execute '%s': %s", script, strerror(errno));
696                 /* Special case to set status of AGI to failure */
697                 fprintf(stdout, "failure\n");
698                 fflush(stdout);
699                 _exit(1);
700         }
701         ast_verb(3, "Launched AGI Script %s\n", script);
702         fds[0] = toast[0];
703         fds[1] = fromast[1];
704         if (efd)
705                 *efd = audio[1];
706         /* close what we're not using in the parent */
707         close(toast[1]);
708         close(fromast[0]);
709
710         if (efd)
711                 close(audio[0]);
712
713         *opid = pid;
714         return AGI_RESULT_SUCCESS;
715 }
716
717 static void setup_env(struct ast_channel *chan, char *request, int fd, int enhanced, int argc, char *argv[])
718 {
719         int count;
720
721         /* Print initial environment, with agi_request always being the first
722            thing */
723         ast_agi_fdprintf(chan, fd, "agi_request: %s\n", request);
724         ast_agi_fdprintf(chan, fd, "agi_channel: %s\n", chan->name);
725         ast_agi_fdprintf(chan, fd, "agi_language: %s\n", chan->language);
726         ast_agi_fdprintf(chan, fd, "agi_type: %s\n", chan->tech->type);
727         ast_agi_fdprintf(chan, fd, "agi_uniqueid: %s\n", chan->uniqueid);
728         ast_agi_fdprintf(chan, fd, "agi_version: %s\n", ast_get_version());
729
730         /* ANI/DNIS */
731         ast_agi_fdprintf(chan, fd, "agi_callerid: %s\n", S_OR(chan->cid.cid_num, "unknown"));
732         ast_agi_fdprintf(chan, fd, "agi_calleridname: %s\n", S_OR(chan->cid.cid_name, "unknown"));
733         ast_agi_fdprintf(chan, fd, "agi_callingpres: %d\n", chan->cid.cid_pres);
734         ast_agi_fdprintf(chan, fd, "agi_callingani2: %d\n", chan->cid.cid_ani2);
735         ast_agi_fdprintf(chan, fd, "agi_callington: %d\n", chan->cid.cid_ton);
736         ast_agi_fdprintf(chan, fd, "agi_callingtns: %d\n", chan->cid.cid_tns);
737         ast_agi_fdprintf(chan, fd, "agi_dnid: %s\n", S_OR(chan->cid.cid_dnid, "unknown"));
738         ast_agi_fdprintf(chan, fd, "agi_rdnis: %s\n", S_OR(chan->cid.cid_rdnis, "unknown"));
739
740         /* Context information */
741         ast_agi_fdprintf(chan, fd, "agi_context: %s\n", chan->context);
742         ast_agi_fdprintf(chan, fd, "agi_extension: %s\n", chan->exten);
743         ast_agi_fdprintf(chan, fd, "agi_priority: %d\n", chan->priority);
744         ast_agi_fdprintf(chan, fd, "agi_enhanced: %s\n", enhanced ? "1.0" : "0.0");
745
746         /* User information */
747         ast_agi_fdprintf(chan, fd, "agi_accountcode: %s\n", chan->accountcode ? chan->accountcode : "");
748         ast_agi_fdprintf(chan, fd, "agi_threadid: %ld\n", (long)pthread_self());
749
750         /* Send any parameters to the fastagi server that have been passed via the agi application */
751         /* Agi application paramaters take the form of: AGI(/path/to/example/script|${EXTEN}) */
752         for(count = 1; count < argc; count++)
753                 ast_agi_fdprintf(chan, fd, "agi_arg_%d: %s\n", count, argv[count]);
754
755         /* End with empty return */
756         ast_agi_fdprintf(chan, fd, "\n");
757 }
758
759 static int handle_answer(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
760 {
761         int res = 0;
762
763         /* Answer the channel */
764         if (chan->_state != AST_STATE_UP)
765                 res = ast_answer(chan);
766
767         ast_agi_fdprintf(chan, agi->fd, "200 result=%d\n", res);
768         return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
769 }
770
771 static int handle_waitfordigit(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
772 {
773         int res, to;
774
775         if (argc != 4)
776                 return RESULT_SHOWUSAGE;
777         if (sscanf(argv[3], "%d", &to) != 1)
778                 return RESULT_SHOWUSAGE;
779         res = ast_waitfordigit_full(chan, to, agi->audio, agi->ctrl);
780         ast_agi_fdprintf(chan, agi->fd, "200 result=%d\n", res);
781         return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
782 }
783
784 static int handle_sendtext(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
785 {
786         int res;
787
788         if (argc != 3)
789                 return RESULT_SHOWUSAGE;
790
791         /* At the moment, the parser (perhaps broken) returns with
792            the last argument PLUS the newline at the end of the input
793            buffer. This probably needs to be fixed, but I wont do that
794            because other stuff may break as a result. The right way
795            would probably be to strip off the trailing newline before
796            parsing, then here, add a newline at the end of the string
797            before sending it to ast_sendtext --DUDE */
798         res = ast_sendtext(chan, argv[2]);
799         ast_agi_fdprintf(chan, agi->fd, "200 result=%d\n", res);
800         return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
801 }
802
803 static int handle_recvchar(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
804 {
805         int res;
806
807         if (argc != 3)
808                 return RESULT_SHOWUSAGE;
809
810         res = ast_recvchar(chan,atoi(argv[2]));
811         if (res == 0) {
812                 ast_agi_fdprintf(chan, agi->fd, "200 result=%d (timeout)\n", res);
813                 return RESULT_SUCCESS;
814         }
815         if (res > 0) {
816                 ast_agi_fdprintf(chan, agi->fd, "200 result=%d\n", res);
817                 return RESULT_SUCCESS;
818         }
819         else {
820                 ast_agi_fdprintf(chan, agi->fd, "200 result=%d (hangup)\n", res);
821                 return RESULT_FAILURE;
822         }
823 }
824
825 static int handle_recvtext(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
826 {
827         char *buf;
828         
829         if (argc != 3)
830                 return RESULT_SHOWUSAGE;
831
832         buf = ast_recvtext(chan,atoi(argv[2]));
833         if (buf) {
834                 ast_agi_fdprintf(chan, agi->fd, "200 result=1 (%s)\n", buf);
835                 ast_free(buf);
836         } else {        
837                 ast_agi_fdprintf(chan, agi->fd, "200 result=-1\n");
838         }
839         return RESULT_SUCCESS;
840 }
841
842 static int handle_tddmode(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
843 {
844         int res, x;
845
846         if (argc != 3)
847                 return RESULT_SHOWUSAGE;
848
849         if (!strncasecmp(argv[2],"on",2)) 
850                 x = 1; 
851         else 
852                 x = 0;
853         if (!strncasecmp(argv[2],"mate",4)) 
854                 x = 2;
855         if (!strncasecmp(argv[2],"tdd",3))
856                 x = 1;
857         res = ast_channel_setoption(chan, AST_OPTION_TDD, &x, sizeof(char), 0);
858         if (res != RESULT_SUCCESS)
859                 ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
860         else
861                 ast_agi_fdprintf(chan, agi->fd, "200 result=1\n");
862         return RESULT_SUCCESS;
863 }
864
865 static int handle_sendimage(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
866 {
867         int res;
868
869         if (argc != 3)
870                 return RESULT_SHOWUSAGE;
871
872         res = ast_send_image(chan, argv[2]);
873         if (!ast_check_hangup(chan))
874                 res = 0;
875         ast_agi_fdprintf(chan, agi->fd, "200 result=%d\n", res);
876         return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
877 }
878
879 static int handle_controlstreamfile(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
880 {
881         int res = 0, skipms = 3000;
882         char *fwd = NULL, *rev = NULL, *pause = NULL, *stop = NULL;
883
884         if (argc < 5 || argc > 9)
885                 return RESULT_SHOWUSAGE;
886
887         if (!ast_strlen_zero(argv[4]))
888                 stop = argv[4];
889         else
890                 stop = NULL;
891         
892         if ((argc > 5) && (sscanf(argv[5], "%d", &skipms) != 1))
893                 return RESULT_SHOWUSAGE;
894
895         if (argc > 6 && !ast_strlen_zero(argv[6]))
896                 fwd = argv[6];
897         else
898                 fwd = "#";
899
900         if (argc > 7 && !ast_strlen_zero(argv[7]))
901                 rev = argv[7];
902         else
903                 rev = "*";
904         
905         if (argc > 8 && !ast_strlen_zero(argv[8]))
906                 pause = argv[8];
907         else
908                 pause = NULL;
909         
910         res = ast_control_streamfile(chan, argv[3], fwd, rev, stop, pause, NULL, skipms, NULL);
911         
912         ast_agi_fdprintf(chan, agi->fd, "200 result=%d\n", res);
913
914         return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
915 }
916
917 static int handle_streamfile(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
918 {
919         int res, vres;
920         struct ast_filestream *fs, *vfs;
921         long sample_offset = 0, max_length;
922         char *edigits = "";
923
924         if (argc < 4 || argc > 5)
925                 return RESULT_SHOWUSAGE;
926
927         if (argv[3]) 
928                 edigits = argv[3];
929
930         if ((argc > 4) && (sscanf(argv[4], "%ld", &sample_offset) != 1))
931                 return RESULT_SHOWUSAGE;
932
933         if (!(fs = ast_openstream(chan, argv[2], chan->language))) {
934                 ast_agi_fdprintf(chan, agi->fd, "200 result=%d endpos=%ld\n", 0, sample_offset);
935                 return RESULT_SUCCESS;
936         }
937
938         if ((vfs = ast_openvstream(chan, argv[2], chan->language)))
939                 ast_debug(1, "Ooh, found a video stream, too\n");
940                 
941         ast_verb(3, "Playing '%s' (escape_digits=%s) (sample_offset %ld)\n", argv[2], edigits, sample_offset);
942
943         ast_seekstream(fs, 0, SEEK_END);
944         max_length = ast_tellstream(fs);
945         ast_seekstream(fs, sample_offset, SEEK_SET);
946         res = ast_applystream(chan, fs);
947         if (vfs)
948                 vres = ast_applystream(chan, vfs);
949         ast_playstream(fs);
950         if (vfs)
951                 ast_playstream(vfs);
952         
953         res = ast_waitstream_full(chan, argv[3], agi->audio, agi->ctrl);
954         /* this is to check for if ast_waitstream closed the stream, we probably are at
955          * the end of the stream, return that amount, else check for the amount */
956         sample_offset = (chan->stream) ? ast_tellstream(fs) : max_length;
957         ast_stopstream(chan);
958         if (res == 1) {
959                 /* Stop this command, don't print a result line, as there is a new command */
960                 return RESULT_SUCCESS;
961         }
962         ast_agi_fdprintf(chan, agi->fd, "200 result=%d endpos=%ld\n", res, sample_offset);
963         return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
964 }
965
966 /*! \brief get option - really similar to the handle_streamfile, but with a timeout */
967 static int handle_getoption(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
968 {
969         int res, vres;
970         struct ast_filestream *fs, *vfs;
971         long sample_offset = 0, max_length;
972         int timeout = 0;
973         char *edigits = "";
974
975         if ( argc < 4 || argc > 5 )
976                 return RESULT_SHOWUSAGE;
977
978         if ( argv[3] ) 
979                 edigits = argv[3];
980
981         if ( argc == 5 )
982                 timeout = atoi(argv[4]);
983         else if (chan->pbx->dtimeout) {
984                 /* by default dtimeout is set to 5sec */
985                 timeout = chan->pbx->dtimeout * 1000; /* in msec */
986         }
987
988         if (!(fs = ast_openstream(chan, argv[2], chan->language))) {
989                 ast_agi_fdprintf(chan, agi->fd, "200 result=%d endpos=%ld\n", 0, sample_offset);
990                 ast_log(LOG_WARNING, "Unable to open %s\n", argv[2]);
991                 return RESULT_SUCCESS;
992         }
993
994         if ((vfs = ast_openvstream(chan, argv[2], chan->language)))
995                 ast_debug(1, "Ooh, found a video stream, too\n");
996         
997         ast_verb(3, "Playing '%s' (escape_digits=%s) (timeout %d)\n", argv[2], edigits, timeout);
998
999         ast_seekstream(fs, 0, SEEK_END);
1000         max_length = ast_tellstream(fs);
1001         ast_seekstream(fs, sample_offset, SEEK_SET);
1002         res = ast_applystream(chan, fs);
1003         if (vfs)
1004                 vres = ast_applystream(chan, vfs);
1005         ast_playstream(fs);
1006         if (vfs)
1007                 ast_playstream(vfs);
1008
1009         res = ast_waitstream_full(chan, argv[3], agi->audio, agi->ctrl);
1010         /* this is to check for if ast_waitstream closed the stream, we probably are at
1011          * the end of the stream, return that amount, else check for the amount */
1012         sample_offset = (chan->stream)?ast_tellstream(fs):max_length;
1013         ast_stopstream(chan);
1014         if (res == 1) {
1015                 /* Stop this command, don't print a result line, as there is a new command */
1016                 return RESULT_SUCCESS;
1017         }
1018
1019         /* If the user didnt press a key, wait for digitTimeout*/
1020         if (res == 0 ) {
1021                 res = ast_waitfordigit_full(chan, timeout, agi->audio, agi->ctrl);
1022                 /* Make sure the new result is in the escape digits of the GET OPTION */
1023                 if ( !strchr(edigits,res) )
1024                         res=0;
1025         }
1026
1027         ast_agi_fdprintf(chan, agi->fd, "200 result=%d endpos=%ld\n", res, sample_offset);
1028         return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
1029 }
1030
1031
1032
1033
1034 /*! \brief Say number in various language syntaxes */
1035 /* While waiting, we're sending a NULL.  */
1036 static int handle_saynumber(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
1037 {
1038         int res, num;
1039
1040         if (argc < 4 || argc > 5)
1041                 return RESULT_SHOWUSAGE;
1042         if (sscanf(argv[2], "%d", &num) != 1)
1043                 return RESULT_SHOWUSAGE;
1044         res = ast_say_number_full(chan, num, argv[3], chan->language, argc > 4 ? argv[4] : NULL, agi->audio, agi->ctrl);
1045         if (res == 1)
1046                 return RESULT_SUCCESS;
1047         ast_agi_fdprintf(chan, agi->fd, "200 result=%d\n", res);
1048         return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
1049 }
1050
1051 static int handle_saydigits(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
1052 {
1053         int res, num;
1054
1055         if (argc != 4)
1056                 return RESULT_SHOWUSAGE;
1057         if (sscanf(argv[2], "%d", &num) != 1)
1058                 return RESULT_SHOWUSAGE;
1059
1060         res = ast_say_digit_str_full(chan, argv[2], argv[3], chan->language, agi->audio, agi->ctrl);
1061         if (res == 1) /* New command */
1062                 return RESULT_SUCCESS;
1063         ast_agi_fdprintf(chan, agi->fd, "200 result=%d\n", res);
1064         return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
1065 }
1066
1067 static int handle_sayalpha(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
1068 {
1069         int res;
1070
1071         if (argc != 4)
1072                 return RESULT_SHOWUSAGE;
1073
1074         res = ast_say_character_str_full(chan, argv[2], argv[3], chan->language, agi->audio, agi->ctrl);
1075         if (res == 1) /* New command */
1076                 return RESULT_SUCCESS;
1077         ast_agi_fdprintf(chan, agi->fd, "200 result=%d\n", res);
1078         return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
1079 }
1080
1081 static int handle_saydate(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
1082 {
1083         int res, num;
1084
1085         if (argc != 4)
1086                 return RESULT_SHOWUSAGE;
1087         if (sscanf(argv[2], "%d", &num) != 1)
1088                 return RESULT_SHOWUSAGE;
1089         res = ast_say_date(chan, num, argv[3], chan->language);
1090         if (res == 1)
1091                 return RESULT_SUCCESS;
1092         ast_agi_fdprintf(chan, agi->fd, "200 result=%d\n", res);
1093         return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
1094 }
1095
1096 static int handle_saytime(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
1097 {
1098         int res, num;
1099
1100         if (argc != 4)
1101                 return RESULT_SHOWUSAGE;
1102         if (sscanf(argv[2], "%d", &num) != 1)
1103                 return RESULT_SHOWUSAGE;
1104         res = ast_say_time(chan, num, argv[3], chan->language);
1105         if (res == 1)
1106                 return RESULT_SUCCESS;
1107         ast_agi_fdprintf(chan, agi->fd, "200 result=%d\n", res);
1108         return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
1109 }
1110
1111 static int handle_saydatetime(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
1112 {
1113         int res = 0;
1114         time_t unixtime;
1115         char *format, *zone = NULL;
1116         
1117         if (argc < 4)
1118                 return RESULT_SHOWUSAGE;
1119
1120         if (argc > 4) {
1121                 format = argv[4];
1122         } else {
1123                 /* XXX this doesn't belong here, but in the 'say' module */
1124                 if (!strcasecmp(chan->language, "de")) {
1125                         format = "A dBY HMS";
1126                 } else {
1127                         format = "ABdY 'digits/at' IMp"; 
1128                 }
1129         }
1130
1131         if (argc > 5 && !ast_strlen_zero(argv[5]))
1132                 zone = argv[5];
1133
1134         if (ast_get_time_t(argv[2], &unixtime, 0, NULL))
1135                 return RESULT_SHOWUSAGE;
1136
1137         res = ast_say_date_with_format(chan, unixtime, argv[3], chan->language, format, zone);
1138         if (res == 1)
1139                 return RESULT_SUCCESS;
1140
1141         ast_agi_fdprintf(chan, agi->fd, "200 result=%d\n", res);
1142         return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
1143 }
1144
1145 static int handle_sayphonetic(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
1146 {
1147         int res;
1148
1149         if (argc != 4)
1150                 return RESULT_SHOWUSAGE;
1151
1152         res = ast_say_phonetic_str_full(chan, argv[2], argv[3], chan->language, agi->audio, agi->ctrl);
1153         if (res == 1) /* New command */
1154                 return RESULT_SUCCESS;
1155         ast_agi_fdprintf(chan, agi->fd, "200 result=%d\n", res);
1156         return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
1157 }
1158
1159 static int handle_getdata(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
1160 {
1161         int res, max, timeout;
1162         char data[1024];
1163
1164         if (argc < 3)
1165                 return RESULT_SHOWUSAGE;
1166         if (argc >= 4)
1167                 timeout = atoi(argv[3]); 
1168         else
1169                 timeout = 0;
1170         if (argc >= 5) 
1171                 max = atoi(argv[4]); 
1172         else
1173                 max = 1024;
1174         res = ast_app_getdata_full(chan, argv[2], data, max, timeout, agi->audio, agi->ctrl);
1175         if (res == 2)                   /* New command */
1176                 return RESULT_SUCCESS;
1177         else if (res == 1)
1178                 ast_agi_fdprintf(chan, agi->fd, "200 result=%s (timeout)\n", data);
1179         else if (res < 0 )
1180                 ast_agi_fdprintf(chan, agi->fd, "200 result=-1\n");
1181         else
1182                 ast_agi_fdprintf(chan, agi->fd, "200 result=%s\n", data);
1183         return RESULT_SUCCESS;
1184 }
1185
1186 static int handle_setcontext(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
1187 {
1188
1189         if (argc != 3)
1190                 return RESULT_SHOWUSAGE;
1191         ast_copy_string(chan->context, argv[2], sizeof(chan->context));
1192         ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
1193         return RESULT_SUCCESS;
1194 }
1195         
1196 static int handle_setextension(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1197 {
1198         if (argc != 3)
1199                 return RESULT_SHOWUSAGE;
1200         ast_copy_string(chan->exten, argv[2], sizeof(chan->exten));
1201         ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
1202         return RESULT_SUCCESS;
1203 }
1204
1205 static int handle_setpriority(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1206 {
1207         int pri;
1208
1209         if (argc != 3)
1210                 return RESULT_SHOWUSAGE;        
1211
1212         if (sscanf(argv[2], "%d", &pri) != 1) {
1213                 if ((pri = ast_findlabel_extension(chan, chan->context, chan->exten, argv[2], chan->cid.cid_num)) < 1)
1214                         return RESULT_SHOWUSAGE;
1215         }
1216
1217         ast_explicit_goto(chan, NULL, NULL, pri);
1218         ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
1219         return RESULT_SUCCESS;
1220 }
1221                 
1222 static int handle_recordfile(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
1223 {
1224         struct ast_filestream *fs;
1225         struct ast_frame *f;
1226         struct timeval start;
1227         long sample_offset = 0;
1228         int res = 0;
1229         int ms;
1230
1231         struct ast_dsp *sildet=NULL;         /* silence detector dsp */
1232         int totalsilence = 0;
1233         int dspsilence = 0;
1234         int silence = 0;                /* amount of silence to allow */
1235         int gotsilence = 0;             /* did we timeout for silence? */
1236         char *silencestr=NULL;
1237         int rfmt=0;
1238
1239
1240         /* XXX EAGI FIXME XXX */
1241
1242         if (argc < 6)
1243                 return RESULT_SHOWUSAGE;
1244         if (sscanf(argv[5], "%d", &ms) != 1)
1245                 return RESULT_SHOWUSAGE;
1246
1247         if (argc > 6)
1248                 silencestr = strchr(argv[6],'s');
1249         if ((argc > 7) && (!silencestr))
1250                 silencestr = strchr(argv[7],'s');
1251         if ((argc > 8) && (!silencestr))
1252                 silencestr = strchr(argv[8],'s');
1253
1254         if (silencestr) {
1255                 if (strlen(silencestr) > 2) {
1256                         if ((silencestr[0] == 's') && (silencestr[1] == '=')) {
1257                                 silencestr++;
1258                                 silencestr++;
1259                                 if (silencestr)
1260                                         silence = atoi(silencestr);
1261                                 if (silence > 0)
1262                                         silence *= 1000;
1263                         }
1264                 }
1265         }
1266
1267         if (silence > 0) {
1268                 rfmt = chan->readformat;
1269                 res = ast_set_read_format(chan, AST_FORMAT_SLINEAR);
1270                 if (res < 0) {
1271                         ast_log(LOG_WARNING, "Unable to set to linear mode, giving up\n");
1272                         return -1;
1273                 }
1274                 sildet = ast_dsp_new();
1275                 if (!sildet) {
1276                         ast_log(LOG_WARNING, "Unable to create silence detector :(\n");
1277                         return -1;
1278                 }
1279                 ast_dsp_set_threshold(sildet, ast_dsp_get_threshold_from_settings(THRESHOLD_SILENCE));
1280         }
1281
1282         /* backward compatibility, if no offset given, arg[6] would have been
1283          * caught below and taken to be a beep, else if it is a digit then it is a
1284          * offset */
1285         if ((argc >6) && (sscanf(argv[6], "%ld", &sample_offset) != 1) && (!strchr(argv[6], '=')))
1286                 res = ast_streamfile(chan, "beep", chan->language);
1287
1288         if ((argc > 7) && (!strchr(argv[7], '=')))
1289                 res = ast_streamfile(chan, "beep", chan->language);
1290
1291         if (!res)
1292                 res = ast_waitstream(chan, argv[4]);
1293         if (res) {
1294                 ast_agi_fdprintf(chan, agi->fd, "200 result=%d (randomerror) endpos=%ld\n", res, sample_offset);
1295         } else {
1296                 fs = ast_writefile(argv[2], argv[3], NULL, O_CREAT | O_WRONLY | (sample_offset ? O_APPEND : 0), 0, AST_FILE_MODE);
1297                 if (!fs) {
1298                         res = -1;
1299                         ast_agi_fdprintf(chan, agi->fd, "200 result=%d (writefile)\n", res);
1300                         if (sildet)
1301                                 ast_dsp_free(sildet);
1302                         return RESULT_FAILURE;
1303                 }
1304                 
1305                 /* Request a video update */
1306                 ast_indicate(chan, AST_CONTROL_VIDUPDATE);
1307         
1308                 chan->stream = fs;
1309                 ast_applystream(chan,fs);
1310                 /* really should have checks */
1311                 ast_seekstream(fs, sample_offset, SEEK_SET);
1312                 ast_truncstream(fs);
1313                 
1314                 start = ast_tvnow();
1315                 while ((ms < 0) || ast_tvdiff_ms(ast_tvnow(), start) < ms) {
1316                         res = ast_waitfor(chan, -1);
1317                         if (res < 0) {
1318                                 ast_closestream(fs);
1319                                 ast_agi_fdprintf(chan, agi->fd, "200 result=%d (waitfor) endpos=%ld\n", res,sample_offset);
1320                                 if (sildet)
1321                                         ast_dsp_free(sildet);
1322                                 return RESULT_FAILURE;
1323                         }
1324                         f = ast_read(chan);
1325                         if (!f) {
1326                                 ast_agi_fdprintf(chan, agi->fd, "200 result=%d (hangup) endpos=%ld\n", -1, sample_offset);
1327                                 ast_closestream(fs);
1328                                 if (sildet)
1329                                         ast_dsp_free(sildet);
1330                                 return RESULT_FAILURE;
1331                         }
1332                         switch(f->frametype) {
1333                         case AST_FRAME_DTMF:
1334                                 if (strchr(argv[4], f->subclass)) {
1335                                         /* This is an interrupting chracter, so rewind to chop off any small
1336                                            amount of DTMF that may have been recorded
1337                                         */
1338                                         ast_stream_rewind(fs, 200);
1339                                         ast_truncstream(fs);
1340                                         sample_offset = ast_tellstream(fs);
1341                                         ast_agi_fdprintf(chan, agi->fd, "200 result=%d (dtmf) endpos=%ld\n", f->subclass, sample_offset);
1342                                         ast_closestream(fs);
1343                                         ast_frfree(f);
1344                                         if (sildet)
1345                                                 ast_dsp_free(sildet);
1346                                         return RESULT_SUCCESS;
1347                                 }
1348                                 break;
1349                         case AST_FRAME_VOICE:
1350                                 ast_writestream(fs, f);
1351                                 /* this is a safe place to check progress since we know that fs
1352                                  * is valid after a write, and it will then have our current
1353                                  * location */
1354                                 sample_offset = ast_tellstream(fs);
1355                                 if (silence > 0) {
1356                                         dspsilence = 0;
1357                                         ast_dsp_silence(sildet, f, &dspsilence);
1358                                         if (dspsilence) {
1359                                                 totalsilence = dspsilence;
1360                                         } else {
1361                                                 totalsilence = 0;
1362                                         }
1363                                         if (totalsilence > silence) {
1364                                                 /* Ended happily with silence */
1365                                                 gotsilence = 1;
1366                                                 break;
1367                                         }
1368                                 }
1369                                 break;
1370                         case AST_FRAME_VIDEO:
1371                                 ast_writestream(fs, f);
1372                         default:
1373                                 /* Ignore all other frames */
1374                                 break;
1375                         }
1376                         ast_frfree(f);
1377                         if (gotsilence)
1378                                 break;
1379                 }
1380
1381                         if (gotsilence) {
1382                                 ast_stream_rewind(fs, silence-1000);
1383                                 ast_truncstream(fs);
1384                                 sample_offset = ast_tellstream(fs);
1385                 }               
1386                 ast_agi_fdprintf(chan, agi->fd, "200 result=%d (timeout) endpos=%ld\n", res, sample_offset);
1387                 ast_closestream(fs);
1388         }
1389
1390         if (silence > 0) {
1391                 res = ast_set_read_format(chan, rfmt);
1392                 if (res)
1393                         ast_log(LOG_WARNING, "Unable to restore read format on '%s'\n", chan->name);
1394                         ast_dsp_free(sildet);
1395         }
1396         return RESULT_SUCCESS;
1397 }
1398
1399 static int handle_autohangup(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
1400 {
1401         int timeout;
1402
1403         if (argc != 3)
1404                 return RESULT_SHOWUSAGE;
1405         if (sscanf(argv[2], "%d", &timeout) != 1)
1406                 return RESULT_SHOWUSAGE;
1407         if (timeout < 0)
1408                 timeout = 0;
1409         if (timeout)
1410                 chan->whentohangup = time(NULL) + timeout;
1411         else
1412                 chan->whentohangup = 0;
1413         ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
1414         return RESULT_SUCCESS;
1415 }
1416
1417 static int handle_hangup(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1418 {
1419         struct ast_channel *c;
1420
1421         if (argc == 1) {
1422                 /* no argument: hangup the current channel */
1423                 ast_softhangup(chan,AST_SOFTHANGUP_EXPLICIT);
1424                 ast_agi_fdprintf(chan, agi->fd, "200 result=1\n");
1425                 return RESULT_SUCCESS;
1426         } else if (argc == 2) {
1427                 /* one argument: look for info on the specified channel */
1428                 c = ast_get_channel_by_name_locked(argv[1]);
1429                 if (c) {
1430                         /* we have a matching channel */
1431                         ast_softhangup(c,AST_SOFTHANGUP_EXPLICIT);
1432                         ast_agi_fdprintf(chan, agi->fd, "200 result=1\n");
1433                         ast_channel_unlock(c);
1434                         return RESULT_SUCCESS;
1435                 }
1436                 /* if we get this far no channel name matched the argument given */
1437                 ast_agi_fdprintf(chan, agi->fd, "200 result=-1\n");
1438                 return RESULT_SUCCESS;
1439         } else {
1440                 return RESULT_SHOWUSAGE;
1441         }
1442 }
1443
1444 static int handle_exec(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1445 {
1446         int res;
1447         struct ast_app *app;
1448
1449         if (argc < 2)
1450                 return RESULT_SHOWUSAGE;
1451
1452         ast_verb(3, "AGI Script Executing Application: (%s) Options: (%s)\n", argv[1], argv[2]);
1453
1454         if ((app = pbx_findapp(argv[1]))) {
1455                 res = pbx_exec(chan, app, argv[2]);
1456         } else {
1457                 ast_log(LOG_WARNING, "Could not find application (%s)\n", argv[1]);
1458                 res = -2;
1459         }
1460         ast_agi_fdprintf(chan, agi->fd, "200 result=%d\n", res);
1461
1462         /* Even though this is wrong, users are depending upon this result. */
1463         return res;
1464 }
1465
1466 static int handle_setcallerid(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1467 {
1468         char tmp[256]="";
1469         char *l = NULL, *n = NULL;
1470
1471         if (argv[2]) {
1472                 ast_copy_string(tmp, argv[2], sizeof(tmp));
1473                 ast_callerid_parse(tmp, &n, &l);
1474                 if (l)
1475                         ast_shrink_phone_number(l);
1476                 else
1477                         l = "";
1478                 if (!n)
1479                         n = "";
1480                 ast_set_callerid(chan, l, n, NULL);
1481         }
1482
1483         ast_agi_fdprintf(chan, agi->fd, "200 result=1\n");
1484         return RESULT_SUCCESS;
1485 }
1486
1487 static int handle_channelstatus(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1488 {
1489         struct ast_channel *c;
1490         if (argc == 2) {
1491                 /* no argument: supply info on the current channel */
1492                 ast_agi_fdprintf(chan, agi->fd, "200 result=%d\n", chan->_state);
1493                 return RESULT_SUCCESS;
1494         } else if (argc == 3) {
1495                 /* one argument: look for info on the specified channel */
1496                 c = ast_get_channel_by_name_locked(argv[2]);
1497                 if (c) {
1498                         ast_agi_fdprintf(chan, agi->fd, "200 result=%d\n", c->_state);
1499                         ast_channel_unlock(c);
1500                         return RESULT_SUCCESS;
1501                 }
1502                 /* if we get this far no channel name matched the argument given */
1503                 ast_agi_fdprintf(chan, agi->fd, "200 result=-1\n");
1504                 return RESULT_SUCCESS;
1505         } else {
1506                 return RESULT_SHOWUSAGE;
1507         }
1508 }
1509
1510 static int handle_setvariable(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1511 {
1512         if (argv[3])
1513                 pbx_builtin_setvar_helper(chan, argv[2], argv[3]);
1514
1515         ast_agi_fdprintf(chan, agi->fd, "200 result=1\n");
1516         return RESULT_SUCCESS;
1517 }
1518
1519 static int handle_getvariable(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1520 {
1521         char *ret;
1522         char tempstr[1024];
1523
1524         if (argc != 3)
1525                 return RESULT_SHOWUSAGE;
1526
1527         /* check if we want to execute an ast_custom_function */
1528         if (!ast_strlen_zero(argv[2]) && (argv[2][strlen(argv[2]) - 1] == ')')) {
1529                 ret = ast_func_read(chan, argv[2], tempstr, sizeof(tempstr)) ? NULL : tempstr;
1530         } else {
1531                 pbx_retrieve_variable(chan, argv[2], &ret, tempstr, sizeof(tempstr), NULL);
1532         }
1533
1534         if (ret)
1535                 ast_agi_fdprintf(chan, agi->fd, "200 result=1 (%s)\n", ret);
1536         else
1537                 ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
1538
1539         return RESULT_SUCCESS;
1540 }
1541
1542 static int handle_getvariablefull(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1543 {
1544         char tmp[4096];
1545         struct ast_channel *chan2=NULL;
1546
1547         if ((argc != 4) && (argc != 5))
1548                 return RESULT_SHOWUSAGE;
1549         if (argc == 5) {
1550                 chan2 = ast_get_channel_by_name_locked(argv[4]);
1551         } else {
1552                 chan2 = chan;
1553         }
1554         if (chan2) {
1555                 pbx_substitute_variables_helper(chan2, argv[3], tmp, sizeof(tmp) - 1);
1556                 ast_agi_fdprintf(chan, agi->fd, "200 result=1 (%s)\n", tmp);
1557         } else {
1558                 ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
1559         }
1560         if (chan2 && (chan2 != chan))
1561                 ast_channel_unlock(chan2);
1562         return RESULT_SUCCESS;
1563 }
1564
1565 static int handle_verbose(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1566 {
1567         int level = 0;
1568
1569         if (argc < 2)
1570                 return RESULT_SHOWUSAGE;
1571
1572         if (argv[2])
1573                 sscanf(argv[2], "%d", &level);
1574
1575         ast_verb(level, "%s: %s\n", chan->data, argv[1]);
1576         
1577         ast_agi_fdprintf(chan, agi->fd, "200 result=1\n");
1578         
1579         return RESULT_SUCCESS;
1580 }
1581
1582 static int handle_dbget(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1583 {
1584         int res;
1585         char tmp[256];
1586
1587         if (argc != 4)
1588                 return RESULT_SHOWUSAGE;
1589         res = ast_db_get(argv[2], argv[3], tmp, sizeof(tmp));
1590         if (res) 
1591                 ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
1592         else
1593                 ast_agi_fdprintf(chan, agi->fd, "200 result=1 (%s)\n", tmp);
1594
1595         return RESULT_SUCCESS;
1596 }
1597
1598 static int handle_dbput(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1599 {
1600         int res;
1601
1602         if (argc != 5)
1603                 return RESULT_SHOWUSAGE;
1604         res = ast_db_put(argv[2], argv[3], argv[4]);
1605         ast_agi_fdprintf(chan, agi->fd, "200 result=%c\n", res ? '0' : '1');
1606         return RESULT_SUCCESS;
1607 }
1608
1609 static int handle_dbdel(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1610 {
1611         int res;
1612
1613         if (argc != 4)
1614                 return RESULT_SHOWUSAGE;
1615         res = ast_db_del(argv[2], argv[3]);
1616         ast_agi_fdprintf(chan, agi->fd, "200 result=%c\n", res ? '0' : '1');
1617         return RESULT_SUCCESS;
1618 }
1619
1620 static int handle_dbdeltree(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1621 {
1622         int res;
1623
1624         if ((argc < 3) || (argc > 4))
1625                 return RESULT_SHOWUSAGE;
1626         if (argc == 4)
1627                 res = ast_db_deltree(argv[2], argv[3]);
1628         else
1629                 res = ast_db_deltree(argv[2], NULL);
1630
1631         ast_agi_fdprintf(chan, agi->fd, "200 result=%c\n", res ? '0' : '1');
1632         return RESULT_SUCCESS;
1633 }
1634
1635 static char *handle_cli_agi_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1636 {
1637         switch (cmd) {
1638         case CLI_INIT:
1639                 e->command = "agi set debug [on|off]";
1640                 e->usage =
1641                         "Usage: agi set debug [on|off]\n"
1642                         "       Enables/disables dumping of AGI transactions for\n"
1643                         "       debugging purposes.\n";
1644                 return NULL;
1645
1646         case CLI_GENERATE:
1647                 return NULL;
1648         }
1649
1650         if (a->argc != e->args)
1651                 return CLI_SHOWUSAGE;
1652
1653         if (strncasecmp(a->argv[3], "off", 3) == 0) {
1654                 agidebug = 0;
1655         } else if (strncasecmp(a->argv[3], "on", 2) == 0) {
1656                 agidebug = 1;
1657         } else {
1658                 return CLI_SHOWUSAGE;
1659         }
1660         ast_cli(a->fd, "AGI Debugging %sabled\n", agidebug ? "En" : "Dis");
1661         return CLI_SUCCESS;
1662 }
1663
1664 static int handle_noop(struct ast_channel *chan, AGI *agi, int arg, char *argv[])
1665 {
1666         ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
1667         return RESULT_SUCCESS;
1668 }
1669
1670 static int handle_setmusic(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
1671 {
1672         if (!strncasecmp(argv[2], "on", 2))
1673                 ast_moh_start(chan, argc > 3 ? argv[3] : NULL, NULL);
1674         else if (!strncasecmp(argv[2], "off", 3))
1675                 ast_moh_stop(chan);
1676         ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
1677         return RESULT_SUCCESS;
1678 }
1679
1680 static int handle_speechcreate(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1681 {
1682         /* If a structure already exists, return an error */
1683         if (agi->speech) {
1684                 ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
1685                 return RESULT_SUCCESS;
1686         }
1687         
1688         if ((agi->speech = ast_speech_new(argv[2], AST_FORMAT_SLINEAR)))
1689                 ast_agi_fdprintf(chan, agi->fd, "200 result=1\n");
1690         else
1691                 ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
1692         
1693         return RESULT_SUCCESS;
1694 }
1695
1696 static int handle_speechset(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1697 {
1698         /* Check for minimum arguments */
1699         if (argc != 3)
1700                 return RESULT_SHOWUSAGE;
1701         
1702         /* Check to make sure speech structure exists */
1703         if (!agi->speech) {
1704                 ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
1705                 return RESULT_SUCCESS;
1706         }
1707         
1708         ast_speech_change(agi->speech, argv[2], argv[3]);
1709         ast_agi_fdprintf(chan, agi->fd, "200 result=1\n");
1710         
1711         return RESULT_SUCCESS;
1712 }
1713
1714 static int handle_speechdestroy(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1715 {
1716         if (agi->speech) {
1717                 ast_speech_destroy(agi->speech);
1718                 agi->speech = NULL;
1719                 ast_agi_fdprintf(chan, agi->fd, "200 result=1\n");
1720         } else {
1721                 ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
1722         }
1723         
1724         return RESULT_SUCCESS;
1725 }
1726
1727 static int handle_speechloadgrammar(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1728 {
1729         if (argc != 5)
1730                 return RESULT_SHOWUSAGE;
1731         
1732         if (!agi->speech) {
1733                 ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
1734                 return RESULT_SUCCESS;
1735         }
1736         
1737         if (ast_speech_grammar_load(agi->speech, argv[3], argv[4]))
1738                 ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
1739         else
1740                 ast_agi_fdprintf(chan, agi->fd, "200 result=1\n");
1741         
1742         return RESULT_SUCCESS;
1743 }
1744
1745 static int handle_speechunloadgrammar(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1746 {
1747         if (argc != 4)
1748                 return RESULT_SHOWUSAGE;
1749         
1750         if (!agi->speech) {
1751                 ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
1752                 return RESULT_SUCCESS;
1753         }
1754         
1755         if (ast_speech_grammar_unload(agi->speech, argv[3]))
1756                 ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
1757         else
1758                 ast_agi_fdprintf(chan, agi->fd, "200 result=1\n");
1759         
1760         return RESULT_SUCCESS;
1761 }
1762
1763 static int handle_speechactivategrammar(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1764 {
1765         if (argc != 4)
1766                 return RESULT_SHOWUSAGE;
1767         
1768         if (!agi->speech) {
1769                 ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
1770                 return RESULT_SUCCESS;
1771         }
1772         
1773         if (ast_speech_grammar_activate(agi->speech, argv[3]))
1774                 ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
1775         else
1776                 ast_agi_fdprintf(chan, agi->fd, "200 result=1\n");
1777         
1778         return RESULT_SUCCESS;
1779 }
1780
1781 static int handle_speechdeactivategrammar(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1782 {
1783         if (argc != 4)
1784                 return RESULT_SHOWUSAGE;
1785         
1786         if (!agi->speech) {
1787                 ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
1788                 return RESULT_SUCCESS;
1789         }
1790         
1791         if (ast_speech_grammar_deactivate(agi->speech, argv[3]))
1792                 ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
1793         else
1794                 ast_agi_fdprintf(chan, agi->fd, "200 result=1\n");
1795         
1796         return RESULT_SUCCESS;
1797 }
1798
1799 static int speech_streamfile(struct ast_channel *chan, const char *filename, const char *preflang, int offset)
1800 {
1801         struct ast_filestream *fs = NULL;
1802         
1803         if (!(fs = ast_openstream(chan, filename, preflang)))
1804                 return -1;
1805         
1806         if (offset)
1807                 ast_seekstream(fs, offset, SEEK_SET);
1808         
1809         if (ast_applystream(chan, fs))
1810                 return -1;
1811         
1812         if (ast_playstream(fs))
1813                 return -1;
1814         
1815         return 0;
1816 }
1817
1818 static int handle_speechrecognize(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1819 {
1820         struct ast_speech *speech = agi->speech;
1821         char *prompt, dtmf = 0, tmp[4096] = "", *buf = tmp;
1822         int timeout = 0, offset = 0, old_read_format = 0, res = 0, i = 0;
1823         long current_offset = 0;
1824         const char *reason = NULL;
1825         struct ast_frame *fr = NULL;
1826         struct ast_speech_result *result = NULL;
1827         size_t left = sizeof(tmp);
1828         time_t start = 0, current;
1829         
1830         if (argc < 4)
1831                 return RESULT_SHOWUSAGE;
1832         
1833         if (!speech) {
1834                 ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
1835                 return RESULT_SUCCESS;
1836         }
1837         
1838         prompt = argv[2];
1839         timeout = atoi(argv[3]);
1840         
1841         /* If offset is specified then convert from text to integer */
1842         if (argc == 5)
1843                 offset = atoi(argv[4]);
1844         
1845         /* We want frames coming in signed linear */
1846         old_read_format = chan->readformat;
1847         if (ast_set_read_format(chan, AST_FORMAT_SLINEAR)) {
1848                 ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
1849                 return RESULT_SUCCESS;
1850         }
1851         
1852         /* Setup speech structure */
1853         if (speech->state == AST_SPEECH_STATE_NOT_READY || speech->state == AST_SPEECH_STATE_DONE) {
1854                 ast_speech_change_state(speech, AST_SPEECH_STATE_NOT_READY);
1855                 ast_speech_start(speech);
1856         }
1857         
1858         /* Start playing prompt */
1859         speech_streamfile(chan, prompt, chan->language, offset);
1860         
1861         /* Go into loop reading in frames, passing to speech thingy, checking for hangup, all that jazz */
1862         while (ast_strlen_zero(reason)) {
1863                 /* Run scheduled items */
1864                 ast_sched_runq(chan->sched);
1865                 
1866                 /* See maximum time of waiting */
1867                 if ((res = ast_sched_wait(chan->sched)) < 0)
1868                         res = 1000;
1869                 
1870                 /* Wait for frame */
1871                 if (ast_waitfor(chan, res) > 0) {
1872                         if (!(fr = ast_read(chan))) {
1873                                 reason = "hangup";
1874                                 break;
1875                         }
1876                 }
1877                 
1878                 /* Perform timeout check */
1879                 if ((timeout > 0) && (start > 0)) {
1880                         time(&current);
1881                         if ((current - start) >= timeout) {
1882                                 reason = "timeout";
1883                                 if (fr)
1884                                         ast_frfree(fr);
1885                                 break;
1886                         }
1887                 }
1888                 
1889                 /* Check the speech structure for any changes */
1890                 ast_mutex_lock(&speech->lock);
1891                 
1892                 /* See if we need to quiet the audio stream playback */
1893                 if (ast_test_flag(speech, AST_SPEECH_QUIET) && chan->stream) {
1894                         current_offset = ast_tellstream(chan->stream);
1895                         ast_stopstream(chan);
1896                         ast_clear_flag(speech, AST_SPEECH_QUIET);
1897                 }
1898                 
1899                 /* Check each state */
1900                 switch (speech->state) {
1901                 case AST_SPEECH_STATE_READY:
1902                         /* If the stream is done, start timeout calculation */
1903                         if ((timeout > 0) && ((!chan->stream) || (chan->streamid == -1 && chan->timingfunc == NULL))) {
1904                                 ast_stopstream(chan);
1905                                 time(&start);
1906                         }
1907                         /* Write audio frame data into speech engine if possible */
1908                         if (fr && fr->frametype == AST_FRAME_VOICE)
1909                                 ast_speech_write(speech, fr->data, fr->datalen);
1910                         break;
1911                 case AST_SPEECH_STATE_WAIT:
1912                         /* Cue waiting sound if not already playing */
1913                         if ((!chan->stream) || (chan->streamid == -1 && chan->timingfunc == NULL)) {
1914                                 ast_stopstream(chan);
1915                                 /* If a processing sound exists, or is not none - play it */
1916                                 if (!ast_strlen_zero(speech->processing_sound) && strcasecmp(speech->processing_sound, "none"))
1917                                         speech_streamfile(chan, speech->processing_sound, chan->language, 0);
1918                         }
1919                         break;
1920                 case AST_SPEECH_STATE_DONE:
1921                         /* Get the results */
1922                         speech->results = ast_speech_results_get(speech);
1923                         /* Change state to not ready */
1924                         ast_speech_change_state(speech, AST_SPEECH_STATE_NOT_READY);
1925                         reason = "speech";
1926                         break;
1927                 default:
1928                         break;
1929                 }
1930                 ast_mutex_unlock(&speech->lock);
1931                 
1932                 /* Check frame for DTMF or hangup */
1933                 if (fr) {
1934                         if (fr->frametype == AST_FRAME_DTMF) {
1935                                 reason = "dtmf";
1936                                 dtmf = fr->subclass;
1937                         } else if (fr->frametype == AST_FRAME_CONTROL && fr->subclass == AST_CONTROL_HANGUP) {
1938                                 reason = "hangup";
1939                         }
1940                         ast_frfree(fr);
1941                 }
1942         }
1943         
1944         if (!strcasecmp(reason, "speech")) {
1945                 /* Build string containing speech results */
1946                 for (result = speech->results; result; result = AST_LIST_NEXT(result, list)) {
1947                         /* Build result string */
1948                         ast_build_string(&buf, &left, "%sscore%d=%d text%d=\"%s\" grammar%d=%s", (i > 0 ? " " : ""), i, result->score, i, result->text, i, result->grammar);
1949                         /* Increment result count */
1950                         i++;
1951                 }
1952                 /* Print out */
1953                 ast_agi_fdprintf(chan, agi->fd, "200 result=1 (speech) endpos=%ld results=%d %s\n", current_offset, i, tmp);
1954         } else if (!strcasecmp(reason, "dtmf")) {
1955                 ast_agi_fdprintf(chan, agi->fd, "200 result=1 (digit) digit=%c endpos=%ld\n", dtmf, current_offset);
1956         } else if (!strcasecmp(reason, "hangup") || !strcasecmp(reason, "timeout")) {
1957                 ast_agi_fdprintf(chan, agi->fd, "200 result=1 (%s) endpos=%ld\n", reason, current_offset);
1958         } else {
1959                 ast_agi_fdprintf(chan, agi->fd, "200 result=0 endpos=%ld\n", current_offset);
1960         }
1961         
1962         return RESULT_SUCCESS;
1963 }
1964
1965 static int handle_asyncagi_break(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
1966 {
1967         ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
1968         return AST_PBX_KEEPALIVE;
1969 }
1970
1971 static char usage_setmusic[] =
1972 " Usage: SET MUSIC ON <on|off> <class>\n"
1973 "       Enables/Disables the music on hold generator.  If <class> is\n"
1974 " not specified, then the default music on hold class will be used.\n"
1975 " Always returns 0.\n";
1976
1977 static char usage_dbput[] =
1978 " Usage: DATABASE PUT <family> <key> <value>\n"
1979 "       Adds or updates an entry in the Asterisk database for a\n"
1980 " given family, key, and value.\n"
1981 " Returns 1 if successful, 0 otherwise.\n";
1982
1983 static char usage_dbget[] =
1984 " Usage: DATABASE GET <family> <key>\n"
1985 "       Retrieves an entry in the Asterisk database for a\n"
1986 " given family and key.\n"
1987 " Returns 0 if <key> is not set.  Returns 1 if <key>\n"
1988 " is set and returns the variable in parentheses.\n"
1989 " Example return code: 200 result=1 (testvariable)\n";
1990
1991 static char usage_dbdel[] =
1992 " Usage: DATABASE DEL <family> <key>\n"
1993 "       Deletes an entry in the Asterisk database for a\n"
1994 " given family and key.\n"
1995 " Returns 1 if successful, 0 otherwise.\n";
1996
1997 static char usage_dbdeltree[] =
1998 " Usage: DATABASE DELTREE <family> [keytree]\n"
1999 "       Deletes a family or specific keytree within a family\n"
2000 " in the Asterisk database.\n"
2001 " Returns 1 if successful, 0 otherwise.\n";
2002
2003 static char usage_verbose[] =
2004 " Usage: VERBOSE <message> <level>\n"
2005 "       Sends <message> to the console via verbose message system.\n"
2006 " <level> is the the verbose level (1-4)\n"
2007 " Always returns 1.\n";
2008
2009 static char usage_getvariable[] =
2010 " Usage: GET VARIABLE <variablename>\n"
2011 "       Returns 0 if <variablename> is not set.  Returns 1 if <variablename>\n"
2012 " is set and returns the variable in parentheses.\n"
2013 " example return code: 200 result=1 (testvariable)\n";
2014
2015 static char usage_getvariablefull[] =
2016 " Usage: GET FULL VARIABLE <variablename> [<channel name>]\n"
2017 "       Returns 0 if <variablename> is not set or channel does not exist.  Returns 1\n"
2018 "if <variablename>  is set and returns the variable in parenthesis.  Understands\n"
2019 "complex variable names and builtin variables, unlike GET VARIABLE.\n"
2020 " example return code: 200 result=1 (testvariable)\n";
2021
2022 static char usage_setvariable[] =
2023 " Usage: SET VARIABLE <variablename> <value>\n";
2024
2025 static char usage_channelstatus[] =
2026 " Usage: CHANNEL STATUS [<channelname>]\n"
2027 "       Returns the status of the specified channel.\n" 
2028 " If no channel name is given the returns the status of the\n"
2029 " current channel.  Return values:\n"
2030 "  0 Channel is down and available\n"
2031 "  1 Channel is down, but reserved\n"
2032 "  2 Channel is off hook\n"
2033 "  3 Digits (or equivalent) have been dialed\n"
2034 "  4 Line is ringing\n"
2035 "  5 Remote end is ringing\n"
2036 "  6 Line is up\n"
2037 "  7 Line is busy\n";
2038
2039 static char usage_setcallerid[] =
2040 " Usage: SET CALLERID <number>\n"
2041 "       Changes the callerid of the current channel.\n";
2042
2043 static char usage_exec[] =
2044 " Usage: EXEC <application> <options>\n"
2045 "       Executes <application> with given <options>.\n"
2046 " Returns whatever the application returns, or -2 on failure to find application\n";
2047
2048 static char usage_hangup[] =
2049 " Usage: HANGUP [<channelname>]\n"
2050 "       Hangs up the specified channel.\n"
2051 " If no channel name is given, hangs up the current channel\n";
2052
2053 static char usage_answer[] = 
2054 " Usage: ANSWER\n"
2055 "       Answers channel if not already in answer state. Returns -1 on\n"
2056 " channel failure, or 0 if successful.\n";
2057
2058 static char usage_waitfordigit[] = 
2059 " Usage: WAIT FOR DIGIT <timeout>\n"
2060 "       Waits up to 'timeout' milliseconds for channel to receive a DTMF digit.\n"
2061 " Returns -1 on channel failure, 0 if no digit is received in the timeout, or\n"
2062 " the numerical value of the ascii of the digit if one is received.  Use -1\n"
2063 " for the timeout value if you desire the call to block indefinitely.\n";
2064
2065 static char usage_sendtext[] =
2066 " Usage: SEND TEXT \"<text to send>\"\n"
2067 "       Sends the given text on a channel. Most channels do not support the\n"
2068 " transmission of text.  Returns 0 if text is sent, or if the channel does not\n"
2069 " support text transmission.  Returns -1 only on error/hangup.  Text\n"
2070 " consisting of greater than one word should be placed in quotes since the\n"
2071 " command only accepts a single argument.\n";
2072
2073 static char usage_recvchar[] =
2074 " Usage: RECEIVE CHAR <timeout>\n"
2075 "       Receives a character of text on a channel. Specify timeout to be the\n"
2076 " maximum time to wait for input in milliseconds, or 0 for infinite. Most channels\n"
2077 " do not support the reception of text. Returns the decimal value of the character\n"
2078 " if one is received, or 0 if the channel does not support text reception.  Returns\n"
2079 " -1 only on error/hangup.\n";
2080
2081 static char usage_recvtext[] =
2082 " Usage: RECEIVE TEXT <timeout>\n"
2083 "       Receives a string of text on a channel. Specify timeout to be the\n"
2084 " maximum time to wait for input in milliseconds, or 0 for infinite. Most channels\n"
2085 " do not support the reception of text. Returns -1 for failure or 1 for success, and the string in parentheses.\n";
2086
2087 static char usage_tddmode[] =
2088 " Usage: TDD MODE <on|off>\n"
2089 "       Enable/Disable TDD transmission/reception on a channel. Returns 1 if\n"
2090 " successful, or 0 if channel is not TDD-capable.\n";
2091
2092 static char usage_sendimage[] =
2093 " Usage: SEND IMAGE <image>\n"
2094 "       Sends the given image on a channel. Most channels do not support the\n"
2095 " transmission of images. Returns 0 if image is sent, or if the channel does not\n"
2096 " support image transmission.  Returns -1 only on error/hangup. Image names\n"
2097 " should not include extensions.\n";
2098
2099 static char usage_streamfile[] =
2100 " Usage: STREAM FILE <filename> <escape digits> [sample offset]\n"
2101 "       Send the given file, allowing playback to be interrupted by the given\n"
2102 " digits, if any. Use double quotes for the digits if you wish none to be\n"
2103 " permitted. If sample offset is provided then the audio will seek to sample\n"
2104 " offset before play starts.  Returns 0 if playback completes without a digit\n"
2105 " being pressed, or the ASCII numerical value of the digit if one was pressed,\n"
2106 " or -1 on error or if the channel was disconnected. Remember, the file\n"
2107 " extension must not be included in the filename.\n";
2108
2109 static char usage_controlstreamfile[] =
2110 " Usage: CONTROL STREAM FILE <filename> <escape digits> [skipms] [ffchar] [rewchr] [pausechr]\n"
2111 "       Send the given file, allowing playback to be controled by the given\n"
2112 " digits, if any. Use double quotes for the digits if you wish none to be\n"
2113 " permitted.  Returns 0 if playback completes without a digit\n"
2114 " being pressed, or the ASCII numerical value of the digit if one was pressed,\n"
2115 " or -1 on error or if the channel was disconnected. Remember, the file\n"
2116 " extension must not be included in the filename.\n\n"
2117 " Note: ffchar and rewchar default to * and # respectively.\n";
2118
2119 static char usage_getoption[] = 
2120 " Usage: GET OPTION <filename> <escape_digits> [timeout]\n"
2121 "       Behaves similar to STREAM FILE but used with a timeout option.\n";
2122
2123 static char usage_saynumber[] =
2124 " Usage: SAY NUMBER <number> <escape digits> [gender]\n"
2125 "       Say a given number, returning early if any of the given DTMF digits\n"
2126 " are received on the channel.  Returns 0 if playback completes without a digit\n"
2127 " being pressed, or the ASCII numerical value of the digit if one was pressed or\n"
2128 " -1 on error/hangup.\n";
2129
2130 static char usage_saydigits[] =
2131 " Usage: SAY DIGITS <number> <escape digits>\n"
2132 "       Say a given digit string, returning early if any of the given DTMF digits\n"
2133 " are received on the channel. Returns 0 if playback completes without a digit\n"
2134 " being pressed, or the ASCII numerical value of the digit if one was pressed or\n"
2135 " -1 on error/hangup.\n";
2136
2137 static char usage_sayalpha[] =
2138 " Usage: SAY ALPHA <number> <escape digits>\n"
2139 "       Say a given character string, returning early if any of the given DTMF digits\n"
2140 " are received on the channel. Returns 0 if playback completes without a digit\n"
2141 " being pressed, or the ASCII numerical value of the digit if one was pressed or\n"
2142 " -1 on error/hangup.\n";
2143
2144 static char usage_saydate[] =
2145 " Usage: SAY DATE <date> <escape digits>\n"
2146 "       Say a given date, returning early if any of the given DTMF digits are\n"
2147 " received on the channel.  <date> is number of seconds elapsed since 00:00:00\n"
2148 " on January 1, 1970, Coordinated Universal Time (UTC). Returns 0 if playback\n"
2149 " completes without a digit being pressed, or the ASCII numerical value of the\n"
2150 " digit if one was pressed or -1 on error/hangup.\n";
2151
2152 static char usage_saytime[] =
2153 " Usage: SAY TIME <time> <escape digits>\n"
2154 "       Say a given time, returning early if any of the given DTMF digits are\n"
2155 " received on the channel.  <time> is number of seconds elapsed since 00:00:00\n"
2156 " on January 1, 1970, Coordinated Universal Time (UTC). Returns 0 if playback\n"
2157 " completes without a digit being pressed, or the ASCII numerical value of the\n"
2158 " digit if one was pressed or -1 on error/hangup.\n";
2159
2160 static char usage_saydatetime[] =
2161 " Usage: SAY DATETIME <time> <escape digits> [format] [timezone]\n"
2162 "       Say a given time, returning early if any of the given DTMF digits are\n"
2163 " received on the channel.  <time> is number of seconds elapsed since 00:00:00\n"
2164 " on January 1, 1970, Coordinated Universal Time (UTC). [format] is the format\n"
2165 " the time should be said in.  See voicemail.conf (defaults to \"ABdY\n"
2166 " 'digits/at' IMp\").  Acceptable values for [timezone] can be found in\n"
2167 " /usr/share/zoneinfo.  Defaults to machine default. Returns 0 if playback\n"
2168 " completes without a digit being pressed, or the ASCII numerical value of the\n"
2169 " digit if one was pressed or -1 on error/hangup.\n";
2170
2171 static char usage_sayphonetic[] =
2172 " Usage: SAY PHONETIC <string> <escape digits>\n"
2173 "       Say a given character string with phonetics, returning early if any of the\n"
2174 " given DTMF digits are received on the channel. Returns 0 if playback\n"
2175 " completes without a digit pressed, the ASCII numerical value of the digit\n"
2176 " if one was pressed, or -1 on error/hangup.\n";
2177
2178 static char usage_getdata[] =
2179 " Usage: GET DATA <file to be streamed> [timeout] [max digits]\n"
2180 "       Stream the given file, and recieve DTMF data. Returns the digits received\n"
2181 "from the channel at the other end.\n";
2182
2183 static char usage_setcontext[] =
2184 " Usage: SET CONTEXT <desired context>\n"
2185 "       Sets the context for continuation upon exiting the application.\n";
2186
2187 static char usage_setextension[] =
2188 " Usage: SET EXTENSION <new extension>\n"
2189 "       Changes the extension for continuation upon exiting the application.\n";
2190
2191 static char usage_setpriority[] =
2192 " Usage: SET PRIORITY <priority>\n"
2193 "       Changes the priority for continuation upon exiting the application.\n"
2194 " The priority must be a valid priority or label.\n";
2195
2196 static char usage_recordfile[] =
2197 " Usage: RECORD FILE <filename> <format> <escape digits> <timeout> \\\n"
2198 "                                          [offset samples] [BEEP] [s=silence]\n"
2199 "       Record to a file until a given dtmf digit in the sequence is received\n"
2200 " Returns -1 on hangup or error.  The format will specify what kind of file\n"
2201 " will be recorded.  The timeout is the maximum record time in milliseconds, or\n"
2202 " -1 for no timeout. \"Offset samples\" is optional, and, if provided, will seek\n"
2203 " to the offset without exceeding the end of the file.  \"silence\" is the number\n"
2204 " of seconds of silence allowed before the function returns despite the\n"
2205 " lack of dtmf digits or reaching timeout.  Silence value must be\n"
2206 " preceeded by \"s=\" and is also optional.\n";
2207
2208 static char usage_autohangup[] =
2209 " Usage: SET AUTOHANGUP <time>\n"
2210 "       Cause the channel to automatically hangup at <time> seconds in the\n"
2211 " future.  Of course it can be hungup before then as well. Setting to 0 will\n"
2212 " cause the autohangup feature to be disabled on this channel.\n";
2213
2214 static char usage_break_aagi[] =
2215 " Usage: ASYNCAGI BREAK\n"
2216 "       Break the Async AGI loop.\n";
2217
2218 static char usage_noop[] =
2219 " Usage: NoOp\n"
2220 "       Does nothing.\n";
2221
2222 static char usage_speechcreate[] =
2223 " Usage: SPEECH CREATE <engine>\n"
2224 "       Create a speech object to be used by the other Speech AGI commands.\n";
2225
2226 static char usage_speechset[] =
2227 " Usage: SPEECH SET <name> <value>\n"
2228 "       Set an engine-specific setting.\n";
2229
2230 static char usage_speechdestroy[] =
2231 " Usage: SPEECH DESTROY\n"
2232 "       Destroy the speech object created by SPEECH CREATE.\n";
2233
2234 static char usage_speechloadgrammar[] =
2235 " Usage: SPEECH LOAD GRAMMAR <grammar name> <path to grammar>\n"
2236 "       Loads the specified grammar as the specified name.\n";
2237
2238 static char usage_speechunloadgrammar[] =
2239 " Usage: SPEECH UNLOAD GRAMMAR <grammar name>\n"
2240 "       Unloads the specified grammar.\n";
2241
2242 static char usage_speechactivategrammar[] =
2243 " Usage: SPEECH ACTIVATE GRAMMAR <grammar name>\n"
2244 "       Activates the specified grammar on the speech object.\n";
2245
2246 static char usage_speechdeactivategrammar[] =
2247 " Usage: SPEECH DEACTIVATE GRAMMAR <grammar name>\n"
2248 "       Deactivates the specified grammar on the speech object.\n";
2249
2250 static char usage_speechrecognize[] =
2251 " Usage: SPEECH RECOGNIZE <prompt> <timeout> [<offset>]\n"
2252 "       Plays back given prompt while listening for speech and dtmf.\n";
2253
2254 /*!
2255  * \brief AGI commands list
2256  */
2257 static struct agi_command commands[] = {
2258         { { "answer", NULL }, handle_answer, "Answer channel", usage_answer , 0 },
2259         { { "channel", "status", NULL }, handle_channelstatus, "Returns status of the connected channel", usage_channelstatus , 0 },
2260         { { "database", "del", NULL }, handle_dbdel, "Removes database key/value", usage_dbdel , 1 },
2261         { { "database", "deltree", NULL }, handle_dbdeltree, "Removes database keytree/value", usage_dbdeltree , 1 },
2262         { { "database", "get", NULL }, handle_dbget, "Gets database value", usage_dbget , 1 },
2263         { { "database", "put", NULL }, handle_dbput, "Adds/updates database value", usage_dbput , 1 },
2264         { { "exec", NULL }, handle_exec, "Executes a given Application", usage_exec , 1 },
2265         { { "get", "data", NULL }, handle_getdata, "Prompts for DTMF on a channel", usage_getdata , 0 },
2266         { { "get", "full", "variable", NULL }, handle_getvariablefull, "Evaluates a channel expression", usage_getvariablefull , 1 },
2267         { { "get", "option", NULL }, handle_getoption, "Stream file, prompt for DTMF, with timeout", usage_getoption , 0 },
2268         { { "get", "variable", NULL }, handle_getvariable, "Gets a channel variable", usage_getvariable , 1 },
2269         { { "hangup", NULL }, handle_hangup, "Hangup the current channel", usage_hangup , 0 },
2270         { { "noop", NULL }, handle_noop, "Does nothing", usage_noop , 1 },
2271         { { "receive", "char", NULL }, handle_recvchar, "Receives one character from channels supporting it", usage_recvchar , 0 },
2272         { { "receive", "text", NULL }, handle_recvtext, "Receives text from channels supporting it", usage_recvtext , 0 },
2273         { { "record", "file", NULL }, handle_recordfile, "Records to a given file", usage_recordfile , 0 },
2274         { { "say", "alpha", NULL }, handle_sayalpha, "Says a given character string", usage_sayalpha , 0 },
2275         { { "say", "digits", NULL }, handle_saydigits, "Says a given digit string", usage_saydigits , 0 },
2276         { { "say", "number", NULL }, handle_saynumber, "Says a given number", usage_saynumber , 0 },
2277         { { "say", "phonetic", NULL }, handle_sayphonetic, "Says a given character string with phonetics", usage_sayphonetic , 0 },
2278         { { "say", "date", NULL }, handle_saydate, "Says a given date", usage_saydate , 0 },
2279         { { "say", "time", NULL }, handle_saytime, "Says a given time", usage_saytime , 0 },
2280         { { "say", "datetime", NULL }, handle_saydatetime, "Says a given time as specfied by the format given", usage_saydatetime , 0 },
2281         { { "send", "image", NULL }, handle_sendimage, "Sends images to channels supporting it", usage_sendimage , 0 },
2282         { { "send", "text", NULL }, handle_sendtext, "Sends text to channels supporting it", usage_sendtext , 0 },
2283         { { "set", "autohangup", NULL }, handle_autohangup, "Autohangup channel in some time", usage_autohangup , 0 },
2284         { { "set", "callerid", NULL }, handle_setcallerid, "Sets callerid for the current channel", usage_setcallerid , 0 },
2285         { { "set", "context", NULL }, handle_setcontext, "Sets channel context", usage_setcontext , 0 },
2286         { { "set", "extension", NULL }, handle_setextension, "Changes channel extension", usage_setextension , 0 },
2287         { { "set", "music", NULL }, handle_setmusic, "Enable/Disable Music on hold generator", usage_setmusic , 0 },
2288         { { "set", "priority", NULL }, handle_setpriority, "Set channel dialplan priority", usage_setpriority , 0 },
2289         { { "set", "variable", NULL }, handle_setvariable, "Sets a channel variable", usage_setvariable , 1 },
2290         { { "stream", "file", NULL }, handle_streamfile, "Sends audio file on channel", usage_streamfile , 0 },
2291         { { "control", "stream", "file", NULL }, handle_controlstreamfile, "Sends audio file on channel and allows the listner to control the stream", usage_controlstreamfile , 0 },
2292         { { "tdd", "mode", NULL }, handle_tddmode, "Toggles TDD mode (for the deaf)", usage_tddmode , 0 },
2293         { { "verbose", NULL }, handle_verbose, "Logs a message to the asterisk verbose log", usage_verbose , 1 },
2294         { { "wait", "for", "digit", NULL }, handle_waitfordigit, "Waits for a digit to be pressed", usage_waitfordigit , 0 },
2295         { { "speech", "create", NULL }, handle_speechcreate, "Creates a speech object", usage_speechcreate, 0 },
2296         { { "speech", "set", NULL }, handle_speechset, "Sets a speech engine setting", usage_speechset, 0 },
2297         { { "speech", "destroy", NULL }, handle_speechdestroy, "Destroys a speech object", usage_speechdestroy, 1 },
2298         { { "speech", "load", "grammar", NULL }, handle_speechloadgrammar, "Loads a grammar", usage_speechloadgrammar, 0 },
2299         { { "speech", "unload", "grammar", NULL }, handle_speechunloadgrammar, "Unloads a grammar", usage_speechunloadgrammar, 1 },
2300         { { "speech", "activate", "grammar", NULL }, handle_speechactivategrammar, "Activates a grammar", usage_speechactivategrammar, 0 },
2301         { { "speech", "deactivate", "grammar", NULL }, handle_speechdeactivategrammar, "Deactivates a grammar", usage_speechdeactivategrammar, 0 },
2302         { { "speech", "recognize", NULL }, handle_speechrecognize, "Recognizes speech", usage_speechrecognize, 0 },
2303         { { "asyncagi", "break", NULL }, handle_asyncagi_break, "Break AsyncAGI loop", usage_break_aagi, 0 },
2304 };
2305
2306 static AST_RWLIST_HEAD_STATIC(agi_commands, agi_command);
2307
2308 static char *help_workhorse(int fd, char *match[])
2309 {
2310         char fullcmd[80], matchstr[80];
2311         struct agi_command *e;
2312
2313         if (match)
2314                 ast_join(matchstr, sizeof(matchstr), match);
2315
2316         ast_cli(fd, "%5.5s %30.30s   %s\n","Dead","Command","Description");
2317         AST_RWLIST_RDLOCK(&agi_commands);
2318         AST_RWLIST_TRAVERSE(&agi_commands, e, list) {
2319                 if (!e->cmda[0])
2320                         break;
2321                 /* Hide commands that start with '_' */
2322                 if ((e->cmda[0])[0] == '_')
2323                         continue;
2324                 ast_join(fullcmd, sizeof(fullcmd), e->cmda);
2325                 if (match && strncasecmp(matchstr, fullcmd, strlen(matchstr)))
2326                         continue;
2327                 ast_cli(fd, "%5.5s %30.30s   %s\n", e->dead ? "Yes" : "No" , fullcmd, e->summary);
2328         }
2329         AST_RWLIST_UNLOCK(&agi_commands);
2330
2331         return CLI_SUCCESS;
2332 }
2333
2334 int ast_agi_register(struct ast_module *mod, agi_command *cmd)
2335 {
2336         char fullcmd[80];
2337
2338         ast_join(fullcmd, sizeof(fullcmd), cmd->cmda);
2339
2340         if (!find_command(cmd->cmda,1)) {
2341                 cmd->mod = mod;
2342                 AST_RWLIST_WRLOCK(&agi_commands);
2343                 AST_LIST_INSERT_TAIL(&agi_commands, cmd, list);
2344                 AST_RWLIST_UNLOCK(&agi_commands);
2345                 if (mod != ast_module_info->self)
2346                         ast_module_ref(ast_module_info->self);
2347                 ast_verb(2, "AGI Command '%s' registered\n",fullcmd);
2348                 return 1;
2349         } else {
2350                 ast_log(LOG_WARNING, "Command already registered!\n");
2351                 return 0;
2352         }
2353 }
2354
2355 int ast_agi_unregister(struct ast_module *mod, agi_command *cmd)
2356 {
2357         struct agi_command *e;
2358         int unregistered = 0;
2359         char fullcmd[80];
2360         
2361         ast_join(fullcmd, sizeof(fullcmd), cmd->cmda);
2362
2363         AST_RWLIST_WRLOCK(&agi_commands);
2364         AST_RWLIST_TRAVERSE_SAFE_BEGIN(&agi_commands, e, list) {
2365                 if (cmd == e) {
2366                         AST_RWLIST_REMOVE_CURRENT(list);
2367                         if (mod != ast_module_info->self)
2368                                 ast_module_unref(ast_module_info->self);
2369                         unregistered=1;
2370                         break;
2371                 }
2372         }
2373         AST_RWLIST_TRAVERSE_SAFE_END;
2374         AST_RWLIST_UNLOCK(&agi_commands);
2375         if (unregistered)
2376                 ast_verb(2, "AGI Command '%s' unregistered\n",fullcmd);
2377         else
2378                 ast_log(LOG_WARNING, "Unable to unregister command: '%s'!\n",fullcmd);
2379         return unregistered;
2380 }
2381
2382 void ast_agi_register_multiple(struct ast_module *mod, agi_command *cmd, int len)
2383 {
2384         int i;
2385
2386         for (i = 0; i < len; i++)
2387                 ast_agi_register(mod, cmd + i);
2388
2389 }
2390
2391 void ast_agi_unregister_multiple(struct ast_module *mod, agi_command *cmd, int len)
2392 {
2393         int i;
2394
2395         for (i = 0; i < len; i++)
2396                 ast_agi_unregister(mod, cmd + i);
2397 }
2398
2399 static agi_command *find_command(char *cmds[], int exact)
2400 {
2401         int y, match;
2402         struct agi_command *e;
2403
2404         AST_RWLIST_RDLOCK(&agi_commands);
2405         AST_RWLIST_TRAVERSE(&agi_commands, e, list) {
2406                 if (!e->cmda[0])
2407                         break;
2408                 /* start optimistic */
2409                 match = 1;
2410                 for (y = 0; match && cmds[y]; y++) {
2411                         /* If there are no more words in the command (and we're looking for
2412                            an exact match) or there is a difference between the two words,
2413                            then this is not a match */
2414                         if (!e->cmda[y] && !exact)
2415                                 break;
2416                         /* don't segfault if the next part of a command doesn't exist */
2417                         if (!e->cmda[y])
2418                                 return NULL;
2419                         if (strcasecmp(e->cmda[y], cmds[y]))
2420                                 match = 0;
2421                 }
2422                 /* If more words are needed to complete the command then this is not
2423                    a candidate (unless we're looking for a really inexact answer  */
2424                 if ((exact > -1) && e->cmda[y])
2425                         match = 0;
2426                 if (match)
2427                         return e;
2428         }
2429         AST_RWLIST_UNLOCK(&agi_commands);
2430         return NULL;
2431 }
2432
2433 static int parse_args(char *s, int *max, char *argv[])
2434 {
2435         int x = 0, quoted = 0, escaped = 0, whitespace = 1;
2436         char *cur;
2437
2438         cur = s;
2439         while(*s) {
2440                 switch(*s) {
2441                 case '"':
2442                         /* If it's escaped, put a literal quote */
2443                         if (escaped) 
2444                                 goto normal;
2445                         else 
2446                                 quoted = !quoted;
2447                         if (quoted && whitespace) {
2448                                 /* If we're starting a quote, coming off white space start a new word, too */
2449                                 argv[x++] = cur;
2450                                 whitespace=0;
2451                         }
2452                         escaped = 0;
2453                 break;
2454                 case ' ':
2455                 case '\t':
2456                         if (!quoted && !escaped) {
2457                                 /* If we're not quoted, mark this as whitespace, and
2458                                    end the previous argument */
2459                                 whitespace = 1;
2460                                 *(cur++) = '\0';
2461                         } else
2462                                 /* Otherwise, just treat it as anything else */ 
2463                                 goto normal;
2464                         break;
2465                 case '\\':
2466                         /* If we're escaped, print a literal, otherwise enable escaping */
2467                         if (escaped) {
2468                                 goto normal;
2469                         } else {
2470                                 escaped=1;
2471                         }
2472                         break;
2473                 default:
2474 normal:
2475                         if (whitespace) {
2476                                 if (x >= MAX_ARGS -1) {
2477                                         ast_log(LOG_WARNING, "Too many arguments, truncating\n");
2478                                         break;
2479                                 }
2480                                 /* Coming off of whitespace, start the next argument */
2481                                 argv[x++] = cur;
2482                                 whitespace=0;
2483                         }
2484                         *(cur++) = *s;
2485                         escaped=0;
2486                 }
2487                 s++;
2488         }
2489         /* Null terminate */
2490         *(cur++) = '\0';
2491         argv[x] = NULL;
2492         *max = x;
2493         return 0;
2494 }
2495
2496 static int agi_handle_command(struct ast_channel *chan, AGI *agi, char *buf, int dead)
2497 {
2498         char *argv[MAX_ARGS];
2499         int argc = MAX_ARGS, res;
2500         agi_command *c;
2501         const char *ami_res = "Unknown Result";
2502         char *ami_cmd = ast_strdupa(buf);
2503         int command_id = ast_random(), resultcode = 200;
2504
2505         manager_event(EVENT_FLAG_CALL, "AGIExec", 
2506                         "SubEvent: Start\r\n"
2507                         "Channel: %s\r\n"
2508                         "CommandId: %d\r\n"
2509                         "Command: %s\r\n", chan->name, command_id, ami_cmd);
2510         parse_args(buf, &argc, argv);
2511         if ((c = find_command(argv, 0)) && (!dead || (dead && c->dead))) {
2512                 /* if this command wasnt registered by res_agi, be sure to usecount
2513                 the module we are using */
2514                 if (c->mod != ast_module_info->self)
2515                         ast_module_ref(c->mod);
2516                 res = c->handler(chan, agi, argc, argv);
2517                 if (c->mod != ast_module_info->self)
2518                         ast_module_unref(c->mod);
2519                 switch (res) {
2520                 case RESULT_SHOWUSAGE: ami_res = "Usage"; resultcode = 520; break;
2521                 case AST_PBX_KEEPALIVE: ami_res = "KeepAlive"; resultcode = 210; break;
2522                 case RESULT_FAILURE: ami_res = "Failure"; resultcode = -1; break;
2523                 case RESULT_SUCCESS: ami_res = "Success"; resultcode = 200; break;
2524                 }
2525                 manager_event(EVENT_FLAG_CALL, "AGIExec",
2526                                 "SubEvent: End\r\n"
2527                                 "Channel: %s\r\n"
2528                                 "CommandId: %d\r\n"
2529                                 "Command: %s\r\n"
2530                                 "ResultCode: %d\r\n"
2531                                 "Result: %s\r\n", chan->name, command_id, ami_cmd, resultcode, ami_res);
2532                 switch(res) {
2533                 case RESULT_SHOWUSAGE:
2534                         ast_agi_fdprintf(chan, agi->fd, "520-Invalid command syntax.  Proper usage follows:\n");
2535                         ast_agi_fdprintf(chan, agi->fd, c->usage);
2536                         ast_agi_fdprintf(chan, agi->fd, "520 End of proper usage.\n");
2537                         break;
2538                 case AST_PBX_KEEPALIVE:
2539                         /* We've been asked to keep alive, so do so */
2540                         return AST_PBX_KEEPALIVE;
2541                         break;
2542                 case RESULT_FAILURE:
2543                         /* They've already given the failure.  We've been hung up on so handle this
2544                            appropriately */
2545                         return -1;
2546                 }
2547         } else if ((c = find_command(argv, 0))) {
2548                 ast_agi_fdprintf(chan, agi->fd, "511 Command Not Permitted on a dead channel\n");
2549                 manager_event(EVENT_FLAG_CALL, "AGIExec",
2550                                 "SubEvent: End\r\n"
2551                                 "Channel: %s\r\n"
2552                                 "CommandId: %d\r\n"
2553                                 "Command: %s\r\n"
2554                                 "ResultCode: 511\r\n"
2555                                 "Result: Command not permitted on a dead channel\r\n", chan->name, command_id, ami_cmd);
2556         } else {
2557                 ast_agi_fdprintf(chan, agi->fd, "510 Invalid or unknown command\n");
2558                 manager_event(EVENT_FLAG_CALL, "AGIExec",
2559                                 "SubEvent: End\r\n"
2560                                 "Channel: %s\r\n"
2561                                 "CommandId: %d\r\n"
2562                                 "Command: %s\r\n"
2563                                 "ResultCode: 510\r\n"
2564                                 "Result: Invalid or unknown command\r\n", chan->name, command_id, ami_cmd);
2565         }
2566         return 0;
2567 }
2568 static enum agi_result run_agi(struct ast_channel *chan, char *request, AGI *agi, int pid, int *status, int dead, int argc, char *argv[])
2569 {
2570         struct ast_channel *c;
2571         int outfd, ms, needhup = 0;
2572         enum agi_result returnstatus = AGI_RESULT_SUCCESS;
2573         struct ast_frame *f;
2574         char buf[AGI_BUF_LEN];
2575         char *res = NULL;
2576         FILE *readf;
2577         /* how many times we'll retry if ast_waitfor_nandfs will return without either 
2578           channel or file descriptor in case select is interrupted by a system call (EINTR) */
2579         int retry = AGI_NANDFS_RETRY;
2580
2581         if (!(readf = fdopen(agi->ctrl, "r"))) {
2582                 ast_log(LOG_WARNING, "Unable to fdopen file descriptor\n");
2583                 if (pid > -1)
2584                         kill(pid, SIGHUP);
2585                 close(agi->ctrl);
2586                 return AGI_RESULT_FAILURE;
2587         }
2588         setlinebuf(readf);
2589         setup_env(chan, request, agi->fd, (agi->audio > -1), argc, argv);
2590         for (;;) {
2591                 if (needhup) {
2592                         needhup = 0;
2593                         dead = 1;
2594                         if (pid > -1)
2595                                 kill(pid, SIGHUP);
2596                 }
2597                 ms = -1;
2598                 c = ast_waitfor_nandfds(&chan, dead ? 0 : 1, &agi->ctrl, 1, NULL, &outfd, &ms);
2599                 if (c) {
2600                         retry = AGI_NANDFS_RETRY;
2601                         /* Idle the channel until we get a command */
2602                         f = ast_read(c);
2603                         if (!f) {
2604                                 ast_debug(1, "%s hungup\n", chan->name);
2605                                 returnstatus = AGI_RESULT_HANGUP;
2606                                 needhup = 1;
2607                                 continue;
2608                         } else {
2609                                 /* If it's voice, write it to the audio pipe */
2610                                 if ((agi->audio > -1) && (f->frametype == AST_FRAME_VOICE)) {
2611                                         /* Write, ignoring errors */
2612                                         write(agi->audio, f->data, f->datalen);
2613                                 }
2614                                 ast_frfree(f);
2615                         }
2616                 } else if (outfd > -1) {
2617                         size_t len = sizeof(buf);
2618                         size_t buflen = 0;
2619
2620                         retry = AGI_NANDFS_RETRY;
2621                         buf[0] = '\0';
2622
2623                         while (buflen < (len - 1)) {
2624                                 res = fgets(buf + buflen, len, readf);
2625                                 if (feof(readf)) 
2626                                         break;
2627                                 if (ferror(readf) && ((errno != EINTR) && (errno != EAGAIN))) 
2628                                         break;
2629                                 if (res != NULL && !agi->fast)
2630                                         break;
2631                                 buflen = strlen(buf);
2632                                 if (buflen && buf[buflen - 1] == '\n')
2633                                         break;
2634                                 len -= buflen;
2635                                 if (agidebug)
2636                                         ast_verbose( "AGI Rx << temp buffer %s - errno %s\n", buf, strerror(errno));
2637                         }
2638
2639                         if (!buf[0]) {
2640                                 /* Program terminated */
2641                                 if (returnstatus && returnstatus != AST_PBX_KEEPALIVE)
2642                                         returnstatus = -1;
2643                                 ast_verb(3, "<%s>AGI Script %s completed, returning %d\n", chan->name, request, returnstatus);
2644                                 if (pid > 0)
2645                                         waitpid(pid, status, 0);
2646                                 /* No need to kill the pid anymore, since they closed us */
2647                                 pid = -1;
2648                                 break;
2649                         }
2650
2651                         /* Special case for inability to execute child process */
2652                         if (*buf && strncasecmp(buf, "failure", 7) == 0) {
2653                                 returnstatus = AGI_RESULT_FAILURE;
2654                                 break;
2655                         }
2656
2657                         /* get rid of trailing newline, if any */
2658                         if (*buf && buf[strlen(buf) - 1] == '\n')
2659                                 buf[strlen(buf) - 1] = 0;
2660                         if (agidebug)
2661                                 ast_verbose("<%s>AGI Rx << %s\n", chan->name, buf);
2662                         returnstatus |= agi_handle_command(chan, agi, buf, dead);
2663                         /* If the handle_command returns -1, we need to stop */
2664                         if ((returnstatus < 0) || (returnstatus == AST_PBX_KEEPALIVE)) {
2665                                 needhup = 1;
2666                                 continue;
2667                         }
2668                 } else {
2669                         if (--retry <= 0) {
2670                                 ast_log(LOG_WARNING, "No channel, no fd?\n");
2671                                 returnstatus = AGI_RESULT_FAILURE;
2672                                 break;
2673                         }
2674                 }
2675         }
2676         /* Notify process */
2677         if (pid > -1) {
2678                 const char *sighup = pbx_builtin_getvar_helper(chan, "AGISIGHUP");
2679                 if (ast_strlen_zero(sighup) || !ast_false(sighup)) {
2680                         if (kill(pid, SIGHUP))
2681                                 ast_log(LOG_WARNING, "unable to send SIGHUP to AGI process %d: %s\n", pid, strerror(errno));
2682                 }
2683         }
2684         fclose(readf);
2685         return returnstatus;
2686 }
2687
2688 static char *handle_cli_agi_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2689 {
2690         struct agi_command *command;
2691         char fullcmd[80];
2692
2693         switch (cmd) {
2694         case CLI_INIT:
2695                 e->command = "agi show";
2696                 e->usage =
2697                         "Usage: agi show [topic]\n"
2698                         "       When called with a topic as an argument, displays usage\n"
2699                         "       information on the given command.  If called without a\n"
2700                         "       topic, it provides a list of AGI commands.\n";
2701                 break;
2702         case CLI_GENERATE:
2703                 return NULL;
2704         }
2705         if (a->argc < e->args)
2706                 return CLI_SHOWUSAGE;
2707         if (a->argc > e->args) {
2708                 command = find_command(a->argv + e->args, 1);
2709                 if (command) {
2710                         ast_cli(a->fd, "%s", command->usage);
2711                         ast_cli(a->fd, " Runs Dead : %s\n", command->dead ? "Yes" : "No");
2712                 } else {
2713                         if (find_command(a->argv + e->args, -1)) {
2714                                 return help_workhorse(a->fd, a->argv + e->args);
2715                         } else {
2716                                 ast_join(fullcmd, sizeof(fullcmd), a->argv + e->args);
2717                                 ast_cli(a->fd, "No such command '%s'.\n", fullcmd);
2718                         }
2719                 }
2720         } else {
2721                 return help_workhorse(a->fd, NULL);
2722         }
2723         return CLI_SUCCESS;
2724 }
2725
2726 /*! \brief Convert string to use HTML escaped characters
2727         \note Maybe this should be a generic function?
2728 */
2729 static void write_html_escaped(FILE *htmlfile, char *str)
2730 {
2731         char *cur = str;
2732
2733         while(*cur) {
2734                 switch (*cur) {
2735                 case '<':
2736                         fprintf(htmlfile, "%s", "&lt;");
2737                         break;
2738                 case '>':
2739                         fprintf(htmlfile, "%s", "&gt;");
2740                         break;
2741                 case '&':
2742                         fprintf(htmlfile, "%s", "&amp;");
2743                         break;
2744                 case '"':
2745                         fprintf(htmlfile, "%s", "&quot;");
2746                         break;
2747                 default:
2748                         fprintf(htmlfile, "%c", *cur);
2749                         break;
2750                 }
2751                 cur++;
2752         }
2753
2754         return;
2755 }
2756
2757 static int write_htmldump(char *filename)
2758 {
2759         struct agi_command *command;
2760         char fullcmd[80];
2761         FILE *htmlfile;
2762
2763         if (!(htmlfile = fopen(filename, "wt")))
2764                 return -1;
2765
2766         fprintf(htmlfile, "<HTML>\n<HEAD>\n<TITLE>AGI Commands</TITLE>\n</HEAD>\n");
2767         fprintf(htmlfile, "<BODY>\n<CENTER><B><H1>AGI Commands</H1></B></CENTER>\n\n");
2768         fprintf(htmlfile, "<TABLE BORDER=\"0\" CELLSPACING=\"10\">\n");
2769
2770         AST_RWLIST_RDLOCK(&agi_commands);
2771         AST_RWLIST_TRAVERSE(&agi_commands, command, list) {
2772                 char *stringp, *tempstr;
2773  
2774                 if (!command->cmda[0])  /* end ? */
2775                         break;
2776                 /* Hide commands that start with '_' */
2777                 if ((command->cmda[0])[0] == '_')
2778                         continue;
2779                 ast_join(fullcmd, sizeof(fullcmd), command->cmda);
2780
2781                 fprintf(htmlfile, "<TR><TD><TABLE BORDER=\"1\" CELLPADDING=\"5\" WIDTH=\"100%%\">\n");
2782                 fprintf(htmlfile, "<TR><TH ALIGN=\"CENTER\"><B>%s - %s</B></TH></TR>\n", fullcmd, command->summary);
2783
2784                 stringp = command->usage;
2785                 tempstr = strsep(&stringp, "\n");
2786
2787                 fprintf(htmlfile, "<TR><TD ALIGN=\"CENTER\">");
2788                 write_html_escaped(htmlfile, tempstr);
2789                 fprintf(htmlfile, "</TD></TR>\n");
2790                 fprintf(htmlfile, "<TR><TD ALIGN=\"CENTER\">\n");
2791
2792                 while ((tempstr = strsep(&stringp, "\n")) != NULL) {
2793                         write_html_escaped(htmlfile, tempstr);
2794                         fprintf(htmlfile, "<BR>\n");
2795                 }
2796                 fprintf(htmlfile, "</TD></TR>\n");
2797                 fprintf(htmlfile, "</TABLE></TD></TR>\n\n");
2798         }
2799         AST_RWLIST_UNLOCK(&agi_commands);
2800         fprintf(htmlfile, "</TABLE>\n</BODY>\n</HTML>\n");
2801         fclose(htmlfile);
2802         return 0;
2803 }
2804
2805 static char *handle_cli_agi_dumphtml_deprecated(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2806 {
2807         switch (cmd) {
2808         case CLI_INIT:
2809                 e->command = "agi dumphtml";
2810                 e->usage =
2811                         "Usage: agi dumphtml <filename>\n"
2812                         "       Dumps the AGI command list in HTML format to the given\n"
2813                         "       file.\n";
2814                 return NULL;
2815         case CLI_GENERATE:
2816                 return NULL;
2817         }
2818         if (a->argc < e->args + 1)
2819                 return CLI_SHOWUSAGE;
2820
2821         if (write_htmldump(a->argv[2]) < 0) {
2822                 ast_cli(a->fd, "Could not create file '%s'\n", a->argv[2]);
2823                 return CLI_SHOWUSAGE;
2824         }
2825         ast_cli(a->fd, "AGI HTML commands dumped to: %s\n", a->argv[2]);
2826         return CLI_SUCCESS;
2827 }
2828
2829 static char *handle_cli_agi_dump_html(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2830 {
2831         switch (cmd) {
2832         case CLI_INIT:
2833                 e->command = "agi dump html";
2834                 e->usage =
2835                         "Usage: agi dump html <filename>\n"
2836                         "       Dumps the AGI command list in HTML format to the given\n"
2837                         "       file.\n";
2838                 return NULL;
2839         case CLI_GENERATE:
2840                 return NULL;
2841         }
2842         if (a->argc != e->args + 1)
2843                 return CLI_SHOWUSAGE;
2844
2845         if (write_htmldump(a->argv[e->args]) < 0) {
2846                 ast_cli(a->fd, "Could not create file '%s'\n", a->argv[e->args]);
2847                 return CLI_SHOWUSAGE;
2848         }
2849         ast_cli(a->fd, "AGI HTML commands dumped to: %s\n", a->argv[e->args]);
2850         return CLI_SUCCESS;
2851 }
2852
2853 static int agi_exec_full(struct ast_channel *chan, void *data, int enhanced, int dead)
2854 {
2855         enum agi_result res;
2856         char buf[AGI_BUF_LEN] = "", *tmp = buf;
2857         int fds[2], efd = -1, pid;
2858         AST_DECLARE_APP_ARGS(args,
2859                 AST_APP_ARG(arg)[MAX_ARGS];
2860         );
2861         AGI agi;
2862
2863         if (ast_strlen_zero(data)) {
2864                 ast_log(LOG_WARNING, "AGI requires an argument (script)\n");
2865                 return -1;
2866         }
2867         if (dead)
2868                 ast_debug(3, "Hungup channel detected, running agi in dead mode.\n");
2869         ast_copy_string(buf, data, sizeof(buf));
2870         memset(&agi, 0, sizeof(agi));
2871         AST_STANDARD_APP_ARGS(args, tmp);
2872         args.argv[args.argc] = NULL;
2873 #if 0
2874          /* Answer if need be */
2875         if (chan->_state != AST_STATE_UP) {
2876                 if (ast_answer(chan))
2877                         return -1;
2878         }
2879 #endif
2880         res = launch_script(chan, args.argv[0], args.argv, fds, enhanced ? &efd : NULL, &pid);
2881         /* Async AGI do not require run_agi(), so just proceed if normal AGI
2882            or Fast AGI are setup with success. */
2883         if (res == AGI_RESULT_SUCCESS || res == AGI_RESULT_SUCCESS_FAST) {
2884                 int status = 0;
2885                 agi.fd = fds[1];
2886                 agi.ctrl = fds[0];
2887                 agi.audio = efd;
2888                 agi.fast = (res == AGI_RESULT_SUCCESS_FAST) ? 1 : 0;
2889                 res = run_agi(chan, args.argv[0], &agi, pid, &status, dead, args.argc, args.argv);
2890                 /* If the fork'd process returns non-zero, set AGISTATUS to FAILURE */
2891                 if ((res == AGI_RESULT_SUCCESS || res == AGI_RESULT_SUCCESS_FAST) && status)
2892                         res = AGI_RESULT_FAILURE;
2893                 if (fds[1] != fds[0])
2894                         close(fds[1]);
2895                 if (efd > -1)
2896                         close(efd);
2897         } 
2898         ast_safe_fork_cleanup();
2899
2900         switch (res) {
2901         case AGI_RESULT_SUCCESS:
2902         case AGI_RESULT_SUCCESS_FAST:
2903         case AGI_RESULT_SUCCESS_ASYNC:
2904                 pbx_builtin_setvar_helper(chan, "AGISTATUS", "SUCCESS");
2905                 break;
2906         case AGI_RESULT_FAILURE:
2907                 pbx_builtin_setvar_helper(chan, "AGISTATUS", "FAILURE");
2908                 break;
2909         case AGI_RESULT_NOTFOUND:
2910                 pbx_builtin_setvar_helper(chan, "AGISTATUS", "NOTFOUND");
2911                 break;
2912         case AGI_RESULT_HANGUP:
2913                 pbx_builtin_setvar_helper(chan, "AGISTATUS", "HANGUP");
2914                 return -1;
2915         }
2916
2917         return 0;
2918 }
2919
2920 static int agi_exec(struct ast_channel *chan, void *data)
2921 {
2922         if (!ast_check_hangup(chan))
2923                 return agi_exec_full(chan, data, 0, 0);
2924         else
2925                 return agi_exec_full(chan, data, 0, 1);
2926 }
2927
2928 static int eagi_exec(struct ast_channel *chan, void *data)
2929 {
2930         int readformat, res;
2931
2932         if (ast_check_hangup(chan)) {
2933                 ast_log(LOG_ERROR, "EAGI cannot be run on a dead/hungup channel, please use AGI.\n");
2934                 return 0;
2935         }
2936         readformat = chan->readformat;
2937         if (ast_set_read_format(chan, AST_FORMAT_SLINEAR)) {
2938                 ast_log(LOG_WARNING, "Unable to set channel '%s' to linear mode\n", chan->name);
2939                 return -1;
2940         }
2941         res = agi_exec_full(chan, data, 1, 0);
2942         if (!res) {
2943                 if (ast_set_read_format(chan, readformat)) {
2944                         ast_log(LOG_WARNING, "Unable to restore channel '%s' to format %s\n", chan->name, ast_getformatname(readformat));
2945                 }
2946         }
2947         return res;
2948 }
2949
2950 static int deadagi_exec(struct ast_channel *chan, void *data)
2951 {
2952         ast_log(LOG_WARNING, "DeadAGI has been deprecated, please use AGI in all cases!\n");
2953         return agi_exec(chan, data);
2954 }
2955
2956 static struct ast_cli_entry cli_agi_dumphtml_deprecated = AST_CLI_DEFINE(handle_cli_agi_dumphtml_deprecated, "Dumps a list of AGI commands in HTML format");
2957
2958 static struct ast_cli_entry cli_agi[] = {
2959         AST_CLI_DEFINE(handle_cli_agi_add_cmd,   "Add AGI command to a channel in Async AGI"),
2960         AST_CLI_DEFINE(handle_cli_agi_debug,     "Enable/Disable AGI debugging"),
2961         AST_CLI_DEFINE(handle_cli_agi_show,      "List AGI commands or specific help"),
2962         AST_CLI_DEFINE(handle_cli_agi_dump_html, "Dumps a list of AGI commands in HTML format", .deprecate_cmd = &cli_agi_dumphtml_deprecated)
2963 };
2964
2965 static int unload_module(void)
2966 {
2967         ast_cli_unregister_multiple(cli_agi, sizeof(cli_agi) / sizeof(struct ast_cli_entry));
2968         ast_agi_unregister_multiple(ast_module_info->self, commands, sizeof(commands) / sizeof(struct agi_command));
2969         ast_unregister_application(eapp);
2970         ast_unregister_application(deadapp);
2971         ast_manager_unregister("AGI");
2972         return ast_unregister_application(app);
2973 }
2974
2975 static int load_module(void)
2976 {
2977         ast_cli_register_multiple(cli_agi, sizeof(cli_agi) / sizeof(struct ast_cli_entry));
2978         ast_agi_register_multiple(ast_module_info->self, commands, sizeof(commands) / sizeof(struct agi_command));
2979         ast_register_application(deadapp, deadagi_exec, deadsynopsis, descrip);
2980         ast_register_application(eapp, eagi_exec, esynopsis, descrip);
2981         ast_manager_register2("AGI", EVENT_FLAG_CALL, action_add_agi_cmd, "Add an AGI command to execute by Async AGI", mandescr_asyncagi);
2982         return ast_register_application(app, agi_exec, synopsis, descrip);
2983 }
2984
2985 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS, "Asterisk Gateway Interface (AGI)",
2986                 .load = load_module,
2987                 .unload = unload_module,
2988                 );