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