2 * Asterisk -- An open source telephony toolkit.
4 * Copyright (C) 1999 - 2006, 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/utils.h"
63 #include "asterisk/lock.h"
64 #include "asterisk/strings.h"
65 #include "asterisk/agi.h"
68 #define MAX_COMMANDS 128
70 /* Recycle some stuff from the CLI interface */
71 #define fdprintf agi_debug_cli
73 static char *app = "AGI";
75 static char *eapp = "EAGI";
77 static char *deadapp = "DeadAGI";
79 static char *synopsis = "Executes an AGI compliant application";
80 static char *esynopsis = "Executes an EAGI compliant application";
81 static char *deadsynopsis = "Executes AGI on a hungup channel";
83 static char *descrip =
84 " [E|Dead]AGI(command|args): Executes an Asterisk Gateway Interface compliant\n"
85 "program on a channel. AGI allows Asterisk to launch external programs\n"
86 "written in any language to control a telephony channel, play audio,\n"
87 "read DTMF digits, etc. by communicating with the AGI protocol on stdin\n"
89 "Returns -1 on hangup (except for DeadAGI) or if application requested\n"
90 " hangup, or 0 on non-hangup exit. \n"
91 "Using 'EAGI' provides enhanced AGI, with incoming audio available out of band\n"
92 "on file descriptor 3\n\n"
93 "Use the CLI command 'show agi' to list available agi commands\n";
95 static int agidebug = 0;
97 struct module_symbols *me;
99 #define TONE_BLOCK_SIZE 200
101 /* Max time to connect to an AGI remote host */
102 #define MAX_AGI_CONNECT 2000
104 #define AGI_PORT 4573
106 static void agi_debug_cli(int fd, char *fmt, ...)
113 res = vasprintf(&stuff, fmt, ap);
116 ast_log(LOG_ERROR, "Out of memory\n");
119 ast_verbose("AGI Tx >> %s", stuff);
120 ast_carefulwrite(fd, stuff, strlen(stuff), 100);
125 /* launch_netscript: The fastagi handler.
126 FastAGI defaults to port 4573 */
127 static int launch_netscript(char *agiurl, char *argv[], int *fds, int *efd, int *opid)
131 struct pollfd pfds[1];
133 char *c; int port = AGI_PORT;
135 struct sockaddr_in sin;
137 struct ast_hostent ahp;
139 /* agiusl is "agi://host.domain[:port][/script/name]" */
140 host = ast_strdupa(agiurl + 6); /* Remove agi:// */
141 /* Strip off any script name */
142 if ((c = strchr(host, '/'))) {
147 if ((c = strchr(host, ':'))) {
153 ast_log(LOG_WARNING, "AGI URI's don't support Enhanced AGI yet\n");
156 hp = ast_gethostbyname(host, &ahp);
158 ast_log(LOG_WARNING, "Unable to locate host '%s'\n", host);
161 s = socket(AF_INET, SOCK_STREAM, 0);
163 ast_log(LOG_WARNING, "Unable to create socket: %s\n", strerror(errno));
166 flags = fcntl(s, F_GETFL);
168 ast_log(LOG_WARNING, "Fcntl(F_GETFL) failed: %s\n", strerror(errno));
172 if (fcntl(s, F_SETFL, flags | O_NONBLOCK) < 0) {
173 ast_log(LOG_WARNING, "Fnctl(F_SETFL) failed: %s\n", strerror(errno));
177 memset(&sin, 0, sizeof(sin));
178 sin.sin_family = AF_INET;
179 sin.sin_port = htons(port);
180 memcpy(&sin.sin_addr, hp->h_addr, sizeof(sin.sin_addr));
181 if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) && (errno != EINPROGRESS)) {
182 ast_log(LOG_WARNING, "Connect failed with unexpected error: %s\n", strerror(errno));
188 pfds[0].events = POLLOUT;
189 while (poll(pfds, 1, MAX_AGI_CONNECT) != 1) {
190 if (errno != EINTR) {
191 ast_log(LOG_WARNING, "Connect to '%s' failed: %s\n", agiurl, strerror(errno));
196 /* XXX in theory should check for partial writes... */
197 while (write(s, "agi_network: yes\n", strlen("agi_network: yes\n")) < 0) {
198 if (errno != EINTR) {
199 ast_log(LOG_WARNING, "Connect to '%s' failed: %s\n", agiurl, strerror(errno));
205 /* If we have a script parameter, relay it to the fastagi server */
206 if (!ast_strlen_zero(script))
207 fdprintf(s, "agi_network_script: %s\n", script);
209 if (option_debug > 3)
210 ast_log(LOG_DEBUG, "Wow, connected!\n");
217 static int launch_script(char *script, char *argv[], int *fds, int *efd, int *opid)
228 if (!strncasecmp(script, "agi://", 6))
229 return launch_netscript(script, argv, fds, efd, opid);
231 if (script[0] != '/') {
232 snprintf(tmp, sizeof(tmp), "%s/%s", (char *)ast_config_AST_AGI_DIR, script);
236 ast_log(LOG_WARNING, "Unable to create toast pipe: %s\n",strerror(errno));
240 ast_log(LOG_WARNING, "unable to create fromast pipe: %s\n", strerror(errno));
247 ast_log(LOG_WARNING, "unable to create audio pipe: %s\n", strerror(errno));
254 res = fcntl(audio[1], F_GETFL);
256 res = fcntl(audio[1], F_SETFL, res | O_NONBLOCK);
258 ast_log(LOG_WARNING, "unable to set audio pipe parameters: %s\n", strerror(errno));
270 ast_log(LOG_WARNING, "Failed to fork(): %s\n", strerror(errno));
274 /* Pass paths to AGI via environmental variables */
275 setenv("AST_CONFIG_DIR", ast_config_AST_CONFIG_DIR, 1);
276 setenv("AST_CONFIG_FILE", ast_config_AST_CONFIG_FILE, 1);
277 setenv("AST_MODULE_DIR", ast_config_AST_MODULE_DIR, 1);
278 setenv("AST_SPOOL_DIR", ast_config_AST_SPOOL_DIR, 1);
279 setenv("AST_MONITOR_DIR", ast_config_AST_MONITOR_DIR, 1);
280 setenv("AST_VAR_DIR", ast_config_AST_VAR_DIR, 1);
281 setenv("AST_DATA_DIR", ast_config_AST_DATA_DIR, 1);
282 setenv("AST_LOG_DIR", ast_config_AST_LOG_DIR, 1);
283 setenv("AST_AGI_DIR", ast_config_AST_AGI_DIR, 1);
284 setenv("AST_KEY_DIR", ast_config_AST_KEY_DIR, 1);
285 setenv("AST_RUN_DIR", ast_config_AST_RUN_DIR, 1);
287 /* Redirect stdin and out, provide enhanced audio channel if desired */
288 dup2(fromast[0], STDIN_FILENO);
289 dup2(toast[1], STDOUT_FILENO);
291 dup2(audio[0], STDERR_FILENO + 1);
293 close(STDERR_FILENO + 1);
296 /* unblock important signal handlers */
297 if (sigfillset(&signal_set) || pthread_sigmask(SIG_UNBLOCK, &signal_set, NULL)) {
298 ast_log(LOG_WARNING, "unable to unblock signals for AGI script: %s\n", strerror(errno));
302 /* Close everything but stdin/out/error */
303 for (x=STDERR_FILENO + 2;x<1024;x++)
306 /* Don't run AGI scripts with realtime priority -- it causes audio stutter */
311 /* Can't use ast_log since FD's are closed */
312 fprintf(stdout, "verbose \"Failed to execute '%s': %s\" 2\n", script, strerror(errno));
316 if (option_verbose > 2)
317 ast_verbose(VERBOSE_PREFIX_3 "Launched AGI Script %s\n", script);
323 /* close what we're not using in the parent */
337 static void setup_env(struct ast_channel *chan, char *request, int fd, int enhanced)
339 /* Print initial environment, with agi_request always being the first
341 fdprintf(fd, "agi_request: %s\n", request);
342 fdprintf(fd, "agi_channel: %s\n", chan->name);
343 fdprintf(fd, "agi_language: %s\n", chan->language);
344 fdprintf(fd, "agi_type: %s\n", chan->tech->type);
345 fdprintf(fd, "agi_uniqueid: %s\n", chan->uniqueid);
348 fdprintf(fd, "agi_callerid: %s\n", S_OR(chan->cid.cid_num, "unknown"));
349 fdprintf(fd, "agi_calleridname: %s\n", S_OR(chan->cid.cid_name, "unknown"));
350 fdprintf(fd, "agi_callingpres: %d\n", chan->cid.cid_pres);
351 fdprintf(fd, "agi_callingani2: %d\n", chan->cid.cid_ani2);
352 fdprintf(fd, "agi_callington: %d\n", chan->cid.cid_ton);
353 fdprintf(fd, "agi_callingtns: %d\n", chan->cid.cid_tns);
354 fdprintf(fd, "agi_dnid: %s\n", S_OR(chan->cid.cid_dnid, "unknown"));
355 fdprintf(fd, "agi_rdnis: %s\n", S_OR(chan->cid.cid_rdnis, "unknown"));
357 /* Context information */
358 fdprintf(fd, "agi_context: %s\n", chan->context);
359 fdprintf(fd, "agi_extension: %s\n", chan->exten);
360 fdprintf(fd, "agi_priority: %d\n", chan->priority);
361 fdprintf(fd, "agi_enhanced: %s\n", enhanced ? "1.0" : "0.0");
363 /* User information */
364 fdprintf(fd, "agi_accountcode: %s\n", chan->accountcode ? chan->accountcode : "");
366 /* End with empty return */
370 static int handle_answer(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
374 if (chan->_state != AST_STATE_UP) {
375 /* Answer the chan */
376 res = ast_answer(chan);
378 fdprintf(agi->fd, "200 result=%d\n", res);
379 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
382 static int handle_waitfordigit(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
387 return RESULT_SHOWUSAGE;
388 if (sscanf(argv[3], "%d", &to) != 1)
389 return RESULT_SHOWUSAGE;
390 res = ast_waitfordigit_full(chan, to, agi->audio, agi->ctrl);
391 fdprintf(agi->fd, "200 result=%d\n", res);
392 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
395 static int handle_sendtext(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
399 return RESULT_SHOWUSAGE;
400 /* At the moment, the parser (perhaps broken) returns with
401 the last argument PLUS the newline at the end of the input
402 buffer. This probably needs to be fixed, but I wont do that
403 because other stuff may break as a result. The right way
404 would probably be to strip off the trailing newline before
405 parsing, then here, add a newline at the end of the string
406 before sending it to ast_sendtext --DUDE */
407 res = ast_sendtext(chan, argv[2]);
408 fdprintf(agi->fd, "200 result=%d\n", res);
409 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
412 static int handle_recvchar(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
416 return RESULT_SHOWUSAGE;
417 res = ast_recvchar(chan,atoi(argv[2]));
419 fdprintf(agi->fd, "200 result=%d (timeout)\n", res);
420 return RESULT_SUCCESS;
423 fdprintf(agi->fd, "200 result=%d\n", res);
424 return RESULT_SUCCESS;
427 fdprintf(agi->fd, "200 result=%d (hangup)\n", res);
428 return RESULT_FAILURE;
432 static int handle_recvtext(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
437 return RESULT_SHOWUSAGE;
438 buf = ast_recvtext(chan,atoi(argv[2]));
440 fdprintf(agi->fd, "200 result=1 (%s)\n", buf);
443 fdprintf(agi->fd, "200 result=-1\n");
445 return RESULT_SUCCESS;
448 static int handle_tddmode(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
452 return RESULT_SHOWUSAGE;
453 if (!strncasecmp(argv[2],"on",2))
457 if (!strncasecmp(argv[2],"mate",4))
459 if (!strncasecmp(argv[2],"tdd",3))
461 res = ast_channel_setoption(chan, AST_OPTION_TDD, &x, sizeof(char), 0);
462 if (res != RESULT_SUCCESS)
463 fdprintf(agi->fd, "200 result=0\n");
465 fdprintf(agi->fd, "200 result=1\n");
466 return RESULT_SUCCESS;
469 static int handle_sendimage(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
473 return RESULT_SHOWUSAGE;
474 res = ast_send_image(chan, argv[2]);
475 if (!ast_check_hangup(chan))
477 fdprintf(agi->fd, "200 result=%d\n", res);
478 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
481 static int handle_controlstreamfile(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
490 if (argc < 5 || argc > 9)
491 return RESULT_SHOWUSAGE;
493 if (!ast_strlen_zero(argv[4]))
498 if ((argc > 5) && (sscanf(argv[5], "%d", &skipms) != 1))
499 return RESULT_SHOWUSAGE;
501 if (argc > 6 && !ast_strlen_zero(argv[8]))
506 if (argc > 7 && !ast_strlen_zero(argv[8]))
511 if (argc > 8 && !ast_strlen_zero(argv[8]))
516 res = ast_control_streamfile(chan, argv[3], fwd, rev, stop, pause, NULL, skipms);
518 fdprintf(agi->fd, "200 result=%d\n", res);
520 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
523 static int handle_streamfile(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
526 struct ast_filestream *fs;
527 long sample_offset = 0;
530 if (argc < 4 || argc > 5)
531 return RESULT_SHOWUSAGE;
532 if ((argc > 4) && (sscanf(argv[4], "%ld", &sample_offset) != 1))
533 return RESULT_SHOWUSAGE;
535 fs = ast_openstream(chan, argv[2], chan->language);
537 fdprintf(agi->fd, "200 result=%d endpos=%ld\n", 0, sample_offset);
538 return RESULT_SUCCESS;
540 ast_seekstream(fs, 0, SEEK_END);
541 max_length = ast_tellstream(fs);
542 ast_seekstream(fs, sample_offset, SEEK_SET);
543 res = ast_applystream(chan, fs);
544 res = ast_playstream(fs);
546 fdprintf(agi->fd, "200 result=%d endpos=%ld\n", res, sample_offset);
547 return (res >= 0) ? RESULT_SHOWUSAGE : RESULT_FAILURE;
549 res = ast_waitstream_full(chan, argv[3], agi->audio, agi->ctrl);
550 /* this is to check for if ast_waitstream closed the stream, we probably are at
551 * the end of the stream, return that amount, else check for the amount */
552 sample_offset = (chan->stream) ? ast_tellstream(fs) : max_length;
553 ast_stopstream(chan);
555 /* Stop this command, don't print a result line, as there is a new command */
556 return RESULT_SUCCESS;
558 fdprintf(agi->fd, "200 result=%d endpos=%ld\n", res, sample_offset);
559 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
562 /* get option - really similar to the handle_streamfile, but with a timeout */
563 static int handle_getoption(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
566 struct ast_filestream *fs;
567 long sample_offset = 0;
570 char *edigits = NULL;
572 if ( argc < 4 || argc > 5 )
573 return RESULT_SHOWUSAGE;
579 timeout = atoi(argv[4]);
580 else if (chan->pbx->dtimeout) {
581 /* by default dtimeout is set to 5sec */
582 timeout = chan->pbx->dtimeout * 1000; /* in msec */
585 fs = ast_openstream(chan, argv[2], chan->language);
587 fdprintf(agi->fd, "200 result=%d endpos=%ld\n", 0, sample_offset);
588 ast_log(LOG_WARNING, "Unable to open %s\n", argv[2]);
589 return RESULT_SUCCESS;
591 if (option_verbose > 2)
592 ast_verbose(VERBOSE_PREFIX_3 "Playing '%s' (escape_digits=%s) (timeout %d)\n", argv[2], edigits, timeout);
594 ast_seekstream(fs, 0, SEEK_END);
595 max_length = ast_tellstream(fs);
596 ast_seekstream(fs, sample_offset, SEEK_SET);
597 res = ast_applystream(chan, fs);
598 res = ast_playstream(fs);
600 fdprintf(agi->fd, "200 result=%d endpos=%ld\n", res, sample_offset);
602 return RESULT_SHOWUSAGE;
604 return RESULT_FAILURE;
606 res = ast_waitstream_full(chan, argv[3], agi->audio, agi->ctrl);
607 /* this is to check for if ast_waitstream closed the stream, we probably are at
608 * the end of the stream, return that amount, else check for the amount */
609 sample_offset = (chan->stream)?ast_tellstream(fs):max_length;
610 ast_stopstream(chan);
612 /* Stop this command, don't print a result line, as there is a new command */
613 return RESULT_SUCCESS;
616 /* If the user didnt press a key, wait for digitTimeout*/
618 res = ast_waitfordigit_full(chan, timeout, agi->audio, agi->ctrl);
619 /* Make sure the new result is in the escape digits of the GET OPTION */
620 if ( !strchr(edigits,res) )
624 fdprintf(agi->fd, "200 result=%d endpos=%ld\n", res, sample_offset);
625 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
631 /*--- handle_saynumber: Say number in various language syntaxes ---*/
632 /* Need to add option for gender here as well. Coders wanted */
633 /* While waiting, we're sending a (char *) NULL. */
634 static int handle_saynumber(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
639 return RESULT_SHOWUSAGE;
640 if (sscanf(argv[2], "%d", &num) != 1)
641 return RESULT_SHOWUSAGE;
642 res = ast_say_number_full(chan, num, argv[3], chan->language, (char *) NULL, agi->audio, agi->ctrl);
644 return RESULT_SUCCESS;
645 fdprintf(agi->fd, "200 result=%d\n", res);
646 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
649 static int handle_saydigits(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
655 return RESULT_SHOWUSAGE;
656 if (sscanf(argv[2], "%d", &num) != 1)
657 return RESULT_SHOWUSAGE;
659 res = ast_say_digit_str_full(chan, argv[2], argv[3], chan->language, agi->audio, agi->ctrl);
660 if (res == 1) /* New command */
661 return RESULT_SUCCESS;
662 fdprintf(agi->fd, "200 result=%d\n", res);
663 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
666 static int handle_sayalpha(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
671 return RESULT_SHOWUSAGE;
673 res = ast_say_character_str_full(chan, argv[2], argv[3], chan->language, agi->audio, agi->ctrl);
674 if (res == 1) /* New command */
675 return RESULT_SUCCESS;
676 fdprintf(agi->fd, "200 result=%d\n", res);
677 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
680 static int handle_saydate(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
685 return RESULT_SHOWUSAGE;
686 if (sscanf(argv[2], "%d", &num) != 1)
687 return RESULT_SHOWUSAGE;
688 res = ast_say_date(chan, num, argv[3], chan->language);
690 return RESULT_SUCCESS;
691 fdprintf(agi->fd, "200 result=%d\n", res);
692 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
695 static int handle_saytime(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
700 return RESULT_SHOWUSAGE;
701 if (sscanf(argv[2], "%d", &num) != 1)
702 return RESULT_SHOWUSAGE;
703 res = ast_say_time(chan, num, argv[3], chan->language);
705 return RESULT_SUCCESS;
706 fdprintf(agi->fd, "200 result=%d\n", res);
707 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
710 static int handle_saydatetime(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
714 char *format, *zone=NULL;
717 return RESULT_SHOWUSAGE;
722 /* XXX this doesn't belong here, but in the 'say' module */
723 if (!strcasecmp(chan->language, "de")) {
724 format = "A dBY HMS";
726 format = "ABdY 'digits/at' IMp";
730 if (argc > 5 && !ast_strlen_zero(argv[5]))
733 if (ast_get_time_t(argv[2], &unixtime, 0, NULL))
734 return RESULT_SHOWUSAGE;
736 res = ast_say_date_with_format(chan, unixtime, argv[3], chan->language, format, zone);
738 return RESULT_SUCCESS;
740 fdprintf(agi->fd, "200 result=%d\n", res);
741 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
744 static int handle_sayphonetic(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
749 return RESULT_SHOWUSAGE;
751 res = ast_say_phonetic_str_full(chan, argv[2], argv[3], chan->language, agi->audio, agi->ctrl);
752 if (res == 1) /* New command */
753 return RESULT_SUCCESS;
754 fdprintf(agi->fd, "200 result=%d\n", res);
755 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
758 static int handle_getdata(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
766 return RESULT_SHOWUSAGE;
768 timeout = atoi(argv[3]);
775 res = ast_app_getdata_full(chan, argv[2], data, max, timeout, agi->audio, agi->ctrl);
776 if (res == 2) /* New command */
777 return RESULT_SUCCESS;
779 fdprintf(agi->fd, "200 result=%s (timeout)\n", data);
781 fdprintf(agi->fd, "200 result=-1\n");
783 fdprintf(agi->fd, "200 result=%s\n", data);
784 return RESULT_SUCCESS;
787 static int handle_setcontext(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
791 return RESULT_SHOWUSAGE;
792 ast_copy_string(chan->context, argv[2], sizeof(chan->context));
793 fdprintf(agi->fd, "200 result=0\n");
794 return RESULT_SUCCESS;
797 static int handle_setextension(struct ast_channel *chan, AGI *agi, int argc, char **argv)
800 return RESULT_SHOWUSAGE;
801 ast_copy_string(chan->exten, argv[2], sizeof(chan->exten));
802 fdprintf(agi->fd, "200 result=0\n");
803 return RESULT_SUCCESS;
806 static int handle_setpriority(struct ast_channel *chan, AGI *agi, int argc, char **argv)
810 return RESULT_SHOWUSAGE;
812 if (sscanf(argv[2], "%d", &pri) != 1) {
813 if ((pri = ast_findlabel_extension(chan, chan->context, chan->exten, argv[2], chan->cid.cid_num)) < 1)
814 return RESULT_SHOWUSAGE;
817 ast_explicit_goto(chan, NULL, NULL, pri);
818 fdprintf(agi->fd, "200 result=0\n");
819 return RESULT_SUCCESS;
822 static int handle_recordfile(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
824 struct ast_filestream *fs;
826 struct timeval start;
827 long sample_offset = 0;
831 struct ast_dsp *sildet=NULL; /* silence detector dsp */
832 int totalsilence = 0;
834 int silence = 0; /* amount of silence to allow */
835 int gotsilence = 0; /* did we timeout for silence? */
836 char *silencestr=NULL;
840 /* XXX EAGI FIXME XXX */
843 return RESULT_SHOWUSAGE;
844 if (sscanf(argv[5], "%d", &ms) != 1)
845 return RESULT_SHOWUSAGE;
848 silencestr = strchr(argv[6],'s');
849 if ((argc > 7) && (!silencestr))
850 silencestr = strchr(argv[7],'s');
851 if ((argc > 8) && (!silencestr))
852 silencestr = strchr(argv[8],'s');
855 if (strlen(silencestr) > 2) {
856 if ((silencestr[0] == 's') && (silencestr[1] == '=')) {
860 silence = atoi(silencestr);
868 rfmt = chan->readformat;
869 res = ast_set_read_format(chan, AST_FORMAT_SLINEAR);
871 ast_log(LOG_WARNING, "Unable to set to linear mode, giving up\n");
874 sildet = ast_dsp_new();
876 ast_log(LOG_WARNING, "Unable to create silence detector :(\n");
879 ast_dsp_set_threshold(sildet, 256);
882 /* backward compatibility, if no offset given, arg[6] would have been
883 * caught below and taken to be a beep, else if it is a digit then it is a
885 if ((argc >6) && (sscanf(argv[6], "%ld", &sample_offset) != 1) && (!strchr(argv[6], '=')))
886 res = ast_streamfile(chan, "beep", chan->language);
888 if ((argc > 7) && (!strchr(argv[7], '=')))
889 res = ast_streamfile(chan, "beep", chan->language);
892 res = ast_waitstream(chan, argv[4]);
894 fdprintf(agi->fd, "200 result=%d (randomerror) endpos=%ld\n", res, sample_offset);
896 fs = ast_writefile(argv[2], argv[3], NULL, O_CREAT | O_WRONLY | (sample_offset ? O_APPEND : 0), 0, 0644);
899 fdprintf(agi->fd, "200 result=%d (writefile)\n", res);
901 ast_dsp_free(sildet);
902 return RESULT_FAILURE;
905 /* Request a video update */
906 ast_indicate(chan, AST_CONTROL_VIDUPDATE);
909 ast_applystream(chan,fs);
910 /* really should have checks */
911 ast_seekstream(fs, sample_offset, SEEK_SET);
915 while ((ms < 0) || ast_tvdiff_ms(ast_tvnow(), start) < ms) {
916 res = ast_waitfor(chan, -1);
919 fdprintf(agi->fd, "200 result=%d (waitfor) endpos=%ld\n", res,sample_offset);
921 ast_dsp_free(sildet);
922 return RESULT_FAILURE;
926 fdprintf(agi->fd, "200 result=%d (hangup) endpos=%ld\n", 0, sample_offset);
929 ast_dsp_free(sildet);
930 return RESULT_FAILURE;
932 switch(f->frametype) {
934 if (strchr(argv[4], f->subclass)) {
935 /* This is an interrupting chracter, so rewind to chop off any small
936 amount of DTMF that may have been recorded
938 ast_stream_rewind(fs, 200);
940 sample_offset = ast_tellstream(fs);
941 fdprintf(agi->fd, "200 result=%d (dtmf) endpos=%ld\n", f->subclass, sample_offset);
945 ast_dsp_free(sildet);
946 return RESULT_SUCCESS;
949 case AST_FRAME_VOICE:
950 ast_writestream(fs, f);
951 /* this is a safe place to check progress since we know that fs
952 * is valid after a write, and it will then have our current
954 sample_offset = ast_tellstream(fs);
957 ast_dsp_silence(sildet, f, &dspsilence);
959 totalsilence = dspsilence;
963 if (totalsilence > silence) {
964 /* Ended happily with silence */
971 case AST_FRAME_VIDEO:
972 ast_writestream(fs, f);
981 ast_stream_rewind(fs, silence-1000);
983 sample_offset = ast_tellstream(fs);
985 fdprintf(agi->fd, "200 result=%d (timeout) endpos=%ld\n", res, sample_offset);
990 res = ast_set_read_format(chan, rfmt);
992 ast_log(LOG_WARNING, "Unable to restore read format on '%s'\n", chan->name);
993 ast_dsp_free(sildet);
995 return RESULT_SUCCESS;
998 static int handle_autohangup(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
1003 return RESULT_SHOWUSAGE;
1004 if (sscanf(argv[2], "%d", &timeout) != 1)
1005 return RESULT_SHOWUSAGE;
1009 chan->whentohangup = time(NULL) + timeout;
1011 chan->whentohangup = 0;
1012 fdprintf(agi->fd, "200 result=0\n");
1013 return RESULT_SUCCESS;
1016 static int handle_hangup(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1018 struct ast_channel *c;
1020 /* no argument: hangup the current channel */
1021 ast_softhangup(chan,AST_SOFTHANGUP_EXPLICIT);
1022 fdprintf(agi->fd, "200 result=1\n");
1023 return RESULT_SUCCESS;
1024 } else if (argc == 2) {
1025 /* one argument: look for info on the specified channel */
1026 c = ast_get_channel_by_name_locked(argv[1]);
1028 /* we have a matching channel */
1029 ast_softhangup(c,AST_SOFTHANGUP_EXPLICIT);
1030 fdprintf(agi->fd, "200 result=1\n");
1031 ast_channel_unlock(c);
1032 return RESULT_SUCCESS;
1034 /* if we get this far no channel name matched the argument given */
1035 fdprintf(agi->fd, "200 result=-1\n");
1036 return RESULT_SUCCESS;
1038 return RESULT_SHOWUSAGE;
1042 static int handle_exec(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1045 struct ast_app *app;
1048 return RESULT_SHOWUSAGE;
1050 if (option_verbose > 2)
1051 ast_verbose(VERBOSE_PREFIX_3 "AGI Script Executing Application: (%s) Options: (%s)\n", argv[1], argv[2]);
1053 app = pbx_findapp(argv[1]);
1056 res = pbx_exec(chan, app, argv[2]);
1058 ast_log(LOG_WARNING, "Could not find application (%s)\n", argv[1]);
1061 fdprintf(agi->fd, "200 result=%d\n", res);
1066 static int handle_setcallerid(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1069 char *l = NULL, *n = NULL;
1072 ast_copy_string(tmp, argv[2], sizeof(tmp));
1073 ast_callerid_parse(tmp, &n, &l);
1075 ast_shrink_phone_number(l);
1080 ast_set_callerid(chan, l, n, NULL);
1083 fdprintf(agi->fd, "200 result=1\n");
1084 return RESULT_SUCCESS;
1087 static int handle_channelstatus(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1089 struct ast_channel *c;
1091 /* no argument: supply info on the current channel */
1092 fdprintf(agi->fd, "200 result=%d\n", chan->_state);
1093 return RESULT_SUCCESS;
1094 } else if (argc == 3) {
1095 /* one argument: look for info on the specified channel */
1096 c = ast_get_channel_by_name_locked(argv[2]);
1098 fdprintf(agi->fd, "200 result=%d\n", c->_state);
1099 ast_channel_unlock(c);
1100 return RESULT_SUCCESS;
1102 /* if we get this far no channel name matched the argument given */
1103 fdprintf(agi->fd, "200 result=-1\n");
1104 return RESULT_SUCCESS;
1106 return RESULT_SHOWUSAGE;
1110 static int handle_setvariable(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1113 pbx_builtin_setvar_helper(chan, argv[2], argv[3]);
1115 fdprintf(agi->fd, "200 result=1\n");
1116 return RESULT_SUCCESS;
1119 static int handle_getvariable(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1125 return RESULT_SHOWUSAGE;
1127 /* check if we want to execute an ast_custom_function */
1128 if (!ast_strlen_zero(argv[2]) && (argv[2][strlen(argv[2]) - 1] == ')')) {
1129 ret = ast_func_read(chan, argv[2], tempstr, sizeof(tempstr)) ? NULL : tempstr;
1131 pbx_retrieve_variable(chan, argv[2], &ret, tempstr, sizeof(tempstr), NULL);
1135 fdprintf(agi->fd, "200 result=1 (%s)\n", ret);
1137 fdprintf(agi->fd, "200 result=0\n");
1139 return RESULT_SUCCESS;
1142 static int handle_getvariablefull(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1144 char tmp[4096] = "";
1145 struct ast_channel *chan2=NULL;
1147 if ((argc != 4) && (argc != 5))
1148 return RESULT_SHOWUSAGE;
1150 chan2 = ast_get_channel_by_name_locked(argv[4]);
1154 if (chan) { /* XXX isn't this chan2 ? */
1155 pbx_substitute_variables_helper(chan2, argv[3], tmp, sizeof(tmp) - 1);
1156 fdprintf(agi->fd, "200 result=1 (%s)\n", tmp);
1158 fdprintf(agi->fd, "200 result=0\n");
1160 if (chan2 && (chan2 != chan))
1161 ast_channel_unlock(chan2);
1162 return RESULT_SUCCESS;
1165 static int handle_verbose(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1171 return RESULT_SHOWUSAGE;
1174 sscanf(argv[2], "%d", &level);
1178 prefix = VERBOSE_PREFIX_4;
1181 prefix = VERBOSE_PREFIX_3;
1184 prefix = VERBOSE_PREFIX_2;
1188 prefix = VERBOSE_PREFIX_1;
1192 if (level <= option_verbose)
1193 ast_verbose("%s %s: %s\n", prefix, chan->data, argv[1]);
1195 fdprintf(agi->fd, "200 result=1\n");
1197 return RESULT_SUCCESS;
1200 static int handle_dbget(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1206 return RESULT_SHOWUSAGE;
1207 res = ast_db_get(argv[2], argv[3], tmp, sizeof(tmp));
1209 fdprintf(agi->fd, "200 result=0\n");
1211 fdprintf(agi->fd, "200 result=1 (%s)\n", tmp);
1213 return RESULT_SUCCESS;
1216 static int handle_dbput(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1221 return RESULT_SHOWUSAGE;
1222 res = ast_db_put(argv[2], argv[3], argv[4]);
1223 fdprintf(agi->fd, "200 result=%c\n", res ? '0' : '1');
1224 return RESULT_SUCCESS;
1227 static int handle_dbdel(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1232 return RESULT_SHOWUSAGE;
1233 res = ast_db_del(argv[2], argv[3]);
1234 fdprintf(agi->fd, "200 result=%c\n", res ? '0' : '1');
1235 return RESULT_SUCCESS;
1238 static int handle_dbdeltree(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1241 if ((argc < 3) || (argc > 4))
1242 return RESULT_SHOWUSAGE;
1244 res = ast_db_deltree(argv[2], argv[3]);
1246 res = ast_db_deltree(argv[2], NULL);
1248 fdprintf(agi->fd, "200 result=%c\n", res ? '0' : '1');
1249 return RESULT_SUCCESS;
1252 static char debug_usage[] =
1253 "Usage: agi debug\n"
1254 " Enables dumping of AGI transactions for debugging purposes\n";
1256 static char no_debug_usage[] =
1257 "Usage: agi no debug\n"
1258 " Disables dumping of AGI transactions for debugging purposes\n";
1260 static int agi_do_debug(int fd, int argc, char *argv[])
1263 return RESULT_SHOWUSAGE;
1265 ast_cli(fd, "AGI Debugging Enabled\n");
1266 return RESULT_SUCCESS;
1269 static int agi_no_debug(int fd, int argc, char *argv[])
1272 return RESULT_SHOWUSAGE;
1274 ast_cli(fd, "AGI Debugging Disabled\n");
1275 return RESULT_SUCCESS;
1278 static struct ast_cli_entry cli_debug =
1279 { { "agi", "debug", NULL }, agi_do_debug, "Enable AGI debugging", debug_usage };
1281 static struct ast_cli_entry cli_no_debug =
1282 { { "agi", "no", "debug", NULL }, agi_no_debug, "Disable AGI debugging", no_debug_usage };
1284 static int handle_noop(struct ast_channel *chan, AGI *agi, int arg, char *argv[])
1286 fdprintf(agi->fd, "200 result=0\n");
1287 return RESULT_SUCCESS;
1290 static int handle_setmusic(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
1292 if (!strncasecmp(argv[2], "on", 2))
1293 ast_moh_start(chan, argc > 3 ? argv[3] : NULL);
1294 else if (!strncasecmp(argv[2], "off", 3))
1296 fdprintf(agi->fd, "200 result=0\n");
1297 return RESULT_SUCCESS;
1300 static char usage_setmusic[] =
1301 " Usage: SET MUSIC ON <on|off> <class>\n"
1302 " Enables/Disables the music on hold generator. If <class> is\n"
1303 " not specified, then the default music on hold class will be used.\n"
1304 " Always returns 0.\n";
1306 static char usage_dbput[] =
1307 " Usage: DATABASE PUT <family> <key> <value>\n"
1308 " Adds or updates an entry in the Asterisk database for a\n"
1309 " given family, key, and value.\n"
1310 " Returns 1 if successful, 0 otherwise.\n";
1312 static char usage_dbget[] =
1313 " Usage: DATABASE GET <family> <key>\n"
1314 " Retrieves an entry in the Asterisk database for a\n"
1315 " given family and key.\n"
1316 " Returns 0 if <key> is not set. Returns 1 if <key>\n"
1317 " is set and returns the variable in parentheses.\n"
1318 " Example return code: 200 result=1 (testvariable)\n";
1320 static char usage_dbdel[] =
1321 " Usage: DATABASE DEL <family> <key>\n"
1322 " Deletes an entry in the Asterisk database for a\n"
1323 " given family and key.\n"
1324 " Returns 1 if successful, 0 otherwise.\n";
1326 static char usage_dbdeltree[] =
1327 " Usage: DATABASE DELTREE <family> [keytree]\n"
1328 " Deletes a family or specific keytree within a family\n"
1329 " in the Asterisk database.\n"
1330 " Returns 1 if successful, 0 otherwise.\n";
1332 static char usage_verbose[] =
1333 " Usage: VERBOSE <message> <level>\n"
1334 " Sends <message> to the console via verbose message system.\n"
1335 " <level> is the the verbose level (1-4)\n"
1336 " Always returns 1.\n";
1338 static char usage_getvariable[] =
1339 " Usage: GET VARIABLE <variablename>\n"
1340 " Returns 0 if <variablename> is not set. Returns 1 if <variablename>\n"
1341 " is set and returns the variable in parentheses.\n"
1342 " example return code: 200 result=1 (testvariable)\n";
1344 static char usage_getvariablefull[] =
1345 " Usage: GET FULL VARIABLE <variablename> [<channel name>]\n"
1346 " Returns 0 if <variablename> is not set or channel does not exist. Returns 1\n"
1347 "if <variablename> is set and returns the variable in parenthesis. Understands\n"
1348 "complex variable names and builtin variables, unlike GET VARIABLE.\n"
1349 " example return code: 200 result=1 (testvariable)\n";
1351 static char usage_setvariable[] =
1352 " Usage: SET VARIABLE <variablename> <value>\n";
1354 static char usage_channelstatus[] =
1355 " Usage: CHANNEL STATUS [<channelname>]\n"
1356 " Returns the status of the specified channel.\n"
1357 " If no channel name is given the returns the status of the\n"
1358 " current channel. Return values:\n"
1359 " 0 Channel is down and available\n"
1360 " 1 Channel is down, but reserved\n"
1361 " 2 Channel is off hook\n"
1362 " 3 Digits (or equivalent) have been dialed\n"
1363 " 4 Line is ringing\n"
1364 " 5 Remote end is ringing\n"
1366 " 7 Line is busy\n";
1368 static char usage_setcallerid[] =
1369 " Usage: SET CALLERID <number>\n"
1370 " Changes the callerid of the current channel.\n";
1372 static char usage_exec[] =
1373 " Usage: EXEC <application> <options>\n"
1374 " Executes <application> with given <options>.\n"
1375 " Returns whatever the application returns, or -2 on failure to find application\n";
1377 static char usage_hangup[] =
1378 " Usage: HANGUP [<channelname>]\n"
1379 " Hangs up the specified channel.\n"
1380 " If no channel name is given, hangs up the current channel\n";
1382 static char usage_answer[] =
1384 " Answers channel if not already in answer state. Returns -1 on\n"
1385 " channel failure, or 0 if successful.\n";
1387 static char usage_waitfordigit[] =
1388 " Usage: WAIT FOR DIGIT <timeout>\n"
1389 " Waits up to 'timeout' milliseconds for channel to receive a DTMF digit.\n"
1390 " Returns -1 on channel failure, 0 if no digit is received in the timeout, or\n"
1391 " the numerical value of the ascii of the digit if one is received. Use -1\n"
1392 " for the timeout value if you desire the call to block indefinitely.\n";
1394 static char usage_sendtext[] =
1395 " Usage: SEND TEXT \"<text to send>\"\n"
1396 " Sends the given text on a channel. Most channels do not support the\n"
1397 " transmission of text. Returns 0 if text is sent, or if the channel does not\n"
1398 " support text transmission. Returns -1 only on error/hangup. Text\n"
1399 " consisting of greater than one word should be placed in quotes since the\n"
1400 " command only accepts a single argument.\n";
1402 static char usage_recvchar[] =
1403 " Usage: RECEIVE CHAR <timeout>\n"
1404 " Receives a character of text on a channel. Specify timeout to be the\n"
1405 " maximum time to wait for input in milliseconds, or 0 for infinite. Most channels\n"
1406 " do not support the reception of text. Returns the decimal value of the character\n"
1407 " if one is received, or 0 if the channel does not support text reception. Returns\n"
1408 " -1 only on error/hangup.\n";
1410 static char usage_recvtext[] =
1411 " Usage: RECEIVE TEXT <timeout>\n"
1412 " Receives a string of text on a channel. Specify timeout to be the\n"
1413 " maximum time to wait for input in milliseconds, or 0 for infinite. Most channels\n"
1414 " do not support the reception of text. Returns -1 for failure or 1 for success, and the string in parentheses.\n";
1416 static char usage_tddmode[] =
1417 " Usage: TDD MODE <on|off>\n"
1418 " Enable/Disable TDD transmission/reception on a channel. Returns 1 if\n"
1419 " successful, or 0 if channel is not TDD-capable.\n";
1421 static char usage_sendimage[] =
1422 " Usage: SEND IMAGE <image>\n"
1423 " Sends the given image on a channel. Most channels do not support the\n"
1424 " transmission of images. Returns 0 if image is sent, or if the channel does not\n"
1425 " support image transmission. Returns -1 only on error/hangup. Image names\n"
1426 " should not include extensions.\n";
1428 static char usage_streamfile[] =
1429 " Usage: STREAM FILE <filename> <escape digits> [sample offset]\n"
1430 " Send the given file, allowing playback to be interrupted by the given\n"
1431 " digits, if any. Use double quotes for the digits if you wish none to be\n"
1432 " permitted. If sample offset is provided then the audio will seek to sample\n"
1433 " offset before play starts. Returns 0 if playback completes without a digit\n"
1434 " being pressed, or the ASCII numerical value of the digit if one was pressed,\n"
1435 " or -1 on error or if the channel was disconnected. Remember, the file\n"
1436 " extension must not be included in the filename.\n";
1438 static char usage_controlstreamfile[] =
1439 " Usage: CONTROL STREAM FILE <filename> <escape digits> [skipms] [ffchar] [rewchr] [pausechr]\n"
1440 " Send the given file, allowing playback to be controled by the given\n"
1441 " digits, if any. Use double quotes for the digits if you wish none to be\n"
1442 " permitted. Returns 0 if playback completes without a digit\n"
1443 " being pressed, or the ASCII numerical value of the digit if one was pressed,\n"
1444 " or -1 on error or if the channel was disconnected. Remember, the file\n"
1445 " extension must not be included in the filename.\n\n"
1446 " Note: ffchar and rewchar default to * and # respectively.\n";
1448 static char usage_getoption[] =
1449 " Usage: GET OPTION <filename> <escape_digits> [timeout]\n"
1450 " Behaves similar to STREAM FILE but used with a timeout option.\n";
1452 static char usage_saynumber[] =
1453 " Usage: SAY NUMBER <number> <escape digits>\n"
1454 " Say a given number, returning early if any of the given DTMF digits\n"
1455 " are received on the channel. Returns 0 if playback completes without a digit\n"
1456 " being pressed, or the ASCII numerical value of the digit if one was pressed or\n"
1457 " -1 on error/hangup.\n";
1459 static char usage_saydigits[] =
1460 " Usage: SAY DIGITS <number> <escape digits>\n"
1461 " Say a given digit string, returning early if any of the given DTMF digits\n"
1462 " are received on the channel. Returns 0 if playback completes without a digit\n"
1463 " being pressed, or the ASCII numerical value of the digit if one was pressed or\n"
1464 " -1 on error/hangup.\n";
1466 static char usage_sayalpha[] =
1467 " Usage: SAY ALPHA <number> <escape digits>\n"
1468 " Say a given character string, returning early if any of the given DTMF digits\n"
1469 " are received on the channel. Returns 0 if playback completes without a digit\n"
1470 " being pressed, or the ASCII numerical value of the digit if one was pressed or\n"
1471 " -1 on error/hangup.\n";
1473 static char usage_saydate[] =
1474 " Usage: SAY DATE <date> <escape digits>\n"
1475 " Say a given date, returning early if any of the given DTMF digits are\n"
1476 " received on the channel. <date> is number of seconds elapsed since 00:00:00\n"
1477 " on January 1, 1970, Coordinated Universal Time (UTC). Returns 0 if playback\n"
1478 " completes without a digit being pressed, or the ASCII numerical value of the\n"
1479 " digit if one was pressed or -1 on error/hangup.\n";
1481 static char usage_saytime[] =
1482 " Usage: SAY TIME <time> <escape digits>\n"
1483 " Say a given time, returning early if any of the given DTMF digits are\n"
1484 " received on the channel. <time> is number of seconds elapsed since 00:00:00\n"
1485 " on January 1, 1970, Coordinated Universal Time (UTC). Returns 0 if playback\n"
1486 " completes without a digit being pressed, or the ASCII numerical value of the\n"
1487 " digit if one was pressed or -1 on error/hangup.\n";
1489 static char usage_saydatetime[] =
1490 " Usage: SAY DATETIME <time> <escape digits> [format] [timezone]\n"
1491 " Say a given time, returning early if any of the given DTMF digits are\n"
1492 " received on the channel. <time> is number of seconds elapsed since 00:00:00\n"
1493 " on January 1, 1970, Coordinated Universal Time (UTC). [format] is the format\n"
1494 " the time should be said in. See voicemail.conf (defaults to \"ABdY\n"
1495 " 'digits/at' IMp\"). Acceptable values for [timezone] can be found in\n"
1496 " /usr/share/zoneinfo. Defaults to machine default. Returns 0 if playback\n"
1497 " completes without a digit being pressed, or the ASCII numerical value of the\n"
1498 " digit if one was pressed or -1 on error/hangup.\n";
1500 static char usage_sayphonetic[] =
1501 " Usage: SAY PHONETIC <string> <escape digits>\n"
1502 " Say a given character string with phonetics, returning early if any of the\n"
1503 " given DTMF digits are received on the channel. Returns 0 if playback\n"
1504 " completes without a digit pressed, the ASCII numerical value of the digit\n"
1505 " if one was pressed, or -1 on error/hangup.\n";
1507 static char usage_getdata[] =
1508 " Usage: GET DATA <file to be streamed> [timeout] [max digits]\n"
1509 " Stream the given file, and recieve DTMF data. Returns the digits received\n"
1510 "from the channel at the other end.\n";
1512 static char usage_setcontext[] =
1513 " Usage: SET CONTEXT <desired context>\n"
1514 " Sets the context for continuation upon exiting the application.\n";
1516 static char usage_setextension[] =
1517 " Usage: SET EXTENSION <new extension>\n"
1518 " Changes the extension for continuation upon exiting the application.\n";
1520 static char usage_setpriority[] =
1521 " Usage: SET PRIORITY <priority>\n"
1522 " Changes the priority for continuation upon exiting the application.\n"
1523 " The priority must be a valid priority or label.\n";
1525 static char usage_recordfile[] =
1526 " Usage: RECORD FILE <filename> <format> <escape digits> <timeout> \\\n"
1527 " [offset samples] [BEEP] [s=silence]\n"
1528 " Record to a file until a given dtmf digit in the sequence is received\n"
1529 " Returns -1 on hangup or error. The format will specify what kind of file\n"
1530 " will be recorded. The timeout is the maximum record time in milliseconds, or\n"
1531 " -1 for no timeout. \"Offset samples\" is optional, and, if provided, will seek\n"
1532 " to the offset without exceeding the end of the file. \"silence\" is the number\n"
1533 " of seconds of silence allowed before the function returns despite the\n"
1534 " lack of dtmf digits or reaching timeout. Silence value must be\n"
1535 " preceeded by \"s=\" and is also optional.\n";
1537 static char usage_autohangup[] =
1538 " Usage: SET AUTOHANGUP <time>\n"
1539 " Cause the channel to automatically hangup at <time> seconds in the\n"
1540 " future. Of course it can be hungup before then as well. Setting to 0 will\n"
1541 " cause the autohangup feature to be disabled on this channel.\n";
1543 static char usage_noop[] =
1547 static agi_command commands[MAX_COMMANDS] = {
1548 { { "answer", NULL }, handle_answer, "Answer channel", usage_answer },
1549 { { "channel", "status", NULL }, handle_channelstatus, "Returns status of the connected channel", usage_channelstatus },
1550 { { "database", "del", NULL }, handle_dbdel, "Removes database key/value", usage_dbdel },
1551 { { "database", "deltree", NULL }, handle_dbdeltree, "Removes database keytree/value", usage_dbdeltree },
1552 { { "database", "get", NULL }, handle_dbget, "Gets database value", usage_dbget },
1553 { { "database", "put", NULL }, handle_dbput, "Adds/updates database value", usage_dbput },
1554 { { "exec", NULL }, handle_exec, "Executes a given Application", usage_exec },
1555 { { "get", "data", NULL }, handle_getdata, "Prompts for DTMF on a channel", usage_getdata },
1556 { { "get", "full", "variable", NULL }, handle_getvariablefull, "Evaluates a channel expression", usage_getvariablefull },
1557 { { "get", "option", NULL }, handle_getoption, "Stream file, prompt for DTMF, with timeout", usage_getoption },
1558 { { "get", "variable", NULL }, handle_getvariable, "Gets a channel variable", usage_getvariable },
1559 { { "hangup", NULL }, handle_hangup, "Hangup the current channel", usage_hangup },
1560 { { "noop", NULL }, handle_noop, "Does nothing", usage_noop },
1561 { { "receive", "char", NULL }, handle_recvchar, "Receives one character from channels supporting it", usage_recvchar },
1562 { { "receive", "text", NULL }, handle_recvtext, "Receives text from channels supporting it", usage_recvtext },
1563 { { "record", "file", NULL }, handle_recordfile, "Records to a given file", usage_recordfile },
1564 { { "say", "alpha", NULL }, handle_sayalpha, "Says a given character string", usage_sayalpha },
1565 { { "say", "digits", NULL }, handle_saydigits, "Says a given digit string", usage_saydigits },
1566 { { "say", "number", NULL }, handle_saynumber, "Says a given number", usage_saynumber },
1567 { { "say", "phonetic", NULL }, handle_sayphonetic, "Says a given character string with phonetics", usage_sayphonetic },
1568 { { "say", "date", NULL }, handle_saydate, "Says a given date", usage_saydate },
1569 { { "say", "time", NULL }, handle_saytime, "Says a given time", usage_saytime },
1570 { { "say", "datetime", NULL }, handle_saydatetime, "Says a given time as specfied by the format given", usage_saydatetime },
1571 { { "send", "image", NULL }, handle_sendimage, "Sends images to channels supporting it", usage_sendimage },
1572 { { "send", "text", NULL }, handle_sendtext, "Sends text to channels supporting it", usage_sendtext },
1573 { { "set", "autohangup", NULL }, handle_autohangup, "Autohangup channel in some time", usage_autohangup },
1574 { { "set", "callerid", NULL }, handle_setcallerid, "Sets callerid for the current channel", usage_setcallerid },
1575 { { "set", "context", NULL }, handle_setcontext, "Sets channel context", usage_setcontext },
1576 { { "set", "extension", NULL }, handle_setextension, "Changes channel extension", usage_setextension },
1577 { { "set", "music", NULL }, handle_setmusic, "Enable/Disable Music on hold generator", usage_setmusic },
1578 { { "set", "priority", NULL }, handle_setpriority, "Set channel dialplan priority", usage_setpriority },
1579 { { "set", "variable", NULL }, handle_setvariable, "Sets a channel variable", usage_setvariable },
1580 { { "stream", "file", NULL }, handle_streamfile, "Sends audio file on channel", usage_streamfile },
1581 { { "control", "stream", "file", NULL }, handle_controlstreamfile, "Sends audio file on channel and allows the listner to control the stream", usage_controlstreamfile },
1582 { { "tdd", "mode", NULL }, handle_tddmode, "Toggles TDD mode (for the deaf)", usage_tddmode },
1583 { { "verbose", NULL }, handle_verbose, "Logs a message to the asterisk verbose log", usage_verbose },
1584 { { "wait", "for", "digit", NULL }, handle_waitfordigit, "Waits for a digit to be pressed", usage_waitfordigit },
1587 static int help_workhorse(int fd, char *match[])
1592 struct agi_command *e;
1594 ast_join(matchstr, sizeof(matchstr), match);
1595 for (x=0;x<sizeof(commands)/sizeof(commands[0]);x++) {
1599 /* Hide commands that start with '_' */
1600 if ((e->cmda[0])[0] == '_')
1602 ast_join(fullcmd, sizeof(fullcmd), e->cmda);
1603 if (match && strncasecmp(matchstr, fullcmd, strlen(matchstr)))
1605 ast_cli(fd, "%20.20s %s\n", fullcmd, e->summary);
1610 int agi_register(agi_command *agi)
1613 for (x=0; x<MAX_COMMANDS - 1; x++) {
1614 if (commands[x].cmda[0] == agi->cmda[0]) {
1615 ast_log(LOG_WARNING, "Command already registered!\n");
1619 for (x=0; x<MAX_COMMANDS - 1; x++) {
1620 if (!commands[x].cmda[0]) {
1625 ast_log(LOG_WARNING, "No more room for new commands!\n");
1629 void agi_unregister(agi_command *agi)
1632 for (x=0; x<MAX_COMMANDS - 1; x++) {
1633 if (commands[x].cmda[0] == agi->cmda[0]) {
1634 memset(&commands[x], 0, sizeof(agi_command));
1639 static agi_command *find_command(char *cmds[], int exact)
1645 for (x=0; x < sizeof(commands) / sizeof(commands[0]); x++) {
1646 if (!commands[x].cmda[0])
1648 /* start optimistic */
1650 for (y=0; match && cmds[y]; y++) {
1651 /* If there are no more words in the command (and we're looking for
1652 an exact match) or there is a difference between the two words,
1653 then this is not a match */
1654 if (!commands[x].cmda[y] && !exact)
1656 /* don't segfault if the next part of a command doesn't exist */
1657 if (!commands[x].cmda[y])
1659 if (strcasecmp(commands[x].cmda[y], cmds[y]))
1662 /* If more words are needed to complete the command then this is not
1663 a candidate (unless we're looking for a really inexact answer */
1664 if ((exact > -1) && commands[x].cmda[y])
1667 return &commands[x];
1673 static int parse_args(char *s, int *max, char *argv[])
1685 /* If it's escaped, put a literal quote */
1690 if (quoted && whitespace) {
1691 /* If we're starting a quote, coming off white space start a new word, too */
1699 if (!quoted && !escaped) {
1700 /* If we're not quoted, mark this as whitespace, and
1701 end the previous argument */
1705 /* Otherwise, just treat it as anything else */
1709 /* If we're escaped, print a literal, otherwise enable escaping */
1719 if (x >= MAX_ARGS -1) {
1720 ast_log(LOG_WARNING, "Too many arguments, truncating\n");
1723 /* Coming off of whitespace, start the next argument */
1732 /* Null terminate */
1739 static int agi_handle_command(struct ast_channel *chan, AGI *agi, char *buf)
1741 char *argv[MAX_ARGS];
1742 int argc = MAX_ARGS;
1746 parse_args(buf, &argc, argv);
1749 for (x=0; x<argc; x++)
1750 fprintf(stderr, "Got Arg%d: %s\n", x, argv[x]); }
1752 c = find_command(argv, 0);
1754 res = c->handler(chan, agi, argc, argv);
1756 case RESULT_SHOWUSAGE:
1757 fdprintf(agi->fd, "520-Invalid command syntax. Proper usage follows:\n");
1758 fdprintf(agi->fd, c->usage);
1759 fdprintf(agi->fd, "520 End of proper usage.\n");
1761 case AST_PBX_KEEPALIVE:
1762 /* We've been asked to keep alive, so do so */
1763 return AST_PBX_KEEPALIVE;
1765 case RESULT_FAILURE:
1766 /* They've already given the failure. We've been hung up on so handle this
1771 fdprintf(agi->fd, "510 Invalid or unknown command\n");
1776 static int run_agi(struct ast_channel *chan, char *request, AGI *agi, int pid, int dead)
1778 struct ast_channel *c;
1781 int returnstatus = 0;
1782 struct ast_frame *f;
1785 /* how many times we'll retry if ast_waitfor_nandfs will return without either
1786 channel or file descriptor in case select is interrupted by a system call (EINTR) */
1789 if (!(readf = fdopen(agi->ctrl, "r"))) {
1790 ast_log(LOG_WARNING, "Unable to fdopen file descriptor\n");
1797 setup_env(chan, request, agi->fd, (agi->audio > -1));
1800 c = ast_waitfor_nandfds(&chan, dead ? 0 : 1, &agi->ctrl, 1, NULL, &outfd, &ms);
1803 /* Idle the channel until we get a command */
1806 ast_log(LOG_DEBUG, "%s hungup\n", chan->name);
1810 /* If it's voice, write it to the audio pipe */
1811 if ((agi->audio > -1) && (f->frametype == AST_FRAME_VOICE)) {
1812 /* Write, ignoring errors */
1813 write(agi->audio, f->data, f->datalen);
1817 } else if (outfd > -1) {
1819 if (!fgets(buf, sizeof(buf), readf)) {
1820 /* Program terminated */
1823 if (option_verbose > 2)
1824 ast_verbose(VERBOSE_PREFIX_3 "AGI Script %s completed, returning %d\n", request, returnstatus);
1825 /* No need to kill the pid anymore, since they closed us */
1829 /* get rid of trailing newline, if any */
1830 if (*buf && buf[strlen(buf) - 1] == '\n')
1831 buf[strlen(buf) - 1] = 0;
1833 ast_verbose("AGI Rx << %s\n", buf);
1834 returnstatus |= agi_handle_command(chan, agi, buf);
1835 /* If the handle_command returns -1, we need to stop */
1836 if ((returnstatus < 0) || (returnstatus == AST_PBX_KEEPALIVE)) {
1841 ast_log(LOG_WARNING, "No channel, no fd?\n");
1847 /* Notify process */
1849 if (kill(pid, SIGHUP))
1850 ast_log(LOG_WARNING, "unable to send SIGHUP to AGI process %d: %s\n", pid, strerror(errno));
1853 return returnstatus;
1856 static int handle_showagi(int fd, int argc, char *argv[])
1858 struct agi_command *e;
1861 return RESULT_SHOWUSAGE;
1863 e = find_command(argv + 2, 1);
1865 ast_cli(fd, e->usage);
1867 if (find_command(argv + 2, -1)) {
1868 return help_workhorse(fd, argv + 1);
1870 ast_join(fullcmd, sizeof(fullcmd), argv+1);
1871 ast_cli(fd, "No such command '%s'.\n", fullcmd);
1875 return help_workhorse(fd, NULL);
1877 return RESULT_SUCCESS;
1880 static int handle_dumpagihtml(int fd, int argc, char *argv[])
1882 struct agi_command *e;
1888 return RESULT_SHOWUSAGE;
1890 if (!(htmlfile = fopen(argv[2], "wt"))) {
1891 ast_cli(fd, "Could not create file '%s'\n", argv[2]);
1892 return RESULT_SHOWUSAGE;
1895 fprintf(htmlfile, "<HTML>\n<HEAD>\n<TITLE>AGI Commands</TITLE>\n</HEAD>\n");
1896 fprintf(htmlfile, "<BODY>\n<CENTER><B><H1>AGI Commands</H1></B></CENTER>\n\n");
1899 fprintf(htmlfile, "<TABLE BORDER=\"0\" CELLSPACING=\"10\">\n");
1901 for (x=0;x<sizeof(commands)/sizeof(commands[0]);x++) {
1902 char *stringp, *tempstr;
1905 if (!e->cmda[0]) /* end ? */
1907 /* Hide commands that start with '_' */
1908 if ((e->cmda[0])[0] == '_')
1910 ast_join(fullcmd, sizeof(fullcmd), e->cmda);
1912 fprintf(htmlfile, "<TR><TD><TABLE BORDER=\"1\" CELLPADDING=\"5\" WIDTH=\"100%%\">\n");
1913 fprintf(htmlfile, "<TR><TH ALIGN=\"CENTER\"><B>%s - %s</B></TD></TR>\n", fullcmd,e->summary);
1916 tempstr = strsep(&stringp, "\n");
1918 fprintf(htmlfile, "<TR><TD ALIGN=\"CENTER\">%s</TD></TR>\n", tempstr);
1920 fprintf(htmlfile, "<TR><TD ALIGN=\"CENTER\">\n");
1921 while ((tempstr = strsep(&stringp, "\n")) != NULL)
1922 fprintf(htmlfile, "%s<BR>\n",tempstr);
1923 fprintf(htmlfile, "</TD></TR>\n");
1924 fprintf(htmlfile, "</TABLE></TD></TR>\n\n");
1928 fprintf(htmlfile, "</TABLE>\n</BODY>\n</HTML>\n");
1930 ast_cli(fd, "AGI HTML Commands Dumped to: %s\n", argv[2]);
1931 return RESULT_SUCCESS;
1934 static int agi_exec_full(struct ast_channel *chan, void *data, int enhanced, int dead)
1937 struct localuser *u;
1938 char *argv[MAX_ARGS];
1940 char *tmp = (char *)buf;
1948 if (ast_strlen_zero(data)) {
1949 ast_log(LOG_WARNING, "AGI requires an argument (script)\n");
1952 ast_copy_string(buf, data, sizeof(buf));
1954 memset(&agi, 0, sizeof(agi));
1955 while ((stringp = strsep(&tmp, "|")) && argc < MAX_ARGS-1)
1956 argv[argc++] = stringp;
1959 u = ast_localuser_add(me, chan);
1961 /* Answer if need be */
1962 if (chan->_state != AST_STATE_UP) {
1963 if (ast_answer(chan)) {
1964 LOCAL_USER_REMOVE(u);
1969 res = launch_script(argv[0], argv, fds, enhanced ? &efd : NULL, &pid);
1974 res = run_agi(chan, argv[0], &agi, pid, dead);
1979 ast_localuser_remove(me, u);
1983 static int agi_exec(struct ast_channel *chan, void *data)
1985 if (chan->_softhangup)
1986 ast_log(LOG_WARNING, "If you want to run AGI on hungup channels you should use DeadAGI!\n");
1987 return agi_exec_full(chan, data, 0, 0);
1990 static int eagi_exec(struct ast_channel *chan, void *data)
1995 if (chan->_softhangup)
1996 ast_log(LOG_WARNING, "If you want to run AGI on hungup channels you should use DeadAGI!\n");
1997 readformat = chan->readformat;
1998 if (ast_set_read_format(chan, AST_FORMAT_SLINEAR)) {
1999 ast_log(LOG_WARNING, "Unable to set channel '%s' to linear mode\n", chan->name);
2002 res = agi_exec_full(chan, data, 1, 0);
2004 if (ast_set_read_format(chan, readformat)) {
2005 ast_log(LOG_WARNING, "Unable to restore channel '%s' to format %s\n", chan->name, ast_getformatname(readformat));
2011 static int deadagi_exec(struct ast_channel *chan, void *data)
2013 return agi_exec_full(chan, data, 0, 1);
2016 static char showagi_help[] =
2017 "Usage: show agi [topic]\n"
2018 " When called with a topic as an argument, displays usage\n"
2019 " information on the given command. If called without a\n"
2020 " topic, it provides a list of AGI commands.\n";
2023 static char dumpagihtml_help[] =
2024 "Usage: dump agihtml <filename>\n"
2025 " Dumps the agi command list in html format to given filename\n";
2027 static struct ast_cli_entry showagi =
2028 { { "show", "agi", NULL }, handle_showagi, "Show AGI commands or specific help", showagi_help };
2030 static struct ast_cli_entry dumpagihtml =
2031 { { "dump", "agihtml", NULL }, handle_dumpagihtml, "Dumps a list of agi command in html format", dumpagihtml_help };
2033 static int unload_module(void *mod)
2035 ast_hangup_localusers(mod);
2036 ast_cli_unregister(&showagi);
2037 ast_cli_unregister(&dumpagihtml);
2038 ast_cli_unregister(&cli_debug);
2039 ast_cli_unregister(&cli_no_debug);
2040 ast_unregister_application(eapp);
2041 ast_unregister_application(deadapp);
2042 return ast_unregister_application(app);
2045 static int load_module(void *mod)
2048 ast_cli_register(&showagi);
2049 ast_cli_register(&dumpagihtml);
2050 ast_cli_register(&cli_debug);
2051 ast_cli_register(&cli_no_debug);
2052 ast_register_application(deadapp, deadagi_exec, deadsynopsis, descrip);
2053 ast_register_application(eapp, eagi_exec, esynopsis, descrip);
2054 return ast_register_application(app, agi_exec, synopsis, descrip);
2057 static const char *description(void)
2059 return "Asterisk Gateway Interface (AGI)";
2062 static const char *key(void)
2064 return ASTERISK_GPL_KEY;
2067 STD_MOD(MOD_0, NULL, NULL, NULL);