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