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