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