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