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