Merged revisions 89536 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 <math.h>
31 #include <signal.h>
32 #include <sys/time.h>
33 #include <sys/wait.h>
34 #include <sys/stat.h>
35
36 #include "asterisk/paths.h"     /* use many ast_config_AST_*_DIR */
37 #include "asterisk/network.h"
38 #include "asterisk/file.h"
39 #include "asterisk/channel.h"
40 #include "asterisk/pbx.h"
41 #include "asterisk/module.h"
42 #include "asterisk/astdb.h"
43 #include "asterisk/callerid.h"
44 #include "asterisk/cli.h"
45 #include "asterisk/image.h"
46 #include "asterisk/say.h"
47 #include "asterisk/app.h"
48 #include "asterisk/dsp.h"
49 #include "asterisk/musiconhold.h"
50 #include "asterisk/utils.h"
51 #include "asterisk/lock.h"
52 #include "asterisk/strings.h"
53 #include "asterisk/agi.h"
54
55 #define MAX_ARGS 128
56 #define AGI_NANDFS_RETRY 3
57 #define AGI_BUF_LEN 2048
58
59 static char *app = "AGI";
60
61 static char *eapp = "EAGI";
62
63 static char *deadapp = "DeadAGI";
64
65 static char *synopsis = "Executes an AGI compliant application";
66 static char *esynopsis = "Executes an EAGI compliant application";
67 static char *deadsynopsis = "Executes AGI on a hungup channel";
68
69 static char *descrip =
70 "  [E|Dead]AGI(command,args): Executes an Asterisk Gateway Interface compliant\n"
71 "program on a channel. AGI allows Asterisk to launch external programs\n"
72 "written in any language to control a telephony channel, play audio,\n"
73 "read DTMF digits, etc. by communicating with the AGI protocol on stdin\n"
74 "and stdout.\n"
75 "  This channel will stop dialplan execution on hangup inside of this\n"
76 "application, except when using DeadAGI.  Otherwise, dialplan execution\n"
77 "will continue normally.\n"
78 "  A locally executed AGI script will receive SIGHUP on hangup from the channel\n"
79 "except when using DeadAGI. This can be disabled by setting the AGISIGHUP channel\n"
80 "variable to \"no\" before executing the AGI application.\n"
81 "  Using 'EAGI' provides enhanced AGI, with incoming audio available out of band\n"
82 "on file descriptor 3\n\n"
83 "  Use the CLI command 'agi show' to list available agi commands\n"
84 "  This application sets the following channel variable upon completion:\n"
85 "     AGISTATUS      The status of the attempt to the run the AGI script\n"
86 "                    text string, one of SUCCESS | FAILED | NOTFOUND | HANGUP\n";
87
88 static int agidebug = 0;
89
90 #define TONE_BLOCK_SIZE 200
91
92 /* Max time to connect to an AGI remote host */
93 #define MAX_AGI_CONNECT 2000
94
95 #define AGI_PORT 4573
96
97 enum agi_result {
98         AGI_RESULT_SUCCESS,
99         AGI_RESULT_SUCCESS_FAST,
100         AGI_RESULT_FAILURE,
101         AGI_RESULT_NOTFOUND,
102         AGI_RESULT_HANGUP,
103 };
104
105 static agi_command *find_command(char *cmds[], int exact);
106
107 AST_THREADSTORAGE(agi_buf);
108 #define AGI_BUF_INITSIZE 256
109
110 int ast_agi_fdprintf(struct ast_channel *chan, int fd, char *fmt, ...)
111 {
112         int res = 0;
113         va_list ap;
114         struct ast_str *buf;
115
116         if (!(buf = ast_str_thread_get(&agi_buf, AGI_BUF_INITSIZE)))
117                 return -1;
118
119         va_start(ap, fmt);
120         res = ast_str_set_va(&buf, 0, fmt, ap);
121         va_end(ap);
122
123         if (res == -1) {
124                 ast_log(LOG_ERROR, "Out of memory\n");
125                 return -1;
126         }
127
128         if (agidebug) {
129                 if (chan) {
130                         ast_verbose("<%s>AGI Tx >> %s", chan->name, buf->str);
131                 } else {
132                         ast_verbose("AGI Tx >> %s", buf->str);
133                 }
134         }
135
136         return ast_carefulwrite(fd, buf->str, buf->used, 100);
137 }
138
139 /* launch_netscript: The fastagi handler.
140         FastAGI defaults to port 4573 */
141 static enum agi_result launch_netscript(char *agiurl, char *argv[], int *fds, int *efd, int *opid)
142 {
143         int s, flags, res, port = AGI_PORT;
144         struct pollfd pfds[1];
145         char *host, *c, *script = "";
146         struct sockaddr_in sin;
147         struct hostent *hp;
148         struct ast_hostent ahp;
149
150         /* agiusl is "agi://host.domain[:port][/script/name]" */
151         host = ast_strdupa(agiurl + 6); /* Remove agi:// */
152         /* Strip off any script name */
153         if ((c = strchr(host, '/'))) {
154                 *c = '\0';
155                 c++;
156                 script = c;
157         }
158         if ((c = strchr(host, ':'))) {
159                 *c = '\0';
160                 c++;
161                 port = atoi(c);
162         }
163         if (efd) {
164                 ast_log(LOG_WARNING, "AGI URI's don't support Enhanced AGI yet\n");
165                 return -1;
166         }
167         if (!(hp = ast_gethostbyname(host, &ahp))) {
168                 ast_log(LOG_WARNING, "Unable to locate host '%s'\n", host);
169                 return -1;
170         }
171         if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
172                 ast_log(LOG_WARNING, "Unable to create socket: %s\n", strerror(errno));
173                 return -1;
174         }
175         if ((flags = fcntl(s, F_GETFL)) < 0) {
176                 ast_log(LOG_WARNING, "Fcntl(F_GETFL) failed: %s\n", strerror(errno));
177                 close(s);
178                 return -1;
179         }
180         if (fcntl(s, F_SETFL, flags | O_NONBLOCK) < 0) {
181                 ast_log(LOG_WARNING, "Fnctl(F_SETFL) failed: %s\n", strerror(errno));
182                 close(s);
183                 return -1;
184         }
185         memset(&sin, 0, sizeof(sin));
186         sin.sin_family = AF_INET;
187         sin.sin_port = htons(port);
188         memcpy(&sin.sin_addr, hp->h_addr, sizeof(sin.sin_addr));
189         if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) && (errno != EINPROGRESS)) {
190                 ast_log(LOG_WARNING, "Connect failed with unexpected error: %s\n", strerror(errno));
191                 close(s);
192                 return AGI_RESULT_FAILURE;
193         }
194
195         pfds[0].fd = s;
196         pfds[0].events = POLLOUT;
197         while ((res = poll(pfds, 1, MAX_AGI_CONNECT)) != 1) {
198                 if (errno != EINTR) {
199                         if (!res) {
200                                 ast_log(LOG_WARNING, "FastAGI connection to '%s' timed out after MAX_AGI_CONNECT (%d) milliseconds.\n",
201                                         agiurl, MAX_AGI_CONNECT);
202                         } else
203                                 ast_log(LOG_WARNING, "Connect to '%s' failed: %s\n", agiurl, strerror(errno));
204                         close(s);
205                         return AGI_RESULT_FAILURE;
206                 }
207         }
208
209         if (ast_agi_fdprintf(NULL, s, "agi_network: yes\n") < 0) {
210                 if (errno != EINTR) {
211                         ast_log(LOG_WARNING, "Connect to '%s' failed: %s\n", agiurl, strerror(errno));
212                         close(s);
213                         return AGI_RESULT_FAILURE;
214                 }
215         }
216
217         /* If we have a script parameter, relay it to the fastagi server */
218         /* Script parameters take the form of: AGI(agi://my.example.com/?extension=${EXTEN}) */
219         if (!ast_strlen_zero(script))
220                 ast_agi_fdprintf(NULL, s, "agi_network_script: %s\n", script);
221
222         ast_debug(4, "Wow, connected!\n");
223         fds[0] = s;
224         fds[1] = s;
225         *opid = -1;
226         return AGI_RESULT_SUCCESS_FAST;
227 }
228
229 static enum agi_result launch_script(char *script, char *argv[], int *fds, int *efd, int *opid)
230 {
231         char tmp[256];
232         int pid, toast[2], fromast[2], audio[2], x, res;
233         sigset_t signal_set, old_set;
234         struct stat st;
235
236         if (!strncasecmp(script, "agi://", 6))
237                 return launch_netscript(script, argv, fds, efd, opid);
238         
239         if (script[0] != '/') {
240                 snprintf(tmp, sizeof(tmp), "%s/%s", ast_config_AST_AGI_DIR, script);
241                 script = tmp;
242         }
243
244         /* Before even trying let's see if the file actually exists */
245         if (stat(script, &st)) {
246                 ast_log(LOG_WARNING, "Failed to execute '%s': File does not exist.\n", script);
247                 return AGI_RESULT_NOTFOUND;
248         }
249
250         if (pipe(toast)) {
251                 ast_log(LOG_WARNING, "Unable to create toast pipe: %s\n",strerror(errno));
252                 return AGI_RESULT_FAILURE;
253         }
254         if (pipe(fromast)) {
255                 ast_log(LOG_WARNING, "unable to create fromast pipe: %s\n", strerror(errno));
256                 close(toast[0]);
257                 close(toast[1]);
258                 return AGI_RESULT_FAILURE;
259         }
260         if (efd) {
261                 if (pipe(audio)) {
262                         ast_log(LOG_WARNING, "unable to create audio pipe: %s\n", strerror(errno));
263                         close(fromast[0]);
264                         close(fromast[1]);
265                         close(toast[0]);
266                         close(toast[1]);
267                         return AGI_RESULT_FAILURE;
268                 }
269                 res = fcntl(audio[1], F_GETFL);
270                 if (res > -1) 
271                         res = fcntl(audio[1], F_SETFL, res | O_NONBLOCK);
272                 if (res < 0) {
273                         ast_log(LOG_WARNING, "unable to set audio pipe parameters: %s\n", strerror(errno));
274                         close(fromast[0]);
275                         close(fromast[1]);
276                         close(toast[0]);
277                         close(toast[1]);
278                         close(audio[0]);
279                         close(audio[1]);
280                         return AGI_RESULT_FAILURE;
281                 }
282         }
283
284         /* Block SIGHUP during the fork - prevents a race */
285         sigfillset(&signal_set);
286         pthread_sigmask(SIG_BLOCK, &signal_set, &old_set);
287         if ((pid = fork()) < 0) {
288                 ast_log(LOG_WARNING, "Failed to fork(): %s\n", strerror(errno));
289                 pthread_sigmask(SIG_SETMASK, &old_set, NULL);
290                 return AGI_RESULT_FAILURE;
291         }
292         if (!pid) {
293                 /* Pass paths to AGI via environmental variables */
294                 setenv("AST_CONFIG_DIR", ast_config_AST_CONFIG_DIR, 1);
295                 setenv("AST_CONFIG_FILE", ast_config_AST_CONFIG_FILE, 1);
296                 setenv("AST_MODULE_DIR", ast_config_AST_MODULE_DIR, 1);
297                 setenv("AST_SPOOL_DIR", ast_config_AST_SPOOL_DIR, 1);
298                 setenv("AST_MONITOR_DIR", ast_config_AST_MONITOR_DIR, 1);
299                 setenv("AST_VAR_DIR", ast_config_AST_VAR_DIR, 1);
300                 setenv("AST_DATA_DIR", ast_config_AST_DATA_DIR, 1);
301                 setenv("AST_LOG_DIR", ast_config_AST_LOG_DIR, 1);
302                 setenv("AST_AGI_DIR", ast_config_AST_AGI_DIR, 1);
303                 setenv("AST_KEY_DIR", ast_config_AST_KEY_DIR, 1);
304                 setenv("AST_RUN_DIR", ast_config_AST_RUN_DIR, 1);
305
306                 /* Don't run AGI scripts with realtime priority -- it causes audio stutter */
307                 ast_set_priority(0);
308
309                 /* Redirect stdin and out, provide enhanced audio channel if desired */
310                 dup2(fromast[0], STDIN_FILENO);
311                 dup2(toast[1], STDOUT_FILENO);
312                 if (efd)
313                         dup2(audio[0], STDERR_FILENO + 1);
314                 else
315                         close(STDERR_FILENO + 1);
316
317                 /* Before we unblock our signals, return our trapped signals back to the defaults */
318                 signal(SIGHUP, SIG_DFL);
319                 signal(SIGCHLD, SIG_DFL);
320                 signal(SIGINT, SIG_DFL);
321                 signal(SIGURG, SIG_DFL);
322                 signal(SIGTERM, SIG_DFL);
323                 signal(SIGPIPE, SIG_DFL);
324                 signal(SIGXFSZ, SIG_DFL);
325
326                 /* unblock important signal handlers */
327                 if (pthread_sigmask(SIG_UNBLOCK, &signal_set, NULL)) {
328                         ast_log(LOG_WARNING, "unable to unblock signals for AGI script: %s\n", strerror(errno));
329                         _exit(1);
330                 }
331
332                 /* Close everything but stdin/out/error */
333                 for (x = STDERR_FILENO + 2; x < 1024; x++) 
334                         close(x);
335
336                 /* Execute script */
337                 /* XXX argv should be deprecated in favor of passing agi_argX paramaters */
338                 execv(script, argv);
339                 /* Can't use ast_log since FD's are closed */
340                 fprintf(stdout, "verbose \"Failed to execute '%s': %s\" 2\n", script, strerror(errno));
341                 fflush(stdout);
342                 _exit(1);
343         }
344         pthread_sigmask(SIG_SETMASK, &old_set, NULL);
345         ast_verb(3, "Launched AGI Script %s\n", script);
346         fds[0] = toast[0];
347         fds[1] = fromast[1];
348         if (efd)
349                 *efd = audio[1];
350         /* close what we're not using in the parent */
351         close(toast[1]);
352         close(fromast[0]);
353
354         if (efd)
355                 close(audio[0]);
356
357         *opid = pid;
358         return AGI_RESULT_SUCCESS;
359 }
360
361 static void setup_env(struct ast_channel *chan, char *request, int fd, int enhanced, int argc, char *argv[])
362 {
363         int count;
364
365         /* Print initial environment, with agi_request always being the first
366            thing */
367         ast_agi_fdprintf(chan, fd, "agi_request: %s\n", request);
368         ast_agi_fdprintf(chan, fd, "agi_channel: %s\n", chan->name);
369         ast_agi_fdprintf(chan, fd, "agi_language: %s\n", chan->language);
370         ast_agi_fdprintf(chan, fd, "agi_type: %s\n", chan->tech->type);
371         ast_agi_fdprintf(chan, fd, "agi_uniqueid: %s\n", chan->uniqueid);
372
373         /* ANI/DNIS */
374         ast_agi_fdprintf(chan, fd, "agi_callerid: %s\n", S_OR(chan->cid.cid_num, "unknown"));
375         ast_agi_fdprintf(chan, fd, "agi_calleridname: %s\n", S_OR(chan->cid.cid_name, "unknown"));
376         ast_agi_fdprintf(chan, fd, "agi_callingpres: %d\n", chan->cid.cid_pres);
377         ast_agi_fdprintf(chan, fd, "agi_callingani2: %d\n", chan->cid.cid_ani2);
378         ast_agi_fdprintf(chan, fd, "agi_callington: %d\n", chan->cid.cid_ton);
379         ast_agi_fdprintf(chan, fd, "agi_callingtns: %d\n", chan->cid.cid_tns);
380         ast_agi_fdprintf(chan, fd, "agi_dnid: %s\n", S_OR(chan->cid.cid_dnid, "unknown"));
381         ast_agi_fdprintf(chan, fd, "agi_rdnis: %s\n", S_OR(chan->cid.cid_rdnis, "unknown"));
382
383         /* Context information */
384         ast_agi_fdprintf(chan, fd, "agi_context: %s\n", chan->context);
385         ast_agi_fdprintf(chan, fd, "agi_extension: %s\n", chan->exten);
386         ast_agi_fdprintf(chan, fd, "agi_priority: %d\n", chan->priority);
387         ast_agi_fdprintf(chan, fd, "agi_enhanced: %s\n", enhanced ? "1.0" : "0.0");
388
389         /* User information */
390         ast_agi_fdprintf(chan, fd, "agi_accountcode: %s\n", chan->accountcode ? chan->accountcode : "");
391
392         /* Send any parameters to the fastagi server that have been passed via the agi application */
393         /* Agi application paramaters take the form of: AGI(/path/to/example/script|${EXTEN}) */
394         for(count = 1; count < argc; count++)
395                 ast_agi_fdprintf(chan, fd, "agi_arg_%d: %s\n", count, argv[count]);
396
397         /* End with empty return */
398         ast_agi_fdprintf(chan, fd, "\n");
399 }
400
401 static int handle_answer(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
402 {
403         int res = 0;
404
405         /* Answer the channel */
406         if (chan->_state != AST_STATE_UP)
407                 res = ast_answer(chan);
408
409         ast_agi_fdprintf(chan, agi->fd, "200 result=%d\n", res);
410         return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
411 }
412
413 static int handle_waitfordigit(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
414 {
415         int res, to;
416
417         if (argc != 4)
418                 return RESULT_SHOWUSAGE;
419         if (sscanf(argv[3], "%d", &to) != 1)
420                 return RESULT_SHOWUSAGE;
421         res = ast_waitfordigit_full(chan, to, agi->audio, agi->ctrl);
422         ast_agi_fdprintf(chan, agi->fd, "200 result=%d\n", res);
423         return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
424 }
425
426 static int handle_sendtext(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
427 {
428         int res;
429
430         if (argc != 3)
431                 return RESULT_SHOWUSAGE;
432
433         /* At the moment, the parser (perhaps broken) returns with
434            the last argument PLUS the newline at the end of the input
435            buffer. This probably needs to be fixed, but I wont do that
436            because other stuff may break as a result. The right way
437            would probably be to strip off the trailing newline before
438            parsing, then here, add a newline at the end of the string
439            before sending it to ast_sendtext --DUDE */
440         res = ast_sendtext(chan, argv[2]);
441         ast_agi_fdprintf(chan, agi->fd, "200 result=%d\n", res);
442         return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
443 }
444
445 static int handle_recvchar(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
446 {
447         int res;
448
449         if (argc != 3)
450                 return RESULT_SHOWUSAGE;
451
452         res = ast_recvchar(chan,atoi(argv[2]));
453         if (res == 0) {
454                 ast_agi_fdprintf(chan, agi->fd, "200 result=%d (timeout)\n", res);
455                 return RESULT_SUCCESS;
456         }
457         if (res > 0) {
458                 ast_agi_fdprintf(chan, agi->fd, "200 result=%d\n", res);
459                 return RESULT_SUCCESS;
460         }
461         else {
462                 ast_agi_fdprintf(chan, agi->fd, "200 result=%d (hangup)\n", res);
463                 return RESULT_FAILURE;
464         }
465 }
466
467 static int handle_recvtext(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
468 {
469         char *buf;
470         
471         if (argc != 3)
472                 return RESULT_SHOWUSAGE;
473
474         buf = ast_recvtext(chan,atoi(argv[2]));
475         if (buf) {
476                 ast_agi_fdprintf(chan, agi->fd, "200 result=1 (%s)\n", buf);
477                 ast_free(buf);
478         } else {        
479                 ast_agi_fdprintf(chan, agi->fd, "200 result=-1\n");
480         }
481         return RESULT_SUCCESS;
482 }
483
484 static int handle_tddmode(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
485 {
486         int res, x;
487
488         if (argc != 3)
489                 return RESULT_SHOWUSAGE;
490
491         if (!strncasecmp(argv[2],"on",2)) 
492                 x = 1; 
493         else 
494                 x = 0;
495         if (!strncasecmp(argv[2],"mate",4)) 
496                 x = 2;
497         if (!strncasecmp(argv[2],"tdd",3))
498                 x = 1;
499         res = ast_channel_setoption(chan, AST_OPTION_TDD, &x, sizeof(char), 0);
500         if (res != RESULT_SUCCESS)
501                 ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
502         else
503                 ast_agi_fdprintf(chan, agi->fd, "200 result=1\n");
504         return RESULT_SUCCESS;
505 }
506
507 static int handle_sendimage(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
508 {
509         int res;
510
511         if (argc != 3)
512                 return RESULT_SHOWUSAGE;
513
514         res = ast_send_image(chan, argv[2]);
515         if (!ast_check_hangup(chan))
516                 res = 0;
517         ast_agi_fdprintf(chan, agi->fd, "200 result=%d\n", res);
518         return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
519 }
520
521 static int handle_controlstreamfile(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
522 {
523         int res = 0, skipms = 3000;
524         char *fwd = NULL, *rev = NULL, *pause = NULL, *stop = NULL;
525
526         if (argc < 5 || argc > 9)
527                 return RESULT_SHOWUSAGE;
528
529         if (!ast_strlen_zero(argv[4]))
530                 stop = argv[4];
531         else
532                 stop = NULL;
533         
534         if ((argc > 5) && (sscanf(argv[5], "%d", &skipms) != 1))
535                 return RESULT_SHOWUSAGE;
536
537         if (argc > 6 && !ast_strlen_zero(argv[6]))
538                 fwd = argv[6];
539         else
540                 fwd = "#";
541
542         if (argc > 7 && !ast_strlen_zero(argv[7]))
543                 rev = argv[7];
544         else
545                 rev = "*";
546         
547         if (argc > 8 && !ast_strlen_zero(argv[8]))
548                 pause = argv[8];
549         else
550                 pause = NULL;
551         
552         res = ast_control_streamfile(chan, argv[3], fwd, rev, stop, pause, NULL, skipms, NULL);
553         
554         ast_agi_fdprintf(chan, agi->fd, "200 result=%d\n", res);
555
556         return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
557 }
558
559 static int handle_streamfile(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
560 {
561         int res, vres;
562         struct ast_filestream *fs, *vfs;
563         long sample_offset = 0, max_length;
564         char *edigits = "";
565
566         if (argc < 4 || argc > 5)
567                 return RESULT_SHOWUSAGE;
568
569         if (argv[3]) 
570                 edigits = argv[3];
571
572         if ((argc > 4) && (sscanf(argv[4], "%ld", &sample_offset) != 1))
573                 return RESULT_SHOWUSAGE;
574
575         if (!(fs = ast_openstream(chan, argv[2], chan->language))) {
576                 ast_agi_fdprintf(chan, agi->fd, "200 result=%d endpos=%ld\n", 0, sample_offset);
577                 return RESULT_SUCCESS;
578         }
579
580         if ((vfs = ast_openvstream(chan, argv[2], chan->language)))
581                 ast_debug(1, "Ooh, found a video stream, too\n");
582                 
583         ast_verb(3, "Playing '%s' (escape_digits=%s) (sample_offset %ld)\n", argv[2], edigits, sample_offset);
584
585         ast_seekstream(fs, 0, SEEK_END);
586         max_length = ast_tellstream(fs);
587         ast_seekstream(fs, sample_offset, SEEK_SET);
588         res = ast_applystream(chan, fs);
589         if (vfs)
590                 vres = ast_applystream(chan, vfs);
591         ast_playstream(fs);
592         if (vfs)
593                 ast_playstream(vfs);
594         
595         res = ast_waitstream_full(chan, argv[3], agi->audio, agi->ctrl);
596         /* this is to check for if ast_waitstream closed the stream, we probably are at
597          * the end of the stream, return that amount, else check for the amount */
598         sample_offset = (chan->stream) ? ast_tellstream(fs) : max_length;
599         ast_stopstream(chan);
600         if (res == 1) {
601                 /* Stop this command, don't print a result line, as there is a new command */
602                 return RESULT_SUCCESS;
603         }
604         ast_agi_fdprintf(chan, agi->fd, "200 result=%d endpos=%ld\n", res, sample_offset);
605         return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
606 }
607
608 /* get option - really similar to the handle_streamfile, but with a timeout */
609 static int handle_getoption(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
610 {
611         int res, vres;
612         struct ast_filestream *fs, *vfs;
613         long sample_offset = 0, max_length;
614         int timeout = 0;
615         char *edigits = "";
616
617         if ( argc < 4 || argc > 5 )
618                 return RESULT_SHOWUSAGE;
619
620         if ( argv[3] ) 
621                 edigits = argv[3];
622
623         if ( argc == 5 )
624                 timeout = atoi(argv[4]);
625         else if (chan->pbx->dtimeout) {
626                 /* by default dtimeout is set to 5sec */
627                 timeout = chan->pbx->dtimeout * 1000; /* in msec */
628         }
629
630         if (!(fs = ast_openstream(chan, argv[2], chan->language))) {
631                 ast_agi_fdprintf(chan, agi->fd, "200 result=%d endpos=%ld\n", 0, sample_offset);
632                 ast_log(LOG_WARNING, "Unable to open %s\n", argv[2]);
633                 return RESULT_SUCCESS;
634         }
635
636         if ((vfs = ast_openvstream(chan, argv[2], chan->language)))
637                 ast_debug(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(chan, 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(chan, 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(chan, 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(chan, 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(chan, 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(chan, 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(chan, 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(chan, 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(chan, agi->fd, "200 result=%s (timeout)\n", data);
821         else if (res < 0 )
822                 ast_agi_fdprintf(chan, agi->fd, "200 result=-1\n");
823         else
824                 ast_agi_fdprintf(chan, 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(chan, 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(chan, 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(chan, 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(chan, 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(chan, 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(chan, 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(chan, 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(chan, 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(chan, 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(chan, 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(chan, 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(chan, 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(chan, 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(chan, 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(chan, 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(chan, 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(chan, 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(chan, 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(chan, 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(chan, agi->fd, "200 result=1 (%s)\n", ret);
1178         else
1179                 ast_agi_fdprintf(chan, 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 (chan2) {
1197                 pbx_substitute_variables_helper(chan2, argv[3], tmp, sizeof(tmp) - 1);
1198                 ast_agi_fdprintf(chan, agi->fd, "200 result=1 (%s)\n", tmp);
1199         } else {
1200                 ast_agi_fdprintf(chan, 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(chan, 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(chan, agi->fd, "200 result=0\n");
1252         else
1253                 ast_agi_fdprintf(chan, 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(chan, 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(chan, 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(chan, agi->fd, "200 result=%c\n", res ? '0' : '1');
1292         return RESULT_SUCCESS;
1293 }
1294
1295 static char *handle_cli_agi_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1296 {
1297         switch (cmd) {
1298         case CLI_INIT:
1299                 e->command = "agi debug [off]";
1300                 e->usage =
1301                         "Usage: agi debug [off]\n"
1302                         "       Enables/disables dumping of AGI transactions for\n"
1303                         "       debugging purposes.\n";
1304                 return NULL;
1305
1306         case CLI_GENERATE:
1307                 return NULL;
1308         }
1309         if (a->argc < e->args - 1 || a->argc > e->args )
1310                 return CLI_SHOWUSAGE;
1311         if (a->argc == e->args - 1) {
1312                 agidebug = 1;
1313         } else {
1314                 if (strncasecmp(a->argv[e->args - 1], "off", 3) == 0) {
1315                         agidebug = 0;
1316                 } else {
1317                         return CLI_SHOWUSAGE;
1318                 }
1319         }
1320         ast_cli(a->fd, "AGI Debugging %sabled\n", agidebug ? "En" : "Dis");
1321         return CLI_SUCCESS;
1322 }
1323
1324 static int handle_noop(struct ast_channel *chan, AGI *agi, int arg, char *argv[])
1325 {
1326         ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
1327         return RESULT_SUCCESS;
1328 }
1329
1330 static int handle_setmusic(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
1331 {
1332         if (!strncasecmp(argv[2], "on", 2))
1333                 ast_moh_start(chan, argc > 3 ? argv[3] : NULL, NULL);
1334         else if (!strncasecmp(argv[2], "off", 3))
1335                 ast_moh_stop(chan);
1336         ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
1337         return RESULT_SUCCESS;
1338 }
1339
1340 static char usage_setmusic[] =
1341 " Usage: SET MUSIC ON <on|off> <class>\n"
1342 "       Enables/Disables the music on hold generator.  If <class> is\n"
1343 " not specified, then the default music on hold class will be used.\n"
1344 " Always returns 0.\n";
1345
1346 static char usage_dbput[] =
1347 " Usage: DATABASE PUT <family> <key> <value>\n"
1348 "       Adds or updates an entry in the Asterisk database for a\n"
1349 " given family, key, and value.\n"
1350 " Returns 1 if successful, 0 otherwise.\n";
1351
1352 static char usage_dbget[] =
1353 " Usage: DATABASE GET <family> <key>\n"
1354 "       Retrieves an entry in the Asterisk database for a\n"
1355 " given family and key.\n"
1356 " Returns 0 if <key> is not set.  Returns 1 if <key>\n"
1357 " is set and returns the variable in parentheses.\n"
1358 " Example return code: 200 result=1 (testvariable)\n";
1359
1360 static char usage_dbdel[] =
1361 " Usage: DATABASE DEL <family> <key>\n"
1362 "       Deletes an entry in the Asterisk database for a\n"
1363 " given family and key.\n"
1364 " Returns 1 if successful, 0 otherwise.\n";
1365
1366 static char usage_dbdeltree[] =
1367 " Usage: DATABASE DELTREE <family> [keytree]\n"
1368 "       Deletes a family or specific keytree within a family\n"
1369 " in the Asterisk database.\n"
1370 " Returns 1 if successful, 0 otherwise.\n";
1371
1372 static char usage_verbose[] =
1373 " Usage: VERBOSE <message> <level>\n"
1374 "       Sends <message> to the console via verbose message system.\n"
1375 " <level> is the the verbose level (1-4)\n"
1376 " Always returns 1.\n";
1377
1378 static char usage_getvariable[] =
1379 " Usage: GET VARIABLE <variablename>\n"
1380 "       Returns 0 if <variablename> is not set.  Returns 1 if <variablename>\n"
1381 " is set and returns the variable in parentheses.\n"
1382 " example return code: 200 result=1 (testvariable)\n";
1383
1384 static char usage_getvariablefull[] =
1385 " Usage: GET FULL VARIABLE <variablename> [<channel name>]\n"
1386 "       Returns 0 if <variablename> is not set or channel does not exist.  Returns 1\n"
1387 "if <variablename>  is set and returns the variable in parenthesis.  Understands\n"
1388 "complex variable names and builtin variables, unlike GET VARIABLE.\n"
1389 " example return code: 200 result=1 (testvariable)\n";
1390
1391 static char usage_setvariable[] =
1392 " Usage: SET VARIABLE <variablename> <value>\n";
1393
1394 static char usage_channelstatus[] =
1395 " Usage: CHANNEL STATUS [<channelname>]\n"
1396 "       Returns the status of the specified channel.\n" 
1397 " If no channel name is given the returns the status of the\n"
1398 " current channel.  Return values:\n"
1399 "  0 Channel is down and available\n"
1400 "  1 Channel is down, but reserved\n"
1401 "  2 Channel is off hook\n"
1402 "  3 Digits (or equivalent) have been dialed\n"
1403 "  4 Line is ringing\n"
1404 "  5 Remote end is ringing\n"
1405 "  6 Line is up\n"
1406 "  7 Line is busy\n";
1407
1408 static char usage_setcallerid[] =
1409 " Usage: SET CALLERID <number>\n"
1410 "       Changes the callerid of the current channel.\n";
1411
1412 static char usage_exec[] =
1413 " Usage: EXEC <application> <options>\n"
1414 "       Executes <application> with given <options>.\n"
1415 " Returns whatever the application returns, or -2 on failure to find application\n";
1416
1417 static char usage_hangup[] =
1418 " Usage: HANGUP [<channelname>]\n"
1419 "       Hangs up the specified channel.\n"
1420 " If no channel name is given, hangs up the current channel\n";
1421
1422 static char usage_answer[] = 
1423 " Usage: ANSWER\n"
1424 "       Answers channel if not already in answer state. Returns -1 on\n"
1425 " channel failure, or 0 if successful.\n";
1426
1427 static char usage_waitfordigit[] = 
1428 " Usage: WAIT FOR DIGIT <timeout>\n"
1429 "       Waits up to 'timeout' milliseconds for channel to receive a DTMF digit.\n"
1430 " Returns -1 on channel failure, 0 if no digit is received in the timeout, or\n"
1431 " the numerical value of the ascii of the digit if one is received.  Use -1\n"
1432 " for the timeout value if you desire the call to block indefinitely.\n";
1433
1434 static char usage_sendtext[] =
1435 " Usage: SEND TEXT \"<text to send>\"\n"
1436 "       Sends the given text on a channel. Most channels do not support the\n"
1437 " transmission of text.  Returns 0 if text is sent, or if the channel does not\n"
1438 " support text transmission.  Returns -1 only on error/hangup.  Text\n"
1439 " consisting of greater than one word should be placed in quotes since the\n"
1440 " command only accepts a single argument.\n";
1441
1442 static char usage_recvchar[] =
1443 " Usage: RECEIVE CHAR <timeout>\n"
1444 "       Receives a character of text on a channel. Specify timeout to be the\n"
1445 " maximum time to wait for input in milliseconds, or 0 for infinite. Most channels\n"
1446 " do not support the reception of text. Returns the decimal value of the character\n"
1447 " if one is received, or 0 if the channel does not support text reception.  Returns\n"
1448 " -1 only on error/hangup.\n";
1449
1450 static char usage_recvtext[] =
1451 " Usage: RECEIVE TEXT <timeout>\n"
1452 "       Receives a string of text on a channel. Specify timeout to be the\n"
1453 " maximum time to wait for input in milliseconds, or 0 for infinite. Most channels\n"
1454 " do not support the reception of text. Returns -1 for failure or 1 for success, and the string in parentheses.\n";
1455
1456 static char usage_tddmode[] =
1457 " Usage: TDD MODE <on|off>\n"
1458 "       Enable/Disable TDD transmission/reception on a channel. Returns 1 if\n"
1459 " successful, or 0 if channel is not TDD-capable.\n";
1460
1461 static char usage_sendimage[] =
1462 " Usage: SEND IMAGE <image>\n"
1463 "       Sends the given image on a channel. Most channels do not support the\n"
1464 " transmission of images. Returns 0 if image is sent, or if the channel does not\n"
1465 " support image transmission.  Returns -1 only on error/hangup. Image names\n"
1466 " should not include extensions.\n";
1467
1468 static char usage_streamfile[] =
1469 " Usage: STREAM FILE <filename> <escape digits> [sample offset]\n"
1470 "       Send the given file, allowing playback to be interrupted by the given\n"
1471 " digits, if any. Use double quotes for the digits if you wish none to be\n"
1472 " permitted. If sample offset is provided then the audio will seek to sample\n"
1473 " offset before play starts.  Returns 0 if playback completes without a digit\n"
1474 " being pressed, or the ASCII numerical value of the digit if one was pressed,\n"
1475 " or -1 on error or if the channel was disconnected. Remember, the file\n"
1476 " extension must not be included in the filename.\n";
1477
1478 static char usage_controlstreamfile[] =
1479 " Usage: CONTROL STREAM FILE <filename> <escape digits> [skipms] [ffchar] [rewchr] [pausechr]\n"
1480 "       Send the given file, allowing playback to be controled by the given\n"
1481 " digits, if any. Use double quotes for the digits if you wish none to be\n"
1482 " permitted.  Returns 0 if playback completes without a digit\n"
1483 " being pressed, or the ASCII numerical value of the digit if one was pressed,\n"
1484 " or -1 on error or if the channel was disconnected. Remember, the file\n"
1485 " extension must not be included in the filename.\n\n"
1486 " Note: ffchar and rewchar default to * and # respectively.\n";
1487
1488 static char usage_getoption[] = 
1489 " Usage: GET OPTION <filename> <escape_digits> [timeout]\n"
1490 "       Behaves similar to STREAM FILE but used with a timeout option.\n";
1491
1492 static char usage_saynumber[] =
1493 " Usage: SAY NUMBER <number> <escape digits> [gender]\n"
1494 "       Say a given number, returning early if any of the given DTMF digits\n"
1495 " are received on the channel.  Returns 0 if playback completes without a digit\n"
1496 " being pressed, or the ASCII numerical value of the digit if one was pressed or\n"
1497 " -1 on error/hangup.\n";
1498
1499 static char usage_saydigits[] =
1500 " Usage: SAY DIGITS <number> <escape digits>\n"
1501 "       Say a given digit string, returning early if any of the given DTMF digits\n"
1502 " are received on the channel. Returns 0 if playback completes without a digit\n"
1503 " being pressed, or the ASCII numerical value of the digit if one was pressed or\n"
1504 " -1 on error/hangup.\n";
1505
1506 static char usage_sayalpha[] =
1507 " Usage: SAY ALPHA <number> <escape digits>\n"
1508 "       Say a given character string, returning early if any of the given DTMF digits\n"
1509 " are received on the channel. Returns 0 if playback completes without a digit\n"
1510 " being pressed, or the ASCII numerical value of the digit if one was pressed or\n"
1511 " -1 on error/hangup.\n";
1512
1513 static char usage_saydate[] =
1514 " Usage: SAY DATE <date> <escape digits>\n"
1515 "       Say a given date, returning early if any of the given DTMF digits are\n"
1516 " received on the channel.  <date> is number of seconds elapsed since 00:00:00\n"
1517 " on January 1, 1970, Coordinated Universal Time (UTC). Returns 0 if playback\n"
1518 " completes without a digit being pressed, or the ASCII numerical value of the\n"
1519 " digit if one was pressed or -1 on error/hangup.\n";
1520
1521 static char usage_saytime[] =
1522 " Usage: SAY TIME <time> <escape digits>\n"
1523 "       Say a given time, returning early if any of the given DTMF digits are\n"
1524 " received on the channel.  <time> is number of seconds elapsed since 00:00:00\n"
1525 " on January 1, 1970, Coordinated Universal Time (UTC). Returns 0 if playback\n"
1526 " completes without a digit being pressed, or the ASCII numerical value of the\n"
1527 " digit if one was pressed or -1 on error/hangup.\n";
1528
1529 static char usage_saydatetime[] =
1530 " Usage: SAY DATETIME <time> <escape digits> [format] [timezone]\n"
1531 "       Say a given time, returning early if any of the given DTMF digits are\n"
1532 " received on the channel.  <time> is number of seconds elapsed since 00:00:00\n"
1533 " on January 1, 1970, Coordinated Universal Time (UTC). [format] is the format\n"
1534 " the time should be said in.  See voicemail.conf (defaults to \"ABdY\n"
1535 " 'digits/at' IMp\").  Acceptable values for [timezone] can be found in\n"
1536 " /usr/share/zoneinfo.  Defaults to machine default. Returns 0 if playback\n"
1537 " completes without a digit being pressed, or the ASCII numerical value of the\n"
1538 " digit if one was pressed or -1 on error/hangup.\n";
1539
1540 static char usage_sayphonetic[] =
1541 " Usage: SAY PHONETIC <string> <escape digits>\n"
1542 "       Say a given character string with phonetics, returning early if any of the\n"
1543 " given DTMF digits are received on the channel. Returns 0 if playback\n"
1544 " completes without a digit pressed, the ASCII numerical value of the digit\n"
1545 " if one was pressed, or -1 on error/hangup.\n";
1546
1547 static char usage_getdata[] =
1548 " Usage: GET DATA <file to be streamed> [timeout] [max digits]\n"
1549 "       Stream the given file, and recieve DTMF data. Returns the digits received\n"
1550 "from the channel at the other end.\n";
1551
1552 static char usage_setcontext[] =
1553 " Usage: SET CONTEXT <desired context>\n"
1554 "       Sets the context for continuation upon exiting the application.\n";
1555
1556 static char usage_setextension[] =
1557 " Usage: SET EXTENSION <new extension>\n"
1558 "       Changes the extension for continuation upon exiting the application.\n";
1559
1560 static char usage_setpriority[] =
1561 " Usage: SET PRIORITY <priority>\n"
1562 "       Changes the priority for continuation upon exiting the application.\n"
1563 " The priority must be a valid priority or label.\n";
1564
1565 static char usage_recordfile[] =
1566 " Usage: RECORD FILE <filename> <format> <escape digits> <timeout> \\\n"
1567 "                                          [offset samples] [BEEP] [s=silence]\n"
1568 "       Record to a file until a given dtmf digit in the sequence is received\n"
1569 " Returns -1 on hangup or error.  The format will specify what kind of file\n"
1570 " will be recorded.  The timeout is the maximum record time in milliseconds, or\n"
1571 " -1 for no timeout. \"Offset samples\" is optional, and, if provided, will seek\n"
1572 " to the offset without exceeding the end of the file.  \"silence\" is the number\n"
1573 " of seconds of silence allowed before the function returns despite the\n"
1574 " lack of dtmf digits or reaching timeout.  Silence value must be\n"
1575 " preceeded by \"s=\" and is also optional.\n";
1576
1577 static char usage_autohangup[] =
1578 " Usage: SET AUTOHANGUP <time>\n"
1579 "       Cause the channel to automatically hangup at <time> seconds in the\n"
1580 " future.  Of course it can be hungup before then as well. Setting to 0 will\n"
1581 " cause the autohangup feature to be disabled on this channel.\n";
1582
1583 static char usage_noop[] =
1584 " Usage: NoOp\n"
1585 "       Does nothing.\n";
1586
1587 /*!
1588  * \brief AGI commands list
1589  */
1590 static struct agi_command commands[] = {
1591         { { "answer", NULL }, handle_answer, "Answer channel", usage_answer , 0 },
1592         { { "channel", "status", NULL }, handle_channelstatus, "Returns status of the connected channel", usage_channelstatus , 0 },
1593         { { "database", "del", NULL }, handle_dbdel, "Removes database key/value", usage_dbdel , 1 },
1594         { { "database", "deltree", NULL }, handle_dbdeltree, "Removes database keytree/value", usage_dbdeltree , 1 },
1595         { { "database", "get", NULL }, handle_dbget, "Gets database value", usage_dbget , 1 },
1596         { { "database", "put", NULL }, handle_dbput, "Adds/updates database value", usage_dbput , 1 },
1597         { { "exec", NULL }, handle_exec, "Executes a given Application", usage_exec , 1 },
1598         { { "get", "data", NULL }, handle_getdata, "Prompts for DTMF on a channel", usage_getdata , 0 },
1599         { { "get", "full", "variable", NULL }, handle_getvariablefull, "Evaluates a channel expression", usage_getvariablefull , 1 },
1600         { { "get", "option", NULL }, handle_getoption, "Stream file, prompt for DTMF, with timeout", usage_getoption , 0 },
1601         { { "get", "variable", NULL }, handle_getvariable, "Gets a channel variable", usage_getvariable , 1 },
1602         { { "hangup", NULL }, handle_hangup, "Hangup the current channel", usage_hangup , 0 },
1603         { { "noop", NULL }, handle_noop, "Does nothing", usage_noop , 1 },
1604         { { "receive", "char", NULL }, handle_recvchar, "Receives one character from channels supporting it", usage_recvchar , 0 },
1605         { { "receive", "text", NULL }, handle_recvtext, "Receives text from channels supporting it", usage_recvtext , 0 },
1606         { { "record", "file", NULL }, handle_recordfile, "Records to a given file", usage_recordfile , 0 },
1607         { { "say", "alpha", NULL }, handle_sayalpha, "Says a given character string", usage_sayalpha , 0 },
1608         { { "say", "digits", NULL }, handle_saydigits, "Says a given digit string", usage_saydigits , 0 },
1609         { { "say", "number", NULL }, handle_saynumber, "Says a given number", usage_saynumber , 0 },
1610         { { "say", "phonetic", NULL }, handle_sayphonetic, "Says a given character string with phonetics", usage_sayphonetic , 0 },
1611         { { "say", "date", NULL }, handle_saydate, "Says a given date", usage_saydate , 0 },
1612         { { "say", "time", NULL }, handle_saytime, "Says a given time", usage_saytime , 0 },
1613         { { "say", "datetime", NULL }, handle_saydatetime, "Says a given time as specfied by the format given", usage_saydatetime , 0 },
1614         { { "send", "image", NULL }, handle_sendimage, "Sends images to channels supporting it", usage_sendimage , 0 },
1615         { { "send", "text", NULL }, handle_sendtext, "Sends text to channels supporting it", usage_sendtext , 0 },
1616         { { "set", "autohangup", NULL }, handle_autohangup, "Autohangup channel in some time", usage_autohangup , 0 },
1617         { { "set", "callerid", NULL }, handle_setcallerid, "Sets callerid for the current channel", usage_setcallerid , 0 },
1618         { { "set", "context", NULL }, handle_setcontext, "Sets channel context", usage_setcontext , 0 },
1619         { { "set", "extension", NULL }, handle_setextension, "Changes channel extension", usage_setextension , 0 },
1620         { { "set", "music", NULL }, handle_setmusic, "Enable/Disable Music on hold generator", usage_setmusic , 0 },
1621         { { "set", "priority", NULL }, handle_setpriority, "Set channel dialplan priority", usage_setpriority , 0 },
1622         { { "set", "variable", NULL }, handle_setvariable, "Sets a channel variable", usage_setvariable , 1 },
1623         { { "stream", "file", NULL }, handle_streamfile, "Sends audio file on channel", usage_streamfile , 0 },
1624         { { "control", "stream", "file", NULL }, handle_controlstreamfile, "Sends audio file on channel and allows the listner to control the stream", usage_controlstreamfile , 0 },
1625         { { "tdd", "mode", NULL }, handle_tddmode, "Toggles TDD mode (for the deaf)", usage_tddmode , 0 },
1626         { { "verbose", NULL }, handle_verbose, "Logs a message to the asterisk verbose log", usage_verbose , 1 },
1627         { { "wait", "for", "digit", NULL }, handle_waitfordigit, "Waits for a digit to be pressed", usage_waitfordigit , 0 },
1628 };
1629
1630 static AST_RWLIST_HEAD_STATIC(agi_commands, agi_command);
1631
1632 static char *help_workhorse(int fd, char *match[])
1633 {
1634         char fullcmd[80], matchstr[80];
1635         struct agi_command *e;
1636
1637         if (match)
1638                 ast_join(matchstr, sizeof(matchstr), match);
1639
1640         ast_cli(fd, "%5.5s %20.20s   %s\n","Dead","Command","Description");
1641         AST_RWLIST_RDLOCK(&agi_commands);
1642         AST_RWLIST_TRAVERSE(&agi_commands, e, list) {
1643                 if (!e->cmda[0])
1644                         break;
1645                 /* Hide commands that start with '_' */
1646                 if ((e->cmda[0])[0] == '_')
1647                         continue;
1648                 ast_join(fullcmd, sizeof(fullcmd), e->cmda);
1649                 if (match && strncasecmp(matchstr, fullcmd, strlen(matchstr)))
1650                         continue;
1651                 ast_cli(fd, "%5.5s %20.20s   %s\n", e->dead ? "Yes" : "No" , fullcmd, e->summary);
1652         }
1653         AST_RWLIST_UNLOCK(&agi_commands);
1654
1655         return CLI_SUCCESS;
1656 }
1657
1658 int ast_agi_register(struct ast_module *mod, agi_command *cmd)
1659 {
1660         char fullcmd[80];
1661
1662         ast_join(fullcmd, sizeof(fullcmd), cmd->cmda);
1663
1664         if (!find_command(cmd->cmda,1)) {
1665                 cmd->mod = mod;
1666                 AST_RWLIST_WRLOCK(&agi_commands);
1667                 AST_LIST_INSERT_TAIL(&agi_commands, cmd, list);
1668                 AST_RWLIST_UNLOCK(&agi_commands);
1669                 if (mod != ast_module_info->self)
1670                         ast_module_ref(ast_module_info->self);
1671                 ast_verb(2, "AGI Command '%s' registered\n",fullcmd);
1672                 return 1;
1673         } else {
1674                 ast_log(LOG_WARNING, "Command already registered!\n");
1675                 return 0;
1676         }
1677 }
1678
1679 int ast_agi_unregister(struct ast_module *mod, agi_command *cmd)
1680 {
1681         struct agi_command *e;
1682         int unregistered = 0;
1683         char fullcmd[80];
1684         
1685         ast_join(fullcmd, sizeof(fullcmd), cmd->cmda);
1686
1687         AST_RWLIST_WRLOCK(&agi_commands);
1688         AST_RWLIST_TRAVERSE_SAFE_BEGIN(&agi_commands, e, list) {
1689                 if (cmd == e) {
1690                         AST_RWLIST_REMOVE_CURRENT(list);
1691                         if (mod != ast_module_info->self)
1692                                 ast_module_unref(ast_module_info->self);
1693                         unregistered=1;
1694                         break;
1695                 }
1696         }
1697         AST_RWLIST_TRAVERSE_SAFE_END;
1698         AST_RWLIST_UNLOCK(&agi_commands);
1699         if (unregistered)
1700                 ast_verb(2, "AGI Command '%s' unregistered\n",fullcmd);
1701         else
1702                 ast_log(LOG_WARNING, "Unable to unregister command: '%s'!\n",fullcmd);
1703         return unregistered;
1704 }
1705
1706 void ast_agi_register_multiple(struct ast_module *mod, agi_command *cmd, int len)
1707 {
1708         int i;
1709
1710         for (i = 0; i < len; i++)
1711                 ast_agi_register(mod, cmd + i);
1712
1713 }
1714
1715 void ast_agi_unregister_multiple(struct ast_module *mod, agi_command *cmd, int len)
1716 {
1717         int i;
1718
1719         for (i = 0; i < len; i++)
1720                 ast_agi_unregister(mod, cmd + i);
1721 }
1722
1723 static agi_command *find_command(char *cmds[], int exact)
1724 {
1725         int y, match;
1726         struct agi_command *e;
1727
1728         AST_RWLIST_RDLOCK(&agi_commands);
1729         AST_RWLIST_TRAVERSE(&agi_commands, e, list) {
1730                 if (!e->cmda[0])
1731                         break;
1732                 /* start optimistic */
1733                 match = 1;
1734                 for (y = 0; match && cmds[y]; y++) {
1735                         /* If there are no more words in the command (and we're looking for
1736                            an exact match) or there is a difference between the two words,
1737                            then this is not a match */
1738                         if (!e->cmda[y] && !exact)
1739                                 break;
1740                         /* don't segfault if the next part of a command doesn't exist */
1741                         if (!e->cmda[y])
1742                                 return NULL;
1743                         if (strcasecmp(e->cmda[y], cmds[y]))
1744                                 match = 0;
1745                 }
1746                 /* If more words are needed to complete the command then this is not
1747                    a candidate (unless we're looking for a really inexact answer  */
1748                 if ((exact > -1) && e->cmda[y])
1749                         match = 0;
1750                 if (match)
1751                         return e;
1752         }
1753         AST_RWLIST_UNLOCK(&agi_commands);
1754         return NULL;
1755 }
1756
1757 static int parse_args(char *s, int *max, char *argv[])
1758 {
1759         int x = 0, quoted = 0, escaped = 0, whitespace = 1;
1760         char *cur;
1761
1762         cur = s;
1763         while(*s) {
1764                 switch(*s) {
1765                 case '"':
1766                         /* If it's escaped, put a literal quote */
1767                         if (escaped) 
1768                                 goto normal;
1769                         else 
1770                                 quoted = !quoted;
1771                         if (quoted && whitespace) {
1772                                 /* If we're starting a quote, coming off white space start a new word, too */
1773                                 argv[x++] = cur;
1774                                 whitespace=0;
1775                         }
1776                         escaped = 0;
1777                 break;
1778                 case ' ':
1779                 case '\t':
1780                         if (!quoted && !escaped) {
1781                                 /* If we're not quoted, mark this as whitespace, and
1782                                    end the previous argument */
1783                                 whitespace = 1;
1784                                 *(cur++) = '\0';
1785                         } else
1786                                 /* Otherwise, just treat it as anything else */ 
1787                                 goto normal;
1788                         break;
1789                 case '\\':
1790                         /* If we're escaped, print a literal, otherwise enable escaping */
1791                         if (escaped) {
1792                                 goto normal;
1793                         } else {
1794                                 escaped=1;
1795                         }
1796                         break;
1797                 default:
1798 normal:
1799                         if (whitespace) {
1800                                 if (x >= MAX_ARGS -1) {
1801                                         ast_log(LOG_WARNING, "Too many arguments, truncating\n");
1802                                         break;
1803                                 }
1804                                 /* Coming off of whitespace, start the next argument */
1805                                 argv[x++] = cur;
1806                                 whitespace=0;
1807                         }
1808                         *(cur++) = *s;
1809                         escaped=0;
1810                 }
1811                 s++;
1812         }
1813         /* Null terminate */
1814         *(cur++) = '\0';
1815         argv[x] = NULL;
1816         *max = x;
1817         return 0;
1818 }
1819
1820 static int agi_handle_command(struct ast_channel *chan, AGI *agi, char *buf, int dead)
1821 {
1822         char *argv[MAX_ARGS];
1823         int argc = MAX_ARGS, res;
1824         agi_command *c;
1825
1826         parse_args(buf, &argc, argv);
1827         if ((c = find_command(argv, 0)) && (!dead || (dead && c->dead))) {
1828                 /* if this command wasnt registered by res_agi, be sure to usecount
1829                 the module we are using */
1830                 if (c->mod != ast_module_info->self)
1831                         ast_module_ref(c->mod);
1832                 res = c->handler(chan, agi, argc, argv);
1833                 if (c->mod != ast_module_info->self)
1834                         ast_module_unref(c->mod);
1835                 switch(res) {
1836                 case RESULT_SHOWUSAGE:
1837                         ast_agi_fdprintf(chan, agi->fd, "520-Invalid command syntax.  Proper usage follows:\n");
1838                         ast_agi_fdprintf(chan, agi->fd, c->usage);
1839                         ast_agi_fdprintf(chan, agi->fd, "520 End of proper usage.\n");
1840                         break;
1841                 case AST_PBX_KEEPALIVE:
1842                         /* We've been asked to keep alive, so do so */
1843                         return AST_PBX_KEEPALIVE;
1844                         break;
1845                 case RESULT_FAILURE:
1846                         /* They've already given the failure.  We've been hung up on so handle this
1847                            appropriately */
1848                         return -1;
1849                 }
1850         } else if ((c = find_command(argv, 0))) {
1851                 ast_agi_fdprintf(chan, agi->fd, "511 Command Not Permitted on a dead channel\n");
1852         } else {
1853                 ast_agi_fdprintf(chan, agi->fd, "510 Invalid or unknown command\n");
1854         }
1855         return 0;
1856 }
1857 static enum agi_result run_agi(struct ast_channel *chan, char *request, AGI *agi, int pid, int *status, int dead, int argc, char *argv[])
1858 {
1859         struct ast_channel *c;
1860         int outfd, ms, needhup = 0;
1861         enum agi_result returnstatus = AGI_RESULT_SUCCESS;
1862         struct ast_frame *f;
1863         char buf[AGI_BUF_LEN];
1864         char *res = NULL;
1865         FILE *readf;
1866         /* how many times we'll retry if ast_waitfor_nandfs will return without either 
1867           channel or file descriptor in case select is interrupted by a system call (EINTR) */
1868         int retry = AGI_NANDFS_RETRY;
1869
1870         if (!(readf = fdopen(agi->ctrl, "r"))) {
1871                 ast_log(LOG_WARNING, "Unable to fdopen file descriptor\n");
1872                 if (pid > -1)
1873                         kill(pid, SIGHUP);
1874                 close(agi->ctrl);
1875                 return AGI_RESULT_FAILURE;
1876         }
1877         setlinebuf(readf);
1878         setup_env(chan, request, agi->fd, (agi->audio > -1), argc, argv);
1879         for (;;) {
1880                 if (needhup) {
1881                         needhup = 0;
1882                         dead = 1;
1883                         kill(pid, SIGHUP);
1884                 }
1885                 ms = -1;
1886                 c = ast_waitfor_nandfds(&chan, dead ? 0 : 1, &agi->ctrl, 1, NULL, &outfd, &ms);
1887                 if (c) {
1888                         retry = AGI_NANDFS_RETRY;
1889                         /* Idle the channel until we get a command */
1890                         f = ast_read(c);
1891                         if (!f) {
1892                                 ast_debug(1, "%s hungup\n", chan->name);
1893                                 returnstatus = AGI_RESULT_HANGUP;
1894                                 needhup = 1;
1895                                 continue;
1896                         } else {
1897                                 /* If it's voice, write it to the audio pipe */
1898                                 if ((agi->audio > -1) && (f->frametype == AST_FRAME_VOICE)) {
1899                                         /* Write, ignoring errors */
1900                                         write(agi->audio, f->data, f->datalen);
1901                                 }
1902                                 ast_frfree(f);
1903                         }
1904                 } else if (outfd > -1) {
1905                         size_t len = sizeof(buf);
1906                         size_t buflen = 0;
1907
1908                         retry = AGI_NANDFS_RETRY;
1909                         buf[0] = '\0';
1910
1911                         while (buflen < (len - 1)) {
1912                                 res = fgets(buf + buflen, len, readf);
1913                                 if (feof(readf)) 
1914                                         break;
1915                                 if (ferror(readf) && ((errno != EINTR) && (errno != EAGAIN))) 
1916                                         break;
1917                                 if (res != NULL && !agi->fast)
1918                                         break;
1919                                 buflen = strlen(buf);
1920                                 if (buflen && buf[buflen - 1] == '\n')
1921                                         break;
1922                                 len -= buflen;
1923                                 if (agidebug)
1924                                         ast_verbose( "AGI Rx << temp buffer %s - errno %s\n", buf, strerror(errno));
1925                         }
1926
1927                         if (!buf[0]) {
1928                                 /* Program terminated */
1929                                 if (returnstatus && returnstatus != AST_PBX_KEEPALIVE)
1930                                         returnstatus = -1;
1931                                 ast_verb(3, "<%s>AGI Script %s completed, returning %d\n", chan->name, request, returnstatus);
1932                                 if (pid > 0)
1933                                         waitpid(pid, status, 0);
1934                                 /* No need to kill the pid anymore, since they closed us */
1935                                 pid = -1;
1936                                 break;
1937                         }
1938
1939                         /* get rid of trailing newline, if any */
1940                         if (*buf && buf[strlen(buf) - 1] == '\n')
1941                                 buf[strlen(buf) - 1] = 0;
1942                         if (agidebug)
1943                                 ast_verbose("<%s>AGI Rx << %s\n", chan->name, buf);
1944                         returnstatus |= agi_handle_command(chan, agi, buf, dead);
1945                         /* If the handle_command returns -1, we need to stop */
1946                         if ((returnstatus < 0) || (returnstatus == AST_PBX_KEEPALIVE)) {
1947                                 needhup = 1;
1948                                 continue;
1949                         }
1950                 } else {
1951                         if (--retry <= 0) {
1952                                 ast_log(LOG_WARNING, "No channel, no fd?\n");
1953                                 returnstatus = AGI_RESULT_FAILURE;
1954                                 break;
1955                         }
1956                 }
1957         }
1958         /* Notify process */
1959         if (pid > -1) {
1960                 const char *sighup = pbx_builtin_getvar_helper(chan, "AGISIGHUP");
1961                 if (ast_strlen_zero(sighup) || !ast_false(sighup)) {
1962                         if (kill(pid, SIGHUP))
1963                                 ast_log(LOG_WARNING, "unable to send SIGHUP to AGI process %d: %s\n", pid, strerror(errno));
1964                 }
1965         }
1966         fclose(readf);
1967         return returnstatus;
1968 }
1969
1970 static char *handle_cli_agi_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1971 {
1972         struct agi_command *command;
1973         char fullcmd[80];
1974
1975         switch (cmd) {
1976         case CLI_INIT:
1977                 e->command = "agi show";
1978                 e->usage =
1979                         "Usage: agi show [topic]\n"
1980                         "       When called with a topic as an argument, displays usage\n"
1981                         "       information on the given command.  If called without a\n"
1982                         "       topic, it provides a list of AGI commands.\n";
1983                 break;
1984         case CLI_GENERATE:
1985                 return NULL;
1986         }
1987         if (a->argc < e->args)
1988                 return CLI_SHOWUSAGE;
1989         if (a->argc > e->args) {
1990                 command = find_command(a->argv + e->args, 1);
1991                 if (command) {
1992                         ast_cli(a->fd, command->usage);
1993                         ast_cli(a->fd, " Runs Dead : %s\n", command->dead ? "Yes" : "No");
1994                 } else {
1995                         if (find_command(a->argv + e->args, -1)) {
1996                                 return help_workhorse(a->fd, a->argv + e->args);
1997                         } else {
1998                                 ast_join(fullcmd, sizeof(fullcmd), a->argv + e->args);
1999                                 ast_cli(a->fd, "No such command '%s'.\n", fullcmd);
2000                         }
2001                 }
2002         } else {
2003                 return help_workhorse(a->fd, NULL);
2004         }
2005         return CLI_SUCCESS;
2006 }
2007
2008 /*! \brief Convert string to use HTML escaped characters
2009         \note Maybe this should be a generic function?
2010 */
2011 static void write_html_escaped(FILE *htmlfile, char *str)
2012 {
2013         char *cur = str;
2014
2015         while(*cur) {
2016                 switch (*cur) {
2017                 case '<':
2018                         fprintf(htmlfile, "%s", "&lt;");
2019                         break;
2020                 case '>':
2021                         fprintf(htmlfile, "%s", "&gt;");
2022                         break;
2023                 case '&':
2024                         fprintf(htmlfile, "%s", "&amp;");
2025                         break;
2026                 case '"':
2027                         fprintf(htmlfile, "%s", "&quot;");
2028                         break;
2029                 default:
2030                         fprintf(htmlfile, "%c", *cur);
2031                         break;
2032                 }
2033                 cur++;
2034         }
2035
2036         return;
2037 }
2038
2039 static char *handle_cli_agi_dumphtml(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2040 {
2041         struct agi_command *command;
2042         char fullcmd[80];
2043         FILE *htmlfile;
2044
2045         switch (cmd) {
2046         case CLI_INIT:
2047                 e->command = "agi dumphtml";
2048                 e->usage =
2049                         "Usage: agi dumphtml <filename>\n"
2050                         "       Dumps the AGI command list in HTML format to the given\n"
2051                         "       file.\n";
2052                 return NULL;
2053         case CLI_GENERATE:
2054                 return NULL;
2055         }
2056         if (a->argc < e->args + 1)
2057                 return CLI_SHOWUSAGE;
2058
2059         if (!(htmlfile = fopen(a->argv[2], "wt"))) {
2060                 ast_cli(a->fd, "Could not create file '%s'\n", a->argv[2]);
2061                 return CLI_SHOWUSAGE;
2062         }
2063
2064         fprintf(htmlfile, "<HTML>\n<HEAD>\n<TITLE>AGI Commands</TITLE>\n</HEAD>\n");
2065         fprintf(htmlfile, "<BODY>\n<CENTER><B><H1>AGI Commands</H1></B></CENTER>\n\n");
2066         fprintf(htmlfile, "<TABLE BORDER=\"0\" CELLSPACING=\"10\">\n");
2067
2068         AST_RWLIST_RDLOCK(&agi_commands);
2069         AST_RWLIST_TRAVERSE(&agi_commands, command, list) {
2070                 char *stringp, *tempstr;
2071  
2072                 if (!command->cmda[0])  /* end ? */
2073                         break;
2074                 /* Hide commands that start with '_' */
2075                 if ((command->cmda[0])[0] == '_')
2076                         continue;
2077                 ast_join(fullcmd, sizeof(fullcmd), command->cmda);
2078
2079                 fprintf(htmlfile, "<TR><TD><TABLE BORDER=\"1\" CELLPADDING=\"5\" WIDTH=\"100%%\">\n");
2080                 fprintf(htmlfile, "<TR><TH ALIGN=\"CENTER\"><B>%s - %s</B></TH></TR>\n", fullcmd, command->summary);
2081
2082                 stringp = command->usage;
2083                 tempstr = strsep(&stringp, "\n");
2084
2085                 fprintf(htmlfile, "<TR><TD ALIGN=\"CENTER\">");
2086                 write_html_escaped(htmlfile, tempstr);
2087                 fprintf(htmlfile, "</TD></TR>\n");
2088                 fprintf(htmlfile, "<TR><TD ALIGN=\"CENTER\">\n");
2089
2090                 while ((tempstr = strsep(&stringp, "\n")) != NULL) {
2091                         write_html_escaped(htmlfile, tempstr);
2092                         fprintf(htmlfile, "<BR>\n");
2093                 }
2094                 fprintf(htmlfile, "</TD></TR>\n");
2095                 fprintf(htmlfile, "</TABLE></TD></TR>\n\n");
2096         }
2097         AST_RWLIST_UNLOCK(&agi_commands);
2098         fprintf(htmlfile, "</TABLE>\n</BODY>\n</HTML>\n");
2099         fclose(htmlfile);
2100         ast_cli(a->fd, "AGI HTML commands dumped to: %s\n", a->argv[2]);
2101         return CLI_SUCCESS;
2102 }
2103
2104 static int agi_exec_full(struct ast_channel *chan, void *data, int enhanced, int dead)
2105 {
2106         enum agi_result res;
2107         struct ast_module_user *u;
2108         char buf[AGI_BUF_LEN] = "", *tmp = buf;
2109         int fds[2], efd = -1, pid;
2110         AST_DECLARE_APP_ARGS(args,
2111                 AST_APP_ARG(arg)[MAX_ARGS];
2112         );
2113         AGI agi;
2114
2115         if (ast_strlen_zero(data)) {
2116                 ast_log(LOG_WARNING, "AGI requires an argument (script)\n");
2117                 return -1;
2118         }
2119         if (dead)
2120                 ast_log(LOG_NOTICE, "Hungup channel detected, running agi in dead mode.");
2121         ast_copy_string(buf, data, sizeof(buf));
2122         memset(&agi, 0, sizeof(agi));
2123         AST_STANDARD_APP_ARGS(args, tmp);
2124         args.argv[args.argc] = NULL;
2125
2126         u = ast_module_user_add(chan);
2127 #if 0
2128          /* Answer if need be */
2129         if (chan->_state != AST_STATE_UP) {
2130                 if (ast_answer(chan)) {
2131                         LOCAL_USER_REMOVE(u);
2132                         return -1;
2133                 }
2134         }
2135 #endif
2136         res = launch_script(args.argv[0], args.argv, fds, enhanced ? &efd : NULL, &pid);
2137         if (res == AGI_RESULT_SUCCESS || res == AGI_RESULT_SUCCESS_FAST) {
2138                 int status = 0;
2139                 agi.fd = fds[1];
2140                 agi.ctrl = fds[0];
2141                 agi.audio = efd;
2142                 agi.fast = (res == AGI_RESULT_SUCCESS_FAST) ? 1 : 0;
2143                 res = run_agi(chan, args.argv[0], &agi, pid, &status, dead, args.argc, args.argv);
2144                 /* If the fork'd process returns non-zero, set AGISTATUS to FAILURE */
2145                 if ((res == AGI_RESULT_SUCCESS || res == AGI_RESULT_SUCCESS_FAST) && status)
2146                         res = AGI_RESULT_FAILURE;
2147                 if (fds[1] != fds[0])
2148                         close(fds[1]);
2149                 if (efd > -1)
2150                         close(efd);
2151                 ast_unreplace_sigchld();
2152         }
2153         ast_module_user_remove(u);
2154
2155         switch (res) {
2156         case AGI_RESULT_SUCCESS:
2157         case AGI_RESULT_SUCCESS_FAST:
2158                 pbx_builtin_setvar_helper(chan, "AGISTATUS", "SUCCESS");
2159                 break;
2160         case AGI_RESULT_FAILURE:
2161                 pbx_builtin_setvar_helper(chan, "AGISTATUS", "FAILURE");
2162                 break;
2163         case AGI_RESULT_NOTFOUND:
2164                 pbx_builtin_setvar_helper(chan, "AGISTATUS", "NOTFOUND");
2165                 break;
2166         case AGI_RESULT_HANGUP:
2167                 pbx_builtin_setvar_helper(chan, "AGISTATUS", "HANGUP");
2168                 return -1;
2169         }
2170
2171         return 0;
2172 }
2173
2174 static int agi_exec(struct ast_channel *chan, void *data)
2175 {
2176         if (!ast_check_hangup(chan))
2177                 return agi_exec_full(chan, data, 0, 0);
2178         else
2179                 return agi_exec_full(chan, data, 0, 1);
2180 }
2181
2182 static int eagi_exec(struct ast_channel *chan, void *data)
2183 {
2184         int readformat, res;
2185
2186         if (ast_check_hangup(chan)) {
2187                 ast_log(LOG_ERROR, "If you want to run AGI on hungup channels you should use DeadAGI!\n");
2188                 return 0;
2189         }
2190         readformat = chan->readformat;
2191         if (ast_set_read_format(chan, AST_FORMAT_SLINEAR)) {
2192                 ast_log(LOG_WARNING, "Unable to set channel '%s' to linear mode\n", chan->name);
2193                 return -1;
2194         }
2195         res = agi_exec_full(chan, data, 1, 0);
2196         if (!res) {
2197                 if (ast_set_read_format(chan, readformat)) {
2198                         ast_log(LOG_WARNING, "Unable to restore channel '%s' to format %s\n", chan->name, ast_getformatname(readformat));
2199                 }
2200         }
2201         return res;
2202 }
2203
2204 static int deadagi_exec(struct ast_channel *chan, void *data)
2205 {
2206         ast_log(LOG_WARNING, "DeadAGI has been deprecated, please use AGI in all cases!");
2207         return agi_exec(chan, data);
2208 }
2209
2210 static struct ast_cli_entry cli_agi[] = {
2211         AST_CLI_DEFINE(handle_cli_agi_debug,    "Enable/Disable AGI debugging"),
2212         AST_CLI_DEFINE(handle_cli_agi_show,     "List AGI commands or specific help"),
2213         AST_CLI_DEFINE(handle_cli_agi_dumphtml, "Dumps a list of AGI commands in HTML format")
2214 };
2215
2216 static int unload_module(void)
2217 {
2218         ast_cli_unregister_multiple(cli_agi, sizeof(cli_agi) / sizeof(struct ast_cli_entry));
2219         ast_agi_unregister_multiple(ast_module_info->self, commands, sizeof(commands) / sizeof(struct agi_command));
2220         ast_unregister_application(eapp);
2221         ast_unregister_application(deadapp);
2222         return ast_unregister_application(app);
2223 }
2224
2225 static int load_module(void)
2226 {
2227         ast_cli_register_multiple(cli_agi, sizeof(cli_agi) / sizeof(struct ast_cli_entry));
2228         ast_agi_register_multiple(ast_module_info->self, commands, sizeof(commands) / sizeof(struct agi_command));
2229         ast_register_application(deadapp, deadagi_exec, deadsynopsis, descrip);
2230         ast_register_application(eapp, eagi_exec, esynopsis, descrip);
2231         return ast_register_application(app, agi_exec, synopsis, descrip);
2232 }
2233
2234 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS, "Asterisk Gateway Interface (AGI)",
2235                 .load = load_module,
2236                 .unload = unload_module,
2237                 );