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 | NOTFOUND | 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
119 static void agi_debug_cli(int fd, char *fmt, ...)
126 res = vasprintf(&stuff, fmt, ap);
129 ast_log(LOG_ERROR, "Out of memory\n");
132 ast_verbose("AGI Tx >> %s\n", stuff);
133 ast_carefulwrite(fd, stuff, strlen(stuff), 100);
138 /* launch_netscript: The fastagi handler.
139 FastAGI defaults to port 4573 */
140 static enum agi_result launch_netscript(char *agiurl, char *argv[], int *fds, int *efd, int *opid)
144 struct pollfd pfds[1];
146 char *c; int port = AGI_PORT;
148 struct sockaddr_in sin;
150 struct ast_hostent ahp;
153 /* agiusl is "agi://host.domain[:port][/script/name]" */
154 host = ast_strdupa(agiurl + 6); /* Remove agi:// */
155 /* Strip off any script name */
156 if ((c = strchr(host, '/'))) {
161 if ((c = strchr(host, ':'))) {
167 ast_log(LOG_WARNING, "AGI URI's don't support Enhanced AGI yet\n");
170 hp = ast_gethostbyname(host, &ahp);
172 ast_log(LOG_WARNING, "Unable to locate host '%s'\n", host);
175 s = socket(AF_INET, SOCK_STREAM, 0);
177 ast_log(LOG_WARNING, "Unable to create socket: %s\n", strerror(errno));
180 flags = fcntl(s, F_GETFL);
182 ast_log(LOG_WARNING, "Fcntl(F_GETFL) failed: %s\n", strerror(errno));
186 if (fcntl(s, F_SETFL, flags | O_NONBLOCK) < 0) {
187 ast_log(LOG_WARNING, "Fnctl(F_SETFL) failed: %s\n", strerror(errno));
191 memset(&sin, 0, sizeof(sin));
192 sin.sin_family = AF_INET;
193 sin.sin_port = htons(port);
194 memcpy(&sin.sin_addr, hp->h_addr, sizeof(sin.sin_addr));
195 if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) && (errno != EINPROGRESS)) {
196 ast_log(LOG_WARNING, "Connect failed with unexpected error: %s\n", strerror(errno));
198 return AGI_RESULT_FAILURE;
202 pfds[0].events = POLLOUT;
203 while ((res = poll(pfds, 1, MAX_AGI_CONNECT)) != 1) {
204 if (errno != EINTR) {
206 ast_log(LOG_WARNING, "FastAGI connection to '%s' timed out after MAX_AGI_CONNECT (%d) milliseconds.\n",
207 agiurl, MAX_AGI_CONNECT);
209 ast_log(LOG_WARNING, "Connect to '%s' failed: %s\n", agiurl, strerror(errno));
211 return AGI_RESULT_FAILURE;
214 /* XXX in theory should check for partial writes... */
215 while (write(s, "agi_network: yes\n", strlen("agi_network: yes\n")) < 0) {
216 if (errno != EINTR) {
217 ast_log(LOG_WARNING, "Connect to '%s' failed: %s\n", agiurl, strerror(errno));
219 return AGI_RESULT_FAILURE;
223 /* If we have a script parameter, relay it to the fastagi server */
224 /* Script parameters take the form of: AGI(agi://my.example.com/?extension=${EXTEN}) */
225 if (!ast_strlen_zero(script))
226 fdprintf(s, "agi_network_script: %s\n", script);
228 ast_debug(4, "Wow, connected!\n");
232 return AGI_RESULT_SUCCESS;
235 static enum agi_result launch_script(char *script, char *argv[], int *fds, int *efd, int *opid)
244 sigset_t signal_set, old_set;
246 if (!strncasecmp(script, "agi://", 6))
247 return launch_netscript(script, argv, fds, efd, opid);
249 if (script[0] != '/') {
250 snprintf(tmp, sizeof(tmp), "%s/%s", ast_config_AST_AGI_DIR, script);
254 /* Before even trying let's see if the file actually exists */
255 if (!ast_fileexists(script, NULL, NULL)) {
256 ast_log(LOG_WARNING, "Failed to execute '%s': File does not exist.\n", script);
257 return AGI_RESULT_NOTFOUND;
261 ast_log(LOG_WARNING, "Unable to create toast pipe: %s\n",strerror(errno));
262 return AGI_RESULT_FAILURE;
265 ast_log(LOG_WARNING, "unable to create fromast pipe: %s\n", strerror(errno));
268 return AGI_RESULT_FAILURE;
272 ast_log(LOG_WARNING, "unable to create audio pipe: %s\n", strerror(errno));
277 return AGI_RESULT_FAILURE;
279 res = fcntl(audio[1], F_GETFL);
281 res = fcntl(audio[1], F_SETFL, res | O_NONBLOCK);
283 ast_log(LOG_WARNING, "unable to set audio pipe parameters: %s\n", strerror(errno));
290 return AGI_RESULT_FAILURE;
294 /* Block SIGHUP during the fork - prevents a race */
295 sigfillset(&signal_set);
296 pthread_sigmask(SIG_BLOCK, &signal_set, &old_set);
299 ast_log(LOG_WARNING, "Failed to fork(): %s\n", strerror(errno));
300 pthread_sigmask(SIG_SETMASK, &old_set, NULL);
301 return AGI_RESULT_FAILURE;
304 /* Pass paths to AGI via environmental variables */
305 setenv("AST_CONFIG_DIR", ast_config_AST_CONFIG_DIR, 1);
306 setenv("AST_CONFIG_FILE", ast_config_AST_CONFIG_FILE, 1);
307 setenv("AST_MODULE_DIR", ast_config_AST_MODULE_DIR, 1);
308 setenv("AST_SPOOL_DIR", ast_config_AST_SPOOL_DIR, 1);
309 setenv("AST_MONITOR_DIR", ast_config_AST_MONITOR_DIR, 1);
310 setenv("AST_VAR_DIR", ast_config_AST_VAR_DIR, 1);
311 setenv("AST_DATA_DIR", ast_config_AST_DATA_DIR, 1);
312 setenv("AST_LOG_DIR", ast_config_AST_LOG_DIR, 1);
313 setenv("AST_AGI_DIR", ast_config_AST_AGI_DIR, 1);
314 setenv("AST_KEY_DIR", ast_config_AST_KEY_DIR, 1);
315 setenv("AST_RUN_DIR", ast_config_AST_RUN_DIR, 1);
317 /* Don't run AGI scripts with realtime priority -- it causes audio stutter */
320 /* Redirect stdin and out, provide enhanced audio channel if desired */
321 dup2(fromast[0], STDIN_FILENO);
322 dup2(toast[1], STDOUT_FILENO);
324 dup2(audio[0], STDERR_FILENO + 1);
326 close(STDERR_FILENO + 1);
329 /* Before we unblock our signals, return our trapped signals back to the defaults */
330 signal(SIGHUP, SIG_DFL);
331 signal(SIGCHLD, SIG_DFL);
332 signal(SIGINT, SIG_DFL);
333 signal(SIGURG, SIG_DFL);
334 signal(SIGTERM, SIG_DFL);
335 signal(SIGPIPE, SIG_DFL);
336 signal(SIGXFSZ, SIG_DFL);
338 /* unblock important signal handlers */
339 if (pthread_sigmask(SIG_UNBLOCK, &signal_set, NULL)) {
340 ast_log(LOG_WARNING, "unable to unblock signals for AGI script: %s\n", strerror(errno));
344 /* Close everything but stdin/out/error */
345 for (x=STDERR_FILENO + 2;x<1024;x++)
349 /* XXX argv should be deprecated in favor of passing agi_argX paramaters */
351 /* Can't use ast_log since FD's are closed */
352 fprintf(stdout, "verbose \"Failed to execute '%s': %s\" 2\n", script, strerror(errno));
356 pthread_sigmask(SIG_SETMASK, &old_set, NULL);
357 if (option_verbose > 2)
358 ast_verbose(VERBOSE_PREFIX_3 "Launched AGI Script %s\n", script);
364 /* close what we're not using in the parent */
372 return AGI_RESULT_SUCCESS;
375 static void setup_env(struct ast_channel *chan, char *request, int fd, int enhanced, int argc, char *argv[])
379 /* Print initial environment, with agi_request always being the first
381 fdprintf(fd, "agi_request: %s\n", request);
382 fdprintf(fd, "agi_channel: %s\n", chan->name);
383 fdprintf(fd, "agi_language: %s\n", chan->language);
384 fdprintf(fd, "agi_type: %s\n", chan->tech->type);
385 fdprintf(fd, "agi_uniqueid: %s\n", chan->uniqueid);
388 fdprintf(fd, "agi_callerid: %s\n", S_OR(chan->cid.cid_num, "unknown"));
389 fdprintf(fd, "agi_calleridname: %s\n", S_OR(chan->cid.cid_name, "unknown"));
390 fdprintf(fd, "agi_callingpres: %d\n", chan->cid.cid_pres);
391 fdprintf(fd, "agi_callingani2: %d\n", chan->cid.cid_ani2);
392 fdprintf(fd, "agi_callington: %d\n", chan->cid.cid_ton);
393 fdprintf(fd, "agi_callingtns: %d\n", chan->cid.cid_tns);
394 fdprintf(fd, "agi_dnid: %s\n", S_OR(chan->cid.cid_dnid, "unknown"));
395 fdprintf(fd, "agi_rdnis: %s\n", S_OR(chan->cid.cid_rdnis, "unknown"));
397 /* Context information */
398 fdprintf(fd, "agi_context: %s\n", chan->context);
399 fdprintf(fd, "agi_extension: %s\n", chan->exten);
400 fdprintf(fd, "agi_priority: %d\n", chan->priority);
401 fdprintf(fd, "agi_enhanced: %s\n", enhanced ? "1.0" : "0.0");
403 /* User information */
404 fdprintf(fd, "agi_accountcode: %s\n", chan->accountcode ? chan->accountcode : "");
406 /* Send any parameters to the fastagi server that have been passed via the agi application */
407 /* Agi application paramaters take the form of: AGI(/path/to/example/script|${EXTEN}) */
408 for(count = 1; count < argc; count++)
409 fdprintf(fd, "agi_arg_%d: %s\n", count, argv[count]);
411 /* End with empty return */
415 static int handle_answer(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
419 if (chan->_state != AST_STATE_UP) {
420 /* Answer the chan */
421 res = ast_answer(chan);
423 fdprintf(agi->fd, "200 result=%d\n", res);
424 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
427 static int handle_waitfordigit(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
432 return RESULT_SHOWUSAGE;
433 if (sscanf(argv[3], "%d", &to) != 1)
434 return RESULT_SHOWUSAGE;
435 res = ast_waitfordigit_full(chan, to, agi->audio, agi->ctrl);
436 fdprintf(agi->fd, "200 result=%d\n", res);
437 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
440 static int handle_sendtext(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
444 return RESULT_SHOWUSAGE;
445 /* At the moment, the parser (perhaps broken) returns with
446 the last argument PLUS the newline at the end of the input
447 buffer. This probably needs to be fixed, but I wont do that
448 because other stuff may break as a result. The right way
449 would probably be to strip off the trailing newline before
450 parsing, then here, add a newline at the end of the string
451 before sending it to ast_sendtext --DUDE */
452 res = ast_sendtext(chan, argv[2]);
453 fdprintf(agi->fd, "200 result=%d\n", res);
454 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
457 static int handle_recvchar(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
461 return RESULT_SHOWUSAGE;
462 res = ast_recvchar(chan,atoi(argv[2]));
464 fdprintf(agi->fd, "200 result=%d (timeout)\n", res);
465 return RESULT_SUCCESS;
468 fdprintf(agi->fd, "200 result=%d\n", res);
469 return RESULT_SUCCESS;
472 fdprintf(agi->fd, "200 result=%d (hangup)\n", res);
473 return RESULT_FAILURE;
477 static int handle_recvtext(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
482 return RESULT_SHOWUSAGE;
483 buf = ast_recvtext(chan,atoi(argv[2]));
485 fdprintf(agi->fd, "200 result=1 (%s)\n", buf);
488 fdprintf(agi->fd, "200 result=-1\n");
490 return RESULT_SUCCESS;
493 static int handle_tddmode(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
497 return RESULT_SHOWUSAGE;
498 if (!strncasecmp(argv[2],"on",2))
502 if (!strncasecmp(argv[2],"mate",4))
504 if (!strncasecmp(argv[2],"tdd",3))
506 res = ast_channel_setoption(chan, AST_OPTION_TDD, &x, sizeof(char), 0);
507 if (res != RESULT_SUCCESS)
508 fdprintf(agi->fd, "200 result=0\n");
510 fdprintf(agi->fd, "200 result=1\n");
511 return RESULT_SUCCESS;
514 static int handle_sendimage(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
518 return RESULT_SHOWUSAGE;
519 res = ast_send_image(chan, argv[2]);
520 if (!ast_check_hangup(chan))
522 fdprintf(agi->fd, "200 result=%d\n", res);
523 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
526 static int handle_controlstreamfile(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
535 if (argc < 5 || argc > 9)
536 return RESULT_SHOWUSAGE;
538 if (!ast_strlen_zero(argv[4]))
543 if ((argc > 5) && (sscanf(argv[5], "%d", &skipms) != 1))
544 return RESULT_SHOWUSAGE;
546 if (argc > 6 && !ast_strlen_zero(argv[6]))
551 if (argc > 7 && !ast_strlen_zero(argv[7]))
556 if (argc > 8 && !ast_strlen_zero(argv[8]))
561 res = ast_control_streamfile(chan, argv[3], fwd, rev, stop, pause, NULL, skipms, NULL);
563 fdprintf(agi->fd, "200 result=%d\n", res);
565 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
568 static int handle_streamfile(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
572 struct ast_filestream *fs;
573 struct ast_filestream *vfs;
574 long sample_offset = 0;
578 if (argc < 4 || argc > 5)
579 return RESULT_SHOWUSAGE;
584 if ((argc > 4) && (sscanf(argv[4], "%ld", &sample_offset) != 1))
585 return RESULT_SHOWUSAGE;
587 fs = ast_openstream(chan, argv[2], chan->language);
590 fdprintf(agi->fd, "200 result=%d endpos=%ld\n", 0, sample_offset);
591 return RESULT_SUCCESS;
593 vfs = ast_openvstream(chan, argv[2], chan->language);
594 ast_debug(vfs && 1, "Ooh, found a video stream, too\n");
596 if (option_verbose > 2)
597 ast_verbose(VERBOSE_PREFIX_3 "Playing '%s' (escape_digits=%s) (sample_offset %ld)\n", argv[2], edigits, sample_offset);
599 ast_seekstream(fs, 0, SEEK_END);
600 max_length = ast_tellstream(fs);
601 ast_seekstream(fs, sample_offset, SEEK_SET);
602 res = ast_applystream(chan, fs);
604 vres = ast_applystream(chan, vfs);
605 res = ast_playstream(fs);
607 vres = ast_playstream(vfs);
610 fdprintf(agi->fd, "200 result=%d endpos=%ld\n", res, sample_offset);
611 return (res >= 0) ? RESULT_SHOWUSAGE : RESULT_FAILURE;
613 res = ast_waitstream_full(chan, argv[3], agi->audio, agi->ctrl);
614 /* this is to check for if ast_waitstream closed the stream, we probably are at
615 * the end of the stream, return that amount, else check for the amount */
616 sample_offset = (chan->stream) ? ast_tellstream(fs) : max_length;
617 ast_stopstream(chan);
619 /* Stop this command, don't print a result line, as there is a new command */
620 return RESULT_SUCCESS;
622 fdprintf(agi->fd, "200 result=%d endpos=%ld\n", res, sample_offset);
623 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
626 /* get option - really similar to the handle_streamfile, but with a timeout */
627 static int handle_getoption(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
631 struct ast_filestream *fs;
632 struct ast_filestream *vfs;
633 long sample_offset = 0;
638 if ( argc < 4 || argc > 5 )
639 return RESULT_SHOWUSAGE;
645 timeout = atoi(argv[4]);
646 else if (chan->pbx->dtimeout) {
647 /* by default dtimeout is set to 5sec */
648 timeout = chan->pbx->dtimeout * 1000; /* in msec */
651 fs = ast_openstream(chan, argv[2], chan->language);
653 fdprintf(agi->fd, "200 result=%d endpos=%ld\n", 0, sample_offset);
654 ast_log(LOG_WARNING, "Unable to open %s\n", argv[2]);
655 return RESULT_SUCCESS;
657 vfs = ast_openvstream(chan, argv[2], chan->language);
658 ast_debug(vfs && 1, "Ooh, found a video stream, too\n");
660 if (option_verbose > 2)
661 ast_verbose(VERBOSE_PREFIX_3 "Playing '%s' (escape_digits=%s) (timeout %d)\n", argv[2], edigits, timeout);
663 ast_seekstream(fs, 0, SEEK_END);
664 max_length = ast_tellstream(fs);
665 ast_seekstream(fs, sample_offset, SEEK_SET);
666 res = ast_applystream(chan, fs);
668 vres = ast_applystream(chan, vfs);
669 res = ast_playstream(fs);
671 vres = ast_playstream(vfs);
673 fdprintf(agi->fd, "200 result=%d endpos=%ld\n", res, sample_offset);
675 return RESULT_SHOWUSAGE;
677 return RESULT_FAILURE;
679 res = ast_waitstream_full(chan, argv[3], agi->audio, agi->ctrl);
680 /* this is to check for if ast_waitstream closed the stream, we probably are at
681 * the end of the stream, return that amount, else check for the amount */
682 sample_offset = (chan->stream)?ast_tellstream(fs):max_length;
683 ast_stopstream(chan);
685 /* Stop this command, don't print a result line, as there is a new command */
686 return RESULT_SUCCESS;
689 /* If the user didnt press a key, wait for digitTimeout*/
691 res = ast_waitfordigit_full(chan, timeout, agi->audio, agi->ctrl);
692 /* Make sure the new result is in the escape digits of the GET OPTION */
693 if ( !strchr(edigits,res) )
697 fdprintf(agi->fd, "200 result=%d endpos=%ld\n", res, sample_offset);
698 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
704 /*--- handle_saynumber: Say number in various language syntaxes ---*/
705 /* While waiting, we're sending a NULL. */
706 static int handle_saynumber(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
710 if (argc < 4 || argc > 5)
711 return RESULT_SHOWUSAGE;
712 if (sscanf(argv[2], "%d", &num) != 1)
713 return RESULT_SHOWUSAGE;
714 res = ast_say_number_full(chan, num, argv[3], chan->language, argc > 4 ? argv[4] : NULL, agi->audio, agi->ctrl);
716 return RESULT_SUCCESS;
717 fdprintf(agi->fd, "200 result=%d\n", res);
718 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
721 static int handle_saydigits(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
727 return RESULT_SHOWUSAGE;
728 if (sscanf(argv[2], "%d", &num) != 1)
729 return RESULT_SHOWUSAGE;
731 res = ast_say_digit_str_full(chan, argv[2], argv[3], chan->language, agi->audio, agi->ctrl);
732 if (res == 1) /* New command */
733 return RESULT_SUCCESS;
734 fdprintf(agi->fd, "200 result=%d\n", res);
735 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
738 static int handle_sayalpha(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
743 return RESULT_SHOWUSAGE;
745 res = ast_say_character_str_full(chan, argv[2], argv[3], chan->language, agi->audio, agi->ctrl);
746 if (res == 1) /* New command */
747 return RESULT_SUCCESS;
748 fdprintf(agi->fd, "200 result=%d\n", res);
749 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
752 static int handle_saydate(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
757 return RESULT_SHOWUSAGE;
758 if (sscanf(argv[2], "%d", &num) != 1)
759 return RESULT_SHOWUSAGE;
760 res = ast_say_date(chan, num, argv[3], chan->language);
762 return RESULT_SUCCESS;
763 fdprintf(agi->fd, "200 result=%d\n", res);
764 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
767 static int handle_saytime(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
772 return RESULT_SHOWUSAGE;
773 if (sscanf(argv[2], "%d", &num) != 1)
774 return RESULT_SHOWUSAGE;
775 res = ast_say_time(chan, num, argv[3], chan->language);
777 return RESULT_SUCCESS;
778 fdprintf(agi->fd, "200 result=%d\n", res);
779 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
782 static int handle_saydatetime(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
786 char *format, *zone=NULL;
789 return RESULT_SHOWUSAGE;
794 /* XXX this doesn't belong here, but in the 'say' module */
795 if (!strcasecmp(chan->language, "de")) {
796 format = "A dBY HMS";
798 format = "ABdY 'digits/at' IMp";
802 if (argc > 5 && !ast_strlen_zero(argv[5]))
805 if (ast_get_time_t(argv[2], &unixtime, 0, NULL))
806 return RESULT_SHOWUSAGE;
808 res = ast_say_date_with_format(chan, unixtime, argv[3], chan->language, format, zone);
810 return RESULT_SUCCESS;
812 fdprintf(agi->fd, "200 result=%d\n", res);
813 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
816 static int handle_sayphonetic(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
821 return RESULT_SHOWUSAGE;
823 res = ast_say_phonetic_str_full(chan, argv[2], argv[3], chan->language, agi->audio, agi->ctrl);
824 if (res == 1) /* New command */
825 return RESULT_SUCCESS;
826 fdprintf(agi->fd, "200 result=%d\n", res);
827 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
830 static int handle_getdata(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
838 return RESULT_SHOWUSAGE;
840 timeout = atoi(argv[3]);
847 res = ast_app_getdata_full(chan, argv[2], data, max, timeout, agi->audio, agi->ctrl);
848 if (res == 2) /* New command */
849 return RESULT_SUCCESS;
851 fdprintf(agi->fd, "200 result=%s (timeout)\n", data);
853 fdprintf(agi->fd, "200 result=-1\n");
855 fdprintf(agi->fd, "200 result=%s\n", data);
856 return RESULT_SUCCESS;
859 static int handle_setcontext(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
863 return RESULT_SHOWUSAGE;
864 ast_copy_string(chan->context, argv[2], sizeof(chan->context));
865 fdprintf(agi->fd, "200 result=0\n");
866 return RESULT_SUCCESS;
869 static int handle_setextension(struct ast_channel *chan, AGI *agi, int argc, char **argv)
872 return RESULT_SHOWUSAGE;
873 ast_copy_string(chan->exten, argv[2], sizeof(chan->exten));
874 fdprintf(agi->fd, "200 result=0\n");
875 return RESULT_SUCCESS;
878 static int handle_setpriority(struct ast_channel *chan, AGI *agi, int argc, char **argv)
882 return RESULT_SHOWUSAGE;
884 if (sscanf(argv[2], "%d", &pri) != 1) {
885 if ((pri = ast_findlabel_extension(chan, chan->context, chan->exten, argv[2], chan->cid.cid_num)) < 1)
886 return RESULT_SHOWUSAGE;
889 ast_explicit_goto(chan, NULL, NULL, pri);
890 fdprintf(agi->fd, "200 result=0\n");
891 return RESULT_SUCCESS;
894 static int handle_recordfile(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
896 struct ast_filestream *fs;
898 struct timeval start;
899 long sample_offset = 0;
903 struct ast_dsp *sildet=NULL; /* silence detector dsp */
904 int totalsilence = 0;
906 int silence = 0; /* amount of silence to allow */
907 int gotsilence = 0; /* did we timeout for silence? */
908 char *silencestr=NULL;
912 /* XXX EAGI FIXME XXX */
915 return RESULT_SHOWUSAGE;
916 if (sscanf(argv[5], "%d", &ms) != 1)
917 return RESULT_SHOWUSAGE;
920 silencestr = strchr(argv[6],'s');
921 if ((argc > 7) && (!silencestr))
922 silencestr = strchr(argv[7],'s');
923 if ((argc > 8) && (!silencestr))
924 silencestr = strchr(argv[8],'s');
927 if (strlen(silencestr) > 2) {
928 if ((silencestr[0] == 's') && (silencestr[1] == '=')) {
932 silence = atoi(silencestr);
940 rfmt = chan->readformat;
941 res = ast_set_read_format(chan, AST_FORMAT_SLINEAR);
943 ast_log(LOG_WARNING, "Unable to set to linear mode, giving up\n");
946 sildet = ast_dsp_new();
948 ast_log(LOG_WARNING, "Unable to create silence detector :(\n");
951 ast_dsp_set_threshold(sildet, 256);
954 /* backward compatibility, if no offset given, arg[6] would have been
955 * caught below and taken to be a beep, else if it is a digit then it is a
957 if ((argc >6) && (sscanf(argv[6], "%ld", &sample_offset) != 1) && (!strchr(argv[6], '=')))
958 res = ast_streamfile(chan, "beep", chan->language);
960 if ((argc > 7) && (!strchr(argv[7], '=')))
961 res = ast_streamfile(chan, "beep", chan->language);
964 res = ast_waitstream(chan, argv[4]);
966 fdprintf(agi->fd, "200 result=%d (randomerror) endpos=%ld\n", res, sample_offset);
968 fs = ast_writefile(argv[2], argv[3], NULL, O_CREAT | O_WRONLY | (sample_offset ? O_APPEND : 0), 0, AST_FILE_MODE);
971 fdprintf(agi->fd, "200 result=%d (writefile)\n", res);
973 ast_dsp_free(sildet);
974 return RESULT_FAILURE;
977 /* Request a video update */
978 ast_indicate(chan, AST_CONTROL_VIDUPDATE);
981 ast_applystream(chan,fs);
982 /* really should have checks */
983 ast_seekstream(fs, sample_offset, SEEK_SET);
987 while ((ms < 0) || ast_tvdiff_ms(ast_tvnow(), start) < ms) {
988 res = ast_waitfor(chan, -1);
991 fdprintf(agi->fd, "200 result=%d (waitfor) endpos=%ld\n", res,sample_offset);
993 ast_dsp_free(sildet);
994 return RESULT_FAILURE;
998 fdprintf(agi->fd, "200 result=%d (hangup) endpos=%ld\n", 0, sample_offset);
1001 ast_dsp_free(sildet);
1002 return RESULT_FAILURE;
1004 switch(f->frametype) {
1005 case AST_FRAME_DTMF:
1006 if (strchr(argv[4], f->subclass)) {
1007 /* This is an interrupting chracter, so rewind to chop off any small
1008 amount of DTMF that may have been recorded
1010 ast_stream_rewind(fs, 200);
1011 ast_truncstream(fs);
1012 sample_offset = ast_tellstream(fs);
1013 fdprintf(agi->fd, "200 result=%d (dtmf) endpos=%ld\n", f->subclass, sample_offset);
1014 ast_closestream(fs);
1017 ast_dsp_free(sildet);
1018 return RESULT_SUCCESS;
1021 case AST_FRAME_VOICE:
1022 ast_writestream(fs, f);
1023 /* this is a safe place to check progress since we know that fs
1024 * is valid after a write, and it will then have our current
1026 sample_offset = ast_tellstream(fs);
1029 ast_dsp_silence(sildet, f, &dspsilence);
1031 totalsilence = dspsilence;
1035 if (totalsilence > silence) {
1036 /* Ended happily with silence */
1042 case AST_FRAME_VIDEO:
1043 ast_writestream(fs, f);
1045 /* Ignore all other frames */
1054 ast_stream_rewind(fs, silence-1000);
1055 ast_truncstream(fs);
1056 sample_offset = ast_tellstream(fs);
1058 fdprintf(agi->fd, "200 result=%d (timeout) endpos=%ld\n", res, sample_offset);
1059 ast_closestream(fs);
1063 res = ast_set_read_format(chan, rfmt);
1065 ast_log(LOG_WARNING, "Unable to restore read format on '%s'\n", chan->name);
1066 ast_dsp_free(sildet);
1068 return RESULT_SUCCESS;
1071 static int handle_autohangup(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
1076 return RESULT_SHOWUSAGE;
1077 if (sscanf(argv[2], "%d", &timeout) != 1)
1078 return RESULT_SHOWUSAGE;
1082 chan->whentohangup = time(NULL) + timeout;
1084 chan->whentohangup = 0;
1085 fdprintf(agi->fd, "200 result=0\n");
1086 return RESULT_SUCCESS;
1089 static int handle_hangup(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1091 struct ast_channel *c;
1093 /* no argument: hangup the current channel */
1094 ast_softhangup(chan,AST_SOFTHANGUP_EXPLICIT);
1095 fdprintf(agi->fd, "200 result=1\n");
1096 return RESULT_SUCCESS;
1097 } else if (argc == 2) {
1098 /* one argument: look for info on the specified channel */
1099 c = ast_get_channel_by_name_locked(argv[1]);
1101 /* we have a matching channel */
1102 ast_softhangup(c,AST_SOFTHANGUP_EXPLICIT);
1103 fdprintf(agi->fd, "200 result=1\n");
1104 ast_channel_unlock(c);
1105 return RESULT_SUCCESS;
1107 /* if we get this far no channel name matched the argument given */
1108 fdprintf(agi->fd, "200 result=-1\n");
1109 return RESULT_SUCCESS;
1111 return RESULT_SHOWUSAGE;
1115 static int handle_exec(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1118 struct ast_app *app;
1121 return RESULT_SHOWUSAGE;
1123 if (option_verbose > 2)
1124 ast_verbose(VERBOSE_PREFIX_3 "AGI Script Executing Application: (%s) Options: (%s)\n", argv[1], argv[2]);
1126 app = pbx_findapp(argv[1]);
1129 res = pbx_exec(chan, app, argv[2]);
1131 ast_log(LOG_WARNING, "Could not find application (%s)\n", argv[1]);
1134 fdprintf(agi->fd, "200 result=%d\n", res);
1139 static int handle_setcallerid(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1142 char *l = NULL, *n = NULL;
1145 ast_copy_string(tmp, argv[2], sizeof(tmp));
1146 ast_callerid_parse(tmp, &n, &l);
1148 ast_shrink_phone_number(l);
1153 ast_set_callerid(chan, l, n, NULL);
1156 fdprintf(agi->fd, "200 result=1\n");
1157 return RESULT_SUCCESS;
1160 static int handle_channelstatus(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1162 struct ast_channel *c;
1164 /* no argument: supply info on the current channel */
1165 fdprintf(agi->fd, "200 result=%d\n", chan->_state);
1166 return RESULT_SUCCESS;
1167 } else if (argc == 3) {
1168 /* one argument: look for info on the specified channel */
1169 c = ast_get_channel_by_name_locked(argv[2]);
1171 fdprintf(agi->fd, "200 result=%d\n", c->_state);
1172 ast_channel_unlock(c);
1173 return RESULT_SUCCESS;
1175 /* if we get this far no channel name matched the argument given */
1176 fdprintf(agi->fd, "200 result=-1\n");
1177 return RESULT_SUCCESS;
1179 return RESULT_SHOWUSAGE;
1183 static int handle_setvariable(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1186 pbx_builtin_setvar_helper(chan, argv[2], argv[3]);
1188 fdprintf(agi->fd, "200 result=1\n");
1189 return RESULT_SUCCESS;
1192 static int handle_getvariable(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1198 return RESULT_SHOWUSAGE;
1200 /* check if we want to execute an ast_custom_function */
1201 if (!ast_strlen_zero(argv[2]) && (argv[2][strlen(argv[2]) - 1] == ')')) {
1202 ret = ast_func_read(chan, argv[2], tempstr, sizeof(tempstr)) ? NULL : tempstr;
1204 pbx_retrieve_variable(chan, argv[2], &ret, tempstr, sizeof(tempstr), NULL);
1208 fdprintf(agi->fd, "200 result=1 (%s)\n", ret);
1210 fdprintf(agi->fd, "200 result=0\n");
1212 return RESULT_SUCCESS;
1215 static int handle_getvariablefull(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1217 char tmp[4096] = "";
1218 struct ast_channel *chan2=NULL;
1220 if ((argc != 4) && (argc != 5))
1221 return RESULT_SHOWUSAGE;
1223 chan2 = ast_get_channel_by_name_locked(argv[4]);
1227 if (chan) { /* XXX isn't this chan2 ? */
1228 pbx_substitute_variables_helper(chan2, argv[3], tmp, sizeof(tmp) - 1);
1229 fdprintf(agi->fd, "200 result=1 (%s)\n", tmp);
1231 fdprintf(agi->fd, "200 result=0\n");
1233 if (chan2 && (chan2 != chan))
1234 ast_channel_unlock(chan2);
1235 return RESULT_SUCCESS;
1238 static int handle_verbose(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1244 return RESULT_SHOWUSAGE;
1247 sscanf(argv[2], "%d", &level);
1251 prefix = VERBOSE_PREFIX_4;
1254 prefix = VERBOSE_PREFIX_3;
1257 prefix = VERBOSE_PREFIX_2;
1261 prefix = VERBOSE_PREFIX_1;
1265 if (level <= option_verbose)
1266 ast_verbose("%s %s: %s\n", prefix, chan->data, argv[1]);
1268 fdprintf(agi->fd, "200 result=1\n");
1270 return RESULT_SUCCESS;
1273 static int handle_dbget(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1279 return RESULT_SHOWUSAGE;
1280 res = ast_db_get(argv[2], argv[3], tmp, sizeof(tmp));
1282 fdprintf(agi->fd, "200 result=0\n");
1284 fdprintf(agi->fd, "200 result=1 (%s)\n", tmp);
1286 return RESULT_SUCCESS;
1289 static int handle_dbput(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1294 return RESULT_SHOWUSAGE;
1295 res = ast_db_put(argv[2], argv[3], argv[4]);
1296 fdprintf(agi->fd, "200 result=%c\n", res ? '0' : '1');
1297 return RESULT_SUCCESS;
1300 static int handle_dbdel(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1305 return RESULT_SHOWUSAGE;
1306 res = ast_db_del(argv[2], argv[3]);
1307 fdprintf(agi->fd, "200 result=%c\n", res ? '0' : '1');
1308 return RESULT_SUCCESS;
1311 static int handle_dbdeltree(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1314 if ((argc < 3) || (argc > 4))
1315 return RESULT_SHOWUSAGE;
1317 res = ast_db_deltree(argv[2], argv[3]);
1319 res = ast_db_deltree(argv[2], NULL);
1321 fdprintf(agi->fd, "200 result=%c\n", res ? '0' : '1');
1322 return RESULT_SUCCESS;
1325 static const char debug_usage[] =
1326 "Usage: agi debug\n"
1327 " Enables dumping of AGI transactions for debugging purposes\n";
1329 static const char no_debug_usage[] =
1330 "Usage: agi debug off\n"
1331 " Disables dumping of AGI transactions for debugging purposes\n";
1333 static int agi_do_debug(int fd, int argc, char *argv[])
1336 return RESULT_SHOWUSAGE;
1338 ast_cli(fd, "AGI Debugging Enabled\n");
1339 return RESULT_SUCCESS;
1342 static int agi_no_debug(int fd, int argc, char *argv[])
1345 return RESULT_SHOWUSAGE;
1347 ast_cli(fd, "AGI Debugging Disabled\n");
1348 return RESULT_SUCCESS;
1351 static int handle_noop(struct ast_channel *chan, AGI *agi, int arg, char *argv[])
1353 fdprintf(agi->fd, "200 result=0\n");
1354 return RESULT_SUCCESS;
1357 static int handle_setmusic(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
1359 if (!strncasecmp(argv[2], "on", 2))
1360 ast_moh_start(chan, argc > 3 ? argv[3] : NULL, NULL);
1361 else if (!strncasecmp(argv[2], "off", 3))
1363 fdprintf(agi->fd, "200 result=0\n");
1364 return RESULT_SUCCESS;
1367 static char usage_setmusic[] =
1368 " Usage: SET MUSIC ON <on|off> <class>\n"
1369 " Enables/Disables the music on hold generator. If <class> is\n"
1370 " not specified, then the default music on hold class will be used.\n"
1371 " Always returns 0.\n";
1373 static char usage_dbput[] =
1374 " Usage: DATABASE PUT <family> <key> <value>\n"
1375 " Adds or updates an entry in the Asterisk database for a\n"
1376 " given family, key, and value.\n"
1377 " Returns 1 if successful, 0 otherwise.\n";
1379 static char usage_dbget[] =
1380 " Usage: DATABASE GET <family> <key>\n"
1381 " Retrieves an entry in the Asterisk database for a\n"
1382 " given family and key.\n"
1383 " Returns 0 if <key> is not set. Returns 1 if <key>\n"
1384 " is set and returns the variable in parentheses.\n"
1385 " Example return code: 200 result=1 (testvariable)\n";
1387 static char usage_dbdel[] =
1388 " Usage: DATABASE DEL <family> <key>\n"
1389 " Deletes an entry in the Asterisk database for a\n"
1390 " given family and key.\n"
1391 " Returns 1 if successful, 0 otherwise.\n";
1393 static char usage_dbdeltree[] =
1394 " Usage: DATABASE DELTREE <family> [keytree]\n"
1395 " Deletes a family or specific keytree within a family\n"
1396 " in the Asterisk database.\n"
1397 " Returns 1 if successful, 0 otherwise.\n";
1399 static char usage_verbose[] =
1400 " Usage: VERBOSE <message> <level>\n"
1401 " Sends <message> to the console via verbose message system.\n"
1402 " <level> is the the verbose level (1-4)\n"
1403 " Always returns 1.\n";
1405 static char usage_getvariable[] =
1406 " Usage: GET VARIABLE <variablename>\n"
1407 " Returns 0 if <variablename> is not set. Returns 1 if <variablename>\n"
1408 " is set and returns the variable in parentheses.\n"
1409 " example return code: 200 result=1 (testvariable)\n";
1411 static char usage_getvariablefull[] =
1412 " Usage: GET FULL VARIABLE <variablename> [<channel name>]\n"
1413 " Returns 0 if <variablename> is not set or channel does not exist. Returns 1\n"
1414 "if <variablename> is set and returns the variable in parenthesis. Understands\n"
1415 "complex variable names and builtin variables, unlike GET VARIABLE.\n"
1416 " example return code: 200 result=1 (testvariable)\n";
1418 static char usage_setvariable[] =
1419 " Usage: SET VARIABLE <variablename> <value>\n";
1421 static char usage_channelstatus[] =
1422 " Usage: CHANNEL STATUS [<channelname>]\n"
1423 " Returns the status of the specified channel.\n"
1424 " If no channel name is given the returns the status of the\n"
1425 " current channel. Return values:\n"
1426 " 0 Channel is down and available\n"
1427 " 1 Channel is down, but reserved\n"
1428 " 2 Channel is off hook\n"
1429 " 3 Digits (or equivalent) have been dialed\n"
1430 " 4 Line is ringing\n"
1431 " 5 Remote end is ringing\n"
1433 " 7 Line is busy\n";
1435 static char usage_setcallerid[] =
1436 " Usage: SET CALLERID <number>\n"
1437 " Changes the callerid of the current channel.\n";
1439 static char usage_exec[] =
1440 " Usage: EXEC <application> <options>\n"
1441 " Executes <application> with given <options>.\n"
1442 " Returns whatever the application returns, or -2 on failure to find application\n";
1444 static char usage_hangup[] =
1445 " Usage: HANGUP [<channelname>]\n"
1446 " Hangs up the specified channel.\n"
1447 " If no channel name is given, hangs up the current channel\n";
1449 static char usage_answer[] =
1451 " Answers channel if not already in answer state. Returns -1 on\n"
1452 " channel failure, or 0 if successful.\n";
1454 static char usage_waitfordigit[] =
1455 " Usage: WAIT FOR DIGIT <timeout>\n"
1456 " Waits up to 'timeout' milliseconds for channel to receive a DTMF digit.\n"
1457 " Returns -1 on channel failure, 0 if no digit is received in the timeout, or\n"
1458 " the numerical value of the ascii of the digit if one is received. Use -1\n"
1459 " for the timeout value if you desire the call to block indefinitely.\n";
1461 static char usage_sendtext[] =
1462 " Usage: SEND TEXT \"<text to send>\"\n"
1463 " Sends the given text on a channel. Most channels do not support the\n"
1464 " transmission of text. Returns 0 if text is sent, or if the channel does not\n"
1465 " support text transmission. Returns -1 only on error/hangup. Text\n"
1466 " consisting of greater than one word should be placed in quotes since the\n"
1467 " command only accepts a single argument.\n";
1469 static char usage_recvchar[] =
1470 " Usage: RECEIVE CHAR <timeout>\n"
1471 " Receives a character 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 the decimal value of the character\n"
1474 " if one is received, or 0 if the channel does not support text reception. Returns\n"
1475 " -1 only on error/hangup.\n";
1477 static char usage_recvtext[] =
1478 " Usage: RECEIVE TEXT <timeout>\n"
1479 " Receives a string of text on a channel. Specify timeout to be the\n"
1480 " maximum time to wait for input in milliseconds, or 0 for infinite. Most channels\n"
1481 " do not support the reception of text. Returns -1 for failure or 1 for success, and the string in parentheses.\n";
1483 static char usage_tddmode[] =
1484 " Usage: TDD MODE <on|off>\n"
1485 " Enable/Disable TDD transmission/reception on a channel. Returns 1 if\n"
1486 " successful, or 0 if channel is not TDD-capable.\n";
1488 static char usage_sendimage[] =
1489 " Usage: SEND IMAGE <image>\n"
1490 " Sends the given image on a channel. Most channels do not support the\n"
1491 " transmission of images. Returns 0 if image is sent, or if the channel does not\n"
1492 " support image transmission. Returns -1 only on error/hangup. Image names\n"
1493 " should not include extensions.\n";
1495 static char usage_streamfile[] =
1496 " Usage: STREAM FILE <filename> <escape digits> [sample offset]\n"
1497 " Send the given file, allowing playback to be interrupted by the given\n"
1498 " digits, if any. Use double quotes for the digits if you wish none to be\n"
1499 " permitted. If sample offset is provided then the audio will seek to sample\n"
1500 " offset before play starts. Returns 0 if playback completes without a digit\n"
1501 " being pressed, or the ASCII numerical value of the digit if one was pressed,\n"
1502 " or -1 on error or if the channel was disconnected. Remember, the file\n"
1503 " extension must not be included in the filename.\n";
1505 static char usage_controlstreamfile[] =
1506 " Usage: CONTROL STREAM FILE <filename> <escape digits> [skipms] [ffchar] [rewchr] [pausechr]\n"
1507 " Send the given file, allowing playback to be controled by the given\n"
1508 " digits, if any. Use double quotes for the digits if you wish none to be\n"
1509 " permitted. Returns 0 if playback completes without a digit\n"
1510 " being pressed, or the ASCII numerical value of the digit if one was pressed,\n"
1511 " or -1 on error or if the channel was disconnected. Remember, the file\n"
1512 " extension must not be included in the filename.\n\n"
1513 " Note: ffchar and rewchar default to * and # respectively.\n";
1515 static char usage_getoption[] =
1516 " Usage: GET OPTION <filename> <escape_digits> [timeout]\n"
1517 " Behaves similar to STREAM FILE but used with a timeout option.\n";
1519 static char usage_saynumber[] =
1520 " Usage: SAY NUMBER <number> <escape digits> [gender]\n"
1521 " Say a given number, returning early if any of the given DTMF digits\n"
1522 " are received on the channel. Returns 0 if playback completes without a digit\n"
1523 " being pressed, or the ASCII numerical value of the digit if one was pressed or\n"
1524 " -1 on error/hangup.\n";
1526 static char usage_saydigits[] =
1527 " Usage: SAY DIGITS <number> <escape digits>\n"
1528 " Say a given digit string, returning early if any of the given DTMF digits\n"
1529 " are received on the channel. Returns 0 if playback completes without a digit\n"
1530 " being pressed, or the ASCII numerical value of the digit if one was pressed or\n"
1531 " -1 on error/hangup.\n";
1533 static char usage_sayalpha[] =
1534 " Usage: SAY ALPHA <number> <escape digits>\n"
1535 " Say a given character string, returning early if any of the given DTMF digits\n"
1536 " are received on the channel. Returns 0 if playback completes without a digit\n"
1537 " being pressed, or the ASCII numerical value of the digit if one was pressed or\n"
1538 " -1 on error/hangup.\n";
1540 static char usage_saydate[] =
1541 " Usage: SAY DATE <date> <escape digits>\n"
1542 " Say a given date, returning early if any of the given DTMF digits are\n"
1543 " received on the channel. <date> 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_saytime[] =
1549 " Usage: SAY TIME <time> <escape digits>\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). Returns 0 if playback\n"
1553 " completes without a digit being pressed, or the ASCII numerical value of the\n"
1554 " digit if one was pressed or -1 on error/hangup.\n";
1556 static char usage_saydatetime[] =
1557 " Usage: SAY DATETIME <time> <escape digits> [format] [timezone]\n"
1558 " Say a given time, returning early if any of the given DTMF digits are\n"
1559 " received on the channel. <time> is number of seconds elapsed since 00:00:00\n"
1560 " on January 1, 1970, Coordinated Universal Time (UTC). [format] is the format\n"
1561 " the time should be said in. See voicemail.conf (defaults to \"ABdY\n"
1562 " 'digits/at' IMp\"). Acceptable values for [timezone] can be found in\n"
1563 " /usr/share/zoneinfo. Defaults to machine default. Returns 0 if playback\n"
1564 " completes without a digit being pressed, or the ASCII numerical value of the\n"
1565 " digit if one was pressed or -1 on error/hangup.\n";
1567 static char usage_sayphonetic[] =
1568 " Usage: SAY PHONETIC <string> <escape digits>\n"
1569 " Say a given character string with phonetics, returning early if any of the\n"
1570 " given DTMF digits are received on the channel. Returns 0 if playback\n"
1571 " completes without a digit pressed, the ASCII numerical value of the digit\n"
1572 " if one was pressed, or -1 on error/hangup.\n";
1574 static char usage_getdata[] =
1575 " Usage: GET DATA <file to be streamed> [timeout] [max digits]\n"
1576 " Stream the given file, and recieve DTMF data. Returns the digits received\n"
1577 "from the channel at the other end.\n";
1579 static char usage_setcontext[] =
1580 " Usage: SET CONTEXT <desired context>\n"
1581 " Sets the context for continuation upon exiting the application.\n";
1583 static char usage_setextension[] =
1584 " Usage: SET EXTENSION <new extension>\n"
1585 " Changes the extension for continuation upon exiting the application.\n";
1587 static char usage_setpriority[] =
1588 " Usage: SET PRIORITY <priority>\n"
1589 " Changes the priority for continuation upon exiting the application.\n"
1590 " The priority must be a valid priority or label.\n";
1592 static char usage_recordfile[] =
1593 " Usage: RECORD FILE <filename> <format> <escape digits> <timeout> \\\n"
1594 " [offset samples] [BEEP] [s=silence]\n"
1595 " Record to a file until a given dtmf digit in the sequence is received\n"
1596 " Returns -1 on hangup or error. The format will specify what kind of file\n"
1597 " will be recorded. The timeout is the maximum record time in milliseconds, or\n"
1598 " -1 for no timeout. \"Offset samples\" is optional, and, if provided, will seek\n"
1599 " to the offset without exceeding the end of the file. \"silence\" is the number\n"
1600 " of seconds of silence allowed before the function returns despite the\n"
1601 " lack of dtmf digits or reaching timeout. Silence value must be\n"
1602 " preceeded by \"s=\" and is also optional.\n";
1604 static char usage_autohangup[] =
1605 " Usage: SET AUTOHANGUP <time>\n"
1606 " Cause the channel to automatically hangup at <time> seconds in the\n"
1607 " future. Of course it can be hungup before then as well. Setting to 0 will\n"
1608 " cause the autohangup feature to be disabled on this channel.\n";
1610 static char usage_noop[] =
1614 static agi_command commands[MAX_COMMANDS] = {
1615 { { "answer", NULL }, handle_answer, "Answer channel", usage_answer },
1616 { { "channel", "status", NULL }, handle_channelstatus, "Returns status of the connected channel", usage_channelstatus },
1617 { { "database", "del", NULL }, handle_dbdel, "Removes database key/value", usage_dbdel },
1618 { { "database", "deltree", NULL }, handle_dbdeltree, "Removes database keytree/value", usage_dbdeltree },
1619 { { "database", "get", NULL }, handle_dbget, "Gets database value", usage_dbget },
1620 { { "database", "put", NULL }, handle_dbput, "Adds/updates database value", usage_dbput },
1621 { { "exec", NULL }, handle_exec, "Executes a given Application", usage_exec },
1622 { { "get", "data", NULL }, handle_getdata, "Prompts for DTMF on a channel", usage_getdata },
1623 { { "get", "full", "variable", NULL }, handle_getvariablefull, "Evaluates a channel expression", usage_getvariablefull },
1624 { { "get", "option", NULL }, handle_getoption, "Stream file, prompt for DTMF, with timeout", usage_getoption },
1625 { { "get", "variable", NULL }, handle_getvariable, "Gets a channel variable", usage_getvariable },
1626 { { "hangup", NULL }, handle_hangup, "Hangup the current channel", usage_hangup },
1627 { { "noop", NULL }, handle_noop, "Does nothing", usage_noop },
1628 { { "receive", "char", NULL }, handle_recvchar, "Receives one character from channels supporting it", usage_recvchar },
1629 { { "receive", "text", NULL }, handle_recvtext, "Receives text from channels supporting it", usage_recvtext },
1630 { { "record", "file", NULL }, handle_recordfile, "Records to a given file", usage_recordfile },
1631 { { "say", "alpha", NULL }, handle_sayalpha, "Says a given character string", usage_sayalpha },
1632 { { "say", "digits", NULL }, handle_saydigits, "Says a given digit string", usage_saydigits },
1633 { { "say", "number", NULL }, handle_saynumber, "Says a given number", usage_saynumber },
1634 { { "say", "phonetic", NULL }, handle_sayphonetic, "Says a given character string with phonetics", usage_sayphonetic },
1635 { { "say", "date", NULL }, handle_saydate, "Says a given date", usage_saydate },
1636 { { "say", "time", NULL }, handle_saytime, "Says a given time", usage_saytime },
1637 { { "say", "datetime", NULL }, handle_saydatetime, "Says a given time as specfied by the format given", usage_saydatetime },
1638 { { "send", "image", NULL }, handle_sendimage, "Sends images to channels supporting it", usage_sendimage },
1639 { { "send", "text", NULL }, handle_sendtext, "Sends text to channels supporting it", usage_sendtext },
1640 { { "set", "autohangup", NULL }, handle_autohangup, "Autohangup channel in some time", usage_autohangup },
1641 { { "set", "callerid", NULL }, handle_setcallerid, "Sets callerid for the current channel", usage_setcallerid },
1642 { { "set", "context", NULL }, handle_setcontext, "Sets channel context", usage_setcontext },
1643 { { "set", "extension", NULL }, handle_setextension, "Changes channel extension", usage_setextension },
1644 { { "set", "music", NULL }, handle_setmusic, "Enable/Disable Music on hold generator", usage_setmusic },
1645 { { "set", "priority", NULL }, handle_setpriority, "Set channel dialplan priority", usage_setpriority },
1646 { { "set", "variable", NULL }, handle_setvariable, "Sets a channel variable", usage_setvariable },
1647 { { "stream", "file", NULL }, handle_streamfile, "Sends audio file on channel", usage_streamfile },
1648 { { "control", "stream", "file", NULL }, handle_controlstreamfile, "Sends audio file on channel and allows the listner to control the stream", usage_controlstreamfile },
1649 { { "tdd", "mode", NULL }, handle_tddmode, "Toggles TDD mode (for the deaf)", usage_tddmode },
1650 { { "verbose", NULL }, handle_verbose, "Logs a message to the asterisk verbose log", usage_verbose },
1651 { { "wait", "for", "digit", NULL }, handle_waitfordigit, "Waits for a digit to be pressed", usage_waitfordigit },
1654 static int help_workhorse(int fd, char *match[])
1659 struct agi_command *e;
1661 ast_join(matchstr, sizeof(matchstr), match);
1662 for (x=0;x<sizeof(commands)/sizeof(commands[0]);x++) {
1666 /* Hide commands that start with '_' */
1667 if ((e->cmda[0])[0] == '_')
1669 ast_join(fullcmd, sizeof(fullcmd), e->cmda);
1670 if (match && strncasecmp(matchstr, fullcmd, strlen(matchstr)))
1672 ast_cli(fd, "%20.20s %s\n", fullcmd, e->summary);
1677 int ast_agi_register(agi_command *agi)
1680 for (x=0; x<MAX_COMMANDS - 1; x++) {
1681 if (commands[x].cmda[0] == agi->cmda[0]) {
1682 ast_log(LOG_WARNING, "Command already registered!\n");
1686 for (x=0; x<MAX_COMMANDS - 1; x++) {
1687 if (!commands[x].cmda[0]) {
1692 ast_log(LOG_WARNING, "No more room for new commands!\n");
1696 void ast_agi_unregister(agi_command *agi)
1699 for (x=0; x<MAX_COMMANDS - 1; x++) {
1700 if (commands[x].cmda[0] == agi->cmda[0]) {
1701 memset(&commands[x], 0, sizeof(agi_command));
1706 static agi_command *find_command(char *cmds[], int exact)
1712 for (x=0; x < sizeof(commands) / sizeof(commands[0]); x++) {
1713 if (!commands[x].cmda[0])
1715 /* start optimistic */
1717 for (y=0; match && cmds[y]; y++) {
1718 /* If there are no more words in the command (and we're looking for
1719 an exact match) or there is a difference between the two words,
1720 then this is not a match */
1721 if (!commands[x].cmda[y] && !exact)
1723 /* don't segfault if the next part of a command doesn't exist */
1724 if (!commands[x].cmda[y])
1726 if (strcasecmp(commands[x].cmda[y], cmds[y]))
1729 /* If more words are needed to complete the command then this is not
1730 a candidate (unless we're looking for a really inexact answer */
1731 if ((exact > -1) && commands[x].cmda[y])
1734 return &commands[x];
1740 static int parse_args(char *s, int *max, char *argv[])
1752 /* If it's escaped, put a literal quote */
1757 if (quoted && whitespace) {
1758 /* If we're starting a quote, coming off white space start a new word, too */
1766 if (!quoted && !escaped) {
1767 /* If we're not quoted, mark this as whitespace, and
1768 end the previous argument */
1772 /* Otherwise, just treat it as anything else */
1776 /* If we're escaped, print a literal, otherwise enable escaping */
1786 if (x >= MAX_ARGS -1) {
1787 ast_log(LOG_WARNING, "Too many arguments, truncating\n");
1790 /* Coming off of whitespace, start the next argument */
1799 /* Null terminate */
1806 static int agi_handle_command(struct ast_channel *chan, AGI *agi, char *buf)
1808 char *argv[MAX_ARGS];
1809 int argc = MAX_ARGS;
1813 parse_args(buf, &argc, argv);
1814 c = find_command(argv, 0);
1816 res = c->handler(chan, agi, argc, argv);
1818 case RESULT_SHOWUSAGE:
1819 fdprintf(agi->fd, "520-Invalid command syntax. Proper usage follows:\n");
1820 fdprintf(agi->fd, c->usage);
1821 fdprintf(agi->fd, "520 End of proper usage.\n");
1823 case AST_PBX_KEEPALIVE:
1824 /* We've been asked to keep alive, so do so */
1825 return AST_PBX_KEEPALIVE;
1827 case RESULT_FAILURE:
1828 /* They've already given the failure. We've been hung up on so handle this
1833 fdprintf(agi->fd, "510 Invalid or unknown command\n");
1838 static enum agi_result run_agi(struct ast_channel *chan, char *request, AGI *agi, int pid, int *status, int dead, int argc, char *argv[])
1840 struct ast_channel *c;
1843 enum agi_result returnstatus = AGI_RESULT_SUCCESS;
1844 struct ast_frame *f;
1847 /* how many times we'll retry if ast_waitfor_nandfs will return without either
1848 channel or file descriptor in case select is interrupted by a system call (EINTR) */
1851 if (!(readf = fdopen(agi->ctrl, "r"))) {
1852 ast_log(LOG_WARNING, "Unable to fdopen file descriptor\n");
1856 return AGI_RESULT_FAILURE;
1859 setup_env(chan, request, agi->fd, (agi->audio > -1), argc, argv);
1862 c = ast_waitfor_nandfds(&chan, dead ? 0 : 1, &agi->ctrl, 1, NULL, &outfd, &ms);
1865 /* Idle the channel until we get a command */
1868 ast_debug(1, "%s hungup\n", chan->name);
1869 returnstatus = AGI_RESULT_HANGUP;
1872 /* If it's voice, write it to the audio pipe */
1873 if ((agi->audio > -1) && (f->frametype == AST_FRAME_VOICE)) {
1874 /* Write, ignoring errors */
1875 write(agi->audio, f->data, f->datalen);
1879 } else if (outfd > -1) {
1881 if (!fgets(buf, sizeof(buf), readf)) {
1882 /* Program terminated */
1885 if (option_verbose > 2)
1886 ast_verbose(VERBOSE_PREFIX_3 "AGI Script %s completed, returning %d\n", request, returnstatus);
1888 waitpid(pid, status, 0);
1889 /* No need to kill the pid anymore, since they closed us */
1893 /* get rid of trailing newline, if any */
1894 if (*buf && buf[strlen(buf) - 1] == '\n')
1895 buf[strlen(buf) - 1] = 0;
1897 ast_verbose("AGI Rx << %s\n", buf);
1898 returnstatus |= agi_handle_command(chan, agi, buf);
1899 /* If the handle_command returns -1, we need to stop */
1900 if ((returnstatus < 0) || (returnstatus == AST_PBX_KEEPALIVE)) {
1905 ast_log(LOG_WARNING, "No channel, no fd?\n");
1906 returnstatus = AGI_RESULT_FAILURE;
1911 /* Notify process */
1913 const char *sighup = pbx_builtin_getvar_helper(chan, "AGISIGHUP");
1914 if (ast_strlen_zero(sighup) || !ast_false(sighup)) {
1915 if (kill(pid, SIGHUP))
1916 ast_log(LOG_WARNING, "unable to send SIGHUP to AGI process %d: %s\n", pid, strerror(errno));
1920 return returnstatus;
1923 static int handle_showagi(int fd, int argc, char *argv[])
1925 struct agi_command *e;
1928 return RESULT_SHOWUSAGE;
1930 e = find_command(argv + 2, 1);
1932 ast_cli(fd, e->usage);
1934 if (find_command(argv + 2, -1)) {
1935 return help_workhorse(fd, argv + 1);
1937 ast_join(fullcmd, sizeof(fullcmd), argv+1);
1938 ast_cli(fd, "No such command '%s'.\n", fullcmd);
1942 return help_workhorse(fd, NULL);
1944 return RESULT_SUCCESS;
1947 /*! \brief Convert string to use HTML escaped characters
1948 \note Maybe this should be a generic function?
1950 static void write_html_escaped(FILE *htmlfile, char *str)
1957 fprintf(htmlfile, "%s", "<");
1960 fprintf(htmlfile, "%s", ">");
1963 fprintf(htmlfile, "%s", "&");
1966 fprintf(htmlfile, "%s", """);
1969 fprintf(htmlfile, "%c", *cur);
1978 static int handle_agidumphtml(int fd, int argc, char *argv[])
1980 struct agi_command *e;
1986 return RESULT_SHOWUSAGE;
1988 if (!(htmlfile = fopen(argv[2], "wt"))) {
1989 ast_cli(fd, "Could not create file '%s'\n", argv[2]);
1990 return RESULT_SHOWUSAGE;
1993 fprintf(htmlfile, "<HTML>\n<HEAD>\n<TITLE>AGI Commands</TITLE>\n</HEAD>\n");
1994 fprintf(htmlfile, "<BODY>\n<CENTER><B><H1>AGI Commands</H1></B></CENTER>\n\n");
1997 fprintf(htmlfile, "<TABLE BORDER=\"0\" CELLSPACING=\"10\">\n");
1999 for (x=0;x<sizeof(commands)/sizeof(commands[0]);x++) {
2000 char *stringp, *tempstr;
2003 if (!e->cmda[0]) /* end ? */
2005 /* Hide commands that start with '_' */
2006 if ((e->cmda[0])[0] == '_')
2008 ast_join(fullcmd, sizeof(fullcmd), e->cmda);
2010 fprintf(htmlfile, "<TR><TD><TABLE BORDER=\"1\" CELLPADDING=\"5\" WIDTH=\"100%%\">\n");
2011 fprintf(htmlfile, "<TR><TH ALIGN=\"CENTER\"><B>%s - %s</B></TH></TR>\n", fullcmd,e->summary);
2014 tempstr = strsep(&stringp, "\n");
2016 fprintf(htmlfile, "<TR><TD ALIGN=\"CENTER\">");
2017 write_html_escaped(htmlfile, tempstr);
2018 fprintf(htmlfile, "</TD></TR>\n");
2021 fprintf(htmlfile, "<TR><TD ALIGN=\"CENTER\">\n");
2022 while ((tempstr = strsep(&stringp, "\n")) != NULL) {
2023 write_html_escaped(htmlfile, tempstr);
2024 fprintf(htmlfile, "<BR>\n");
2026 fprintf(htmlfile, "</TD></TR>\n");
2027 fprintf(htmlfile, "</TABLE></TD></TR>\n\n");
2031 fprintf(htmlfile, "</TABLE>\n</BODY>\n</HTML>\n");
2033 ast_cli(fd, "AGI HTML Commands Dumped to: %s\n", argv[2]);
2034 return RESULT_SUCCESS;
2037 static int agi_exec_full(struct ast_channel *chan, void *data, int enhanced, int dead)
2039 enum agi_result res;
2040 struct ast_module_user *u;
2041 char *argv[MAX_ARGS];
2051 if (ast_strlen_zero(data)) {
2052 ast_log(LOG_WARNING, "AGI requires an argument (script)\n");
2055 ast_copy_string(buf, data, sizeof(buf));
2057 memset(&agi, 0, sizeof(agi));
2058 while ((stringp = strsep(&tmp, "|")) && argc < MAX_ARGS-1)
2059 argv[argc++] = stringp;
2062 u = ast_module_user_add(chan);
2064 /* Answer if need be */
2065 if (chan->_state != AST_STATE_UP) {
2066 if (ast_answer(chan)) {
2067 LOCAL_USER_REMOVE(u);
2072 res = launch_script(argv[0], argv, fds, enhanced ? &efd : NULL, &pid);
2073 if (res == AGI_RESULT_SUCCESS) {
2078 res = run_agi(chan, argv[0], &agi, pid, &status, dead, argc, argv);
2079 /* If the fork'd process returns non-zero, set AGISTATUS to FAILURE */
2080 if (res == AGI_RESULT_SUCCESS && status)
2081 res = AGI_RESULT_FAILURE;
2082 if (fds[1] != fds[0])
2086 ast_unreplace_sigchld();
2088 ast_module_user_remove(u);
2091 case AGI_RESULT_SUCCESS:
2092 pbx_builtin_setvar_helper(chan, "AGISTATUS", "SUCCESS");
2094 case AGI_RESULT_FAILURE:
2095 pbx_builtin_setvar_helper(chan, "AGISTATUS", "FAILURE");
2097 case AGI_RESULT_NOTFOUND:
2098 pbx_builtin_setvar_helper(chan, "AGISTATUS", "NOTFOUND");
2100 case AGI_RESULT_HANGUP:
2101 pbx_builtin_setvar_helper(chan, "AGISTATUS", "HANGUP");
2108 static int agi_exec(struct ast_channel *chan, void *data)
2110 if (chan->_softhangup)
2111 ast_log(LOG_WARNING, "If you want to run AGI on hungup channels you should use DeadAGI!\n");
2112 return agi_exec_full(chan, data, 0, 0);
2115 static int eagi_exec(struct ast_channel *chan, void *data)
2120 if (chan->_softhangup)
2121 ast_log(LOG_WARNING, "If you want to run AGI on hungup channels you should use DeadAGI!\n");
2122 readformat = chan->readformat;
2123 if (ast_set_read_format(chan, AST_FORMAT_SLINEAR)) {
2124 ast_log(LOG_WARNING, "Unable to set channel '%s' to linear mode\n", chan->name);
2127 res = agi_exec_full(chan, data, 1, 0);
2129 if (ast_set_read_format(chan, readformat)) {
2130 ast_log(LOG_WARNING, "Unable to restore channel '%s' to format %s\n", chan->name, ast_getformatname(readformat));
2136 static int deadagi_exec(struct ast_channel *chan, void *data)
2138 return agi_exec_full(chan, data, 0, 1);
2141 static char showagi_help[] =
2142 "Usage: agi show [topic]\n"
2143 " When called with a topic as an argument, displays usage\n"
2144 " information on the given command. If called without a\n"
2145 " topic, it provides a list of AGI commands.\n";
2148 static char dumpagihtml_help[] =
2149 "Usage: agi dumphtml <filename>\n"
2150 " Dumps the agi command list in html format to given filename\n";
2152 static struct ast_cli_entry cli_agi[] = {
2153 { { "agi", "debug", NULL },
2154 agi_do_debug, "Enable AGI debugging",
2157 { { "agi", "debug", "off", NULL },
2158 agi_no_debug, "Disable AGI debugging",
2161 { { "agi", "show", NULL },
2162 handle_showagi, "List AGI commands or specific help",
2165 { { "agi", "dumphtml", NULL },
2166 handle_agidumphtml, "Dumps a list of agi commands in html format",
2170 static int unload_module(void)
2172 ast_module_user_hangup_all();
2173 ast_cli_unregister_multiple(cli_agi, sizeof(cli_agi) / sizeof(struct ast_cli_entry));
2174 ast_unregister_application(eapp);
2175 ast_unregister_application(deadapp);
2176 return ast_unregister_application(app);
2179 static int load_module(void)
2181 ast_cli_register_multiple(cli_agi, sizeof(cli_agi) / sizeof(struct ast_cli_entry));
2182 ast_register_application(deadapp, deadagi_exec, deadsynopsis, descrip);
2183 ast_register_application(eapp, eagi_exec, esynopsis, descrip);
2184 return ast_register_application(app, agi_exec, synopsis, descrip);
2187 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS, "Asterisk Gateway Interface (AGI)",
2188 .load = load_module,
2189 .unload = unload_module,