b78d923ae9b8be82114e704e49fbcd82e683cd27
[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 <netdb.h>
15 #include <sys/socket.h>
16 #include <netinet/in.h>
17 #include <netinet/tcp.h>
18 #include <arpa/inet.h>
19 #include <sys/types.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 <sys/socket.h>
38 #include <asterisk/cli.h>
39 #include <asterisk/logger.h>
40 #include <asterisk/options.h>
41 #include <asterisk/image.h>
42 #include <asterisk/say.h>
43 #include <asterisk/app.h>
44 #include <asterisk/dsp.h>
45 #include <asterisk/musiconhold.h>
46 #include <asterisk/manager.h>
47 #include <asterisk/utils.h>
48 #include <asterisk/lock.h>
49 #include <asterisk/agi.h>
50 #include "../asterisk.h"
51 #include "../astconf.h"
52
53 #define MAX_ARGS 128
54 #define MAX_COMMANDS 128
55
56 /* Recycle some stuff from the CLI interface */
57 #define fdprintf agi_debug_cli
58
59 static char *tdesc = "Asterisk Gateway Interface (AGI)";
60
61 static char *app = "AGI";
62
63 static char *eapp = "EAGI";
64
65 static char *deadapp = "DeadAGI";
66
67 static char *synopsis = "Executes an AGI compliant application";
68 static char *esynopsis = "Executes an EAGI compliant application";
69 static char *deadsynopsis = "Executes AGI on a hungup channel";
70
71 static char *descrip =
72 "  [E|Dead]AGI(command|args): Executes an Asterisk Gateway Interface compliant\n"
73 "program on a channel. AGI allows Asterisk to launch external programs\n"
74 "written in any language to control a telephony channel, play audio,\n"
75 "read DTMF digits, etc. by communicating with the AGI protocol on stdin\n"
76 "and stdout.\n"
77 "Returns -1 on hangup (except for DeadAGI) or if application requested\n"
78 " hangup, or 0 on non-hangup exit. \n"
79 "Using 'EAGI' provides enhanced AGI, with incoming audio available out of band"
80 "on file descriptor 3\n\n"
81 "Use the CLI command 'show agi' to list available agi commands\n";
82
83 static int agidebug = 0;
84
85 STANDARD_LOCAL_USER;
86
87 LOCAL_USER_DECL;
88
89
90 #define TONE_BLOCK_SIZE 200
91
92 /* Max time to connect to an AGI remote host */
93 #define MAX_AGI_CONNECT 2000
94
95 #define AGI_PORT 4573
96
97 static void agi_debug_cli(int fd, char *fmt, ...)
98 {
99         char *stuff;
100         int res = 0;
101
102         va_list ap;
103         va_start(ap, fmt);
104         res = vasprintf(&stuff, fmt, ap);
105         va_end(ap);
106         if (res == -1) {
107                 ast_log(LOG_ERROR, "Out of memory\n");
108         } else {
109                 if (agidebug)
110                         ast_verbose("AGI Tx >> %s", stuff);
111                 ast_carefulwrite(fd, stuff, strlen(stuff), 100);
112                 free(stuff);
113         }
114 }
115
116 static int launch_netscript(char *agiurl, char *argv[], int *fds, int *efd, int *opid)
117 {
118         int s;
119         int flags;
120         struct pollfd pfds[1];
121         char *host;
122         char *c; int port = AGI_PORT;
123         char *script;
124         struct sockaddr_in sin;
125         struct hostent *hp;
126         struct ast_hostent ahp;
127         ast_log(LOG_DEBUG, "Blah\n");
128         host = ast_strdupa(agiurl + 6);
129         if (!host)
130                 return -1;
131         /* Strip off any script name */
132         if ((c = strchr(host, '/'))) {
133                 *c = '\0';
134                 c++;
135                 script = c;
136         }
137         if ((c = strchr(host, ':'))) {
138                 *c = '\0';
139                 c++;
140                 port = atoi(c + 1);
141         }
142         if (efd) {
143                 ast_log(LOG_WARNING, "AGI URI's don't support Enhanced AGI yet\n");
144                 return -1;
145         }
146         hp = ast_gethostbyname(host, &ahp);
147         if (!hp) {
148                 ast_log(LOG_WARNING, "Unable to locate host '%s'\n", host);
149                 return -1;
150         }
151         s = socket(AF_INET, SOCK_STREAM, 0);
152         if (s < 0) {
153                 ast_log(LOG_WARNING, "Unable to create socket: %s\n", strerror(errno));
154                 return -1;
155         }
156         flags = fcntl(s, F_GETFL);
157         if (flags < 0) {
158                 ast_log(LOG_WARNING, "Fcntl(F_GETFL) failed: %s\n", strerror(errno));
159                 close(s);
160                 return -1;
161         }
162         if (fcntl(s, F_SETFL, flags | O_NONBLOCK) < 0) {
163                 ast_log(LOG_WARNING, "Fnctl(F_SETFL) failed: %s\n", strerror(errno));
164                 close(s);
165                 return -1;
166         }
167         memset(&sin, 0, sizeof(sin));
168         sin.sin_family = AF_INET;
169         sin.sin_port = htons(port);
170         memcpy(&sin.sin_addr, hp->h_addr, sizeof(sin.sin_addr));
171         if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) && (errno != EINPROGRESS)) {
172                 ast_log(LOG_WARNING, "Connect failed with unexpected error: %s\n", strerror(errno));
173                 close(s);
174                 return -1;
175         }
176         pfds[0].fd = s;
177         pfds[0].events = POLLOUT;
178         if (poll(pfds, 1, MAX_AGI_CONNECT) != 1) {
179                 ast_log(LOG_WARNING, "Connect to '%s' failed!\n", agiurl);
180                 close(s);
181                 return -1;
182         }
183         if (write(s, "agi_network: yes\n", strlen("agi_network: yes\n")) < 0) {
184                 ast_log(LOG_WARNING, "Connect to '%s' failed: %s\n", agiurl, strerror(errno));
185                 close(s);
186                 return -1;
187         }
188         ast_log(LOG_DEBUG, "Wow, connected!\n");
189         fds[0] = s;
190         fds[1] = s;
191         *opid = -1;
192         return 0;
193 }
194
195 static int launch_script(char *script, char *argv[], int *fds, int *efd, int *opid)
196 {
197         char tmp[256];
198         int pid;
199         int toast[2];
200         int fromast[2];
201         int audio[2];
202         int x;
203         int res;
204         
205         if (!strncasecmp(script, "agi://", 6))
206                 return launch_netscript(script, argv, fds, efd, opid);
207         
208         if (script[0] != '/') {
209                 snprintf(tmp, sizeof(tmp), "%s/%s", (char *)ast_config_AST_AGI_DIR, script);
210                 script = tmp;
211         }
212         if (pipe(toast)) {
213                 ast_log(LOG_WARNING, "Unable to create toast pipe: %s\n",strerror(errno));
214                 return -1;
215         }
216         if (pipe(fromast)) {
217                 ast_log(LOG_WARNING, "unable to create fromast pipe: %s\n", strerror(errno));
218                 close(toast[0]);
219                 close(toast[1]);
220                 return -1;
221         }
222         if (efd) {
223                 if (pipe(audio)) {
224                         ast_log(LOG_WARNING, "unable to create audio pipe: %s\n", strerror(errno));
225                         close(fromast[0]);
226                         close(fromast[1]);
227                         close(toast[0]);
228                         close(toast[1]);
229                         return -1;
230                 }
231                 res = fcntl(audio[1], F_GETFL);
232                 if (res > -1) 
233                         res = fcntl(audio[1], F_SETFL, res | O_NONBLOCK);
234                 if (res < 0) {
235                         ast_log(LOG_WARNING, "unable to set audio pipe parameters: %s\n", strerror(errno));
236                         close(fromast[0]);
237                         close(fromast[1]);
238                         close(toast[0]);
239                         close(toast[1]);
240                         close(audio[0]);
241                         close(audio[1]);
242                         return -1;
243                 }
244         }
245         pid = fork();
246         if (pid < 0) {
247                 ast_log(LOG_WARNING, "Failed to fork(): %s\n", strerror(errno));
248                 return -1;
249         }
250         if (!pid) {
251                 /* Redirect stdin and out, provide enhanced audio channel if desired */
252                 dup2(fromast[0], STDIN_FILENO);
253                 dup2(toast[1], STDOUT_FILENO);
254                 if (efd) {
255                         dup2(audio[0], STDERR_FILENO + 1);
256                 } else {
257                         close(STDERR_FILENO + 1);
258                 }
259                 /* Close everything but stdin/out/error */
260                 for (x=STDERR_FILENO + 2;x<1024;x++) 
261                         close(x);
262                 /* Execute script */
263                 execv(script, argv);
264                 /* Can't use ast_log since FD's are closed */
265                 fprintf(stderr, "Failed to execute '%s': %s\n", script, strerror(errno));
266                 exit(1);
267         }
268         if (option_verbose > 2) 
269                 ast_verbose(VERBOSE_PREFIX_3 "Launched AGI Script %s\n", script);
270         fds[0] = toast[0];
271         fds[1] = fromast[1];
272         if (efd) {
273                 *efd = audio[1];
274         }
275         /* close what we're not using in the parent */
276         close(toast[1]);
277         close(fromast[0]);
278
279         if (efd) {
280                 // [PHM 12/18/03]
281                 close(audio[0]);
282         }
283
284         *opid = pid;
285         return 0;
286                 
287 }
288
289 static void setup_env(struct ast_channel *chan, char *request, int fd, int enhanced)
290 {
291         /* Print initial environment, with agi_request always being the first
292            thing */
293         fdprintf(fd, "agi_request: %s\n", request);
294         fdprintf(fd, "agi_channel: %s\n", chan->name);
295         fdprintf(fd, "agi_language: %s\n", chan->language);
296         fdprintf(fd, "agi_type: %s\n", chan->type);
297         fdprintf(fd, "agi_uniqueid: %s\n", chan->uniqueid);
298
299         /* ANI/DNIS */
300         fdprintf(fd, "agi_callerid: %s\n", chan->callerid ? chan->callerid : "unknown");
301         fdprintf(fd, "agi_dnid: %s\n", chan->dnid ? chan->dnid : "unknown");
302         fdprintf(fd, "agi_rdnis: %s\n", chan->rdnis ? chan->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         if (argv[2])
842                 ast_set_callerid(chan, argv[2], 0);
843
844         fdprintf(agi->fd, "200 result=1\n");
845         return RESULT_SUCCESS;
846 }
847
848 static int handle_channelstatus(struct ast_channel *chan, AGI *agi, int argc, char **argv)
849 {
850         struct ast_channel *c;
851         if (argc==2) {
852                 /* no argument: supply info on the current channel */
853                 fdprintf(agi->fd, "200 result=%d\n", chan->_state);
854                 return RESULT_SUCCESS;
855         } else if (argc==3) {
856                 /* one argument: look for info on the specified channel */
857                 c = ast_channel_walk_locked(NULL);
858                 while (c) {
859                         if (strcasecmp(argv[2],c->name)==0) {
860                                 fdprintf(agi->fd, "200 result=%d\n", c->_state);
861                                 ast_mutex_unlock(&c->lock);
862                                 return RESULT_SUCCESS;
863                         }
864                         ast_mutex_unlock(&c->lock);
865                         c = ast_channel_walk_locked(c);
866                 }
867                 /* if we get this far no channel name matched the argument given */
868                 fdprintf(agi->fd, "200 result=-1\n");
869                 return RESULT_SUCCESS;
870         } else {
871                 return RESULT_SHOWUSAGE;
872         }
873 }
874
875 static int handle_setvariable(struct ast_channel *chan, AGI *agi, int argc, char **argv)
876 {
877         if (argv[3])
878                 pbx_builtin_setvar_helper(chan, argv[2], argv[3]);
879
880         fdprintf(agi->fd, "200 result=1\n");
881         return RESULT_SUCCESS;
882 }
883
884 static int handle_getvariable(struct ast_channel *chan, AGI *agi, int argc, char **argv)
885 {
886         char *tempstr;
887
888         if ((tempstr = pbx_builtin_getvar_helper(chan, argv[2]))) 
889                 fdprintf(agi->fd, "200 result=1 (%s)\n", tempstr);
890         else
891                 fdprintf(agi->fd, "200 result=0\n");
892
893         return RESULT_SUCCESS;
894 }
895
896 static int handle_verbose(struct ast_channel *chan, AGI *agi, int argc, char **argv)
897 {
898         int level = 0;
899         char *prefix;
900
901         if (argc < 2)
902                 return RESULT_SHOWUSAGE;
903
904         if (argv[2])
905                 sscanf(argv[2], "%d", &level);
906
907         switch (level) {
908                 case 4:
909                         prefix = VERBOSE_PREFIX_4;
910                         break;
911                 case 3:
912                         prefix = VERBOSE_PREFIX_3;
913                         break;
914                 case 2:
915                         prefix = VERBOSE_PREFIX_2;
916                         break;
917                 case 1:
918                 default:
919                         prefix = VERBOSE_PREFIX_1;
920                         break;
921         }
922
923         if (level <= option_verbose)
924                 ast_verbose("%s %s: %s\n", prefix, chan->data, argv[1]);
925         
926         fdprintf(agi->fd, "200 result=1\n");
927         
928         return RESULT_SUCCESS;
929 }
930
931 static int handle_dbget(struct ast_channel *chan, AGI *agi, int argc, char **argv)
932 {
933         int res;
934         char tmp[256];
935         if (argc != 4)
936                 return RESULT_SHOWUSAGE;
937         res = ast_db_get(argv[2], argv[3], tmp, sizeof(tmp));
938         if (res) 
939                 fdprintf(agi->fd, "200 result=0\n");
940         else
941                 fdprintf(agi->fd, "200 result=1 (%s)\n", tmp);
942
943         return RESULT_SUCCESS;
944 }
945
946 static int handle_dbput(struct ast_channel *chan, AGI *agi, int argc, char **argv)
947 {
948         int res;
949         if (argc != 5)
950                 return RESULT_SHOWUSAGE;
951         res = ast_db_put(argv[2], argv[3], argv[4]);
952         if (res) 
953                 fdprintf(agi->fd, "200 result=0\n");
954         else
955                 fdprintf(agi->fd, "200 result=1\n");
956
957         return RESULT_SUCCESS;
958 }
959
960 static int handle_dbdel(struct ast_channel *chan, AGI *agi, int argc, char **argv)
961 {
962         int res;
963         if (argc != 4)
964                 return RESULT_SHOWUSAGE;
965         res = ast_db_del(argv[2], argv[3]);
966         if (res) 
967                 fdprintf(agi->fd, "200 result=0\n");
968         else
969                 fdprintf(agi->fd, "200 result=1\n");
970
971         return RESULT_SUCCESS;
972 }
973
974 static int handle_dbdeltree(struct ast_channel *chan, AGI *agi, int argc, char **argv)
975 {
976         int res;
977         if ((argc < 3) || (argc > 4))
978                 return RESULT_SHOWUSAGE;
979         if (argc == 4)
980                 res = ast_db_deltree(argv[2], argv[3]);
981         else
982                 res = ast_db_deltree(argv[2], NULL);
983
984         if (res) 
985                 fdprintf(agi->fd, "200 result=0\n");
986         else
987                 fdprintf(agi->fd, "200 result=1\n");
988         return RESULT_SUCCESS;
989 }
990
991 static char debug_usage[] = 
992 "Usage: agi debug\n"
993 "       Enables dumping of AGI transactions for debugging purposes\n";
994
995 static char no_debug_usage[] = 
996 "Usage: agi no debug\n"
997 "       Disables dumping of AGI transactions for debugging purposes\n";
998
999 static int agi_do_debug(int fd, int argc, char *argv[])
1000 {
1001         if (argc != 2)
1002                 return RESULT_SHOWUSAGE;
1003         agidebug = 1;
1004         ast_cli(fd, "AGI Debugging Enabled\n");
1005         return RESULT_SUCCESS;
1006 }
1007
1008 static int agi_no_debug(int fd, int argc, char *argv[])
1009 {
1010         if (argc != 3)
1011                 return RESULT_SHOWUSAGE;
1012         agidebug = 0;
1013         ast_cli(fd, "AGI Debugging Disabled\n");
1014         return RESULT_SUCCESS;
1015 }
1016
1017 static struct ast_cli_entry  cli_debug =
1018         { { "agi", "debug", NULL }, agi_do_debug, "Enable AGI debugging", debug_usage };
1019
1020 static struct ast_cli_entry  cli_no_debug =
1021         { { "agi", "no", "debug", NULL }, agi_no_debug, "Disable AGI debugging", no_debug_usage };
1022
1023 static int handle_noop(struct ast_channel *chan, AGI *agi, int arg, char *argv[])
1024 {
1025         fdprintf(agi->fd, "200 result=0\n");
1026         return RESULT_SUCCESS;
1027 }
1028
1029 static int handle_setmusic(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
1030 {
1031         if (!strncasecmp(argv[2],"on",2)) {
1032                 if (argc > 3)
1033                         ast_moh_start(chan, argv[3]);
1034                 else
1035                         ast_moh_start(chan, NULL);
1036         }
1037         if (!strncasecmp(argv[2],"off",3)) {
1038                 ast_moh_stop(chan);
1039         }
1040         fdprintf(agi->fd, "200 result=0\n");
1041         return RESULT_SUCCESS;
1042 }
1043
1044 static char usage_setmusic[] =
1045 " Usage: SET MUSIC ON <on|off> <class>\n"
1046 "       Enables/Disables the music on hold generator.  If <class> is\n"
1047 " not specified then the default music on hold class will be used.\n"
1048 " Always returns 0\n";
1049
1050 static char usage_dbput[] =
1051 " Usage: DATABASE PUT <family> <key> <value>\n"
1052 "       Adds or updates an entry in the Asterisk database for a\n"
1053 " given family, key, and value.\n"
1054 " Returns 1 if succesful, 0 otherwise\n";
1055
1056 static char usage_dbget[] =
1057 " Usage: DATABASE GET <family> <key>\n"
1058 "       Retrieves an entry in the Asterisk database for a\n"
1059 " given family and key.\n"
1060 "       Returns 0 if <key> is not set.  Returns 1 if <key>\n"
1061 " is set and returns the variable in parenthesis\n"
1062 " example return code: 200 result=1 (testvariable)\n";
1063
1064 static char usage_dbdel[] =
1065 " Usage: DATABASE DEL <family> <key>\n"
1066 "       Deletes an entry in the Asterisk database for a\n"
1067 " given family and key.\n"
1068 " Returns 1 if succesful, 0 otherwise\n";
1069
1070 static char usage_dbdeltree[] =
1071 " Usage: DATABASE DELTREE <family> [keytree]\n"
1072 "       Deletes a family or specific keytree withing a family\n"
1073 " in the Asterisk database.\n"
1074 " Returns 1 if succesful, 0 otherwise\n";
1075
1076 static char usage_verbose[] =
1077 " Usage: VERBOSE <message> <level>\n"
1078 "       Sends <message> to the console via verbose message system.\n"
1079 "       <level> is the the verbose level (1-4)\n"
1080 "       Always returns 1\n";
1081
1082 static char usage_getvariable[] =
1083 " Usage: GET VARIABLE <variablename>\n"
1084 "       Returns 0 if <variablename> is not set.  Returns 1 if <variablename>\n"
1085 " is set and returns the variable in parenthesis\n"
1086 " example return code: 200 result=1 (testvariable)\n";
1087
1088 static char usage_setvariable[] =
1089 " Usage: SET VARIABLE <variablename> <value>\n";
1090
1091 static char usage_channelstatus[] =
1092 " Usage: CHANNEL STATUS [<channelname>]\n"
1093 "       Returns the status of the specified channel.\n" 
1094 "       If no channel name is given the returns the status of the\n"
1095 "       current channel.\n"
1096 "       Return values:\n"
1097 " 0 Channel is down and available\n"
1098 " 1 Channel is down, but reserved\n"
1099 " 2 Channel is off hook\n"
1100 " 3 Digits (or equivalent) have been dialed\n"
1101 " 4 Line is ringing\n"
1102 " 5 Remote end is ringing\n"
1103 " 6 Line is up\n"
1104 " 7 Line is busy\n";
1105
1106 static char usage_setcallerid[] =
1107 " Usage: SET CALLERID <number>\n"
1108 "       Changes the callerid of the current channel.\n";
1109
1110 static char usage_exec[] =
1111 " Usage: EXEC <application> <options>\n"
1112 "       Executes <application> with given <options>.\n"
1113 "       Returns whatever the application returns, or -2 on failure to find application\n";
1114
1115 static char usage_hangup[] =
1116 " Usage: HANGUP [<channelname>]\n"
1117 "       Hangs up the specified channel.\n"
1118 "       If no channel name is given, hangs up the current channel\n";
1119
1120 static char usage_answer[] = 
1121 " Usage: ANSWER\n"
1122 "        Answers channel if not already in answer state. Returns -1 on\n"
1123 " channel failure, or 0 if successful.\n";
1124
1125 static char usage_waitfordigit[] = 
1126 " Usage: WAIT FOR DIGIT <timeout>\n"
1127 "        Waits up to 'timeout' milliseconds for channel to receive a DTMF digit.\n"
1128 " Returns -1 on channel failure, 0 if no digit is received in the timeout, or\n"
1129 " the numerical value of the ascii of the digit if one is received.  Use -1\n"
1130 " for the timeout value if you desire the call to block indefinitely.\n";
1131
1132 static char usage_sendtext[] =
1133 " Usage: SEND TEXT \"<text to send>\"\n"
1134 "        Sends the given text on a channel.  Most channels do not support the\n"
1135 " transmission of text.  Returns 0 if text is sent, or if the channel does not\n"
1136 " support text transmission.  Returns -1 only on error/hangup.  Text\n"
1137 " consisting of greater than one word should be placed in quotes since the\n"
1138 " command only accepts a single argument.\n";
1139
1140 static char usage_recvchar[] =
1141 " Usage: RECEIVE CHAR <timeout>\n"
1142 "        Receives a character of text on a channel.  Specify timeout to be the\n"
1143 " maximum time to wait for input in milliseconds, or 0 for infinite. Most channels\n"
1144 " do not support the reception of text.  Returns the decimal value of the character\n"
1145 " if one is received, or 0 if the channel does not support text reception.  Returns\n"
1146 " -1 only on error/hangup.\n";
1147
1148 static char usage_tddmode[] =
1149 " Usage: TDD MODE <on|off>\n"
1150 "        Enable/Disable TDD transmission/reception on a channel. Returns 1 if\n"
1151 " successful, or 0 if channel is not TDD-capable.\n";
1152
1153 static char usage_sendimage[] =
1154 " Usage: SEND IMAGE <image>\n"
1155 "        Sends the given image on a channel.  Most channels do not support the\n"
1156 " transmission of images.  Returns 0 if image is sent, or if the channel does not\n"
1157 " support image transmission.  Returns -1 only on error/hangup.  Image names\n"
1158 " should not include extensions.\n";
1159
1160 static char usage_streamfile[] =
1161 " Usage: STREAM FILE <filename> <escape digits> [sample offset]\n"
1162 "        Send the given file, allowing playback to be interrupted by the given\n"
1163 " digits, if any.  Use double quotes for the digits if you wish none to be\n"
1164 " permitted.  If sample offset is provided then the audio will seek to sample\n"
1165 " offset before play starts.  Returns 0 if playback completes without a digit\n"
1166 " being pressed, or the ASCII numerical value of the digit if one was pressed,\n"
1167 " or -1 on error or if the channel was disconnected.  Remember, the file\n"
1168 " extension must not be included in the filename.\n";
1169
1170 static char usage_saynumber[] =
1171 " Usage: SAY NUMBER <number> <escape digits>\n"
1172 "        Say a given number, returning early if any of the given DTMF digits\n"
1173 " are received on the channel.  Returns 0 if playback completes without a digit\n"
1174 " being pressed, or the ASCII numerical value of the digit if one was pressed or\n"
1175 " -1 on error/hangup.\n";
1176
1177 static char usage_saydigits[] =
1178 " Usage: SAY DIGITS <number> <escape digits>\n"
1179 "        Say a given digit string, returning early if any of the given DTMF digits\n"
1180 " are received on the channel.  Returns 0 if playback completes without a digit\n"
1181 " being pressed, or the ASCII numerical value of the digit if one was pressed or\n"
1182 " -1 on error/hangup.\n";
1183
1184 static char usage_saytime[] =
1185 " Usage: SAY TIME <time> <escape digits>\n"
1186 "        Say a given time, returning early if any of the given DTMF digits are\n"
1187 " received on the channel.  <time> is number of seconds elapsed since 00:00:00\n"
1188 " on January 1, 1970, Coordinated Universal Time (UTC).  Returns 0 if playback\n"
1189 " completes without a digit being pressed, or the ASCII numerical value of the\n"
1190 " digit if one was pressed or -1 on error/hangup.\n";
1191
1192 static char usage_sayphonetic[] =
1193 " Usage: SAY PHONETIC <string> <escape digits>\n"
1194 "        Say a given character string with phonetics, returning early if any of the given DTMF digits\n"
1195 " are received on the channel.  Returns 0 if playback completes without a digit\n"
1196 " being pressed, or the ASCII numerical value of the digit if one was pressed or\n"
1197 " -1 on error/hangup.\n";
1198
1199 static char usage_getdata[] =
1200 " Usage: GET DATA <file to be streamed> [timeout] [max digits]\n"
1201 "        Stream the given file, and recieve DTMF data. Returns the digits recieved\n"
1202 "from the channel at the other end.\n";
1203
1204 static char usage_setcontext[] =
1205 " Usage: SET CONTEXT <desired context>\n"
1206 "        Sets the context for continuation upon exiting the application.\n";
1207
1208 static char usage_setextension[] =
1209 " Usage: SET EXTENSION <new extension>\n"
1210 "        Changes the extension for continuation upon exiting the application.\n";
1211
1212 static char usage_setpriority[] =
1213 " Usage: SET PRIORITY <num>\n"
1214 "        Changes the priority for continuation upon exiting the application.\n";
1215
1216 static char usage_recordfile[] =
1217 " Usage: RECORD FILE <filename> <format> <escape digits> <timeout> [offset samples] [BEEP] [s=silence]\n"
1218 "        Record to a file until a given dtmf digit in the sequence is received\n"
1219 " Returns -1 on hangup or error.  The format will specify what kind of file\n"
1220 " will be recorded.  The timeout is the maximum record time in milliseconds, or\n"
1221 " -1 for no timeout. Offset samples is optional, and if provided will seek to\n"
1222 " the offset without exceeding the end of the file.  \"silence\" is the number\n"
1223 " of seconds of silence allowed before the function returns despite the\n"
1224 " lack of dtmf digits or reaching timeout.  Silence value must be\n"
1225 " preceeded by \"s=\" and is optional.\n";
1226
1227
1228 static char usage_autohangup[] =
1229 " Usage: SET AUTOHANGUP <time>\n"
1230 "    Cause the channel to automatically hangup at <time> seconds in the\n"
1231 "future.  Of course it can be hungup before then as well.   Setting to\n"
1232 "0 will cause the autohangup feature to be disabled on this channel.\n";
1233
1234 static char usage_noop[] =
1235 " Usage: NOOP\n"
1236 "    Does nothing.\n";
1237
1238 static agi_command commands[MAX_COMMANDS] = {
1239         { { "answer", NULL }, handle_answer, "Asserts answer", usage_answer },
1240         { { "wait", "for", "digit", NULL }, handle_waitfordigit, "Waits for a digit to be pressed", usage_waitfordigit },
1241         { { "send", "text", NULL }, handle_sendtext, "Sends text to channels supporting it", usage_sendtext },
1242         { { "receive", "char", NULL }, handle_recvchar, "Receives text from channels supporting it", usage_recvchar },
1243         { { "tdd", "mode", NULL }, handle_tddmode, "Sends text to channels supporting it", usage_tddmode },
1244         { { "stream", "file", NULL }, handle_streamfile, "Sends audio file on channel", usage_streamfile },
1245         { { "send", "image", NULL }, handle_sendimage, "Sends images to channels supporting it", usage_sendimage },
1246         { { "say", "digits", NULL }, handle_saydigits, "Says a given digit string", usage_saydigits },
1247         { { "say", "number", NULL }, handle_saynumber, "Says a given number", usage_saynumber },
1248         { { "say", "phonetic", NULL }, handle_sayphonetic, "Says a given character string with phonetics", usage_sayphonetic },
1249         { { "say", "time", NULL }, handle_saytime, "Says a given time", usage_saytime },
1250         { { "get", "data", NULL }, handle_getdata, "Gets data on a channel", usage_getdata },
1251         { { "set", "context", NULL }, handle_setcontext, "Sets channel context", usage_setcontext },
1252         { { "set", "extension", NULL }, handle_setextension, "Changes channel extension", usage_setextension },
1253         { { "set", "priority", NULL }, handle_setpriority, "Prioritizes the channel", usage_setpriority },
1254         { { "record", "file", NULL }, handle_recordfile, "Records to a given file", usage_recordfile },
1255         { { "set", "autohangup", NULL }, handle_autohangup, "Autohangup channel in some time", usage_autohangup },
1256         { { "hangup", NULL }, handle_hangup, "Hangup the current channel", usage_hangup },
1257         { { "exec", NULL }, handle_exec, "Executes a given Application", usage_exec },
1258         { { "set", "callerid", NULL }, handle_setcallerid, "Sets callerid for the current channel", usage_setcallerid },
1259         { { "channel", "status", NULL }, handle_channelstatus, "Returns status of the connected channel", usage_channelstatus },
1260         { { "set", "variable", NULL }, handle_setvariable, "Sets a channel variable", usage_setvariable },
1261         { { "get", "variable", NULL }, handle_getvariable, "Gets a channel variable", usage_getvariable },
1262         { { "verbose", NULL }, handle_verbose, "Logs a message to the asterisk verbose log", usage_verbose },
1263         { { "database", "get", NULL }, handle_dbget, "Gets database value", usage_dbget },
1264         { { "database", "put", NULL }, handle_dbput, "Adds/updates database value", usage_dbput },
1265         { { "database", "del", NULL }, handle_dbdel, "Removes database key/value", usage_dbdel },
1266         { { "database", "deltree", NULL }, handle_dbdeltree, "Removes database keytree/value", usage_dbdeltree },
1267         { { "noop", NULL }, handle_noop, "Does nothing", usage_noop },
1268         { { "set", "music", NULL }, handle_setmusic, "Enable/Disable Music on hold generator", usage_setmusic }
1269 };
1270
1271 static void join(char *s, size_t len, char *w[])
1272 {
1273         int x;
1274         /* Join words into a string */
1275         if (!s) {
1276                 return;
1277         }
1278         s[0] = '\0';
1279         for (x=0;w[x];x++) {
1280                 if (x)
1281                         strncat(s, " ", len - strlen(s) - 1);
1282                 strncat(s, w[x], len - strlen(s) - 1);
1283         }
1284 }
1285
1286 static int help_workhorse(int fd, char *match[])
1287 {
1288         char fullcmd[80];
1289         char matchstr[80];
1290         int x;
1291         struct agi_command *e;
1292         if (match)
1293                 join(matchstr, sizeof(matchstr), match);
1294         for (x=0;x<sizeof(commands)/sizeof(commands[0]);x++) {
1295                 if (!commands[x].cmda[0]) break;
1296                 e = &commands[x]; 
1297                 if (e)
1298                         join(fullcmd, sizeof(fullcmd), e->cmda);
1299                 /* Hide commands that start with '_' */
1300                 if (fullcmd[0] == '_')
1301                         continue;
1302                 if (match) {
1303                         if (strncasecmp(matchstr, fullcmd, strlen(matchstr))) {
1304                                 continue;
1305                         }
1306                 }
1307                 ast_cli(fd, "%20.20s   %s\n", fullcmd, e->summary);
1308         }
1309         return 0;
1310 }
1311
1312 int agi_register(agi_command *agi)
1313 {
1314         int x;
1315         for (x=0;x<MAX_COMMANDS - 1;x++) {
1316                 if (commands[x].cmda[0] == agi->cmda[0]) {
1317                         ast_log(LOG_WARNING, "Command already registered!\n");
1318                         return -1;
1319                 }
1320         }
1321         for (x=0;x<MAX_COMMANDS - 1;x++) {
1322                 if (!commands[x].cmda[0]) {
1323                         commands[x] = *agi;
1324                         return 0;
1325                 }
1326         }
1327         ast_log(LOG_WARNING, "No more room for new commands!\n");
1328         return -1;
1329 }
1330
1331 void agi_unregister(agi_command *agi)
1332 {
1333         int x;
1334         for (x=0;x<MAX_COMMANDS - 1;x++) {
1335                 if (commands[x].cmda[0] == agi->cmda[0]) {
1336                         memset(&commands[x], 0, sizeof(agi_command));
1337                 }
1338         }
1339 }
1340
1341 static agi_command *find_command(char *cmds[], int exact)
1342 {
1343         int x;
1344         int y;
1345         int match;
1346         for (x=0;x < sizeof(commands) / sizeof(commands[0]);x++) {
1347                 if (!commands[x].cmda[0]) break;
1348                 /* start optimistic */
1349                 match = 1;
1350                 for (y=0;match && cmds[y]; y++) {
1351                         /* If there are no more words in the command (and we're looking for
1352                            an exact match) or there is a difference between the two words,
1353                            then this is not a match */
1354                         if (!commands[x].cmda[y] && !exact)
1355                                 break;
1356                         /* don't segfault if the next part of a command doesn't exist */
1357                         if (!commands[x].cmda[y]) return NULL;
1358                         if (strcasecmp(commands[x].cmda[y], cmds[y]))
1359                                 match = 0;
1360                 }
1361                 /* If more words are needed to complete the command then this is not
1362                    a candidate (unless we're looking for a really inexact answer  */
1363                 if ((exact > -1) && commands[x].cmda[y])
1364                         match = 0;
1365                 if (match)
1366                         return &commands[x];
1367         }
1368         return NULL;
1369 }
1370
1371
1372 static int parse_args(char *s, int *max, char *argv[])
1373 {
1374         int x=0;
1375         int quoted=0;
1376         int escaped=0;
1377         int whitespace=1;
1378         char *cur;
1379
1380         cur = s;
1381         while(*s) {
1382                 switch(*s) {
1383                 case '"':
1384                         /* If it's escaped, put a literal quote */
1385                         if (escaped) 
1386                                 goto normal;
1387                         else 
1388                                 quoted = !quoted;
1389                         if (quoted && whitespace) {
1390                                 /* If we're starting a quote, coming off white space start a new word, too */
1391                                 argv[x++] = cur;
1392                                 whitespace=0;
1393                         }
1394                         escaped = 0;
1395                 break;
1396                 case ' ':
1397                 case '\t':
1398                         if (!quoted && !escaped) {
1399                                 /* If we're not quoted, mark this as whitespace, and
1400                                    end the previous argument */
1401                                 whitespace = 1;
1402                                 *(cur++) = '\0';
1403                         } else
1404                                 /* Otherwise, just treat it as anything else */ 
1405                                 goto normal;
1406                         break;
1407                 case '\\':
1408                         /* If we're escaped, print a literal, otherwise enable escaping */
1409                         if (escaped) {
1410                                 goto normal;
1411                         } else {
1412                                 escaped=1;
1413                         }
1414                         break;
1415                 default:
1416 normal:
1417                         if (whitespace) {
1418                                 if (x >= MAX_ARGS -1) {
1419                                         ast_log(LOG_WARNING, "Too many arguments, truncating\n");
1420                                         break;
1421                                 }
1422                                 /* Coming off of whitespace, start the next argument */
1423                                 argv[x++] = cur;
1424                                 whitespace=0;
1425                         }
1426                         *(cur++) = *s;
1427                         escaped=0;
1428                 }
1429                 s++;
1430         }
1431         /* Null terminate */
1432         *(cur++) = '\0';
1433         argv[x] = NULL;
1434         *max = x;
1435         return 0;
1436 }
1437
1438 static int agi_handle_command(struct ast_channel *chan, AGI *agi, char *buf)
1439 {
1440         char *argv[MAX_ARGS];
1441         int argc = 0;
1442         int res;
1443         agi_command *c;
1444         argc = MAX_ARGS;
1445         parse_args(buf, &argc, argv);
1446 #if     0
1447         { int x;
1448         for (x=0;x<argc;x++) 
1449                 fprintf(stderr, "Got Arg%d: %s\n", x, argv[x]); }
1450 #endif
1451         c = find_command(argv, 0);
1452         if (c) {
1453                 res = c->handler(chan, agi, argc, argv);
1454                 switch(res) {
1455                 case RESULT_SHOWUSAGE:
1456                         fdprintf(agi->fd, "520-Invalid command syntax.  Proper usage follows:\n");
1457                         fdprintf(agi->fd, c->usage);
1458                         fdprintf(agi->fd, "520 End of proper usage.\n");
1459                         break;
1460                 case AST_PBX_KEEPALIVE:
1461                         /* We've been asked to keep alive, so do so */
1462                         return AST_PBX_KEEPALIVE;
1463                         break;
1464                 case RESULT_FAILURE:
1465                         /* They've already given the failure.  We've been hung up on so handle this
1466                            appropriately */
1467                         return -1;
1468                 }
1469         } else {
1470                 fdprintf(agi->fd, "510 Invalid or unknown command\n");
1471         }
1472         return 0;
1473 }
1474 #define RETRY   3
1475 static int run_agi(struct ast_channel *chan, char *request, AGI *agi, int pid, int dead)
1476 {
1477         struct ast_channel *c;
1478         int outfd;
1479         int ms;
1480         int returnstatus = 0;
1481         struct ast_frame *f;
1482         char buf[2048];
1483         FILE *readf;
1484         /* how many times we'll retry if ast_waitfor_nandfs will return without either 
1485           channel or file descriptor in case select is interrupted by a system call (EINTR) */
1486         int retry = RETRY;
1487
1488         if (!(readf = fdopen(agi->ctrl, "r"))) {
1489                 ast_log(LOG_WARNING, "Unable to fdopen file descriptor\n");
1490                 if (pid > -1)
1491                         kill(pid, SIGHUP);
1492                 close(agi->ctrl);
1493                 return -1;
1494         }
1495         setlinebuf(readf);
1496         setup_env(chan, request, agi->fd, (agi->audio > -1));
1497         for (;;) {
1498                 ms = -1;
1499                 c = ast_waitfor_nandfds(&chan, dead ? 0 : 1, &agi->ctrl, 1, NULL, &outfd, &ms);
1500                 if (c) {
1501                         retry = RETRY;
1502                         /* Idle the channel until we get a command */
1503                         f = ast_read(c);
1504                         if (!f) {
1505                                 ast_log(LOG_DEBUG, "%s hungup\n", chan->name);
1506                                 returnstatus = -1;
1507                                 break;
1508                         } else {
1509                                 /* If it's voice, write it to the audio pipe */
1510                                 if ((agi->audio > -1) && (f->frametype == AST_FRAME_VOICE)) {
1511                                         /* Write, ignoring errors */
1512                                         write(agi->audio, f->data, f->datalen);
1513                                 }
1514                                 ast_frfree(f);
1515                         }
1516                 } else if (outfd > -1) {
1517                         retry = RETRY;
1518                         if (!fgets(buf, sizeof(buf), readf)) {
1519                                 /* Program terminated */
1520                                 if (returnstatus)
1521                                         returnstatus = -1;
1522                                 if (option_verbose > 2) 
1523                                         ast_verbose(VERBOSE_PREFIX_3 "AGI Script %s completed, returning %d\n", request, returnstatus);
1524                                 /* No need to kill the pid anymore, since they closed us */
1525                                 pid = -1;
1526                                 break;
1527                         }
1528                           /* get rid of trailing newline, if any */
1529                         if (*buf && buf[strlen(buf) - 1] == '\n')
1530                                 buf[strlen(buf) - 1] = 0;
1531                         if (agidebug)
1532                                 ast_verbose("AGI Rx << %s\n", buf);
1533                         returnstatus |= agi_handle_command(chan, agi, buf);
1534                         /* If the handle_command returns -1, we need to stop */
1535                         if ((returnstatus < 0) || (returnstatus == AST_PBX_KEEPALIVE)) {
1536                                 break;
1537                         }
1538                 } else {
1539                         if (--retry <= 0) {
1540                                 ast_log(LOG_WARNING, "No channel, no fd?\n");
1541                                 returnstatus = -1;
1542                                 break;
1543                         }
1544                 }
1545         }
1546         /* Notify process */
1547         if (pid > -1)
1548                 kill(pid, SIGHUP);
1549         fclose(readf);
1550         return returnstatus;
1551 }
1552
1553 static int handle_showagi(int fd, int argc, char *argv[]) {
1554         struct agi_command *e;
1555         char fullcmd[80];
1556         if ((argc < 2))
1557                 return RESULT_SHOWUSAGE;
1558         if (argc > 2) {
1559                 e = find_command(argv + 2, 1);
1560                 if (e) 
1561                         ast_cli(fd, e->usage);
1562                 else {
1563                         if (find_command(argv + 2, -1)) {
1564                                 return help_workhorse(fd, argv + 1);
1565                         } else {
1566                                 join(fullcmd, sizeof(fullcmd), argv+1);
1567                                 ast_cli(fd, "No such command '%s'.\n", fullcmd);
1568                         }
1569                 }
1570         } else {
1571                 return help_workhorse(fd, NULL);
1572         }
1573         return RESULT_SUCCESS;
1574 }
1575
1576 static int handle_dumpagihtml(int fd, int argc, char *argv[]) {
1577         struct agi_command *e;
1578         char fullcmd[80];
1579         char *tempstr;
1580         int x;
1581         FILE *htmlfile;
1582
1583         if ((argc < 3))
1584                 return RESULT_SHOWUSAGE;
1585
1586         if (!(htmlfile = fopen(argv[2], "wt"))) {
1587                 ast_cli(fd, "Could not create file '%s'\n", argv[2]);
1588                 return RESULT_SHOWUSAGE;
1589         }
1590
1591         fprintf(htmlfile, "<HTML>\n<HEAD>\n<TITLE>AGI Commands</TITLE>\n</HEAD>\n");
1592         fprintf(htmlfile, "<BODY>\n<CENTER><B><H1>AGI Commands</H1></B></CENTER>\n\n");
1593
1594
1595         fprintf(htmlfile, "<TABLE BORDER=\"0\" CELLSPACING=\"10\">\n");
1596
1597         for (x=0;x<sizeof(commands)/sizeof(commands[0]);x++) {
1598                 char *stringp=NULL;
1599                 if (!commands[x].cmda[0]) break;
1600                 e = &commands[x]; 
1601                 if (e)
1602                         join(fullcmd, sizeof(fullcmd), e->cmda);
1603                 /* Hide commands that start with '_' */
1604                 if (fullcmd[0] == '_')
1605                         continue;
1606
1607                 fprintf(htmlfile, "<TR><TD><TABLE BORDER=\"1\" CELLPADDING=\"5\" WIDTH=\"100%%\">\n");
1608                 fprintf(htmlfile, "<TR><TH ALIGN=\"CENTER\"><B>%s - %s</B></TD></TR>\n", fullcmd,e->summary);
1609
1610
1611                 stringp=e->usage;
1612                 tempstr = strsep(&stringp, "\n");
1613
1614                 fprintf(htmlfile, "<TR><TD ALIGN=\"CENTER\">%s</TD></TR>\n", tempstr);
1615                 
1616                 fprintf(htmlfile, "<TR><TD ALIGN=\"CENTER\">\n");
1617                 while ((tempstr = strsep(&stringp, "\n")) != NULL) {
1618                 fprintf(htmlfile, "%s<BR>\n",tempstr);
1619
1620                 }
1621                 fprintf(htmlfile, "</TD></TR>\n");
1622                 fprintf(htmlfile, "</TABLE></TD></TR>\n\n");
1623
1624         }
1625
1626         fprintf(htmlfile, "</TABLE>\n</BODY>\n</HTML>\n");
1627         fclose(htmlfile);
1628         ast_cli(fd, "AGI HTML Commands Dumped to: %s\n", argv[2]);
1629         return RESULT_SUCCESS;
1630 }
1631
1632 static int agi_exec_full(struct ast_channel *chan, void *data, int enhanced, int dead)
1633 {
1634         int res=0;
1635         struct localuser *u;
1636         char *argv[MAX_ARGS];
1637         char buf[2048]="";
1638         char *tmp = (char *)buf;
1639         int argc = 0;
1640         int fds[2];
1641         int efd = -1;
1642         int pid;
1643         char *stringp;
1644         AGI agi;
1645         if (!data || ast_strlen_zero(data)) {
1646                 ast_log(LOG_WARNING, "AGI requires an argument (script)\n");
1647                 return -1;
1648         }
1649         strncpy(buf, data, sizeof(buf) - 1);
1650
1651         memset(&agi, 0, sizeof(agi));
1652         while ((stringp = strsep(&tmp, "|"))) {
1653                 argv[argc++] = stringp;
1654         }
1655         argv[argc] = NULL;
1656
1657         LOCAL_USER_ADD(u);
1658 #if 0
1659          /* Answer if need be */
1660         if (chan->_state != AST_STATE_UP) {
1661                 if (ast_answer(chan)) {
1662                         LOCAL_USER_REMOVE(u);
1663                         return -1;
1664                 }
1665         }
1666 #endif
1667         res = launch_script(argv[0], argv, fds, enhanced ? &efd : NULL, &pid);
1668         if (!res) {
1669                 agi.fd = fds[1];
1670                 agi.ctrl = fds[0];
1671                 agi.audio = efd;
1672                 res = run_agi(chan, argv[0], &agi, pid, dead);
1673                 close(fds[1]);
1674                 if (efd > -1)
1675                         close(efd);
1676         }
1677         LOCAL_USER_REMOVE(u);
1678         return res;
1679 }
1680
1681 static int agi_exec(struct ast_channel *chan, void *data)
1682 {
1683         if (chan->_softhangup)
1684                 ast_log(LOG_WARNING, "If you want to run AGI on hungup channels you should use DeadAGI!\n");
1685         return agi_exec_full(chan, data, 0, 0);
1686 }
1687
1688 static int eagi_exec(struct ast_channel *chan, void *data)
1689 {
1690         int readformat;
1691         int res;
1692         if (chan->_softhangup)
1693                 ast_log(LOG_WARNING, "If you want to run AGI on hungup channels you should use DeadAGI!\n");
1694         readformat = chan->readformat;
1695         if (ast_set_read_format(chan, AST_FORMAT_SLINEAR)) {
1696                 ast_log(LOG_WARNING, "Unable to set channel '%s' to linear mode\n", chan->name);
1697                 return -1;
1698         }
1699         res = agi_exec_full(chan, data, 1, 0);
1700         if (!res) {
1701                 if (ast_set_read_format(chan, readformat)) {
1702                         ast_log(LOG_WARNING, "Unable to restore channel '%s' to format %s\n", chan->name, ast_getformatname(readformat));
1703                 }
1704         }
1705         return res;
1706 }
1707
1708 static int deadagi_exec(struct ast_channel *chan, void *data)
1709 {
1710         return agi_exec_full(chan, data, 0, 1);
1711 }
1712
1713 static char showagi_help[] =
1714 "Usage: show agi [topic]\n"
1715 "       When called with a topic as an argument, displays usage\n"
1716 "       information on the given command.  If called without a\n"
1717 "       topic, it provides a list of AGI commands.\n";
1718
1719
1720 static char dumpagihtml_help[] =
1721 "Usage: dump agihtml <filename>\n"
1722 "       Dumps the agi command list in html format to given filename\n";
1723
1724 static struct ast_cli_entry showagi = 
1725 { { "show", "agi", NULL }, handle_showagi, "Show AGI commands or specific help", showagi_help };
1726
1727 static struct ast_cli_entry dumpagihtml = 
1728 { { "dump", "agihtml", NULL }, handle_dumpagihtml, "Dumps a list of agi command in html format", dumpagihtml_help };
1729
1730 int unload_module(void)
1731 {
1732         STANDARD_HANGUP_LOCALUSERS;
1733         ast_cli_unregister(&showagi);
1734         ast_cli_unregister(&dumpagihtml);
1735         ast_cli_unregister(&cli_debug);
1736         ast_cli_unregister(&cli_no_debug);
1737         ast_unregister_application(eapp);
1738         ast_unregister_application(deadapp);
1739         return ast_unregister_application(app);
1740 }
1741
1742 int load_module(void)
1743 {
1744         ast_cli_register(&showagi);
1745         ast_cli_register(&dumpagihtml);
1746         ast_cli_register(&cli_debug);
1747         ast_cli_register(&cli_no_debug);
1748         ast_register_application(deadapp, deadagi_exec, deadsynopsis, descrip);
1749         ast_register_application(eapp, eagi_exec, esynopsis, descrip);
1750         return ast_register_application(app, agi_exec, synopsis, descrip);
1751 }
1752
1753 char *description(void)
1754 {
1755         return tdesc;
1756 }
1757
1758 int usecount(void)
1759 {
1760         int res;
1761         STANDARD_USECOUNT(res);
1762         return res;
1763 }
1764
1765 char *key()
1766 {
1767         return ASTERISK_GPL_KEY;
1768 }
1769