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