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