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