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