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