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