4675b5fb6bf3dfaa1bc359c864ee19abbd5ab551
[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->dtimeoutms) {
984                 /* by default dtimeout is set to 5sec */
985                 timeout = chan->pbx->dtimeoutms; /* 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         double timeout;
1402         struct timeval whentohangup = { 0, 0 };
1403
1404         if (argc != 3)
1405                 return RESULT_SHOWUSAGE;
1406         if (sscanf(argv[2], "%lf", &timeout) != 1)
1407                 return RESULT_SHOWUSAGE;
1408         if (timeout < 0)
1409                 timeout = 0;
1410         if (timeout) {
1411                 whentohangup.tv_sec = timeout;
1412                 whentohangup.tv_usec = (timeout - whentohangup.tv_sec) * 1000000.0;
1413         }
1414         ast_channel_setwhentohangup_tv(chan, whentohangup);
1415         ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
1416         return RESULT_SUCCESS;
1417 }
1418
1419 static int handle_hangup(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1420 {
1421         struct ast_channel *c;
1422
1423         if (argc == 1) {
1424                 /* no argument: hangup the current channel */
1425                 ast_softhangup(chan,AST_SOFTHANGUP_EXPLICIT);
1426                 ast_agi_fdprintf(chan, agi->fd, "200 result=1\n");
1427                 return RESULT_SUCCESS;
1428         } else if (argc == 2) {
1429                 /* one argument: look for info on the specified channel */
1430                 c = ast_get_channel_by_name_locked(argv[1]);
1431                 if (c) {
1432                         /* we have a matching channel */
1433                         ast_softhangup(c,AST_SOFTHANGUP_EXPLICIT);
1434                         ast_agi_fdprintf(chan, agi->fd, "200 result=1\n");
1435                         ast_channel_unlock(c);
1436                         return RESULT_SUCCESS;
1437                 }
1438                 /* if we get this far no channel name matched the argument given */
1439                 ast_agi_fdprintf(chan, agi->fd, "200 result=-1\n");
1440                 return RESULT_SUCCESS;
1441         } else {
1442                 return RESULT_SHOWUSAGE;
1443         }
1444 }
1445
1446 static int handle_exec(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1447 {
1448         int res;
1449         struct ast_app *app;
1450
1451         if (argc < 2)
1452                 return RESULT_SHOWUSAGE;
1453
1454         ast_verb(3, "AGI Script Executing Application: (%s) Options: (%s)\n", argv[1], argv[2]);
1455
1456         if ((app = pbx_findapp(argv[1]))) {
1457                 res = pbx_exec(chan, app, argv[2]);
1458         } else {
1459                 ast_log(LOG_WARNING, "Could not find application (%s)\n", argv[1]);
1460                 res = -2;
1461         }
1462         ast_agi_fdprintf(chan, agi->fd, "200 result=%d\n", res);
1463
1464         /* Even though this is wrong, users are depending upon this result. */
1465         return res;
1466 }
1467
1468 static int handle_setcallerid(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1469 {
1470         char tmp[256]="";
1471         char *l = NULL, *n = NULL;
1472
1473         if (argv[2]) {
1474                 ast_copy_string(tmp, argv[2], sizeof(tmp));
1475                 ast_callerid_parse(tmp, &n, &l);
1476                 if (l)
1477                         ast_shrink_phone_number(l);
1478                 else
1479                         l = "";
1480                 if (!n)
1481                         n = "";
1482                 ast_set_callerid(chan, l, n, NULL);
1483         }
1484
1485         ast_agi_fdprintf(chan, agi->fd, "200 result=1\n");
1486         return RESULT_SUCCESS;
1487 }
1488
1489 static int handle_channelstatus(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1490 {
1491         struct ast_channel *c;
1492         if (argc == 2) {
1493                 /* no argument: supply info on the current channel */
1494                 ast_agi_fdprintf(chan, agi->fd, "200 result=%d\n", chan->_state);
1495                 return RESULT_SUCCESS;
1496         } else if (argc == 3) {
1497                 /* one argument: look for info on the specified channel */
1498                 c = ast_get_channel_by_name_locked(argv[2]);
1499                 if (c) {
1500                         ast_agi_fdprintf(chan, agi->fd, "200 result=%d\n", c->_state);
1501                         ast_channel_unlock(c);
1502                         return RESULT_SUCCESS;
1503                 }
1504                 /* if we get this far no channel name matched the argument given */
1505                 ast_agi_fdprintf(chan, agi->fd, "200 result=-1\n");
1506                 return RESULT_SUCCESS;
1507         } else {
1508                 return RESULT_SHOWUSAGE;
1509         }
1510 }
1511
1512 static int handle_setvariable(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1513 {
1514         if (argv[3])
1515                 pbx_builtin_setvar_helper(chan, argv[2], argv[3]);
1516
1517         ast_agi_fdprintf(chan, agi->fd, "200 result=1\n");
1518         return RESULT_SUCCESS;
1519 }
1520
1521 static int handle_getvariable(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1522 {
1523         char *ret;
1524         char tempstr[1024];
1525
1526         if (argc != 3)
1527                 return RESULT_SHOWUSAGE;
1528
1529         /* check if we want to execute an ast_custom_function */
1530         if (!ast_strlen_zero(argv[2]) && (argv[2][strlen(argv[2]) - 1] == ')')) {
1531                 ret = ast_func_read(chan, argv[2], tempstr, sizeof(tempstr)) ? NULL : tempstr;
1532         } else {
1533                 pbx_retrieve_variable(chan, argv[2], &ret, tempstr, sizeof(tempstr), NULL);
1534         }
1535
1536         if (ret)
1537                 ast_agi_fdprintf(chan, agi->fd, "200 result=1 (%s)\n", ret);
1538         else
1539                 ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
1540
1541         return RESULT_SUCCESS;
1542 }
1543
1544 static int handle_getvariablefull(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1545 {
1546         char tmp[4096];
1547         struct ast_channel *chan2=NULL;
1548
1549         if ((argc != 4) && (argc != 5))
1550                 return RESULT_SHOWUSAGE;
1551         if (argc == 5) {
1552                 chan2 = ast_get_channel_by_name_locked(argv[4]);
1553         } else {
1554                 chan2 = chan;
1555         }
1556         if (chan2) {
1557                 pbx_substitute_variables_helper(chan2, argv[3], tmp, sizeof(tmp) - 1);
1558                 ast_agi_fdprintf(chan, agi->fd, "200 result=1 (%s)\n", tmp);
1559         } else {
1560                 ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
1561         }
1562         if (chan2 && (chan2 != chan))
1563                 ast_channel_unlock(chan2);
1564         return RESULT_SUCCESS;
1565 }
1566
1567 static int handle_verbose(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1568 {
1569         int level = 0;
1570
1571         if (argc < 2)
1572                 return RESULT_SHOWUSAGE;
1573
1574         if (argv[2])
1575                 sscanf(argv[2], "%d", &level);
1576
1577         ast_verb(level, "%s: %s\n", chan->data, argv[1]);
1578         
1579         ast_agi_fdprintf(chan, agi->fd, "200 result=1\n");
1580         
1581         return RESULT_SUCCESS;
1582 }
1583
1584 static int handle_dbget(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1585 {
1586         int res;
1587         char tmp[256];
1588
1589         if (argc != 4)
1590                 return RESULT_SHOWUSAGE;
1591         res = ast_db_get(argv[2], argv[3], tmp, sizeof(tmp));
1592         if (res) 
1593                 ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
1594         else
1595                 ast_agi_fdprintf(chan, agi->fd, "200 result=1 (%s)\n", tmp);
1596
1597         return RESULT_SUCCESS;
1598 }
1599
1600 static int handle_dbput(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1601 {
1602         int res;
1603
1604         if (argc != 5)
1605                 return RESULT_SHOWUSAGE;
1606         res = ast_db_put(argv[2], argv[3], argv[4]);
1607         ast_agi_fdprintf(chan, agi->fd, "200 result=%c\n", res ? '0' : '1');
1608         return RESULT_SUCCESS;
1609 }
1610
1611 static int handle_dbdel(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1612 {
1613         int res;
1614
1615         if (argc != 4)
1616                 return RESULT_SHOWUSAGE;
1617         res = ast_db_del(argv[2], argv[3]);
1618         ast_agi_fdprintf(chan, agi->fd, "200 result=%c\n", res ? '0' : '1');
1619         return RESULT_SUCCESS;
1620 }
1621
1622 static int handle_dbdeltree(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1623 {
1624         int res;
1625
1626         if ((argc < 3) || (argc > 4))
1627                 return RESULT_SHOWUSAGE;
1628         if (argc == 4)
1629                 res = ast_db_deltree(argv[2], argv[3]);
1630         else
1631                 res = ast_db_deltree(argv[2], NULL);
1632
1633         ast_agi_fdprintf(chan, agi->fd, "200 result=%c\n", res ? '0' : '1');
1634         return RESULT_SUCCESS;
1635 }
1636
1637 static char *handle_cli_agi_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1638 {
1639         switch (cmd) {
1640         case CLI_INIT:
1641                 e->command = "agi set debug [on|off]";
1642                 e->usage =
1643                         "Usage: agi set debug [on|off]\n"
1644                         "       Enables/disables dumping of AGI transactions for\n"
1645                         "       debugging purposes.\n";
1646                 return NULL;
1647
1648         case CLI_GENERATE:
1649                 return NULL;
1650         }
1651
1652         if (a->argc != e->args)
1653                 return CLI_SHOWUSAGE;
1654
1655         if (strncasecmp(a->argv[3], "off", 3) == 0) {
1656                 agidebug = 0;
1657         } else if (strncasecmp(a->argv[3], "on", 2) == 0) {
1658                 agidebug = 1;
1659         } else {
1660                 return CLI_SHOWUSAGE;
1661         }
1662         ast_cli(a->fd, "AGI Debugging %sabled\n", agidebug ? "En" : "Dis");
1663         return CLI_SUCCESS;
1664 }
1665
1666 static int handle_noop(struct ast_channel *chan, AGI *agi, int arg, char *argv[])
1667 {
1668         ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
1669         return RESULT_SUCCESS;
1670 }
1671
1672 static int handle_setmusic(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
1673 {
1674         if (!strncasecmp(argv[2], "on", 2))
1675                 ast_moh_start(chan, argc > 3 ? argv[3] : NULL, NULL);
1676         else if (!strncasecmp(argv[2], "off", 3))
1677                 ast_moh_stop(chan);
1678         ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
1679         return RESULT_SUCCESS;
1680 }
1681
1682 static int handle_speechcreate(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1683 {
1684         /* If a structure already exists, return an error */
1685         if (agi->speech) {
1686                 ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
1687                 return RESULT_SUCCESS;
1688         }
1689         
1690         if ((agi->speech = ast_speech_new(argv[2], AST_FORMAT_SLINEAR)))
1691                 ast_agi_fdprintf(chan, agi->fd, "200 result=1\n");
1692         else
1693                 ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
1694         
1695         return RESULT_SUCCESS;
1696 }
1697
1698 static int handle_speechset(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1699 {
1700         /* Check for minimum arguments */
1701         if (argc != 3)
1702                 return RESULT_SHOWUSAGE;
1703         
1704         /* Check to make sure speech structure exists */
1705         if (!agi->speech) {
1706                 ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
1707                 return RESULT_SUCCESS;
1708         }
1709         
1710         ast_speech_change(agi->speech, argv[2], argv[3]);
1711         ast_agi_fdprintf(chan, agi->fd, "200 result=1\n");
1712         
1713         return RESULT_SUCCESS;
1714 }
1715
1716 static int handle_speechdestroy(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1717 {
1718         if (agi->speech) {
1719                 ast_speech_destroy(agi->speech);
1720                 agi->speech = NULL;
1721                 ast_agi_fdprintf(chan, agi->fd, "200 result=1\n");
1722         } else {
1723                 ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
1724         }
1725         
1726         return RESULT_SUCCESS;
1727 }
1728
1729 static int handle_speechloadgrammar(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1730 {
1731         if (argc != 5)
1732                 return RESULT_SHOWUSAGE;
1733         
1734         if (!agi->speech) {
1735                 ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
1736                 return RESULT_SUCCESS;
1737         }
1738         
1739         if (ast_speech_grammar_load(agi->speech, argv[3], argv[4]))
1740                 ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
1741         else
1742                 ast_agi_fdprintf(chan, agi->fd, "200 result=1\n");
1743         
1744         return RESULT_SUCCESS;
1745 }
1746
1747 static int handle_speechunloadgrammar(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1748 {
1749         if (argc != 4)
1750                 return RESULT_SHOWUSAGE;
1751         
1752         if (!agi->speech) {
1753                 ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
1754                 return RESULT_SUCCESS;
1755         }
1756         
1757         if (ast_speech_grammar_unload(agi->speech, argv[3]))
1758                 ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
1759         else
1760                 ast_agi_fdprintf(chan, agi->fd, "200 result=1\n");
1761         
1762         return RESULT_SUCCESS;
1763 }
1764
1765 static int handle_speechactivategrammar(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1766 {
1767         if (argc != 4)
1768                 return RESULT_SHOWUSAGE;
1769         
1770         if (!agi->speech) {
1771                 ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
1772                 return RESULT_SUCCESS;
1773         }
1774         
1775         if (ast_speech_grammar_activate(agi->speech, argv[3]))
1776                 ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
1777         else
1778                 ast_agi_fdprintf(chan, agi->fd, "200 result=1\n");
1779         
1780         return RESULT_SUCCESS;
1781 }
1782
1783 static int handle_speechdeactivategrammar(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1784 {
1785         if (argc != 4)
1786                 return RESULT_SHOWUSAGE;
1787         
1788         if (!agi->speech) {
1789                 ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
1790                 return RESULT_SUCCESS;
1791         }
1792         
1793         if (ast_speech_grammar_deactivate(agi->speech, argv[3]))
1794                 ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
1795         else
1796                 ast_agi_fdprintf(chan, agi->fd, "200 result=1\n");
1797         
1798         return RESULT_SUCCESS;
1799 }
1800
1801 static int speech_streamfile(struct ast_channel *chan, const char *filename, const char *preflang, int offset)
1802 {
1803         struct ast_filestream *fs = NULL;
1804         
1805         if (!(fs = ast_openstream(chan, filename, preflang)))
1806                 return -1;
1807         
1808         if (offset)
1809                 ast_seekstream(fs, offset, SEEK_SET);
1810         
1811         if (ast_applystream(chan, fs))
1812                 return -1;
1813         
1814         if (ast_playstream(fs))
1815                 return -1;
1816         
1817         return 0;
1818 }
1819
1820 static int handle_speechrecognize(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1821 {
1822         struct ast_speech *speech = agi->speech;
1823         char *prompt, dtmf = 0, tmp[4096] = "", *buf = tmp;
1824         int timeout = 0, offset = 0, old_read_format = 0, res = 0, i = 0;
1825         long current_offset = 0;
1826         const char *reason = NULL;
1827         struct ast_frame *fr = NULL;
1828         struct ast_speech_result *result = NULL;
1829         size_t left = sizeof(tmp);
1830         time_t start = 0, current;
1831         
1832         if (argc < 4)
1833                 return RESULT_SHOWUSAGE;
1834         
1835         if (!speech) {
1836                 ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
1837                 return RESULT_SUCCESS;
1838         }
1839         
1840         prompt = argv[2];
1841         timeout = atoi(argv[3]);
1842         
1843         /* If offset is specified then convert from text to integer */
1844         if (argc == 5)
1845                 offset = atoi(argv[4]);
1846         
1847         /* We want frames coming in signed linear */
1848         old_read_format = chan->readformat;
1849         if (ast_set_read_format(chan, AST_FORMAT_SLINEAR)) {
1850                 ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
1851                 return RESULT_SUCCESS;
1852         }
1853         
1854         /* Setup speech structure */
1855         if (speech->state == AST_SPEECH_STATE_NOT_READY || speech->state == AST_SPEECH_STATE_DONE) {
1856                 ast_speech_change_state(speech, AST_SPEECH_STATE_NOT_READY);
1857                 ast_speech_start(speech);
1858         }
1859         
1860         /* Start playing prompt */
1861         speech_streamfile(chan, prompt, chan->language, offset);
1862         
1863         /* Go into loop reading in frames, passing to speech thingy, checking for hangup, all that jazz */
1864         while (ast_strlen_zero(reason)) {
1865                 /* Run scheduled items */
1866                 ast_sched_runq(chan->sched);
1867                 
1868                 /* See maximum time of waiting */
1869                 if ((res = ast_sched_wait(chan->sched)) < 0)
1870                         res = 1000;
1871                 
1872                 /* Wait for frame */
1873                 if (ast_waitfor(chan, res) > 0) {
1874                         if (!(fr = ast_read(chan))) {
1875                                 reason = "hangup";
1876                                 break;
1877                         }
1878                 }
1879                 
1880                 /* Perform timeout check */
1881                 if ((timeout > 0) && (start > 0)) {
1882                         time(&current);
1883                         if ((current - start) >= timeout) {
1884                                 reason = "timeout";
1885                                 if (fr)
1886                                         ast_frfree(fr);
1887                                 break;
1888                         }
1889                 }
1890                 
1891                 /* Check the speech structure for any changes */
1892                 ast_mutex_lock(&speech->lock);
1893                 
1894                 /* See if we need to quiet the audio stream playback */
1895                 if (ast_test_flag(speech, AST_SPEECH_QUIET) && chan->stream) {
1896                         current_offset = ast_tellstream(chan->stream);
1897                         ast_stopstream(chan);
1898                         ast_clear_flag(speech, AST_SPEECH_QUIET);
1899                 }
1900                 
1901                 /* Check each state */
1902                 switch (speech->state) {
1903                 case AST_SPEECH_STATE_READY:
1904                         /* If the stream is done, start timeout calculation */
1905                         if ((timeout > 0) && ((!chan->stream) || (chan->streamid == -1 && chan->timingfunc == NULL))) {
1906                                 ast_stopstream(chan);
1907                                 time(&start);
1908                         }
1909                         /* Write audio frame data into speech engine if possible */
1910                         if (fr && fr->frametype == AST_FRAME_VOICE)
1911                                 ast_speech_write(speech, fr->data, fr->datalen);
1912                         break;
1913                 case AST_SPEECH_STATE_WAIT:
1914                         /* Cue waiting sound if not already playing */
1915                         if ((!chan->stream) || (chan->streamid == -1 && chan->timingfunc == NULL)) {
1916                                 ast_stopstream(chan);
1917                                 /* If a processing sound exists, or is not none - play it */
1918                                 if (!ast_strlen_zero(speech->processing_sound) && strcasecmp(speech->processing_sound, "none"))
1919                                         speech_streamfile(chan, speech->processing_sound, chan->language, 0);
1920                         }
1921                         break;
1922                 case AST_SPEECH_STATE_DONE:
1923                         /* Get the results */
1924                         speech->results = ast_speech_results_get(speech);
1925                         /* Change state to not ready */
1926                         ast_speech_change_state(speech, AST_SPEECH_STATE_NOT_READY);
1927                         reason = "speech";
1928                         break;
1929                 default:
1930                         break;
1931                 }
1932                 ast_mutex_unlock(&speech->lock);
1933                 
1934                 /* Check frame for DTMF or hangup */
1935                 if (fr) {
1936                         if (fr->frametype == AST_FRAME_DTMF) {
1937                                 reason = "dtmf";
1938                                 dtmf = fr->subclass;
1939                         } else if (fr->frametype == AST_FRAME_CONTROL && fr->subclass == AST_CONTROL_HANGUP) {
1940                                 reason = "hangup";
1941                         }
1942                         ast_frfree(fr);
1943                 }
1944         }
1945         
1946         if (!strcasecmp(reason, "speech")) {
1947                 /* Build string containing speech results */
1948                 for (result = speech->results; result; result = AST_LIST_NEXT(result, list)) {
1949                         /* Build result string */
1950                         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);
1951                         /* Increment result count */
1952                         i++;
1953                 }
1954                 /* Print out */
1955                 ast_agi_fdprintf(chan, agi->fd, "200 result=1 (speech) endpos=%ld results=%d %s\n", current_offset, i, tmp);
1956         } else if (!strcasecmp(reason, "dtmf")) {
1957                 ast_agi_fdprintf(chan, agi->fd, "200 result=1 (digit) digit=%c endpos=%ld\n", dtmf, current_offset);
1958         } else if (!strcasecmp(reason, "hangup") || !strcasecmp(reason, "timeout")) {
1959                 ast_agi_fdprintf(chan, agi->fd, "200 result=1 (%s) endpos=%ld\n", reason, current_offset);
1960         } else {
1961                 ast_agi_fdprintf(chan, agi->fd, "200 result=0 endpos=%ld\n", current_offset);
1962         }
1963         
1964         return RESULT_SUCCESS;
1965 }
1966
1967 static int handle_asyncagi_break(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
1968 {
1969         ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
1970         return AST_PBX_KEEPALIVE;
1971 }
1972
1973 static char usage_setmusic[] =
1974 " Usage: SET MUSIC ON <on|off> <class>\n"
1975 "       Enables/Disables the music on hold generator.  If <class> is\n"
1976 " not specified, then the default music on hold class will be used.\n"
1977 " Always returns 0.\n";
1978
1979 static char usage_dbput[] =
1980 " Usage: DATABASE PUT <family> <key> <value>\n"
1981 "       Adds or updates an entry in the Asterisk database for a\n"
1982 " given family, key, and value.\n"
1983 " Returns 1 if successful, 0 otherwise.\n";
1984
1985 static char usage_dbget[] =
1986 " Usage: DATABASE GET <family> <key>\n"
1987 "       Retrieves an entry in the Asterisk database for a\n"
1988 " given family and key.\n"
1989 " Returns 0 if <key> is not set.  Returns 1 if <key>\n"
1990 " is set and returns the variable in parentheses.\n"
1991 " Example return code: 200 result=1 (testvariable)\n";
1992
1993 static char usage_dbdel[] =
1994 " Usage: DATABASE DEL <family> <key>\n"
1995 "       Deletes an entry in the Asterisk database for a\n"
1996 " given family and key.\n"
1997 " Returns 1 if successful, 0 otherwise.\n";
1998
1999 static char usage_dbdeltree[] =
2000 " Usage: DATABASE DELTREE <family> [keytree]\n"
2001 "       Deletes a family or specific keytree within a family\n"
2002 " in the Asterisk database.\n"
2003 " Returns 1 if successful, 0 otherwise.\n";
2004
2005 static char usage_verbose[] =
2006 " Usage: VERBOSE <message> <level>\n"
2007 "       Sends <message> to the console via verbose message system.\n"
2008 " <level> is the the verbose level (1-4)\n"
2009 " Always returns 1.\n";
2010
2011 static char usage_getvariable[] =
2012 " Usage: GET VARIABLE <variablename>\n"
2013 "       Returns 0 if <variablename> is not set.  Returns 1 if <variablename>\n"
2014 " is set and returns the variable in parentheses.\n"
2015 " example return code: 200 result=1 (testvariable)\n";
2016
2017 static char usage_getvariablefull[] =
2018 " Usage: GET FULL VARIABLE <variablename> [<channel name>]\n"
2019 "       Returns 0 if <variablename> is not set or channel does not exist.  Returns 1\n"
2020 "if <variablename>  is set and returns the variable in parenthesis.  Understands\n"
2021 "complex variable names and builtin variables, unlike GET VARIABLE.\n"
2022 " example return code: 200 result=1 (testvariable)\n";
2023
2024 static char usage_setvariable[] =
2025 " Usage: SET VARIABLE <variablename> <value>\n";
2026
2027 static char usage_channelstatus[] =
2028 " Usage: CHANNEL STATUS [<channelname>]\n"
2029 "       Returns the status of the specified channel.\n" 
2030 " If no channel name is given the returns the status of the\n"
2031 " current channel.  Return values:\n"
2032 "  0 Channel is down and available\n"
2033 "  1 Channel is down, but reserved\n"
2034 "  2 Channel is off hook\n"
2035 "  3 Digits (or equivalent) have been dialed\n"
2036 "  4 Line is ringing\n"
2037 "  5 Remote end is ringing\n"
2038 "  6 Line is up\n"
2039 "  7 Line is busy\n";
2040
2041 static char usage_setcallerid[] =
2042 " Usage: SET CALLERID <number>\n"
2043 "       Changes the callerid of the current channel.\n";
2044
2045 static char usage_exec[] =
2046 " Usage: EXEC <application> <options>\n"
2047 "       Executes <application> with given <options>.\n"
2048 " Returns whatever the application returns, or -2 on failure to find application\n";
2049
2050 static char usage_hangup[] =
2051 " Usage: HANGUP [<channelname>]\n"
2052 "       Hangs up the specified channel.\n"
2053 " If no channel name is given, hangs up the current channel\n";
2054
2055 static char usage_answer[] = 
2056 " Usage: ANSWER\n"
2057 "       Answers channel if not already in answer state. Returns -1 on\n"
2058 " channel failure, or 0 if successful.\n";
2059
2060 static char usage_waitfordigit[] = 
2061 " Usage: WAIT FOR DIGIT <timeout>\n"
2062 "       Waits up to 'timeout' milliseconds for channel to receive a DTMF digit.\n"
2063 " Returns -1 on channel failure, 0 if no digit is received in the timeout, or\n"
2064 " the numerical value of the ascii of the digit if one is received.  Use -1\n"
2065 " for the timeout value if you desire the call to block indefinitely.\n";
2066
2067 static char usage_sendtext[] =
2068 " Usage: SEND TEXT \"<text to send>\"\n"
2069 "       Sends the given text on a channel. Most channels do not support the\n"
2070 " transmission of text.  Returns 0 if text is sent, or if the channel does not\n"
2071 " support text transmission.  Returns -1 only on error/hangup.  Text\n"
2072 " consisting of greater than one word should be placed in quotes since the\n"
2073 " command only accepts a single argument.\n";
2074
2075 static char usage_recvchar[] =
2076 " Usage: RECEIVE CHAR <timeout>\n"
2077 "       Receives a character of text on a channel. Specify timeout to be the\n"
2078 " maximum time to wait for input in milliseconds, or 0 for infinite. Most channels\n"
2079 " do not support the reception of text. Returns the decimal value of the character\n"
2080 " if one is received, or 0 if the channel does not support text reception.  Returns\n"
2081 " -1 only on error/hangup.\n";
2082
2083 static char usage_recvtext[] =
2084 " Usage: RECEIVE TEXT <timeout>\n"
2085 "       Receives a string of text on a channel. Specify timeout to be the\n"
2086 " maximum time to wait for input in milliseconds, or 0 for infinite. Most channels\n"
2087 " do not support the reception of text. Returns -1 for failure or 1 for success, and the string in parentheses.\n";
2088
2089 static char usage_tddmode[] =
2090 " Usage: TDD MODE <on|off>\n"
2091 "       Enable/Disable TDD transmission/reception on a channel. Returns 1 if\n"
2092 " successful, or 0 if channel is not TDD-capable.\n";
2093
2094 static char usage_sendimage[] =
2095 " Usage: SEND IMAGE <image>\n"
2096 "       Sends the given image on a channel. Most channels do not support the\n"
2097 " transmission of images. Returns 0 if image is sent, or if the channel does not\n"
2098 " support image transmission.  Returns -1 only on error/hangup. Image names\n"
2099 " should not include extensions.\n";
2100
2101 static char usage_streamfile[] =
2102 " Usage: STREAM FILE <filename> <escape digits> [sample offset]\n"
2103 "       Send the given file, allowing playback to be interrupted by the given\n"
2104 " digits, if any. Use double quotes for the digits if you wish none to be\n"
2105 " permitted. If sample offset is provided then the audio will seek to sample\n"
2106 " offset before play starts.  Returns 0 if playback completes without a digit\n"
2107 " being pressed, or the ASCII numerical value of the digit if one was pressed,\n"
2108 " or -1 on error or if the channel was disconnected. Remember, the file\n"
2109 " extension must not be included in the filename.\n";
2110
2111 static char usage_controlstreamfile[] =
2112 " Usage: CONTROL STREAM FILE <filename> <escape digits> [skipms] [ffchar] [rewchr] [pausechr]\n"
2113 "       Send the given file, allowing playback to be controled by the given\n"
2114 " digits, if any. Use double quotes for the digits if you wish none to be\n"
2115 " permitted.  Returns 0 if playback completes without a digit\n"
2116 " being pressed, or the ASCII numerical value of the digit if one was pressed,\n"
2117 " or -1 on error or if the channel was disconnected. Remember, the file\n"
2118 " extension must not be included in the filename.\n\n"
2119 " Note: ffchar and rewchar default to * and # respectively.\n";
2120
2121 static char usage_getoption[] = 
2122 " Usage: GET OPTION <filename> <escape_digits> [timeout]\n"
2123 "       Behaves similar to STREAM FILE but used with a timeout option.\n";
2124
2125 static char usage_saynumber[] =
2126 " Usage: SAY NUMBER <number> <escape digits> [gender]\n"
2127 "       Say a given number, returning early if any of the given DTMF digits\n"
2128 " are received on the channel.  Returns 0 if playback completes without a digit\n"
2129 " being pressed, or the ASCII numerical value of the digit if one was pressed or\n"
2130 " -1 on error/hangup.\n";
2131
2132 static char usage_saydigits[] =
2133 " Usage: SAY DIGITS <number> <escape digits>\n"
2134 "       Say a given digit string, returning early if any of the given DTMF digits\n"
2135 " are received on the channel. Returns 0 if playback completes without a digit\n"
2136 " being pressed, or the ASCII numerical value of the digit if one was pressed or\n"
2137 " -1 on error/hangup.\n";
2138
2139 static char usage_sayalpha[] =
2140 " Usage: SAY ALPHA <number> <escape digits>\n"
2141 "       Say a given character string, returning early if any of the given DTMF digits\n"
2142 " are received on the channel. Returns 0 if playback completes without a digit\n"
2143 " being pressed, or the ASCII numerical value of the digit if one was pressed or\n"
2144 " -1 on error/hangup.\n";
2145
2146 static char usage_saydate[] =
2147 " Usage: SAY DATE <date> <escape digits>\n"
2148 "       Say a given date, returning early if any of the given DTMF digits are\n"
2149 " received on the channel.  <date> is number of seconds elapsed since 00:00:00\n"
2150 " on January 1, 1970, Coordinated Universal Time (UTC). Returns 0 if playback\n"
2151 " completes without a digit being pressed, or the ASCII numerical value of the\n"
2152 " digit if one was pressed or -1 on error/hangup.\n";
2153
2154 static char usage_saytime[] =
2155 " Usage: SAY TIME <time> <escape digits>\n"
2156 "       Say a given time, returning early if any of the given DTMF digits are\n"
2157 " received on the channel.  <time> is number of seconds elapsed since 00:00:00\n"
2158 " on January 1, 1970, Coordinated Universal Time (UTC). Returns 0 if playback\n"
2159 " completes without a digit being pressed, or the ASCII numerical value of the\n"
2160 " digit if one was pressed or -1 on error/hangup.\n";
2161
2162 static char usage_saydatetime[] =
2163 " Usage: SAY DATETIME <time> <escape digits> [format] [timezone]\n"
2164 "       Say a given time, returning early if any of the given DTMF digits are\n"
2165 " received on the channel.  <time> is number of seconds elapsed since 00:00:00\n"
2166 " on January 1, 1970, Coordinated Universal Time (UTC). [format] is the format\n"
2167 " the time should be said in.  See voicemail.conf (defaults to \"ABdY\n"
2168 " 'digits/at' IMp\").  Acceptable values for [timezone] can be found in\n"
2169 " /usr/share/zoneinfo.  Defaults to machine default. Returns 0 if playback\n"
2170 " completes without a digit being pressed, or the ASCII numerical value of the\n"
2171 " digit if one was pressed or -1 on error/hangup.\n";
2172
2173 static char usage_sayphonetic[] =
2174 " Usage: SAY PHONETIC <string> <escape digits>\n"
2175 "       Say a given character string with phonetics, returning early if any of the\n"
2176 " given DTMF digits are received on the channel. Returns 0 if playback\n"
2177 " completes without a digit pressed, the ASCII numerical value of the digit\n"
2178 " if one was pressed, or -1 on error/hangup.\n";
2179
2180 static char usage_getdata[] =
2181 " Usage: GET DATA <file to be streamed> [timeout] [max digits]\n"
2182 "       Stream the given file, and recieve DTMF data. Returns the digits received\n"
2183 "from the channel at the other end.\n";
2184
2185 static char usage_setcontext[] =
2186 " Usage: SET CONTEXT <desired context>\n"
2187 "       Sets the context for continuation upon exiting the application.\n";
2188
2189 static char usage_setextension[] =
2190 " Usage: SET EXTENSION <new extension>\n"
2191 "       Changes the extension for continuation upon exiting the application.\n";
2192
2193 static char usage_setpriority[] =
2194 " Usage: SET PRIORITY <priority>\n"
2195 "       Changes the priority for continuation upon exiting the application.\n"
2196 " The priority must be a valid priority or label.\n";
2197
2198 static char usage_recordfile[] =
2199 " Usage: RECORD FILE <filename> <format> <escape digits> <timeout> \\\n"
2200 "                                          [offset samples] [BEEP] [s=silence]\n"
2201 "       Record to a file until a given dtmf digit in the sequence is received\n"
2202 " Returns -1 on hangup or error.  The format will specify what kind of file\n"
2203 " will be recorded.  The timeout is the maximum record time in milliseconds, or\n"
2204 " -1 for no timeout. \"Offset samples\" is optional, and, if provided, will seek\n"
2205 " to the offset without exceeding the end of the file.  \"silence\" is the number\n"
2206 " of seconds of silence allowed before the function returns despite the\n"
2207 " lack of dtmf digits or reaching timeout.  Silence value must be\n"
2208 " preceeded by \"s=\" and is also optional.\n";
2209
2210 static char usage_autohangup[] =
2211 " Usage: SET AUTOHANGUP <time>\n"
2212 "       Cause the channel to automatically hangup at <time> seconds in the\n"
2213 " future.  Of course it can be hungup before then as well. Setting to 0 will\n"
2214 " cause the autohangup feature to be disabled on this channel.\n";
2215
2216 static char usage_break_aagi[] =
2217 " Usage: ASYNCAGI BREAK\n"
2218 "       Break the Async AGI loop.\n";
2219
2220 static char usage_noop[] =
2221 " Usage: NoOp\n"
2222 "       Does nothing.\n";
2223
2224 static char usage_speechcreate[] =
2225 " Usage: SPEECH CREATE <engine>\n"
2226 "       Create a speech object to be used by the other Speech AGI commands.\n";
2227
2228 static char usage_speechset[] =
2229 " Usage: SPEECH SET <name> <value>\n"
2230 "       Set an engine-specific setting.\n";
2231
2232 static char usage_speechdestroy[] =
2233 " Usage: SPEECH DESTROY\n"
2234 "       Destroy the speech object created by SPEECH CREATE.\n";
2235
2236 static char usage_speechloadgrammar[] =
2237 " Usage: SPEECH LOAD GRAMMAR <grammar name> <path to grammar>\n"
2238 "       Loads the specified grammar as the specified name.\n";
2239
2240 static char usage_speechunloadgrammar[] =
2241 " Usage: SPEECH UNLOAD GRAMMAR <grammar name>\n"
2242 "       Unloads the specified grammar.\n";
2243
2244 static char usage_speechactivategrammar[] =
2245 " Usage: SPEECH ACTIVATE GRAMMAR <grammar name>\n"
2246 "       Activates the specified grammar on the speech object.\n";
2247
2248 static char usage_speechdeactivategrammar[] =
2249 " Usage: SPEECH DEACTIVATE GRAMMAR <grammar name>\n"
2250 "       Deactivates the specified grammar on the speech object.\n";
2251
2252 static char usage_speechrecognize[] =
2253 " Usage: SPEECH RECOGNIZE <prompt> <timeout> [<offset>]\n"
2254 "       Plays back given prompt while listening for speech and dtmf.\n";
2255
2256 /*!
2257  * \brief AGI commands list
2258  */
2259 static struct agi_command commands[] = {
2260         { { "answer", NULL }, handle_answer, "Answer channel", usage_answer , 0 },
2261         { { "channel", "status", NULL }, handle_channelstatus, "Returns status of the connected channel", usage_channelstatus , 0 },
2262         { { "database", "del", NULL }, handle_dbdel, "Removes database key/value", usage_dbdel , 1 },
2263         { { "database", "deltree", NULL }, handle_dbdeltree, "Removes database keytree/value", usage_dbdeltree , 1 },
2264         { { "database", "get", NULL }, handle_dbget, "Gets database value", usage_dbget , 1 },
2265         { { "database", "put", NULL }, handle_dbput, "Adds/updates database value", usage_dbput , 1 },
2266         { { "exec", NULL }, handle_exec, "Executes a given Application", usage_exec , 1 },
2267         { { "get", "data", NULL }, handle_getdata, "Prompts for DTMF on a channel", usage_getdata , 0 },
2268         { { "get", "full", "variable", NULL }, handle_getvariablefull, "Evaluates a channel expression", usage_getvariablefull , 1 },
2269         { { "get", "option", NULL }, handle_getoption, "Stream file, prompt for DTMF, with timeout", usage_getoption , 0 },
2270         { { "get", "variable", NULL }, handle_getvariable, "Gets a channel variable", usage_getvariable , 1 },
2271         { { "hangup", NULL }, handle_hangup, "Hangup the current channel", usage_hangup , 0 },
2272         { { "noop", NULL }, handle_noop, "Does nothing", usage_noop , 1 },
2273         { { "receive", "char", NULL }, handle_recvchar, "Receives one character from channels supporting it", usage_recvchar , 0 },
2274         { { "receive", "text", NULL }, handle_recvtext, "Receives text from channels supporting it", usage_recvtext , 0 },
2275         { { "record", "file", NULL }, handle_recordfile, "Records to a given file", usage_recordfile , 0 },
2276         { { "say", "alpha", NULL }, handle_sayalpha, "Says a given character string", usage_sayalpha , 0 },
2277         { { "say", "digits", NULL }, handle_saydigits, "Says a given digit string", usage_saydigits , 0 },
2278         { { "say", "number", NULL }, handle_saynumber, "Says a given number", usage_saynumber , 0 },
2279         { { "say", "phonetic", NULL }, handle_sayphonetic, "Says a given character string with phonetics", usage_sayphonetic , 0 },
2280         { { "say", "date", NULL }, handle_saydate, "Says a given date", usage_saydate , 0 },
2281         { { "say", "time", NULL }, handle_saytime, "Says a given time", usage_saytime , 0 },
2282         { { "say", "datetime", NULL }, handle_saydatetime, "Says a given time as specfied by the format given", usage_saydatetime , 0 },
2283         { { "send", "image", NULL }, handle_sendimage, "Sends images to channels supporting it", usage_sendimage , 0 },
2284         { { "send", "text", NULL }, handle_sendtext, "Sends text to channels supporting it", usage_sendtext , 0 },
2285         { { "set", "autohangup", NULL }, handle_autohangup, "Autohangup channel in some time", usage_autohangup , 0 },
2286         { { "set", "callerid", NULL }, handle_setcallerid, "Sets callerid for the current channel", usage_setcallerid , 0 },
2287         { { "set", "context", NULL }, handle_setcontext, "Sets channel context", usage_setcontext , 0 },
2288         { { "set", "extension", NULL }, handle_setextension, "Changes channel extension", usage_setextension , 0 },
2289         { { "set", "music", NULL }, handle_setmusic, "Enable/Disable Music on hold generator", usage_setmusic , 0 },
2290         { { "set", "priority", NULL }, handle_setpriority, "Set channel dialplan priority", usage_setpriority , 0 },
2291         { { "set", "variable", NULL }, handle_setvariable, "Sets a channel variable", usage_setvariable , 1 },
2292         { { "stream", "file", NULL }, handle_streamfile, "Sends audio file on channel", usage_streamfile , 0 },
2293         { { "control", "stream", "file", NULL }, handle_controlstreamfile, "Sends audio file on channel and allows the listner to control the stream", usage_controlstreamfile , 0 },
2294         { { "tdd", "mode", NULL }, handle_tddmode, "Toggles TDD mode (for the deaf)", usage_tddmode , 0 },
2295         { { "verbose", NULL }, handle_verbose, "Logs a message to the asterisk verbose log", usage_verbose , 1 },
2296         { { "wait", "for", "digit", NULL }, handle_waitfordigit, "Waits for a digit to be pressed", usage_waitfordigit , 0 },
2297         { { "speech", "create", NULL }, handle_speechcreate, "Creates a speech object", usage_speechcreate, 0 },
2298         { { "speech", "set", NULL }, handle_speechset, "Sets a speech engine setting", usage_speechset, 0 },
2299         { { "speech", "destroy", NULL }, handle_speechdestroy, "Destroys a speech object", usage_speechdestroy, 1 },
2300         { { "speech", "load", "grammar", NULL }, handle_speechloadgrammar, "Loads a grammar", usage_speechloadgrammar, 0 },
2301         { { "speech", "unload", "grammar", NULL }, handle_speechunloadgrammar, "Unloads a grammar", usage_speechunloadgrammar, 1 },
2302         { { "speech", "activate", "grammar", NULL }, handle_speechactivategrammar, "Activates a grammar", usage_speechactivategrammar, 0 },
2303         { { "speech", "deactivate", "grammar", NULL }, handle_speechdeactivategrammar, "Deactivates a grammar", usage_speechdeactivategrammar, 0 },
2304         { { "speech", "recognize", NULL }, handle_speechrecognize, "Recognizes speech", usage_speechrecognize, 0 },
2305         { { "asyncagi", "break", NULL }, handle_asyncagi_break, "Break AsyncAGI loop", usage_break_aagi, 0 },
2306 };
2307
2308 static AST_RWLIST_HEAD_STATIC(agi_commands, agi_command);
2309
2310 static char *help_workhorse(int fd, char *match[])
2311 {
2312         char fullcmd[80], matchstr[80];
2313         struct agi_command *e;
2314
2315         if (match)
2316                 ast_join(matchstr, sizeof(matchstr), match);
2317
2318         ast_cli(fd, "%5.5s %30.30s   %s\n","Dead","Command","Description");
2319         AST_RWLIST_RDLOCK(&agi_commands);
2320         AST_RWLIST_TRAVERSE(&agi_commands, e, list) {
2321                 if (!e->cmda[0])
2322                         break;
2323                 /* Hide commands that start with '_' */
2324                 if ((e->cmda[0])[0] == '_')
2325                         continue;
2326                 ast_join(fullcmd, sizeof(fullcmd), e->cmda);
2327                 if (match && strncasecmp(matchstr, fullcmd, strlen(matchstr)))
2328                         continue;
2329                 ast_cli(fd, "%5.5s %30.30s   %s\n", e->dead ? "Yes" : "No" , fullcmd, e->summary);
2330         }
2331         AST_RWLIST_UNLOCK(&agi_commands);
2332
2333         return CLI_SUCCESS;
2334 }
2335
2336 int ast_agi_register(struct ast_module *mod, agi_command *cmd)
2337 {
2338         char fullcmd[80];
2339
2340         ast_join(fullcmd, sizeof(fullcmd), cmd->cmda);
2341
2342         if (!find_command(cmd->cmda,1)) {
2343                 cmd->mod = mod;
2344                 AST_RWLIST_WRLOCK(&agi_commands);
2345                 AST_LIST_INSERT_TAIL(&agi_commands, cmd, list);
2346                 AST_RWLIST_UNLOCK(&agi_commands);
2347                 if (mod != ast_module_info->self)
2348                         ast_module_ref(ast_module_info->self);
2349                 ast_verb(2, "AGI Command '%s' registered\n",fullcmd);
2350                 return 1;
2351         } else {
2352                 ast_log(LOG_WARNING, "Command already registered!\n");
2353                 return 0;
2354         }
2355 }
2356
2357 int ast_agi_unregister(struct ast_module *mod, agi_command *cmd)
2358 {
2359         struct agi_command *e;
2360         int unregistered = 0;
2361         char fullcmd[80];
2362         
2363         ast_join(fullcmd, sizeof(fullcmd), cmd->cmda);
2364
2365         AST_RWLIST_WRLOCK(&agi_commands);
2366         AST_RWLIST_TRAVERSE_SAFE_BEGIN(&agi_commands, e, list) {
2367                 if (cmd == e) {
2368                         AST_RWLIST_REMOVE_CURRENT(list);
2369                         if (mod != ast_module_info->self)
2370                                 ast_module_unref(ast_module_info->self);
2371                         unregistered=1;
2372                         break;
2373                 }
2374         }
2375         AST_RWLIST_TRAVERSE_SAFE_END;
2376         AST_RWLIST_UNLOCK(&agi_commands);
2377         if (unregistered)
2378                 ast_verb(2, "AGI Command '%s' unregistered\n",fullcmd);
2379         else
2380                 ast_log(LOG_WARNING, "Unable to unregister command: '%s'!\n",fullcmd);
2381         return unregistered;
2382 }
2383
2384 void ast_agi_register_multiple(struct ast_module *mod, agi_command *cmd, int len)
2385 {
2386         int i;
2387
2388         for (i = 0; i < len; i++)
2389                 ast_agi_register(mod, cmd + i);
2390
2391 }
2392
2393 void ast_agi_unregister_multiple(struct ast_module *mod, agi_command *cmd, int len)
2394 {
2395         int i;
2396
2397         for (i = 0; i < len; i++)
2398                 ast_agi_unregister(mod, cmd + i);
2399 }
2400
2401 static agi_command *find_command(char *cmds[], int exact)
2402 {
2403         int y, match;
2404         struct agi_command *e;
2405
2406         AST_RWLIST_RDLOCK(&agi_commands);
2407         AST_RWLIST_TRAVERSE(&agi_commands, e, list) {
2408                 if (!e->cmda[0])
2409                         break;
2410                 /* start optimistic */
2411                 match = 1;
2412                 for (y = 0; match && cmds[y]; y++) {
2413                         /* If there are no more words in the command (and we're looking for
2414                            an exact match) or there is a difference between the two words,
2415                            then this is not a match */
2416                         if (!e->cmda[y] && !exact)
2417                                 break;
2418                         /* don't segfault if the next part of a command doesn't exist */
2419                         if (!e->cmda[y])
2420                                 return NULL;
2421                         if (strcasecmp(e->cmda[y], cmds[y]))
2422                                 match = 0;
2423                 }
2424                 /* If more words are needed to complete the command then this is not
2425                    a candidate (unless we're looking for a really inexact answer  */
2426                 if ((exact > -1) && e->cmda[y])
2427                         match = 0;
2428                 if (match)
2429                         return e;
2430         }
2431         AST_RWLIST_UNLOCK(&agi_commands);
2432         return NULL;
2433 }
2434
2435 static int parse_args(char *s, int *max, char *argv[])
2436 {
2437         int x = 0, quoted = 0, escaped = 0, whitespace = 1;
2438         char *cur;
2439
2440         cur = s;
2441         while(*s) {
2442                 switch(*s) {
2443                 case '"':
2444                         /* If it's escaped, put a literal quote */
2445                         if (escaped) 
2446                                 goto normal;
2447                         else 
2448                                 quoted = !quoted;
2449                         if (quoted && whitespace) {
2450                                 /* If we're starting a quote, coming off white space start a new word, too */
2451                                 argv[x++] = cur;
2452                                 whitespace=0;
2453                         }
2454                         escaped = 0;
2455                 break;
2456                 case ' ':
2457                 case '\t':
2458                         if (!quoted && !escaped) {
2459                                 /* If we're not quoted, mark this as whitespace, and
2460                                    end the previous argument */
2461                                 whitespace = 1;
2462                                 *(cur++) = '\0';
2463                         } else
2464                                 /* Otherwise, just treat it as anything else */ 
2465                                 goto normal;
2466                         break;
2467                 case '\\':
2468                         /* If we're escaped, print a literal, otherwise enable escaping */
2469                         if (escaped) {
2470                                 goto normal;
2471                         } else {
2472                                 escaped=1;
2473                         }
2474                         break;
2475                 default:
2476 normal:
2477                         if (whitespace) {
2478                                 if (x >= MAX_ARGS -1) {
2479                                         ast_log(LOG_WARNING, "Too many arguments, truncating\n");
2480                                         break;
2481                                 }
2482                                 /* Coming off of whitespace, start the next argument */
2483                                 argv[x++] = cur;
2484                                 whitespace=0;
2485                         }
2486                         *(cur++) = *s;
2487                         escaped=0;
2488                 }
2489                 s++;
2490         }
2491         /* Null terminate */
2492         *(cur++) = '\0';
2493         argv[x] = NULL;
2494         *max = x;
2495         return 0;
2496 }
2497
2498 static int agi_handle_command(struct ast_channel *chan, AGI *agi, char *buf, int dead)
2499 {
2500         char *argv[MAX_ARGS];
2501         int argc = MAX_ARGS, res;
2502         agi_command *c;
2503         const char *ami_res = "Unknown Result";
2504         char *ami_cmd = ast_strdupa(buf);
2505         int command_id = ast_random(), resultcode = 200;
2506
2507         manager_event(EVENT_FLAG_CALL, "AGIExec", 
2508                         "SubEvent: Start\r\n"
2509                         "Channel: %s\r\n"
2510                         "CommandId: %d\r\n"
2511                         "Command: %s\r\n", chan->name, command_id, ami_cmd);
2512         parse_args(buf, &argc, argv);
2513         if ((c = find_command(argv, 0)) && (!dead || (dead && c->dead))) {
2514                 /* if this command wasnt registered by res_agi, be sure to usecount
2515                 the module we are using */
2516                 if (c->mod != ast_module_info->self)
2517                         ast_module_ref(c->mod);
2518                 res = c->handler(chan, agi, argc, argv);
2519                 if (c->mod != ast_module_info->self)
2520                         ast_module_unref(c->mod);
2521                 switch (res) {
2522                 case RESULT_SHOWUSAGE: ami_res = "Usage"; resultcode = 520; break;
2523                 case AST_PBX_KEEPALIVE: ami_res = "KeepAlive"; resultcode = 210; break;
2524                 case RESULT_FAILURE: ami_res = "Failure"; resultcode = -1; break;
2525                 case RESULT_SUCCESS: ami_res = "Success"; resultcode = 200; break;
2526                 }
2527                 manager_event(EVENT_FLAG_CALL, "AGIExec",
2528                                 "SubEvent: End\r\n"
2529                                 "Channel: %s\r\n"
2530                                 "CommandId: %d\r\n"
2531                                 "Command: %s\r\n"
2532                                 "ResultCode: %d\r\n"
2533                                 "Result: %s\r\n", chan->name, command_id, ami_cmd, resultcode, ami_res);
2534                 switch(res) {
2535                 case RESULT_SHOWUSAGE:
2536                         ast_agi_fdprintf(chan, agi->fd, "520-Invalid command syntax.  Proper usage follows:\n");
2537                         ast_agi_fdprintf(chan, agi->fd, c->usage);
2538                         ast_agi_fdprintf(chan, agi->fd, "520 End of proper usage.\n");
2539                         break;
2540                 case AST_PBX_KEEPALIVE:
2541                         /* We've been asked to keep alive, so do so */
2542                         return AST_PBX_KEEPALIVE;
2543                         break;
2544                 case RESULT_FAILURE:
2545                         /* They've already given the failure.  We've been hung up on so handle this
2546                            appropriately */
2547                         return -1;
2548                 }
2549         } else if ((c = find_command(argv, 0))) {
2550                 ast_agi_fdprintf(chan, agi->fd, "511 Command Not Permitted on a dead channel\n");
2551                 manager_event(EVENT_FLAG_CALL, "AGIExec",
2552                                 "SubEvent: End\r\n"
2553                                 "Channel: %s\r\n"
2554                                 "CommandId: %d\r\n"
2555                                 "Command: %s\r\n"
2556                                 "ResultCode: 511\r\n"
2557                                 "Result: Command not permitted on a dead channel\r\n", chan->name, command_id, ami_cmd);
2558         } else {
2559                 ast_agi_fdprintf(chan, agi->fd, "510 Invalid or unknown command\n");
2560                 manager_event(EVENT_FLAG_CALL, "AGIExec",
2561                                 "SubEvent: End\r\n"
2562                                 "Channel: %s\r\n"
2563                                 "CommandId: %d\r\n"
2564                                 "Command: %s\r\n"
2565                                 "ResultCode: 510\r\n"
2566                                 "Result: Invalid or unknown command\r\n", chan->name, command_id, ami_cmd);
2567         }
2568         return 0;
2569 }
2570 static enum agi_result run_agi(struct ast_channel *chan, char *request, AGI *agi, int pid, int *status, int dead, int argc, char *argv[])
2571 {
2572         struct ast_channel *c;
2573         int outfd, ms, needhup = 0;
2574         enum agi_result returnstatus = AGI_RESULT_SUCCESS;
2575         struct ast_frame *f;
2576         char buf[AGI_BUF_LEN];
2577         char *res = NULL;
2578         FILE *readf;
2579         /* how many times we'll retry if ast_waitfor_nandfs will return without either 
2580           channel or file descriptor in case select is interrupted by a system call (EINTR) */
2581         int retry = AGI_NANDFS_RETRY;
2582
2583         if (!(readf = fdopen(agi->ctrl, "r"))) {
2584                 ast_log(LOG_WARNING, "Unable to fdopen file descriptor\n");
2585                 if (pid > -1)
2586                         kill(pid, SIGHUP);
2587                 close(agi->ctrl);
2588                 return AGI_RESULT_FAILURE;
2589         }
2590         setlinebuf(readf);
2591         setup_env(chan, request, agi->fd, (agi->audio > -1), argc, argv);
2592         for (;;) {
2593                 if (needhup) {
2594                         needhup = 0;
2595                         dead = 1;
2596                         if (pid > -1)
2597                                 kill(pid, SIGHUP);
2598                 }
2599                 ms = -1;
2600                 c = ast_waitfor_nandfds(&chan, dead ? 0 : 1, &agi->ctrl, 1, NULL, &outfd, &ms);
2601                 if (c) {
2602                         retry = AGI_NANDFS_RETRY;
2603                         /* Idle the channel until we get a command */
2604                         f = ast_read(c);
2605                         if (!f) {
2606                                 ast_debug(1, "%s hungup\n", chan->name);
2607                                 returnstatus = AGI_RESULT_HANGUP;
2608                                 needhup = 1;
2609                                 continue;
2610                         } else {
2611                                 /* If it's voice, write it to the audio pipe */
2612                                 if ((agi->audio > -1) && (f->frametype == AST_FRAME_VOICE)) {
2613                                         /* Write, ignoring errors */
2614                                         write(agi->audio, f->data, f->datalen);
2615                                 }
2616                                 ast_frfree(f);
2617                         }
2618                 } else if (outfd > -1) {
2619                         size_t len = sizeof(buf);
2620                         size_t buflen = 0;
2621
2622                         retry = AGI_NANDFS_RETRY;
2623                         buf[0] = '\0';
2624
2625                         while (buflen < (len - 1)) {
2626                                 res = fgets(buf + buflen, len, readf);
2627                                 if (feof(readf)) 
2628                                         break;
2629                                 if (ferror(readf) && ((errno != EINTR) && (errno != EAGAIN))) 
2630                                         break;
2631                                 if (res != NULL && !agi->fast)
2632                                         break;
2633                                 buflen = strlen(buf);
2634                                 if (buflen && buf[buflen - 1] == '\n')
2635                                         break;
2636                                 len -= buflen;
2637                                 if (agidebug)
2638                                         ast_verbose( "AGI Rx << temp buffer %s - errno %s\n", buf, strerror(errno));
2639                         }
2640
2641                         if (!buf[0]) {
2642                                 /* Program terminated */
2643                                 if (returnstatus && returnstatus != AST_PBX_KEEPALIVE)
2644                                         returnstatus = -1;
2645                                 ast_verb(3, "<%s>AGI Script %s completed, returning %d\n", chan->name, request, returnstatus);
2646                                 if (pid > 0)
2647                                         waitpid(pid, status, 0);
2648                                 /* No need to kill the pid anymore, since they closed us */
2649                                 pid = -1;
2650                                 break;
2651                         }
2652
2653                         /* Special case for inability to execute child process */
2654                         if (*buf && strncasecmp(buf, "failure", 7) == 0) {
2655                                 returnstatus = AGI_RESULT_FAILURE;
2656                                 break;
2657                         }
2658
2659                         /* get rid of trailing newline, if any */
2660                         if (*buf && buf[strlen(buf) - 1] == '\n')
2661                                 buf[strlen(buf) - 1] = 0;
2662                         if (agidebug)
2663                                 ast_verbose("<%s>AGI Rx << %s\n", chan->name, buf);
2664                         returnstatus |= agi_handle_command(chan, agi, buf, dead);
2665                         /* If the handle_command returns -1, we need to stop */
2666                         if ((returnstatus < 0) || (returnstatus == AST_PBX_KEEPALIVE)) {
2667                                 needhup = 1;
2668                                 continue;
2669                         }
2670                 } else {
2671                         if (--retry <= 0) {
2672                                 ast_log(LOG_WARNING, "No channel, no fd?\n");
2673                                 returnstatus = AGI_RESULT_FAILURE;
2674                                 break;
2675                         }
2676                 }
2677         }
2678         /* Notify process */
2679         if (pid > -1) {
2680                 const char *sighup = pbx_builtin_getvar_helper(chan, "AGISIGHUP");
2681                 if (ast_strlen_zero(sighup) || !ast_false(sighup)) {
2682                         if (kill(pid, SIGHUP))
2683                                 ast_log(LOG_WARNING, "unable to send SIGHUP to AGI process %d: %s\n", pid, strerror(errno));
2684                 }
2685         }
2686         fclose(readf);
2687         return returnstatus;
2688 }
2689
2690 static char *handle_cli_agi_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2691 {
2692         struct agi_command *command;
2693         char fullcmd[80];
2694
2695         switch (cmd) {
2696         case CLI_INIT:
2697                 e->command = "agi show";
2698                 e->usage =
2699                         "Usage: agi show [topic]\n"
2700                         "       When called with a topic as an argument, displays usage\n"
2701                         "       information on the given command.  If called without a\n"
2702                         "       topic, it provides a list of AGI commands.\n";
2703                 break;
2704         case CLI_GENERATE:
2705                 return NULL;
2706         }
2707         if (a->argc < e->args)
2708                 return CLI_SHOWUSAGE;
2709         if (a->argc > e->args) {
2710                 command = find_command(a->argv + e->args, 1);
2711                 if (command) {
2712                         ast_cli(a->fd, "%s", command->usage);
2713                         ast_cli(a->fd, " Runs Dead : %s\n", command->dead ? "Yes" : "No");
2714                 } else {
2715                         if (find_command(a->argv + e->args, -1)) {
2716                                 return help_workhorse(a->fd, a->argv + e->args);
2717                         } else {
2718                                 ast_join(fullcmd, sizeof(fullcmd), a->argv + e->args);
2719                                 ast_cli(a->fd, "No such command '%s'.\n", fullcmd);
2720                         }
2721                 }
2722         } else {
2723                 return help_workhorse(a->fd, NULL);
2724         }
2725         return CLI_SUCCESS;
2726 }
2727
2728 /*! \brief Convert string to use HTML escaped characters
2729         \note Maybe this should be a generic function?
2730 */
2731 static void write_html_escaped(FILE *htmlfile, char *str)
2732 {
2733         char *cur = str;
2734
2735         while(*cur) {
2736                 switch (*cur) {
2737                 case '<':
2738                         fprintf(htmlfile, "%s", "&lt;");
2739                         break;
2740                 case '>':
2741                         fprintf(htmlfile, "%s", "&gt;");
2742                         break;
2743                 case '&':
2744                         fprintf(htmlfile, "%s", "&amp;");
2745                         break;
2746                 case '"':
2747                         fprintf(htmlfile, "%s", "&quot;");
2748                         break;
2749                 default:
2750                         fprintf(htmlfile, "%c", *cur);
2751                         break;
2752                 }
2753                 cur++;
2754         }
2755
2756         return;
2757 }
2758
2759 static int write_htmldump(char *filename)
2760 {
2761         struct agi_command *command;
2762         char fullcmd[80];
2763         FILE *htmlfile;
2764
2765         if (!(htmlfile = fopen(filename, "wt")))
2766                 return -1;
2767
2768         fprintf(htmlfile, "<HTML>\n<HEAD>\n<TITLE>AGI Commands</TITLE>\n</HEAD>\n");
2769         fprintf(htmlfile, "<BODY>\n<CENTER><B><H1>AGI Commands</H1></B></CENTER>\n\n");
2770         fprintf(htmlfile, "<TABLE BORDER=\"0\" CELLSPACING=\"10\">\n");
2771
2772         AST_RWLIST_RDLOCK(&agi_commands);
2773         AST_RWLIST_TRAVERSE(&agi_commands, command, list) {
2774                 char *stringp, *tempstr;
2775  
2776                 if (!command->cmda[0])  /* end ? */
2777                         break;
2778                 /* Hide commands that start with '_' */
2779                 if ((command->cmda[0])[0] == '_')
2780                         continue;
2781                 ast_join(fullcmd, sizeof(fullcmd), command->cmda);
2782
2783                 fprintf(htmlfile, "<TR><TD><TABLE BORDER=\"1\" CELLPADDING=\"5\" WIDTH=\"100%%\">\n");
2784                 fprintf(htmlfile, "<TR><TH ALIGN=\"CENTER\"><B>%s - %s</B></TH></TR>\n", fullcmd, command->summary);
2785
2786                 stringp = command->usage;
2787                 tempstr = strsep(&stringp, "\n");
2788
2789                 fprintf(htmlfile, "<TR><TD ALIGN=\"CENTER\">");
2790                 write_html_escaped(htmlfile, tempstr);
2791                 fprintf(htmlfile, "</TD></TR>\n");
2792                 fprintf(htmlfile, "<TR><TD ALIGN=\"CENTER\">\n");
2793
2794                 while ((tempstr = strsep(&stringp, "\n")) != NULL) {
2795                         write_html_escaped(htmlfile, tempstr);
2796                         fprintf(htmlfile, "<BR>\n");
2797                 }
2798                 fprintf(htmlfile, "</TD></TR>\n");
2799                 fprintf(htmlfile, "</TABLE></TD></TR>\n\n");
2800         }
2801         AST_RWLIST_UNLOCK(&agi_commands);
2802         fprintf(htmlfile, "</TABLE>\n</BODY>\n</HTML>\n");
2803         fclose(htmlfile);
2804         return 0;
2805 }
2806
2807 static char *handle_cli_agi_dumphtml_deprecated(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2808 {
2809         switch (cmd) {
2810         case CLI_INIT:
2811                 e->command = "agi dumphtml";
2812                 e->usage =
2813                         "Usage: agi dumphtml <filename>\n"
2814                         "       Dumps the AGI command list in HTML format to the given\n"
2815                         "       file.\n";
2816                 return NULL;
2817         case CLI_GENERATE:
2818                 return NULL;
2819         }
2820         if (a->argc < e->args + 1)
2821                 return CLI_SHOWUSAGE;
2822
2823         if (write_htmldump(a->argv[2]) < 0) {
2824                 ast_cli(a->fd, "Could not create file '%s'\n", a->argv[2]);
2825                 return CLI_SHOWUSAGE;
2826         }
2827         ast_cli(a->fd, "AGI HTML commands dumped to: %s\n", a->argv[2]);
2828         return CLI_SUCCESS;
2829 }
2830
2831 static char *handle_cli_agi_dump_html(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2832 {
2833         switch (cmd) {
2834         case CLI_INIT:
2835                 e->command = "agi dump html";
2836                 e->usage =
2837                         "Usage: agi dump html <filename>\n"
2838                         "       Dumps the AGI command list in HTML format to the given\n"
2839                         "       file.\n";
2840                 return NULL;
2841         case CLI_GENERATE:
2842                 return NULL;
2843         }
2844         if (a->argc != e->args + 1)
2845                 return CLI_SHOWUSAGE;
2846
2847         if (write_htmldump(a->argv[e->args]) < 0) {
2848                 ast_cli(a->fd, "Could not create file '%s'\n", a->argv[e->args]);
2849                 return CLI_SHOWUSAGE;
2850         }
2851         ast_cli(a->fd, "AGI HTML commands dumped to: %s\n", a->argv[e->args]);
2852         return CLI_SUCCESS;
2853 }
2854
2855 static int agi_exec_full(struct ast_channel *chan, void *data, int enhanced, int dead)
2856 {
2857         enum agi_result res;
2858         char buf[AGI_BUF_LEN] = "", *tmp = buf;
2859         int fds[2], efd = -1, pid;
2860         AST_DECLARE_APP_ARGS(args,
2861                 AST_APP_ARG(arg)[MAX_ARGS];
2862         );
2863         AGI agi;
2864
2865         if (ast_strlen_zero(data)) {
2866                 ast_log(LOG_WARNING, "AGI requires an argument (script)\n");
2867                 return -1;
2868         }
2869         if (dead)
2870                 ast_debug(3, "Hungup channel detected, running agi in dead mode.\n");
2871         ast_copy_string(buf, data, sizeof(buf));
2872         memset(&agi, 0, sizeof(agi));
2873         AST_STANDARD_APP_ARGS(args, tmp);
2874         args.argv[args.argc] = NULL;
2875 #if 0
2876          /* Answer if need be */
2877         if (chan->_state != AST_STATE_UP) {
2878                 if (ast_answer(chan))
2879                         return -1;
2880         }
2881 #endif
2882         res = launch_script(chan, args.argv[0], args.argv, fds, enhanced ? &efd : NULL, &pid);
2883         /* Async AGI do not require run_agi(), so just proceed if normal AGI
2884            or Fast AGI are setup with success. */
2885         if (res == AGI_RESULT_SUCCESS || res == AGI_RESULT_SUCCESS_FAST) {
2886                 int status = 0;
2887                 agi.fd = fds[1];
2888                 agi.ctrl = fds[0];
2889                 agi.audio = efd;
2890                 agi.fast = (res == AGI_RESULT_SUCCESS_FAST) ? 1 : 0;
2891                 res = run_agi(chan, args.argv[0], &agi, pid, &status, dead, args.argc, args.argv);
2892                 /* If the fork'd process returns non-zero, set AGISTATUS to FAILURE */
2893                 if ((res == AGI_RESULT_SUCCESS || res == AGI_RESULT_SUCCESS_FAST) && status)
2894                         res = AGI_RESULT_FAILURE;
2895                 if (fds[1] != fds[0])
2896                         close(fds[1]);
2897                 if (efd > -1)
2898                         close(efd);
2899         } 
2900         ast_safe_fork_cleanup();
2901
2902         switch (res) {
2903         case AGI_RESULT_SUCCESS:
2904         case AGI_RESULT_SUCCESS_FAST:
2905         case AGI_RESULT_SUCCESS_ASYNC:
2906                 pbx_builtin_setvar_helper(chan, "AGISTATUS", "SUCCESS");
2907                 break;
2908         case AGI_RESULT_FAILURE:
2909                 pbx_builtin_setvar_helper(chan, "AGISTATUS", "FAILURE");
2910                 break;
2911         case AGI_RESULT_NOTFOUND:
2912                 pbx_builtin_setvar_helper(chan, "AGISTATUS", "NOTFOUND");
2913                 break;
2914         case AGI_RESULT_HANGUP:
2915                 pbx_builtin_setvar_helper(chan, "AGISTATUS", "HANGUP");
2916                 return -1;
2917         }
2918
2919         return 0;
2920 }
2921
2922 static int agi_exec(struct ast_channel *chan, void *data)
2923 {
2924         if (!ast_check_hangup(chan))
2925                 return agi_exec_full(chan, data, 0, 0);
2926         else
2927                 return agi_exec_full(chan, data, 0, 1);
2928 }
2929
2930 static int eagi_exec(struct ast_channel *chan, void *data)
2931 {
2932         int readformat, res;
2933
2934         if (ast_check_hangup(chan)) {
2935                 ast_log(LOG_ERROR, "EAGI cannot be run on a dead/hungup channel, please use AGI.\n");
2936                 return 0;
2937         }
2938         readformat = chan->readformat;
2939         if (ast_set_read_format(chan, AST_FORMAT_SLINEAR)) {
2940                 ast_log(LOG_WARNING, "Unable to set channel '%s' to linear mode\n", chan->name);
2941                 return -1;
2942         }
2943         res = agi_exec_full(chan, data, 1, 0);
2944         if (!res) {
2945                 if (ast_set_read_format(chan, readformat)) {
2946                         ast_log(LOG_WARNING, "Unable to restore channel '%s' to format %s\n", chan->name, ast_getformatname(readformat));
2947                 }
2948         }
2949         return res;
2950 }
2951
2952 static int deadagi_exec(struct ast_channel *chan, void *data)
2953 {
2954         ast_log(LOG_WARNING, "DeadAGI has been deprecated, please use AGI in all cases!\n");
2955         return agi_exec(chan, data);
2956 }
2957
2958 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");
2959
2960 static struct ast_cli_entry cli_agi[] = {
2961         AST_CLI_DEFINE(handle_cli_agi_add_cmd,   "Add AGI command to a channel in Async AGI"),
2962         AST_CLI_DEFINE(handle_cli_agi_debug,     "Enable/Disable AGI debugging"),
2963         AST_CLI_DEFINE(handle_cli_agi_show,      "List AGI commands or specific help"),
2964         AST_CLI_DEFINE(handle_cli_agi_dump_html, "Dumps a list of AGI commands in HTML format", .deprecate_cmd = &cli_agi_dumphtml_deprecated)
2965 };
2966
2967 static int unload_module(void)
2968 {
2969         ast_cli_unregister_multiple(cli_agi, sizeof(cli_agi) / sizeof(struct ast_cli_entry));
2970         ast_agi_unregister_multiple(ast_module_info->self, commands, sizeof(commands) / sizeof(struct agi_command));
2971         ast_unregister_application(eapp);
2972         ast_unregister_application(deadapp);
2973         ast_manager_unregister("AGI");
2974         return ast_unregister_application(app);
2975 }
2976
2977 static int load_module(void)
2978 {
2979         ast_cli_register_multiple(cli_agi, sizeof(cli_agi) / sizeof(struct ast_cli_entry));
2980         ast_agi_register_multiple(ast_module_info->self, commands, sizeof(commands) / sizeof(struct agi_command));
2981         ast_register_application(deadapp, deadagi_exec, deadsynopsis, descrip);
2982         ast_register_application(eapp, eagi_exec, esynopsis, descrip);
2983         ast_manager_register2("AGI", EVENT_FLAG_CALL, action_add_agi_cmd, "Add an AGI command to execute by Async AGI", mandescr_asyncagi);
2984         return ast_register_application(app, agi_exec, synopsis, descrip);
2985 }
2986
2987 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS, "Asterisk Gateway Interface (AGI)",
2988                 .load = load_module,
2989                 .unload = unload_module,
2990                 );