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