Convert most of the strings in the call_queue struct to use stringfields.
[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 <sys/types.h>
31 #include <netdb.h>
32 #include <sys/socket.h>
33 #include <netinet/in.h>
34 #include <netinet/tcp.h>
35 #include <arpa/inet.h>
36 #include <math.h>
37 #include <stdlib.h>
38 #include <unistd.h>
39 #include <string.h>
40 #include <stdlib.h>
41 #include <signal.h>
42 #include <sys/time.h>
43 #include <stdio.h>
44 #include <fcntl.h>
45 #include <errno.h>
46 #include <sys/wait.h>
47 #include <sys/stat.h>
48
49 #include "asterisk/file.h"
50 #include "asterisk/logger.h"
51 #include "asterisk/channel.h"
52 #include "asterisk/pbx.h"
53 #include "asterisk/module.h"
54 #include "asterisk/astdb.h"
55 #include "asterisk/callerid.h"
56 #include "asterisk/cli.h"
57 #include "asterisk/logger.h"
58 #include "asterisk/options.h"
59 #include "asterisk/image.h"
60 #include "asterisk/say.h"
61 #include "asterisk/app.h"
62 #include "asterisk/dsp.h"
63 #include "asterisk/musiconhold.h"
64 #include "asterisk/utils.h"
65 #include "asterisk/lock.h"
66 #include "asterisk/strings.h"
67 #include "asterisk/agi.h"
68
69 #define MAX_ARGS 128
70 #define AGI_NANDFS_RETRY 3
71 #define AGI_BUF_LEN 2048
72
73 static char *app = "AGI";
74
75 static char *eapp = "EAGI";
76
77 static char *deadapp = "DeadAGI";
78
79 static char *synopsis = "Executes an AGI compliant application";
80 static char *esynopsis = "Executes an EAGI compliant application";
81 static char *deadsynopsis = "Executes AGI on a hungup channel";
82
83 static char *descrip =
84 "  [E|Dead]AGI(command,args): Executes an Asterisk Gateway Interface compliant\n"
85 "program on a channel. AGI allows Asterisk to launch external programs\n"
86 "written in any language to control a telephony channel, play audio,\n"
87 "read DTMF digits, etc. by communicating with the AGI protocol on stdin\n"
88 "and stdout.\n"
89 "  This channel will stop dialplan execution on hangup inside of this\n"
90 "application, except when using DeadAGI.  Otherwise, dialplan execution\n"
91 "will continue normally.\n"
92 "  A locally executed AGI script will receive SIGHUP on hangup from the channel\n"
93 "except when using DeadAGI. This can be disabled by setting the AGISIGHUP channel\n"
94 "variable to \"no\" before executing the AGI application.\n"
95 "  Using 'EAGI' provides enhanced AGI, with incoming audio available out of band\n"
96 "on file descriptor 3\n\n"
97 "  Use the CLI command 'agi show' to list available agi commands\n"
98 "  This application sets the following channel variable upon completion:\n"
99 "     AGISTATUS      The status of the attempt to the run the AGI script\n"
100 "                    text string, one of SUCCESS | FAILED | NOTFOUND | HANGUP\n";
101
102 static int agidebug = 0;
103
104 #define TONE_BLOCK_SIZE 200
105
106 /* Max time to connect to an AGI remote host */
107 #define MAX_AGI_CONNECT 2000
108
109 #define AGI_PORT 4573
110
111 enum agi_result {
112         AGI_RESULT_SUCCESS,
113         AGI_RESULT_SUCCESS_FAST,
114         AGI_RESULT_FAILURE,
115         AGI_RESULT_NOTFOUND,
116         AGI_RESULT_HANGUP,
117 };
118
119 static agi_command *find_command(char *cmds[], int exact);
120
121 AST_THREADSTORAGE(agi_buf);
122 #define AGI_BUF_INITSIZE 256
123
124 int ast_agi_fdprintf(struct ast_channel *chan, int fd, char *fmt, ...)
125 {
126         int res = 0;
127         va_list ap;
128         struct ast_str *buf;
129
130         if (!(buf = ast_str_thread_get(&agi_buf, AGI_BUF_INITSIZE)))
131                 return -1;
132
133         va_start(ap, fmt);
134         res = ast_str_set_va(&buf, 0, fmt, ap);
135         va_end(ap);
136
137         if (res == -1) {
138                 ast_log(LOG_ERROR, "Out of memory\n");
139                 return -1;
140         }
141
142         if (agidebug) {
143                 if (chan) {
144                         ast_verbose("<%s>AGI Tx >> %s", chan->name, buf->str);
145                 } else {
146                         ast_verbose("AGI Tx >> %s", buf->str);
147                 }
148         }
149
150         return ast_carefulwrite(fd, buf->str, buf->used, 100);
151 }
152
153 /* launch_netscript: The fastagi handler.
154         FastAGI defaults to port 4573 */
155 static enum agi_result launch_netscript(char *agiurl, char *argv[], int *fds, int *efd, int *opid)
156 {
157         int s, flags, res, port = AGI_PORT;
158         struct pollfd pfds[1];
159         char *host, *c, *script = "";
160         struct sockaddr_in sin;
161         struct hostent *hp;
162         struct ast_hostent ahp;
163
164         /* agiusl is "agi://host.domain[:port][/script/name]" */
165         host = ast_strdupa(agiurl + 6); /* Remove agi:// */
166         /* Strip off any script name */
167         if ((c = strchr(host, '/'))) {
168                 *c = '\0';
169                 c++;
170                 script = c;
171         }
172         if ((c = strchr(host, ':'))) {
173                 *c = '\0';
174                 c++;
175                 port = atoi(c);
176         }
177         if (efd) {
178                 ast_log(LOG_WARNING, "AGI URI's don't support Enhanced AGI yet\n");
179                 return -1;
180         }
181         if (!(hp = ast_gethostbyname(host, &ahp))) {
182                 ast_log(LOG_WARNING, "Unable to locate host '%s'\n", host);
183                 return -1;
184         }
185         if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
186                 ast_log(LOG_WARNING, "Unable to create socket: %s\n", strerror(errno));
187                 return -1;
188         }
189         if ((flags = fcntl(s, F_GETFL)) < 0) {
190                 ast_log(LOG_WARNING, "Fcntl(F_GETFL) failed: %s\n", strerror(errno));
191                 close(s);
192                 return -1;
193         }
194         if (fcntl(s, F_SETFL, flags | O_NONBLOCK) < 0) {
195                 ast_log(LOG_WARNING, "Fnctl(F_SETFL) failed: %s\n", strerror(errno));
196                 close(s);
197                 return -1;
198         }
199         memset(&sin, 0, sizeof(sin));
200         sin.sin_family = AF_INET;
201         sin.sin_port = htons(port);
202         memcpy(&sin.sin_addr, hp->h_addr, sizeof(sin.sin_addr));
203         if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) && (errno != EINPROGRESS)) {
204                 ast_log(LOG_WARNING, "Connect failed with unexpected error: %s\n", strerror(errno));
205                 close(s);
206                 return AGI_RESULT_FAILURE;
207         }
208
209         pfds[0].fd = s;
210         pfds[0].events = POLLOUT;
211         while ((res = poll(pfds, 1, MAX_AGI_CONNECT)) != 1) {
212                 if (errno != EINTR) {
213                         if (!res) {
214                                 ast_log(LOG_WARNING, "FastAGI connection to '%s' timed out after MAX_AGI_CONNECT (%d) milliseconds.\n",
215                                         agiurl, MAX_AGI_CONNECT);
216                         } else
217                                 ast_log(LOG_WARNING, "Connect to '%s' failed: %s\n", agiurl, strerror(errno));
218                         close(s);
219                         return AGI_RESULT_FAILURE;
220                 }
221         }
222
223         if (ast_agi_fdprintf(NULL, s, "agi_network: yes\n") < 0) {
224                 if (errno != EINTR) {
225                         ast_log(LOG_WARNING, "Connect to '%s' failed: %s\n", agiurl, strerror(errno));
226                         close(s);
227                         return AGI_RESULT_FAILURE;
228                 }
229         }
230
231         /* If we have a script parameter, relay it to the fastagi server */
232         /* Script parameters take the form of: AGI(agi://my.example.com/?extension=${EXTEN}) */
233         if (!ast_strlen_zero(script))
234                 ast_agi_fdprintf(NULL, s, "agi_network_script: %s\n", script);
235
236         ast_debug(4, "Wow, connected!\n");
237         fds[0] = s;
238         fds[1] = s;
239         *opid = -1;
240         return AGI_RESULT_SUCCESS_FAST;
241 }
242
243 static enum agi_result launch_script(char *script, char *argv[], int *fds, int *efd, int *opid)
244 {
245         char tmp[256];
246         int pid, toast[2], fromast[2], audio[2], x, res;
247         sigset_t signal_set, old_set;
248         struct stat st;
249
250         if (!strncasecmp(script, "agi://", 6))
251                 return launch_netscript(script, argv, fds, efd, opid);
252         
253         if (script[0] != '/') {
254                 snprintf(tmp, sizeof(tmp), "%s/%s", ast_config_AST_AGI_DIR, script);
255                 script = tmp;
256         }
257
258         /* Before even trying let's see if the file actually exists */
259         if (stat(script, &st)) {
260                 ast_log(LOG_WARNING, "Failed to execute '%s': File does not exist.\n", script);
261                 return AGI_RESULT_NOTFOUND;
262         }
263
264         if (pipe(toast)) {
265                 ast_log(LOG_WARNING, "Unable to create toast pipe: %s\n",strerror(errno));
266                 return AGI_RESULT_FAILURE;
267         }
268         if (pipe(fromast)) {
269                 ast_log(LOG_WARNING, "unable to create fromast pipe: %s\n", strerror(errno));
270                 close(toast[0]);
271                 close(toast[1]);
272                 return AGI_RESULT_FAILURE;
273         }
274         if (efd) {
275                 if (pipe(audio)) {
276                         ast_log(LOG_WARNING, "unable to create audio pipe: %s\n", strerror(errno));
277                         close(fromast[0]);
278                         close(fromast[1]);
279                         close(toast[0]);
280                         close(toast[1]);
281                         return AGI_RESULT_FAILURE;
282                 }
283                 res = fcntl(audio[1], F_GETFL);
284                 if (res > -1) 
285                         res = fcntl(audio[1], F_SETFL, res | O_NONBLOCK);
286                 if (res < 0) {
287                         ast_log(LOG_WARNING, "unable to set audio pipe parameters: %s\n", strerror(errno));
288                         close(fromast[0]);
289                         close(fromast[1]);
290                         close(toast[0]);
291                         close(toast[1]);
292                         close(audio[0]);
293                         close(audio[1]);
294                         return AGI_RESULT_FAILURE;
295                 }
296         }
297
298         /* Block SIGHUP during the fork - prevents a race */
299         sigfillset(&signal_set);
300         pthread_sigmask(SIG_BLOCK, &signal_set, &old_set);
301         if ((pid = fork()) < 0) {
302                 ast_log(LOG_WARNING, "Failed to fork(): %s\n", strerror(errno));
303                 pthread_sigmask(SIG_SETMASK, &old_set, NULL);
304                 return AGI_RESULT_FAILURE;
305         }
306         if (!pid) {
307                 /* Pass paths to AGI via environmental variables */
308                 setenv("AST_CONFIG_DIR", ast_config_AST_CONFIG_DIR, 1);
309                 setenv("AST_CONFIG_FILE", ast_config_AST_CONFIG_FILE, 1);
310                 setenv("AST_MODULE_DIR", ast_config_AST_MODULE_DIR, 1);
311                 setenv("AST_SPOOL_DIR", ast_config_AST_SPOOL_DIR, 1);
312                 setenv("AST_MONITOR_DIR", ast_config_AST_MONITOR_DIR, 1);
313                 setenv("AST_VAR_DIR", ast_config_AST_VAR_DIR, 1);
314                 setenv("AST_DATA_DIR", ast_config_AST_DATA_DIR, 1);
315                 setenv("AST_LOG_DIR", ast_config_AST_LOG_DIR, 1);
316                 setenv("AST_AGI_DIR", ast_config_AST_AGI_DIR, 1);
317                 setenv("AST_KEY_DIR", ast_config_AST_KEY_DIR, 1);
318                 setenv("AST_RUN_DIR", ast_config_AST_RUN_DIR, 1);
319
320                 /* Don't run AGI scripts with realtime priority -- it causes audio stutter */
321                 ast_set_priority(0);
322
323                 /* Redirect stdin and out, provide enhanced audio channel if desired */
324                 dup2(fromast[0], STDIN_FILENO);
325                 dup2(toast[1], STDOUT_FILENO);
326                 if (efd)
327                         dup2(audio[0], STDERR_FILENO + 1);
328                 else
329                         close(STDERR_FILENO + 1);
330
331                 /* Before we unblock our signals, return our trapped signals back to the defaults */
332                 signal(SIGHUP, SIG_DFL);
333                 signal(SIGCHLD, SIG_DFL);
334                 signal(SIGINT, SIG_DFL);
335                 signal(SIGURG, SIG_DFL);
336                 signal(SIGTERM, SIG_DFL);
337                 signal(SIGPIPE, SIG_DFL);
338                 signal(SIGXFSZ, SIG_DFL);
339
340                 /* unblock important signal handlers */
341                 if (pthread_sigmask(SIG_UNBLOCK, &signal_set, NULL)) {
342                         ast_log(LOG_WARNING, "unable to unblock signals for AGI script: %s\n", strerror(errno));
343                         _exit(1);
344                 }
345
346                 /* Close everything but stdin/out/error */
347                 for (x = STDERR_FILENO + 2; x < 1024; x++) 
348                         close(x);
349
350                 /* Execute script */
351                 /* XXX argv should be deprecated in favor of passing agi_argX paramaters */
352                 execv(script, argv);
353                 /* Can't use ast_log since FD's are closed */
354                 fprintf(stdout, "verbose \"Failed to execute '%s': %s\" 2\n", script, strerror(errno));
355                 fflush(stdout);
356                 _exit(1);
357         }
358         pthread_sigmask(SIG_SETMASK, &old_set, NULL);
359         ast_verb(3, "Launched AGI Script %s\n", script);
360         fds[0] = toast[0];
361         fds[1] = fromast[1];
362         if (efd)
363                 *efd = audio[1];
364         /* close what we're not using in the parent */
365         close(toast[1]);
366         close(fromast[0]);
367
368         if (efd)
369                 close(audio[0]);
370
371         *opid = pid;
372         return AGI_RESULT_SUCCESS;
373 }
374
375 static void setup_env(struct ast_channel *chan, char *request, int fd, int enhanced, int argc, char *argv[])
376 {
377         int count;
378
379         /* Print initial environment, with agi_request always being the first
380            thing */
381         ast_agi_fdprintf(chan, fd, "agi_request: %s\n", request);
382         ast_agi_fdprintf(chan, fd, "agi_channel: %s\n", chan->name);
383         ast_agi_fdprintf(chan, fd, "agi_language: %s\n", chan->language);
384         ast_agi_fdprintf(chan, fd, "agi_type: %s\n", chan->tech->type);
385         ast_agi_fdprintf(chan, fd, "agi_uniqueid: %s\n", chan->uniqueid);
386
387         /* ANI/DNIS */
388         ast_agi_fdprintf(chan, fd, "agi_callerid: %s\n", S_OR(chan->cid.cid_num, "unknown"));
389         ast_agi_fdprintf(chan, fd, "agi_calleridname: %s\n", S_OR(chan->cid.cid_name, "unknown"));
390         ast_agi_fdprintf(chan, fd, "agi_callingpres: %d\n", chan->cid.cid_pres);
391         ast_agi_fdprintf(chan, fd, "agi_callingani2: %d\n", chan->cid.cid_ani2);
392         ast_agi_fdprintf(chan, fd, "agi_callington: %d\n", chan->cid.cid_ton);
393         ast_agi_fdprintf(chan, fd, "agi_callingtns: %d\n", chan->cid.cid_tns);
394         ast_agi_fdprintf(chan, fd, "agi_dnid: %s\n", S_OR(chan->cid.cid_dnid, "unknown"));
395         ast_agi_fdprintf(chan, fd, "agi_rdnis: %s\n", S_OR(chan->cid.cid_rdnis, "unknown"));
396
397         /* Context information */
398         ast_agi_fdprintf(chan, fd, "agi_context: %s\n", chan->context);
399         ast_agi_fdprintf(chan, fd, "agi_extension: %s\n", chan->exten);
400         ast_agi_fdprintf(chan, fd, "agi_priority: %d\n", chan->priority);
401         ast_agi_fdprintf(chan, fd, "agi_enhanced: %s\n", enhanced ? "1.0" : "0.0");
402
403         /* User information */
404         ast_agi_fdprintf(chan, fd, "agi_accountcode: %s\n", chan->accountcode ? chan->accountcode : "");
405
406         /* Send any parameters to the fastagi server that have been passed via the agi application */
407         /* Agi application paramaters take the form of: AGI(/path/to/example/script|${EXTEN}) */
408         for(count = 1; count < argc; count++)
409                 ast_agi_fdprintf(chan, fd, "agi_arg_%d: %s\n", count, argv[count]);
410
411         /* End with empty return */
412         ast_agi_fdprintf(chan, fd, "\n");
413 }
414
415 static int handle_answer(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
416 {
417         int res = 0;
418
419         /* Answer the channel */
420         if (chan->_state != AST_STATE_UP)
421                 res = ast_answer(chan);
422
423         ast_agi_fdprintf(chan, agi->fd, "200 result=%d\n", res);
424         return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
425 }
426
427 static int handle_waitfordigit(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
428 {
429         int res, to;
430
431         if (argc != 4)
432                 return RESULT_SHOWUSAGE;
433         if (sscanf(argv[3], "%d", &to) != 1)
434                 return RESULT_SHOWUSAGE;
435         res = ast_waitfordigit_full(chan, to, agi->audio, agi->ctrl);
436         ast_agi_fdprintf(chan, agi->fd, "200 result=%d\n", res);
437         return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
438 }
439
440 static int handle_sendtext(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
441 {
442         int res;
443
444         if (argc != 3)
445                 return RESULT_SHOWUSAGE;
446
447         /* At the moment, the parser (perhaps broken) returns with
448            the last argument PLUS the newline at the end of the input
449            buffer. This probably needs to be fixed, but I wont do that
450            because other stuff may break as a result. The right way
451            would probably be to strip off the trailing newline before
452            parsing, then here, add a newline at the end of the string
453            before sending it to ast_sendtext --DUDE */
454         res = ast_sendtext(chan, argv[2]);
455         ast_agi_fdprintf(chan, agi->fd, "200 result=%d\n", res);
456         return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
457 }
458
459 static int handle_recvchar(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
460 {
461         int res;
462
463         if (argc != 3)
464                 return RESULT_SHOWUSAGE;
465
466         res = ast_recvchar(chan,atoi(argv[2]));
467         if (res == 0) {
468                 ast_agi_fdprintf(chan, agi->fd, "200 result=%d (timeout)\n", res);
469                 return RESULT_SUCCESS;
470         }
471         if (res > 0) {
472                 ast_agi_fdprintf(chan, agi->fd, "200 result=%d\n", res);
473                 return RESULT_SUCCESS;
474         }
475         else {
476                 ast_agi_fdprintf(chan, agi->fd, "200 result=%d (hangup)\n", res);
477                 return RESULT_FAILURE;
478         }
479 }
480
481 static int handle_recvtext(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
482 {
483         char *buf;
484         
485         if (argc != 3)
486                 return RESULT_SHOWUSAGE;
487
488         buf = ast_recvtext(chan,atoi(argv[2]));
489         if (buf) {
490                 ast_agi_fdprintf(chan, agi->fd, "200 result=1 (%s)\n", buf);
491                 ast_free(buf);
492         } else {        
493                 ast_agi_fdprintf(chan, agi->fd, "200 result=-1\n");
494         }
495         return RESULT_SUCCESS;
496 }
497
498 static int handle_tddmode(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
499 {
500         int res, x;
501
502         if (argc != 3)
503                 return RESULT_SHOWUSAGE;
504
505         if (!strncasecmp(argv[2],"on",2)) 
506                 x = 1; 
507         else 
508                 x = 0;
509         if (!strncasecmp(argv[2],"mate",4)) 
510                 x = 2;
511         if (!strncasecmp(argv[2],"tdd",3))
512                 x = 1;
513         res = ast_channel_setoption(chan, AST_OPTION_TDD, &x, sizeof(char), 0);
514         if (res != RESULT_SUCCESS)
515                 ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
516         else
517                 ast_agi_fdprintf(chan, agi->fd, "200 result=1\n");
518         return RESULT_SUCCESS;
519 }
520
521 static int handle_sendimage(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
522 {
523         int res;
524
525         if (argc != 3)
526                 return RESULT_SHOWUSAGE;
527
528         res = ast_send_image(chan, argv[2]);
529         if (!ast_check_hangup(chan))
530                 res = 0;
531         ast_agi_fdprintf(chan, agi->fd, "200 result=%d\n", res);
532         return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
533 }
534
535 static int handle_controlstreamfile(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
536 {
537         int res = 0, skipms = 3000;
538         char *fwd = NULL, *rev = NULL, *pause = NULL, *stop = NULL;
539
540         if (argc < 5 || argc > 9)
541                 return RESULT_SHOWUSAGE;
542
543         if (!ast_strlen_zero(argv[4]))
544                 stop = argv[4];
545         else
546                 stop = NULL;
547         
548         if ((argc > 5) && (sscanf(argv[5], "%d", &skipms) != 1))
549                 return RESULT_SHOWUSAGE;
550
551         if (argc > 6 && !ast_strlen_zero(argv[6]))
552                 fwd = argv[6];
553         else
554                 fwd = "#";
555
556         if (argc > 7 && !ast_strlen_zero(argv[7]))
557                 rev = argv[7];
558         else
559                 rev = "*";
560         
561         if (argc > 8 && !ast_strlen_zero(argv[8]))
562                 pause = argv[8];
563         else
564                 pause = NULL;
565         
566         res = ast_control_streamfile(chan, argv[3], fwd, rev, stop, pause, NULL, skipms, NULL);
567         
568         ast_agi_fdprintf(chan, agi->fd, "200 result=%d\n", res);
569
570         return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
571 }
572
573 static int handle_streamfile(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
574 {
575         int res, vres;
576         struct ast_filestream *fs, *vfs;
577         long sample_offset = 0, max_length;
578         char *edigits = "";
579
580         if (argc < 4 || argc > 5)
581                 return RESULT_SHOWUSAGE;
582
583         if (argv[3]) 
584                 edigits = argv[3];
585
586         if ((argc > 4) && (sscanf(argv[4], "%ld", &sample_offset) != 1))
587                 return RESULT_SHOWUSAGE;
588
589         if (!(fs = ast_openstream(chan, argv[2], chan->language))) {
590                 ast_agi_fdprintf(chan, agi->fd, "200 result=%d endpos=%ld\n", 0, sample_offset);
591                 return RESULT_SUCCESS;
592         }
593
594         if ((vfs = ast_openvstream(chan, argv[2], chan->language)))
595                 ast_debug(1, "Ooh, found a video stream, too\n");
596                 
597         ast_verb(3, "Playing '%s' (escape_digits=%s) (sample_offset %ld)\n", argv[2], edigits, sample_offset);
598
599         ast_seekstream(fs, 0, SEEK_END);
600         max_length = ast_tellstream(fs);
601         ast_seekstream(fs, sample_offset, SEEK_SET);
602         res = ast_applystream(chan, fs);
603         if (vfs)
604                 vres = ast_applystream(chan, vfs);
605         ast_playstream(fs);
606         if (vfs)
607                 ast_playstream(vfs);
608         
609         res = ast_waitstream_full(chan, argv[3], agi->audio, agi->ctrl);
610         /* this is to check for if ast_waitstream closed the stream, we probably are at
611          * the end of the stream, return that amount, else check for the amount */
612         sample_offset = (chan->stream) ? ast_tellstream(fs) : max_length;
613         ast_stopstream(chan);
614         if (res == 1) {
615                 /* Stop this command, don't print a result line, as there is a new command */
616                 return RESULT_SUCCESS;
617         }
618         ast_agi_fdprintf(chan, agi->fd, "200 result=%d endpos=%ld\n", res, sample_offset);
619         return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
620 }
621
622 /* get option - really similar to the handle_streamfile, but with a timeout */
623 static int handle_getoption(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
624 {
625         int res, vres;
626         struct ast_filestream *fs, *vfs;
627         long sample_offset = 0, max_length;
628         int timeout = 0;
629         char *edigits = "";
630
631         if ( argc < 4 || argc > 5 )
632                 return RESULT_SHOWUSAGE;
633
634         if ( argv[3] ) 
635                 edigits = argv[3];
636
637         if ( argc == 5 )
638                 timeout = atoi(argv[4]);
639         else if (chan->pbx->dtimeout) {
640                 /* by default dtimeout is set to 5sec */
641                 timeout = chan->pbx->dtimeout * 1000; /* in msec */
642         }
643
644         if (!(fs = ast_openstream(chan, argv[2], chan->language))) {
645                 ast_agi_fdprintf(chan, agi->fd, "200 result=%d endpos=%ld\n", 0, sample_offset);
646                 ast_log(LOG_WARNING, "Unable to open %s\n", argv[2]);
647                 return RESULT_SUCCESS;
648         }
649
650         if ((vfs = ast_openvstream(chan, argv[2], chan->language)))
651                 ast_debug(1, "Ooh, found a video stream, too\n");
652         
653         ast_verb(3, "Playing '%s' (escape_digits=%s) (timeout %d)\n", argv[2], edigits, timeout);
654
655         ast_seekstream(fs, 0, SEEK_END);
656         max_length = ast_tellstream(fs);
657         ast_seekstream(fs, sample_offset, SEEK_SET);
658         res = ast_applystream(chan, fs);
659         if (vfs)
660                 vres = ast_applystream(chan, vfs);
661         ast_playstream(fs);
662         if (vfs)
663                 ast_playstream(vfs);
664
665         res = ast_waitstream_full(chan, argv[3], agi->audio, agi->ctrl);
666         /* this is to check for if ast_waitstream closed the stream, we probably are at
667          * the end of the stream, return that amount, else check for the amount */
668         sample_offset = (chan->stream)?ast_tellstream(fs):max_length;
669         ast_stopstream(chan);
670         if (res == 1) {
671                 /* Stop this command, don't print a result line, as there is a new command */
672                 return RESULT_SUCCESS;
673         }
674
675         /* If the user didnt press a key, wait for digitTimeout*/
676         if (res == 0 ) {
677                 res = ast_waitfordigit_full(chan, timeout, agi->audio, agi->ctrl);
678                 /* Make sure the new result is in the escape digits of the GET OPTION */
679                 if ( !strchr(edigits,res) )
680                         res=0;
681         }
682
683         ast_agi_fdprintf(chan, agi->fd, "200 result=%d endpos=%ld\n", res, sample_offset);
684         return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
685 }
686
687
688
689
690 /*--- handle_saynumber: Say number in various language syntaxes ---*/
691 /* While waiting, we're sending a NULL.  */
692 static int handle_saynumber(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
693 {
694         int res, num;
695
696         if (argc < 4 || argc > 5)
697                 return RESULT_SHOWUSAGE;
698         if (sscanf(argv[2], "%d", &num) != 1)
699                 return RESULT_SHOWUSAGE;
700         res = ast_say_number_full(chan, num, argv[3], chan->language, argc > 4 ? argv[4] : NULL, agi->audio, agi->ctrl);
701         if (res == 1)
702                 return RESULT_SUCCESS;
703         ast_agi_fdprintf(chan, agi->fd, "200 result=%d\n", res);
704         return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
705 }
706
707 static int handle_saydigits(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
708 {
709         int res, num;
710
711         if (argc != 4)
712                 return RESULT_SHOWUSAGE;
713         if (sscanf(argv[2], "%d", &num) != 1)
714                 return RESULT_SHOWUSAGE;
715
716         res = ast_say_digit_str_full(chan, argv[2], argv[3], chan->language, agi->audio, agi->ctrl);
717         if (res == 1) /* New command */
718                 return RESULT_SUCCESS;
719         ast_agi_fdprintf(chan, agi->fd, "200 result=%d\n", res);
720         return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
721 }
722
723 static int handle_sayalpha(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
724 {
725         int res;
726
727         if (argc != 4)
728                 return RESULT_SHOWUSAGE;
729
730         res = ast_say_character_str_full(chan, argv[2], argv[3], chan->language, agi->audio, agi->ctrl);
731         if (res == 1) /* New command */
732                 return RESULT_SUCCESS;
733         ast_agi_fdprintf(chan, agi->fd, "200 result=%d\n", res);
734         return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
735 }
736
737 static int handle_saydate(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
738 {
739         int res, num;
740
741         if (argc != 4)
742                 return RESULT_SHOWUSAGE;
743         if (sscanf(argv[2], "%d", &num) != 1)
744                 return RESULT_SHOWUSAGE;
745         res = ast_say_date(chan, num, argv[3], chan->language);
746         if (res == 1)
747                 return RESULT_SUCCESS;
748         ast_agi_fdprintf(chan, agi->fd, "200 result=%d\n", res);
749         return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
750 }
751
752 static int handle_saytime(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
753 {
754         int res, num;
755
756         if (argc != 4)
757                 return RESULT_SHOWUSAGE;
758         if (sscanf(argv[2], "%d", &num) != 1)
759                 return RESULT_SHOWUSAGE;
760         res = ast_say_time(chan, num, argv[3], chan->language);
761         if (res == 1)
762                 return RESULT_SUCCESS;
763         ast_agi_fdprintf(chan, agi->fd, "200 result=%d\n", res);
764         return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
765 }
766
767 static int handle_saydatetime(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
768 {
769         int res = 0;
770         time_t unixtime;
771         char *format, *zone = NULL;
772         
773         if (argc < 4)
774                 return RESULT_SHOWUSAGE;
775
776         if (argc > 4) {
777                 format = argv[4];
778         } else {
779                 /* XXX this doesn't belong here, but in the 'say' module */
780                 if (!strcasecmp(chan->language, "de")) {
781                         format = "A dBY HMS";
782                 } else {
783                         format = "ABdY 'digits/at' IMp"; 
784                 }
785         }
786
787         if (argc > 5 && !ast_strlen_zero(argv[5]))
788                 zone = argv[5];
789
790         if (ast_get_time_t(argv[2], &unixtime, 0, NULL))
791                 return RESULT_SHOWUSAGE;
792
793         res = ast_say_date_with_format(chan, unixtime, argv[3], chan->language, format, zone);
794         if (res == 1)
795                 return RESULT_SUCCESS;
796
797         ast_agi_fdprintf(chan, agi->fd, "200 result=%d\n", res);
798         return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
799 }
800
801 static int handle_sayphonetic(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
802 {
803         int res;
804
805         if (argc != 4)
806                 return RESULT_SHOWUSAGE;
807
808         res = ast_say_phonetic_str_full(chan, argv[2], argv[3], chan->language, agi->audio, agi->ctrl);
809         if (res == 1) /* New command */
810                 return RESULT_SUCCESS;
811         ast_agi_fdprintf(chan, agi->fd, "200 result=%d\n", res);
812         return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
813 }
814
815 static int handle_getdata(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
816 {
817         int res, max, timeout;
818         char data[1024];
819
820         if (argc < 3)
821                 return RESULT_SHOWUSAGE;
822         if (argc >= 4)
823                 timeout = atoi(argv[3]); 
824         else
825                 timeout = 0;
826         if (argc >= 5) 
827                 max = atoi(argv[4]); 
828         else
829                 max = 1024;
830         res = ast_app_getdata_full(chan, argv[2], data, max, timeout, agi->audio, agi->ctrl);
831         if (res == 2)                   /* New command */
832                 return RESULT_SUCCESS;
833         else if (res == 1)
834                 ast_agi_fdprintf(chan, agi->fd, "200 result=%s (timeout)\n", data);
835         else if (res < 0 )
836                 ast_agi_fdprintf(chan, agi->fd, "200 result=-1\n");
837         else
838                 ast_agi_fdprintf(chan, agi->fd, "200 result=%s\n", data);
839         return RESULT_SUCCESS;
840 }
841
842 static int handle_setcontext(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
843 {
844
845         if (argc != 3)
846                 return RESULT_SHOWUSAGE;
847         ast_copy_string(chan->context, argv[2], sizeof(chan->context));
848         ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
849         return RESULT_SUCCESS;
850 }
851         
852 static int handle_setextension(struct ast_channel *chan, AGI *agi, int argc, char **argv)
853 {
854         if (argc != 3)
855                 return RESULT_SHOWUSAGE;
856         ast_copy_string(chan->exten, argv[2], sizeof(chan->exten));
857         ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
858         return RESULT_SUCCESS;
859 }
860
861 static int handle_setpriority(struct ast_channel *chan, AGI *agi, int argc, char **argv)
862 {
863         int pri;
864
865         if (argc != 3)
866                 return RESULT_SHOWUSAGE;        
867
868         if (sscanf(argv[2], "%d", &pri) != 1) {
869                 if ((pri = ast_findlabel_extension(chan, chan->context, chan->exten, argv[2], chan->cid.cid_num)) < 1)
870                         return RESULT_SHOWUSAGE;
871         }
872
873         ast_explicit_goto(chan, NULL, NULL, pri);
874         ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
875         return RESULT_SUCCESS;
876 }
877                 
878 static int handle_recordfile(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
879 {
880         struct ast_filestream *fs;
881         struct ast_frame *f;
882         struct timeval start;
883         long sample_offset = 0;
884         int res = 0;
885         int ms;
886
887         struct ast_dsp *sildet=NULL;         /* silence detector dsp */
888         int totalsilence = 0;
889         int dspsilence = 0;
890         int silence = 0;                /* amount of silence to allow */
891         int gotsilence = 0;             /* did we timeout for silence? */
892         char *silencestr=NULL;
893         int rfmt=0;
894
895
896         /* XXX EAGI FIXME XXX */
897
898         if (argc < 6)
899                 return RESULT_SHOWUSAGE;
900         if (sscanf(argv[5], "%d", &ms) != 1)
901                 return RESULT_SHOWUSAGE;
902
903         if (argc > 6)
904                 silencestr = strchr(argv[6],'s');
905         if ((argc > 7) && (!silencestr))
906                 silencestr = strchr(argv[7],'s');
907         if ((argc > 8) && (!silencestr))
908                 silencestr = strchr(argv[8],'s');
909
910         if (silencestr) {
911                 if (strlen(silencestr) > 2) {
912                         if ((silencestr[0] == 's') && (silencestr[1] == '=')) {
913                                 silencestr++;
914                                 silencestr++;
915                                 if (silencestr)
916                                         silence = atoi(silencestr);
917                                 if (silence > 0)
918                                         silence *= 1000;
919                         }
920                 }
921         }
922
923         if (silence > 0) {
924                 rfmt = chan->readformat;
925                 res = ast_set_read_format(chan, AST_FORMAT_SLINEAR);
926                 if (res < 0) {
927                         ast_log(LOG_WARNING, "Unable to set to linear mode, giving up\n");
928                         return -1;
929                 }
930                 sildet = ast_dsp_new();
931                 if (!sildet) {
932                         ast_log(LOG_WARNING, "Unable to create silence detector :(\n");
933                         return -1;
934                 }
935                 ast_dsp_set_threshold(sildet, 256);
936         }
937
938         /* backward compatibility, if no offset given, arg[6] would have been
939          * caught below and taken to be a beep, else if it is a digit then it is a
940          * offset */
941         if ((argc >6) && (sscanf(argv[6], "%ld", &sample_offset) != 1) && (!strchr(argv[6], '=')))
942                 res = ast_streamfile(chan, "beep", chan->language);
943
944         if ((argc > 7) && (!strchr(argv[7], '=')))
945                 res = ast_streamfile(chan, "beep", chan->language);
946
947         if (!res)
948                 res = ast_waitstream(chan, argv[4]);
949         if (res) {
950                 ast_agi_fdprintf(chan, agi->fd, "200 result=%d (randomerror) endpos=%ld\n", res, sample_offset);
951         } else {
952                 fs = ast_writefile(argv[2], argv[3], NULL, O_CREAT | O_WRONLY | (sample_offset ? O_APPEND : 0), 0, AST_FILE_MODE);
953                 if (!fs) {
954                         res = -1;
955                         ast_agi_fdprintf(chan, agi->fd, "200 result=%d (writefile)\n", res);
956                         if (sildet)
957                                 ast_dsp_free(sildet);
958                         return RESULT_FAILURE;
959                 }
960                 
961                 /* Request a video update */
962                 ast_indicate(chan, AST_CONTROL_VIDUPDATE);
963         
964                 chan->stream = fs;
965                 ast_applystream(chan,fs);
966                 /* really should have checks */
967                 ast_seekstream(fs, sample_offset, SEEK_SET);
968                 ast_truncstream(fs);
969                 
970                 start = ast_tvnow();
971                 while ((ms < 0) || ast_tvdiff_ms(ast_tvnow(), start) < ms) {
972                         res = ast_waitfor(chan, -1);
973                         if (res < 0) {
974                                 ast_closestream(fs);
975                                 ast_agi_fdprintf(chan, agi->fd, "200 result=%d (waitfor) endpos=%ld\n", res,sample_offset);
976                                 if (sildet)
977                                         ast_dsp_free(sildet);
978                                 return RESULT_FAILURE;
979                         }
980                         f = ast_read(chan);
981                         if (!f) {
982                                 ast_agi_fdprintf(chan, agi->fd, "200 result=%d (hangup) endpos=%ld\n", 0, sample_offset);
983                                 ast_closestream(fs);
984                                 if (sildet)
985                                         ast_dsp_free(sildet);
986                                 return RESULT_FAILURE;
987                         }
988                         switch(f->frametype) {
989                         case AST_FRAME_DTMF:
990                                 if (strchr(argv[4], f->subclass)) {
991                                         /* This is an interrupting chracter, so rewind to chop off any small
992                                            amount of DTMF that may have been recorded
993                                         */
994                                         ast_stream_rewind(fs, 200);
995                                         ast_truncstream(fs);
996                                         sample_offset = ast_tellstream(fs);
997                                         ast_agi_fdprintf(chan, agi->fd, "200 result=%d (dtmf) endpos=%ld\n", f->subclass, sample_offset);
998                                         ast_closestream(fs);
999                                         ast_frfree(f);
1000                                         if (sildet)
1001                                                 ast_dsp_free(sildet);
1002                                         return RESULT_SUCCESS;
1003                                 }
1004                                 break;
1005                         case AST_FRAME_VOICE:
1006                                 ast_writestream(fs, f);
1007                                 /* this is a safe place to check progress since we know that fs
1008                                  * is valid after a write, and it will then have our current
1009                                  * location */
1010                                 sample_offset = ast_tellstream(fs);
1011                                 if (silence > 0) {
1012                                         dspsilence = 0;
1013                                         ast_dsp_silence(sildet, f, &dspsilence);
1014                                         if (dspsilence) {
1015                                                 totalsilence = dspsilence;
1016                                         } else {
1017                                                 totalsilence = 0;
1018                                         }
1019                                         if (totalsilence > silence) {
1020                                                 /* Ended happily with silence */
1021                                                 gotsilence = 1;
1022                                                 break;
1023                                         }
1024                                 }
1025                                 break;
1026                         case AST_FRAME_VIDEO:
1027                                 ast_writestream(fs, f);
1028                         default:
1029                                 /* Ignore all other frames */
1030                                 break;
1031                         }
1032                         ast_frfree(f);
1033                         if (gotsilence)
1034                                 break;
1035                 }
1036
1037                         if (gotsilence) {
1038                                 ast_stream_rewind(fs, silence-1000);
1039                                 ast_truncstream(fs);
1040                                 sample_offset = ast_tellstream(fs);
1041                 }               
1042                 ast_agi_fdprintf(chan, agi->fd, "200 result=%d (timeout) endpos=%ld\n", res, sample_offset);
1043                 ast_closestream(fs);
1044         }
1045
1046         if (silence > 0) {
1047                 res = ast_set_read_format(chan, rfmt);
1048                 if (res)
1049                         ast_log(LOG_WARNING, "Unable to restore read format on '%s'\n", chan->name);
1050                         ast_dsp_free(sildet);
1051         }
1052         return RESULT_SUCCESS;
1053 }
1054
1055 static int handle_autohangup(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
1056 {
1057         int timeout;
1058
1059         if (argc != 3)
1060                 return RESULT_SHOWUSAGE;
1061         if (sscanf(argv[2], "%d", &timeout) != 1)
1062                 return RESULT_SHOWUSAGE;
1063         if (timeout < 0)
1064                 timeout = 0;
1065         if (timeout)
1066                 chan->whentohangup = time(NULL) + timeout;
1067         else
1068                 chan->whentohangup = 0;
1069         ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
1070         return RESULT_SUCCESS;
1071 }
1072
1073 static int handle_hangup(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1074 {
1075         struct ast_channel *c;
1076
1077         if (argc == 1) {
1078                 /* no argument: hangup the current channel */
1079                 ast_softhangup(chan,AST_SOFTHANGUP_EXPLICIT);
1080                 ast_agi_fdprintf(chan, agi->fd, "200 result=1\n");
1081                 return RESULT_SUCCESS;
1082         } else if (argc == 2) {
1083                 /* one argument: look for info on the specified channel */
1084                 c = ast_get_channel_by_name_locked(argv[1]);
1085                 if (c) {
1086                         /* we have a matching channel */
1087                         ast_softhangup(c,AST_SOFTHANGUP_EXPLICIT);
1088                         ast_agi_fdprintf(chan, agi->fd, "200 result=1\n");
1089                         ast_channel_unlock(c);
1090                         return RESULT_SUCCESS;
1091                 }
1092                 /* if we get this far no channel name matched the argument given */
1093                 ast_agi_fdprintf(chan, agi->fd, "200 result=-1\n");
1094                 return RESULT_SUCCESS;
1095         } else {
1096                 return RESULT_SHOWUSAGE;
1097         }
1098 }
1099
1100 static int handle_exec(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1101 {
1102         int res;
1103         struct ast_app *app;
1104
1105         if (argc < 2)
1106                 return RESULT_SHOWUSAGE;
1107
1108         ast_verb(3, "AGI Script Executing Application: (%s) Options: (%s)\n", argv[1], argv[2]);
1109
1110         if ((app = pbx_findapp(argv[1]))) {
1111                 res = pbx_exec(chan, app, argv[2]);
1112         } else {
1113                 ast_log(LOG_WARNING, "Could not find application (%s)\n", argv[1]);
1114                 res = -2;
1115         }
1116         ast_agi_fdprintf(chan, agi->fd, "200 result=%d\n", res);
1117
1118         /* Even though this is wrong, users are depending upon this result. */
1119         return res;
1120 }
1121
1122 static int handle_setcallerid(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1123 {
1124         char tmp[256]="";
1125         char *l = NULL, *n = NULL;
1126
1127         if (argv[2]) {
1128                 ast_copy_string(tmp, argv[2], sizeof(tmp));
1129                 ast_callerid_parse(tmp, &n, &l);
1130                 if (l)
1131                         ast_shrink_phone_number(l);
1132                 else
1133                         l = "";
1134                 if (!n)
1135                         n = "";
1136                 ast_set_callerid(chan, l, n, NULL);
1137         }
1138
1139         ast_agi_fdprintf(chan, agi->fd, "200 result=1\n");
1140         return RESULT_SUCCESS;
1141 }
1142
1143 static int handle_channelstatus(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1144 {
1145         struct ast_channel *c;
1146         if (argc == 2) {
1147                 /* no argument: supply info on the current channel */
1148                 ast_agi_fdprintf(chan, agi->fd, "200 result=%d\n", chan->_state);
1149                 return RESULT_SUCCESS;
1150         } else if (argc == 3) {
1151                 /* one argument: look for info on the specified channel */
1152                 c = ast_get_channel_by_name_locked(argv[2]);
1153                 if (c) {
1154                         ast_agi_fdprintf(chan, agi->fd, "200 result=%d\n", c->_state);
1155                         ast_channel_unlock(c);
1156                         return RESULT_SUCCESS;
1157                 }
1158                 /* if we get this far no channel name matched the argument given */
1159                 ast_agi_fdprintf(chan, agi->fd, "200 result=-1\n");
1160                 return RESULT_SUCCESS;
1161         } else {
1162                 return RESULT_SHOWUSAGE;
1163         }
1164 }
1165
1166 static int handle_setvariable(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1167 {
1168         if (argv[3])
1169                 pbx_builtin_setvar_helper(chan, argv[2], argv[3]);
1170
1171         ast_agi_fdprintf(chan, agi->fd, "200 result=1\n");
1172         return RESULT_SUCCESS;
1173 }
1174
1175 static int handle_getvariable(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1176 {
1177         char *ret;
1178         char tempstr[1024];
1179
1180         if (argc != 3)
1181                 return RESULT_SHOWUSAGE;
1182
1183         /* check if we want to execute an ast_custom_function */
1184         if (!ast_strlen_zero(argv[2]) && (argv[2][strlen(argv[2]) - 1] == ')')) {
1185                 ret = ast_func_read(chan, argv[2], tempstr, sizeof(tempstr)) ? NULL : tempstr;
1186         } else {
1187                 pbx_retrieve_variable(chan, argv[2], &ret, tempstr, sizeof(tempstr), NULL);
1188         }
1189
1190         if (ret)
1191                 ast_agi_fdprintf(chan, agi->fd, "200 result=1 (%s)\n", ret);
1192         else
1193                 ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
1194
1195         return RESULT_SUCCESS;
1196 }
1197
1198 static int handle_getvariablefull(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1199 {
1200         char tmp[4096];
1201         struct ast_channel *chan2=NULL;
1202
1203         if ((argc != 4) && (argc != 5))
1204                 return RESULT_SHOWUSAGE;
1205         if (argc == 5) {
1206                 chan2 = ast_get_channel_by_name_locked(argv[4]);
1207         } else {
1208                 chan2 = chan;
1209         }
1210         if (chan2) {
1211                 pbx_substitute_variables_helper(chan2, argv[3], tmp, sizeof(tmp) - 1);
1212                 ast_agi_fdprintf(chan, agi->fd, "200 result=1 (%s)\n", tmp);
1213         } else {
1214                 ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
1215         }
1216         if (chan2 && (chan2 != chan))
1217                 ast_channel_unlock(chan2);
1218         return RESULT_SUCCESS;
1219 }
1220
1221 static int handle_verbose(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1222 {
1223         int level = 0;
1224         char *prefix;
1225
1226         if (argc < 2)
1227                 return RESULT_SHOWUSAGE;
1228
1229         if (argv[2])
1230                 sscanf(argv[2], "%d", &level);
1231
1232         switch (level) {
1233                 case 4:
1234                         prefix = VERBOSE_PREFIX_4;
1235                         break;
1236                 case 3:
1237                         prefix = VERBOSE_PREFIX_3;
1238                         break;
1239                 case 2:
1240                         prefix = VERBOSE_PREFIX_2;
1241                         break;
1242                 case 1:
1243                 default:
1244                         prefix = VERBOSE_PREFIX_1;
1245                         break;
1246         }
1247
1248         if (level <= option_verbose)
1249                 ast_verbose("%s %s: %s\n", prefix, chan->data, argv[1]);
1250         
1251         ast_agi_fdprintf(chan, agi->fd, "200 result=1\n");
1252         
1253         return RESULT_SUCCESS;
1254 }
1255
1256 static int handle_dbget(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1257 {
1258         int res;
1259         char tmp[256];
1260
1261         if (argc != 4)
1262                 return RESULT_SHOWUSAGE;
1263         res = ast_db_get(argv[2], argv[3], tmp, sizeof(tmp));
1264         if (res) 
1265                 ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
1266         else
1267                 ast_agi_fdprintf(chan, agi->fd, "200 result=1 (%s)\n", tmp);
1268
1269         return RESULT_SUCCESS;
1270 }
1271
1272 static int handle_dbput(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1273 {
1274         int res;
1275
1276         if (argc != 5)
1277                 return RESULT_SHOWUSAGE;
1278         res = ast_db_put(argv[2], argv[3], argv[4]);
1279         ast_agi_fdprintf(chan, agi->fd, "200 result=%c\n", res ? '0' : '1');
1280         return RESULT_SUCCESS;
1281 }
1282
1283 static int handle_dbdel(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1284 {
1285         int res;
1286
1287         if (argc != 4)
1288                 return RESULT_SHOWUSAGE;
1289         res = ast_db_del(argv[2], argv[3]);
1290         ast_agi_fdprintf(chan, agi->fd, "200 result=%c\n", res ? '0' : '1');
1291         return RESULT_SUCCESS;
1292 }
1293
1294 static int handle_dbdeltree(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1295 {
1296         int res;
1297
1298         if ((argc < 3) || (argc > 4))
1299                 return RESULT_SHOWUSAGE;
1300         if (argc == 4)
1301                 res = ast_db_deltree(argv[2], argv[3]);
1302         else
1303                 res = ast_db_deltree(argv[2], NULL);
1304
1305         ast_agi_fdprintf(chan, agi->fd, "200 result=%c\n", res ? '0' : '1');
1306         return RESULT_SUCCESS;
1307 }
1308
1309 static char *handle_cli_agi_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1310 {
1311         switch (cmd) {
1312         case CLI_INIT:
1313                 e->command = "agi debug [off]";
1314                 e->usage =
1315                         "Usage: agi debug [off]\n"
1316                         "       Enables/disables dumping of AGI transactions for\n"
1317                         "       debugging purposes.\n";
1318                 return NULL;
1319
1320         case CLI_GENERATE:
1321                 return NULL;
1322         }
1323         if (a->argc < e->args - 1 || a->argc > e->args )
1324                 return CLI_SHOWUSAGE;
1325         if (a->argc == e->args - 1) {
1326                 agidebug = 1;
1327         } else {
1328                 if (strncasecmp(a->argv[e->args - 1], "off", 3) == 0) {
1329                         agidebug = 0;
1330                 } else {
1331                         return CLI_SHOWUSAGE;
1332                 }
1333         }
1334         ast_cli(a->fd, "AGI Debugging %sabled\n", agidebug ? "En" : "Dis");
1335         return CLI_SUCCESS;
1336 }
1337
1338 static int handle_noop(struct ast_channel *chan, AGI *agi, int arg, char *argv[])
1339 {
1340         ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
1341         return RESULT_SUCCESS;
1342 }
1343
1344 static int handle_setmusic(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
1345 {
1346         if (!strncasecmp(argv[2], "on", 2))
1347                 ast_moh_start(chan, argc > 3 ? argv[3] : NULL, NULL);
1348         else if (!strncasecmp(argv[2], "off", 3))
1349                 ast_moh_stop(chan);
1350         ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
1351         return RESULT_SUCCESS;
1352 }
1353
1354 static char usage_setmusic[] =
1355 " Usage: SET MUSIC ON <on|off> <class>\n"
1356 "       Enables/Disables the music on hold generator.  If <class> is\n"
1357 " not specified, then the default music on hold class will be used.\n"
1358 " Always returns 0.\n";
1359
1360 static char usage_dbput[] =
1361 " Usage: DATABASE PUT <family> <key> <value>\n"
1362 "       Adds or updates an entry in the Asterisk database for a\n"
1363 " given family, key, and value.\n"
1364 " Returns 1 if successful, 0 otherwise.\n";
1365
1366 static char usage_dbget[] =
1367 " Usage: DATABASE GET <family> <key>\n"
1368 "       Retrieves an entry in the Asterisk database for a\n"
1369 " given family and key.\n"
1370 " Returns 0 if <key> is not set.  Returns 1 if <key>\n"
1371 " is set and returns the variable in parentheses.\n"
1372 " Example return code: 200 result=1 (testvariable)\n";
1373
1374 static char usage_dbdel[] =
1375 " Usage: DATABASE DEL <family> <key>\n"
1376 "       Deletes an entry in the Asterisk database for a\n"
1377 " given family and key.\n"
1378 " Returns 1 if successful, 0 otherwise.\n";
1379
1380 static char usage_dbdeltree[] =
1381 " Usage: DATABASE DELTREE <family> [keytree]\n"
1382 "       Deletes a family or specific keytree within a family\n"
1383 " in the Asterisk database.\n"
1384 " Returns 1 if successful, 0 otherwise.\n";
1385
1386 static char usage_verbose[] =
1387 " Usage: VERBOSE <message> <level>\n"
1388 "       Sends <message> to the console via verbose message system.\n"
1389 " <level> is the the verbose level (1-4)\n"
1390 " Always returns 1.\n";
1391
1392 static char usage_getvariable[] =
1393 " Usage: GET VARIABLE <variablename>\n"
1394 "       Returns 0 if <variablename> is not set.  Returns 1 if <variablename>\n"
1395 " is set and returns the variable in parentheses.\n"
1396 " example return code: 200 result=1 (testvariable)\n";
1397
1398 static char usage_getvariablefull[] =
1399 " Usage: GET FULL VARIABLE <variablename> [<channel name>]\n"
1400 "       Returns 0 if <variablename> is not set or channel does not exist.  Returns 1\n"
1401 "if <variablename>  is set and returns the variable in parenthesis.  Understands\n"
1402 "complex variable names and builtin variables, unlike GET VARIABLE.\n"
1403 " example return code: 200 result=1 (testvariable)\n";
1404
1405 static char usage_setvariable[] =
1406 " Usage: SET VARIABLE <variablename> <value>\n";
1407
1408 static char usage_channelstatus[] =
1409 " Usage: CHANNEL STATUS [<channelname>]\n"
1410 "       Returns the status of the specified channel.\n" 
1411 " If no channel name is given the returns the status of the\n"
1412 " current channel.  Return values:\n"
1413 "  0 Channel is down and available\n"
1414 "  1 Channel is down, but reserved\n"
1415 "  2 Channel is off hook\n"
1416 "  3 Digits (or equivalent) have been dialed\n"
1417 "  4 Line is ringing\n"
1418 "  5 Remote end is ringing\n"
1419 "  6 Line is up\n"
1420 "  7 Line is busy\n";
1421
1422 static char usage_setcallerid[] =
1423 " Usage: SET CALLERID <number>\n"
1424 "       Changes the callerid of the current channel.\n";
1425
1426 static char usage_exec[] =
1427 " Usage: EXEC <application> <options>\n"
1428 "       Executes <application> with given <options>.\n"
1429 " Returns whatever the application returns, or -2 on failure to find application\n";
1430
1431 static char usage_hangup[] =
1432 " Usage: HANGUP [<channelname>]\n"
1433 "       Hangs up the specified channel.\n"
1434 " If no channel name is given, hangs up the current channel\n";
1435
1436 static char usage_answer[] = 
1437 " Usage: ANSWER\n"
1438 "       Answers channel if not already in answer state. Returns -1 on\n"
1439 " channel failure, or 0 if successful.\n";
1440
1441 static char usage_waitfordigit[] = 
1442 " Usage: WAIT FOR DIGIT <timeout>\n"
1443 "       Waits up to 'timeout' milliseconds for channel to receive a DTMF digit.\n"
1444 " Returns -1 on channel failure, 0 if no digit is received in the timeout, or\n"
1445 " the numerical value of the ascii of the digit if one is received.  Use -1\n"
1446 " for the timeout value if you desire the call to block indefinitely.\n";
1447
1448 static char usage_sendtext[] =
1449 " Usage: SEND TEXT \"<text to send>\"\n"
1450 "       Sends the given text on a channel. Most channels do not support the\n"
1451 " transmission of text.  Returns 0 if text is sent, or if the channel does not\n"
1452 " support text transmission.  Returns -1 only on error/hangup.  Text\n"
1453 " consisting of greater than one word should be placed in quotes since the\n"
1454 " command only accepts a single argument.\n";
1455
1456 static char usage_recvchar[] =
1457 " Usage: RECEIVE CHAR <timeout>\n"
1458 "       Receives a character of text on a channel. Specify timeout to be the\n"
1459 " maximum time to wait for input in milliseconds, or 0 for infinite. Most channels\n"
1460 " do not support the reception of text. Returns the decimal value of the character\n"
1461 " if one is received, or 0 if the channel does not support text reception.  Returns\n"
1462 " -1 only on error/hangup.\n";
1463
1464 static char usage_recvtext[] =
1465 " Usage: RECEIVE TEXT <timeout>\n"
1466 "       Receives a string of text on a channel. Specify timeout to be the\n"
1467 " maximum time to wait for input in milliseconds, or 0 for infinite. Most channels\n"
1468 " do not support the reception of text. Returns -1 for failure or 1 for success, and the string in parentheses.\n";
1469
1470 static char usage_tddmode[] =
1471 " Usage: TDD MODE <on|off>\n"
1472 "       Enable/Disable TDD transmission/reception on a channel. Returns 1 if\n"
1473 " successful, or 0 if channel is not TDD-capable.\n";
1474
1475 static char usage_sendimage[] =
1476 " Usage: SEND IMAGE <image>\n"
1477 "       Sends the given image on a channel. Most channels do not support the\n"
1478 " transmission of images. Returns 0 if image is sent, or if the channel does not\n"
1479 " support image transmission.  Returns -1 only on error/hangup. Image names\n"
1480 " should not include extensions.\n";
1481
1482 static char usage_streamfile[] =
1483 " Usage: STREAM FILE <filename> <escape digits> [sample offset]\n"
1484 "       Send the given file, allowing playback to be interrupted by the given\n"
1485 " digits, if any. Use double quotes for the digits if you wish none to be\n"
1486 " permitted. If sample offset is provided then the audio will seek to sample\n"
1487 " offset before play starts.  Returns 0 if playback completes without a digit\n"
1488 " being pressed, or the ASCII numerical value of the digit if one was pressed,\n"
1489 " or -1 on error or if the channel was disconnected. Remember, the file\n"
1490 " extension must not be included in the filename.\n";
1491
1492 static char usage_controlstreamfile[] =
1493 " Usage: CONTROL STREAM FILE <filename> <escape digits> [skipms] [ffchar] [rewchr] [pausechr]\n"
1494 "       Send the given file, allowing playback to be controled by the given\n"
1495 " digits, if any. Use double quotes for the digits if you wish none to be\n"
1496 " permitted.  Returns 0 if playback completes without a digit\n"
1497 " being pressed, or the ASCII numerical value of the digit if one was pressed,\n"
1498 " or -1 on error or if the channel was disconnected. Remember, the file\n"
1499 " extension must not be included in the filename.\n\n"
1500 " Note: ffchar and rewchar default to * and # respectively.\n";
1501
1502 static char usage_getoption[] = 
1503 " Usage: GET OPTION <filename> <escape_digits> [timeout]\n"
1504 "       Behaves similar to STREAM FILE but used with a timeout option.\n";
1505
1506 static char usage_saynumber[] =
1507 " Usage: SAY NUMBER <number> <escape digits> [gender]\n"
1508 "       Say a given number, returning early if any of the given DTMF digits\n"
1509 " are received on the channel.  Returns 0 if playback completes without a digit\n"
1510 " being pressed, or the ASCII numerical value of the digit if one was pressed or\n"
1511 " -1 on error/hangup.\n";
1512
1513 static char usage_saydigits[] =
1514 " Usage: SAY DIGITS <number> <escape digits>\n"
1515 "       Say a given digit string, returning early if any of the given DTMF digits\n"
1516 " are received on the channel. Returns 0 if playback completes without a digit\n"
1517 " being pressed, or the ASCII numerical value of the digit if one was pressed or\n"
1518 " -1 on error/hangup.\n";
1519
1520 static char usage_sayalpha[] =
1521 " Usage: SAY ALPHA <number> <escape digits>\n"
1522 "       Say a given character string, returning early if any of the given DTMF digits\n"
1523 " are received on the channel. Returns 0 if playback completes without a digit\n"
1524 " being pressed, or the ASCII numerical value of the digit if one was pressed or\n"
1525 " -1 on error/hangup.\n";
1526
1527 static char usage_saydate[] =
1528 " Usage: SAY DATE <date> <escape digits>\n"
1529 "       Say a given date, returning early if any of the given DTMF digits are\n"
1530 " received on the channel.  <date> is number of seconds elapsed since 00:00:00\n"
1531 " on January 1, 1970, Coordinated Universal Time (UTC). Returns 0 if playback\n"
1532 " completes without a digit being pressed, or the ASCII numerical value of the\n"
1533 " digit if one was pressed or -1 on error/hangup.\n";
1534
1535 static char usage_saytime[] =
1536 " Usage: SAY TIME <time> <escape digits>\n"
1537 "       Say a given time, returning early if any of the given DTMF digits are\n"
1538 " received on the channel.  <time> is number of seconds elapsed since 00:00:00\n"
1539 " on January 1, 1970, Coordinated Universal Time (UTC). Returns 0 if playback\n"
1540 " completes without a digit being pressed, or the ASCII numerical value of the\n"
1541 " digit if one was pressed or -1 on error/hangup.\n";
1542
1543 static char usage_saydatetime[] =
1544 " Usage: SAY DATETIME <time> <escape digits> [format] [timezone]\n"
1545 "       Say a given time, returning early if any of the given DTMF digits are\n"
1546 " received on the channel.  <time> is number of seconds elapsed since 00:00:00\n"
1547 " on January 1, 1970, Coordinated Universal Time (UTC). [format] is the format\n"
1548 " the time should be said in.  See voicemail.conf (defaults to \"ABdY\n"
1549 " 'digits/at' IMp\").  Acceptable values for [timezone] can be found in\n"
1550 " /usr/share/zoneinfo.  Defaults to machine default. Returns 0 if playback\n"
1551 " completes without a digit being pressed, or the ASCII numerical value of the\n"
1552 " digit if one was pressed or -1 on error/hangup.\n";
1553
1554 static char usage_sayphonetic[] =
1555 " Usage: SAY PHONETIC <string> <escape digits>\n"
1556 "       Say a given character string with phonetics, returning early if any of the\n"
1557 " given DTMF digits are received on the channel. Returns 0 if playback\n"
1558 " completes without a digit pressed, the ASCII numerical value of the digit\n"
1559 " if one was pressed, or -1 on error/hangup.\n";
1560
1561 static char usage_getdata[] =
1562 " Usage: GET DATA <file to be streamed> [timeout] [max digits]\n"
1563 "       Stream the given file, and recieve DTMF data. Returns the digits received\n"
1564 "from the channel at the other end.\n";
1565
1566 static char usage_setcontext[] =
1567 " Usage: SET CONTEXT <desired context>\n"
1568 "       Sets the context for continuation upon exiting the application.\n";
1569
1570 static char usage_setextension[] =
1571 " Usage: SET EXTENSION <new extension>\n"
1572 "       Changes the extension for continuation upon exiting the application.\n";
1573
1574 static char usage_setpriority[] =
1575 " Usage: SET PRIORITY <priority>\n"
1576 "       Changes the priority for continuation upon exiting the application.\n"
1577 " The priority must be a valid priority or label.\n";
1578
1579 static char usage_recordfile[] =
1580 " Usage: RECORD FILE <filename> <format> <escape digits> <timeout> \\\n"
1581 "                                          [offset samples] [BEEP] [s=silence]\n"
1582 "       Record to a file until a given dtmf digit in the sequence is received\n"
1583 " Returns -1 on hangup or error.  The format will specify what kind of file\n"
1584 " will be recorded.  The timeout is the maximum record time in milliseconds, or\n"
1585 " -1 for no timeout. \"Offset samples\" is optional, and, if provided, will seek\n"
1586 " to the offset without exceeding the end of the file.  \"silence\" is the number\n"
1587 " of seconds of silence allowed before the function returns despite the\n"
1588 " lack of dtmf digits or reaching timeout.  Silence value must be\n"
1589 " preceeded by \"s=\" and is also optional.\n";
1590
1591 static char usage_autohangup[] =
1592 " Usage: SET AUTOHANGUP <time>\n"
1593 "       Cause the channel to automatically hangup at <time> seconds in the\n"
1594 " future.  Of course it can be hungup before then as well. Setting to 0 will\n"
1595 " cause the autohangup feature to be disabled on this channel.\n";
1596
1597 static char usage_noop[] =
1598 " Usage: NoOp\n"
1599 "       Does nothing.\n";
1600
1601 /*!
1602  * \brief AGI commands list
1603  */
1604 static struct agi_command commands[] = {
1605         { { "answer", NULL }, handle_answer, "Answer channel", usage_answer , 0 },
1606         { { "channel", "status", NULL }, handle_channelstatus, "Returns status of the connected channel", usage_channelstatus , 0 },
1607         { { "database", "del", NULL }, handle_dbdel, "Removes database key/value", usage_dbdel , 1 },
1608         { { "database", "deltree", NULL }, handle_dbdeltree, "Removes database keytree/value", usage_dbdeltree , 1 },
1609         { { "database", "get", NULL }, handle_dbget, "Gets database value", usage_dbget , 1 },
1610         { { "database", "put", NULL }, handle_dbput, "Adds/updates database value", usage_dbput , 1 },
1611         { { "exec", NULL }, handle_exec, "Executes a given Application", usage_exec , 1 },
1612         { { "get", "data", NULL }, handle_getdata, "Prompts for DTMF on a channel", usage_getdata , 0 },
1613         { { "get", "full", "variable", NULL }, handle_getvariablefull, "Evaluates a channel expression", usage_getvariablefull , 1 },
1614         { { "get", "option", NULL }, handle_getoption, "Stream file, prompt for DTMF, with timeout", usage_getoption , 0 },
1615         { { "get", "variable", NULL }, handle_getvariable, "Gets a channel variable", usage_getvariable , 1 },
1616         { { "hangup", NULL }, handle_hangup, "Hangup the current channel", usage_hangup , 0 },
1617         { { "noop", NULL }, handle_noop, "Does nothing", usage_noop , 1 },
1618         { { "receive", "char", NULL }, handle_recvchar, "Receives one character from channels supporting it", usage_recvchar , 0 },
1619         { { "receive", "text", NULL }, handle_recvtext, "Receives text from channels supporting it", usage_recvtext , 0 },
1620         { { "record", "file", NULL }, handle_recordfile, "Records to a given file", usage_recordfile , 0 },
1621         { { "say", "alpha", NULL }, handle_sayalpha, "Says a given character string", usage_sayalpha , 0 },
1622         { { "say", "digits", NULL }, handle_saydigits, "Says a given digit string", usage_saydigits , 0 },
1623         { { "say", "number", NULL }, handle_saynumber, "Says a given number", usage_saynumber , 0 },
1624         { { "say", "phonetic", NULL }, handle_sayphonetic, "Says a given character string with phonetics", usage_sayphonetic , 0 },
1625         { { "say", "date", NULL }, handle_saydate, "Says a given date", usage_saydate , 0 },
1626         { { "say", "time", NULL }, handle_saytime, "Says a given time", usage_saytime , 0 },
1627         { { "say", "datetime", NULL }, handle_saydatetime, "Says a given time as specfied by the format given", usage_saydatetime , 0 },
1628         { { "send", "image", NULL }, handle_sendimage, "Sends images to channels supporting it", usage_sendimage , 0 },
1629         { { "send", "text", NULL }, handle_sendtext, "Sends text to channels supporting it", usage_sendtext , 0 },
1630         { { "set", "autohangup", NULL }, handle_autohangup, "Autohangup channel in some time", usage_autohangup , 0 },
1631         { { "set", "callerid", NULL }, handle_setcallerid, "Sets callerid for the current channel", usage_setcallerid , 0 },
1632         { { "set", "context", NULL }, handle_setcontext, "Sets channel context", usage_setcontext , 0 },
1633         { { "set", "extension", NULL }, handle_setextension, "Changes channel extension", usage_setextension , 0 },
1634         { { "set", "music", NULL }, handle_setmusic, "Enable/Disable Music on hold generator", usage_setmusic , 0 },
1635         { { "set", "priority", NULL }, handle_setpriority, "Set channel dialplan priority", usage_setpriority , 0 },
1636         { { "set", "variable", NULL }, handle_setvariable, "Sets a channel variable", usage_setvariable , 1 },
1637         { { "stream", "file", NULL }, handle_streamfile, "Sends audio file on channel", usage_streamfile , 0 },
1638         { { "control", "stream", "file", NULL }, handle_controlstreamfile, "Sends audio file on channel and allows the listner to control the stream", usage_controlstreamfile , 0 },
1639         { { "tdd", "mode", NULL }, handle_tddmode, "Toggles TDD mode (for the deaf)", usage_tddmode , 0 },
1640         { { "verbose", NULL }, handle_verbose, "Logs a message to the asterisk verbose log", usage_verbose , 1 },
1641         { { "wait", "for", "digit", NULL }, handle_waitfordigit, "Waits for a digit to be pressed", usage_waitfordigit , 0 },
1642 };
1643
1644 static AST_RWLIST_HEAD_STATIC(agi_commands, agi_command);
1645
1646 static char *help_workhorse(int fd, char *match[])
1647 {
1648         char fullcmd[80], matchstr[80];
1649         struct agi_command *e;
1650
1651         if (match)
1652                 ast_join(matchstr, sizeof(matchstr), match);
1653
1654         ast_cli(fd, "%5.5s %20.20s   %s\n","Dead","Command","Description");
1655         AST_RWLIST_RDLOCK(&agi_commands);
1656         AST_RWLIST_TRAVERSE(&agi_commands, e, list) {
1657                 if (!e->cmda[0])
1658                         break;
1659                 /* Hide commands that start with '_' */
1660                 if ((e->cmda[0])[0] == '_')
1661                         continue;
1662                 ast_join(fullcmd, sizeof(fullcmd), e->cmda);
1663                 if (match && strncasecmp(matchstr, fullcmd, strlen(matchstr)))
1664                         continue;
1665                 ast_cli(fd, "%5.5s %20.20s   %s\n", e->dead ? "Yes" : "No" , fullcmd, e->summary);
1666         }
1667         AST_RWLIST_UNLOCK(&agi_commands);
1668
1669         return CLI_SUCCESS;
1670 }
1671
1672 int ast_agi_register(struct ast_module *mod, agi_command *cmd)
1673 {
1674         char fullcmd[80];
1675
1676         ast_join(fullcmd, sizeof(fullcmd), cmd->cmda);
1677
1678         if (!find_command(cmd->cmda,1)) {
1679                 cmd->mod = mod;
1680                 AST_RWLIST_WRLOCK(&agi_commands);
1681                 AST_LIST_INSERT_TAIL(&agi_commands, cmd, list);
1682                 AST_RWLIST_UNLOCK(&agi_commands);
1683                 if (mod != ast_module_info->self)
1684                         ast_module_ref(ast_module_info->self);
1685                 ast_verb(2, "AGI Command '%s' registered\n",fullcmd);
1686                 return 1;
1687         } else {
1688                 ast_log(LOG_WARNING, "Command already registered!\n");
1689                 return 0;
1690         }
1691 }
1692
1693 int ast_agi_unregister(struct ast_module *mod, agi_command *cmd)
1694 {
1695         struct agi_command *e;
1696         int unregistered = 0;
1697         char fullcmd[80];
1698         
1699         ast_join(fullcmd, sizeof(fullcmd), cmd->cmda);
1700
1701         AST_RWLIST_WRLOCK(&agi_commands);
1702         AST_RWLIST_TRAVERSE_SAFE_BEGIN(&agi_commands, e, list) {
1703                 if (cmd == e) {
1704                         AST_RWLIST_REMOVE_CURRENT(list);
1705                         if (mod != ast_module_info->self)
1706                                 ast_module_unref(ast_module_info->self);
1707                         unregistered=1;
1708                         break;
1709                 }
1710         }
1711         AST_RWLIST_TRAVERSE_SAFE_END;
1712         AST_RWLIST_UNLOCK(&agi_commands);
1713         if (unregistered)
1714                 ast_verb(2, "AGI Command '%s' unregistered\n",fullcmd);
1715         else
1716                 ast_log(LOG_WARNING, "Unable to unregister command: '%s'!\n",fullcmd);
1717         return unregistered;
1718 }
1719
1720 void ast_agi_register_multiple(struct ast_module *mod, agi_command *cmd, int len)
1721 {
1722         int i;
1723
1724         for (i = 0; i < len; i++)
1725                 ast_agi_register(mod, cmd + i);
1726
1727 }
1728
1729 void ast_agi_unregister_multiple(struct ast_module *mod, agi_command *cmd, int len)
1730 {
1731         int i;
1732
1733         for (i = 0; i < len; i++)
1734                 ast_agi_unregister(mod, cmd + i);
1735 }
1736
1737 static agi_command *find_command(char *cmds[], int exact)
1738 {
1739         int y, match;
1740         struct agi_command *e;
1741
1742         AST_RWLIST_RDLOCK(&agi_commands);
1743         AST_RWLIST_TRAVERSE(&agi_commands, e, list) {
1744                 if (!e->cmda[0])
1745                         break;
1746                 /* start optimistic */
1747                 match = 1;
1748                 for (y = 0; match && cmds[y]; y++) {
1749                         /* If there are no more words in the command (and we're looking for
1750                            an exact match) or there is a difference between the two words,
1751                            then this is not a match */
1752                         if (!e->cmda[y] && !exact)
1753                                 break;
1754                         /* don't segfault if the next part of a command doesn't exist */
1755                         if (!e->cmda[y])
1756                                 return NULL;
1757                         if (strcasecmp(e->cmda[y], cmds[y]))
1758                                 match = 0;
1759                 }
1760                 /* If more words are needed to complete the command then this is not
1761                    a candidate (unless we're looking for a really inexact answer  */
1762                 if ((exact > -1) && e->cmda[y])
1763                         match = 0;
1764                 if (match)
1765                         return e;
1766         }
1767         AST_RWLIST_UNLOCK(&agi_commands);
1768         return NULL;
1769 }
1770
1771 static int parse_args(char *s, int *max, char *argv[])
1772 {
1773         int x = 0, quoted = 0, escaped = 0, whitespace = 1;
1774         char *cur;
1775
1776         cur = s;
1777         while(*s) {
1778                 switch(*s) {
1779                 case '"':
1780                         /* If it's escaped, put a literal quote */
1781                         if (escaped) 
1782                                 goto normal;
1783                         else 
1784                                 quoted = !quoted;
1785                         if (quoted && whitespace) {
1786                                 /* If we're starting a quote, coming off white space start a new word, too */
1787                                 argv[x++] = cur;
1788                                 whitespace=0;
1789                         }
1790                         escaped = 0;
1791                 break;
1792                 case ' ':
1793                 case '\t':
1794                         if (!quoted && !escaped) {
1795                                 /* If we're not quoted, mark this as whitespace, and
1796                                    end the previous argument */
1797                                 whitespace = 1;
1798                                 *(cur++) = '\0';
1799                         } else
1800                                 /* Otherwise, just treat it as anything else */ 
1801                                 goto normal;
1802                         break;
1803                 case '\\':
1804                         /* If we're escaped, print a literal, otherwise enable escaping */
1805                         if (escaped) {
1806                                 goto normal;
1807                         } else {
1808                                 escaped=1;
1809                         }
1810                         break;
1811                 default:
1812 normal:
1813                         if (whitespace) {
1814                                 if (x >= MAX_ARGS -1) {
1815                                         ast_log(LOG_WARNING, "Too many arguments, truncating\n");
1816                                         break;
1817                                 }
1818                                 /* Coming off of whitespace, start the next argument */
1819                                 argv[x++] = cur;
1820                                 whitespace=0;
1821                         }
1822                         *(cur++) = *s;
1823                         escaped=0;
1824                 }
1825                 s++;
1826         }
1827         /* Null terminate */
1828         *(cur++) = '\0';
1829         argv[x] = NULL;
1830         *max = x;
1831         return 0;
1832 }
1833
1834 static int agi_handle_command(struct ast_channel *chan, AGI *agi, char *buf, int dead)
1835 {
1836         char *argv[MAX_ARGS];
1837         int argc = MAX_ARGS, res;
1838         agi_command *c;
1839
1840         parse_args(buf, &argc, argv);
1841         if ((c = find_command(argv, 0)) && (!dead || (dead && c->dead))) {
1842                 /* if this command wasnt registered by res_agi, be sure to usecount
1843                 the module we are using */
1844                 if (c->mod != ast_module_info->self)
1845                         ast_module_ref(c->mod);
1846                 res = c->handler(chan, agi, argc, argv);
1847                 if (c->mod != ast_module_info->self)
1848                         ast_module_unref(c->mod);
1849                 switch(res) {
1850                 case RESULT_SHOWUSAGE:
1851                         ast_agi_fdprintf(chan, agi->fd, "520-Invalid command syntax.  Proper usage follows:\n");
1852                         ast_agi_fdprintf(chan, agi->fd, c->usage);
1853                         ast_agi_fdprintf(chan, agi->fd, "520 End of proper usage.\n");
1854                         break;
1855                 case AST_PBX_KEEPALIVE:
1856                         /* We've been asked to keep alive, so do so */
1857                         return AST_PBX_KEEPALIVE;
1858                         break;
1859                 case RESULT_FAILURE:
1860                         /* They've already given the failure.  We've been hung up on so handle this
1861                            appropriately */
1862                         return -1;
1863                 }
1864         } else if ((c = find_command(argv, 0))) {
1865                 ast_agi_fdprintf(chan, agi->fd, "511 Command Not Permitted on a dead channel\n");
1866         } else {
1867                 ast_agi_fdprintf(chan, agi->fd, "510 Invalid or unknown command\n");
1868         }
1869         return 0;
1870 }
1871 static enum agi_result run_agi(struct ast_channel *chan, char *request, AGI *agi, int pid, int *status, int dead, int argc, char *argv[])
1872 {
1873         struct ast_channel *c;
1874         int outfd, ms, needhup = 0;
1875         enum agi_result returnstatus = AGI_RESULT_SUCCESS;
1876         struct ast_frame *f;
1877         char buf[AGI_BUF_LEN];
1878         char *res = NULL;
1879         FILE *readf;
1880         /* how many times we'll retry if ast_waitfor_nandfs will return without either 
1881           channel or file descriptor in case select is interrupted by a system call (EINTR) */
1882         int retry = AGI_NANDFS_RETRY;
1883
1884         if (!(readf = fdopen(agi->ctrl, "r"))) {
1885                 ast_log(LOG_WARNING, "Unable to fdopen file descriptor\n");
1886                 if (pid > -1)
1887                         kill(pid, SIGHUP);
1888                 close(agi->ctrl);
1889                 return AGI_RESULT_FAILURE;
1890         }
1891         setlinebuf(readf);
1892         setup_env(chan, request, agi->fd, (agi->audio > -1), argc, argv);
1893         for (;;) {
1894                 if (needhup) {
1895                         needhup = 0;
1896                         dead = 1;
1897                         kill(pid, SIGHUP);
1898                 }
1899                 ms = -1;
1900                 c = ast_waitfor_nandfds(&chan, dead ? 0 : 1, &agi->ctrl, 1, NULL, &outfd, &ms);
1901                 if (c) {
1902                         retry = AGI_NANDFS_RETRY;
1903                         /* Idle the channel until we get a command */
1904                         f = ast_read(c);
1905                         if (!f) {
1906                                 ast_debug(1, "%s hungup\n", chan->name);
1907                                 returnstatus = AGI_RESULT_HANGUP;
1908                                 needhup = 1;
1909                                 continue;
1910                         } else {
1911                                 /* If it's voice, write it to the audio pipe */
1912                                 if ((agi->audio > -1) && (f->frametype == AST_FRAME_VOICE)) {
1913                                         /* Write, ignoring errors */
1914                                         write(agi->audio, f->data, f->datalen);
1915                                 }
1916                                 ast_frfree(f);
1917                         }
1918                 } else if (outfd > -1) {
1919                         size_t len = sizeof(buf);
1920                         size_t buflen = 0;
1921
1922                         retry = AGI_NANDFS_RETRY;
1923                         buf[0] = '\0';
1924
1925                         while (buflen < (len - 1)) {
1926                                 res = fgets(buf + buflen, len, readf);
1927                                 if (feof(readf)) 
1928                                         break;
1929                                 if (ferror(readf) && ((errno != EINTR) && (errno != EAGAIN))) 
1930                                         break;
1931                                 if (res != NULL && !agi->fast)
1932                                         break;
1933                                 buflen = strlen(buf);
1934                                 if (buflen && buf[buflen - 1] == '\n')
1935                                         break;
1936                                 len -= buflen;
1937                                 if (agidebug)
1938                                         ast_verbose( "AGI Rx << temp buffer %s - errno %s\n", buf, strerror(errno));
1939                         }
1940
1941                         if (!buf[0]) {
1942                                 /* Program terminated */
1943                                 if (returnstatus && returnstatus != AST_PBX_KEEPALIVE)
1944                                         returnstatus = -1;
1945                                 ast_verb(3, "<%s>AGI Script %s completed, returning %d\n", chan->name, request, returnstatus);
1946                                 if (pid > 0)
1947                                         waitpid(pid, status, 0);
1948                                 /* No need to kill the pid anymore, since they closed us */
1949                                 pid = -1;
1950                                 break;
1951                         }
1952
1953                         /* get rid of trailing newline, if any */
1954                         if (*buf && buf[strlen(buf) - 1] == '\n')
1955                                 buf[strlen(buf) - 1] = 0;
1956                         if (agidebug)
1957                                 ast_verbose("<%s>AGI Rx << %s\n", chan->name, buf);
1958                         returnstatus |= agi_handle_command(chan, agi, buf, dead);
1959                         /* If the handle_command returns -1, we need to stop */
1960                         if ((returnstatus < 0) || (returnstatus == AST_PBX_KEEPALIVE)) {
1961                                 needhup = 1;
1962                                 continue;
1963                         }
1964                 } else {
1965                         if (--retry <= 0) {
1966                                 ast_log(LOG_WARNING, "No channel, no fd?\n");
1967                                 returnstatus = AGI_RESULT_FAILURE;
1968                                 break;
1969                         }
1970                 }
1971         }
1972         /* Notify process */
1973         if (pid > -1) {
1974                 const char *sighup = pbx_builtin_getvar_helper(chan, "AGISIGHUP");
1975                 if (ast_strlen_zero(sighup) || !ast_false(sighup)) {
1976                         if (kill(pid, SIGHUP))
1977                                 ast_log(LOG_WARNING, "unable to send SIGHUP to AGI process %d: %s\n", pid, strerror(errno));
1978                 }
1979         }
1980         fclose(readf);
1981         return returnstatus;
1982 }
1983
1984 static char *handle_cli_agi_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1985 {
1986         struct agi_command *command;
1987         char fullcmd[80];
1988
1989         switch (cmd) {
1990         case CLI_INIT:
1991                 e->command = "agi show";
1992                 e->usage =
1993                         "Usage: agi show [topic]\n"
1994                         "       When called with a topic as an argument, displays usage\n"
1995                         "       information on the given command.  If called without a\n"
1996                         "       topic, it provides a list of AGI commands.\n";
1997                 break;
1998         case CLI_GENERATE:
1999                 return NULL;
2000         }
2001         if (a->argc < e->args)
2002                 return CLI_SHOWUSAGE;
2003         if (a->argc > e->args) {
2004                 command = find_command(a->argv + e->args, 1);
2005                 if (command) {
2006                         ast_cli(a->fd, command->usage);
2007                         ast_cli(a->fd, " Runs Dead : %s\n", command->dead ? "Yes" : "No");
2008                 } else {
2009                         if (find_command(a->argv + e->args, -1)) {
2010                                 return help_workhorse(a->fd, a->argv + e->args);
2011                         } else {
2012                                 ast_join(fullcmd, sizeof(fullcmd), a->argv + e->args);
2013                                 ast_cli(a->fd, "No such command '%s'.\n", fullcmd);
2014                         }
2015                 }
2016         } else {
2017                 return help_workhorse(a->fd, NULL);
2018         }
2019         return CLI_SUCCESS;
2020 }
2021
2022 /*! \brief Convert string to use HTML escaped characters
2023         \note Maybe this should be a generic function?
2024 */
2025 static void write_html_escaped(FILE *htmlfile, char *str)
2026 {
2027         char *cur = str;
2028
2029         while(*cur) {
2030                 switch (*cur) {
2031                 case '<':
2032                         fprintf(htmlfile, "%s", "&lt;");
2033                         break;
2034                 case '>':
2035                         fprintf(htmlfile, "%s", "&gt;");
2036                         break;
2037                 case '&':
2038                         fprintf(htmlfile, "%s", "&amp;");
2039                         break;
2040                 case '"':
2041                         fprintf(htmlfile, "%s", "&quot;");
2042                         break;
2043                 default:
2044                         fprintf(htmlfile, "%c", *cur);
2045                         break;
2046                 }
2047                 cur++;
2048         }
2049
2050         return;
2051 }
2052
2053 static char *handle_cli_agi_dumphtml(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2054 {
2055         struct agi_command *command;
2056         char fullcmd[80];
2057         FILE *htmlfile;
2058
2059         switch (cmd) {
2060         case CLI_INIT:
2061                 e->command = "agi dumphtml";
2062                 e->usage =
2063                         "Usage: agi dumphtml <filename>\n"
2064                         "       Dumps the AGI command list in HTML format to the given\n"
2065                         "       file.\n";
2066                 return NULL;
2067         case CLI_GENERATE:
2068                 return NULL;
2069         }
2070         if (a->argc < e->args + 1)
2071                 return CLI_SHOWUSAGE;
2072
2073         if (!(htmlfile = fopen(a->argv[2], "wt"))) {
2074                 ast_cli(a->fd, "Could not create file '%s'\n", a->argv[2]);
2075                 return CLI_SHOWUSAGE;
2076         }
2077
2078         fprintf(htmlfile, "<HTML>\n<HEAD>\n<TITLE>AGI Commands</TITLE>\n</HEAD>\n");
2079         fprintf(htmlfile, "<BODY>\n<CENTER><B><H1>AGI Commands</H1></B></CENTER>\n\n");
2080         fprintf(htmlfile, "<TABLE BORDER=\"0\" CELLSPACING=\"10\">\n");
2081
2082         AST_RWLIST_RDLOCK(&agi_commands);
2083         AST_RWLIST_TRAVERSE(&agi_commands, command, list) {
2084                 char *stringp, *tempstr;
2085  
2086                 if (!command->cmda[0])  /* end ? */
2087                         break;
2088                 /* Hide commands that start with '_' */
2089                 if ((command->cmda[0])[0] == '_')
2090                         continue;
2091                 ast_join(fullcmd, sizeof(fullcmd), command->cmda);
2092
2093                 fprintf(htmlfile, "<TR><TD><TABLE BORDER=\"1\" CELLPADDING=\"5\" WIDTH=\"100%%\">\n");
2094                 fprintf(htmlfile, "<TR><TH ALIGN=\"CENTER\"><B>%s - %s</B></TH></TR>\n", fullcmd, command->summary);
2095
2096                 stringp = command->usage;
2097                 tempstr = strsep(&stringp, "\n");
2098
2099                 fprintf(htmlfile, "<TR><TD ALIGN=\"CENTER\">");
2100                 write_html_escaped(htmlfile, tempstr);
2101                 fprintf(htmlfile, "</TD></TR>\n");
2102                 fprintf(htmlfile, "<TR><TD ALIGN=\"CENTER\">\n");
2103
2104                 while ((tempstr = strsep(&stringp, "\n")) != NULL) {
2105                         write_html_escaped(htmlfile, tempstr);
2106                         fprintf(htmlfile, "<BR>\n");
2107                 }
2108                 fprintf(htmlfile, "</TD></TR>\n");
2109                 fprintf(htmlfile, "</TABLE></TD></TR>\n\n");
2110         }
2111         AST_RWLIST_UNLOCK(&agi_commands);
2112         fprintf(htmlfile, "</TABLE>\n</BODY>\n</HTML>\n");
2113         fclose(htmlfile);
2114         ast_cli(a->fd, "AGI HTML commands dumped to: %s\n", a->argv[2]);
2115         return CLI_SUCCESS;
2116 }
2117
2118 static int agi_exec_full(struct ast_channel *chan, void *data, int enhanced, int dead)
2119 {
2120         enum agi_result res;
2121         struct ast_module_user *u;
2122         char buf[AGI_BUF_LEN] = "", *tmp = buf;
2123         int fds[2], efd = -1, pid;
2124         AST_DECLARE_APP_ARGS(args,
2125                 AST_APP_ARG(arg)[MAX_ARGS];
2126         );
2127         AGI agi;
2128
2129         if (ast_strlen_zero(data)) {
2130                 ast_log(LOG_WARNING, "AGI requires an argument (script)\n");
2131                 return -1;
2132         }
2133         if (dead)
2134                 ast_log(LOG_NOTICE, "Hungup channel detected, running agi in dead mode.");
2135         ast_copy_string(buf, data, sizeof(buf));
2136         memset(&agi, 0, sizeof(agi));
2137         AST_STANDARD_APP_ARGS(args, tmp);
2138         args.argv[args.argc] = NULL;
2139
2140         u = ast_module_user_add(chan);
2141 #if 0
2142          /* Answer if need be */
2143         if (chan->_state != AST_STATE_UP) {
2144                 if (ast_answer(chan)) {
2145                         LOCAL_USER_REMOVE(u);
2146                         return -1;
2147                 }
2148         }
2149 #endif
2150         res = launch_script(args.argv[0], args.argv, fds, enhanced ? &efd : NULL, &pid);
2151         if (res == AGI_RESULT_SUCCESS || res == AGI_RESULT_SUCCESS_FAST) {
2152                 int status = 0;
2153                 agi.fd = fds[1];
2154                 agi.ctrl = fds[0];
2155                 agi.audio = efd;
2156                 agi.fast = (res == AGI_RESULT_SUCCESS_FAST) ? 1 : 0;
2157                 res = run_agi(chan, args.argv[0], &agi, pid, &status, dead, args.argc, args.argv);
2158                 /* If the fork'd process returns non-zero, set AGISTATUS to FAILURE */
2159                 if ((res == AGI_RESULT_SUCCESS || res == AGI_RESULT_SUCCESS_FAST) && status)
2160                         res = AGI_RESULT_FAILURE;
2161                 if (fds[1] != fds[0])
2162                         close(fds[1]);
2163                 if (efd > -1)
2164                         close(efd);
2165                 ast_unreplace_sigchld();
2166         }
2167         ast_module_user_remove(u);
2168
2169         switch (res) {
2170         case AGI_RESULT_SUCCESS:
2171         case AGI_RESULT_SUCCESS_FAST:
2172                 pbx_builtin_setvar_helper(chan, "AGISTATUS", "SUCCESS");
2173                 break;
2174         case AGI_RESULT_FAILURE:
2175                 pbx_builtin_setvar_helper(chan, "AGISTATUS", "FAILURE");
2176                 break;
2177         case AGI_RESULT_NOTFOUND:
2178                 pbx_builtin_setvar_helper(chan, "AGISTATUS", "NOTFOUND");
2179                 break;
2180         case AGI_RESULT_HANGUP:
2181                 pbx_builtin_setvar_helper(chan, "AGISTATUS", "HANGUP");
2182                 return -1;
2183         }
2184
2185         return 0;
2186 }
2187
2188 static int agi_exec(struct ast_channel *chan, void *data)
2189 {
2190         if (!ast_check_hangup(chan))
2191                 return agi_exec_full(chan, data, 0, 0);
2192         else
2193                 return agi_exec_full(chan, data, 0, 1);
2194 }
2195
2196 static int eagi_exec(struct ast_channel *chan, void *data)
2197 {
2198         int readformat, res;
2199
2200         if (ast_check_hangup(chan)) {
2201                 ast_log(LOG_ERROR, "If you want to run AGI on hungup channels you should use DeadAGI!\n");
2202                 return 0;
2203         }
2204         readformat = chan->readformat;
2205         if (ast_set_read_format(chan, AST_FORMAT_SLINEAR)) {
2206                 ast_log(LOG_WARNING, "Unable to set channel '%s' to linear mode\n", chan->name);
2207                 return -1;
2208         }
2209         res = agi_exec_full(chan, data, 1, 0);
2210         if (!res) {
2211                 if (ast_set_read_format(chan, readformat)) {
2212                         ast_log(LOG_WARNING, "Unable to restore channel '%s' to format %s\n", chan->name, ast_getformatname(readformat));
2213                 }
2214         }
2215         return res;
2216 }
2217
2218 static int deadagi_exec(struct ast_channel *chan, void *data)
2219 {
2220         ast_log(LOG_WARNING, "DeadAGI has been deprecated, please use AGI in all cases!");
2221         return agi_exec(chan, data);
2222 }
2223
2224 static struct ast_cli_entry cli_agi[] = {
2225         AST_CLI_DEFINE(handle_cli_agi_debug,    "Enable/Disable AGI debugging"),
2226         AST_CLI_DEFINE(handle_cli_agi_show,     "List AGI commands or specific help"),
2227         AST_CLI_DEFINE(handle_cli_agi_dumphtml, "Dumps a list of AGI commands in HTML format")
2228 };
2229
2230 static int unload_module(void)
2231 {
2232         ast_cli_unregister_multiple(cli_agi, sizeof(cli_agi) / sizeof(struct ast_cli_entry));
2233         ast_agi_unregister_multiple(ast_module_info->self, commands, sizeof(commands) / sizeof(struct agi_command));
2234         ast_unregister_application(eapp);
2235         ast_unregister_application(deadapp);
2236         return ast_unregister_application(app);
2237 }
2238
2239 static int load_module(void)
2240 {
2241         ast_cli_register_multiple(cli_agi, sizeof(cli_agi) / sizeof(struct ast_cli_entry));
2242         ast_agi_register_multiple(ast_module_info->self, commands, sizeof(commands) / sizeof(struct agi_command));
2243         ast_register_application(deadapp, deadagi_exec, deadsynopsis, descrip);
2244         ast_register_application(eapp, eagi_exec, esynopsis, descrip);
2245         return ast_register_application(app, agi_exec, synopsis, descrip);
2246 }
2247
2248 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS, "Asterisk Gateway Interface (AGI)",
2249                 .load = load_module,
2250                 .unload = unload_module,
2251                 );