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