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