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>
28 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
30 #include <sys/types.h>
32 #include <sys/socket.h>
33 #include <netinet/in.h>
34 #include <netinet/tcp.h>
35 #include <arpa/inet.h>
48 #include "asterisk/file.h"
49 #include "asterisk/logger.h"
50 #include "asterisk/channel.h"
51 #include "asterisk/pbx.h"
52 #include "asterisk/module.h"
53 #include "asterisk/astdb.h"
54 #include "asterisk/callerid.h"
55 #include "asterisk/cli.h"
56 #include "asterisk/logger.h"
57 #include "asterisk/options.h"
58 #include "asterisk/image.h"
59 #include "asterisk/say.h"
60 #include "asterisk/app.h"
61 #include "asterisk/dsp.h"
62 #include "asterisk/musiconhold.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 *app = "AGI";
76 static char *eapp = "EAGI";
78 static char *deadapp = "DeadAGI";
80 static char *synopsis = "Executes an AGI compliant application";
81 static char *esynopsis = "Executes an EAGI compliant application";
82 static char *deadsynopsis = "Executes AGI on a hungup channel";
84 static char *descrip =
85 " [E|Dead]AGI(command|args): Executes an Asterisk Gateway Interface compliant\n"
86 "program on a channel. AGI allows Asterisk to launch external programs\n"
87 "written in any language to control a telephony channel, play audio,\n"
88 "read DTMF digits, etc. by communicating with the AGI protocol on stdin\n"
90 " This channel will stop dialplan execution on hangup inside of this\n"
91 "application, except when using DeadAGI. Otherwise, dialplan execution\n"
92 "will continue normally.\n"
93 " A locally executed AGI script will receive SIGHUP on hangup from the channel\n"
94 "except when using DeadAGI. This can be disabled by setting the AGISIGHUP channel\n"
95 "variable to \"no\" before executing the AGI application.\n"
96 " Using 'EAGI' provides enhanced AGI, with incoming audio available out of band\n"
97 "on file descriptor 3\n\n"
98 " Use the CLI command 'agi show' to list available agi commands\n"
99 " This application sets the following channel variable upon completion:\n"
100 " AGISTATUS The status of the attempt to the run the AGI script\n"
101 " text string, one of SUCCESS | FAILED | HANGUP\n";
103 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
118 static void agi_debug_cli(int fd, char *fmt, ...)
125 res = vasprintf(&stuff, fmt, ap);
128 ast_log(LOG_ERROR, "Out of memory\n");
131 ast_verbose("AGI Tx >> %s\n", stuff);
132 ast_carefulwrite(fd, stuff, strlen(stuff), 100);
137 /* launch_netscript: The fastagi handler.
138 FastAGI defaults to port 4573 */
139 static enum agi_result launch_netscript(char *agiurl, char *argv[], int *fds, int *efd, int *opid)
143 struct pollfd pfds[1];
145 char *c; int port = AGI_PORT;
147 struct sockaddr_in sin;
149 struct ast_hostent ahp;
152 /* agiusl is "agi://host.domain[:port][/script/name]" */
153 host = ast_strdupa(agiurl + 6); /* Remove agi:// */
154 /* Strip off any script name */
155 if ((c = strchr(host, '/'))) {
160 if ((c = strchr(host, ':'))) {
166 ast_log(LOG_WARNING, "AGI URI's don't support Enhanced AGI yet\n");
169 hp = ast_gethostbyname(host, &ahp);
171 ast_log(LOG_WARNING, "Unable to locate host '%s'\n", host);
174 s = socket(AF_INET, SOCK_STREAM, 0);
176 ast_log(LOG_WARNING, "Unable to create socket: %s\n", strerror(errno));
179 flags = fcntl(s, F_GETFL);
181 ast_log(LOG_WARNING, "Fcntl(F_GETFL) failed: %s\n", strerror(errno));
185 if (fcntl(s, F_SETFL, flags | O_NONBLOCK) < 0) {
186 ast_log(LOG_WARNING, "Fnctl(F_SETFL) failed: %s\n", strerror(errno));
190 memset(&sin, 0, sizeof(sin));
191 sin.sin_family = AF_INET;
192 sin.sin_port = htons(port);
193 memcpy(&sin.sin_addr, hp->h_addr, sizeof(sin.sin_addr));
194 if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) && (errno != EINPROGRESS)) {
195 ast_log(LOG_WARNING, "Connect failed with unexpected error: %s\n", strerror(errno));
197 return AGI_RESULT_FAILURE;
201 pfds[0].events = POLLOUT;
202 while ((res = poll(pfds, 1, MAX_AGI_CONNECT)) != 1) {
203 if (errno != EINTR) {
205 ast_log(LOG_WARNING, "FastAGI connection to '%s' timed out after MAX_AGI_CONNECT (%d) milliseconds.\n",
206 agiurl, MAX_AGI_CONNECT);
208 ast_log(LOG_WARNING, "Connect to '%s' failed: %s\n", agiurl, strerror(errno));
210 return AGI_RESULT_FAILURE;
213 /* XXX in theory should check for partial writes... */
214 while (write(s, "agi_network: yes\n", strlen("agi_network: yes\n")) < 0) {
215 if (errno != EINTR) {
216 ast_log(LOG_WARNING, "Connect to '%s' failed: %s\n", agiurl, strerror(errno));
218 return AGI_RESULT_FAILURE;
222 /* If we have a script parameter, relay it to the fastagi server */
223 /* Script parameters take the form of: AGI(agi://my.example.com/?extension=${EXTEN}) */
224 if (!ast_strlen_zero(script))
225 fdprintf(s, "agi_network_script: %s\n", script);
227 ast_debug(4, "Wow, connected!\n");
231 return AGI_RESULT_SUCCESS;
234 static enum agi_result launch_script(char *script, char *argv[], int *fds, int *efd, int *opid)
243 sigset_t signal_set, old_set;
245 if (!strncasecmp(script, "agi://", 6))
246 return launch_netscript(script, argv, fds, efd, opid);
248 if (script[0] != '/') {
249 snprintf(tmp, sizeof(tmp), "%s/%s", ast_config_AST_AGI_DIR, script);
253 ast_log(LOG_WARNING, "Unable to create toast pipe: %s\n",strerror(errno));
254 return AGI_RESULT_FAILURE;
257 ast_log(LOG_WARNING, "unable to create fromast pipe: %s\n", strerror(errno));
260 return AGI_RESULT_FAILURE;
264 ast_log(LOG_WARNING, "unable to create audio pipe: %s\n", strerror(errno));
269 return AGI_RESULT_FAILURE;
271 res = fcntl(audio[1], F_GETFL);
273 res = fcntl(audio[1], F_SETFL, res | O_NONBLOCK);
275 ast_log(LOG_WARNING, "unable to set audio pipe parameters: %s\n", strerror(errno));
282 return AGI_RESULT_FAILURE;
286 /* Block SIGHUP during the fork - prevents a race */
287 sigfillset(&signal_set);
288 pthread_sigmask(SIG_BLOCK, &signal_set, &old_set);
291 ast_log(LOG_WARNING, "Failed to fork(): %s\n", strerror(errno));
292 pthread_sigmask(SIG_SETMASK, &old_set, NULL);
293 return AGI_RESULT_FAILURE;
296 /* Pass paths to AGI via environmental variables */
297 setenv("AST_CONFIG_DIR", ast_config_AST_CONFIG_DIR, 1);
298 setenv("AST_CONFIG_FILE", ast_config_AST_CONFIG_FILE, 1);
299 setenv("AST_MODULE_DIR", ast_config_AST_MODULE_DIR, 1);
300 setenv("AST_SPOOL_DIR", ast_config_AST_SPOOL_DIR, 1);
301 setenv("AST_MONITOR_DIR", ast_config_AST_MONITOR_DIR, 1);
302 setenv("AST_VAR_DIR", ast_config_AST_VAR_DIR, 1);
303 setenv("AST_DATA_DIR", ast_config_AST_DATA_DIR, 1);
304 setenv("AST_LOG_DIR", ast_config_AST_LOG_DIR, 1);
305 setenv("AST_AGI_DIR", ast_config_AST_AGI_DIR, 1);
306 setenv("AST_KEY_DIR", ast_config_AST_KEY_DIR, 1);
307 setenv("AST_RUN_DIR", ast_config_AST_RUN_DIR, 1);
309 /* Don't run AGI scripts with realtime priority -- it causes audio stutter */
312 /* Redirect stdin and out, provide enhanced audio channel if desired */
313 dup2(fromast[0], STDIN_FILENO);
314 dup2(toast[1], STDOUT_FILENO);
316 dup2(audio[0], STDERR_FILENO + 1);
318 close(STDERR_FILENO + 1);
321 /* Before we unblock our signals, return our trapped signals back to the defaults */
322 signal(SIGHUP, SIG_DFL);
323 signal(SIGCHLD, SIG_DFL);
324 signal(SIGINT, SIG_DFL);
325 signal(SIGURG, SIG_DFL);
326 signal(SIGTERM, SIG_DFL);
327 signal(SIGPIPE, SIG_DFL);
328 signal(SIGXFSZ, SIG_DFL);
330 /* unblock important signal handlers */
331 if (pthread_sigmask(SIG_UNBLOCK, &signal_set, NULL)) {
332 ast_log(LOG_WARNING, "unable to unblock signals for AGI script: %s\n", strerror(errno));
336 /* Close everything but stdin/out/error */
337 for (x=STDERR_FILENO + 2;x<1024;x++)
341 /* XXX argv should be deprecated in favor of passing agi_argX paramaters */
343 /* Can't use ast_log since FD's are closed */
344 fprintf(stdout, "verbose \"Failed to execute '%s': %s\" 2\n", script, strerror(errno));
348 pthread_sigmask(SIG_SETMASK, &old_set, NULL);
349 if (option_verbose > 2)
350 ast_verbose(VERBOSE_PREFIX_3 "Launched AGI Script %s\n", script);
356 /* close what we're not using in the parent */
364 return AGI_RESULT_SUCCESS;
367 static void setup_env(struct ast_channel *chan, char *request, int fd, int enhanced, int argc, char *argv[])
371 /* Print initial environment, with agi_request always being the first
373 fdprintf(fd, "agi_request: %s\n", request);
374 fdprintf(fd, "agi_channel: %s\n", chan->name);
375 fdprintf(fd, "agi_language: %s\n", chan->language);
376 fdprintf(fd, "agi_type: %s\n", chan->tech->type);
377 fdprintf(fd, "agi_uniqueid: %s\n", chan->uniqueid);
380 fdprintf(fd, "agi_callerid: %s\n", S_OR(chan->cid.cid_num, "unknown"));
381 fdprintf(fd, "agi_calleridname: %s\n", S_OR(chan->cid.cid_name, "unknown"));
382 fdprintf(fd, "agi_callingpres: %d\n", chan->cid.cid_pres);
383 fdprintf(fd, "agi_callingani2: %d\n", chan->cid.cid_ani2);
384 fdprintf(fd, "agi_callington: %d\n", chan->cid.cid_ton);
385 fdprintf(fd, "agi_callingtns: %d\n", chan->cid.cid_tns);
386 fdprintf(fd, "agi_dnid: %s\n", S_OR(chan->cid.cid_dnid, "unknown"));
387 fdprintf(fd, "agi_rdnis: %s\n", S_OR(chan->cid.cid_rdnis, "unknown"));
389 /* Context information */
390 fdprintf(fd, "agi_context: %s\n", chan->context);
391 fdprintf(fd, "agi_extension: %s\n", chan->exten);
392 fdprintf(fd, "agi_priority: %d\n", chan->priority);
393 fdprintf(fd, "agi_enhanced: %s\n", enhanced ? "1.0" : "0.0");
395 /* User information */
396 fdprintf(fd, "agi_accountcode: %s\n", chan->accountcode ? chan->accountcode : "");
398 /* Send any parameters to the fastagi server that have been passed via the agi application */
399 /* Agi application paramaters take the form of: AGI(/path/to/example/script|${EXTEN}) */
400 for(count = 1; count < argc; count++)
401 fdprintf(fd, "agi_arg_%d: %s\n", count, argv[count]);
403 /* End with empty return */
407 static int handle_answer(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
411 if (chan->_state != AST_STATE_UP) {
412 /* Answer the chan */
413 res = ast_answer(chan);
415 fdprintf(agi->fd, "200 result=%d\n", res);
416 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
419 static int handle_waitfordigit(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
424 return RESULT_SHOWUSAGE;
425 if (sscanf(argv[3], "%d", &to) != 1)
426 return RESULT_SHOWUSAGE;
427 res = ast_waitfordigit_full(chan, to, agi->audio, agi->ctrl);
428 fdprintf(agi->fd, "200 result=%d\n", res);
429 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
432 static int handle_sendtext(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
436 return RESULT_SHOWUSAGE;
437 /* At the moment, the parser (perhaps broken) returns with
438 the last argument PLUS the newline at the end of the input
439 buffer. This probably needs to be fixed, but I wont do that
440 because other stuff may break as a result. The right way
441 would probably be to strip off the trailing newline before
442 parsing, then here, add a newline at the end of the string
443 before sending it to ast_sendtext --DUDE */
444 res = ast_sendtext(chan, argv[2]);
445 fdprintf(agi->fd, "200 result=%d\n", res);
446 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
449 static int handle_recvchar(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
453 return RESULT_SHOWUSAGE;
454 res = ast_recvchar(chan,atoi(argv[2]));
456 fdprintf(agi->fd, "200 result=%d (timeout)\n", res);
457 return RESULT_SUCCESS;
460 fdprintf(agi->fd, "200 result=%d\n", res);
461 return RESULT_SUCCESS;
464 fdprintf(agi->fd, "200 result=%d (hangup)\n", res);
465 return RESULT_FAILURE;
469 static int handle_recvtext(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
474 return RESULT_SHOWUSAGE;
475 buf = ast_recvtext(chan,atoi(argv[2]));
477 fdprintf(agi->fd, "200 result=1 (%s)\n", buf);
480 fdprintf(agi->fd, "200 result=-1\n");
482 return RESULT_SUCCESS;
485 static int handle_tddmode(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
489 return RESULT_SHOWUSAGE;
490 if (!strncasecmp(argv[2],"on",2))
494 if (!strncasecmp(argv[2],"mate",4))
496 if (!strncasecmp(argv[2],"tdd",3))
498 res = ast_channel_setoption(chan, AST_OPTION_TDD, &x, sizeof(char), 0);
499 if (res != RESULT_SUCCESS)
500 fdprintf(agi->fd, "200 result=0\n");
502 fdprintf(agi->fd, "200 result=1\n");
503 return RESULT_SUCCESS;
506 static int handle_sendimage(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
510 return RESULT_SHOWUSAGE;
511 res = ast_send_image(chan, argv[2]);
512 if (!ast_check_hangup(chan))
514 fdprintf(agi->fd, "200 result=%d\n", res);
515 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
518 static int handle_controlstreamfile(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
527 if (argc < 5 || argc > 9)
528 return RESULT_SHOWUSAGE;
530 if (!ast_strlen_zero(argv[4]))
535 if ((argc > 5) && (sscanf(argv[5], "%d", &skipms) != 1))
536 return RESULT_SHOWUSAGE;
538 if (argc > 6 && !ast_strlen_zero(argv[6]))
543 if (argc > 7 && !ast_strlen_zero(argv[7]))
548 if (argc > 8 && !ast_strlen_zero(argv[8]))
553 res = ast_control_streamfile(chan, argv[3], fwd, rev, stop, pause, NULL, skipms, NULL);
555 fdprintf(agi->fd, "200 result=%d\n", res);
557 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
560 static int handle_streamfile(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
564 struct ast_filestream *fs;
565 struct ast_filestream *vfs;
566 long sample_offset = 0;
570 if (argc < 4 || argc > 5)
571 return RESULT_SHOWUSAGE;
576 if ((argc > 4) && (sscanf(argv[4], "%ld", &sample_offset) != 1))
577 return RESULT_SHOWUSAGE;
579 fs = ast_openstream(chan, argv[2], chan->language);
582 fdprintf(agi->fd, "200 result=%d endpos=%ld\n", 0, sample_offset);
583 return RESULT_SUCCESS;
585 vfs = ast_openvstream(chan, argv[2], chan->language);
586 ast_debug(vfs && 1, "Ooh, found a video stream, too\n");
588 if (option_verbose > 2)
589 ast_verbose(VERBOSE_PREFIX_3 "Playing '%s' (escape_digits=%s) (sample_offset %ld)\n", argv[2], edigits, sample_offset);
591 ast_seekstream(fs, 0, SEEK_END);
592 max_length = ast_tellstream(fs);
593 ast_seekstream(fs, sample_offset, SEEK_SET);
594 res = ast_applystream(chan, fs);
596 vres = ast_applystream(chan, vfs);
597 res = ast_playstream(fs);
599 vres = ast_playstream(vfs);
602 fdprintf(agi->fd, "200 result=%d endpos=%ld\n", res, sample_offset);
603 return (res >= 0) ? RESULT_SHOWUSAGE : RESULT_FAILURE;
605 res = ast_waitstream_full(chan, argv[3], agi->audio, agi->ctrl);
606 /* this is to check for if ast_waitstream closed the stream, we probably are at
607 * the end of the stream, return that amount, else check for the amount */
608 sample_offset = (chan->stream) ? ast_tellstream(fs) : max_length;
609 ast_stopstream(chan);
611 /* Stop this command, don't print a result line, as there is a new command */
612 return RESULT_SUCCESS;
614 fdprintf(agi->fd, "200 result=%d endpos=%ld\n", res, sample_offset);
615 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
618 /* get option - really similar to the handle_streamfile, but with a timeout */
619 static int handle_getoption(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
623 struct ast_filestream *fs;
624 struct ast_filestream *vfs;
625 long sample_offset = 0;
630 if ( argc < 4 || argc > 5 )
631 return RESULT_SHOWUSAGE;
637 timeout = atoi(argv[4]);
638 else if (chan->pbx->dtimeout) {
639 /* by default dtimeout is set to 5sec */
640 timeout = chan->pbx->dtimeout * 1000; /* in msec */
643 fs = ast_openstream(chan, argv[2], chan->language);
645 fdprintf(agi->fd, "200 result=%d endpos=%ld\n", 0, sample_offset);
646 ast_log(LOG_WARNING, "Unable to open %s\n", argv[2]);
647 return RESULT_SUCCESS;
649 vfs = ast_openvstream(chan, argv[2], chan->language);
650 ast_debug(vfs && 1, "Ooh, found a video stream, too\n");
652 if (option_verbose > 2)
653 ast_verbose(VERBOSE_PREFIX_3 "Playing '%s' (escape_digits=%s) (timeout %d)\n", argv[2], edigits, timeout);
655 ast_seekstream(fs, 0, SEEK_END);
656 max_length = ast_tellstream(fs);
657 ast_seekstream(fs, sample_offset, SEEK_SET);
658 res = ast_applystream(chan, fs);
660 vres = ast_applystream(chan, vfs);
661 res = ast_playstream(fs);
663 vres = ast_playstream(vfs);
665 fdprintf(agi->fd, "200 result=%d endpos=%ld\n", res, sample_offset);
667 return RESULT_SHOWUSAGE;
669 return RESULT_FAILURE;
671 res = ast_waitstream_full(chan, argv[3], agi->audio, agi->ctrl);
672 /* this is to check for if ast_waitstream closed the stream, we probably are at
673 * the end of the stream, return that amount, else check for the amount */
674 sample_offset = (chan->stream)?ast_tellstream(fs):max_length;
675 ast_stopstream(chan);
677 /* Stop this command, don't print a result line, as there is a new command */
678 return RESULT_SUCCESS;
681 /* If the user didnt press a key, wait for digitTimeout*/
683 res = ast_waitfordigit_full(chan, timeout, agi->audio, agi->ctrl);
684 /* Make sure the new result is in the escape digits of the GET OPTION */
685 if ( !strchr(edigits,res) )
689 fdprintf(agi->fd, "200 result=%d endpos=%ld\n", res, sample_offset);
690 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
696 /*--- handle_saynumber: Say number in various language syntaxes ---*/
697 /* While waiting, we're sending a NULL. */
698 static int handle_saynumber(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
702 if (argc < 4 || argc > 5)
703 return RESULT_SHOWUSAGE;
704 if (sscanf(argv[2], "%d", &num) != 1)
705 return RESULT_SHOWUSAGE;
706 res = ast_say_number_full(chan, num, argv[3], chan->language, argc > 4 ? argv[4] : NULL, agi->audio, agi->ctrl);
708 return RESULT_SUCCESS;
709 fdprintf(agi->fd, "200 result=%d\n", res);
710 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
713 static int handle_saydigits(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
719 return RESULT_SHOWUSAGE;
720 if (sscanf(argv[2], "%d", &num) != 1)
721 return RESULT_SHOWUSAGE;
723 res = ast_say_digit_str_full(chan, argv[2], argv[3], chan->language, agi->audio, agi->ctrl);
724 if (res == 1) /* New command */
725 return RESULT_SUCCESS;
726 fdprintf(agi->fd, "200 result=%d\n", res);
727 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
730 static int handle_sayalpha(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
735 return RESULT_SHOWUSAGE;
737 res = ast_say_character_str_full(chan, argv[2], argv[3], chan->language, agi->audio, agi->ctrl);
738 if (res == 1) /* New command */
739 return RESULT_SUCCESS;
740 fdprintf(agi->fd, "200 result=%d\n", res);
741 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
744 static int handle_saydate(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
749 return RESULT_SHOWUSAGE;
750 if (sscanf(argv[2], "%d", &num) != 1)
751 return RESULT_SHOWUSAGE;
752 res = ast_say_date(chan, num, argv[3], chan->language);
754 return RESULT_SUCCESS;
755 fdprintf(agi->fd, "200 result=%d\n", res);
756 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
759 static int handle_saytime(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
764 return RESULT_SHOWUSAGE;
765 if (sscanf(argv[2], "%d", &num) != 1)
766 return RESULT_SHOWUSAGE;
767 res = ast_say_time(chan, num, argv[3], chan->language);
769 return RESULT_SUCCESS;
770 fdprintf(agi->fd, "200 result=%d\n", res);
771 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
774 static int handle_saydatetime(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
778 char *format, *zone=NULL;
781 return RESULT_SHOWUSAGE;
786 /* XXX this doesn't belong here, but in the 'say' module */
787 if (!strcasecmp(chan->language, "de")) {
788 format = "A dBY HMS";
790 format = "ABdY 'digits/at' IMp";
794 if (argc > 5 && !ast_strlen_zero(argv[5]))
797 if (ast_get_time_t(argv[2], &unixtime, 0, NULL))
798 return RESULT_SHOWUSAGE;
800 res = ast_say_date_with_format(chan, unixtime, argv[3], chan->language, format, zone);
802 return RESULT_SUCCESS;
804 fdprintf(agi->fd, "200 result=%d\n", res);
805 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
808 static int handle_sayphonetic(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
813 return RESULT_SHOWUSAGE;
815 res = ast_say_phonetic_str_full(chan, argv[2], argv[3], chan->language, agi->audio, agi->ctrl);
816 if (res == 1) /* New command */
817 return RESULT_SUCCESS;
818 fdprintf(agi->fd, "200 result=%d\n", res);
819 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
822 static int handle_getdata(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
830 return RESULT_SHOWUSAGE;
832 timeout = atoi(argv[3]);
839 res = ast_app_getdata_full(chan, argv[2], data, max, timeout, agi->audio, agi->ctrl);
840 if (res == 2) /* New command */
841 return RESULT_SUCCESS;
843 fdprintf(agi->fd, "200 result=%s (timeout)\n", data);
845 fdprintf(agi->fd, "200 result=-1\n");
847 fdprintf(agi->fd, "200 result=%s\n", data);
848 return RESULT_SUCCESS;
851 static int handle_setcontext(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
855 return RESULT_SHOWUSAGE;
856 ast_copy_string(chan->context, argv[2], sizeof(chan->context));
857 fdprintf(agi->fd, "200 result=0\n");
858 return RESULT_SUCCESS;
861 static int handle_setextension(struct ast_channel *chan, AGI *agi, int argc, char **argv)
864 return RESULT_SHOWUSAGE;
865 ast_copy_string(chan->exten, argv[2], sizeof(chan->exten));
866 fdprintf(agi->fd, "200 result=0\n");
867 return RESULT_SUCCESS;
870 static int handle_setpriority(struct ast_channel *chan, AGI *agi, int argc, char **argv)
874 return RESULT_SHOWUSAGE;
876 if (sscanf(argv[2], "%d", &pri) != 1) {
877 if ((pri = ast_findlabel_extension(chan, chan->context, chan->exten, argv[2], chan->cid.cid_num)) < 1)
878 return RESULT_SHOWUSAGE;
881 ast_explicit_goto(chan, NULL, NULL, pri);
882 fdprintf(agi->fd, "200 result=0\n");
883 return RESULT_SUCCESS;
886 static int handle_recordfile(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
888 struct ast_filestream *fs;
890 struct timeval start;
891 long sample_offset = 0;
895 struct ast_dsp *sildet=NULL; /* silence detector dsp */
896 int totalsilence = 0;
898 int silence = 0; /* amount of silence to allow */
899 int gotsilence = 0; /* did we timeout for silence? */
900 char *silencestr=NULL;
904 /* XXX EAGI FIXME XXX */
907 return RESULT_SHOWUSAGE;
908 if (sscanf(argv[5], "%d", &ms) != 1)
909 return RESULT_SHOWUSAGE;
912 silencestr = strchr(argv[6],'s');
913 if ((argc > 7) && (!silencestr))
914 silencestr = strchr(argv[7],'s');
915 if ((argc > 8) && (!silencestr))
916 silencestr = strchr(argv[8],'s');
919 if (strlen(silencestr) > 2) {
920 if ((silencestr[0] == 's') && (silencestr[1] == '=')) {
924 silence = atoi(silencestr);
932 rfmt = chan->readformat;
933 res = ast_set_read_format(chan, AST_FORMAT_SLINEAR);
935 ast_log(LOG_WARNING, "Unable to set to linear mode, giving up\n");
938 sildet = ast_dsp_new();
940 ast_log(LOG_WARNING, "Unable to create silence detector :(\n");
943 ast_dsp_set_threshold(sildet, 256);
946 /* backward compatibility, if no offset given, arg[6] would have been
947 * caught below and taken to be a beep, else if it is a digit then it is a
949 if ((argc >6) && (sscanf(argv[6], "%ld", &sample_offset) != 1) && (!strchr(argv[6], '=')))
950 res = ast_streamfile(chan, "beep", chan->language);
952 if ((argc > 7) && (!strchr(argv[7], '=')))
953 res = ast_streamfile(chan, "beep", chan->language);
956 res = ast_waitstream(chan, argv[4]);
958 fdprintf(agi->fd, "200 result=%d (randomerror) endpos=%ld\n", res, sample_offset);
960 fs = ast_writefile(argv[2], argv[3], NULL, O_CREAT | O_WRONLY | (sample_offset ? O_APPEND : 0), 0, AST_FILE_MODE);
963 fdprintf(agi->fd, "200 result=%d (writefile)\n", res);
965 ast_dsp_free(sildet);
966 return RESULT_FAILURE;
969 /* Request a video update */
970 ast_indicate(chan, AST_CONTROL_VIDUPDATE);
973 ast_applystream(chan,fs);
974 /* really should have checks */
975 ast_seekstream(fs, sample_offset, SEEK_SET);
979 while ((ms < 0) || ast_tvdiff_ms(ast_tvnow(), start) < ms) {
980 res = ast_waitfor(chan, -1);
983 fdprintf(agi->fd, "200 result=%d (waitfor) endpos=%ld\n", res,sample_offset);
985 ast_dsp_free(sildet);
986 return RESULT_FAILURE;
990 fdprintf(agi->fd, "200 result=%d (hangup) endpos=%ld\n", 0, sample_offset);
993 ast_dsp_free(sildet);
994 return RESULT_FAILURE;
996 switch(f->frametype) {
998 if (strchr(argv[4], f->subclass)) {
999 /* This is an interrupting chracter, so rewind to chop off any small
1000 amount of DTMF that may have been recorded
1002 ast_stream_rewind(fs, 200);
1003 ast_truncstream(fs);
1004 sample_offset = ast_tellstream(fs);
1005 fdprintf(agi->fd, "200 result=%d (dtmf) endpos=%ld\n", f->subclass, sample_offset);
1006 ast_closestream(fs);
1009 ast_dsp_free(sildet);
1010 return RESULT_SUCCESS;
1013 case AST_FRAME_VOICE:
1014 ast_writestream(fs, f);
1015 /* this is a safe place to check progress since we know that fs
1016 * is valid after a write, and it will then have our current
1018 sample_offset = ast_tellstream(fs);
1021 ast_dsp_silence(sildet, f, &dspsilence);
1023 totalsilence = dspsilence;
1027 if (totalsilence > silence) {
1028 /* Ended happily with silence */
1034 case AST_FRAME_VIDEO:
1035 ast_writestream(fs, f);
1037 /* Ignore all other frames */
1046 ast_stream_rewind(fs, silence-1000);
1047 ast_truncstream(fs);
1048 sample_offset = ast_tellstream(fs);
1050 fdprintf(agi->fd, "200 result=%d (timeout) endpos=%ld\n", res, sample_offset);
1051 ast_closestream(fs);
1055 res = ast_set_read_format(chan, rfmt);
1057 ast_log(LOG_WARNING, "Unable to restore read format on '%s'\n", chan->name);
1058 ast_dsp_free(sildet);
1060 return RESULT_SUCCESS;
1063 static int handle_autohangup(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
1068 return RESULT_SHOWUSAGE;
1069 if (sscanf(argv[2], "%d", &timeout) != 1)
1070 return RESULT_SHOWUSAGE;
1074 chan->whentohangup = time(NULL) + timeout;
1076 chan->whentohangup = 0;
1077 fdprintf(agi->fd, "200 result=0\n");
1078 return RESULT_SUCCESS;
1081 static int handle_hangup(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1083 struct ast_channel *c;
1085 /* no argument: hangup the current channel */
1086 ast_softhangup(chan,AST_SOFTHANGUP_EXPLICIT);
1087 fdprintf(agi->fd, "200 result=1\n");
1088 return RESULT_SUCCESS;
1089 } else if (argc == 2) {
1090 /* one argument: look for info on the specified channel */
1091 c = ast_get_channel_by_name_locked(argv[1]);
1093 /* we have a matching channel */
1094 ast_softhangup(c,AST_SOFTHANGUP_EXPLICIT);
1095 fdprintf(agi->fd, "200 result=1\n");
1096 ast_channel_unlock(c);
1097 return RESULT_SUCCESS;
1099 /* if we get this far no channel name matched the argument given */
1100 fdprintf(agi->fd, "200 result=-1\n");
1101 return RESULT_SUCCESS;
1103 return RESULT_SHOWUSAGE;
1107 static int handle_exec(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1110 struct ast_app *app;
1113 return RESULT_SHOWUSAGE;
1115 if (option_verbose > 2)
1116 ast_verbose(VERBOSE_PREFIX_3 "AGI Script Executing Application: (%s) Options: (%s)\n", argv[1], argv[2]);
1118 app = pbx_findapp(argv[1]);
1121 res = pbx_exec(chan, app, argv[2]);
1123 ast_log(LOG_WARNING, "Could not find application (%s)\n", argv[1]);
1126 fdprintf(agi->fd, "200 result=%d\n", res);
1131 static int handle_setcallerid(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1134 char *l = NULL, *n = NULL;
1137 ast_copy_string(tmp, argv[2], sizeof(tmp));
1138 ast_callerid_parse(tmp, &n, &l);
1140 ast_shrink_phone_number(l);
1145 ast_set_callerid(chan, l, n, NULL);
1148 fdprintf(agi->fd, "200 result=1\n");
1149 return RESULT_SUCCESS;
1152 static int handle_channelstatus(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1154 struct ast_channel *c;
1156 /* no argument: supply info on the current channel */
1157 fdprintf(agi->fd, "200 result=%d\n", chan->_state);
1158 return RESULT_SUCCESS;
1159 } else if (argc == 3) {
1160 /* one argument: look for info on the specified channel */
1161 c = ast_get_channel_by_name_locked(argv[2]);
1163 fdprintf(agi->fd, "200 result=%d\n", c->_state);
1164 ast_channel_unlock(c);
1165 return RESULT_SUCCESS;
1167 /* if we get this far no channel name matched the argument given */
1168 fdprintf(agi->fd, "200 result=-1\n");
1169 return RESULT_SUCCESS;
1171 return RESULT_SHOWUSAGE;
1175 static int handle_setvariable(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1178 pbx_builtin_setvar_helper(chan, argv[2], argv[3]);
1180 fdprintf(agi->fd, "200 result=1\n");
1181 return RESULT_SUCCESS;
1184 static int handle_getvariable(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1190 return RESULT_SHOWUSAGE;
1192 /* check if we want to execute an ast_custom_function */
1193 if (!ast_strlen_zero(argv[2]) && (argv[2][strlen(argv[2]) - 1] == ')')) {
1194 ret = ast_func_read(chan, argv[2], tempstr, sizeof(tempstr)) ? NULL : tempstr;
1196 pbx_retrieve_variable(chan, argv[2], &ret, tempstr, sizeof(tempstr), NULL);
1200 fdprintf(agi->fd, "200 result=1 (%s)\n", ret);
1202 fdprintf(agi->fd, "200 result=0\n");
1204 return RESULT_SUCCESS;
1207 static int handle_getvariablefull(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1209 char tmp[4096] = "";
1210 struct ast_channel *chan2=NULL;
1212 if ((argc != 4) && (argc != 5))
1213 return RESULT_SHOWUSAGE;
1215 chan2 = ast_get_channel_by_name_locked(argv[4]);
1219 if (chan) { /* XXX isn't this chan2 ? */
1220 pbx_substitute_variables_helper(chan2, argv[3], tmp, sizeof(tmp) - 1);
1221 fdprintf(agi->fd, "200 result=1 (%s)\n", tmp);
1223 fdprintf(agi->fd, "200 result=0\n");
1225 if (chan2 && (chan2 != chan))
1226 ast_channel_unlock(chan2);
1227 return RESULT_SUCCESS;
1230 static int handle_verbose(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1236 return RESULT_SHOWUSAGE;
1239 sscanf(argv[2], "%d", &level);
1243 prefix = VERBOSE_PREFIX_4;
1246 prefix = VERBOSE_PREFIX_3;
1249 prefix = VERBOSE_PREFIX_2;
1253 prefix = VERBOSE_PREFIX_1;
1257 if (level <= option_verbose)
1258 ast_verbose("%s %s: %s\n", prefix, chan->data, argv[1]);
1260 fdprintf(agi->fd, "200 result=1\n");
1262 return RESULT_SUCCESS;
1265 static int handle_dbget(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1271 return RESULT_SHOWUSAGE;
1272 res = ast_db_get(argv[2], argv[3], tmp, sizeof(tmp));
1274 fdprintf(agi->fd, "200 result=0\n");
1276 fdprintf(agi->fd, "200 result=1 (%s)\n", tmp);
1278 return RESULT_SUCCESS;
1281 static int handle_dbput(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1286 return RESULT_SHOWUSAGE;
1287 res = ast_db_put(argv[2], argv[3], argv[4]);
1288 fdprintf(agi->fd, "200 result=%c\n", res ? '0' : '1');
1289 return RESULT_SUCCESS;
1292 static int handle_dbdel(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1297 return RESULT_SHOWUSAGE;
1298 res = ast_db_del(argv[2], argv[3]);
1299 fdprintf(agi->fd, "200 result=%c\n", res ? '0' : '1');
1300 return RESULT_SUCCESS;
1303 static int handle_dbdeltree(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1306 if ((argc < 3) || (argc > 4))
1307 return RESULT_SHOWUSAGE;
1309 res = ast_db_deltree(argv[2], argv[3]);
1311 res = ast_db_deltree(argv[2], NULL);
1313 fdprintf(agi->fd, "200 result=%c\n", res ? '0' : '1');
1314 return RESULT_SUCCESS;
1317 static const char debug_usage[] =
1318 "Usage: agi debug\n"
1319 " Enables dumping of AGI transactions for debugging purposes\n";
1321 static const char no_debug_usage[] =
1322 "Usage: agi debug off\n"
1323 " Disables dumping of AGI transactions for debugging purposes\n";
1325 static int agi_do_debug(int fd, int argc, char *argv[])
1328 return RESULT_SHOWUSAGE;
1330 ast_cli(fd, "AGI Debugging Enabled\n");
1331 return RESULT_SUCCESS;
1334 static int agi_no_debug(int fd, int argc, char *argv[])
1337 return RESULT_SHOWUSAGE;
1339 ast_cli(fd, "AGI Debugging Disabled\n");
1340 return RESULT_SUCCESS;
1343 static int handle_noop(struct ast_channel *chan, AGI *agi, int arg, char *argv[])
1345 fdprintf(agi->fd, "200 result=0\n");
1346 return RESULT_SUCCESS;
1349 static int handle_setmusic(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
1351 if (!strncasecmp(argv[2], "on", 2))
1352 ast_moh_start(chan, argc > 3 ? argv[3] : NULL, NULL);
1353 else if (!strncasecmp(argv[2], "off", 3))
1355 fdprintf(agi->fd, "200 result=0\n");
1356 return RESULT_SUCCESS;
1359 static char usage_setmusic[] =
1360 " Usage: SET MUSIC ON <on|off> <class>\n"
1361 " Enables/Disables the music on hold generator. If <class> is\n"
1362 " not specified, then the default music on hold class will be used.\n"
1363 " Always returns 0.\n";
1365 static char usage_dbput[] =
1366 " Usage: DATABASE PUT <family> <key> <value>\n"
1367 " Adds or updates an entry in the Asterisk database for a\n"
1368 " given family, key, and value.\n"
1369 " Returns 1 if successful, 0 otherwise.\n";
1371 static char usage_dbget[] =
1372 " Usage: DATABASE GET <family> <key>\n"
1373 " Retrieves an entry in the Asterisk database for a\n"
1374 " given family and key.\n"
1375 " Returns 0 if <key> is not set. Returns 1 if <key>\n"
1376 " is set and returns the variable in parentheses.\n"
1377 " Example return code: 200 result=1 (testvariable)\n";
1379 static char usage_dbdel[] =
1380 " Usage: DATABASE DEL <family> <key>\n"
1381 " Deletes an entry in the Asterisk database for a\n"
1382 " given family and key.\n"
1383 " Returns 1 if successful, 0 otherwise.\n";
1385 static char usage_dbdeltree[] =
1386 " Usage: DATABASE DELTREE <family> [keytree]\n"
1387 " Deletes a family or specific keytree within a family\n"
1388 " in the Asterisk database.\n"
1389 " Returns 1 if successful, 0 otherwise.\n";
1391 static char usage_verbose[] =
1392 " Usage: VERBOSE <message> <level>\n"
1393 " Sends <message> to the console via verbose message system.\n"
1394 " <level> is the the verbose level (1-4)\n"
1395 " Always returns 1.\n";
1397 static char usage_getvariable[] =
1398 " Usage: GET VARIABLE <variablename>\n"
1399 " Returns 0 if <variablename> is not set. Returns 1 if <variablename>\n"
1400 " is set and returns the variable in parentheses.\n"
1401 " example return code: 200 result=1 (testvariable)\n";
1403 static char usage_getvariablefull[] =
1404 " Usage: GET FULL VARIABLE <variablename> [<channel name>]\n"
1405 " Returns 0 if <variablename> is not set or channel does not exist. Returns 1\n"
1406 "if <variablename> is set and returns the variable in parenthesis. Understands\n"
1407 "complex variable names and builtin variables, unlike GET VARIABLE.\n"
1408 " example return code: 200 result=1 (testvariable)\n";
1410 static char usage_setvariable[] =
1411 " Usage: SET VARIABLE <variablename> <value>\n";
1413 static char usage_channelstatus[] =
1414 " Usage: CHANNEL STATUS [<channelname>]\n"
1415 " Returns the status of the specified channel.\n"
1416 " If no channel name is given the returns the status of the\n"
1417 " current channel. Return values:\n"
1418 " 0 Channel is down and available\n"
1419 " 1 Channel is down, but reserved\n"
1420 " 2 Channel is off hook\n"
1421 " 3 Digits (or equivalent) have been dialed\n"
1422 " 4 Line is ringing\n"
1423 " 5 Remote end is ringing\n"
1425 " 7 Line is busy\n";
1427 static char usage_setcallerid[] =
1428 " Usage: SET CALLERID <number>\n"
1429 " Changes the callerid of the current channel.\n";
1431 static char usage_exec[] =
1432 " Usage: EXEC <application> <options>\n"
1433 " Executes <application> with given <options>.\n"
1434 " Returns whatever the application returns, or -2 on failure to find application\n";
1436 static char usage_hangup[] =
1437 " Usage: HANGUP [<channelname>]\n"
1438 " Hangs up the specified channel.\n"
1439 " If no channel name is given, hangs up the current channel\n";
1441 static char usage_answer[] =
1443 " Answers channel if not already in answer state. Returns -1 on\n"
1444 " channel failure, or 0 if successful.\n";
1446 static char usage_waitfordigit[] =
1447 " Usage: WAIT FOR DIGIT <timeout>\n"
1448 " Waits up to 'timeout' milliseconds for channel to receive a DTMF digit.\n"
1449 " Returns -1 on channel failure, 0 if no digit is received in the timeout, or\n"
1450 " the numerical value of the ascii of the digit if one is received. Use -1\n"
1451 " for the timeout value if you desire the call to block indefinitely.\n";
1453 static char usage_sendtext[] =
1454 " Usage: SEND TEXT \"<text to send>\"\n"
1455 " Sends the given text on a channel. Most channels do not support the\n"
1456 " transmission of text. Returns 0 if text is sent, or if the channel does not\n"
1457 " support text transmission. Returns -1 only on error/hangup. Text\n"
1458 " consisting of greater than one word should be placed in quotes since the\n"
1459 " command only accepts a single argument.\n";
1461 static char usage_recvchar[] =
1462 " Usage: RECEIVE CHAR <timeout>\n"
1463 " Receives a character of text on a channel. Specify timeout to be the\n"
1464 " maximum time to wait for input in milliseconds, or 0 for infinite. Most channels\n"
1465 " do not support the reception of text. Returns the decimal value of the character\n"
1466 " if one is received, or 0 if the channel does not support text reception. Returns\n"
1467 " -1 only on error/hangup.\n";
1469 static char usage_recvtext[] =
1470 " Usage: RECEIVE TEXT <timeout>\n"
1471 " Receives a string of text on a channel. Specify timeout to be the\n"
1472 " maximum time to wait for input in milliseconds, or 0 for infinite. Most channels\n"
1473 " do not support the reception of text. Returns -1 for failure or 1 for success, and the string in parentheses.\n";
1475 static char usage_tddmode[] =
1476 " Usage: TDD MODE <on|off>\n"
1477 " Enable/Disable TDD transmission/reception on a channel. Returns 1 if\n"
1478 " successful, or 0 if channel is not TDD-capable.\n";
1480 static char usage_sendimage[] =
1481 " Usage: SEND IMAGE <image>\n"
1482 " Sends the given image on a channel. Most channels do not support the\n"
1483 " transmission of images. Returns 0 if image is sent, or if the channel does not\n"
1484 " support image transmission. Returns -1 only on error/hangup. Image names\n"
1485 " should not include extensions.\n";
1487 static char usage_streamfile[] =
1488 " Usage: STREAM FILE <filename> <escape digits> [sample offset]\n"
1489 " Send the given file, allowing playback to be interrupted by the given\n"
1490 " digits, if any. Use double quotes for the digits if you wish none to be\n"
1491 " permitted. If sample offset is provided then the audio will seek to sample\n"
1492 " offset before play starts. Returns 0 if playback completes without a digit\n"
1493 " being pressed, or the ASCII numerical value of the digit if one was pressed,\n"
1494 " or -1 on error or if the channel was disconnected. Remember, the file\n"
1495 " extension must not be included in the filename.\n";
1497 static char usage_controlstreamfile[] =
1498 " Usage: CONTROL STREAM FILE <filename> <escape digits> [skipms] [ffchar] [rewchr] [pausechr]\n"
1499 " Send the given file, allowing playback to be controled by the given\n"
1500 " digits, if any. Use double quotes for the digits if you wish none to be\n"
1501 " permitted. Returns 0 if playback completes without a digit\n"
1502 " being pressed, or the ASCII numerical value of the digit if one was pressed,\n"
1503 " or -1 on error or if the channel was disconnected. Remember, the file\n"
1504 " extension must not be included in the filename.\n\n"
1505 " Note: ffchar and rewchar default to * and # respectively.\n";
1507 static char usage_getoption[] =
1508 " Usage: GET OPTION <filename> <escape_digits> [timeout]\n"
1509 " Behaves similar to STREAM FILE but used with a timeout option.\n";
1511 static char usage_saynumber[] =
1512 " Usage: SAY NUMBER <number> <escape digits> [gender]\n"
1513 " Say a given number, returning early if any of the given DTMF digits\n"
1514 " are received on the channel. Returns 0 if playback completes without a digit\n"
1515 " being pressed, or the ASCII numerical value of the digit if one was pressed or\n"
1516 " -1 on error/hangup.\n";
1518 static char usage_saydigits[] =
1519 " Usage: SAY DIGITS <number> <escape digits>\n"
1520 " Say a given digit string, returning early if any of the given DTMF digits\n"
1521 " are received on the channel. Returns 0 if playback completes without a digit\n"
1522 " being pressed, or the ASCII numerical value of the digit if one was pressed or\n"
1523 " -1 on error/hangup.\n";
1525 static char usage_sayalpha[] =
1526 " Usage: SAY ALPHA <number> <escape digits>\n"
1527 " Say a given character string, returning early if any of the given DTMF digits\n"
1528 " are received on the channel. Returns 0 if playback completes without a digit\n"
1529 " being pressed, or the ASCII numerical value of the digit if one was pressed or\n"
1530 " -1 on error/hangup.\n";
1532 static char usage_saydate[] =
1533 " Usage: SAY DATE <date> <escape digits>\n"
1534 " Say a given date, returning early if any of the given DTMF digits are\n"
1535 " received on the channel. <date> is number of seconds elapsed since 00:00:00\n"
1536 " on January 1, 1970, Coordinated Universal Time (UTC). Returns 0 if playback\n"
1537 " completes without a digit being pressed, or the ASCII numerical value of the\n"
1538 " digit if one was pressed or -1 on error/hangup.\n";
1540 static char usage_saytime[] =
1541 " Usage: SAY TIME <time> <escape digits>\n"
1542 " Say a given time, returning early if any of the given DTMF digits are\n"
1543 " received on the channel. <time> is number of seconds elapsed since 00:00:00\n"
1544 " on January 1, 1970, Coordinated Universal Time (UTC). Returns 0 if playback\n"
1545 " completes without a digit being pressed, or the ASCII numerical value of the\n"
1546 " digit if one was pressed or -1 on error/hangup.\n";
1548 static char usage_saydatetime[] =
1549 " Usage: SAY DATETIME <time> <escape digits> [format] [timezone]\n"
1550 " Say a given time, returning early if any of the given DTMF digits are\n"
1551 " received on the channel. <time> is number of seconds elapsed since 00:00:00\n"
1552 " on January 1, 1970, Coordinated Universal Time (UTC). [format] is the format\n"
1553 " the time should be said in. See voicemail.conf (defaults to \"ABdY\n"
1554 " 'digits/at' IMp\"). Acceptable values for [timezone] can be found in\n"
1555 " /usr/share/zoneinfo. Defaults to machine default. Returns 0 if playback\n"
1556 " completes without a digit being pressed, or the ASCII numerical value of the\n"
1557 " digit if one was pressed or -1 on error/hangup.\n";
1559 static char usage_sayphonetic[] =
1560 " Usage: SAY PHONETIC <string> <escape digits>\n"
1561 " Say a given character string with phonetics, returning early if any of the\n"
1562 " given DTMF digits are received on the channel. Returns 0 if playback\n"
1563 " completes without a digit pressed, the ASCII numerical value of the digit\n"
1564 " if one was pressed, or -1 on error/hangup.\n";
1566 static char usage_getdata[] =
1567 " Usage: GET DATA <file to be streamed> [timeout] [max digits]\n"
1568 " Stream the given file, and recieve DTMF data. Returns the digits received\n"
1569 "from the channel at the other end.\n";
1571 static char usage_setcontext[] =
1572 " Usage: SET CONTEXT <desired context>\n"
1573 " Sets the context for continuation upon exiting the application.\n";
1575 static char usage_setextension[] =
1576 " Usage: SET EXTENSION <new extension>\n"
1577 " Changes the extension for continuation upon exiting the application.\n";
1579 static char usage_setpriority[] =
1580 " Usage: SET PRIORITY <priority>\n"
1581 " Changes the priority for continuation upon exiting the application.\n"
1582 " The priority must be a valid priority or label.\n";
1584 static char usage_recordfile[] =
1585 " Usage: RECORD FILE <filename> <format> <escape digits> <timeout> \\\n"
1586 " [offset samples] [BEEP] [s=silence]\n"
1587 " Record to a file until a given dtmf digit in the sequence is received\n"
1588 " Returns -1 on hangup or error. The format will specify what kind of file\n"
1589 " will be recorded. The timeout is the maximum record time in milliseconds, or\n"
1590 " -1 for no timeout. \"Offset samples\" is optional, and, if provided, will seek\n"
1591 " to the offset without exceeding the end of the file. \"silence\" is the number\n"
1592 " of seconds of silence allowed before the function returns despite the\n"
1593 " lack of dtmf digits or reaching timeout. Silence value must be\n"
1594 " preceeded by \"s=\" and is also optional.\n";
1596 static char usage_autohangup[] =
1597 " Usage: SET AUTOHANGUP <time>\n"
1598 " Cause the channel to automatically hangup at <time> seconds in the\n"
1599 " future. Of course it can be hungup before then as well. Setting to 0 will\n"
1600 " cause the autohangup feature to be disabled on this channel.\n";
1602 static char usage_noop[] =
1606 static agi_command commands[MAX_COMMANDS] = {
1607 { { "answer", NULL }, handle_answer, "Answer channel", usage_answer },
1608 { { "channel", "status", NULL }, handle_channelstatus, "Returns status of the connected channel", usage_channelstatus },
1609 { { "database", "del", NULL }, handle_dbdel, "Removes database key/value", usage_dbdel },
1610 { { "database", "deltree", NULL }, handle_dbdeltree, "Removes database keytree/value", usage_dbdeltree },
1611 { { "database", "get", NULL }, handle_dbget, "Gets database value", usage_dbget },
1612 { { "database", "put", NULL }, handle_dbput, "Adds/updates database value", usage_dbput },
1613 { { "exec", NULL }, handle_exec, "Executes a given Application", usage_exec },
1614 { { "get", "data", NULL }, handle_getdata, "Prompts for DTMF on a channel", usage_getdata },
1615 { { "get", "full", "variable", NULL }, handle_getvariablefull, "Evaluates a channel expression", usage_getvariablefull },
1616 { { "get", "option", NULL }, handle_getoption, "Stream file, prompt for DTMF, with timeout", usage_getoption },
1617 { { "get", "variable", NULL }, handle_getvariable, "Gets a channel variable", usage_getvariable },
1618 { { "hangup", NULL }, handle_hangup, "Hangup the current channel", usage_hangup },
1619 { { "noop", NULL }, handle_noop, "Does nothing", usage_noop },
1620 { { "receive", "char", NULL }, handle_recvchar, "Receives one character from channels supporting it", usage_recvchar },
1621 { { "receive", "text", NULL }, handle_recvtext, "Receives text from channels supporting it", usage_recvtext },
1622 { { "record", "file", NULL }, handle_recordfile, "Records to a given file", usage_recordfile },
1623 { { "say", "alpha", NULL }, handle_sayalpha, "Says a given character string", usage_sayalpha },
1624 { { "say", "digits", NULL }, handle_saydigits, "Says a given digit string", usage_saydigits },
1625 { { "say", "number", NULL }, handle_saynumber, "Says a given number", usage_saynumber },
1626 { { "say", "phonetic", NULL }, handle_sayphonetic, "Says a given character string with phonetics", usage_sayphonetic },
1627 { { "say", "date", NULL }, handle_saydate, "Says a given date", usage_saydate },
1628 { { "say", "time", NULL }, handle_saytime, "Says a given time", usage_saytime },
1629 { { "say", "datetime", NULL }, handle_saydatetime, "Says a given time as specfied by the format given", usage_saydatetime },
1630 { { "send", "image", NULL }, handle_sendimage, "Sends images to channels supporting it", usage_sendimage },
1631 { { "send", "text", NULL }, handle_sendtext, "Sends text to channels supporting it", usage_sendtext },
1632 { { "set", "autohangup", NULL }, handle_autohangup, "Autohangup channel in some time", usage_autohangup },
1633 { { "set", "callerid", NULL }, handle_setcallerid, "Sets callerid for the current channel", usage_setcallerid },
1634 { { "set", "context", NULL }, handle_setcontext, "Sets channel context", usage_setcontext },
1635 { { "set", "extension", NULL }, handle_setextension, "Changes channel extension", usage_setextension },
1636 { { "set", "music", NULL }, handle_setmusic, "Enable/Disable Music on hold generator", usage_setmusic },
1637 { { "set", "priority", NULL }, handle_setpriority, "Set channel dialplan priority", usage_setpriority },
1638 { { "set", "variable", NULL }, handle_setvariable, "Sets a channel variable", usage_setvariable },
1639 { { "stream", "file", NULL }, handle_streamfile, "Sends audio file on channel", usage_streamfile },
1640 { { "control", "stream", "file", NULL }, handle_controlstreamfile, "Sends audio file on channel and allows the listner to control the stream", usage_controlstreamfile },
1641 { { "tdd", "mode", NULL }, handle_tddmode, "Toggles TDD mode (for the deaf)", usage_tddmode },
1642 { { "verbose", NULL }, handle_verbose, "Logs a message to the asterisk verbose log", usage_verbose },
1643 { { "wait", "for", "digit", NULL }, handle_waitfordigit, "Waits for a digit to be pressed", usage_waitfordigit },
1646 static int help_workhorse(int fd, char *match[])
1651 struct agi_command *e;
1653 ast_join(matchstr, sizeof(matchstr), match);
1654 for (x=0;x<sizeof(commands)/sizeof(commands[0]);x++) {
1658 /* Hide commands that start with '_' */
1659 if ((e->cmda[0])[0] == '_')
1661 ast_join(fullcmd, sizeof(fullcmd), e->cmda);
1662 if (match && strncasecmp(matchstr, fullcmd, strlen(matchstr)))
1664 ast_cli(fd, "%20.20s %s\n", fullcmd, e->summary);
1669 int ast_agi_register(agi_command *agi)
1672 for (x=0; x<MAX_COMMANDS - 1; x++) {
1673 if (commands[x].cmda[0] == agi->cmda[0]) {
1674 ast_log(LOG_WARNING, "Command already registered!\n");
1678 for (x=0; x<MAX_COMMANDS - 1; x++) {
1679 if (!commands[x].cmda[0]) {
1684 ast_log(LOG_WARNING, "No more room for new commands!\n");
1688 void ast_agi_unregister(agi_command *agi)
1691 for (x=0; x<MAX_COMMANDS - 1; x++) {
1692 if (commands[x].cmda[0] == agi->cmda[0]) {
1693 memset(&commands[x], 0, sizeof(agi_command));
1698 static agi_command *find_command(char *cmds[], int exact)
1704 for (x=0; x < sizeof(commands) / sizeof(commands[0]); x++) {
1705 if (!commands[x].cmda[0])
1707 /* start optimistic */
1709 for (y=0; match && cmds[y]; y++) {
1710 /* If there are no more words in the command (and we're looking for
1711 an exact match) or there is a difference between the two words,
1712 then this is not a match */
1713 if (!commands[x].cmda[y] && !exact)
1715 /* don't segfault if the next part of a command doesn't exist */
1716 if (!commands[x].cmda[y])
1718 if (strcasecmp(commands[x].cmda[y], cmds[y]))
1721 /* If more words are needed to complete the command then this is not
1722 a candidate (unless we're looking for a really inexact answer */
1723 if ((exact > -1) && commands[x].cmda[y])
1726 return &commands[x];
1732 static int parse_args(char *s, int *max, char *argv[])
1744 /* If it's escaped, put a literal quote */
1749 if (quoted && whitespace) {
1750 /* If we're starting a quote, coming off white space start a new word, too */
1758 if (!quoted && !escaped) {
1759 /* If we're not quoted, mark this as whitespace, and
1760 end the previous argument */
1764 /* Otherwise, just treat it as anything else */
1768 /* If we're escaped, print a literal, otherwise enable escaping */
1778 if (x >= MAX_ARGS -1) {
1779 ast_log(LOG_WARNING, "Too many arguments, truncating\n");
1782 /* Coming off of whitespace, start the next argument */
1791 /* Null terminate */
1798 static int agi_handle_command(struct ast_channel *chan, AGI *agi, char *buf)
1800 char *argv[MAX_ARGS];
1801 int argc = MAX_ARGS;
1805 parse_args(buf, &argc, argv);
1806 c = find_command(argv, 0);
1808 res = c->handler(chan, agi, argc, argv);
1810 case RESULT_SHOWUSAGE:
1811 fdprintf(agi->fd, "520-Invalid command syntax. Proper usage follows:\n");
1812 fdprintf(agi->fd, c->usage);
1813 fdprintf(agi->fd, "520 End of proper usage.\n");
1815 case AST_PBX_KEEPALIVE:
1816 /* We've been asked to keep alive, so do so */
1817 return AST_PBX_KEEPALIVE;
1819 case RESULT_FAILURE:
1820 /* They've already given the failure. We've been hung up on so handle this
1825 fdprintf(agi->fd, "510 Invalid or unknown command\n");
1830 static enum agi_result run_agi(struct ast_channel *chan, char *request, AGI *agi, int pid, int *status, int dead, int argc, char *argv[])
1832 struct ast_channel *c;
1835 enum agi_result returnstatus = AGI_RESULT_SUCCESS;
1836 struct ast_frame *f;
1839 /* how many times we'll retry if ast_waitfor_nandfs will return without either
1840 channel or file descriptor in case select is interrupted by a system call (EINTR) */
1843 if (!(readf = fdopen(agi->ctrl, "r"))) {
1844 ast_log(LOG_WARNING, "Unable to fdopen file descriptor\n");
1848 return AGI_RESULT_FAILURE;
1851 setup_env(chan, request, agi->fd, (agi->audio > -1), argc, argv);
1854 c = ast_waitfor_nandfds(&chan, dead ? 0 : 1, &agi->ctrl, 1, NULL, &outfd, &ms);
1857 /* Idle the channel until we get a command */
1860 ast_debug(1, "%s hungup\n", chan->name);
1861 returnstatus = AGI_RESULT_HANGUP;
1864 /* If it's voice, write it to the audio pipe */
1865 if ((agi->audio > -1) && (f->frametype == AST_FRAME_VOICE)) {
1866 /* Write, ignoring errors */
1867 write(agi->audio, f->data, f->datalen);
1871 } else if (outfd > -1) {
1873 if (!fgets(buf, sizeof(buf), readf)) {
1874 /* Program terminated */
1877 if (option_verbose > 2)
1878 ast_verbose(VERBOSE_PREFIX_3 "AGI Script %s completed, returning %d\n", request, returnstatus);
1880 waitpid(pid, status, 0);
1881 /* No need to kill the pid anymore, since they closed us */
1885 /* get rid of trailing newline, if any */
1886 if (*buf && buf[strlen(buf) - 1] == '\n')
1887 buf[strlen(buf) - 1] = 0;
1889 ast_verbose("AGI Rx << %s\n", buf);
1890 returnstatus |= agi_handle_command(chan, agi, buf);
1891 /* If the handle_command returns -1, we need to stop */
1892 if ((returnstatus < 0) || (returnstatus == AST_PBX_KEEPALIVE)) {
1897 ast_log(LOG_WARNING, "No channel, no fd?\n");
1898 returnstatus = AGI_RESULT_FAILURE;
1903 /* Notify process */
1905 const char *sighup = pbx_builtin_getvar_helper(chan, "AGISIGHUP");
1906 if (ast_strlen_zero(sighup) || !ast_false(sighup)) {
1907 if (kill(pid, SIGHUP))
1908 ast_log(LOG_WARNING, "unable to send SIGHUP to AGI process %d: %s\n", pid, strerror(errno));
1912 return returnstatus;
1915 static int handle_showagi(int fd, int argc, char *argv[])
1917 struct agi_command *e;
1920 return RESULT_SHOWUSAGE;
1922 e = find_command(argv + 2, 1);
1924 ast_cli(fd, e->usage);
1926 if (find_command(argv + 2, -1)) {
1927 return help_workhorse(fd, argv + 1);
1929 ast_join(fullcmd, sizeof(fullcmd), argv+1);
1930 ast_cli(fd, "No such command '%s'.\n", fullcmd);
1934 return help_workhorse(fd, NULL);
1936 return RESULT_SUCCESS;
1939 /*! \brief Convert string to use HTML escaped characters
1940 \note Maybe this should be a generic function?
1942 static void write_html_escaped(FILE *htmlfile, char *str)
1949 fprintf(htmlfile, "%s", "<");
1952 fprintf(htmlfile, "%s", ">");
1955 fprintf(htmlfile, "%s", "&");
1958 fprintf(htmlfile, "%s", """);
1961 fprintf(htmlfile, "%c", *cur);
1970 static int handle_agidumphtml(int fd, int argc, char *argv[])
1972 struct agi_command *e;
1978 return RESULT_SHOWUSAGE;
1980 if (!(htmlfile = fopen(argv[2], "wt"))) {
1981 ast_cli(fd, "Could not create file '%s'\n", argv[2]);
1982 return RESULT_SHOWUSAGE;
1985 fprintf(htmlfile, "<HTML>\n<HEAD>\n<TITLE>AGI Commands</TITLE>\n</HEAD>\n");
1986 fprintf(htmlfile, "<BODY>\n<CENTER><B><H1>AGI Commands</H1></B></CENTER>\n\n");
1989 fprintf(htmlfile, "<TABLE BORDER=\"0\" CELLSPACING=\"10\">\n");
1991 for (x=0;x<sizeof(commands)/sizeof(commands[0]);x++) {
1992 char *stringp, *tempstr;
1995 if (!e->cmda[0]) /* end ? */
1997 /* Hide commands that start with '_' */
1998 if ((e->cmda[0])[0] == '_')
2000 ast_join(fullcmd, sizeof(fullcmd), e->cmda);
2002 fprintf(htmlfile, "<TR><TD><TABLE BORDER=\"1\" CELLPADDING=\"5\" WIDTH=\"100%%\">\n");
2003 fprintf(htmlfile, "<TR><TH ALIGN=\"CENTER\"><B>%s - %s</B></TH></TR>\n", fullcmd,e->summary);
2006 tempstr = strsep(&stringp, "\n");
2008 fprintf(htmlfile, "<TR><TD ALIGN=\"CENTER\">");
2009 write_html_escaped(htmlfile, tempstr);
2010 fprintf(htmlfile, "</TD></TR>\n");
2013 fprintf(htmlfile, "<TR><TD ALIGN=\"CENTER\">\n");
2014 while ((tempstr = strsep(&stringp, "\n")) != NULL) {
2015 write_html_escaped(htmlfile, tempstr);
2016 fprintf(htmlfile, "<BR>\n");
2018 fprintf(htmlfile, "</TD></TR>\n");
2019 fprintf(htmlfile, "</TABLE></TD></TR>\n\n");
2023 fprintf(htmlfile, "</TABLE>\n</BODY>\n</HTML>\n");
2025 ast_cli(fd, "AGI HTML Commands Dumped to: %s\n", argv[2]);
2026 return RESULT_SUCCESS;
2029 static int agi_exec_full(struct ast_channel *chan, void *data, int enhanced, int dead)
2031 enum agi_result res;
2032 struct ast_module_user *u;
2033 char *argv[MAX_ARGS];
2043 if (ast_strlen_zero(data)) {
2044 ast_log(LOG_WARNING, "AGI requires an argument (script)\n");
2047 ast_copy_string(buf, data, sizeof(buf));
2049 memset(&agi, 0, sizeof(agi));
2050 while ((stringp = strsep(&tmp, "|")) && argc < MAX_ARGS-1)
2051 argv[argc++] = stringp;
2054 u = ast_module_user_add(chan);
2056 /* Answer if need be */
2057 if (chan->_state != AST_STATE_UP) {
2058 if (ast_answer(chan)) {
2059 LOCAL_USER_REMOVE(u);
2064 res = launch_script(argv[0], argv, fds, enhanced ? &efd : NULL, &pid);
2065 if (res == AGI_RESULT_SUCCESS) {
2070 res = run_agi(chan, argv[0], &agi, pid, &status, dead, argc, argv);
2071 /* If the fork'd process returns non-zero, set AGISTATUS to FAILURE */
2072 if (res == AGI_RESULT_SUCCESS && status)
2073 res = AGI_RESULT_FAILURE;
2074 if (fds[1] != fds[0])
2078 ast_unreplace_sigchld();
2080 ast_module_user_remove(u);
2083 case AGI_RESULT_SUCCESS:
2084 pbx_builtin_setvar_helper(chan, "AGISTATUS", "SUCCESS");
2086 case AGI_RESULT_FAILURE:
2087 pbx_builtin_setvar_helper(chan, "AGISTATUS", "FAILURE");
2089 case AGI_RESULT_HANGUP:
2090 pbx_builtin_setvar_helper(chan, "AGISTATUS", "HANGUP");
2097 static int agi_exec(struct ast_channel *chan, void *data)
2099 if (chan->_softhangup)
2100 ast_log(LOG_WARNING, "If you want to run AGI on hungup channels you should use DeadAGI!\n");
2101 return agi_exec_full(chan, data, 0, 0);
2104 static int eagi_exec(struct ast_channel *chan, void *data)
2109 if (chan->_softhangup)
2110 ast_log(LOG_WARNING, "If you want to run AGI on hungup channels you should use DeadAGI!\n");
2111 readformat = chan->readformat;
2112 if (ast_set_read_format(chan, AST_FORMAT_SLINEAR)) {
2113 ast_log(LOG_WARNING, "Unable to set channel '%s' to linear mode\n", chan->name);
2116 res = agi_exec_full(chan, data, 1, 0);
2118 if (ast_set_read_format(chan, readformat)) {
2119 ast_log(LOG_WARNING, "Unable to restore channel '%s' to format %s\n", chan->name, ast_getformatname(readformat));
2125 static int deadagi_exec(struct ast_channel *chan, void *data)
2127 return agi_exec_full(chan, data, 0, 1);
2130 static char showagi_help[] =
2131 "Usage: agi show [topic]\n"
2132 " When called with a topic as an argument, displays usage\n"
2133 " information on the given command. If called without a\n"
2134 " topic, it provides a list of AGI commands.\n";
2137 static char dumpagihtml_help[] =
2138 "Usage: agi dumphtml <filename>\n"
2139 " Dumps the agi command list in html format to given filename\n";
2141 static struct ast_cli_entry cli_agi[] = {
2142 { { "agi", "debug", NULL },
2143 agi_do_debug, "Enable AGI debugging",
2146 { { "agi", "debug", "off", NULL },
2147 agi_no_debug, "Disable AGI debugging",
2150 { { "agi", "show", NULL },
2151 handle_showagi, "List AGI commands or specific help",
2154 { { "agi", "dumphtml", NULL },
2155 handle_agidumphtml, "Dumps a list of agi commands in html format",
2159 static int unload_module(void)
2161 ast_module_user_hangup_all();
2162 ast_cli_unregister_multiple(cli_agi, sizeof(cli_agi) / sizeof(struct ast_cli_entry));
2163 ast_unregister_application(eapp);
2164 ast_unregister_application(deadapp);
2165 return ast_unregister_application(app);
2168 static int load_module(void)
2170 ast_cli_register_multiple(cli_agi, sizeof(cli_agi) / sizeof(struct ast_cli_entry));
2171 ast_register_application(deadapp, deadagi_exec, deadsynopsis, descrip);
2172 ast_register_application(eapp, eagi_exec, esynopsis, descrip);
2173 return ast_register_application(app, agi_exec, synopsis, descrip);
2176 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS, "Asterisk Gateway Interface (AGI)",
2177 .load = load_module,
2178 .unload = unload_module,