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