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