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