Formatting fixes
[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/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 1;
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 1;
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], x, res;
607         sigset_t signal_set, old_set;
608         struct stat st;
609
610         if (!strncasecmp(script, "agi://", 6))
611                 return launch_netscript(script, argv, fds, efd, opid);
612         if (!strncasecmp(script, "agi:async", sizeof("agi:async")-1))
613                 return launch_asyncagi(chan, argv, efd);
614         
615         if (script[0] != '/') {
616                 snprintf(tmp, sizeof(tmp), "%s/%s", ast_config_AST_AGI_DIR, script);
617                 script = tmp;
618         }
619
620         /* Before even trying let's see if the file actually exists */
621         if (stat(script, &st)) {
622                 ast_log(LOG_WARNING, "Failed to execute '%s': File does not exist.\n", script);
623                 return AGI_RESULT_NOTFOUND;
624         }
625
626         if (pipe(toast)) {
627                 ast_log(LOG_WARNING, "Unable to create toast pipe: %s\n",strerror(errno));
628                 return AGI_RESULT_FAILURE;
629         }
630         if (pipe(fromast)) {
631                 ast_log(LOG_WARNING, "unable to create fromast pipe: %s\n", strerror(errno));
632                 close(toast[0]);
633                 close(toast[1]);
634                 return AGI_RESULT_FAILURE;
635         }
636         if (efd) {
637                 if (pipe(audio)) {
638                         ast_log(LOG_WARNING, "unable to create audio pipe: %s\n", strerror(errno));
639                         close(fromast[0]);
640                         close(fromast[1]);
641                         close(toast[0]);
642                         close(toast[1]);
643                         return AGI_RESULT_FAILURE;
644                 }
645                 res = fcntl(audio[1], F_GETFL);
646                 if (res > -1) 
647                         res = fcntl(audio[1], F_SETFL, res | O_NONBLOCK);
648                 if (res < 0) {
649                         ast_log(LOG_WARNING, "unable to set audio pipe parameters: %s\n", strerror(errno));
650                         close(fromast[0]);
651                         close(fromast[1]);
652                         close(toast[0]);
653                         close(toast[1]);
654                         close(audio[0]);
655                         close(audio[1]);
656                         return AGI_RESULT_FAILURE;
657                 }
658         }
659
660         /* Block SIGHUP during the fork - prevents a race */
661         sigfillset(&signal_set);
662         pthread_sigmask(SIG_BLOCK, &signal_set, &old_set);
663         if ((pid = fork()) < 0) {
664                 ast_log(LOG_WARNING, "Failed to fork(): %s\n", strerror(errno));
665                 pthread_sigmask(SIG_SETMASK, &old_set, NULL);
666                 return AGI_RESULT_FAILURE;
667         }
668         if (!pid) {
669                 /* Pass paths to AGI via environmental variables */
670                 setenv("AST_CONFIG_DIR", ast_config_AST_CONFIG_DIR, 1);
671                 setenv("AST_CONFIG_FILE", ast_config_AST_CONFIG_FILE, 1);
672                 setenv("AST_MODULE_DIR", ast_config_AST_MODULE_DIR, 1);
673                 setenv("AST_SPOOL_DIR", ast_config_AST_SPOOL_DIR, 1);
674                 setenv("AST_MONITOR_DIR", ast_config_AST_MONITOR_DIR, 1);
675                 setenv("AST_VAR_DIR", ast_config_AST_VAR_DIR, 1);
676                 setenv("AST_DATA_DIR", ast_config_AST_DATA_DIR, 1);
677                 setenv("AST_LOG_DIR", ast_config_AST_LOG_DIR, 1);
678                 setenv("AST_AGI_DIR", ast_config_AST_AGI_DIR, 1);
679                 setenv("AST_KEY_DIR", ast_config_AST_KEY_DIR, 1);
680                 setenv("AST_RUN_DIR", ast_config_AST_RUN_DIR, 1);
681
682                 /* Don't run AGI scripts with realtime priority -- it causes audio stutter */
683                 ast_set_priority(0);
684
685                 /* Redirect stdin and out, provide enhanced audio channel if desired */
686                 dup2(fromast[0], STDIN_FILENO);
687                 dup2(toast[1], STDOUT_FILENO);
688                 if (efd)
689                         dup2(audio[0], STDERR_FILENO + 1);
690                 else
691                         close(STDERR_FILENO + 1);
692
693                 /* Before we unblock our signals, return our trapped signals back to the defaults */
694                 signal(SIGHUP, SIG_DFL);
695                 signal(SIGCHLD, SIG_DFL);
696                 signal(SIGINT, SIG_DFL);
697                 signal(SIGURG, SIG_DFL);
698                 signal(SIGTERM, SIG_DFL);
699                 signal(SIGPIPE, SIG_DFL);
700                 signal(SIGXFSZ, SIG_DFL);
701
702                 /* unblock important signal handlers */
703                 if (pthread_sigmask(SIG_UNBLOCK, &signal_set, NULL)) {
704                         ast_log(LOG_WARNING, "unable to unblock signals for AGI script: %s\n", strerror(errno));
705                         _exit(1);
706                 }
707
708                 /* Close everything but stdin/out/error */
709                 for (x = STDERR_FILENO + 2; x < 1024; x++) 
710                         close(x);
711
712                 /* Execute script */
713                 /* XXX argv should be deprecated in favor of passing agi_argX paramaters */
714                 execv(script, argv);
715                 /* Can't use ast_log since FD's are closed */
716                 fprintf(stdout, "verbose \"Failed to execute '%s': %s\" 2\n", script, strerror(errno));
717                 fflush(stdout);
718                 _exit(1);
719         }
720         pthread_sigmask(SIG_SETMASK, &old_set, NULL);
721         ast_verb(3, "Launched AGI Script %s\n", script);
722         fds[0] = toast[0];
723         fds[1] = fromast[1];
724         if (efd)
725                 *efd = audio[1];
726         /* close what we're not using in the parent */
727         close(toast[1]);
728         close(fromast[0]);
729
730         if (efd)
731                 close(audio[0]);
732
733         *opid = pid;
734         return AGI_RESULT_SUCCESS;
735 }
736
737 static void setup_env(struct ast_channel *chan, char *request, int fd, int enhanced, int argc, char *argv[])
738 {
739         int count;
740
741         /* Print initial environment, with agi_request always being the first
742            thing */
743         ast_agi_fdprintf(chan, fd, "agi_request: %s\n", request);
744         ast_agi_fdprintf(chan, fd, "agi_channel: %s\n", chan->name);
745         ast_agi_fdprintf(chan, fd, "agi_language: %s\n", chan->language);
746         ast_agi_fdprintf(chan, fd, "agi_type: %s\n", chan->tech->type);
747         ast_agi_fdprintf(chan, fd, "agi_uniqueid: %s\n", chan->uniqueid);
748         ast_agi_fdprintf(chan, fd, "agi_version: %s\n", ast_get_version());
749
750         /* ANI/DNIS */
751         ast_agi_fdprintf(chan, fd, "agi_callerid: %s\n", S_OR(chan->cid.cid_num, "unknown"));
752         ast_agi_fdprintf(chan, fd, "agi_calleridname: %s\n", S_OR(chan->cid.cid_name, "unknown"));
753         ast_agi_fdprintf(chan, fd, "agi_callingpres: %d\n", chan->cid.cid_pres);
754         ast_agi_fdprintf(chan, fd, "agi_callingani2: %d\n", chan->cid.cid_ani2);
755         ast_agi_fdprintf(chan, fd, "agi_callington: %d\n", chan->cid.cid_ton);
756         ast_agi_fdprintf(chan, fd, "agi_callingtns: %d\n", chan->cid.cid_tns);
757         ast_agi_fdprintf(chan, fd, "agi_dnid: %s\n", S_OR(chan->cid.cid_dnid, "unknown"));
758         ast_agi_fdprintf(chan, fd, "agi_rdnis: %s\n", S_OR(chan->cid.cid_rdnis, "unknown"));
759
760         /* Context information */
761         ast_agi_fdprintf(chan, fd, "agi_context: %s\n", chan->context);
762         ast_agi_fdprintf(chan, fd, "agi_extension: %s\n", chan->exten);
763         ast_agi_fdprintf(chan, fd, "agi_priority: %d\n", chan->priority);
764         ast_agi_fdprintf(chan, fd, "agi_enhanced: %s\n", enhanced ? "1.0" : "0.0");
765
766         /* User information */
767         ast_agi_fdprintf(chan, fd, "agi_accountcode: %s\n", chan->accountcode ? chan->accountcode : "");
768         ast_agi_fdprintf(chan, fd, "agi_threadid: %ld\n", (long)pthread_self());
769
770         /* Send any parameters to the fastagi server that have been passed via the agi application */
771         /* Agi application paramaters take the form of: AGI(/path/to/example/script|${EXTEN}) */
772         for(count = 1; count < argc; count++)
773                 ast_agi_fdprintf(chan, fd, "agi_arg_%d: %s\n", count, argv[count]);
774
775         /* End with empty return */
776         ast_agi_fdprintf(chan, fd, "\n");
777 }
778
779 static int handle_answer(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
780 {
781         int res = 0;
782
783         /* Answer the channel */
784         if (chan->_state != AST_STATE_UP)
785                 res = ast_answer(chan);
786
787         ast_agi_fdprintf(chan, agi->fd, "200 result=%d\n", res);
788         return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
789 }
790
791 static int handle_waitfordigit(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
792 {
793         int res, to;
794
795         if (argc != 4)
796                 return RESULT_SHOWUSAGE;
797         if (sscanf(argv[3], "%d", &to) != 1)
798                 return RESULT_SHOWUSAGE;
799         res = ast_waitfordigit_full(chan, to, agi->audio, agi->ctrl);
800         ast_agi_fdprintf(chan, agi->fd, "200 result=%d\n", res);
801         return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
802 }
803
804 static int handle_sendtext(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
805 {
806         int res;
807
808         if (argc != 3)
809                 return RESULT_SHOWUSAGE;
810
811         /* At the moment, the parser (perhaps broken) returns with
812            the last argument PLUS the newline at the end of the input
813            buffer. This probably needs to be fixed, but I wont do that
814            because other stuff may break as a result. The right way
815            would probably be to strip off the trailing newline before
816            parsing, then here, add a newline at the end of the string
817            before sending it to ast_sendtext --DUDE */
818         res = ast_sendtext(chan, argv[2]);
819         ast_agi_fdprintf(chan, agi->fd, "200 result=%d\n", res);
820         return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
821 }
822
823 static int handle_recvchar(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
824 {
825         int res;
826
827         if (argc != 3)
828                 return RESULT_SHOWUSAGE;
829
830         res = ast_recvchar(chan,atoi(argv[2]));
831         if (res == 0) {
832                 ast_agi_fdprintf(chan, agi->fd, "200 result=%d (timeout)\n", res);
833                 return RESULT_SUCCESS;
834         }
835         if (res > 0) {
836                 ast_agi_fdprintf(chan, agi->fd, "200 result=%d\n", res);
837                 return RESULT_SUCCESS;
838         }
839         else {
840                 ast_agi_fdprintf(chan, agi->fd, "200 result=%d (hangup)\n", res);
841                 return RESULT_FAILURE;
842         }
843 }
844
845 static int handle_recvtext(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
846 {
847         char *buf;
848         
849         if (argc != 3)
850                 return RESULT_SHOWUSAGE;
851
852         buf = ast_recvtext(chan,atoi(argv[2]));
853         if (buf) {
854                 ast_agi_fdprintf(chan, agi->fd, "200 result=1 (%s)\n", buf);
855                 ast_free(buf);
856         } else {        
857                 ast_agi_fdprintf(chan, agi->fd, "200 result=-1\n");
858         }
859         return RESULT_SUCCESS;
860 }
861
862 static int handle_tddmode(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
863 {
864         int res, x;
865
866         if (argc != 3)
867                 return RESULT_SHOWUSAGE;
868
869         if (!strncasecmp(argv[2],"on",2)) 
870                 x = 1; 
871         else 
872                 x = 0;
873         if (!strncasecmp(argv[2],"mate",4)) 
874                 x = 2;
875         if (!strncasecmp(argv[2],"tdd",3))
876                 x = 1;
877         res = ast_channel_setoption(chan, AST_OPTION_TDD, &x, sizeof(char), 0);
878         if (res != RESULT_SUCCESS)
879                 ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
880         else
881                 ast_agi_fdprintf(chan, agi->fd, "200 result=1\n");
882         return RESULT_SUCCESS;
883 }
884
885 static int handle_sendimage(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
886 {
887         int res;
888
889         if (argc != 3)
890                 return RESULT_SHOWUSAGE;
891
892         res = ast_send_image(chan, argv[2]);
893         if (!ast_check_hangup(chan))
894                 res = 0;
895         ast_agi_fdprintf(chan, agi->fd, "200 result=%d\n", res);
896         return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
897 }
898
899 static int handle_controlstreamfile(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
900 {
901         int res = 0, skipms = 3000;
902         char *fwd = NULL, *rev = NULL, *pause = NULL, *stop = NULL;
903
904         if (argc < 5 || argc > 9)
905                 return RESULT_SHOWUSAGE;
906
907         if (!ast_strlen_zero(argv[4]))
908                 stop = argv[4];
909         else
910                 stop = NULL;
911         
912         if ((argc > 5) && (sscanf(argv[5], "%d", &skipms) != 1))
913                 return RESULT_SHOWUSAGE;
914
915         if (argc > 6 && !ast_strlen_zero(argv[6]))
916                 fwd = argv[6];
917         else
918                 fwd = "#";
919
920         if (argc > 7 && !ast_strlen_zero(argv[7]))
921                 rev = argv[7];
922         else
923                 rev = "*";
924         
925         if (argc > 8 && !ast_strlen_zero(argv[8]))
926                 pause = argv[8];
927         else
928                 pause = NULL;
929         
930         res = ast_control_streamfile(chan, argv[3], fwd, rev, stop, pause, NULL, skipms, NULL);
931         
932         ast_agi_fdprintf(chan, agi->fd, "200 result=%d\n", res);
933
934         return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
935 }
936
937 static int handle_streamfile(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
938 {
939         int res, vres;
940         struct ast_filestream *fs, *vfs;
941         long sample_offset = 0, max_length;
942         char *edigits = "";
943
944         if (argc < 4 || argc > 5)
945                 return RESULT_SHOWUSAGE;
946
947         if (argv[3]) 
948                 edigits = argv[3];
949
950         if ((argc > 4) && (sscanf(argv[4], "%ld", &sample_offset) != 1))
951                 return RESULT_SHOWUSAGE;
952
953         if (!(fs = ast_openstream(chan, argv[2], chan->language))) {
954                 ast_agi_fdprintf(chan, agi->fd, "200 result=%d endpos=%ld\n", 0, sample_offset);
955                 return RESULT_SUCCESS;
956         }
957
958         if ((vfs = ast_openvstream(chan, argv[2], chan->language)))
959                 ast_debug(1, "Ooh, found a video stream, too\n");
960                 
961         ast_verb(3, "Playing '%s' (escape_digits=%s) (sample_offset %ld)\n", argv[2], edigits, sample_offset);
962
963         ast_seekstream(fs, 0, SEEK_END);
964         max_length = ast_tellstream(fs);
965         ast_seekstream(fs, sample_offset, SEEK_SET);
966         res = ast_applystream(chan, fs);
967         if (vfs)
968                 vres = ast_applystream(chan, vfs);
969         ast_playstream(fs);
970         if (vfs)
971                 ast_playstream(vfs);
972         
973         res = ast_waitstream_full(chan, argv[3], agi->audio, agi->ctrl);
974         /* this is to check for if ast_waitstream closed the stream, we probably are at
975          * the end of the stream, return that amount, else check for the amount */
976         sample_offset = (chan->stream) ? ast_tellstream(fs) : max_length;
977         ast_stopstream(chan);
978         if (res == 1) {
979                 /* Stop this command, don't print a result line, as there is a new command */
980                 return RESULT_SUCCESS;
981         }
982         ast_agi_fdprintf(chan, agi->fd, "200 result=%d endpos=%ld\n", res, sample_offset);
983         return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
984 }
985
986 /*! \brief get option - really similar to the handle_streamfile, but with a timeout */
987 static int handle_getoption(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
988 {
989         int res, vres;
990         struct ast_filestream *fs, *vfs;
991         long sample_offset = 0, max_length;
992         int timeout = 0;
993         char *edigits = "";
994
995         if ( argc < 4 || argc > 5 )
996                 return RESULT_SHOWUSAGE;
997
998         if ( argv[3] ) 
999                 edigits = argv[3];
1000
1001         if ( argc == 5 )
1002                 timeout = atoi(argv[4]);
1003         else if (chan->pbx->dtimeout) {
1004                 /* by default dtimeout is set to 5sec */
1005                 timeout = chan->pbx->dtimeout * 1000; /* in msec */
1006         }
1007
1008         if (!(fs = ast_openstream(chan, argv[2], chan->language))) {
1009                 ast_agi_fdprintf(chan, agi->fd, "200 result=%d endpos=%ld\n", 0, sample_offset);
1010                 ast_log(LOG_WARNING, "Unable to open %s\n", argv[2]);
1011                 return RESULT_SUCCESS;
1012         }
1013
1014         if ((vfs = ast_openvstream(chan, argv[2], chan->language)))
1015                 ast_debug(1, "Ooh, found a video stream, too\n");
1016         
1017         ast_verb(3, "Playing '%s' (escape_digits=%s) (timeout %d)\n", argv[2], edigits, timeout);
1018
1019         ast_seekstream(fs, 0, SEEK_END);
1020         max_length = ast_tellstream(fs);
1021         ast_seekstream(fs, sample_offset, SEEK_SET);
1022         res = ast_applystream(chan, fs);
1023         if (vfs)
1024                 vres = ast_applystream(chan, vfs);
1025         ast_playstream(fs);
1026         if (vfs)
1027                 ast_playstream(vfs);
1028
1029         res = ast_waitstream_full(chan, argv[3], agi->audio, agi->ctrl);
1030         /* this is to check for if ast_waitstream closed the stream, we probably are at
1031          * the end of the stream, return that amount, else check for the amount */
1032         sample_offset = (chan->stream)?ast_tellstream(fs):max_length;
1033         ast_stopstream(chan);
1034         if (res == 1) {
1035                 /* Stop this command, don't print a result line, as there is a new command */
1036                 return RESULT_SUCCESS;
1037         }
1038
1039         /* If the user didnt press a key, wait for digitTimeout*/
1040         if (res == 0 ) {
1041                 res = ast_waitfordigit_full(chan, timeout, agi->audio, agi->ctrl);
1042                 /* Make sure the new result is in the escape digits of the GET OPTION */
1043                 if ( !strchr(edigits,res) )
1044                         res=0;
1045         }
1046
1047         ast_agi_fdprintf(chan, agi->fd, "200 result=%d endpos=%ld\n", res, sample_offset);
1048         return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
1049 }
1050
1051
1052
1053
1054 /*! \brief Say number in various language syntaxes */
1055 /* While waiting, we're sending a NULL.  */
1056 static int handle_saynumber(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
1057 {
1058         int res, num;
1059
1060         if (argc < 4 || argc > 5)
1061                 return RESULT_SHOWUSAGE;
1062         if (sscanf(argv[2], "%d", &num) != 1)
1063                 return RESULT_SHOWUSAGE;
1064         res = ast_say_number_full(chan, num, argv[3], chan->language, argc > 4 ? argv[4] : NULL, agi->audio, agi->ctrl);
1065         if (res == 1)
1066                 return RESULT_SUCCESS;
1067         ast_agi_fdprintf(chan, agi->fd, "200 result=%d\n", res);
1068         return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
1069 }
1070
1071 static int handle_saydigits(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
1072 {
1073         int res, num;
1074
1075         if (argc != 4)
1076                 return RESULT_SHOWUSAGE;
1077         if (sscanf(argv[2], "%d", &num) != 1)
1078                 return RESULT_SHOWUSAGE;
1079
1080         res = ast_say_digit_str_full(chan, argv[2], argv[3], chan->language, agi->audio, agi->ctrl);
1081         if (res == 1) /* New command */
1082                 return RESULT_SUCCESS;
1083         ast_agi_fdprintf(chan, agi->fd, "200 result=%d\n", res);
1084         return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
1085 }
1086
1087 static int handle_sayalpha(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
1088 {
1089         int res;
1090
1091         if (argc != 4)
1092                 return RESULT_SHOWUSAGE;
1093
1094         res = ast_say_character_str_full(chan, argv[2], argv[3], chan->language, agi->audio, agi->ctrl);
1095         if (res == 1) /* New command */
1096                 return RESULT_SUCCESS;
1097         ast_agi_fdprintf(chan, agi->fd, "200 result=%d\n", res);
1098         return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
1099 }
1100
1101 static int handle_saydate(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
1102 {
1103         int res, num;
1104
1105         if (argc != 4)
1106                 return RESULT_SHOWUSAGE;
1107         if (sscanf(argv[2], "%d", &num) != 1)
1108                 return RESULT_SHOWUSAGE;
1109         res = ast_say_date(chan, num, argv[3], chan->language);
1110         if (res == 1)
1111                 return RESULT_SUCCESS;
1112         ast_agi_fdprintf(chan, agi->fd, "200 result=%d\n", res);
1113         return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
1114 }
1115
1116 static int handle_saytime(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
1117 {
1118         int res, num;
1119
1120         if (argc != 4)
1121                 return RESULT_SHOWUSAGE;
1122         if (sscanf(argv[2], "%d", &num) != 1)
1123                 return RESULT_SHOWUSAGE;
1124         res = ast_say_time(chan, num, argv[3], chan->language);
1125         if (res == 1)
1126                 return RESULT_SUCCESS;
1127         ast_agi_fdprintf(chan, agi->fd, "200 result=%d\n", res);
1128         return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
1129 }
1130
1131 static int handle_saydatetime(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
1132 {
1133         int res = 0;
1134         time_t unixtime;
1135         char *format, *zone = NULL;
1136         
1137         if (argc < 4)
1138                 return RESULT_SHOWUSAGE;
1139
1140         if (argc > 4) {
1141                 format = argv[4];
1142         } else {
1143                 /* XXX this doesn't belong here, but in the 'say' module */
1144                 if (!strcasecmp(chan->language, "de")) {
1145                         format = "A dBY HMS";
1146                 } else {
1147                         format = "ABdY 'digits/at' IMp"; 
1148                 }
1149         }
1150
1151         if (argc > 5 && !ast_strlen_zero(argv[5]))
1152                 zone = argv[5];
1153
1154         if (ast_get_time_t(argv[2], &unixtime, 0, NULL))
1155                 return RESULT_SHOWUSAGE;
1156
1157         res = ast_say_date_with_format(chan, unixtime, argv[3], chan->language, format, zone);
1158         if (res == 1)
1159                 return RESULT_SUCCESS;
1160
1161         ast_agi_fdprintf(chan, agi->fd, "200 result=%d\n", res);
1162         return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
1163 }
1164
1165 static int handle_sayphonetic(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
1166 {
1167         int res;
1168
1169         if (argc != 4)
1170                 return RESULT_SHOWUSAGE;
1171
1172         res = ast_say_phonetic_str_full(chan, argv[2], argv[3], chan->language, agi->audio, agi->ctrl);
1173         if (res == 1) /* New command */
1174                 return RESULT_SUCCESS;
1175         ast_agi_fdprintf(chan, agi->fd, "200 result=%d\n", res);
1176         return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
1177 }
1178
1179 static int handle_getdata(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
1180 {
1181         int res, max, timeout;
1182         char data[1024];
1183
1184         if (argc < 3)
1185                 return RESULT_SHOWUSAGE;
1186         if (argc >= 4)
1187                 timeout = atoi(argv[3]); 
1188         else
1189                 timeout = 0;
1190         if (argc >= 5) 
1191                 max = atoi(argv[4]); 
1192         else
1193                 max = 1024;
1194         res = ast_app_getdata_full(chan, argv[2], data, max, timeout, agi->audio, agi->ctrl);
1195         if (res == 2)                   /* New command */
1196                 return RESULT_SUCCESS;
1197         else if (res == 1)
1198                 ast_agi_fdprintf(chan, agi->fd, "200 result=%s (timeout)\n", data);
1199         else if (res < 0 )
1200                 ast_agi_fdprintf(chan, agi->fd, "200 result=-1\n");
1201         else
1202                 ast_agi_fdprintf(chan, agi->fd, "200 result=%s\n", data);
1203         return RESULT_SUCCESS;
1204 }
1205
1206 static int handle_setcontext(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
1207 {
1208
1209         if (argc != 3)
1210                 return RESULT_SHOWUSAGE;
1211         ast_copy_string(chan->context, argv[2], sizeof(chan->context));
1212         ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
1213         return RESULT_SUCCESS;
1214 }
1215         
1216 static int handle_setextension(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1217 {
1218         if (argc != 3)
1219                 return RESULT_SHOWUSAGE;
1220         ast_copy_string(chan->exten, argv[2], sizeof(chan->exten));
1221         ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
1222         return RESULT_SUCCESS;
1223 }
1224
1225 static int handle_setpriority(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1226 {
1227         int pri;
1228
1229         if (argc != 3)
1230                 return RESULT_SHOWUSAGE;        
1231
1232         if (sscanf(argv[2], "%d", &pri) != 1) {
1233                 if ((pri = ast_findlabel_extension(chan, chan->context, chan->exten, argv[2], chan->cid.cid_num)) < 1)
1234                         return RESULT_SHOWUSAGE;
1235         }
1236
1237         ast_explicit_goto(chan, NULL, NULL, pri);
1238         ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
1239         return RESULT_SUCCESS;
1240 }
1241                 
1242 static int handle_recordfile(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
1243 {
1244         struct ast_filestream *fs;
1245         struct ast_frame *f;
1246         struct timeval start;
1247         long sample_offset = 0;
1248         int res = 0;
1249         int ms;
1250
1251         struct ast_dsp *sildet=NULL;         /* silence detector dsp */
1252         int totalsilence = 0;
1253         int dspsilence = 0;
1254         int silence = 0;                /* amount of silence to allow */
1255         int gotsilence = 0;             /* did we timeout for silence? */
1256         char *silencestr=NULL;
1257         int rfmt=0;
1258
1259
1260         /* XXX EAGI FIXME XXX */
1261
1262         if (argc < 6)
1263                 return RESULT_SHOWUSAGE;
1264         if (sscanf(argv[5], "%d", &ms) != 1)
1265                 return RESULT_SHOWUSAGE;
1266
1267         if (argc > 6)
1268                 silencestr = strchr(argv[6],'s');
1269         if ((argc > 7) && (!silencestr))
1270                 silencestr = strchr(argv[7],'s');
1271         if ((argc > 8) && (!silencestr))
1272                 silencestr = strchr(argv[8],'s');
1273
1274         if (silencestr) {
1275                 if (strlen(silencestr) > 2) {
1276                         if ((silencestr[0] == 's') && (silencestr[1] == '=')) {
1277                                 silencestr++;
1278                                 silencestr++;
1279                                 if (silencestr)
1280                                         silence = atoi(silencestr);
1281                                 if (silence > 0)
1282                                         silence *= 1000;
1283                         }
1284                 }
1285         }
1286
1287         if (silence > 0) {
1288                 rfmt = chan->readformat;
1289                 res = ast_set_read_format(chan, AST_FORMAT_SLINEAR);
1290                 if (res < 0) {
1291                         ast_log(LOG_WARNING, "Unable to set to linear mode, giving up\n");
1292                         return -1;
1293                 }
1294                 sildet = ast_dsp_new();
1295                 if (!sildet) {
1296                         ast_log(LOG_WARNING, "Unable to create silence detector :(\n");
1297                         return -1;
1298                 }
1299                 ast_dsp_set_threshold(sildet, 256);
1300         }
1301
1302         /* backward compatibility, if no offset given, arg[6] would have been
1303          * caught below and taken to be a beep, else if it is a digit then it is a
1304          * offset */
1305         if ((argc >6) && (sscanf(argv[6], "%ld", &sample_offset) != 1) && (!strchr(argv[6], '=')))
1306                 res = ast_streamfile(chan, "beep", chan->language);
1307
1308         if ((argc > 7) && (!strchr(argv[7], '=')))
1309                 res = ast_streamfile(chan, "beep", chan->language);
1310
1311         if (!res)
1312                 res = ast_waitstream(chan, argv[4]);
1313         if (res) {
1314                 ast_agi_fdprintf(chan, agi->fd, "200 result=%d (randomerror) endpos=%ld\n", res, sample_offset);
1315         } else {
1316                 fs = ast_writefile(argv[2], argv[3], NULL, O_CREAT | O_WRONLY | (sample_offset ? O_APPEND : 0), 0, AST_FILE_MODE);
1317                 if (!fs) {
1318                         res = -1;
1319                         ast_agi_fdprintf(chan, agi->fd, "200 result=%d (writefile)\n", res);
1320                         if (sildet)
1321                                 ast_dsp_free(sildet);
1322                         return RESULT_FAILURE;
1323                 }
1324                 
1325                 /* Request a video update */
1326                 ast_indicate(chan, AST_CONTROL_VIDUPDATE);
1327         
1328                 chan->stream = fs;
1329                 ast_applystream(chan,fs);
1330                 /* really should have checks */
1331                 ast_seekstream(fs, sample_offset, SEEK_SET);
1332                 ast_truncstream(fs);
1333                 
1334                 start = ast_tvnow();
1335                 while ((ms < 0) || ast_tvdiff_ms(ast_tvnow(), start) < ms) {
1336                         res = ast_waitfor(chan, -1);
1337                         if (res < 0) {
1338                                 ast_closestream(fs);
1339                                 ast_agi_fdprintf(chan, agi->fd, "200 result=%d (waitfor) endpos=%ld\n", res,sample_offset);
1340                                 if (sildet)
1341                                         ast_dsp_free(sildet);
1342                                 return RESULT_FAILURE;
1343                         }
1344                         f = ast_read(chan);
1345                         if (!f) {
1346                                 ast_agi_fdprintf(chan, agi->fd, "200 result=%d (hangup) endpos=%ld\n", -1, sample_offset);
1347                                 ast_closestream(fs);
1348                                 if (sildet)
1349                                         ast_dsp_free(sildet);
1350                                 return RESULT_FAILURE;
1351                         }
1352                         switch(f->frametype) {
1353                         case AST_FRAME_DTMF:
1354                                 if (strchr(argv[4], f->subclass)) {
1355                                         /* This is an interrupting chracter, so rewind to chop off any small
1356                                            amount of DTMF that may have been recorded
1357                                         */
1358                                         ast_stream_rewind(fs, 200);
1359                                         ast_truncstream(fs);
1360                                         sample_offset = ast_tellstream(fs);
1361                                         ast_agi_fdprintf(chan, agi->fd, "200 result=%d (dtmf) endpos=%ld\n", f->subclass, sample_offset);
1362                                         ast_closestream(fs);
1363                                         ast_frfree(f);
1364                                         if (sildet)
1365                                                 ast_dsp_free(sildet);
1366                                         return RESULT_SUCCESS;
1367                                 }
1368                                 break;
1369                         case AST_FRAME_VOICE:
1370                                 ast_writestream(fs, f);
1371                                 /* this is a safe place to check progress since we know that fs
1372                                  * is valid after a write, and it will then have our current
1373                                  * location */
1374                                 sample_offset = ast_tellstream(fs);
1375                                 if (silence > 0) {
1376                                         dspsilence = 0;
1377                                         ast_dsp_silence(sildet, f, &dspsilence);
1378                                         if (dspsilence) {
1379                                                 totalsilence = dspsilence;
1380                                         } else {
1381                                                 totalsilence = 0;
1382                                         }
1383                                         if (totalsilence > silence) {
1384                                                 /* Ended happily with silence */
1385                                                 gotsilence = 1;
1386                                                 break;
1387                                         }
1388                                 }
1389                                 break;
1390                         case AST_FRAME_VIDEO:
1391                                 ast_writestream(fs, f);
1392                         default:
1393                                 /* Ignore all other frames */
1394                                 break;
1395                         }
1396                         ast_frfree(f);
1397                         if (gotsilence)
1398                                 break;
1399                 }
1400
1401                         if (gotsilence) {
1402                                 ast_stream_rewind(fs, silence-1000);
1403                                 ast_truncstream(fs);
1404                                 sample_offset = ast_tellstream(fs);
1405                 }               
1406                 ast_agi_fdprintf(chan, agi->fd, "200 result=%d (timeout) endpos=%ld\n", res, sample_offset);
1407                 ast_closestream(fs);
1408         }
1409
1410         if (silence > 0) {
1411                 res = ast_set_read_format(chan, rfmt);
1412                 if (res)
1413                         ast_log(LOG_WARNING, "Unable to restore read format on '%s'\n", chan->name);
1414                         ast_dsp_free(sildet);
1415         }
1416         return RESULT_SUCCESS;
1417 }
1418
1419 static int handle_autohangup(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
1420 {
1421         int timeout;
1422
1423         if (argc != 3)
1424                 return RESULT_SHOWUSAGE;
1425         if (sscanf(argv[2], "%d", &timeout) != 1)
1426                 return RESULT_SHOWUSAGE;
1427         if (timeout < 0)
1428                 timeout = 0;
1429         if (timeout)
1430                 chan->whentohangup = time(NULL) + timeout;
1431         else
1432                 chan->whentohangup = 0;
1433         ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
1434         return RESULT_SUCCESS;
1435 }
1436
1437 static int handle_hangup(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1438 {
1439         struct ast_channel *c;
1440
1441         if (argc == 1) {
1442                 /* no argument: hangup the current channel */
1443                 ast_softhangup(chan,AST_SOFTHANGUP_EXPLICIT);
1444                 ast_agi_fdprintf(chan, agi->fd, "200 result=1\n");
1445                 return RESULT_SUCCESS;
1446         } else if (argc == 2) {
1447                 /* one argument: look for info on the specified channel */
1448                 c = ast_get_channel_by_name_locked(argv[1]);
1449                 if (c) {
1450                         /* we have a matching channel */
1451                         ast_softhangup(c,AST_SOFTHANGUP_EXPLICIT);
1452                         ast_agi_fdprintf(chan, agi->fd, "200 result=1\n");
1453                         ast_channel_unlock(c);
1454                         return RESULT_SUCCESS;
1455                 }
1456                 /* if we get this far no channel name matched the argument given */
1457                 ast_agi_fdprintf(chan, agi->fd, "200 result=-1\n");
1458                 return RESULT_SUCCESS;
1459         } else {
1460                 return RESULT_SHOWUSAGE;
1461         }
1462 }
1463
1464 static int handle_exec(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1465 {
1466         int res;
1467         struct ast_app *app;
1468
1469         if (argc < 2)
1470                 return RESULT_SHOWUSAGE;
1471
1472         ast_verb(3, "AGI Script Executing Application: (%s) Options: (%s)\n", argv[1], argv[2]);
1473
1474         if ((app = pbx_findapp(argv[1]))) {
1475                 res = pbx_exec(chan, app, argv[2]);
1476         } else {
1477                 ast_log(LOG_WARNING, "Could not find application (%s)\n", argv[1]);
1478                 res = -2;
1479         }
1480         ast_agi_fdprintf(chan, agi->fd, "200 result=%d\n", res);
1481
1482         /* Even though this is wrong, users are depending upon this result. */
1483         return res;
1484 }
1485
1486 static int handle_setcallerid(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1487 {
1488         char tmp[256]="";
1489         char *l = NULL, *n = NULL;
1490
1491         if (argv[2]) {
1492                 ast_copy_string(tmp, argv[2], sizeof(tmp));
1493                 ast_callerid_parse(tmp, &n, &l);
1494                 if (l)
1495                         ast_shrink_phone_number(l);
1496                 else
1497                         l = "";
1498                 if (!n)
1499                         n = "";
1500                 ast_set_callerid(chan, l, n, NULL);
1501         }
1502
1503         ast_agi_fdprintf(chan, agi->fd, "200 result=1\n");
1504         return RESULT_SUCCESS;
1505 }
1506
1507 static int handle_channelstatus(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1508 {
1509         struct ast_channel *c;
1510         if (argc == 2) {
1511                 /* no argument: supply info on the current channel */
1512                 ast_agi_fdprintf(chan, agi->fd, "200 result=%d\n", chan->_state);
1513                 return RESULT_SUCCESS;
1514         } else if (argc == 3) {
1515                 /* one argument: look for info on the specified channel */
1516                 c = ast_get_channel_by_name_locked(argv[2]);
1517                 if (c) {
1518                         ast_agi_fdprintf(chan, agi->fd, "200 result=%d\n", c->_state);
1519                         ast_channel_unlock(c);
1520                         return RESULT_SUCCESS;
1521                 }
1522                 /* if we get this far no channel name matched the argument given */
1523                 ast_agi_fdprintf(chan, agi->fd, "200 result=-1\n");
1524                 return RESULT_SUCCESS;
1525         } else {
1526                 return RESULT_SHOWUSAGE;
1527         }
1528 }
1529
1530 static int handle_setvariable(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1531 {
1532         if (argv[3])
1533                 pbx_builtin_setvar_helper(chan, argv[2], argv[3]);
1534
1535         ast_agi_fdprintf(chan, agi->fd, "200 result=1\n");
1536         return RESULT_SUCCESS;
1537 }
1538
1539 static int handle_getvariable(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1540 {
1541         char *ret;
1542         char tempstr[1024];
1543
1544         if (argc != 3)
1545                 return RESULT_SHOWUSAGE;
1546
1547         /* check if we want to execute an ast_custom_function */
1548         if (!ast_strlen_zero(argv[2]) && (argv[2][strlen(argv[2]) - 1] == ')')) {
1549                 ret = ast_func_read(chan, argv[2], tempstr, sizeof(tempstr)) ? NULL : tempstr;
1550         } else {
1551                 pbx_retrieve_variable(chan, argv[2], &ret, tempstr, sizeof(tempstr), NULL);
1552         }
1553
1554         if (ret)
1555                 ast_agi_fdprintf(chan, agi->fd, "200 result=1 (%s)\n", ret);
1556         else
1557                 ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
1558
1559         return RESULT_SUCCESS;
1560 }
1561
1562 static int handle_getvariablefull(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1563 {
1564         char tmp[4096];
1565         struct ast_channel *chan2=NULL;
1566
1567         if ((argc != 4) && (argc != 5))
1568                 return RESULT_SHOWUSAGE;
1569         if (argc == 5) {
1570                 chan2 = ast_get_channel_by_name_locked(argv[4]);
1571         } else {
1572                 chan2 = chan;
1573         }
1574         if (chan2) {
1575                 pbx_substitute_variables_helper(chan2, argv[3], tmp, sizeof(tmp) - 1);
1576                 ast_agi_fdprintf(chan, agi->fd, "200 result=1 (%s)\n", tmp);
1577         } else {
1578                 ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
1579         }
1580         if (chan2 && (chan2 != chan))
1581                 ast_channel_unlock(chan2);
1582         return RESULT_SUCCESS;
1583 }
1584
1585 static int handle_verbose(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1586 {
1587         int level = 0;
1588
1589         if (argc < 2)
1590                 return RESULT_SHOWUSAGE;
1591
1592         if (argv[2])
1593                 sscanf(argv[2], "%d", &level);
1594
1595         ast_verb(level, "%s: %s\n", chan->data, argv[1]);
1596         
1597         ast_agi_fdprintf(chan, agi->fd, "200 result=1\n");
1598         
1599         return RESULT_SUCCESS;
1600 }
1601
1602 static int handle_dbget(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1603 {
1604         int res;
1605         char tmp[256];
1606
1607         if (argc != 4)
1608                 return RESULT_SHOWUSAGE;
1609         res = ast_db_get(argv[2], argv[3], tmp, sizeof(tmp));
1610         if (res) 
1611                 ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
1612         else
1613                 ast_agi_fdprintf(chan, agi->fd, "200 result=1 (%s)\n", tmp);
1614
1615         return RESULT_SUCCESS;
1616 }
1617
1618 static int handle_dbput(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1619 {
1620         int res;
1621
1622         if (argc != 5)
1623                 return RESULT_SHOWUSAGE;
1624         res = ast_db_put(argv[2], argv[3], argv[4]);
1625         ast_agi_fdprintf(chan, agi->fd, "200 result=%c\n", res ? '0' : '1');
1626         return RESULT_SUCCESS;
1627 }
1628
1629 static int handle_dbdel(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1630 {
1631         int res;
1632
1633         if (argc != 4)
1634                 return RESULT_SHOWUSAGE;
1635         res = ast_db_del(argv[2], argv[3]);
1636         ast_agi_fdprintf(chan, agi->fd, "200 result=%c\n", res ? '0' : '1');
1637         return RESULT_SUCCESS;
1638 }
1639
1640 static int handle_dbdeltree(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1641 {
1642         int res;
1643
1644         if ((argc < 3) || (argc > 4))
1645                 return RESULT_SHOWUSAGE;
1646         if (argc == 4)
1647                 res = ast_db_deltree(argv[2], argv[3]);
1648         else
1649                 res = ast_db_deltree(argv[2], NULL);
1650
1651         ast_agi_fdprintf(chan, agi->fd, "200 result=%c\n", res ? '0' : '1');
1652         return RESULT_SUCCESS;
1653 }
1654
1655 static char *handle_cli_agi_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1656 {
1657         switch (cmd) {
1658         case CLI_INIT:
1659                 e->command = "agi set debug [on|off]";
1660                 e->usage =
1661                         "Usage: agi set debug [on|off]\n"
1662                         "       Enables/disables dumping of AGI transactions for\n"
1663                         "       debugging purposes.\n";
1664                 return NULL;
1665
1666         case CLI_GENERATE:
1667                 return NULL;
1668         }
1669
1670         if (a->argc != e->args)
1671                 return CLI_SHOWUSAGE;
1672
1673         if (strncasecmp(a->argv[3], "off", 3) == 0) {
1674                 agidebug = 0;
1675         } else if (strncasecmp(a->argv[3], "on", 2) == 0) {
1676                 agidebug = 1;
1677         } else {
1678                 return CLI_SHOWUSAGE;
1679         }
1680         ast_cli(a->fd, "AGI Debugging %sabled\n", agidebug ? "En" : "Dis");
1681         return CLI_SUCCESS;
1682 }
1683
1684 static int handle_noop(struct ast_channel *chan, AGI *agi, int arg, char *argv[])
1685 {
1686         ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
1687         return RESULT_SUCCESS;
1688 }
1689
1690 static int handle_setmusic(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
1691 {
1692         if (!strncasecmp(argv[2], "on", 2))
1693                 ast_moh_start(chan, argc > 3 ? argv[3] : NULL, NULL);
1694         else if (!strncasecmp(argv[2], "off", 3))
1695                 ast_moh_stop(chan);
1696         ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
1697         return RESULT_SUCCESS;
1698 }
1699
1700 static int handle_speechcreate(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1701 {
1702         /* If a structure already exists, return an error */
1703         if (agi->speech) {
1704                 ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
1705                 return RESULT_SUCCESS;
1706         }
1707         
1708         if ((agi->speech = ast_speech_new(argv[2], AST_FORMAT_SLINEAR)))
1709                 ast_agi_fdprintf(chan, agi->fd, "200 result=1\n");
1710         else
1711                 ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
1712         
1713         return RESULT_SUCCESS;
1714 }
1715
1716 static int handle_speechset(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1717 {
1718         /* Check for minimum arguments */
1719         if (argc != 3)
1720                 return RESULT_SHOWUSAGE;
1721         
1722         /* Check to make sure speech structure exists */
1723         if (!agi->speech) {
1724                 ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
1725                 return RESULT_SUCCESS;
1726         }
1727         
1728         ast_speech_change(agi->speech, argv[2], argv[3]);
1729         ast_agi_fdprintf(chan, agi->fd, "200 result=1\n");
1730         
1731         return RESULT_SUCCESS;
1732 }
1733
1734 static int handle_speechdestroy(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1735 {
1736         if (agi->speech) {
1737                 ast_speech_destroy(agi->speech);
1738                 agi->speech = NULL;
1739                 ast_agi_fdprintf(chan, agi->fd, "200 result=1\n");
1740         } else {
1741                 ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
1742         }
1743         
1744         return RESULT_SUCCESS;
1745 }
1746
1747 static int handle_speechloadgrammar(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1748 {
1749         if (argc != 5)
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_load(agi->speech, argv[3], argv[4]))
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_speechunloadgrammar(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_unload(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_speechactivategrammar(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_activate(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 handle_speechdeactivategrammar(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1802 {
1803         if (argc != 4)
1804                 return RESULT_SHOWUSAGE;
1805         
1806         if (!agi->speech) {
1807                 ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
1808                 return RESULT_SUCCESS;
1809         }
1810         
1811         if (ast_speech_grammar_deactivate(agi->speech, argv[3]))
1812                 ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
1813         else
1814                 ast_agi_fdprintf(chan, agi->fd, "200 result=1\n");
1815         
1816         return RESULT_SUCCESS;
1817 }
1818
1819 static int speech_streamfile(struct ast_channel *chan, const char *filename, const char *preflang, int offset)
1820 {
1821         struct ast_filestream *fs = NULL;
1822         
1823         if (!(fs = ast_openstream(chan, filename, preflang)))
1824                 return -1;
1825         
1826         if (offset)
1827                 ast_seekstream(fs, offset, SEEK_SET);
1828         
1829         if (ast_applystream(chan, fs))
1830                 return -1;
1831         
1832         if (ast_playstream(fs))
1833                 return -1;
1834         
1835         return 0;
1836 }
1837
1838 static int handle_speechrecognize(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1839 {
1840         struct ast_speech *speech = agi->speech;
1841         char *prompt, dtmf = 0, tmp[4096] = "", *buf = tmp;
1842         int timeout = 0, offset = 0, old_read_format = 0, res = 0, i = 0;
1843         long current_offset = 0;
1844         const char *reason = NULL;
1845         struct ast_frame *fr = NULL;
1846         struct ast_speech_result *result = NULL;
1847         size_t left = sizeof(tmp);
1848         time_t start = 0, current;
1849         
1850         if (argc < 4)
1851                 return RESULT_SHOWUSAGE;
1852         
1853         if (!speech) {
1854                 ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
1855                 return RESULT_SUCCESS;
1856         }
1857         
1858         prompt = argv[2];
1859         timeout = atoi(argv[3]);
1860         
1861         /* If offset is specified then convert from text to integer */
1862         if (argc == 5)
1863                 offset = atoi(argv[4]);
1864         
1865         /* We want frames coming in signed linear */
1866         old_read_format = chan->readformat;
1867         if (ast_set_read_format(chan, AST_FORMAT_SLINEAR)) {
1868                 ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
1869                 return RESULT_SUCCESS;
1870         }
1871         
1872         /* Setup speech structure */
1873         if (speech->state == AST_SPEECH_STATE_NOT_READY || speech->state == AST_SPEECH_STATE_DONE) {
1874                 ast_speech_change_state(speech, AST_SPEECH_STATE_NOT_READY);
1875                 ast_speech_start(speech);
1876         }
1877         
1878         /* Start playing prompt */
1879         speech_streamfile(chan, prompt, chan->language, offset);
1880         
1881         /* Go into loop reading in frames, passing to speech thingy, checking for hangup, all that jazz */
1882         while (ast_strlen_zero(reason)) {
1883                 /* Run scheduled items */
1884                 ast_sched_runq(chan->sched);
1885                 
1886                 /* See maximum time of waiting */
1887                 if ((res = ast_sched_wait(chan->sched)) < 0)
1888                         res = 1000;
1889                 
1890                 /* Wait for frame */
1891                 if (ast_waitfor(chan, res) > 0) {
1892                         if (!(fr = ast_read(chan))) {
1893                                 reason = "hangup";
1894                                 break;
1895                         }
1896                 }
1897                 
1898                 /* Perform timeout check */
1899                 if ((timeout > 0) && (start > 0)) {
1900                         time(&current);
1901                         if ((current - start) >= timeout) {
1902                                 reason = "timeout";
1903                                 if (fr)
1904                                         ast_frfree(fr);
1905                                 break;
1906                         }
1907                 }
1908                 
1909                 /* Check the speech structure for any changes */
1910                 ast_mutex_lock(&speech->lock);
1911                 
1912                 /* See if we need to quiet the audio stream playback */
1913                 if (ast_test_flag(speech, AST_SPEECH_QUIET) && chan->stream) {
1914                         current_offset = ast_tellstream(chan->stream);
1915                         ast_stopstream(chan);
1916                         ast_clear_flag(speech, AST_SPEECH_QUIET);
1917                 }
1918                 
1919                 /* Check each state */
1920                 switch (speech->state) {
1921                 case AST_SPEECH_STATE_READY:
1922                         /* If the stream is done, start timeout calculation */
1923                         if ((timeout > 0) && ((!chan->stream) || (chan->streamid == -1 && chan->timingfunc == NULL))) {
1924                                 ast_stopstream(chan);
1925                                 time(&start);
1926                         }
1927                         /* Write audio frame data into speech engine if possible */
1928                         if (fr && fr->frametype == AST_FRAME_VOICE)
1929                                 ast_speech_write(speech, fr->data, fr->datalen);
1930                         break;
1931                 case AST_SPEECH_STATE_WAIT:
1932                         /* Cue waiting sound if not already playing */
1933                         if ((!chan->stream) || (chan->streamid == -1 && chan->timingfunc == NULL)) {
1934                                 ast_stopstream(chan);
1935                                 /* If a processing sound exists, or is not none - play it */
1936                                 if (!ast_strlen_zero(speech->processing_sound) && strcasecmp(speech->processing_sound, "none"))
1937                                         speech_streamfile(chan, speech->processing_sound, chan->language, 0);
1938                         }
1939                         break;
1940                 case AST_SPEECH_STATE_DONE:
1941                         /* Get the results */
1942                         speech->results = ast_speech_results_get(speech);
1943                         /* Change state to not ready */
1944                         ast_speech_change_state(speech, AST_SPEECH_STATE_NOT_READY);
1945                         reason = "speech";
1946                         break;
1947                 default:
1948                         break;
1949                 }
1950                 ast_mutex_unlock(&speech->lock);
1951                 
1952                 /* Check frame for DTMF or hangup */
1953                 if (fr) {
1954                         if (fr->frametype == AST_FRAME_DTMF) {
1955                                 reason = "dtmf";
1956                                 dtmf = fr->subclass;
1957                         } else if (fr->frametype == AST_FRAME_CONTROL && fr->subclass == AST_CONTROL_HANGUP) {
1958                                 reason = "hangup";
1959                         }
1960                         ast_frfree(fr);
1961                 }
1962         }
1963         
1964         if (!strcasecmp(reason, "speech")) {
1965                 /* Build string containing speech results */
1966                 for (result = speech->results; result; result = AST_LIST_NEXT(result, list)) {
1967                         /* Build result string */
1968                         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);
1969                         /* Increment result count */
1970                         i++;
1971                 }
1972                 /* Print out */
1973                 ast_agi_fdprintf(chan, agi->fd, "200 result=1 (speech) endpos=%ld results=%d %s\n", current_offset, i, tmp);
1974         } else if (!strcasecmp(reason, "dtmf")) {
1975                 ast_agi_fdprintf(chan, agi->fd, "200 result=1 (digit) digit=%c endpos=%ld\n", dtmf, current_offset);
1976         } else if (!strcasecmp(reason, "hangup") || !strcasecmp(reason, "timeout")) {
1977                 ast_agi_fdprintf(chan, agi->fd, "200 result=1 (%s) endpos=%ld\n", reason, current_offset);
1978         } else {
1979                 ast_agi_fdprintf(chan, agi->fd, "200 result=0 endpos=%ld\n", current_offset);
1980         }
1981         
1982         return RESULT_SUCCESS;
1983 }
1984
1985 static int handle_asyncagi_break(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
1986 {
1987         ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
1988         return AST_PBX_KEEPALIVE;
1989 }
1990
1991 static char usage_setmusic[] =
1992 " Usage: SET MUSIC ON <on|off> <class>\n"
1993 "       Enables/Disables the music on hold generator.  If <class> is\n"
1994 " not specified, then the default music on hold class will be used.\n"
1995 " Always returns 0.\n";
1996
1997 static char usage_dbput[] =
1998 " Usage: DATABASE PUT <family> <key> <value>\n"
1999 "       Adds or updates an entry in the Asterisk database for a\n"
2000 " given family, key, and value.\n"
2001 " Returns 1 if successful, 0 otherwise.\n";
2002
2003 static char usage_dbget[] =
2004 " Usage: DATABASE GET <family> <key>\n"
2005 "       Retrieves an entry in the Asterisk database for a\n"
2006 " given family and key.\n"
2007 " Returns 0 if <key> is not set.  Returns 1 if <key>\n"
2008 " is set and returns the variable in parentheses.\n"
2009 " Example return code: 200 result=1 (testvariable)\n";
2010
2011 static char usage_dbdel[] =
2012 " Usage: DATABASE DEL <family> <key>\n"
2013 "       Deletes an entry in the Asterisk database for a\n"
2014 " given family and key.\n"
2015 " Returns 1 if successful, 0 otherwise.\n";
2016
2017 static char usage_dbdeltree[] =
2018 " Usage: DATABASE DELTREE <family> [keytree]\n"
2019 "       Deletes a family or specific keytree within a family\n"
2020 " in the Asterisk database.\n"
2021 " Returns 1 if successful, 0 otherwise.\n";
2022
2023 static char usage_verbose[] =
2024 " Usage: VERBOSE <message> <level>\n"
2025 "       Sends <message> to the console via verbose message system.\n"
2026 " <level> is the the verbose level (1-4)\n"
2027 " Always returns 1.\n";
2028
2029 static char usage_getvariable[] =
2030 " Usage: GET VARIABLE <variablename>\n"
2031 "       Returns 0 if <variablename> is not set.  Returns 1 if <variablename>\n"
2032 " is set and returns the variable in parentheses.\n"
2033 " example return code: 200 result=1 (testvariable)\n";
2034
2035 static char usage_getvariablefull[] =
2036 " Usage: GET FULL VARIABLE <variablename> [<channel name>]\n"
2037 "       Returns 0 if <variablename> is not set or channel does not exist.  Returns 1\n"
2038 "if <variablename>  is set and returns the variable in parenthesis.  Understands\n"
2039 "complex variable names and builtin variables, unlike GET VARIABLE.\n"
2040 " example return code: 200 result=1 (testvariable)\n";
2041
2042 static char usage_setvariable[] =
2043 " Usage: SET VARIABLE <variablename> <value>\n";
2044
2045 static char usage_channelstatus[] =
2046 " Usage: CHANNEL STATUS [<channelname>]\n"
2047 "       Returns the status of the specified channel.\n" 
2048 " If no channel name is given the returns the status of the\n"
2049 " current channel.  Return values:\n"
2050 "  0 Channel is down and available\n"
2051 "  1 Channel is down, but reserved\n"
2052 "  2 Channel is off hook\n"
2053 "  3 Digits (or equivalent) have been dialed\n"
2054 "  4 Line is ringing\n"
2055 "  5 Remote end is ringing\n"
2056 "  6 Line is up\n"
2057 "  7 Line is busy\n";
2058
2059 static char usage_setcallerid[] =
2060 " Usage: SET CALLERID <number>\n"
2061 "       Changes the callerid of the current channel.\n";
2062
2063 static char usage_exec[] =
2064 " Usage: EXEC <application> <options>\n"
2065 "       Executes <application> with given <options>.\n"
2066 " Returns whatever the application returns, or -2 on failure to find application\n";
2067
2068 static char usage_hangup[] =
2069 " Usage: HANGUP [<channelname>]\n"
2070 "       Hangs up the specified channel.\n"
2071 " If no channel name is given, hangs up the current channel\n";
2072
2073 static char usage_answer[] = 
2074 " Usage: ANSWER\n"
2075 "       Answers channel if not already in answer state. Returns -1 on\n"
2076 " channel failure, or 0 if successful.\n";
2077
2078 static char usage_waitfordigit[] = 
2079 " Usage: WAIT FOR DIGIT <timeout>\n"
2080 "       Waits up to 'timeout' milliseconds for channel to receive a DTMF digit.\n"
2081 " Returns -1 on channel failure, 0 if no digit is received in the timeout, or\n"
2082 " the numerical value of the ascii of the digit if one is received.  Use -1\n"
2083 " for the timeout value if you desire the call to block indefinitely.\n";
2084
2085 static char usage_sendtext[] =
2086 " Usage: SEND TEXT \"<text to send>\"\n"
2087 "       Sends the given text on a channel. Most channels do not support the\n"
2088 " transmission of text.  Returns 0 if text is sent, or if the channel does not\n"
2089 " support text transmission.  Returns -1 only on error/hangup.  Text\n"
2090 " consisting of greater than one word should be placed in quotes since the\n"
2091 " command only accepts a single argument.\n";
2092
2093 static char usage_recvchar[] =
2094 " Usage: RECEIVE CHAR <timeout>\n"
2095 "       Receives a character of text on a channel. Specify timeout to be the\n"
2096 " maximum time to wait for input in milliseconds, or 0 for infinite. Most channels\n"
2097 " do not support the reception of text. Returns the decimal value of the character\n"
2098 " if one is received, or 0 if the channel does not support text reception.  Returns\n"
2099 " -1 only on error/hangup.\n";
2100
2101 static char usage_recvtext[] =
2102 " Usage: RECEIVE TEXT <timeout>\n"
2103 "       Receives a string of text on a channel. Specify timeout to be the\n"
2104 " maximum time to wait for input in milliseconds, or 0 for infinite. Most channels\n"
2105 " do not support the reception of text. Returns -1 for failure or 1 for success, and the string in parentheses.\n";
2106
2107 static char usage_tddmode[] =
2108 " Usage: TDD MODE <on|off>\n"
2109 "       Enable/Disable TDD transmission/reception on a channel. Returns 1 if\n"
2110 " successful, or 0 if channel is not TDD-capable.\n";
2111
2112 static char usage_sendimage[] =
2113 " Usage: SEND IMAGE <image>\n"
2114 "       Sends the given image on a channel. Most channels do not support the\n"
2115 " transmission of images. Returns 0 if image is sent, or if the channel does not\n"
2116 " support image transmission.  Returns -1 only on error/hangup. Image names\n"
2117 " should not include extensions.\n";
2118
2119 static char usage_streamfile[] =
2120 " Usage: STREAM FILE <filename> <escape digits> [sample offset]\n"
2121 "       Send the given file, allowing playback to be interrupted by the given\n"
2122 " digits, if any. Use double quotes for the digits if you wish none to be\n"
2123 " permitted. If sample offset is provided then the audio will seek to sample\n"
2124 " offset before play starts.  Returns 0 if playback completes without a digit\n"
2125 " being pressed, or the ASCII numerical value of the digit if one was pressed,\n"
2126 " or -1 on error or if the channel was disconnected. Remember, the file\n"
2127 " extension must not be included in the filename.\n";
2128
2129 static char usage_controlstreamfile[] =
2130 " Usage: CONTROL STREAM FILE <filename> <escape digits> [skipms] [ffchar] [rewchr] [pausechr]\n"
2131 "       Send the given file, allowing playback to be controled by the given\n"
2132 " digits, if any. Use double quotes for the digits if you wish none to be\n"
2133 " permitted.  Returns 0 if playback completes without a digit\n"
2134 " being pressed, or the ASCII numerical value of the digit if one was pressed,\n"
2135 " or -1 on error or if the channel was disconnected. Remember, the file\n"
2136 " extension must not be included in the filename.\n\n"
2137 " Note: ffchar and rewchar default to * and # respectively.\n";
2138
2139 static char usage_getoption[] = 
2140 " Usage: GET OPTION <filename> <escape_digits> [timeout]\n"
2141 "       Behaves similar to STREAM FILE but used with a timeout option.\n";
2142
2143 static char usage_saynumber[] =
2144 " Usage: SAY NUMBER <number> <escape digits> [gender]\n"
2145 "       Say a given number, returning early if any of the given DTMF digits\n"
2146 " are received on the channel.  Returns 0 if playback completes without a digit\n"
2147 " being pressed, or the ASCII numerical value of the digit if one was pressed or\n"
2148 " -1 on error/hangup.\n";
2149
2150 static char usage_saydigits[] =
2151 " Usage: SAY DIGITS <number> <escape digits>\n"
2152 "       Say a given digit string, returning early if any of the given DTMF digits\n"
2153 " are received on the channel. Returns 0 if playback completes without a digit\n"
2154 " being pressed, or the ASCII numerical value of the digit if one was pressed or\n"
2155 " -1 on error/hangup.\n";
2156
2157 static char usage_sayalpha[] =
2158 " Usage: SAY ALPHA <number> <escape digits>\n"
2159 "       Say a given character string, returning early if any of the given DTMF digits\n"
2160 " are received on the channel. Returns 0 if playback completes without a digit\n"
2161 " being pressed, or the ASCII numerical value of the digit if one was pressed or\n"
2162 " -1 on error/hangup.\n";
2163
2164 static char usage_saydate[] =
2165 " Usage: SAY DATE <date> <escape digits>\n"
2166 "       Say a given date, returning early if any of the given DTMF digits are\n"
2167 " received on the channel.  <date> is number of seconds elapsed since 00:00:00\n"
2168 " on January 1, 1970, Coordinated Universal Time (UTC). Returns 0 if playback\n"
2169 " completes without a digit being pressed, or the ASCII numerical value of the\n"
2170 " digit if one was pressed or -1 on error/hangup.\n";
2171
2172 static char usage_saytime[] =
2173 " Usage: SAY TIME <time> <escape digits>\n"
2174 "       Say a given time, returning early if any of the given DTMF digits are\n"
2175 " received on the channel.  <time> is number of seconds elapsed since 00:00:00\n"
2176 " on January 1, 1970, Coordinated Universal Time (UTC). Returns 0 if playback\n"
2177 " completes without a digit being pressed, or the ASCII numerical value of the\n"
2178 " digit if one was pressed or -1 on error/hangup.\n";
2179
2180 static char usage_saydatetime[] =
2181 " Usage: SAY DATETIME <time> <escape digits> [format] [timezone]\n"
2182 "       Say a given time, returning early if any of the given DTMF digits are\n"
2183 " received on the channel.  <time> is number of seconds elapsed since 00:00:00\n"
2184 " on January 1, 1970, Coordinated Universal Time (UTC). [format] is the format\n"
2185 " the time should be said in.  See voicemail.conf (defaults to \"ABdY\n"
2186 " 'digits/at' IMp\").  Acceptable values for [timezone] can be found in\n"
2187 " /usr/share/zoneinfo.  Defaults to machine default. Returns 0 if playback\n"
2188 " completes without a digit being pressed, or the ASCII numerical value of the\n"
2189 " digit if one was pressed or -1 on error/hangup.\n";
2190
2191 static char usage_sayphonetic[] =
2192 " Usage: SAY PHONETIC <string> <escape digits>\n"
2193 "       Say a given character string with phonetics, returning early if any of the\n"
2194 " given DTMF digits are received on the channel. Returns 0 if playback\n"
2195 " completes without a digit pressed, the ASCII numerical value of the digit\n"
2196 " if one was pressed, or -1 on error/hangup.\n";
2197
2198 static char usage_getdata[] =
2199 " Usage: GET DATA <file to be streamed> [timeout] [max digits]\n"
2200 "       Stream the given file, and recieve DTMF data. Returns the digits received\n"
2201 "from the channel at the other end.\n";
2202
2203 static char usage_setcontext[] =
2204 " Usage: SET CONTEXT <desired context>\n"
2205 "       Sets the context for continuation upon exiting the application.\n";
2206
2207 static char usage_setextension[] =
2208 " Usage: SET EXTENSION <new extension>\n"
2209 "       Changes the extension for continuation upon exiting the application.\n";
2210
2211 static char usage_setpriority[] =
2212 " Usage: SET PRIORITY <priority>\n"
2213 "       Changes the priority for continuation upon exiting the application.\n"
2214 " The priority must be a valid priority or label.\n";
2215
2216 static char usage_recordfile[] =
2217 " Usage: RECORD FILE <filename> <format> <escape digits> <timeout> \\\n"
2218 "                                          [offset samples] [BEEP] [s=silence]\n"
2219 "       Record to a file until a given dtmf digit in the sequence is received\n"
2220 " Returns -1 on hangup or error.  The format will specify what kind of file\n"
2221 " will be recorded.  The timeout is the maximum record time in milliseconds, or\n"
2222 " -1 for no timeout. \"Offset samples\" is optional, and, if provided, will seek\n"
2223 " to the offset without exceeding the end of the file.  \"silence\" is the number\n"
2224 " of seconds of silence allowed before the function returns despite the\n"
2225 " lack of dtmf digits or reaching timeout.  Silence value must be\n"
2226 " preceeded by \"s=\" and is also optional.\n";
2227
2228 static char usage_autohangup[] =
2229 " Usage: SET AUTOHANGUP <time>\n"
2230 "       Cause the channel to automatically hangup at <time> seconds in the\n"
2231 " future.  Of course it can be hungup before then as well. Setting to 0 will\n"
2232 " cause the autohangup feature to be disabled on this channel.\n";
2233
2234 static char usage_break_aagi[] =
2235 " Usage: ASYNCAGI BREAK\n"
2236 "       Break the Async AGI loop.\n";
2237
2238 static char usage_noop[] =
2239 " Usage: NoOp\n"
2240 "       Does nothing.\n";
2241
2242 static char usage_speechcreate[] =
2243 " Usage: SPEECH CREATE <engine>\n"
2244 "       Create a speech object to be used by the other Speech AGI commands.\n";
2245
2246 static char usage_speechset[] =
2247 " Usage: SPEECH SET <name> <value>\n"
2248 "       Set an engine-specific setting.\n";
2249
2250 static char usage_speechdestroy[] =
2251 " Usage: SPEECH DESTROY\n"
2252 "       Destroy the speech object created by SPEECH CREATE.\n";
2253
2254 static char usage_speechloadgrammar[] =
2255 " Usage: SPEECH LOAD GRAMMAR <grammar name> <path to grammar>\n"
2256 "       Loads the specified grammar as the specified name.\n";
2257
2258 static char usage_speechunloadgrammar[] =
2259 " Usage: SPEECH UNLOAD GRAMMAR <grammar name>\n"
2260 "       Unloads the specified grammar.\n";
2261
2262 static char usage_speechactivategrammar[] =
2263 " Usage: SPEECH ACTIVATE GRAMMAR <grammar name>\n"
2264 "       Activates the specified grammar on the speech object.\n";
2265
2266 static char usage_speechdeactivategrammar[] =
2267 " Usage: SPEECH DEACTIVATE GRAMMAR <grammar name>\n"
2268 "       Deactivates the specified grammar on the speech object.\n";
2269
2270 static char usage_speechrecognize[] =
2271 " Usage: SPEECH RECOGNIZE <prompt> <timeout> [<offset>]\n"
2272 "       Plays back given prompt while listening for speech and dtmf.\n";
2273
2274 /*!
2275  * \brief AGI commands list
2276  */
2277 static struct agi_command commands[] = {
2278         { { "answer", NULL }, handle_answer, "Answer channel", usage_answer , 0 },
2279         { { "channel", "status", NULL }, handle_channelstatus, "Returns status of the connected channel", usage_channelstatus , 0 },
2280         { { "database", "del", NULL }, handle_dbdel, "Removes database key/value", usage_dbdel , 1 },
2281         { { "database", "deltree", NULL }, handle_dbdeltree, "Removes database keytree/value", usage_dbdeltree , 1 },
2282         { { "database", "get", NULL }, handle_dbget, "Gets database value", usage_dbget , 1 },
2283         { { "database", "put", NULL }, handle_dbput, "Adds/updates database value", usage_dbput , 1 },
2284         { { "exec", NULL }, handle_exec, "Executes a given Application", usage_exec , 1 },
2285         { { "get", "data", NULL }, handle_getdata, "Prompts for DTMF on a channel", usage_getdata , 0 },
2286         { { "get", "full", "variable", NULL }, handle_getvariablefull, "Evaluates a channel expression", usage_getvariablefull , 1 },
2287         { { "get", "option", NULL }, handle_getoption, "Stream file, prompt for DTMF, with timeout", usage_getoption , 0 },
2288         { { "get", "variable", NULL }, handle_getvariable, "Gets a channel variable", usage_getvariable , 1 },
2289         { { "hangup", NULL }, handle_hangup, "Hangup the current channel", usage_hangup , 0 },
2290         { { "noop", NULL }, handle_noop, "Does nothing", usage_noop , 1 },
2291         { { "receive", "char", NULL }, handle_recvchar, "Receives one character from channels supporting it", usage_recvchar , 0 },
2292         { { "receive", "text", NULL }, handle_recvtext, "Receives text from channels supporting it", usage_recvtext , 0 },
2293         { { "record", "file", NULL }, handle_recordfile, "Records to a given file", usage_recordfile , 0 },
2294         { { "say", "alpha", NULL }, handle_sayalpha, "Says a given character string", usage_sayalpha , 0 },
2295         { { "say", "digits", NULL }, handle_saydigits, "Says a given digit string", usage_saydigits , 0 },
2296         { { "say", "number", NULL }, handle_saynumber, "Says a given number", usage_saynumber , 0 },
2297         { { "say", "phonetic", NULL }, handle_sayphonetic, "Says a given character string with phonetics", usage_sayphonetic , 0 },
2298         { { "say", "date", NULL }, handle_saydate, "Says a given date", usage_saydate , 0 },
2299         { { "say", "time", NULL }, handle_saytime, "Says a given time", usage_saytime , 0 },
2300         { { "say", "datetime", NULL }, handle_saydatetime, "Says a given time as specfied by the format given", usage_saydatetime , 0 },
2301         { { "send", "image", NULL }, handle_sendimage, "Sends images to channels supporting it", usage_sendimage , 0 },
2302         { { "send", "text", NULL }, handle_sendtext, "Sends text to channels supporting it", usage_sendtext , 0 },
2303         { { "set", "autohangup", NULL }, handle_autohangup, "Autohangup channel in some time", usage_autohangup , 0 },
2304         { { "set", "callerid", NULL }, handle_setcallerid, "Sets callerid for the current channel", usage_setcallerid , 0 },
2305         { { "set", "context", NULL }, handle_setcontext, "Sets channel context", usage_setcontext , 0 },
2306         { { "set", "extension", NULL }, handle_setextension, "Changes channel extension", usage_setextension , 0 },
2307         { { "set", "music", NULL }, handle_setmusic, "Enable/Disable Music on hold generator", usage_setmusic , 0 },
2308         { { "set", "priority", NULL }, handle_setpriority, "Set channel dialplan priority", usage_setpriority , 0 },
2309         { { "set", "variable", NULL }, handle_setvariable, "Sets a channel variable", usage_setvariable , 1 },
2310         { { "stream", "file", NULL }, handle_streamfile, "Sends audio file on channel", usage_streamfile , 0 },
2311         { { "control", "stream", "file", NULL }, handle_controlstreamfile, "Sends audio file on channel and allows the listner to control the stream", usage_controlstreamfile , 0 },
2312         { { "tdd", "mode", NULL }, handle_tddmode, "Toggles TDD mode (for the deaf)", usage_tddmode , 0 },
2313         { { "verbose", NULL }, handle_verbose, "Logs a message to the asterisk verbose log", usage_verbose , 1 },
2314         { { "wait", "for", "digit", NULL }, handle_waitfordigit, "Waits for a digit to be pressed", usage_waitfordigit , 0 },
2315         { { "speech", "create", NULL }, handle_speechcreate, "Creates a speech object", usage_speechcreate, 0 },
2316         { { "speech", "set", NULL }, handle_speechset, "Sets a speech engine setting", usage_speechset, 0 },
2317         { { "speech", "destroy", NULL }, handle_speechdestroy, "Destroys a speech object", usage_speechdestroy, 1 },
2318         { { "speech", "load", "grammar", NULL }, handle_speechloadgrammar, "Loads a grammar", usage_speechloadgrammar, 0 },
2319         { { "speech", "unload", "grammar", NULL }, handle_speechunloadgrammar, "Unloads a grammar", usage_speechunloadgrammar, 1 },
2320         { { "speech", "activate", "grammar", NULL }, handle_speechactivategrammar, "Activates a grammar", usage_speechactivategrammar, 0 },
2321         { { "speech", "deactivate", "grammar", NULL }, handle_speechdeactivategrammar, "Deactivates a grammar", usage_speechdeactivategrammar, 0 },
2322         { { "speech", "recognize", NULL }, handle_speechrecognize, "Recognizes speech", usage_speechrecognize, 0 },
2323         { { "asyncagi", "break", NULL }, handle_asyncagi_break, "Break AsyncAGI loop", usage_break_aagi, 0 },
2324 };
2325
2326 static AST_RWLIST_HEAD_STATIC(agi_commands, agi_command);
2327
2328 static char *help_workhorse(int fd, char *match[])
2329 {
2330         char fullcmd[80], matchstr[80];
2331         struct agi_command *e;
2332
2333         if (match)
2334                 ast_join(matchstr, sizeof(matchstr), match);
2335
2336         ast_cli(fd, "%5.5s %30.30s   %s\n","Dead","Command","Description");
2337         AST_RWLIST_RDLOCK(&agi_commands);
2338         AST_RWLIST_TRAVERSE(&agi_commands, e, list) {
2339                 if (!e->cmda[0])
2340                         break;
2341                 /* Hide commands that start with '_' */
2342                 if ((e->cmda[0])[0] == '_')
2343                         continue;
2344                 ast_join(fullcmd, sizeof(fullcmd), e->cmda);
2345                 if (match && strncasecmp(matchstr, fullcmd, strlen(matchstr)))
2346                         continue;
2347                 ast_cli(fd, "%5.5s %30.30s   %s\n", e->dead ? "Yes" : "No" , fullcmd, e->summary);
2348         }
2349         AST_RWLIST_UNLOCK(&agi_commands);
2350
2351         return CLI_SUCCESS;
2352 }
2353
2354 int ast_agi_register(struct ast_module *mod, agi_command *cmd)
2355 {
2356         char fullcmd[80];
2357
2358         ast_join(fullcmd, sizeof(fullcmd), cmd->cmda);
2359
2360         if (!find_command(cmd->cmda,1)) {
2361                 cmd->mod = mod;
2362                 AST_RWLIST_WRLOCK(&agi_commands);
2363                 AST_LIST_INSERT_TAIL(&agi_commands, cmd, list);
2364                 AST_RWLIST_UNLOCK(&agi_commands);
2365                 if (mod != ast_module_info->self)
2366                         ast_module_ref(ast_module_info->self);
2367                 ast_verb(2, "AGI Command '%s' registered\n",fullcmd);
2368                 return 1;
2369         } else {
2370                 ast_log(LOG_WARNING, "Command already registered!\n");
2371                 return 0;
2372         }
2373 }
2374
2375 int ast_agi_unregister(struct ast_module *mod, agi_command *cmd)
2376 {
2377         struct agi_command *e;
2378         int unregistered = 0;
2379         char fullcmd[80];
2380         
2381         ast_join(fullcmd, sizeof(fullcmd), cmd->cmda);
2382
2383         AST_RWLIST_WRLOCK(&agi_commands);
2384         AST_RWLIST_TRAVERSE_SAFE_BEGIN(&agi_commands, e, list) {
2385                 if (cmd == e) {
2386                         AST_RWLIST_REMOVE_CURRENT(list);
2387                         if (mod != ast_module_info->self)
2388                                 ast_module_unref(ast_module_info->self);
2389                         unregistered=1;
2390                         break;
2391                 }
2392         }
2393         AST_RWLIST_TRAVERSE_SAFE_END;
2394         AST_RWLIST_UNLOCK(&agi_commands);
2395         if (unregistered)
2396                 ast_verb(2, "AGI Command '%s' unregistered\n",fullcmd);
2397         else
2398                 ast_log(LOG_WARNING, "Unable to unregister command: '%s'!\n",fullcmd);
2399         return unregistered;
2400 }
2401
2402 void ast_agi_register_multiple(struct ast_module *mod, agi_command *cmd, int len)
2403 {
2404         int i;
2405
2406         for (i = 0; i < len; i++)
2407                 ast_agi_register(mod, cmd + i);
2408
2409 }
2410
2411 void ast_agi_unregister_multiple(struct ast_module *mod, agi_command *cmd, int len)
2412 {
2413         int i;
2414
2415         for (i = 0; i < len; i++)
2416                 ast_agi_unregister(mod, cmd + i);
2417 }
2418
2419 static agi_command *find_command(char *cmds[], int exact)
2420 {
2421         int y, match;
2422         struct agi_command *e;
2423
2424         AST_RWLIST_RDLOCK(&agi_commands);
2425         AST_RWLIST_TRAVERSE(&agi_commands, e, list) {
2426                 if (!e->cmda[0])
2427                         break;
2428                 /* start optimistic */
2429                 match = 1;
2430                 for (y = 0; match && cmds[y]; y++) {
2431                         /* If there are no more words in the command (and we're looking for
2432                            an exact match) or there is a difference between the two words,
2433                            then this is not a match */
2434                         if (!e->cmda[y] && !exact)
2435                                 break;
2436                         /* don't segfault if the next part of a command doesn't exist */
2437                         if (!e->cmda[y])
2438                                 return NULL;
2439                         if (strcasecmp(e->cmda[y], cmds[y]))
2440                                 match = 0;
2441                 }
2442                 /* If more words are needed to complete the command then this is not
2443                    a candidate (unless we're looking for a really inexact answer  */
2444                 if ((exact > -1) && e->cmda[y])
2445                         match = 0;
2446                 if (match)
2447                         return e;
2448         }
2449         AST_RWLIST_UNLOCK(&agi_commands);
2450         return NULL;
2451 }
2452
2453 static int parse_args(char *s, int *max, char *argv[])
2454 {
2455         int x = 0, quoted = 0, escaped = 0, whitespace = 1;
2456         char *cur;
2457
2458         cur = s;
2459         while(*s) {
2460                 switch(*s) {
2461                 case '"':
2462                         /* If it's escaped, put a literal quote */
2463                         if (escaped) 
2464                                 goto normal;
2465                         else 
2466                                 quoted = !quoted;
2467                         if (quoted && whitespace) {
2468                                 /* If we're starting a quote, coming off white space start a new word, too */
2469                                 argv[x++] = cur;
2470                                 whitespace=0;
2471                         }
2472                         escaped = 0;
2473                 break;
2474                 case ' ':
2475                 case '\t':
2476                         if (!quoted && !escaped) {
2477                                 /* If we're not quoted, mark this as whitespace, and
2478                                    end the previous argument */
2479                                 whitespace = 1;
2480                                 *(cur++) = '\0';
2481                         } else
2482                                 /* Otherwise, just treat it as anything else */ 
2483                                 goto normal;
2484                         break;
2485                 case '\\':
2486                         /* If we're escaped, print a literal, otherwise enable escaping */
2487                         if (escaped) {
2488                                 goto normal;
2489                         } else {
2490                                 escaped=1;
2491                         }
2492                         break;
2493                 default:
2494 normal:
2495                         if (whitespace) {
2496                                 if (x >= MAX_ARGS -1) {
2497                                         ast_log(LOG_WARNING, "Too many arguments, truncating\n");
2498                                         break;
2499                                 }
2500                                 /* Coming off of whitespace, start the next argument */
2501                                 argv[x++] = cur;
2502                                 whitespace=0;
2503                         }
2504                         *(cur++) = *s;
2505                         escaped=0;
2506                 }
2507                 s++;
2508         }
2509         /* Null terminate */
2510         *(cur++) = '\0';
2511         argv[x] = NULL;
2512         *max = x;
2513         return 0;
2514 }
2515
2516 static int agi_handle_command(struct ast_channel *chan, AGI *agi, char *buf, int dead)
2517 {
2518         char *argv[MAX_ARGS];
2519         int argc = MAX_ARGS, res;
2520         agi_command *c;
2521         const char *ami_res = "Unknown Result";
2522         char *ami_cmd = ast_strdupa(buf);
2523         int command_id = ast_random(), resultcode = 200;
2524
2525         manager_event(EVENT_FLAG_CALL, "AGIExec", 
2526                         "SubEvent: Start\r\n"
2527                         "Channel: %s\r\n"
2528                         "CommandId: %d\r\n"
2529                         "Command: %s\r\n", chan->name, command_id, ami_cmd);
2530         parse_args(buf, &argc, argv);
2531         if ((c = find_command(argv, 0)) && (!dead || (dead && c->dead))) {
2532                 /* if this command wasnt registered by res_agi, be sure to usecount
2533                 the module we are using */
2534                 if (c->mod != ast_module_info->self)
2535                         ast_module_ref(c->mod);
2536                 res = c->handler(chan, agi, argc, argv);
2537                 if (c->mod != ast_module_info->self)
2538                         ast_module_unref(c->mod);
2539                 switch (res) {
2540                 case RESULT_SHOWUSAGE: ami_res = "Usage"; resultcode = 520; break;
2541                 case AST_PBX_KEEPALIVE: ami_res = "KeepAlive"; resultcode = 210; break;
2542                 case RESULT_FAILURE: ami_res = "Failure"; resultcode = -1; break;
2543                 case RESULT_SUCCESS: ami_res = "Success"; resultcode = 200; break;
2544                 }
2545                 manager_event(EVENT_FLAG_CALL, "AGIExec",
2546                                 "SubEvent: End\r\n"
2547                                 "Channel: %s\r\n"
2548                                 "CommandId: %d\r\n"
2549                                 "Command: %s\r\n"
2550                                 "ResultCode: %d\r\n"
2551                                 "Result: %s\r\n", chan->name, command_id, ami_cmd, resultcode, ami_res);
2552                 switch(res) {
2553                 case RESULT_SHOWUSAGE:
2554                         ast_agi_fdprintf(chan, agi->fd, "520-Invalid command syntax.  Proper usage follows:\n");
2555                         ast_agi_fdprintf(chan, agi->fd, c->usage);
2556                         ast_agi_fdprintf(chan, agi->fd, "520 End of proper usage.\n");
2557                         break;
2558                 case AST_PBX_KEEPALIVE:
2559                         /* We've been asked to keep alive, so do so */
2560                         return AST_PBX_KEEPALIVE;
2561                         break;
2562                 case RESULT_FAILURE:
2563                         /* They've already given the failure.  We've been hung up on so handle this
2564                            appropriately */
2565                         return -1;
2566                 }
2567         } else if ((c = find_command(argv, 0))) {
2568                 ast_agi_fdprintf(chan, agi->fd, "511 Command Not Permitted on a dead channel\n");
2569                 manager_event(EVENT_FLAG_CALL, "AGIExec",
2570                                 "SubEvent: End\r\n"
2571                                 "Channel: %s\r\n"
2572                                 "CommandId: %d\r\n"
2573                                 "Command: %s\r\n"
2574                                 "ResultCode: 511\r\n"
2575                                 "Result: Command not permitted on a dead channel\r\n", chan->name, command_id, ami_cmd);
2576         } else {
2577                 ast_agi_fdprintf(chan, agi->fd, "510 Invalid or unknown command\n");
2578                 manager_event(EVENT_FLAG_CALL, "AGIExec",
2579                                 "SubEvent: End\r\n"
2580                                 "Channel: %s\r\n"
2581                                 "CommandId: %d\r\n"
2582                                 "Command: %s\r\n"
2583                                 "ResultCode: 510\r\n"
2584                                 "Result: Invalid or unknown command\r\n", chan->name, command_id, ami_cmd);
2585         }
2586         return 0;
2587 }
2588 static enum agi_result run_agi(struct ast_channel *chan, char *request, AGI *agi, int pid, int *status, int dead, int argc, char *argv[])
2589 {
2590         struct ast_channel *c;
2591         int outfd, ms, needhup = 0;
2592         enum agi_result returnstatus = AGI_RESULT_SUCCESS;
2593         struct ast_frame *f;
2594         char buf[AGI_BUF_LEN];
2595         char *res = NULL;
2596         FILE *readf;
2597         /* how many times we'll retry if ast_waitfor_nandfs will return without either 
2598           channel or file descriptor in case select is interrupted by a system call (EINTR) */
2599         int retry = AGI_NANDFS_RETRY;
2600
2601         if (!(readf = fdopen(agi->ctrl, "r"))) {
2602                 ast_log(LOG_WARNING, "Unable to fdopen file descriptor\n");
2603                 if (pid > -1)
2604                         kill(pid, SIGHUP);
2605                 close(agi->ctrl);
2606                 return AGI_RESULT_FAILURE;
2607         }
2608         setlinebuf(readf);
2609         setup_env(chan, request, agi->fd, (agi->audio > -1), argc, argv);
2610         for (;;) {
2611                 if (needhup) {
2612                         needhup = 0;
2613                         dead = 1;
2614                         if (pid > -1)
2615                                 kill(pid, SIGHUP);
2616                 }
2617                 ms = -1;
2618                 c = ast_waitfor_nandfds(&chan, dead ? 0 : 1, &agi->ctrl, 1, NULL, &outfd, &ms);
2619                 if (c) {
2620                         retry = AGI_NANDFS_RETRY;
2621                         /* Idle the channel until we get a command */
2622                         f = ast_read(c);
2623                         if (!f) {
2624                                 ast_debug(1, "%s hungup\n", chan->name);
2625                                 returnstatus = AGI_RESULT_HANGUP;
2626                                 needhup = 1;
2627                                 continue;
2628                         } else {
2629                                 /* If it's voice, write it to the audio pipe */
2630                                 if ((agi->audio > -1) && (f->frametype == AST_FRAME_VOICE)) {
2631                                         /* Write, ignoring errors */
2632                                         write(agi->audio, f->data, f->datalen);
2633                                 }
2634                                 ast_frfree(f);
2635                         }
2636                 } else if (outfd > -1) {
2637                         size_t len = sizeof(buf);
2638                         size_t buflen = 0;
2639
2640                         retry = AGI_NANDFS_RETRY;
2641                         buf[0] = '\0';
2642
2643                         while (buflen < (len - 1)) {
2644                                 res = fgets(buf + buflen, len, readf);
2645                                 if (feof(readf)) 
2646                                         break;
2647                                 if (ferror(readf) && ((errno != EINTR) && (errno != EAGAIN))) 
2648                                         break;
2649                                 if (res != NULL && !agi->fast)
2650                                         break;
2651                                 buflen = strlen(buf);
2652                                 if (buflen && buf[buflen - 1] == '\n')
2653                                         break;
2654                                 len -= buflen;
2655                                 if (agidebug)
2656                                         ast_verbose( "AGI Rx << temp buffer %s - errno %s\n", buf, strerror(errno));
2657                         }
2658
2659                         if (!buf[0]) {
2660                                 /* Program terminated */
2661                                 if (returnstatus && returnstatus != AST_PBX_KEEPALIVE)
2662                                         returnstatus = -1;
2663                                 ast_verb(3, "<%s>AGI Script %s completed, returning %d\n", chan->name, request, returnstatus);
2664                                 if (pid > 0)
2665                                         waitpid(pid, status, 0);
2666                                 /* No need to kill the pid anymore, since they closed us */
2667                                 pid = -1;
2668                                 break;
2669                         }
2670
2671                         /* get rid of trailing newline, if any */
2672                         if (*buf && buf[strlen(buf) - 1] == '\n')
2673                                 buf[strlen(buf) - 1] = 0;
2674                         if (agidebug)
2675                                 ast_verbose("<%s>AGI Rx << %s\n", chan->name, buf);
2676                         returnstatus |= agi_handle_command(chan, agi, buf, dead);
2677                         /* If the handle_command returns -1, we need to stop */
2678                         if ((returnstatus < 0) || (returnstatus == AST_PBX_KEEPALIVE)) {
2679                                 needhup = 1;
2680                                 continue;
2681                         }
2682                 } else {
2683                         if (--retry <= 0) {
2684                                 ast_log(LOG_WARNING, "No channel, no fd?\n");
2685                                 returnstatus = AGI_RESULT_FAILURE;
2686                                 break;
2687                         }
2688                 }
2689         }
2690         /* Notify process */
2691         if (pid > -1) {
2692                 const char *sighup = pbx_builtin_getvar_helper(chan, "AGISIGHUP");
2693                 if (ast_strlen_zero(sighup) || !ast_false(sighup)) {
2694                         if (kill(pid, SIGHUP))
2695                                 ast_log(LOG_WARNING, "unable to send SIGHUP to AGI process %d: %s\n", pid, strerror(errno));
2696                 }
2697         }
2698         fclose(readf);
2699         return returnstatus;
2700 }
2701
2702 static char *handle_cli_agi_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2703 {
2704         struct agi_command *command;
2705         char fullcmd[80];
2706
2707         switch (cmd) {
2708         case CLI_INIT:
2709                 e->command = "agi show";
2710                 e->usage =
2711                         "Usage: agi show [topic]\n"
2712                         "       When called with a topic as an argument, displays usage\n"
2713                         "       information on the given command.  If called without a\n"
2714                         "       topic, it provides a list of AGI commands.\n";
2715                 break;
2716         case CLI_GENERATE:
2717                 return NULL;
2718         }
2719         if (a->argc < e->args)
2720                 return CLI_SHOWUSAGE;
2721         if (a->argc > e->args) {
2722                 command = find_command(a->argv + e->args, 1);
2723                 if (command) {
2724                         ast_cli(a->fd, command->usage);
2725                         ast_cli(a->fd, " Runs Dead : %s\n", command->dead ? "Yes" : "No");
2726                 } else {
2727                         if (find_command(a->argv + e->args, -1)) {
2728                                 return help_workhorse(a->fd, a->argv + e->args);
2729                         } else {
2730                                 ast_join(fullcmd, sizeof(fullcmd), a->argv + e->args);
2731                                 ast_cli(a->fd, "No such command '%s'.\n", fullcmd);
2732                         }
2733                 }
2734         } else {
2735                 return help_workhorse(a->fd, NULL);
2736         }
2737         return CLI_SUCCESS;
2738 }
2739
2740 /*! \brief Convert string to use HTML escaped characters
2741         \note Maybe this should be a generic function?
2742 */
2743 static void write_html_escaped(FILE *htmlfile, char *str)
2744 {
2745         char *cur = str;
2746
2747         while(*cur) {
2748                 switch (*cur) {
2749                 case '<':
2750                         fprintf(htmlfile, "%s", "&lt;");
2751                         break;
2752                 case '>':
2753                         fprintf(htmlfile, "%s", "&gt;");
2754                         break;
2755                 case '&':
2756                         fprintf(htmlfile, "%s", "&amp;");
2757                         break;
2758                 case '"':
2759                         fprintf(htmlfile, "%s", "&quot;");
2760                         break;
2761                 default:
2762                         fprintf(htmlfile, "%c", *cur);
2763                         break;
2764                 }
2765                 cur++;
2766         }
2767
2768         return;
2769 }
2770
2771 static int write_htmldump(char *filename)
2772 {
2773         struct agi_command *command;
2774         char fullcmd[80];
2775         FILE *htmlfile;
2776
2777         if (!(htmlfile = fopen(filename, "wt")))
2778                 return -1;
2779
2780         fprintf(htmlfile, "<HTML>\n<HEAD>\n<TITLE>AGI Commands</TITLE>\n</HEAD>\n");
2781         fprintf(htmlfile, "<BODY>\n<CENTER><B><H1>AGI Commands</H1></B></CENTER>\n\n");
2782         fprintf(htmlfile, "<TABLE BORDER=\"0\" CELLSPACING=\"10\">\n");
2783
2784         AST_RWLIST_RDLOCK(&agi_commands);
2785         AST_RWLIST_TRAVERSE(&agi_commands, command, list) {
2786                 char *stringp, *tempstr;
2787  
2788                 if (!command->cmda[0])  /* end ? */
2789                         break;
2790                 /* Hide commands that start with '_' */
2791                 if ((command->cmda[0])[0] == '_')
2792                         continue;
2793                 ast_join(fullcmd, sizeof(fullcmd), command->cmda);
2794
2795                 fprintf(htmlfile, "<TR><TD><TABLE BORDER=\"1\" CELLPADDING=\"5\" WIDTH=\"100%%\">\n");
2796                 fprintf(htmlfile, "<TR><TH ALIGN=\"CENTER\"><B>%s - %s</B></TH></TR>\n", fullcmd, command->summary);
2797
2798                 stringp = command->usage;
2799                 tempstr = strsep(&stringp, "\n");
2800
2801                 fprintf(htmlfile, "<TR><TD ALIGN=\"CENTER\">");
2802                 write_html_escaped(htmlfile, tempstr);
2803                 fprintf(htmlfile, "</TD></TR>\n");
2804                 fprintf(htmlfile, "<TR><TD ALIGN=\"CENTER\">\n");
2805
2806                 while ((tempstr = strsep(&stringp, "\n")) != NULL) {
2807                         write_html_escaped(htmlfile, tempstr);
2808                         fprintf(htmlfile, "<BR>\n");
2809                 }
2810                 fprintf(htmlfile, "</TD></TR>\n");
2811                 fprintf(htmlfile, "</TABLE></TD></TR>\n\n");
2812         }
2813         AST_RWLIST_UNLOCK(&agi_commands);
2814         fprintf(htmlfile, "</TABLE>\n</BODY>\n</HTML>\n");
2815         fclose(htmlfile);
2816         return 0;
2817 }
2818
2819 static char *handle_cli_agi_dumphtml_deprecated(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2820 {
2821         switch (cmd) {
2822         case CLI_INIT:
2823                 e->command = "agi dumphtml";
2824                 e->usage =
2825                         "Usage: agi dumphtml <filename>\n"
2826                         "       Dumps the AGI command list in HTML format to the given\n"
2827                         "       file.\n";
2828                 return NULL;
2829         case CLI_GENERATE:
2830                 return NULL;
2831         }
2832         if (a->argc < e->args + 1)
2833                 return CLI_SHOWUSAGE;
2834
2835         if (write_htmldump(a->argv[2]) < 0) {
2836                 ast_cli(a->fd, "Could not create file '%s'\n", a->argv[2]);
2837                 return CLI_SHOWUSAGE;
2838         }
2839         ast_cli(a->fd, "AGI HTML commands dumped to: %s\n", a->argv[2]);
2840         return CLI_SUCCESS;
2841 }
2842
2843 static char *handle_cli_agi_dump_html(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2844 {
2845         switch (cmd) {
2846         case CLI_INIT:
2847                 e->command = "agi dump html";
2848                 e->usage =
2849                         "Usage: agi dump html <filename>\n"
2850                         "       Dumps the AGI command list in HTML format to the given\n"
2851                         "       file.\n";
2852                 return NULL;
2853         case CLI_GENERATE:
2854                 return NULL;
2855         }
2856         if (a->argc != e->args + 1)
2857                 return CLI_SHOWUSAGE;
2858
2859         if (write_htmldump(a->argv[e->args]) < 0) {
2860                 ast_cli(a->fd, "Could not create file '%s'\n", a->argv[e->args]);
2861                 return CLI_SHOWUSAGE;
2862         }
2863         ast_cli(a->fd, "AGI HTML commands dumped to: %s\n", a->argv[e->args]);
2864         return CLI_SUCCESS;
2865 }
2866
2867 static int agi_exec_full(struct ast_channel *chan, void *data, int enhanced, int dead)
2868 {
2869         enum agi_result res;
2870         char buf[AGI_BUF_LEN] = "", *tmp = buf;
2871         int fds[2], efd = -1, pid;
2872         AST_DECLARE_APP_ARGS(args,
2873                 AST_APP_ARG(arg)[MAX_ARGS];
2874         );
2875         AGI agi;
2876
2877         if (ast_strlen_zero(data)) {
2878                 ast_log(LOG_WARNING, "AGI requires an argument (script)\n");
2879                 return -1;
2880         }
2881         if (dead)
2882                 ast_log(LOG_NOTICE, "Hungup channel detected, running agi in dead mode.\n");
2883         ast_copy_string(buf, data, sizeof(buf));
2884         memset(&agi, 0, sizeof(agi));
2885         AST_STANDARD_APP_ARGS(args, tmp);
2886         args.argv[args.argc] = NULL;
2887 #if 0
2888          /* Answer if need be */
2889         if (chan->_state != AST_STATE_UP) {
2890                 if (ast_answer(chan))
2891                         return -1;
2892         }
2893 #endif
2894         res = launch_script(chan, args.argv[0], args.argv, fds, enhanced ? &efd : NULL, &pid);
2895         /* Async AGI do not require run_agi(), so just proceed if normal AGI
2896            or Fast AGI are setup with success. */
2897         if (res == AGI_RESULT_SUCCESS || res == AGI_RESULT_SUCCESS_FAST) {
2898                 int status = 0;
2899                 agi.fd = fds[1];
2900                 agi.ctrl = fds[0];
2901                 agi.audio = efd;
2902                 agi.fast = (res == AGI_RESULT_SUCCESS_FAST) ? 1 : 0;
2903                 res = run_agi(chan, args.argv[0], &agi, pid, &status, dead, args.argc, args.argv);
2904                 /* If the fork'd process returns non-zero, set AGISTATUS to FAILURE */
2905                 if ((res == AGI_RESULT_SUCCESS || res == AGI_RESULT_SUCCESS_FAST) && status)
2906                         res = AGI_RESULT_FAILURE;
2907                 if (fds[1] != fds[0])
2908                         close(fds[1]);
2909                 if (efd > -1)
2910                         close(efd);
2911                 ast_unreplace_sigchld();
2912         } 
2913
2914         switch (res) {
2915         case AGI_RESULT_SUCCESS:
2916         case AGI_RESULT_SUCCESS_FAST:
2917         case AGI_RESULT_SUCCESS_ASYNC:
2918                 pbx_builtin_setvar_helper(chan, "AGISTATUS", "SUCCESS");
2919                 break;
2920         case AGI_RESULT_FAILURE:
2921                 pbx_builtin_setvar_helper(chan, "AGISTATUS", "FAILURE");
2922                 break;
2923         case AGI_RESULT_NOTFOUND:
2924                 pbx_builtin_setvar_helper(chan, "AGISTATUS", "NOTFOUND");
2925                 break;
2926         case AGI_RESULT_HANGUP:
2927                 pbx_builtin_setvar_helper(chan, "AGISTATUS", "HANGUP");
2928                 return -1;
2929         }
2930
2931         return 0;
2932 }
2933
2934 static int agi_exec(struct ast_channel *chan, void *data)
2935 {
2936         if (!ast_check_hangup(chan))
2937                 return agi_exec_full(chan, data, 0, 0);
2938         else
2939                 return agi_exec_full(chan, data, 0, 1);
2940 }
2941
2942 static int eagi_exec(struct ast_channel *chan, void *data)
2943 {
2944         int readformat, res;
2945
2946         if (ast_check_hangup(chan)) {
2947                 ast_log(LOG_ERROR, "If you want to run AGI on hungup channels you should use DeadAGI!\n");
2948                 return 0;
2949         }
2950         readformat = chan->readformat;
2951         if (ast_set_read_format(chan, AST_FORMAT_SLINEAR)) {
2952                 ast_log(LOG_WARNING, "Unable to set channel '%s' to linear mode\n", chan->name);
2953                 return -1;
2954         }
2955         res = agi_exec_full(chan, data, 1, 0);
2956         if (!res) {
2957                 if (ast_set_read_format(chan, readformat)) {
2958                         ast_log(LOG_WARNING, "Unable to restore channel '%s' to format %s\n", chan->name, ast_getformatname(readformat));
2959                 }
2960         }
2961         return res;
2962 }
2963
2964 static int deadagi_exec(struct ast_channel *chan, void *data)
2965 {
2966         ast_log(LOG_WARNING, "DeadAGI has been deprecated, please use AGI in all cases!\n");
2967         return agi_exec(chan, data);
2968 }
2969
2970 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");
2971
2972 static struct ast_cli_entry cli_agi[] = {
2973         AST_CLI_DEFINE(handle_cli_agi_add_cmd,   "Add AGI command to a channel in Async AGI"),
2974         AST_CLI_DEFINE(handle_cli_agi_debug,     "Enable/Disable AGI debugging"),
2975         AST_CLI_DEFINE(handle_cli_agi_show,      "List AGI commands or specific help"),
2976         AST_CLI_DEFINE(handle_cli_agi_dump_html, "Dumps a list of AGI commands in HTML format", .deprecate_cmd = &cli_agi_dumphtml_deprecated)
2977 };
2978
2979 static int unload_module(void)
2980 {
2981         ast_cli_unregister_multiple(cli_agi, sizeof(cli_agi) / sizeof(struct ast_cli_entry));
2982         ast_agi_unregister_multiple(ast_module_info->self, commands, sizeof(commands) / sizeof(struct agi_command));
2983         ast_unregister_application(eapp);
2984         ast_unregister_application(deadapp);
2985         ast_manager_unregister("AGI");
2986         return ast_unregister_application(app);
2987 }
2988
2989 static int load_module(void)
2990 {
2991         ast_cli_register_multiple(cli_agi, sizeof(cli_agi) / sizeof(struct ast_cli_entry));
2992         ast_agi_register_multiple(ast_module_info->self, commands, sizeof(commands) / sizeof(struct agi_command));
2993         ast_register_application(deadapp, deadagi_exec, deadsynopsis, descrip);
2994         ast_register_application(eapp, eagi_exec, esynopsis, descrip);
2995         ast_manager_register2("AGI", EVENT_FLAG_CALL, action_add_agi_cmd, "Add an AGI command to execute by Async AGI", mandescr_asyncagi);
2996         return ast_register_application(app, agi_exec, synopsis, descrip);
2997 }
2998
2999 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS, "Asterisk Gateway Interface (AGI)",
3000                 .load = load_module,
3001                 .unload = unload_module,
3002                 );