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