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