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