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