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