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