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