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