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