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