2 * Asterisk -- A telephony toolkit for Linux.
4 * Asterisk Gateway Interface
6 * Copyright (C) 1999 - 2005, Digium, Inc.
8 * Mark Spencer <markster@digium.com>
10 * This program is free software, distributed under the terms of
11 * the GNU General Public License
14 #include <sys/types.h>
16 #include <sys/socket.h>
17 #include <netinet/in.h>
18 #include <netinet/tcp.h>
19 #include <arpa/inet.h>
20 #include "asterisk/file.h"
21 #include "asterisk/logger.h"
22 #include "asterisk/channel.h"
23 #include "asterisk/pbx.h"
24 #include "asterisk/module.h"
25 #include "asterisk/astdb.h"
26 #include "asterisk/callerid.h"
37 #include "asterisk/cli.h"
38 #include "asterisk/logger.h"
39 #include "asterisk/options.h"
40 #include "asterisk/image.h"
41 #include "asterisk/say.h"
42 #include "asterisk/app.h"
43 #include "asterisk/dsp.h"
44 #include "asterisk/musiconhold.h"
45 #include "asterisk/manager.h"
46 #include "asterisk/utils.h"
47 #include "asterisk/lock.h"
48 #include "asterisk/agi.h"
51 #include "asterisk/astmm.h"
55 #define MAX_COMMANDS 128
57 /* Recycle some stuff from the CLI interface */
58 #define fdprintf agi_debug_cli
60 static char *tdesc = "Asterisk Gateway Interface (AGI)";
62 static char *app = "AGI";
64 static char *eapp = "EAGI";
66 static char *deadapp = "DeadAGI";
68 static char *synopsis = "Executes an AGI compliant application";
69 static char *esynopsis = "Executes an EAGI compliant application";
70 static char *deadsynopsis = "Executes AGI on a hungup channel";
72 static char *descrip =
73 " [E|Dead]AGI(command|args): Executes an Asterisk Gateway Interface compliant\n"
74 "program on a channel. AGI allows Asterisk to launch external programs\n"
75 "written in any language to control a telephony channel, play audio,\n"
76 "read DTMF digits, etc. by communicating with the AGI protocol on stdin\n"
78 "Returns -1 on hangup (except for DeadAGI) or if application requested\n"
79 " hangup, or 0 on non-hangup exit. \n"
80 "Using 'EAGI' provides enhanced AGI, with incoming audio available out of band"
81 "on file descriptor 3\n\n"
82 "Use the CLI command 'show agi' to list available agi commands\n";
84 static int agidebug = 0;
91 #define TONE_BLOCK_SIZE 200
93 /* Max time to connect to an AGI remote host */
94 #define MAX_AGI_CONNECT 2000
98 static void agi_debug_cli(int fd, char *fmt, ...)
105 res = vasprintf(&stuff, fmt, ap);
108 ast_log(LOG_ERROR, "Out of memory\n");
111 ast_verbose("AGI Tx >> %s", stuff);
112 ast_carefulwrite(fd, stuff, strlen(stuff), 100);
117 /* launch_netscript: The fastagi handler.
118 FastAGI defaults to port 4573 */
119 static int launch_netscript(char *agiurl, char *argv[], int *fds, int *efd, int *opid)
123 struct pollfd pfds[1];
125 char *c; int port = AGI_PORT;
127 struct sockaddr_in sin;
129 struct ast_hostent ahp;
131 host = ast_strdupa(agiurl + 6); /* Remove agi:// */
134 /* Strip off any script name */
135 if ((c = strchr(host, '/'))) {
140 if ((c = strchr(host, ':'))) {
146 ast_log(LOG_WARNING, "AGI URI's don't support Enhanced AGI yet\n");
149 hp = ast_gethostbyname(host, &ahp);
151 ast_log(LOG_WARNING, "Unable to locate host '%s'\n", host);
154 s = socket(AF_INET, SOCK_STREAM, 0);
156 ast_log(LOG_WARNING, "Unable to create socket: %s\n", strerror(errno));
159 flags = fcntl(s, F_GETFL);
161 ast_log(LOG_WARNING, "Fcntl(F_GETFL) failed: %s\n", strerror(errno));
165 if (fcntl(s, F_SETFL, flags | O_NONBLOCK) < 0) {
166 ast_log(LOG_WARNING, "Fnctl(F_SETFL) failed: %s\n", strerror(errno));
170 memset(&sin, 0, sizeof(sin));
171 sin.sin_family = AF_INET;
172 sin.sin_port = htons(port);
173 memcpy(&sin.sin_addr, hp->h_addr, sizeof(sin.sin_addr));
174 if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) && (errno != EINPROGRESS)) {
175 ast_log(LOG_WARNING, "Connect failed with unexpected error: %s\n", strerror(errno));
180 pfds[0].events = POLLOUT;
181 if (poll(pfds, 1, MAX_AGI_CONNECT) != 1) {
182 ast_log(LOG_WARNING, "Connect to '%s' failed!\n", agiurl);
186 if (write(s, "agi_network: yes\n", strlen("agi_network: yes\n")) < 0) {
187 ast_log(LOG_WARNING, "Connect to '%s' failed: %s\n", agiurl, strerror(errno));
192 /* If we have a script parameter, relay it to the fastagi server */
193 if (!ast_strlen_zero(script))
194 fdprintf(s, "agi_network_script: %s\n", script);
196 if (option_debug > 3)
197 ast_log(LOG_DEBUG, "Wow, connected!\n");
204 static int launch_script(char *script, char *argv[], int *fds, int *efd, int *opid)
214 if (!strncasecmp(script, "agi://", 6))
215 return launch_netscript(script, argv, fds, efd, opid);
217 if (script[0] != '/') {
218 snprintf(tmp, sizeof(tmp), "%s/%s", (char *)ast_config_AST_AGI_DIR, script);
222 ast_log(LOG_WARNING, "Unable to create toast pipe: %s\n",strerror(errno));
226 ast_log(LOG_WARNING, "unable to create fromast pipe: %s\n", strerror(errno));
233 ast_log(LOG_WARNING, "unable to create audio pipe: %s\n", strerror(errno));
240 res = fcntl(audio[1], F_GETFL);
242 res = fcntl(audio[1], F_SETFL, res | O_NONBLOCK);
244 ast_log(LOG_WARNING, "unable to set audio pipe parameters: %s\n", strerror(errno));
256 ast_log(LOG_WARNING, "Failed to fork(): %s\n", strerror(errno));
260 /* Redirect stdin and out, provide enhanced audio channel if desired */
261 dup2(fromast[0], STDIN_FILENO);
262 dup2(toast[1], STDOUT_FILENO);
264 dup2(audio[0], STDERR_FILENO + 1);
266 close(STDERR_FILENO + 1);
268 /* Close everything but stdin/out/error */
269 for (x=STDERR_FILENO + 2;x<1024;x++)
273 /* Can't use ast_log since FD's are closed */
274 fprintf(stderr, "Failed to execute '%s': %s\n", script, strerror(errno));
277 if (option_verbose > 2)
278 ast_verbose(VERBOSE_PREFIX_3 "Launched AGI Script %s\n", script);
284 /* close what we're not using in the parent */
298 static void setup_env(struct ast_channel *chan, char *request, int fd, int enhanced)
300 /* Print initial environment, with agi_request always being the first
302 fdprintf(fd, "agi_request: %s\n", request);
303 fdprintf(fd, "agi_channel: %s\n", chan->name);
304 fdprintf(fd, "agi_language: %s\n", chan->language);
305 fdprintf(fd, "agi_type: %s\n", chan->type);
306 fdprintf(fd, "agi_uniqueid: %s\n", chan->uniqueid);
309 fdprintf(fd, "agi_callerid: %s\n", chan->cid.cid_num ? chan->cid.cid_num : "unknown");
310 fdprintf(fd, "agi_calleridname: %s\n", chan->cid.cid_name ? chan->cid.cid_name : "unknown");
311 fdprintf(fd, "agi_callingpres: %d\n", chan->cid.cid_pres);
312 fdprintf(fd, "agi_callingani2: %d\n", chan->cid.cid_ani2);
313 fdprintf(fd, "agi_callington: %d\n", chan->cid.cid_ton);
314 fdprintf(fd, "agi_callingtns: %d\n", chan->cid.cid_tns);
315 fdprintf(fd, "agi_dnid: %s\n", chan->cid.cid_dnid ? chan->cid.cid_dnid : "unknown");
316 fdprintf(fd, "agi_rdnis: %s\n", chan->cid.cid_rdnis ? chan->cid.cid_rdnis : "unknown");
318 /* Context information */
319 fdprintf(fd, "agi_context: %s\n", chan->context);
320 fdprintf(fd, "agi_extension: %s\n", chan->exten);
321 fdprintf(fd, "agi_priority: %d\n", chan->priority);
322 fdprintf(fd, "agi_enhanced: %s\n", enhanced ? "1.0" : "0.0");
324 /* User information */
325 fdprintf(fd, "agi_accountcode: %s\n", chan->accountcode ? chan->accountcode : "");
327 /* End with empty return */
331 static int handle_answer(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
335 if (chan->_state != AST_STATE_UP) {
336 /* Answer the chan */
337 res = ast_answer(chan);
339 fdprintf(agi->fd, "200 result=%d\n", res);
341 return RESULT_SUCCESS;
343 return RESULT_FAILURE;
346 static int handle_waitfordigit(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
351 return RESULT_SHOWUSAGE;
352 if (sscanf(argv[3], "%d", &to) != 1)
353 return RESULT_SHOWUSAGE;
354 res = ast_waitfordigit_full(chan, to, agi->audio, agi->ctrl);
355 fdprintf(agi->fd, "200 result=%d\n", res);
357 return RESULT_SUCCESS;
359 return RESULT_FAILURE;
362 static int handle_sendtext(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
366 return RESULT_SHOWUSAGE;
367 /* At the moment, the parser (perhaps broken) returns with
368 the last argument PLUS the newline at the end of the input
369 buffer. This probably needs to be fixed, but I wont do that
370 because other stuff may break as a result. The right way
371 would probably be to strip off the trailing newline before
372 parsing, then here, add a newline at the end of the string
373 before sending it to ast_sendtext --DUDE */
374 res = ast_sendtext(chan, argv[2]);
375 fdprintf(agi->fd, "200 result=%d\n", res);
377 return RESULT_SUCCESS;
379 return RESULT_FAILURE;
382 static int handle_recvchar(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
386 return RESULT_SHOWUSAGE;
387 res = ast_recvchar(chan,atoi(argv[2]));
389 fdprintf(agi->fd, "200 result=%d (timeout)\n", res);
390 return RESULT_SUCCESS;
393 fdprintf(agi->fd, "200 result=%d\n", res);
394 return RESULT_SUCCESS;
397 fdprintf(agi->fd, "200 result=%d (hangup)\n", res);
398 return RESULT_FAILURE;
402 static int handle_tddmode(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
406 return RESULT_SHOWUSAGE;
407 if (!strncasecmp(argv[2],"on",2))
411 if (!strncasecmp(argv[2],"mate",4))
413 if (!strncasecmp(argv[2],"tdd",3))
415 res = ast_channel_setoption(chan, AST_OPTION_TDD, &x, sizeof(char), 0);
416 if(res != RESULT_SUCCESS)
417 fdprintf(agi->fd, "200 result=0\n");
419 fdprintf(agi->fd, "200 result=1\n");
420 return RESULT_SUCCESS;
423 static int handle_sendimage(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
427 return RESULT_SHOWUSAGE;
428 res = ast_send_image(chan, argv[2]);
429 if (!ast_check_hangup(chan))
431 fdprintf(agi->fd, "200 result=%d\n", res);
433 return RESULT_SUCCESS;
435 return RESULT_FAILURE;
438 static int handle_streamfile(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
441 struct ast_filestream *fs;
442 long sample_offset = 0;
446 return RESULT_SHOWUSAGE;
448 return RESULT_SHOWUSAGE;
449 if ((argc > 4) && (sscanf(argv[4], "%ld", &sample_offset) != 1))
450 return RESULT_SHOWUSAGE;
452 fs = ast_openstream(chan, argv[2], chan->language);
454 fdprintf(agi->fd, "200 result=%d endpos=%ld\n", 0, sample_offset);
455 return RESULT_SUCCESS;
457 ast_seekstream(fs, 0, SEEK_END);
458 max_length = ast_tellstream(fs);
459 ast_seekstream(fs, sample_offset, SEEK_SET);
460 res = ast_applystream(chan, fs);
461 res = ast_playstream(fs);
463 fdprintf(agi->fd, "200 result=%d endpos=%ld\n", res, sample_offset);
465 return RESULT_SHOWUSAGE;
467 return RESULT_FAILURE;
469 res = ast_waitstream_full(chan, argv[3], agi->audio, agi->ctrl);
470 /* this is to check for if ast_waitstream closed the stream, we probably are at
471 * the end of the stream, return that amount, else check for the amount */
472 sample_offset = (chan->stream) ? ast_tellstream(fs) : max_length;
473 ast_stopstream(chan);
475 /* Stop this command, don't print a result line, as there is a new command */
476 return RESULT_SUCCESS;
478 fdprintf(agi->fd, "200 result=%d endpos=%ld\n", res, sample_offset);
480 return RESULT_SUCCESS;
482 return RESULT_FAILURE;
485 /* get option - really similar to the handle_streamfile, but with a timeout */
486 static int handle_getoption(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
489 struct ast_filestream *fs;
490 long sample_offset = 0;
493 char *edigits = NULL;
495 if ( argc < 4 || argc > 5 )
496 return RESULT_SHOWUSAGE;
502 timeout = atoi(argv[4]);
503 else if (chan->pbx->dtimeout) {
504 /* by default dtimeout is set to 5sec */
505 timeout = chan->pbx->dtimeout * 1000; /* in msec */
508 fs = ast_openstream(chan, argv[2], chan->language);
510 fdprintf(agi->fd, "200 result=%d endpos=%ld\n", 0, sample_offset);
511 ast_log(LOG_WARNING, "Unable to open %s\n", argv[2]);
512 return RESULT_SUCCESS;
514 if (option_verbose > 2)
515 ast_verbose(VERBOSE_PREFIX_3 "Playing '%s' (escape_digits=%s) (timeout %d)\n", argv[2], edigits, timeout);
517 ast_seekstream(fs, 0, SEEK_END);
518 max_length = ast_tellstream(fs);
519 ast_seekstream(fs, sample_offset, SEEK_SET);
520 res = ast_applystream(chan, fs);
521 res = ast_playstream(fs);
523 fdprintf(agi->fd, "200 result=%d endpos=%ld\n", res, sample_offset);
525 return RESULT_SHOWUSAGE;
527 return RESULT_FAILURE;
529 res = ast_waitstream_full(chan, argv[3], agi->audio, agi->ctrl);
530 /* this is to check for if ast_waitstream closed the stream, we probably are at
531 * the end of the stream, return that amount, else check for the amount */
532 sample_offset = (chan->stream)?ast_tellstream(fs):max_length;
533 ast_stopstream(chan);
535 /* Stop this command, don't print a result line, as there is a new command */
536 return RESULT_SUCCESS;
539 /* If the user didnt press a key, wait for digitTimeout*/
541 res = ast_waitfordigit_full(chan, timeout, agi->audio, agi->ctrl);
542 /* Make sure the new result is in the escape digits of the GET OPTION */
543 if ( !strchr(edigits,res) )
547 fdprintf(agi->fd, "200 result=%d endpos=%ld\n", res, sample_offset);
549 return RESULT_SUCCESS;
551 return RESULT_FAILURE;
557 /*--- handle_saynumber: Say number in various language syntaxes ---*/
558 /* Need to add option for gender here as well. Coders wanted */
559 /* While waiting, we're sending a (char *) NULL. */
560 static int handle_saynumber(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
565 return RESULT_SHOWUSAGE;
566 if (sscanf(argv[2], "%d", &num) != 1)
567 return RESULT_SHOWUSAGE;
568 res = ast_say_number_full(chan, num, argv[3], chan->language, (char *) NULL, agi->audio, agi->ctrl);
570 return RESULT_SUCCESS;
571 fdprintf(agi->fd, "200 result=%d\n", res);
573 return RESULT_SUCCESS;
575 return RESULT_FAILURE;
578 static int handle_saydigits(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
584 return RESULT_SHOWUSAGE;
585 if (sscanf(argv[2], "%d", &num) != 1)
586 return RESULT_SHOWUSAGE;
588 res = ast_say_digit_str_full(chan, argv[2], argv[3], chan->language, agi->audio, agi->ctrl);
589 if (res == 1) /* New command */
590 return RESULT_SUCCESS;
591 fdprintf(agi->fd, "200 result=%d\n", res);
593 return RESULT_SUCCESS;
595 return RESULT_FAILURE;
598 static int handle_sayalpha(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
603 return RESULT_SHOWUSAGE;
605 res = ast_say_character_str_full(chan, argv[2], argv[3], chan->language, agi->audio, agi->ctrl);
606 if (res == 1) /* New command */
607 return RESULT_SUCCESS;
608 fdprintf(agi->fd, "200 result=%d\n", res);
610 return RESULT_SUCCESS;
612 return RESULT_FAILURE;
615 static int handle_saydate(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
620 return RESULT_SHOWUSAGE;
621 if (sscanf(argv[2], "%d", &num) != 1)
622 return RESULT_SHOWUSAGE;
623 res = ast_say_date(chan, num, argv[3], chan->language);
625 return RESULT_SUCCESS;
626 fdprintf(agi->fd, "200 result=%d\n", res);
628 return RESULT_SUCCESS;
630 return RESULT_FAILURE;
633 static int handle_saytime(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
638 return RESULT_SHOWUSAGE;
639 if (sscanf(argv[2], "%d", &num) != 1)
640 return RESULT_SHOWUSAGE;
641 res = ast_say_time(chan, num, argv[3], chan->language);
643 return RESULT_SUCCESS;
644 fdprintf(agi->fd, "200 result=%d\n", res);
646 return RESULT_SUCCESS;
648 return RESULT_FAILURE;
651 static int handle_saydatetime(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
655 char *format, *zone=NULL;
658 return RESULT_SHOWUSAGE;
663 if (!strcasecmp(chan->language, "de")) {
664 format = "A dBY HMS";
666 format = "ABdY 'digits/at' IMp";
670 if (argc > 5 && !ast_strlen_zero(argv[5]))
673 if (sscanf(argv[2], "%ld", &unixtime) != 1)
674 return RESULT_SHOWUSAGE;
676 res = ast_say_date_with_format(chan, (time_t) unixtime, argv[3], chan->language, format, zone);
678 return RESULT_SUCCESS;
680 fdprintf(agi->fd, "200 result=%d\n", res);
683 return RESULT_SUCCESS;
685 return RESULT_FAILURE;
688 static int handle_sayphonetic(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
693 return RESULT_SHOWUSAGE;
695 res = ast_say_phonetic_str_full(chan, argv[2], argv[3], chan->language, agi->audio, agi->ctrl);
696 if (res == 1) /* New command */
697 return RESULT_SUCCESS;
698 fdprintf(agi->fd, "200 result=%d\n", res);
700 return RESULT_SUCCESS;
702 return RESULT_FAILURE;
705 static int handle_getdata(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
713 return RESULT_SHOWUSAGE;
715 timeout = atoi(argv[3]);
722 res = ast_app_getdata_full(chan, argv[2], data, max, timeout, agi->audio, agi->ctrl);
723 if (res == 2) /* New command */
724 return RESULT_SUCCESS;
726 fdprintf(agi->fd, "200 result=%s (timeout)\n", data);
728 fdprintf(agi->fd, "200 result=-1\n");
730 fdprintf(agi->fd, "200 result=%s\n", data);
731 return RESULT_SUCCESS;
734 static int handle_setcontext(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
738 return RESULT_SHOWUSAGE;
739 strncpy(chan->context, argv[2], sizeof(chan->context)-1);
740 fdprintf(agi->fd, "200 result=0\n");
741 return RESULT_SUCCESS;
744 static int handle_setextension(struct ast_channel *chan, AGI *agi, int argc, char **argv)
747 return RESULT_SHOWUSAGE;
748 strncpy(chan->exten, argv[2], sizeof(chan->exten)-1);
749 fdprintf(agi->fd, "200 result=0\n");
750 return RESULT_SUCCESS;
753 static int handle_setpriority(struct ast_channel *chan, AGI *agi, int argc, char **argv)
757 return RESULT_SHOWUSAGE;
759 if (sscanf(argv[2], "%d", &pri) != 1) {
760 if ((pri = ast_findlabel_extension(chan, chan->context, chan->exten, argv[2], chan->cid.cid_num)) < 1)
761 return RESULT_SHOWUSAGE;
764 ast_explicit_goto(chan, NULL, NULL, pri);
765 fdprintf(agi->fd, "200 result=0\n");
766 return RESULT_SUCCESS;
769 static int handle_recordfile(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
771 struct ast_filestream *fs;
773 struct timeval tv, start;
774 long sample_offset = 0;
778 struct ast_dsp *sildet=NULL; /* silence detector dsp */
779 int totalsilence = 0;
781 int silence = 0; /* amount of silence to allow */
782 int gotsilence = 0; /* did we timeout for silence? */
783 char *silencestr=NULL;
787 /* XXX EAGI FIXME XXX */
790 return RESULT_SHOWUSAGE;
791 if (sscanf(argv[5], "%d", &ms) != 1)
792 return RESULT_SHOWUSAGE;
795 silencestr = strchr(argv[6],'s');
796 if ((argc > 7) && (!silencestr))
797 silencestr = strchr(argv[7],'s');
798 if ((argc > 8) && (!silencestr))
799 silencestr = strchr(argv[8],'s');
802 if (strlen(silencestr) > 2) {
803 if ((silencestr[0] == 's') && (silencestr[1] == '=')) {
807 silence = atoi(silencestr);
815 rfmt = chan->readformat;
816 res = ast_set_read_format(chan, AST_FORMAT_SLINEAR);
818 ast_log(LOG_WARNING, "Unable to set to linear mode, giving up\n");
821 sildet = ast_dsp_new();
823 ast_log(LOG_WARNING, "Unable to create silence detector :(\n");
826 ast_dsp_set_threshold(sildet, 256);
829 /* backward compatibility, if no offset given, arg[6] would have been
830 * caught below and taken to be a beep, else if it is a digit then it is a
832 if ((argc >6) && (sscanf(argv[6], "%ld", &sample_offset) != 1) && (!strchr(argv[6], '=')))
833 res = ast_streamfile(chan, "beep", chan->language);
835 if ((argc > 7) && (!strchr(argv[7], '=')))
836 res = ast_streamfile(chan, "beep", chan->language);
839 res = ast_waitstream(chan, argv[4]);
841 fs = ast_writefile(argv[2], argv[3], NULL, O_CREAT | O_WRONLY | (sample_offset ? O_APPEND : 0), 0, 0644);
844 fdprintf(agi->fd, "200 result=%d (writefile)\n", res);
846 ast_dsp_free(sildet);
847 return RESULT_FAILURE;
851 ast_applystream(chan,fs);
852 /* really should have checks */
853 ast_seekstream(fs, sample_offset, SEEK_SET);
856 gettimeofday(&start, NULL);
857 gettimeofday(&tv, NULL);
858 while ((ms < 0) || (((tv.tv_sec - start.tv_sec) * 1000 + (tv.tv_usec - start.tv_usec)/1000) < ms)) {
859 res = ast_waitfor(chan, -1);
862 fdprintf(agi->fd, "200 result=%d (waitfor) endpos=%ld\n", res,sample_offset);
864 ast_dsp_free(sildet);
865 return RESULT_FAILURE;
869 fdprintf(agi->fd, "200 result=%d (hangup) endpos=%ld\n", 0, sample_offset);
872 ast_dsp_free(sildet);
873 return RESULT_FAILURE;
875 switch(f->frametype) {
877 if (strchr(argv[4], f->subclass)) {
878 /* This is an interrupting chracter */
879 sample_offset = ast_tellstream(fs);
880 fdprintf(agi->fd, "200 result=%d (dtmf) endpos=%ld\n", f->subclass, sample_offset);
884 ast_dsp_free(sildet);
885 return RESULT_SUCCESS;
888 case AST_FRAME_VOICE:
889 ast_writestream(fs, f);
890 /* this is a safe place to check progress since we know that fs
891 * is valid after a write, and it will then have our current
893 sample_offset = ast_tellstream(fs);
896 ast_dsp_silence(sildet, f, &dspsilence);
898 totalsilence = dspsilence;
902 if (totalsilence > silence) {
903 /* Ended happily with silence */
912 gettimeofday(&tv, NULL);
918 ast_stream_rewind(fs, silence-1000);
920 sample_offset = ast_tellstream(fs);
922 fdprintf(agi->fd, "200 result=%d (timeout) endpos=%ld\n", res, sample_offset);
925 fdprintf(agi->fd, "200 result=%d (randomerror) endpos=%ld\n", res, sample_offset);
928 res = ast_set_read_format(chan, rfmt);
930 ast_log(LOG_WARNING, "Unable to restore read format on '%s'\n", chan->name);
931 ast_dsp_free(sildet);
933 return RESULT_SUCCESS;
936 static int handle_autohangup(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
941 return RESULT_SHOWUSAGE;
942 if (sscanf(argv[2], "%d", &timeout) != 1)
943 return RESULT_SHOWUSAGE;
947 chan->whentohangup = time(NULL) + timeout;
949 chan->whentohangup = 0;
950 fdprintf(agi->fd, "200 result=0\n");
951 return RESULT_SUCCESS;
954 static int handle_hangup(struct ast_channel *chan, AGI *agi, int argc, char **argv)
956 struct ast_channel *c;
958 /* no argument: hangup the current channel */
959 ast_softhangup(chan,AST_SOFTHANGUP_EXPLICIT);
960 fdprintf(agi->fd, "200 result=1\n");
961 return RESULT_SUCCESS;
962 } else if (argc == 2) {
963 /* one argument: look for info on the specified channel */
964 c = ast_get_channel_by_name_locked(argv[1]);
966 /* we have a matching channel */
967 ast_softhangup(c,AST_SOFTHANGUP_EXPLICIT);
968 fdprintf(agi->fd, "200 result=1\n");
969 ast_mutex_unlock(&c->lock);
970 return RESULT_SUCCESS;
972 /* if we get this far no channel name matched the argument given */
973 fdprintf(agi->fd, "200 result=-1\n");
974 return RESULT_SUCCESS;
976 return RESULT_SHOWUSAGE;
980 static int handle_exec(struct ast_channel *chan, AGI *agi, int argc, char **argv)
986 return RESULT_SHOWUSAGE;
988 if (option_verbose > 2)
989 ast_verbose(VERBOSE_PREFIX_3 "AGI Script Executing Application: (%s) Options: (%s)\n", argv[1], argv[2]);
991 app = pbx_findapp(argv[1]);
994 res = pbx_exec(chan, app, argv[2], 1);
996 ast_log(LOG_WARNING, "Could not find application (%s)\n", argv[1]);
999 fdprintf(agi->fd, "200 result=%d\n", res);
1004 static int handle_setcallerid(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1007 char *l = NULL, *n = NULL;
1010 strncpy(tmp, argv[2], sizeof(tmp) - 1);
1011 ast_callerid_parse(tmp, &n, &l);
1013 ast_shrink_phone_number(l);
1018 ast_set_callerid(chan, l, n, NULL);
1021 fdprintf(agi->fd, "200 result=1\n");
1022 return RESULT_SUCCESS;
1025 static int handle_channelstatus(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1027 struct ast_channel *c;
1029 /* no argument: supply info on the current channel */
1030 fdprintf(agi->fd, "200 result=%d\n", chan->_state);
1031 return RESULT_SUCCESS;
1032 } else if (argc == 3) {
1033 /* one argument: look for info on the specified channel */
1034 c = ast_get_channel_by_name_locked(argv[2]);
1036 fdprintf(agi->fd, "200 result=%d\n", c->_state);
1037 ast_mutex_unlock(&c->lock);
1038 return RESULT_SUCCESS;
1040 /* if we get this far no channel name matched the argument given */
1041 fdprintf(agi->fd, "200 result=-1\n");
1042 return RESULT_SUCCESS;
1044 return RESULT_SHOWUSAGE;
1048 static int handle_setvariable(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1051 pbx_builtin_setvar_helper(chan, argv[2], argv[3]);
1053 fdprintf(agi->fd, "200 result=1\n");
1054 return RESULT_SUCCESS;
1057 static int handle_getvariable(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1063 return RESULT_SHOWUSAGE;
1064 pbx_retrieve_variable(chan, argv[2], &ret, tempstr, sizeof(tempstr), NULL);
1066 fdprintf(agi->fd, "200 result=1 (%s)\n", ret);
1068 fdprintf(agi->fd, "200 result=0\n");
1070 return RESULT_SUCCESS;
1073 static int handle_getvariablefull(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1076 struct ast_channel *chan2=NULL;
1078 if ((argc != 4) && (argc != 5))
1079 return RESULT_SHOWUSAGE;
1081 chan2 = ast_get_channel_by_name_locked(argv[4]);
1085 if (chan) { /* XXX isn't this chan2 ? */
1086 pbx_substitute_variables_helper(chan2, argv[3], tmp, sizeof(tmp) - 1);
1087 fdprintf(agi->fd, "200 result=1 (%s)\n", tmp);
1089 fdprintf(agi->fd, "200 result=0\n");
1091 if (chan2 && (chan2 != chan))
1092 ast_mutex_unlock(&chan2->lock);
1093 return RESULT_SUCCESS;
1096 static int handle_verbose(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1102 return RESULT_SHOWUSAGE;
1105 sscanf(argv[2], "%d", &level);
1109 prefix = VERBOSE_PREFIX_4;
1112 prefix = VERBOSE_PREFIX_3;
1115 prefix = VERBOSE_PREFIX_2;
1119 prefix = VERBOSE_PREFIX_1;
1123 if (level <= option_verbose)
1124 ast_verbose("%s %s: %s\n", prefix, chan->data, argv[1]);
1126 fdprintf(agi->fd, "200 result=1\n");
1128 return RESULT_SUCCESS;
1131 static int handle_dbget(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1137 return RESULT_SHOWUSAGE;
1138 res = ast_db_get(argv[2], argv[3], tmp, sizeof(tmp));
1140 fdprintf(agi->fd, "200 result=0\n");
1142 fdprintf(agi->fd, "200 result=1 (%s)\n", tmp);
1144 return RESULT_SUCCESS;
1147 static int handle_dbput(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1152 return RESULT_SHOWUSAGE;
1153 res = ast_db_put(argv[2], argv[3], argv[4]);
1155 fdprintf(agi->fd, "200 result=0\n");
1157 fdprintf(agi->fd, "200 result=1\n");
1159 return RESULT_SUCCESS;
1162 static int handle_dbdel(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1167 return RESULT_SHOWUSAGE;
1168 res = ast_db_del(argv[2], argv[3]);
1170 fdprintf(agi->fd, "200 result=0\n");
1172 fdprintf(agi->fd, "200 result=1\n");
1174 return RESULT_SUCCESS;
1177 static int handle_dbdeltree(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1180 if ((argc < 3) || (argc > 4))
1181 return RESULT_SHOWUSAGE;
1183 res = ast_db_deltree(argv[2], argv[3]);
1185 res = ast_db_deltree(argv[2], NULL);
1188 fdprintf(agi->fd, "200 result=0\n");
1190 fdprintf(agi->fd, "200 result=1\n");
1191 return RESULT_SUCCESS;
1194 static char debug_usage[] =
1195 "Usage: agi debug\n"
1196 " Enables dumping of AGI transactions for debugging purposes\n";
1198 static char no_debug_usage[] =
1199 "Usage: agi no debug\n"
1200 " Disables dumping of AGI transactions for debugging purposes\n";
1202 static int agi_do_debug(int fd, int argc, char *argv[])
1205 return RESULT_SHOWUSAGE;
1207 ast_cli(fd, "AGI Debugging Enabled\n");
1208 return RESULT_SUCCESS;
1211 static int agi_no_debug(int fd, int argc, char *argv[])
1214 return RESULT_SHOWUSAGE;
1216 ast_cli(fd, "AGI Debugging Disabled\n");
1217 return RESULT_SUCCESS;
1220 static struct ast_cli_entry cli_debug =
1221 { { "agi", "debug", NULL }, agi_do_debug, "Enable AGI debugging", debug_usage };
1223 static struct ast_cli_entry cli_no_debug =
1224 { { "agi", "no", "debug", NULL }, agi_no_debug, "Disable AGI debugging", no_debug_usage };
1226 static int handle_noop(struct ast_channel *chan, AGI *agi, int arg, char *argv[])
1228 fdprintf(agi->fd, "200 result=0\n");
1229 return RESULT_SUCCESS;
1232 static int handle_setmusic(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
1234 if (!strncasecmp(argv[2],"on",2)) {
1236 ast_moh_start(chan, argv[3]);
1238 ast_moh_start(chan, NULL);
1240 if (!strncasecmp(argv[2],"off",3)) {
1243 fdprintf(agi->fd, "200 result=0\n");
1244 return RESULT_SUCCESS;
1247 static char usage_setmusic[] =
1248 " Usage: SET MUSIC ON <on|off> <class>\n"
1249 " Enables/Disables the music on hold generator. If <class> is\n"
1250 " not specified, then the default music on hold class will be used.\n"
1251 " Always returns 0.\n";
1253 static char usage_dbput[] =
1254 " Usage: DATABASE PUT <family> <key> <value>\n"
1255 " Adds or updates an entry in the Asterisk database for a\n"
1256 " given family, key, and value.\n"
1257 " Returns 1 if successful, 0 otherwise.\n";
1259 static char usage_dbget[] =
1260 " Usage: DATABASE GET <family> <key>\n"
1261 " Retrieves an entry in the Asterisk database for a\n"
1262 " given family and key.\n"
1263 " Returns 0 if <key> is not set. Returns 1 if <key>\n"
1264 " is set and returns the variable in parentheses.\n"
1265 " Example return code: 200 result=1 (testvariable)\n";
1267 static char usage_dbdel[] =
1268 " Usage: DATABASE DEL <family> <key>\n"
1269 " Deletes an entry in the Asterisk database for a\n"
1270 " given family and key.\n"
1271 " Returns 1 if successful, 0 otherwise.\n";
1273 static char usage_dbdeltree[] =
1274 " Usage: DATABASE DELTREE <family> [keytree]\n"
1275 " Deletes a family or specific keytree within a family\n"
1276 " in the Asterisk database.\n"
1277 " Returns 1 if successful, 0 otherwise.\n";
1279 static char usage_verbose[] =
1280 " Usage: VERBOSE <message> <level>\n"
1281 " Sends <message> to the console via verbose message system.\n"
1282 " <level> is the the verbose level (1-4)\n"
1283 " Always returns 1.\n";
1285 static char usage_getvariable[] =
1286 " Usage: GET VARIABLE <variablename>\n"
1287 " Returns 0 if <variablename> is not set. Returns 1 if <variablename>\n"
1288 " is set and returns the variable in parentheses.\n"
1289 " example return code: 200 result=1 (testvariable)\n";
1291 static char usage_getvariablefull[] =
1292 " Usage: GET FULL VARIABLE <variablename> [<channel name>]\n"
1293 " Returns 0 if <variablename> is not set or channel does not exist. Returns 1\n"
1294 "if <variablename> is set and returns the variable in parenthesis. Understands\n"
1295 "complex variable names and builtin variables, unlike GET VARIABLE.\n"
1296 " example return code: 200 result=1 (testvariable)\n";
1298 static char usage_setvariable[] =
1299 " Usage: SET VARIABLE <variablename> <value>\n";
1301 static char usage_channelstatus[] =
1302 " Usage: CHANNEL STATUS [<channelname>]\n"
1303 " Returns the status of the specified channel.\n"
1304 " If no channel name is given the returns the status of the\n"
1305 " current channel. Return values:\n"
1306 " 0 Channel is down and available\n"
1307 " 1 Channel is down, but reserved\n"
1308 " 2 Channel is off hook\n"
1309 " 3 Digits (or equivalent) have been dialed\n"
1310 " 4 Line is ringing\n"
1311 " 5 Remote end is ringing\n"
1313 " 7 Line is busy\n";
1315 static char usage_setcallerid[] =
1316 " Usage: SET CALLERID <number>\n"
1317 " Changes the callerid of the current channel.\n";
1319 static char usage_exec[] =
1320 " Usage: EXEC <application> <options>\n"
1321 " Executes <application> with given <options>.\n"
1322 " Returns whatever the application returns, or -2 on failure to find application\n";
1324 static char usage_hangup[] =
1325 " Usage: HANGUP [<channelname>]\n"
1326 " Hangs up the specified channel.\n"
1327 " If no channel name is given, hangs up the current channel\n";
1329 static char usage_answer[] =
1331 " Answers channel if not already in answer state. Returns -1 on\n"
1332 " channel failure, or 0 if successful.\n";
1334 static char usage_waitfordigit[] =
1335 " Usage: WAIT FOR DIGIT <timeout>\n"
1336 " Waits up to 'timeout' milliseconds for channel to receive a DTMF digit.\n"
1337 " Returns -1 on channel failure, 0 if no digit is received in the timeout, or\n"
1338 " the numerical value of the ascii of the digit if one is received. Use -1\n"
1339 " for the timeout value if you desire the call to block indefinitely.\n";
1341 static char usage_sendtext[] =
1342 " Usage: SEND TEXT \"<text to send>\"\n"
1343 " Sends the given text on a channel. Most channels do not support the\n"
1344 " transmission of text. Returns 0 if text is sent, or if the channel does not\n"
1345 " support text transmission. Returns -1 only on error/hangup. Text\n"
1346 " consisting of greater than one word should be placed in quotes since the\n"
1347 " command only accepts a single argument.\n";
1349 static char usage_recvchar[] =
1350 " Usage: RECEIVE CHAR <timeout>\n"
1351 " Receives a character of text on a channel. Specify timeout to be the\n"
1352 " maximum time to wait for input in milliseconds, or 0 for infinite. Most channels\n"
1353 " do not support the reception of text. Returns the decimal value of the character\n"
1354 " if one is received, or 0 if the channel does not support text reception. Returns\n"
1355 " -1 only on error/hangup.\n";
1357 static char usage_tddmode[] =
1358 " Usage: TDD MODE <on|off>\n"
1359 " Enable/Disable TDD transmission/reception on a channel. Returns 1 if\n"
1360 " successful, or 0 if channel is not TDD-capable.\n";
1362 static char usage_sendimage[] =
1363 " Usage: SEND IMAGE <image>\n"
1364 " Sends the given image on a channel. Most channels do not support the\n"
1365 " transmission of images. Returns 0 if image is sent, or if the channel does not\n"
1366 " support image transmission. Returns -1 only on error/hangup. Image names\n"
1367 " should not include extensions.\n";
1369 static char usage_streamfile[] =
1370 " Usage: STREAM FILE <filename> <escape digits> [sample offset]\n"
1371 " Send the given file, allowing playback to be interrupted by the given\n"
1372 " digits, if any. Use double quotes for the digits if you wish none to be\n"
1373 " permitted. If sample offset is provided then the audio will seek to sample\n"
1374 " offset before play starts. Returns 0 if playback completes without a digit\n"
1375 " being pressed, or the ASCII numerical value of the digit if one was pressed,\n"
1376 " or -1 on error or if the channel was disconnected. Remember, the file\n"
1377 " extension must not be included in the filename.\n";
1379 static char usage_getoption[] =
1380 " Usage: GET OPTION <filename> <escape_digits> [timeout]\n"
1381 " Behaves similar to STREAM FILE but used with a timeout option.\n";
1383 static char usage_saynumber[] =
1384 " Usage: SAY NUMBER <number> <escape digits>\n"
1385 " Say a given number, returning early if any of the given DTMF digits\n"
1386 " are received on the channel. Returns 0 if playback completes without a digit\n"
1387 " being pressed, or the ASCII numerical value of the digit if one was pressed or\n"
1388 " -1 on error/hangup.\n";
1390 static char usage_saydigits[] =
1391 " Usage: SAY DIGITS <number> <escape digits>\n"
1392 " Say a given digit string, returning early if any of the given DTMF digits\n"
1393 " are received on the channel. Returns 0 if playback completes without a digit\n"
1394 " being pressed, or the ASCII numerical value of the digit if one was pressed or\n"
1395 " -1 on error/hangup.\n";
1397 static char usage_sayalpha[] =
1398 " Usage: SAY ALPHA <number> <escape digits>\n"
1399 " Say a given character string, returning early if any of the given DTMF digits\n"
1400 " are received on the channel. Returns 0 if playback completes without a digit\n"
1401 " being pressed, or the ASCII numerical value of the digit if one was pressed or\n"
1402 " -1 on error/hangup.\n";
1404 static char usage_saydate[] =
1405 " Usage: SAY DATE <date> <escape digits>\n"
1406 " Say a given date, returning early if any of the given DTMF digits are\n"
1407 " received on the channel. <date> is number of seconds elapsed since 00:00:00\n"
1408 " on January 1, 1970, Coordinated Universal Time (UTC). Returns 0 if playback\n"
1409 " completes without a digit being pressed, or the ASCII numerical value of the\n"
1410 " digit if one was pressed or -1 on error/hangup.\n";
1412 static char usage_saytime[] =
1413 " Usage: SAY TIME <time> <escape digits>\n"
1414 " Say a given time, returning early if any of the given DTMF digits are\n"
1415 " received on the channel. <time> is number of seconds elapsed since 00:00:00\n"
1416 " on January 1, 1970, Coordinated Universal Time (UTC). Returns 0 if playback\n"
1417 " completes without a digit being pressed, or the ASCII numerical value of the\n"
1418 " digit if one was pressed or -1 on error/hangup.\n";
1420 static char usage_saydatetime[] =
1421 " Usage: SAY DATETIME <time> <escape digits> [format] [timezone]\n"
1422 " Say a given time, returning early if any of the given DTMF digits are\n"
1423 " received on the channel. <time> is number of seconds elapsed since 00:00:00\n"
1424 " on January 1, 1970, Coordinated Universal Time (UTC). [format] is the format\n"
1425 " the time should be said in. See voicemail.conf (defaults to \"ABdY\n"
1426 " 'digits/at' IMp\"). Acceptable values for [timezone] can be found in\n"
1427 " /usr/share/zoneinfo. Defaults to machine default. Returns 0 if playback\n"
1428 " completes without a digit being pressed, or the ASCII numerical value of the\n"
1429 " digit if one was pressed or -1 on error/hangup.\n";
1431 static char usage_sayphonetic[] =
1432 " Usage: SAY PHONETIC <string> <escape digits>\n"
1433 " Say a given character string with phonetics, returning early if any of the\n"
1434 " given DTMF digits are received on the channel. Returns 0 if playback\n"
1435 " completes without a digit pressed, the ASCII numerical value of the digit\n"
1436 " if one was pressed, or -1 on error/hangup.\n";
1438 static char usage_getdata[] =
1439 " Usage: GET DATA <file to be streamed> [timeout] [max digits]\n"
1440 " Stream the given file, and recieve DTMF data. Returns the digits received\n"
1441 "from the channel at the other end.\n";
1443 static char usage_setcontext[] =
1444 " Usage: SET CONTEXT <desired context>\n"
1445 " Sets the context for continuation upon exiting the application.\n";
1447 static char usage_setextension[] =
1448 " Usage: SET EXTENSION <new extension>\n"
1449 " Changes the extension for continuation upon exiting the application.\n";
1451 static char usage_setpriority[] =
1452 " Usage: SET PRIORITY <priority>\n"
1453 " Changes the priority for continuation upon exiting the application.\n"
1454 " The priority must be a valid priority or label.\n";
1456 static char usage_recordfile[] =
1457 " Usage: RECORD FILE <filename> <format> <escape digits> <timeout> \\\n"
1458 " [offset samples] [BEEP] [s=silence]\n"
1459 " Record to a file until a given dtmf digit in the sequence is received\n"
1460 " Returns -1 on hangup or error. The format will specify what kind of file\n"
1461 " will be recorded. The timeout is the maximum record time in milliseconds, or\n"
1462 " -1 for no timeout. \"Offset samples\" is optional, and, if provided, will seek\n"
1463 " to the offset without exceeding the end of the file. \"silence\" is the number\n"
1464 " of seconds of silence allowed before the function returns despite the\n"
1465 " lack of dtmf digits or reaching timeout. Silence value must be\n"
1466 " preceeded by \"s=\" and is also optional.\n";
1468 static char usage_autohangup[] =
1469 " Usage: SET AUTOHANGUP <time>\n"
1470 " Cause the channel to automatically hangup at <time> seconds in the\n"
1471 " future. Of course it can be hungup before then as well. Setting to 0 will\n"
1472 " cause the autohangup feature to be disabled on this channel.\n";
1474 static char usage_noop[] =
1478 static agi_command commands[MAX_COMMANDS] = {
1479 { { "answer", NULL }, handle_answer, "Answer channel", usage_answer },
1480 { { "channel", "status", NULL }, handle_channelstatus, "Returns status of the connected channel", usage_channelstatus },
1481 { { "database", "del", NULL }, handle_dbdel, "Removes database key/value", usage_dbdel },
1482 { { "database", "deltree", NULL }, handle_dbdeltree, "Removes database keytree/value", usage_dbdeltree },
1483 { { "database", "get", NULL }, handle_dbget, "Gets database value", usage_dbget },
1484 { { "database", "put", NULL }, handle_dbput, "Adds/updates database value", usage_dbput },
1485 { { "exec", NULL }, handle_exec, "Executes a given Application", usage_exec },
1486 { { "get", "data", NULL }, handle_getdata, "Prompts for DTMF on a channel", usage_getdata },
1487 { { "get", "full", "variable", NULL }, handle_getvariablefull, "Evaluates a channel expression", usage_getvariablefull },
1488 { { "get", "option", NULL }, handle_getoption, "Stream file, prompt for DTMF, with timeout", usage_getoption },
1489 { { "get", "variable", NULL }, handle_getvariable, "Gets a channel variable", usage_getvariable },
1490 { { "hangup", NULL }, handle_hangup, "Hangup the current channel", usage_hangup },
1491 { { "noop", NULL }, handle_noop, "Does nothing", usage_noop },
1492 { { "receive", "char", NULL }, handle_recvchar, "Receives text from channels supporting it", usage_recvchar },
1493 { { "record", "file", NULL }, handle_recordfile, "Records to a given file", usage_recordfile },
1494 { { "say", "alpha", NULL }, handle_sayalpha, "Says a given character string", usage_sayalpha },
1495 { { "say", "digits", NULL }, handle_saydigits, "Says a given digit string", usage_saydigits },
1496 { { "say", "number", NULL }, handle_saynumber, "Says a given number", usage_saynumber },
1497 { { "say", "phonetic", NULL }, handle_sayphonetic, "Says a given character string with phonetics", usage_sayphonetic },
1498 { { "say", "date", NULL }, handle_saydate, "Says a given date", usage_saydate },
1499 { { "say", "time", NULL }, handle_saytime, "Says a given time", usage_saytime },
1500 { { "say", "datetime", NULL }, handle_saydatetime, "Says a given time as specfied by the format given", usage_saydatetime },
1501 { { "send", "image", NULL }, handle_sendimage, "Sends images to channels supporting it", usage_sendimage },
1502 { { "send", "text", NULL }, handle_sendtext, "Sends text to channels supporting it", usage_sendtext },
1503 { { "set", "autohangup", NULL }, handle_autohangup, "Autohangup channel in some time", usage_autohangup },
1504 { { "set", "callerid", NULL }, handle_setcallerid, "Sets callerid for the current channel", usage_setcallerid },
1505 { { "set", "context", NULL }, handle_setcontext, "Sets channel context", usage_setcontext },
1506 { { "set", "extension", NULL }, handle_setextension, "Changes channel extension", usage_setextension },
1507 { { "set", "music", NULL }, handle_setmusic, "Enable/Disable Music on hold generator", usage_setmusic },
1508 { { "set", "priority", NULL }, handle_setpriority, "Set channel dialplan priority", usage_setpriority },
1509 { { "set", "variable", NULL }, handle_setvariable, "Sets a channel variable", usage_setvariable },
1510 { { "stream", "file", NULL }, handle_streamfile, "Sends audio file on channel", usage_streamfile },
1511 { { "tdd", "mode", NULL }, handle_tddmode, "Toggles TDD mode (for the deaf)", usage_tddmode },
1512 { { "verbose", NULL }, handle_verbose, "Logs a message to the asterisk verbose log", usage_verbose },
1513 { { "wait", "for", "digit", NULL }, handle_waitfordigit, "Waits for a digit to be pressed", usage_waitfordigit },
1516 static void join(char *s, size_t len, char *w[])
1520 /* Join words into a string */
1525 for (x=0; w[x]; x++) {
1527 strncat(s, " ", len - strlen(s) - 1);
1528 strncat(s, w[x], len - strlen(s) - 1);
1532 static int help_workhorse(int fd, char *match[])
1537 struct agi_command *e;
1539 join(matchstr, sizeof(matchstr), match);
1540 for (x=0;x<sizeof(commands)/sizeof(commands[0]);x++) {
1541 if (!commands[x].cmda[0]) break;
1544 join(fullcmd, sizeof(fullcmd), e->cmda);
1545 /* Hide commands that start with '_' */
1546 if (fullcmd[0] == '_')
1549 if (strncasecmp(matchstr, fullcmd, strlen(matchstr))) {
1553 ast_cli(fd, "%20.20s %s\n", fullcmd, e->summary);
1558 int agi_register(agi_command *agi)
1561 for (x=0; x<MAX_COMMANDS - 1; x++) {
1562 if (commands[x].cmda[0] == agi->cmda[0]) {
1563 ast_log(LOG_WARNING, "Command already registered!\n");
1567 for (x=0; x<MAX_COMMANDS - 1; x++) {
1568 if (!commands[x].cmda[0]) {
1573 ast_log(LOG_WARNING, "No more room for new commands!\n");
1577 void agi_unregister(agi_command *agi)
1580 for (x=0; x<MAX_COMMANDS - 1; x++) {
1581 if (commands[x].cmda[0] == agi->cmda[0]) {
1582 memset(&commands[x], 0, sizeof(agi_command));
1587 static agi_command *find_command(char *cmds[], int exact)
1593 for (x=0; x < sizeof(commands) / sizeof(commands[0]); x++) {
1594 if (!commands[x].cmda[0])
1596 /* start optimistic */
1598 for (y=0; match && cmds[y]; y++) {
1599 /* If there are no more words in the command (and we're looking for
1600 an exact match) or there is a difference between the two words,
1601 then this is not a match */
1602 if (!commands[x].cmda[y] && !exact)
1604 /* don't segfault if the next part of a command doesn't exist */
1605 if (!commands[x].cmda[y])
1607 if (strcasecmp(commands[x].cmda[y], cmds[y]))
1610 /* If more words are needed to complete the command then this is not
1611 a candidate (unless we're looking for a really inexact answer */
1612 if ((exact > -1) && commands[x].cmda[y])
1615 return &commands[x];
1621 static int parse_args(char *s, int *max, char *argv[])
1633 /* If it's escaped, put a literal quote */
1638 if (quoted && whitespace) {
1639 /* If we're starting a quote, coming off white space start a new word, too */
1647 if (!quoted && !escaped) {
1648 /* If we're not quoted, mark this as whitespace, and
1649 end the previous argument */
1653 /* Otherwise, just treat it as anything else */
1657 /* If we're escaped, print a literal, otherwise enable escaping */
1667 if (x >= MAX_ARGS -1) {
1668 ast_log(LOG_WARNING, "Too many arguments, truncating\n");
1671 /* Coming off of whitespace, start the next argument */
1680 /* Null terminate */
1687 static int agi_handle_command(struct ast_channel *chan, AGI *agi, char *buf)
1689 char *argv[MAX_ARGS];
1695 parse_args(buf, &argc, argv);
1698 for (x=0; x<argc; x++)
1699 fprintf(stderr, "Got Arg%d: %s\n", x, argv[x]); }
1701 c = find_command(argv, 0);
1703 res = c->handler(chan, agi, argc, argv);
1705 case RESULT_SHOWUSAGE:
1706 fdprintf(agi->fd, "520-Invalid command syntax. Proper usage follows:\n");
1707 fdprintf(agi->fd, c->usage);
1708 fdprintf(agi->fd, "520 End of proper usage.\n");
1710 case AST_PBX_KEEPALIVE:
1711 /* We've been asked to keep alive, so do so */
1712 return AST_PBX_KEEPALIVE;
1714 case RESULT_FAILURE:
1715 /* They've already given the failure. We've been hung up on so handle this
1720 fdprintf(agi->fd, "510 Invalid or unknown command\n");
1725 static int run_agi(struct ast_channel *chan, char *request, AGI *agi, int pid, int dead)
1727 struct ast_channel *c;
1730 int returnstatus = 0;
1731 struct ast_frame *f;
1734 /* how many times we'll retry if ast_waitfor_nandfs will return without either
1735 channel or file descriptor in case select is interrupted by a system call (EINTR) */
1738 if (!(readf = fdopen(agi->ctrl, "r"))) {
1739 ast_log(LOG_WARNING, "Unable to fdopen file descriptor\n");
1746 setup_env(chan, request, agi->fd, (agi->audio > -1));
1749 c = ast_waitfor_nandfds(&chan, dead ? 0 : 1, &agi->ctrl, 1, NULL, &outfd, &ms);
1752 /* Idle the channel until we get a command */
1755 ast_log(LOG_DEBUG, "%s hungup\n", chan->name);
1759 /* If it's voice, write it to the audio pipe */
1760 if ((agi->audio > -1) && (f->frametype == AST_FRAME_VOICE)) {
1761 /* Write, ignoring errors */
1762 write(agi->audio, f->data, f->datalen);
1766 } else if (outfd > -1) {
1768 if (!fgets(buf, sizeof(buf), readf)) {
1769 /* Program terminated */
1772 if (option_verbose > 2)
1773 ast_verbose(VERBOSE_PREFIX_3 "AGI Script %s completed, returning %d\n", request, returnstatus);
1774 /* No need to kill the pid anymore, since they closed us */
1778 /* get rid of trailing newline, if any */
1779 if (*buf && buf[strlen(buf) - 1] == '\n')
1780 buf[strlen(buf) - 1] = 0;
1782 ast_verbose("AGI Rx << %s\n", buf);
1783 returnstatus |= agi_handle_command(chan, agi, buf);
1784 /* If the handle_command returns -1, we need to stop */
1785 if ((returnstatus < 0) || (returnstatus == AST_PBX_KEEPALIVE)) {
1790 ast_log(LOG_WARNING, "No channel, no fd?\n");
1796 /* Notify process */
1800 return returnstatus;
1803 static int handle_showagi(int fd, int argc, char *argv[]) {
1804 struct agi_command *e;
1807 return RESULT_SHOWUSAGE;
1809 e = find_command(argv + 2, 1);
1811 ast_cli(fd, e->usage);
1813 if (find_command(argv + 2, -1)) {
1814 return help_workhorse(fd, argv + 1);
1816 join(fullcmd, sizeof(fullcmd), argv+1);
1817 ast_cli(fd, "No such command '%s'.\n", fullcmd);
1821 return help_workhorse(fd, NULL);
1823 return RESULT_SUCCESS;
1826 static int handle_dumpagihtml(int fd, int argc, char *argv[]) {
1827 struct agi_command *e;
1834 return RESULT_SHOWUSAGE;
1836 if (!(htmlfile = fopen(argv[2], "wt"))) {
1837 ast_cli(fd, "Could not create file '%s'\n", argv[2]);
1838 return RESULT_SHOWUSAGE;
1841 fprintf(htmlfile, "<HTML>\n<HEAD>\n<TITLE>AGI Commands</TITLE>\n</HEAD>\n");
1842 fprintf(htmlfile, "<BODY>\n<CENTER><B><H1>AGI Commands</H1></B></CENTER>\n\n");
1845 fprintf(htmlfile, "<TABLE BORDER=\"0\" CELLSPACING=\"10\">\n");
1847 for (x=0;x<sizeof(commands)/sizeof(commands[0]);x++) {
1849 if (!commands[x].cmda[0]) break;
1852 join(fullcmd, sizeof(fullcmd), e->cmda);
1853 /* Hide commands that start with '_' */
1854 if (fullcmd[0] == '_')
1857 fprintf(htmlfile, "<TR><TD><TABLE BORDER=\"1\" CELLPADDING=\"5\" WIDTH=\"100%%\">\n");
1858 fprintf(htmlfile, "<TR><TH ALIGN=\"CENTER\"><B>%s - %s</B></TD></TR>\n", fullcmd,e->summary);
1862 tempstr = strsep(&stringp, "\n");
1864 fprintf(htmlfile, "<TR><TD ALIGN=\"CENTER\">%s</TD></TR>\n", tempstr);
1866 fprintf(htmlfile, "<TR><TD ALIGN=\"CENTER\">\n");
1867 while ((tempstr = strsep(&stringp, "\n")) != NULL) {
1868 fprintf(htmlfile, "%s<BR>\n",tempstr);
1871 fprintf(htmlfile, "</TD></TR>\n");
1872 fprintf(htmlfile, "</TABLE></TD></TR>\n\n");
1876 fprintf(htmlfile, "</TABLE>\n</BODY>\n</HTML>\n");
1878 ast_cli(fd, "AGI HTML Commands Dumped to: %s\n", argv[2]);
1879 return RESULT_SUCCESS;
1882 static int agi_exec_full(struct ast_channel *chan, void *data, int enhanced, int dead)
1885 struct localuser *u;
1886 char *argv[MAX_ARGS];
1888 char *tmp = (char *)buf;
1896 if (!data || ast_strlen_zero(data)) {
1897 ast_log(LOG_WARNING, "AGI requires an argument (script)\n");
1900 strncpy(buf, data, sizeof(buf) - 1);
1902 memset(&agi, 0, sizeof(agi));
1903 while ((stringp = strsep(&tmp, "|"))) {
1904 argv[argc++] = stringp;
1910 /* Answer if need be */
1911 if (chan->_state != AST_STATE_UP) {
1912 if (ast_answer(chan)) {
1913 LOCAL_USER_REMOVE(u);
1918 res = launch_script(argv[0], argv, fds, enhanced ? &efd : NULL, &pid);
1923 res = run_agi(chan, argv[0], &agi, pid, dead);
1928 LOCAL_USER_REMOVE(u);
1932 static int agi_exec(struct ast_channel *chan, void *data)
1934 if (chan->_softhangup)
1935 ast_log(LOG_WARNING, "If you want to run AGI on hungup channels you should use DeadAGI!\n");
1936 return agi_exec_full(chan, data, 0, 0);
1939 static int eagi_exec(struct ast_channel *chan, void *data)
1944 if (chan->_softhangup)
1945 ast_log(LOG_WARNING, "If you want to run AGI on hungup channels you should use DeadAGI!\n");
1946 readformat = chan->readformat;
1947 if (ast_set_read_format(chan, AST_FORMAT_SLINEAR)) {
1948 ast_log(LOG_WARNING, "Unable to set channel '%s' to linear mode\n", chan->name);
1951 res = agi_exec_full(chan, data, 1, 0);
1953 if (ast_set_read_format(chan, readformat)) {
1954 ast_log(LOG_WARNING, "Unable to restore channel '%s' to format %s\n", chan->name, ast_getformatname(readformat));
1960 static int deadagi_exec(struct ast_channel *chan, void *data)
1962 return agi_exec_full(chan, data, 0, 1);
1965 static char showagi_help[] =
1966 "Usage: show agi [topic]\n"
1967 " When called with a topic as an argument, displays usage\n"
1968 " information on the given command. If called without a\n"
1969 " topic, it provides a list of AGI commands.\n";
1972 static char dumpagihtml_help[] =
1973 "Usage: dump agihtml <filename>\n"
1974 " Dumps the agi command list in html format to given filename\n";
1976 static struct ast_cli_entry showagi =
1977 { { "show", "agi", NULL }, handle_showagi, "Show AGI commands or specific help", showagi_help };
1979 static struct ast_cli_entry dumpagihtml =
1980 { { "dump", "agihtml", NULL }, handle_dumpagihtml, "Dumps a list of agi command in html format", dumpagihtml_help };
1982 int unload_module(void)
1984 STANDARD_HANGUP_LOCALUSERS;
1985 ast_cli_unregister(&showagi);
1986 ast_cli_unregister(&dumpagihtml);
1987 ast_cli_unregister(&cli_debug);
1988 ast_cli_unregister(&cli_no_debug);
1989 ast_unregister_application(eapp);
1990 ast_unregister_application(deadapp);
1991 return ast_unregister_application(app);
1994 int load_module(void)
1996 ast_cli_register(&showagi);
1997 ast_cli_register(&dumpagihtml);
1998 ast_cli_register(&cli_debug);
1999 ast_cli_register(&cli_no_debug);
2000 ast_register_application(deadapp, deadagi_exec, deadsynopsis, descrip);
2001 ast_register_application(eapp, eagi_exec, esynopsis, descrip);
2002 return ast_register_application(app, agi_exec, synopsis, descrip);
2005 char *description(void)
2013 STANDARD_USECOUNT(res);
2019 return ASTERISK_GPL_KEY;