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