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