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