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