2 * Asterisk -- An open source telephony toolkit.
4 * Copyright (C) 1999 - 2005, Digium, Inc.
6 * Mark Spencer <markster@digium.com>
8 * See http://www.asterisk.org for more information about
9 * the Asterisk project. Please do not directly contact
10 * any of the maintainers of this project for assistance;
11 * the project provides a web site, mailing lists and IRC
12 * channels for your use.
14 * This program is free software, distributed under the terms of
15 * the GNU General Public License Version 2. See the LICENSE file
16 * at the top of the source tree.
21 * \brief AGI - the Asterisk Gateway Interface
23 * \author Mark Spencer <markster@digium.com>
26 #include <sys/types.h>
28 #include <sys/socket.h>
29 #include <netinet/in.h>
30 #include <netinet/tcp.h>
31 #include <arpa/inet.h>
45 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
47 #include "asterisk/file.h"
48 #include "asterisk/logger.h"
49 #include "asterisk/channel.h"
50 #include "asterisk/pbx.h"
51 #include "asterisk/module.h"
52 #include "asterisk/astdb.h"
53 #include "asterisk/callerid.h"
54 #include "asterisk/cli.h"
55 #include "asterisk/logger.h"
56 #include "asterisk/options.h"
57 #include "asterisk/image.h"
58 #include "asterisk/say.h"
59 #include "asterisk/app.h"
60 #include "asterisk/dsp.h"
61 #include "asterisk/musiconhold.h"
62 #include "asterisk/manager.h"
63 #include "asterisk/utils.h"
64 #include "asterisk/lock.h"
65 #include "asterisk/strings.h"
66 #include "asterisk/agi.h"
69 #define MAX_COMMANDS 128
71 /* Recycle some stuff from the CLI interface */
72 #define fdprintf agi_debug_cli
74 static char *tdesc = "Asterisk Gateway Interface (AGI)";
76 static char *app = "AGI";
78 static char *eapp = "EAGI";
80 static char *deadapp = "DeadAGI";
82 static char *synopsis = "Executes an AGI compliant application";
83 static char *esynopsis = "Executes an EAGI compliant application";
84 static char *deadsynopsis = "Executes AGI on a hungup channel";
86 static char *descrip =
87 " [E|Dead]AGI(command|args): Executes an Asterisk Gateway Interface compliant\n"
88 "program on a channel. AGI allows Asterisk to launch external programs\n"
89 "written in any language to control a telephony channel, play audio,\n"
90 "read DTMF digits, etc. by communicating with the AGI protocol on stdin\n"
92 "Returns -1 on hangup (except for DeadAGI) or if application requested\n"
93 " hangup, or 0 on non-hangup exit. \n"
94 "Using 'EAGI' provides enhanced AGI, with incoming audio available out of band"
95 "on file descriptor 3\n\n"
96 "Use the CLI command 'show agi' to list available agi commands\n";
98 static int agidebug = 0;
105 #define TONE_BLOCK_SIZE 200
107 /* Max time to connect to an AGI remote host */
108 #define MAX_AGI_CONNECT 2000
110 #define AGI_PORT 4573
112 static void agi_debug_cli(int fd, char *fmt, ...)
119 res = vasprintf(&stuff, fmt, ap);
122 ast_log(LOG_ERROR, "Out of memory\n");
125 ast_verbose("AGI Tx >> %s", stuff);
126 ast_carefulwrite(fd, stuff, strlen(stuff), 100);
131 /* launch_netscript: The fastagi handler.
132 FastAGI defaults to port 4573 */
133 static int launch_netscript(char *agiurl, char *argv[], int *fds, int *efd, int *opid)
137 struct pollfd pfds[1];
139 char *c; int port = AGI_PORT;
141 struct sockaddr_in sin;
143 struct ast_hostent ahp;
145 host = ast_strdupa(agiurl + 6); /* Remove agi:// */
148 /* Strip off any script name */
149 if ((c = strchr(host, '/'))) {
154 if ((c = strchr(host, ':'))) {
160 ast_log(LOG_WARNING, "AGI URI's don't support Enhanced AGI yet\n");
163 hp = ast_gethostbyname(host, &ahp);
165 ast_log(LOG_WARNING, "Unable to locate host '%s'\n", host);
168 s = socket(AF_INET, SOCK_STREAM, 0);
170 ast_log(LOG_WARNING, "Unable to create socket: %s\n", strerror(errno));
173 flags = fcntl(s, F_GETFL);
175 ast_log(LOG_WARNING, "Fcntl(F_GETFL) failed: %s\n", strerror(errno));
179 if (fcntl(s, F_SETFL, flags | O_NONBLOCK) < 0) {
180 ast_log(LOG_WARNING, "Fnctl(F_SETFL) failed: %s\n", strerror(errno));
184 memset(&sin, 0, sizeof(sin));
185 sin.sin_family = AF_INET;
186 sin.sin_port = htons(port);
187 memcpy(&sin.sin_addr, hp->h_addr, sizeof(sin.sin_addr));
188 if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) && (errno != EINPROGRESS)) {
189 ast_log(LOG_WARNING, "Connect failed with unexpected error: %s\n", strerror(errno));
194 pfds[0].events = POLLOUT;
195 if (poll(pfds, 1, MAX_AGI_CONNECT) != 1) {
196 ast_log(LOG_WARNING, "Connect to '%s' failed!\n", agiurl);
200 if (write(s, "agi_network: yes\n", strlen("agi_network: yes\n")) < 0) {
201 ast_log(LOG_WARNING, "Connect to '%s' failed: %s\n", agiurl, strerror(errno));
206 /* If we have a script parameter, relay it to the fastagi server */
207 if (!ast_strlen_zero(script))
208 fdprintf(s, "agi_network_script: %s\n", script);
210 if (option_debug > 3)
211 ast_log(LOG_DEBUG, "Wow, connected!\n");
218 static int launch_script(char *script, char *argv[], int *fds, int *efd, int *opid)
229 if (!strncasecmp(script, "agi://", 6))
230 return launch_netscript(script, argv, fds, efd, opid);
232 if (script[0] != '/') {
233 snprintf(tmp, sizeof(tmp), "%s/%s", (char *)ast_config_AST_AGI_DIR, script);
237 ast_log(LOG_WARNING, "Unable to create toast pipe: %s\n",strerror(errno));
241 ast_log(LOG_WARNING, "unable to create fromast pipe: %s\n", strerror(errno));
248 ast_log(LOG_WARNING, "unable to create audio pipe: %s\n", strerror(errno));
255 res = fcntl(audio[1], F_GETFL);
257 res = fcntl(audio[1], F_SETFL, res | O_NONBLOCK);
259 ast_log(LOG_WARNING, "unable to set audio pipe parameters: %s\n", strerror(errno));
271 ast_log(LOG_WARNING, "Failed to fork(): %s\n", strerror(errno));
275 /* Redirect stdin and out, provide enhanced audio channel if desired */
276 dup2(fromast[0], STDIN_FILENO);
277 dup2(toast[1], STDOUT_FILENO);
279 dup2(audio[0], STDERR_FILENO + 1);
281 close(STDERR_FILENO + 1);
284 /* unblock important signal handlers */
285 if (sigfillset(&signal_set) || pthread_sigmask(SIG_UNBLOCK, &signal_set, NULL)) {
286 ast_log(LOG_WARNING, "unable to unblock signals for AGI script: %s\n", strerror(errno));
290 /* Close everything but stdin/out/error */
291 for (x=STDERR_FILENO + 2;x<1024;x++)
294 /* Don't run AGI scripts with realtime priority -- it causes audio stutter */
299 /* Can't use ast_log since FD's are closed */
300 fprintf(stderr, "Failed to execute '%s': %s\n", script, strerror(errno));
303 if (option_verbose > 2)
304 ast_verbose(VERBOSE_PREFIX_3 "Launched AGI Script %s\n", script);
310 /* close what we're not using in the parent */
324 static void setup_env(struct ast_channel *chan, char *request, int fd, int enhanced)
326 /* Print initial environment, with agi_request always being the first
328 fdprintf(fd, "agi_request: %s\n", request);
329 fdprintf(fd, "agi_channel: %s\n", chan->name);
330 fdprintf(fd, "agi_language: %s\n", chan->language);
331 fdprintf(fd, "agi_type: %s\n", chan->type);
332 fdprintf(fd, "agi_uniqueid: %s\n", chan->uniqueid);
335 fdprintf(fd, "agi_callerid: %s\n", chan->cid.cid_num ? chan->cid.cid_num : "unknown");
336 fdprintf(fd, "agi_calleridname: %s\n", chan->cid.cid_name ? chan->cid.cid_name : "unknown");
337 fdprintf(fd, "agi_callingpres: %d\n", chan->cid.cid_pres);
338 fdprintf(fd, "agi_callingani2: %d\n", chan->cid.cid_ani2);
339 fdprintf(fd, "agi_callington: %d\n", chan->cid.cid_ton);
340 fdprintf(fd, "agi_callingtns: %d\n", chan->cid.cid_tns);
341 fdprintf(fd, "agi_dnid: %s\n", chan->cid.cid_dnid ? chan->cid.cid_dnid : "unknown");
342 fdprintf(fd, "agi_rdnis: %s\n", chan->cid.cid_rdnis ? chan->cid.cid_rdnis : "unknown");
344 /* Context information */
345 fdprintf(fd, "agi_context: %s\n", chan->context);
346 fdprintf(fd, "agi_extension: %s\n", chan->exten);
347 fdprintf(fd, "agi_priority: %d\n", chan->priority);
348 fdprintf(fd, "agi_enhanced: %s\n", enhanced ? "1.0" : "0.0");
350 /* User information */
351 fdprintf(fd, "agi_accountcode: %s\n", chan->accountcode ? chan->accountcode : "");
353 /* End with empty return */
357 static int handle_answer(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
361 if (chan->_state != AST_STATE_UP) {
362 /* Answer the chan */
363 res = ast_answer(chan);
365 fdprintf(agi->fd, "200 result=%d\n", res);
367 return RESULT_SUCCESS;
369 return RESULT_FAILURE;
372 static int handle_waitfordigit(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
377 return RESULT_SHOWUSAGE;
378 if (sscanf(argv[3], "%d", &to) != 1)
379 return RESULT_SHOWUSAGE;
380 res = ast_waitfordigit_full(chan, to, agi->audio, agi->ctrl);
381 fdprintf(agi->fd, "200 result=%d\n", res);
383 return RESULT_SUCCESS;
385 return RESULT_FAILURE;
388 static int handle_sendtext(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
392 return RESULT_SHOWUSAGE;
393 /* At the moment, the parser (perhaps broken) returns with
394 the last argument PLUS the newline at the end of the input
395 buffer. This probably needs to be fixed, but I wont do that
396 because other stuff may break as a result. The right way
397 would probably be to strip off the trailing newline before
398 parsing, then here, add a newline at the end of the string
399 before sending it to ast_sendtext --DUDE */
400 res = ast_sendtext(chan, argv[2]);
401 fdprintf(agi->fd, "200 result=%d\n", res);
403 return RESULT_SUCCESS;
405 return RESULT_FAILURE;
408 static int handle_recvchar(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
412 return RESULT_SHOWUSAGE;
413 res = ast_recvchar(chan,atoi(argv[2]));
415 fdprintf(agi->fd, "200 result=%d (timeout)\n", res);
416 return RESULT_SUCCESS;
419 fdprintf(agi->fd, "200 result=%d\n", res);
420 return RESULT_SUCCESS;
423 fdprintf(agi->fd, "200 result=%d (hangup)\n", res);
424 return RESULT_FAILURE;
428 static int handle_recvtext(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
433 return RESULT_SHOWUSAGE;
434 buf = ast_recvtext(chan,atoi(argv[2]));
436 fdprintf(agi->fd, "200 result=1 (%s)\n", buf);
439 fdprintf(agi->fd, "200 result=-1\n");
441 return RESULT_SUCCESS;
444 static int handle_tddmode(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
448 return RESULT_SHOWUSAGE;
449 if (!strncasecmp(argv[2],"on",2))
453 if (!strncasecmp(argv[2],"mate",4))
455 if (!strncasecmp(argv[2],"tdd",3))
457 res = ast_channel_setoption(chan, AST_OPTION_TDD, &x, sizeof(char), 0);
458 if (res != RESULT_SUCCESS)
459 fdprintf(agi->fd, "200 result=0\n");
461 fdprintf(agi->fd, "200 result=1\n");
462 return RESULT_SUCCESS;
465 static int handle_sendimage(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
469 return RESULT_SHOWUSAGE;
470 res = ast_send_image(chan, argv[2]);
471 if (!ast_check_hangup(chan))
473 fdprintf(agi->fd, "200 result=%d\n", res);
475 return RESULT_SUCCESS;
477 return RESULT_FAILURE;
480 static int handle_controlstreamfile(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
489 if (argc < 5 || argc > 9)
490 return RESULT_SHOWUSAGE;
492 if (!ast_strlen_zero(argv[4]))
497 if ((argc > 5) && (sscanf(argv[5], "%d", &skipms) != 1))
498 return RESULT_SHOWUSAGE;
500 if (argc > 6 && !ast_strlen_zero(argv[8]))
505 if (argc > 7 && !ast_strlen_zero(argv[8]))
510 if (argc > 8 && !ast_strlen_zero(argv[8]))
515 res = ast_control_streamfile(chan, argv[3], fwd, rev, stop, pause, NULL, skipms);
517 fdprintf(agi->fd, "200 result=%d\n", res);
520 return RESULT_SUCCESS;
522 return RESULT_FAILURE;
525 static int handle_streamfile(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
528 struct ast_filestream *fs;
529 long sample_offset = 0;
533 return RESULT_SHOWUSAGE;
535 return RESULT_SHOWUSAGE;
536 if ((argc > 4) && (sscanf(argv[4], "%ld", &sample_offset) != 1))
537 return RESULT_SHOWUSAGE;
539 fs = ast_openstream(chan, argv[2], chan->language);
541 fdprintf(agi->fd, "200 result=%d endpos=%ld\n", 0, sample_offset);
542 return RESULT_SUCCESS;
544 ast_seekstream(fs, 0, SEEK_END);
545 max_length = ast_tellstream(fs);
546 ast_seekstream(fs, sample_offset, SEEK_SET);
547 res = ast_applystream(chan, fs);
548 res = ast_playstream(fs);
550 fdprintf(agi->fd, "200 result=%d endpos=%ld\n", res, sample_offset);
552 return RESULT_SHOWUSAGE;
554 return RESULT_FAILURE;
556 res = ast_waitstream_full(chan, argv[3], agi->audio, agi->ctrl);
557 /* this is to check for if ast_waitstream closed the stream, we probably are at
558 * the end of the stream, return that amount, else check for the amount */
559 sample_offset = (chan->stream) ? ast_tellstream(fs) : max_length;
560 ast_stopstream(chan);
562 /* Stop this command, don't print a result line, as there is a new command */
563 return RESULT_SUCCESS;
565 fdprintf(agi->fd, "200 result=%d endpos=%ld\n", res, sample_offset);
567 return RESULT_SUCCESS;
569 return RESULT_FAILURE;
572 /* get option - really similar to the handle_streamfile, but with a timeout */
573 static int handle_getoption(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
576 struct ast_filestream *fs;
577 long sample_offset = 0;
580 char *edigits = NULL;
582 if ( argc < 4 || argc > 5 )
583 return RESULT_SHOWUSAGE;
589 timeout = atoi(argv[4]);
590 else if (chan->pbx->dtimeout) {
591 /* by default dtimeout is set to 5sec */
592 timeout = chan->pbx->dtimeout * 1000; /* in msec */
595 fs = ast_openstream(chan, argv[2], chan->language);
597 fdprintf(agi->fd, "200 result=%d endpos=%ld\n", 0, sample_offset);
598 ast_log(LOG_WARNING, "Unable to open %s\n", argv[2]);
599 return RESULT_SUCCESS;
601 if (option_verbose > 2)
602 ast_verbose(VERBOSE_PREFIX_3 "Playing '%s' (escape_digits=%s) (timeout %d)\n", argv[2], edigits, timeout);
604 ast_seekstream(fs, 0, SEEK_END);
605 max_length = ast_tellstream(fs);
606 ast_seekstream(fs, sample_offset, SEEK_SET);
607 res = ast_applystream(chan, fs);
608 res = ast_playstream(fs);
610 fdprintf(agi->fd, "200 result=%d endpos=%ld\n", res, sample_offset);
612 return RESULT_SHOWUSAGE;
614 return RESULT_FAILURE;
616 res = ast_waitstream_full(chan, argv[3], agi->audio, agi->ctrl);
617 /* this is to check for if ast_waitstream closed the stream, we probably are at
618 * the end of the stream, return that amount, else check for the amount */
619 sample_offset = (chan->stream)?ast_tellstream(fs):max_length;
620 ast_stopstream(chan);
622 /* Stop this command, don't print a result line, as there is a new command */
623 return RESULT_SUCCESS;
626 /* If the user didnt press a key, wait for digitTimeout*/
628 res = ast_waitfordigit_full(chan, timeout, agi->audio, agi->ctrl);
629 /* Make sure the new result is in the escape digits of the GET OPTION */
630 if ( !strchr(edigits,res) )
634 fdprintf(agi->fd, "200 result=%d endpos=%ld\n", res, sample_offset);
636 return RESULT_SUCCESS;
638 return RESULT_FAILURE;
644 /*--- handle_saynumber: Say number in various language syntaxes ---*/
645 /* Need to add option for gender here as well. Coders wanted */
646 /* While waiting, we're sending a (char *) NULL. */
647 static int handle_saynumber(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
652 return RESULT_SHOWUSAGE;
653 if (sscanf(argv[2], "%d", &num) != 1)
654 return RESULT_SHOWUSAGE;
655 res = ast_say_number_full(chan, num, argv[3], chan->language, (char *) NULL, agi->audio, agi->ctrl);
657 return RESULT_SUCCESS;
658 fdprintf(agi->fd, "200 result=%d\n", res);
660 return RESULT_SUCCESS;
662 return RESULT_FAILURE;
665 static int handle_saydigits(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
671 return RESULT_SHOWUSAGE;
672 if (sscanf(argv[2], "%d", &num) != 1)
673 return RESULT_SHOWUSAGE;
675 res = ast_say_digit_str_full(chan, argv[2], argv[3], chan->language, agi->audio, agi->ctrl);
676 if (res == 1) /* New command */
677 return RESULT_SUCCESS;
678 fdprintf(agi->fd, "200 result=%d\n", res);
680 return RESULT_SUCCESS;
682 return RESULT_FAILURE;
685 static int handle_sayalpha(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
690 return RESULT_SHOWUSAGE;
692 res = ast_say_character_str_full(chan, argv[2], argv[3], chan->language, agi->audio, agi->ctrl);
693 if (res == 1) /* New command */
694 return RESULT_SUCCESS;
695 fdprintf(agi->fd, "200 result=%d\n", res);
697 return RESULT_SUCCESS;
699 return RESULT_FAILURE;
702 static int handle_saydate(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
707 return RESULT_SHOWUSAGE;
708 if (sscanf(argv[2], "%d", &num) != 1)
709 return RESULT_SHOWUSAGE;
710 res = ast_say_date(chan, num, argv[3], chan->language);
712 return RESULT_SUCCESS;
713 fdprintf(agi->fd, "200 result=%d\n", res);
715 return RESULT_SUCCESS;
717 return RESULT_FAILURE;
720 static int handle_saytime(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
725 return RESULT_SHOWUSAGE;
726 if (sscanf(argv[2], "%d", &num) != 1)
727 return RESULT_SHOWUSAGE;
728 res = ast_say_time(chan, num, argv[3], chan->language);
730 return RESULT_SUCCESS;
731 fdprintf(agi->fd, "200 result=%d\n", res);
733 return RESULT_SUCCESS;
735 return RESULT_FAILURE;
738 static int handle_saydatetime(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
742 char *format, *zone=NULL;
745 return RESULT_SHOWUSAGE;
750 if (!strcasecmp(chan->language, "de")) {
751 format = "A dBY HMS";
753 format = "ABdY 'digits/at' IMp";
757 if (argc > 5 && !ast_strlen_zero(argv[5]))
760 if (sscanf(argv[2], "%ld", &unixtime) != 1)
761 return RESULT_SHOWUSAGE;
763 res = ast_say_date_with_format(chan, (time_t) unixtime, argv[3], chan->language, format, zone);
765 return RESULT_SUCCESS;
767 fdprintf(agi->fd, "200 result=%d\n", res);
770 return RESULT_SUCCESS;
772 return RESULT_FAILURE;
775 static int handle_sayphonetic(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
780 return RESULT_SHOWUSAGE;
782 res = ast_say_phonetic_str_full(chan, argv[2], argv[3], chan->language, agi->audio, agi->ctrl);
783 if (res == 1) /* New command */
784 return RESULT_SUCCESS;
785 fdprintf(agi->fd, "200 result=%d\n", res);
787 return RESULT_SUCCESS;
789 return RESULT_FAILURE;
792 static int handle_getdata(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
800 return RESULT_SHOWUSAGE;
802 timeout = atoi(argv[3]);
809 res = ast_app_getdata_full(chan, argv[2], data, max, timeout, agi->audio, agi->ctrl);
810 if (res == 2) /* New command */
811 return RESULT_SUCCESS;
813 fdprintf(agi->fd, "200 result=%s (timeout)\n", data);
815 fdprintf(agi->fd, "200 result=-1\n");
817 fdprintf(agi->fd, "200 result=%s\n", data);
818 return RESULT_SUCCESS;
821 static int handle_setcontext(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
825 return RESULT_SHOWUSAGE;
826 ast_copy_string(chan->context, argv[2], sizeof(chan->context));
827 fdprintf(agi->fd, "200 result=0\n");
828 return RESULT_SUCCESS;
831 static int handle_setextension(struct ast_channel *chan, AGI *agi, int argc, char **argv)
834 return RESULT_SHOWUSAGE;
835 ast_copy_string(chan->exten, argv[2], sizeof(chan->exten));
836 fdprintf(agi->fd, "200 result=0\n");
837 return RESULT_SUCCESS;
840 static int handle_setpriority(struct ast_channel *chan, AGI *agi, int argc, char **argv)
844 return RESULT_SHOWUSAGE;
846 if (sscanf(argv[2], "%d", &pri) != 1) {
847 if ((pri = ast_findlabel_extension(chan, chan->context, chan->exten, argv[2], chan->cid.cid_num)) < 1)
848 return RESULT_SHOWUSAGE;
851 ast_explicit_goto(chan, NULL, NULL, pri);
852 fdprintf(agi->fd, "200 result=0\n");
853 return RESULT_SUCCESS;
856 static int handle_recordfile(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
858 struct ast_filestream *fs;
860 struct timeval start;
861 long sample_offset = 0;
865 struct ast_dsp *sildet=NULL; /* silence detector dsp */
866 int totalsilence = 0;
868 int silence = 0; /* amount of silence to allow */
869 int gotsilence = 0; /* did we timeout for silence? */
870 char *silencestr=NULL;
874 /* XXX EAGI FIXME XXX */
877 return RESULT_SHOWUSAGE;
878 if (sscanf(argv[5], "%d", &ms) != 1)
879 return RESULT_SHOWUSAGE;
882 silencestr = strchr(argv[6],'s');
883 if ((argc > 7) && (!silencestr))
884 silencestr = strchr(argv[7],'s');
885 if ((argc > 8) && (!silencestr))
886 silencestr = strchr(argv[8],'s');
889 if (strlen(silencestr) > 2) {
890 if ((silencestr[0] == 's') && (silencestr[1] == '=')) {
894 silence = atoi(silencestr);
902 rfmt = chan->readformat;
903 res = ast_set_read_format(chan, AST_FORMAT_SLINEAR);
905 ast_log(LOG_WARNING, "Unable to set to linear mode, giving up\n");
908 sildet = ast_dsp_new();
910 ast_log(LOG_WARNING, "Unable to create silence detector :(\n");
913 ast_dsp_set_threshold(sildet, 256);
916 /* backward compatibility, if no offset given, arg[6] would have been
917 * caught below and taken to be a beep, else if it is a digit then it is a
919 if ((argc >6) && (sscanf(argv[6], "%ld", &sample_offset) != 1) && (!strchr(argv[6], '=')))
920 res = ast_streamfile(chan, "beep", chan->language);
922 if ((argc > 7) && (!strchr(argv[7], '=')))
923 res = ast_streamfile(chan, "beep", chan->language);
926 res = ast_waitstream(chan, argv[4]);
928 fdprintf(agi->fd, "200 result=%d (randomerror) endpos=%ld\n", res, sample_offset);
930 fs = ast_writefile(argv[2], argv[3], NULL, O_CREAT | O_WRONLY | (sample_offset ? O_APPEND : 0), 0, 0644);
933 fdprintf(agi->fd, "200 result=%d (writefile)\n", res);
935 ast_dsp_free(sildet);
936 return RESULT_FAILURE;
940 ast_applystream(chan,fs);
941 /* really should have checks */
942 ast_seekstream(fs, sample_offset, SEEK_SET);
946 while ((ms < 0) || ast_tvdiff_ms(ast_tvnow(), start) < ms) {
947 res = ast_waitfor(chan, -1);
950 fdprintf(agi->fd, "200 result=%d (waitfor) endpos=%ld\n", res,sample_offset);
952 ast_dsp_free(sildet);
953 return RESULT_FAILURE;
957 fdprintf(agi->fd, "200 result=%d (hangup) endpos=%ld\n", 0, sample_offset);
960 ast_dsp_free(sildet);
961 return RESULT_FAILURE;
963 switch(f->frametype) {
965 if (strchr(argv[4], f->subclass)) {
966 /* This is an interrupting chracter, so rewind to chop off any small
967 amount of DTMF that may have been recorded
969 ast_stream_rewind(fs, 200);
971 sample_offset = ast_tellstream(fs);
972 fdprintf(agi->fd, "200 result=%d (dtmf) endpos=%ld\n", f->subclass, sample_offset);
976 ast_dsp_free(sildet);
977 return RESULT_SUCCESS;
980 case AST_FRAME_VOICE:
981 ast_writestream(fs, f);
982 /* this is a safe place to check progress since we know that fs
983 * is valid after a write, and it will then have our current
985 sample_offset = ast_tellstream(fs);
988 ast_dsp_silence(sildet, f, &dspsilence);
990 totalsilence = dspsilence;
994 if (totalsilence > silence) {
995 /* Ended happily with silence */
1009 ast_stream_rewind(fs, silence-1000);
1010 ast_truncstream(fs);
1011 sample_offset = ast_tellstream(fs);
1013 fdprintf(agi->fd, "200 result=%d (timeout) endpos=%ld\n", res, sample_offset);
1014 ast_closestream(fs);
1018 res = ast_set_read_format(chan, rfmt);
1020 ast_log(LOG_WARNING, "Unable to restore read format on '%s'\n", chan->name);
1021 ast_dsp_free(sildet);
1023 return RESULT_SUCCESS;
1026 static int handle_autohangup(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
1031 return RESULT_SHOWUSAGE;
1032 if (sscanf(argv[2], "%d", &timeout) != 1)
1033 return RESULT_SHOWUSAGE;
1037 chan->whentohangup = time(NULL) + timeout;
1039 chan->whentohangup = 0;
1040 fdprintf(agi->fd, "200 result=0\n");
1041 return RESULT_SUCCESS;
1044 static int handle_hangup(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1046 struct ast_channel *c;
1048 /* no argument: hangup the current channel */
1049 ast_softhangup(chan,AST_SOFTHANGUP_EXPLICIT);
1050 fdprintf(agi->fd, "200 result=1\n");
1051 return RESULT_SUCCESS;
1052 } else if (argc == 2) {
1053 /* one argument: look for info on the specified channel */
1054 c = ast_get_channel_by_name_locked(argv[1]);
1056 /* we have a matching channel */
1057 ast_softhangup(c,AST_SOFTHANGUP_EXPLICIT);
1058 fdprintf(agi->fd, "200 result=1\n");
1059 ast_mutex_unlock(&c->lock);
1060 return RESULT_SUCCESS;
1062 /* if we get this far no channel name matched the argument given */
1063 fdprintf(agi->fd, "200 result=-1\n");
1064 return RESULT_SUCCESS;
1066 return RESULT_SHOWUSAGE;
1070 static int handle_exec(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1073 struct ast_app *app;
1076 return RESULT_SHOWUSAGE;
1078 if (option_verbose > 2)
1079 ast_verbose(VERBOSE_PREFIX_3 "AGI Script Executing Application: (%s) Options: (%s)\n", argv[1], argv[2]);
1081 app = pbx_findapp(argv[1]);
1084 res = pbx_exec(chan, app, argv[2], 1);
1086 ast_log(LOG_WARNING, "Could not find application (%s)\n", argv[1]);
1089 fdprintf(agi->fd, "200 result=%d\n", res);
1094 static int handle_setcallerid(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1097 char *l = NULL, *n = NULL;
1100 ast_copy_string(tmp, argv[2], sizeof(tmp));
1101 ast_callerid_parse(tmp, &n, &l);
1103 ast_shrink_phone_number(l);
1108 ast_set_callerid(chan, l, n, NULL);
1111 fdprintf(agi->fd, "200 result=1\n");
1112 return RESULT_SUCCESS;
1115 static int handle_channelstatus(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1117 struct ast_channel *c;
1119 /* no argument: supply info on the current channel */
1120 fdprintf(agi->fd, "200 result=%d\n", chan->_state);
1121 return RESULT_SUCCESS;
1122 } else if (argc == 3) {
1123 /* one argument: look for info on the specified channel */
1124 c = ast_get_channel_by_name_locked(argv[2]);
1126 fdprintf(agi->fd, "200 result=%d\n", c->_state);
1127 ast_mutex_unlock(&c->lock);
1128 return RESULT_SUCCESS;
1130 /* if we get this far no channel name matched the argument given */
1131 fdprintf(agi->fd, "200 result=-1\n");
1132 return RESULT_SUCCESS;
1134 return RESULT_SHOWUSAGE;
1138 static int handle_setvariable(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1141 pbx_builtin_setvar_helper(chan, argv[2], argv[3]);
1143 fdprintf(agi->fd, "200 result=1\n");
1144 return RESULT_SUCCESS;
1147 static int handle_getvariable(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1153 return RESULT_SHOWUSAGE;
1155 /* check if we want to execute an ast_custom_function */
1156 if (!ast_strlen_zero(argv[2]) && (argv[2][strlen(argv[2]) - 1] == ')')) {
1157 ret = ast_func_read(chan, argv[2], tempstr, sizeof(tempstr));
1159 pbx_retrieve_variable(chan, argv[2], &ret, tempstr, sizeof(tempstr), NULL);
1163 fdprintf(agi->fd, "200 result=1 (%s)\n", ret);
1165 fdprintf(agi->fd, "200 result=0\n");
1167 return RESULT_SUCCESS;
1170 static int handle_getvariablefull(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1172 char tmp[4096] = "";
1173 struct ast_channel *chan2=NULL;
1175 if ((argc != 4) && (argc != 5))
1176 return RESULT_SHOWUSAGE;
1178 chan2 = ast_get_channel_by_name_locked(argv[4]);
1182 if (chan) { /* XXX isn't this chan2 ? */
1183 pbx_substitute_variables_helper(chan2, argv[3], tmp, sizeof(tmp) - 1);
1184 fdprintf(agi->fd, "200 result=1 (%s)\n", tmp);
1186 fdprintf(agi->fd, "200 result=0\n");
1188 if (chan2 && (chan2 != chan))
1189 ast_mutex_unlock(&chan2->lock);
1190 return RESULT_SUCCESS;
1193 static int handle_verbose(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1199 return RESULT_SHOWUSAGE;
1202 sscanf(argv[2], "%d", &level);
1206 prefix = VERBOSE_PREFIX_4;
1209 prefix = VERBOSE_PREFIX_3;
1212 prefix = VERBOSE_PREFIX_2;
1216 prefix = VERBOSE_PREFIX_1;
1220 if (level <= option_verbose)
1221 ast_verbose("%s %s: %s\n", prefix, chan->data, argv[1]);
1223 fdprintf(agi->fd, "200 result=1\n");
1225 return RESULT_SUCCESS;
1228 static int handle_dbget(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1234 return RESULT_SHOWUSAGE;
1235 res = ast_db_get(argv[2], argv[3], tmp, sizeof(tmp));
1237 fdprintf(agi->fd, "200 result=0\n");
1239 fdprintf(agi->fd, "200 result=1 (%s)\n", tmp);
1241 return RESULT_SUCCESS;
1244 static int handle_dbput(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1249 return RESULT_SHOWUSAGE;
1250 res = ast_db_put(argv[2], argv[3], argv[4]);
1252 fdprintf(agi->fd, "200 result=0\n");
1254 fdprintf(agi->fd, "200 result=1\n");
1256 return RESULT_SUCCESS;
1259 static int handle_dbdel(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1264 return RESULT_SHOWUSAGE;
1265 res = ast_db_del(argv[2], argv[3]);
1267 fdprintf(agi->fd, "200 result=0\n");
1269 fdprintf(agi->fd, "200 result=1\n");
1271 return RESULT_SUCCESS;
1274 static int handle_dbdeltree(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1277 if ((argc < 3) || (argc > 4))
1278 return RESULT_SHOWUSAGE;
1280 res = ast_db_deltree(argv[2], argv[3]);
1282 res = ast_db_deltree(argv[2], NULL);
1285 fdprintf(agi->fd, "200 result=0\n");
1287 fdprintf(agi->fd, "200 result=1\n");
1288 return RESULT_SUCCESS;
1291 static char debug_usage[] =
1292 "Usage: agi debug\n"
1293 " Enables dumping of AGI transactions for debugging purposes\n";
1295 static char no_debug_usage[] =
1296 "Usage: agi no debug\n"
1297 " Disables dumping of AGI transactions for debugging purposes\n";
1299 static int agi_do_debug(int fd, int argc, char *argv[])
1302 return RESULT_SHOWUSAGE;
1304 ast_cli(fd, "AGI Debugging Enabled\n");
1305 return RESULT_SUCCESS;
1308 static int agi_no_debug(int fd, int argc, char *argv[])
1311 return RESULT_SHOWUSAGE;
1313 ast_cli(fd, "AGI Debugging Disabled\n");
1314 return RESULT_SUCCESS;
1317 static struct ast_cli_entry cli_debug =
1318 { { "agi", "debug", NULL }, agi_do_debug, "Enable AGI debugging", debug_usage };
1320 static struct ast_cli_entry cli_no_debug =
1321 { { "agi", "no", "debug", NULL }, agi_no_debug, "Disable AGI debugging", no_debug_usage };
1323 static int handle_noop(struct ast_channel *chan, AGI *agi, int arg, char *argv[])
1325 fdprintf(agi->fd, "200 result=0\n");
1326 return RESULT_SUCCESS;
1329 static int handle_setmusic(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
1331 if (!strncasecmp(argv[2],"on",2)) {
1333 ast_moh_start(chan, argv[3]);
1335 ast_moh_start(chan, NULL);
1337 if (!strncasecmp(argv[2],"off",3)) {
1340 fdprintf(agi->fd, "200 result=0\n");
1341 return RESULT_SUCCESS;
1344 static char usage_setmusic[] =
1345 " Usage: SET MUSIC ON <on|off> <class>\n"
1346 " Enables/Disables the music on hold generator. If <class> is\n"
1347 " not specified, then the default music on hold class will be used.\n"
1348 " Always returns 0.\n";
1350 static char usage_dbput[] =
1351 " Usage: DATABASE PUT <family> <key> <value>\n"
1352 " Adds or updates an entry in the Asterisk database for a\n"
1353 " given family, key, and value.\n"
1354 " Returns 1 if successful, 0 otherwise.\n";
1356 static char usage_dbget[] =
1357 " Usage: DATABASE GET <family> <key>\n"
1358 " Retrieves an entry in the Asterisk database for a\n"
1359 " given family and key.\n"
1360 " Returns 0 if <key> is not set. Returns 1 if <key>\n"
1361 " is set and returns the variable in parentheses.\n"
1362 " Example return code: 200 result=1 (testvariable)\n";
1364 static char usage_dbdel[] =
1365 " Usage: DATABASE DEL <family> <key>\n"
1366 " Deletes an entry in the Asterisk database for a\n"
1367 " given family and key.\n"
1368 " Returns 1 if successful, 0 otherwise.\n";
1370 static char usage_dbdeltree[] =
1371 " Usage: DATABASE DELTREE <family> [keytree]\n"
1372 " Deletes a family or specific keytree within a family\n"
1373 " in the Asterisk database.\n"
1374 " Returns 1 if successful, 0 otherwise.\n";
1376 static char usage_verbose[] =
1377 " Usage: VERBOSE <message> <level>\n"
1378 " Sends <message> to the console via verbose message system.\n"
1379 " <level> is the the verbose level (1-4)\n"
1380 " Always returns 1.\n";
1382 static char usage_getvariable[] =
1383 " Usage: GET VARIABLE <variablename>\n"
1384 " Returns 0 if <variablename> is not set. Returns 1 if <variablename>\n"
1385 " is set and returns the variable in parentheses.\n"
1386 " example return code: 200 result=1 (testvariable)\n";
1388 static char usage_getvariablefull[] =
1389 " Usage: GET FULL VARIABLE <variablename> [<channel name>]\n"
1390 " Returns 0 if <variablename> is not set or channel does not exist. Returns 1\n"
1391 "if <variablename> is set and returns the variable in parenthesis. Understands\n"
1392 "complex variable names and builtin variables, unlike GET VARIABLE.\n"
1393 " example return code: 200 result=1 (testvariable)\n";
1395 static char usage_setvariable[] =
1396 " Usage: SET VARIABLE <variablename> <value>\n";
1398 static char usage_channelstatus[] =
1399 " Usage: CHANNEL STATUS [<channelname>]\n"
1400 " Returns the status of the specified channel.\n"
1401 " If no channel name is given the returns the status of the\n"
1402 " current channel. Return values:\n"
1403 " 0 Channel is down and available\n"
1404 " 1 Channel is down, but reserved\n"
1405 " 2 Channel is off hook\n"
1406 " 3 Digits (or equivalent) have been dialed\n"
1407 " 4 Line is ringing\n"
1408 " 5 Remote end is ringing\n"
1410 " 7 Line is busy\n";
1412 static char usage_setcallerid[] =
1413 " Usage: SET CALLERID <number>\n"
1414 " Changes the callerid of the current channel.\n";
1416 static char usage_exec[] =
1417 " Usage: EXEC <application> <options>\n"
1418 " Executes <application> with given <options>.\n"
1419 " Returns whatever the application returns, or -2 on failure to find application\n";
1421 static char usage_hangup[] =
1422 " Usage: HANGUP [<channelname>]\n"
1423 " Hangs up the specified channel.\n"
1424 " If no channel name is given, hangs up the current channel\n";
1426 static char usage_answer[] =
1428 " Answers channel if not already in answer state. Returns -1 on\n"
1429 " channel failure, or 0 if successful.\n";
1431 static char usage_waitfordigit[] =
1432 " Usage: WAIT FOR DIGIT <timeout>\n"
1433 " Waits up to 'timeout' milliseconds for channel to receive a DTMF digit.\n"
1434 " Returns -1 on channel failure, 0 if no digit is received in the timeout, or\n"
1435 " the numerical value of the ascii of the digit if one is received. Use -1\n"
1436 " for the timeout value if you desire the call to block indefinitely.\n";
1438 static char usage_sendtext[] =
1439 " Usage: SEND TEXT \"<text to send>\"\n"
1440 " Sends the given text on a channel. Most channels do not support the\n"
1441 " transmission of text. Returns 0 if text is sent, or if the channel does not\n"
1442 " support text transmission. Returns -1 only on error/hangup. Text\n"
1443 " consisting of greater than one word should be placed in quotes since the\n"
1444 " command only accepts a single argument.\n";
1446 static char usage_recvchar[] =
1447 " Usage: RECEIVE CHAR <timeout>\n"
1448 " Receives a character of text on a channel. Specify timeout to be the\n"
1449 " maximum time to wait for input in milliseconds, or 0 for infinite. Most channels\n"
1450 " do not support the reception of text. Returns the decimal value of the character\n"
1451 " if one is received, or 0 if the channel does not support text reception. Returns\n"
1452 " -1 only on error/hangup.\n";
1454 static char usage_recvtext[] =
1455 " Usage: RECEIVE TEXT <timeout>\n"
1456 " Receives a string of text on a channel. Specify timeout to be the\n"
1457 " maximum time to wait for input in milliseconds, or 0 for infinite. Most channels\n"
1458 " do not support the reception of text. Returns -1 for failure or 1 for success, and the string in parentheses.\n";
1460 static char usage_tddmode[] =
1461 " Usage: TDD MODE <on|off>\n"
1462 " Enable/Disable TDD transmission/reception on a channel. Returns 1 if\n"
1463 " successful, or 0 if channel is not TDD-capable.\n";
1465 static char usage_sendimage[] =
1466 " Usage: SEND IMAGE <image>\n"
1467 " Sends the given image on a channel. Most channels do not support the\n"
1468 " transmission of images. Returns 0 if image is sent, or if the channel does not\n"
1469 " support image transmission. Returns -1 only on error/hangup. Image names\n"
1470 " should not include extensions.\n";
1472 static char usage_streamfile[] =
1473 " Usage: STREAM FILE <filename> <escape digits> [sample offset]\n"
1474 " Send the given file, allowing playback to be interrupted by the given\n"
1475 " digits, if any. Use double quotes for the digits if you wish none to be\n"
1476 " permitted. If sample offset is provided then the audio will seek to sample\n"
1477 " offset before play starts. Returns 0 if playback completes without a digit\n"
1478 " being pressed, or the ASCII numerical value of the digit if one was pressed,\n"
1479 " or -1 on error or if the channel was disconnected. Remember, the file\n"
1480 " extension must not be included in the filename.\n";
1482 static char usage_controlstreamfile[] =
1483 " Usage: CONTROL STREAM FILE <filename> <escape digits> [skipms] [ffchar] [rewchr] [pausechr]\n"
1484 " Send the given file, allowing playback to be controled by the given\n"
1485 " digits, if any. Use double quotes for the digits if you wish none to be\n"
1486 " permitted. Returns 0 if playback completes without a digit\n"
1487 " being pressed, or the ASCII numerical value of the digit if one was pressed,\n"
1488 " or -1 on error or if the channel was disconnected. Remember, the file\n"
1489 " extension must not be included in the filename.\n\n"
1490 " Note: ffchar and rewchar default to * and # respectively.\n";
1492 static char usage_getoption[] =
1493 " Usage: GET OPTION <filename> <escape_digits> [timeout]\n"
1494 " Behaves similar to STREAM FILE but used with a timeout option.\n";
1496 static char usage_saynumber[] =
1497 " Usage: SAY NUMBER <number> <escape digits>\n"
1498 " Say a given number, returning early if any of the given DTMF digits\n"
1499 " are received on the channel. Returns 0 if playback completes without a digit\n"
1500 " being pressed, or the ASCII numerical value of the digit if one was pressed or\n"
1501 " -1 on error/hangup.\n";
1503 static char usage_saydigits[] =
1504 " Usage: SAY DIGITS <number> <escape digits>\n"
1505 " Say a given digit string, returning early if any of the given DTMF digits\n"
1506 " are received on the channel. Returns 0 if playback completes without a digit\n"
1507 " being pressed, or the ASCII numerical value of the digit if one was pressed or\n"
1508 " -1 on error/hangup.\n";
1510 static char usage_sayalpha[] =
1511 " Usage: SAY ALPHA <number> <escape digits>\n"
1512 " Say a given character string, returning early if any of the given DTMF digits\n"
1513 " are received on the channel. Returns 0 if playback completes without a digit\n"
1514 " being pressed, or the ASCII numerical value of the digit if one was pressed or\n"
1515 " -1 on error/hangup.\n";
1517 static char usage_saydate[] =
1518 " Usage: SAY DATE <date> <escape digits>\n"
1519 " Say a given date, returning early if any of the given DTMF digits are\n"
1520 " received on the channel. <date> is number of seconds elapsed since 00:00:00\n"
1521 " on January 1, 1970, Coordinated Universal Time (UTC). Returns 0 if playback\n"
1522 " completes without a digit being pressed, or the ASCII numerical value of the\n"
1523 " digit if one was pressed or -1 on error/hangup.\n";
1525 static char usage_saytime[] =
1526 " Usage: SAY TIME <time> <escape digits>\n"
1527 " Say a given time, returning early if any of the given DTMF digits are\n"
1528 " received on the channel. <time> is number of seconds elapsed since 00:00:00\n"
1529 " on January 1, 1970, Coordinated Universal Time (UTC). Returns 0 if playback\n"
1530 " completes without a digit being pressed, or the ASCII numerical value of the\n"
1531 " digit if one was pressed or -1 on error/hangup.\n";
1533 static char usage_saydatetime[] =
1534 " Usage: SAY DATETIME <time> <escape digits> [format] [timezone]\n"
1535 " Say a given time, returning early if any of the given DTMF digits are\n"
1536 " received on the channel. <time> is number of seconds elapsed since 00:00:00\n"
1537 " on January 1, 1970, Coordinated Universal Time (UTC). [format] is the format\n"
1538 " the time should be said in. See voicemail.conf (defaults to \"ABdY\n"
1539 " 'digits/at' IMp\"). Acceptable values for [timezone] can be found in\n"
1540 " /usr/share/zoneinfo. Defaults to machine default. Returns 0 if playback\n"
1541 " completes without a digit being pressed, or the ASCII numerical value of the\n"
1542 " digit if one was pressed or -1 on error/hangup.\n";
1544 static char usage_sayphonetic[] =
1545 " Usage: SAY PHONETIC <string> <escape digits>\n"
1546 " Say a given character string with phonetics, returning early if any of the\n"
1547 " given DTMF digits are received on the channel. Returns 0 if playback\n"
1548 " completes without a digit pressed, the ASCII numerical value of the digit\n"
1549 " if one was pressed, or -1 on error/hangup.\n";
1551 static char usage_getdata[] =
1552 " Usage: GET DATA <file to be streamed> [timeout] [max digits]\n"
1553 " Stream the given file, and recieve DTMF data. Returns the digits received\n"
1554 "from the channel at the other end.\n";
1556 static char usage_setcontext[] =
1557 " Usage: SET CONTEXT <desired context>\n"
1558 " Sets the context for continuation upon exiting the application.\n";
1560 static char usage_setextension[] =
1561 " Usage: SET EXTENSION <new extension>\n"
1562 " Changes the extension for continuation upon exiting the application.\n";
1564 static char usage_setpriority[] =
1565 " Usage: SET PRIORITY <priority>\n"
1566 " Changes the priority for continuation upon exiting the application.\n"
1567 " The priority must be a valid priority or label.\n";
1569 static char usage_recordfile[] =
1570 " Usage: RECORD FILE <filename> <format> <escape digits> <timeout> \\\n"
1571 " [offset samples] [BEEP] [s=silence]\n"
1572 " Record to a file until a given dtmf digit in the sequence is received\n"
1573 " Returns -1 on hangup or error. The format will specify what kind of file\n"
1574 " will be recorded. The timeout is the maximum record time in milliseconds, or\n"
1575 " -1 for no timeout. \"Offset samples\" is optional, and, if provided, will seek\n"
1576 " to the offset without exceeding the end of the file. \"silence\" is the number\n"
1577 " of seconds of silence allowed before the function returns despite the\n"
1578 " lack of dtmf digits or reaching timeout. Silence value must be\n"
1579 " preceeded by \"s=\" and is also optional.\n";
1581 static char usage_autohangup[] =
1582 " Usage: SET AUTOHANGUP <time>\n"
1583 " Cause the channel to automatically hangup at <time> seconds in the\n"
1584 " future. Of course it can be hungup before then as well. Setting to 0 will\n"
1585 " cause the autohangup feature to be disabled on this channel.\n";
1587 static char usage_noop[] =
1591 static agi_command commands[MAX_COMMANDS] = {
1592 { { "answer", NULL }, handle_answer, "Answer channel", usage_answer },
1593 { { "channel", "status", NULL }, handle_channelstatus, "Returns status of the connected channel", usage_channelstatus },
1594 { { "database", "del", NULL }, handle_dbdel, "Removes database key/value", usage_dbdel },
1595 { { "database", "deltree", NULL }, handle_dbdeltree, "Removes database keytree/value", usage_dbdeltree },
1596 { { "database", "get", NULL }, handle_dbget, "Gets database value", usage_dbget },
1597 { { "database", "put", NULL }, handle_dbput, "Adds/updates database value", usage_dbput },
1598 { { "exec", NULL }, handle_exec, "Executes a given Application", usage_exec },
1599 { { "get", "data", NULL }, handle_getdata, "Prompts for DTMF on a channel", usage_getdata },
1600 { { "get", "full", "variable", NULL }, handle_getvariablefull, "Evaluates a channel expression", usage_getvariablefull },
1601 { { "get", "option", NULL }, handle_getoption, "Stream file, prompt for DTMF, with timeout", usage_getoption },
1602 { { "get", "variable", NULL }, handle_getvariable, "Gets a channel variable", usage_getvariable },
1603 { { "hangup", NULL }, handle_hangup, "Hangup the current channel", usage_hangup },
1604 { { "noop", NULL }, handle_noop, "Does nothing", usage_noop },
1605 { { "receive", "char", NULL }, handle_recvchar, "Receives one character from channels supporting it", usage_recvchar },
1606 { { "receive", "text", NULL }, handle_recvtext, "Receives text from channels supporting it", usage_recvtext },
1607 { { "record", "file", NULL }, handle_recordfile, "Records to a given file", usage_recordfile },
1608 { { "say", "alpha", NULL }, handle_sayalpha, "Says a given character string", usage_sayalpha },
1609 { { "say", "digits", NULL }, handle_saydigits, "Says a given digit string", usage_saydigits },
1610 { { "say", "number", NULL }, handle_saynumber, "Says a given number", usage_saynumber },
1611 { { "say", "phonetic", NULL }, handle_sayphonetic, "Says a given character string with phonetics", usage_sayphonetic },
1612 { { "say", "date", NULL }, handle_saydate, "Says a given date", usage_saydate },
1613 { { "say", "time", NULL }, handle_saytime, "Says a given time", usage_saytime },
1614 { { "say", "datetime", NULL }, handle_saydatetime, "Says a given time as specfied by the format given", usage_saydatetime },
1615 { { "send", "image", NULL }, handle_sendimage, "Sends images to channels supporting it", usage_sendimage },
1616 { { "send", "text", NULL }, handle_sendtext, "Sends text to channels supporting it", usage_sendtext },
1617 { { "set", "autohangup", NULL }, handle_autohangup, "Autohangup channel in some time", usage_autohangup },
1618 { { "set", "callerid", NULL }, handle_setcallerid, "Sets callerid for the current channel", usage_setcallerid },
1619 { { "set", "context", NULL }, handle_setcontext, "Sets channel context", usage_setcontext },
1620 { { "set", "extension", NULL }, handle_setextension, "Changes channel extension", usage_setextension },
1621 { { "set", "music", NULL }, handle_setmusic, "Enable/Disable Music on hold generator", usage_setmusic },
1622 { { "set", "priority", NULL }, handle_setpriority, "Set channel dialplan priority", usage_setpriority },
1623 { { "set", "variable", NULL }, handle_setvariable, "Sets a channel variable", usage_setvariable },
1624 { { "stream", "file", NULL }, handle_streamfile, "Sends audio file on channel", usage_streamfile },
1625 { { "control", "stream", "file", NULL }, handle_controlstreamfile, "Sends audio file on channel and allows the listner to control the stream", usage_controlstreamfile },
1626 { { "tdd", "mode", NULL }, handle_tddmode, "Toggles TDD mode (for the deaf)", usage_tddmode },
1627 { { "verbose", NULL }, handle_verbose, "Logs a message to the asterisk verbose log", usage_verbose },
1628 { { "wait", "for", "digit", NULL }, handle_waitfordigit, "Waits for a digit to be pressed", usage_waitfordigit },
1631 static int help_workhorse(int fd, char *match[])
1636 struct agi_command *e;
1638 ast_join(matchstr, sizeof(matchstr), match);
1639 for (x=0;x<sizeof(commands)/sizeof(commands[0]);x++) {
1643 /* Hide commands that start with '_' */
1644 if ((e->cmda[0])[0] == '_')
1646 ast_join(fullcmd, sizeof(fullcmd), e->cmda);
1647 if (match && strncasecmp(matchstr, fullcmd, strlen(matchstr)))
1649 ast_cli(fd, "%20.20s %s\n", fullcmd, e->summary);
1654 int agi_register(agi_command *agi)
1657 for (x=0; x<MAX_COMMANDS - 1; x++) {
1658 if (commands[x].cmda[0] == agi->cmda[0]) {
1659 ast_log(LOG_WARNING, "Command already registered!\n");
1663 for (x=0; x<MAX_COMMANDS - 1; x++) {
1664 if (!commands[x].cmda[0]) {
1669 ast_log(LOG_WARNING, "No more room for new commands!\n");
1673 void agi_unregister(agi_command *agi)
1676 for (x=0; x<MAX_COMMANDS - 1; x++) {
1677 if (commands[x].cmda[0] == agi->cmda[0]) {
1678 memset(&commands[x], 0, sizeof(agi_command));
1683 static agi_command *find_command(char *cmds[], int exact)
1689 for (x=0; x < sizeof(commands) / sizeof(commands[0]); x++) {
1690 if (!commands[x].cmda[0])
1692 /* start optimistic */
1694 for (y=0; match && cmds[y]; y++) {
1695 /* If there are no more words in the command (and we're looking for
1696 an exact match) or there is a difference between the two words,
1697 then this is not a match */
1698 if (!commands[x].cmda[y] && !exact)
1700 /* don't segfault if the next part of a command doesn't exist */
1701 if (!commands[x].cmda[y])
1703 if (strcasecmp(commands[x].cmda[y], cmds[y]))
1706 /* If more words are needed to complete the command then this is not
1707 a candidate (unless we're looking for a really inexact answer */
1708 if ((exact > -1) && commands[x].cmda[y])
1711 return &commands[x];
1717 static int parse_args(char *s, int *max, char *argv[])
1729 /* If it's escaped, put a literal quote */
1734 if (quoted && whitespace) {
1735 /* If we're starting a quote, coming off white space start a new word, too */
1743 if (!quoted && !escaped) {
1744 /* If we're not quoted, mark this as whitespace, and
1745 end the previous argument */
1749 /* Otherwise, just treat it as anything else */
1753 /* If we're escaped, print a literal, otherwise enable escaping */
1763 if (x >= MAX_ARGS -1) {
1764 ast_log(LOG_WARNING, "Too many arguments, truncating\n");
1767 /* Coming off of whitespace, start the next argument */
1776 /* Null terminate */
1783 static int agi_handle_command(struct ast_channel *chan, AGI *agi, char *buf)
1785 char *argv[MAX_ARGS];
1786 int argc = MAX_ARGS;
1790 parse_args(buf, &argc, argv);
1793 for (x=0; x<argc; x++)
1794 fprintf(stderr, "Got Arg%d: %s\n", x, argv[x]); }
1796 c = find_command(argv, 0);
1798 res = c->handler(chan, agi, argc, argv);
1800 case RESULT_SHOWUSAGE:
1801 fdprintf(agi->fd, "520-Invalid command syntax. Proper usage follows:\n");
1802 fdprintf(agi->fd, c->usage);
1803 fdprintf(agi->fd, "520 End of proper usage.\n");
1805 case AST_PBX_KEEPALIVE:
1806 /* We've been asked to keep alive, so do so */
1807 return AST_PBX_KEEPALIVE;
1809 case RESULT_FAILURE:
1810 /* They've already given the failure. We've been hung up on so handle this
1815 fdprintf(agi->fd, "510 Invalid or unknown command\n");
1820 static int run_agi(struct ast_channel *chan, char *request, AGI *agi, int pid, int dead)
1822 struct ast_channel *c;
1825 int returnstatus = 0;
1826 struct ast_frame *f;
1829 /* how many times we'll retry if ast_waitfor_nandfs will return without either
1830 channel or file descriptor in case select is interrupted by a system call (EINTR) */
1833 if (!(readf = fdopen(agi->ctrl, "r"))) {
1834 ast_log(LOG_WARNING, "Unable to fdopen file descriptor\n");
1841 setup_env(chan, request, agi->fd, (agi->audio > -1));
1844 c = ast_waitfor_nandfds(&chan, dead ? 0 : 1, &agi->ctrl, 1, NULL, &outfd, &ms);
1847 /* Idle the channel until we get a command */
1850 ast_log(LOG_DEBUG, "%s hungup\n", chan->name);
1854 /* If it's voice, write it to the audio pipe */
1855 if ((agi->audio > -1) && (f->frametype == AST_FRAME_VOICE)) {
1856 /* Write, ignoring errors */
1857 write(agi->audio, f->data, f->datalen);
1861 } else if (outfd > -1) {
1863 if (!fgets(buf, sizeof(buf), readf)) {
1864 /* Program terminated */
1867 if (option_verbose > 2)
1868 ast_verbose(VERBOSE_PREFIX_3 "AGI Script %s completed, returning %d\n", request, returnstatus);
1869 /* No need to kill the pid anymore, since they closed us */
1873 /* get rid of trailing newline, if any */
1874 if (*buf && buf[strlen(buf) - 1] == '\n')
1875 buf[strlen(buf) - 1] = 0;
1877 ast_verbose("AGI Rx << %s\n", buf);
1878 returnstatus |= agi_handle_command(chan, agi, buf);
1879 /* If the handle_command returns -1, we need to stop */
1880 if ((returnstatus < 0) || (returnstatus == AST_PBX_KEEPALIVE)) {
1885 ast_log(LOG_WARNING, "No channel, no fd?\n");
1891 /* Notify process */
1893 if (kill(pid, SIGHUP))
1894 ast_log(LOG_WARNING, "unable to send SIGHUP to AGI process %d: %s\n", pid, strerror(errno));
1897 return returnstatus;
1900 static int handle_showagi(int fd, int argc, char *argv[]) {
1901 struct agi_command *e;
1904 return RESULT_SHOWUSAGE;
1906 e = find_command(argv + 2, 1);
1908 ast_cli(fd, e->usage);
1910 if (find_command(argv + 2, -1)) {
1911 return help_workhorse(fd, argv + 1);
1913 ast_join(fullcmd, sizeof(fullcmd), argv+1);
1914 ast_cli(fd, "No such command '%s'.\n", fullcmd);
1918 return help_workhorse(fd, NULL);
1920 return RESULT_SUCCESS;
1923 static int handle_dumpagihtml(int fd, int argc, char *argv[]) {
1924 struct agi_command *e;
1930 return RESULT_SHOWUSAGE;
1932 if (!(htmlfile = fopen(argv[2], "wt"))) {
1933 ast_cli(fd, "Could not create file '%s'\n", argv[2]);
1934 return RESULT_SHOWUSAGE;
1937 fprintf(htmlfile, "<HTML>\n<HEAD>\n<TITLE>AGI Commands</TITLE>\n</HEAD>\n");
1938 fprintf(htmlfile, "<BODY>\n<CENTER><B><H1>AGI Commands</H1></B></CENTER>\n\n");
1941 fprintf(htmlfile, "<TABLE BORDER=\"0\" CELLSPACING=\"10\">\n");
1943 for (x=0;x<sizeof(commands)/sizeof(commands[0]);x++) {
1944 char *stringp, *tempstr;
1947 if (!e->cmda[0]) /* end ? */
1949 /* Hide commands that start with '_' */
1950 if ((e->cmda[0])[0] == '_')
1952 ast_join(fullcmd, sizeof(fullcmd), e->cmda);
1954 fprintf(htmlfile, "<TR><TD><TABLE BORDER=\"1\" CELLPADDING=\"5\" WIDTH=\"100%%\">\n");
1955 fprintf(htmlfile, "<TR><TH ALIGN=\"CENTER\"><B>%s - %s</B></TD></TR>\n", fullcmd,e->summary);
1958 tempstr = strsep(&stringp, "\n");
1960 fprintf(htmlfile, "<TR><TD ALIGN=\"CENTER\">%s</TD></TR>\n", tempstr);
1962 fprintf(htmlfile, "<TR><TD ALIGN=\"CENTER\">\n");
1963 while ((tempstr = strsep(&stringp, "\n")) != NULL)
1964 fprintf(htmlfile, "%s<BR>\n",tempstr);
1965 fprintf(htmlfile, "</TD></TR>\n");
1966 fprintf(htmlfile, "</TABLE></TD></TR>\n\n");
1970 fprintf(htmlfile, "</TABLE>\n</BODY>\n</HTML>\n");
1972 ast_cli(fd, "AGI HTML Commands Dumped to: %s\n", argv[2]);
1973 return RESULT_SUCCESS;
1976 static int agi_exec_full(struct ast_channel *chan, void *data, int enhanced, int dead)
1979 struct localuser *u;
1980 char *argv[MAX_ARGS];
1982 char *tmp = (char *)buf;
1990 if (ast_strlen_zero(data)) {
1991 ast_log(LOG_WARNING, "AGI requires an argument (script)\n");
1994 ast_copy_string(buf, data, sizeof(buf));
1996 memset(&agi, 0, sizeof(agi));
1997 while ((stringp = strsep(&tmp, "|")) && argc < MAX_ARGS-1)
1998 argv[argc++] = stringp;
2003 /* Answer if need be */
2004 if (chan->_state != AST_STATE_UP) {
2005 if (ast_answer(chan)) {
2006 LOCAL_USER_REMOVE(u);
2011 res = launch_script(argv[0], argv, fds, enhanced ? &efd : NULL, &pid);
2016 res = run_agi(chan, argv[0], &agi, pid, dead);
2021 LOCAL_USER_REMOVE(u);
2025 static int agi_exec(struct ast_channel *chan, void *data)
2027 if (chan->_softhangup)
2028 ast_log(LOG_WARNING, "If you want to run AGI on hungup channels you should use DeadAGI!\n");
2029 return agi_exec_full(chan, data, 0, 0);
2032 static int eagi_exec(struct ast_channel *chan, void *data)
2037 if (chan->_softhangup)
2038 ast_log(LOG_WARNING, "If you want to run AGI on hungup channels you should use DeadAGI!\n");
2039 readformat = chan->readformat;
2040 if (ast_set_read_format(chan, AST_FORMAT_SLINEAR)) {
2041 ast_log(LOG_WARNING, "Unable to set channel '%s' to linear mode\n", chan->name);
2044 res = agi_exec_full(chan, data, 1, 0);
2046 if (ast_set_read_format(chan, readformat)) {
2047 ast_log(LOG_WARNING, "Unable to restore channel '%s' to format %s\n", chan->name, ast_getformatname(readformat));
2053 static int deadagi_exec(struct ast_channel *chan, void *data)
2055 return agi_exec_full(chan, data, 0, 1);
2058 static char showagi_help[] =
2059 "Usage: show agi [topic]\n"
2060 " When called with a topic as an argument, displays usage\n"
2061 " information on the given command. If called without a\n"
2062 " topic, it provides a list of AGI commands.\n";
2065 static char dumpagihtml_help[] =
2066 "Usage: dump agihtml <filename>\n"
2067 " Dumps the agi command list in html format to given filename\n";
2069 static struct ast_cli_entry showagi =
2070 { { "show", "agi", NULL }, handle_showagi, "Show AGI commands or specific help", showagi_help };
2072 static struct ast_cli_entry dumpagihtml =
2073 { { "dump", "agihtml", NULL }, handle_dumpagihtml, "Dumps a list of agi command in html format", dumpagihtml_help };
2075 int unload_module(void)
2077 STANDARD_HANGUP_LOCALUSERS;
2078 ast_cli_unregister(&showagi);
2079 ast_cli_unregister(&dumpagihtml);
2080 ast_cli_unregister(&cli_debug);
2081 ast_cli_unregister(&cli_no_debug);
2082 ast_unregister_application(eapp);
2083 ast_unregister_application(deadapp);
2084 return ast_unregister_application(app);
2087 int load_module(void)
2089 ast_cli_register(&showagi);
2090 ast_cli_register(&dumpagihtml);
2091 ast_cli_register(&cli_debug);
2092 ast_cli_register(&cli_no_debug);
2093 ast_register_application(deadapp, deadagi_exec, deadsynopsis, descrip);
2094 ast_register_application(eapp, eagi_exec, esynopsis, descrip);
2095 return ast_register_application(app, agi_exec, synopsis, descrip);
2098 char *description(void)
2106 STANDARD_USECOUNT(res);
2112 return ASTERISK_GPL_KEY;