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