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