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 if (option_debug > 3)
228 ast_log(LOG_DEBUG, "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 ast_log(LOG_WARNING, "Unable to create toast pipe: %s\n",strerror(errno));
255 return AGI_RESULT_FAILURE;
258 ast_log(LOG_WARNING, "unable to create fromast pipe: %s\n", strerror(errno));
261 return AGI_RESULT_FAILURE;
265 ast_log(LOG_WARNING, "unable to create audio pipe: %s\n", strerror(errno));
270 return AGI_RESULT_FAILURE;
272 res = fcntl(audio[1], F_GETFL);
274 res = fcntl(audio[1], F_SETFL, res | O_NONBLOCK);
276 ast_log(LOG_WARNING, "unable to set audio pipe parameters: %s\n", strerror(errno));
283 return AGI_RESULT_FAILURE;
287 /* Block SIGHUP during the fork - prevents a race */
288 sigfillset(&signal_set);
289 pthread_sigmask(SIG_BLOCK, &signal_set, &old_set);
292 ast_log(LOG_WARNING, "Failed to fork(): %s\n", strerror(errno));
293 pthread_sigmask(SIG_SETMASK, &old_set, NULL);
294 return AGI_RESULT_FAILURE;
297 /* Pass paths to AGI via environmental variables */
298 setenv("AST_CONFIG_DIR", ast_config_AST_CONFIG_DIR, 1);
299 setenv("AST_CONFIG_FILE", ast_config_AST_CONFIG_FILE, 1);
300 setenv("AST_MODULE_DIR", ast_config_AST_MODULE_DIR, 1);
301 setenv("AST_SPOOL_DIR", ast_config_AST_SPOOL_DIR, 1);
302 setenv("AST_MONITOR_DIR", ast_config_AST_MONITOR_DIR, 1);
303 setenv("AST_VAR_DIR", ast_config_AST_VAR_DIR, 1);
304 setenv("AST_DATA_DIR", ast_config_AST_DATA_DIR, 1);
305 setenv("AST_LOG_DIR", ast_config_AST_LOG_DIR, 1);
306 setenv("AST_AGI_DIR", ast_config_AST_AGI_DIR, 1);
307 setenv("AST_KEY_DIR", ast_config_AST_KEY_DIR, 1);
308 setenv("AST_RUN_DIR", ast_config_AST_RUN_DIR, 1);
310 /* Don't run AGI scripts with realtime priority -- it causes audio stutter */
313 /* Redirect stdin and out, provide enhanced audio channel if desired */
314 dup2(fromast[0], STDIN_FILENO);
315 dup2(toast[1], STDOUT_FILENO);
317 dup2(audio[0], STDERR_FILENO + 1);
319 close(STDERR_FILENO + 1);
322 /* Before we unblock our signals, return our trapped signals back to the defaults */
323 signal(SIGHUP, SIG_DFL);
324 signal(SIGCHLD, SIG_DFL);
325 signal(SIGINT, SIG_DFL);
326 signal(SIGURG, SIG_DFL);
327 signal(SIGTERM, SIG_DFL);
328 signal(SIGPIPE, SIG_DFL);
329 signal(SIGXFSZ, SIG_DFL);
331 /* unblock important signal handlers */
332 if (pthread_sigmask(SIG_UNBLOCK, &signal_set, NULL)) {
333 ast_log(LOG_WARNING, "unable to unblock signals for AGI script: %s\n", strerror(errno));
337 /* Close everything but stdin/out/error */
338 for (x=STDERR_FILENO + 2;x<1024;x++)
342 /* XXX argv should be deprecated in favor of passing agi_argX paramaters */
344 /* Can't use ast_log since FD's are closed */
345 fprintf(stdout, "verbose \"Failed to execute '%s': %s\" 2\n", script, strerror(errno));
349 pthread_sigmask(SIG_SETMASK, &old_set, NULL);
350 if (option_verbose > 2)
351 ast_verbose(VERBOSE_PREFIX_3 "Launched AGI Script %s\n", script);
357 /* close what we're not using in the parent */
365 return AGI_RESULT_SUCCESS;
368 static void setup_env(struct ast_channel *chan, char *request, int fd, int enhanced, int argc, char *argv[])
372 /* Print initial environment, with agi_request always being the first
374 fdprintf(fd, "agi_request: %s\n", request);
375 fdprintf(fd, "agi_channel: %s\n", chan->name);
376 fdprintf(fd, "agi_language: %s\n", chan->language);
377 fdprintf(fd, "agi_type: %s\n", chan->tech->type);
378 fdprintf(fd, "agi_uniqueid: %s\n", chan->uniqueid);
381 fdprintf(fd, "agi_callerid: %s\n", S_OR(chan->cid.cid_num, "unknown"));
382 fdprintf(fd, "agi_calleridname: %s\n", S_OR(chan->cid.cid_name, "unknown"));
383 fdprintf(fd, "agi_callingpres: %d\n", chan->cid.cid_pres);
384 fdprintf(fd, "agi_callingani2: %d\n", chan->cid.cid_ani2);
385 fdprintf(fd, "agi_callington: %d\n", chan->cid.cid_ton);
386 fdprintf(fd, "agi_callingtns: %d\n", chan->cid.cid_tns);
387 fdprintf(fd, "agi_dnid: %s\n", S_OR(chan->cid.cid_dnid, "unknown"));
388 fdprintf(fd, "agi_rdnis: %s\n", S_OR(chan->cid.cid_rdnis, "unknown"));
390 /* Context information */
391 fdprintf(fd, "agi_context: %s\n", chan->context);
392 fdprintf(fd, "agi_extension: %s\n", chan->exten);
393 fdprintf(fd, "agi_priority: %d\n", chan->priority);
394 fdprintf(fd, "agi_enhanced: %s\n", enhanced ? "1.0" : "0.0");
396 /* User information */
397 fdprintf(fd, "agi_accountcode: %s\n", chan->accountcode ? chan->accountcode : "");
399 /* Send any parameters to the fastagi server that have been passed via the agi application */
400 /* Agi application paramaters take the form of: AGI(/path/to/example/script|${EXTEN}) */
401 for(count = 1; count < argc; count++)
402 fdprintf(fd, "agi_arg_%d: %s\n", count, argv[count]);
404 /* End with empty return */
408 static int handle_answer(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
412 if (chan->_state != AST_STATE_UP) {
413 /* Answer the chan */
414 res = ast_answer(chan);
416 fdprintf(agi->fd, "200 result=%d\n", res);
417 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
420 static int handle_waitfordigit(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
425 return RESULT_SHOWUSAGE;
426 if (sscanf(argv[3], "%d", &to) != 1)
427 return RESULT_SHOWUSAGE;
428 res = ast_waitfordigit_full(chan, to, agi->audio, agi->ctrl);
429 fdprintf(agi->fd, "200 result=%d\n", res);
430 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
433 static int handle_sendtext(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
437 return RESULT_SHOWUSAGE;
438 /* At the moment, the parser (perhaps broken) returns with
439 the last argument PLUS the newline at the end of the input
440 buffer. This probably needs to be fixed, but I wont do that
441 because other stuff may break as a result. The right way
442 would probably be to strip off the trailing newline before
443 parsing, then here, add a newline at the end of the string
444 before sending it to ast_sendtext --DUDE */
445 res = ast_sendtext(chan, argv[2]);
446 fdprintf(agi->fd, "200 result=%d\n", res);
447 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
450 static int handle_recvchar(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
454 return RESULT_SHOWUSAGE;
455 res = ast_recvchar(chan,atoi(argv[2]));
457 fdprintf(agi->fd, "200 result=%d (timeout)\n", res);
458 return RESULT_SUCCESS;
461 fdprintf(agi->fd, "200 result=%d\n", res);
462 return RESULT_SUCCESS;
465 fdprintf(agi->fd, "200 result=%d (hangup)\n", res);
466 return RESULT_FAILURE;
470 static int handle_recvtext(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
475 return RESULT_SHOWUSAGE;
476 buf = ast_recvtext(chan,atoi(argv[2]));
478 fdprintf(agi->fd, "200 result=1 (%s)\n", buf);
481 fdprintf(agi->fd, "200 result=-1\n");
483 return RESULT_SUCCESS;
486 static int handle_tddmode(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
490 return RESULT_SHOWUSAGE;
491 if (!strncasecmp(argv[2],"on",2))
495 if (!strncasecmp(argv[2],"mate",4))
497 if (!strncasecmp(argv[2],"tdd",3))
499 res = ast_channel_setoption(chan, AST_OPTION_TDD, &x, sizeof(char), 0);
500 if (res != RESULT_SUCCESS)
501 fdprintf(agi->fd, "200 result=0\n");
503 fdprintf(agi->fd, "200 result=1\n");
504 return RESULT_SUCCESS;
507 static int handle_sendimage(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
511 return RESULT_SHOWUSAGE;
512 res = ast_send_image(chan, argv[2]);
513 if (!ast_check_hangup(chan))
515 fdprintf(agi->fd, "200 result=%d\n", res);
516 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
519 static int handle_controlstreamfile(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
528 if (argc < 5 || argc > 9)
529 return RESULT_SHOWUSAGE;
531 if (!ast_strlen_zero(argv[4]))
536 if ((argc > 5) && (sscanf(argv[5], "%d", &skipms) != 1))
537 return RESULT_SHOWUSAGE;
539 if (argc > 6 && !ast_strlen_zero(argv[6]))
544 if (argc > 7 && !ast_strlen_zero(argv[7]))
549 if (argc > 8 && !ast_strlen_zero(argv[8]))
554 res = ast_control_streamfile(chan, argv[3], fwd, rev, stop, pause, NULL, skipms);
556 fdprintf(agi->fd, "200 result=%d\n", res);
558 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
561 static int handle_streamfile(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
565 struct ast_filestream *fs;
566 struct ast_filestream *vfs;
567 long sample_offset = 0;
571 if (argc < 4 || argc > 5)
572 return RESULT_SHOWUSAGE;
577 if ((argc > 4) && (sscanf(argv[4], "%ld", &sample_offset) != 1))
578 return RESULT_SHOWUSAGE;
580 fs = ast_openstream(chan, argv[2], chan->language);
583 fdprintf(agi->fd, "200 result=%d endpos=%ld\n", 0, sample_offset);
584 return RESULT_SUCCESS;
586 vfs = ast_openvstream(chan, argv[2], chan->language);
587 if (vfs && option_debug)
588 ast_log(LOG_DEBUG, "Ooh, found a video stream, too\n");
590 if (option_verbose > 2)
591 ast_verbose(VERBOSE_PREFIX_3 "Playing '%s' (escape_digits=%s) (sample_offset %ld)\n", argv[2], edigits, sample_offset);
593 ast_seekstream(fs, 0, SEEK_END);
594 max_length = ast_tellstream(fs);
595 ast_seekstream(fs, sample_offset, SEEK_SET);
596 res = ast_applystream(chan, fs);
598 vres = ast_applystream(chan, vfs);
599 res = ast_playstream(fs);
601 vres = ast_playstream(vfs);
604 fdprintf(agi->fd, "200 result=%d endpos=%ld\n", res, sample_offset);
605 return (res >= 0) ? RESULT_SHOWUSAGE : RESULT_FAILURE;
607 res = ast_waitstream_full(chan, argv[3], agi->audio, agi->ctrl);
608 /* this is to check for if ast_waitstream closed the stream, we probably are at
609 * the end of the stream, return that amount, else check for the amount */
610 sample_offset = (chan->stream) ? ast_tellstream(fs) : max_length;
611 ast_stopstream(chan);
613 /* Stop this command, don't print a result line, as there is a new command */
614 return RESULT_SUCCESS;
616 fdprintf(agi->fd, "200 result=%d endpos=%ld\n", res, sample_offset);
617 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
620 /* get option - really similar to the handle_streamfile, but with a timeout */
621 static int handle_getoption(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
625 struct ast_filestream *fs;
626 struct ast_filestream *vfs;
627 long sample_offset = 0;
632 if ( argc < 4 || argc > 5 )
633 return RESULT_SHOWUSAGE;
639 timeout = atoi(argv[4]);
640 else if (chan->pbx->dtimeout) {
641 /* by default dtimeout is set to 5sec */
642 timeout = chan->pbx->dtimeout * 1000; /* in msec */
645 fs = ast_openstream(chan, argv[2], chan->language);
647 fdprintf(agi->fd, "200 result=%d endpos=%ld\n", 0, sample_offset);
648 ast_log(LOG_WARNING, "Unable to open %s\n", argv[2]);
649 return RESULT_SUCCESS;
651 vfs = ast_openvstream(chan, argv[2], chan->language);
652 if (vfs && option_debug)
653 ast_log(LOG_DEBUG, "Ooh, found a video stream, too\n");
655 if (option_verbose > 2)
656 ast_verbose(VERBOSE_PREFIX_3 "Playing '%s' (escape_digits=%s) (timeout %d)\n", argv[2], edigits, timeout);
658 ast_seekstream(fs, 0, SEEK_END);
659 max_length = ast_tellstream(fs);
660 ast_seekstream(fs, sample_offset, SEEK_SET);
661 res = ast_applystream(chan, fs);
663 vres = ast_applystream(chan, vfs);
664 res = ast_playstream(fs);
666 vres = ast_playstream(vfs);
668 fdprintf(agi->fd, "200 result=%d endpos=%ld\n", res, sample_offset);
670 return RESULT_SHOWUSAGE;
672 return RESULT_FAILURE;
674 res = ast_waitstream_full(chan, argv[3], agi->audio, agi->ctrl);
675 /* this is to check for if ast_waitstream closed the stream, we probably are at
676 * the end of the stream, return that amount, else check for the amount */
677 sample_offset = (chan->stream)?ast_tellstream(fs):max_length;
678 ast_stopstream(chan);
680 /* Stop this command, don't print a result line, as there is a new command */
681 return RESULT_SUCCESS;
684 /* If the user didnt press a key, wait for digitTimeout*/
686 res = ast_waitfordigit_full(chan, timeout, agi->audio, agi->ctrl);
687 /* Make sure the new result is in the escape digits of the GET OPTION */
688 if ( !strchr(edigits,res) )
692 fdprintf(agi->fd, "200 result=%d endpos=%ld\n", res, sample_offset);
693 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
699 /*--- handle_saynumber: Say number in various language syntaxes ---*/
700 /* Need to add option for gender here as well. Coders wanted */
701 /* While waiting, we're sending a NULL. */
702 static int handle_saynumber(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
707 return RESULT_SHOWUSAGE;
708 if (sscanf(argv[2], "%d", &num) != 1)
709 return RESULT_SHOWUSAGE;
710 res = ast_say_number_full(chan, num, argv[3], chan->language, NULL, agi->audio, agi->ctrl);
712 return RESULT_SUCCESS;
713 fdprintf(agi->fd, "200 result=%d\n", res);
714 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
717 static int handle_saydigits(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
723 return RESULT_SHOWUSAGE;
724 if (sscanf(argv[2], "%d", &num) != 1)
725 return RESULT_SHOWUSAGE;
727 res = ast_say_digit_str_full(chan, argv[2], argv[3], chan->language, agi->audio, agi->ctrl);
728 if (res == 1) /* New command */
729 return RESULT_SUCCESS;
730 fdprintf(agi->fd, "200 result=%d\n", res);
731 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
734 static int handle_sayalpha(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
739 return RESULT_SHOWUSAGE;
741 res = ast_say_character_str_full(chan, argv[2], argv[3], chan->language, agi->audio, agi->ctrl);
742 if (res == 1) /* New command */
743 return RESULT_SUCCESS;
744 fdprintf(agi->fd, "200 result=%d\n", res);
745 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
748 static int handle_saydate(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
753 return RESULT_SHOWUSAGE;
754 if (sscanf(argv[2], "%d", &num) != 1)
755 return RESULT_SHOWUSAGE;
756 res = ast_say_date(chan, num, argv[3], chan->language);
758 return RESULT_SUCCESS;
759 fdprintf(agi->fd, "200 result=%d\n", res);
760 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
763 static int handle_saytime(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
768 return RESULT_SHOWUSAGE;
769 if (sscanf(argv[2], "%d", &num) != 1)
770 return RESULT_SHOWUSAGE;
771 res = ast_say_time(chan, num, argv[3], chan->language);
773 return RESULT_SUCCESS;
774 fdprintf(agi->fd, "200 result=%d\n", res);
775 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
778 static int handle_saydatetime(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
782 char *format, *zone=NULL;
785 return RESULT_SHOWUSAGE;
790 /* XXX this doesn't belong here, but in the 'say' module */
791 if (!strcasecmp(chan->language, "de")) {
792 format = "A dBY HMS";
794 format = "ABdY 'digits/at' IMp";
798 if (argc > 5 && !ast_strlen_zero(argv[5]))
801 if (ast_get_time_t(argv[2], &unixtime, 0, NULL))
802 return RESULT_SHOWUSAGE;
804 res = ast_say_date_with_format(chan, unixtime, argv[3], chan->language, format, zone);
806 return RESULT_SUCCESS;
808 fdprintf(agi->fd, "200 result=%d\n", res);
809 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
812 static int handle_sayphonetic(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
817 return RESULT_SHOWUSAGE;
819 res = ast_say_phonetic_str_full(chan, argv[2], argv[3], chan->language, agi->audio, agi->ctrl);
820 if (res == 1) /* New command */
821 return RESULT_SUCCESS;
822 fdprintf(agi->fd, "200 result=%d\n", res);
823 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
826 static int handle_getdata(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
834 return RESULT_SHOWUSAGE;
836 timeout = atoi(argv[3]);
843 res = ast_app_getdata_full(chan, argv[2], data, max, timeout, agi->audio, agi->ctrl);
844 if (res == 2) /* New command */
845 return RESULT_SUCCESS;
847 fdprintf(agi->fd, "200 result=%s (timeout)\n", data);
849 fdprintf(agi->fd, "200 result=-1\n");
851 fdprintf(agi->fd, "200 result=%s\n", data);
852 return RESULT_SUCCESS;
855 static int handle_setcontext(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
859 return RESULT_SHOWUSAGE;
860 ast_copy_string(chan->context, argv[2], sizeof(chan->context));
861 fdprintf(agi->fd, "200 result=0\n");
862 return RESULT_SUCCESS;
865 static int handle_setextension(struct ast_channel *chan, AGI *agi, int argc, char **argv)
868 return RESULT_SHOWUSAGE;
869 ast_copy_string(chan->exten, argv[2], sizeof(chan->exten));
870 fdprintf(agi->fd, "200 result=0\n");
871 return RESULT_SUCCESS;
874 static int handle_setpriority(struct ast_channel *chan, AGI *agi, int argc, char **argv)
878 return RESULT_SHOWUSAGE;
880 if (sscanf(argv[2], "%d", &pri) != 1) {
881 if ((pri = ast_findlabel_extension(chan, chan->context, chan->exten, argv[2], chan->cid.cid_num)) < 1)
882 return RESULT_SHOWUSAGE;
885 ast_explicit_goto(chan, NULL, NULL, pri);
886 fdprintf(agi->fd, "200 result=0\n");
887 return RESULT_SUCCESS;
890 static int handle_recordfile(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
892 struct ast_filestream *fs;
894 struct timeval start;
895 long sample_offset = 0;
899 struct ast_dsp *sildet=NULL; /* silence detector dsp */
900 int totalsilence = 0;
902 int silence = 0; /* amount of silence to allow */
903 int gotsilence = 0; /* did we timeout for silence? */
904 char *silencestr=NULL;
908 /* XXX EAGI FIXME XXX */
911 return RESULT_SHOWUSAGE;
912 if (sscanf(argv[5], "%d", &ms) != 1)
913 return RESULT_SHOWUSAGE;
916 silencestr = strchr(argv[6],'s');
917 if ((argc > 7) && (!silencestr))
918 silencestr = strchr(argv[7],'s');
919 if ((argc > 8) && (!silencestr))
920 silencestr = strchr(argv[8],'s');
923 if (strlen(silencestr) > 2) {
924 if ((silencestr[0] == 's') && (silencestr[1] == '=')) {
928 silence = atoi(silencestr);
936 rfmt = chan->readformat;
937 res = ast_set_read_format(chan, AST_FORMAT_SLINEAR);
939 ast_log(LOG_WARNING, "Unable to set to linear mode, giving up\n");
942 sildet = ast_dsp_new();
944 ast_log(LOG_WARNING, "Unable to create silence detector :(\n");
947 ast_dsp_set_threshold(sildet, 256);
950 /* backward compatibility, if no offset given, arg[6] would have been
951 * caught below and taken to be a beep, else if it is a digit then it is a
953 if ((argc >6) && (sscanf(argv[6], "%ld", &sample_offset) != 1) && (!strchr(argv[6], '=')))
954 res = ast_streamfile(chan, "beep", chan->language);
956 if ((argc > 7) && (!strchr(argv[7], '=')))
957 res = ast_streamfile(chan, "beep", chan->language);
960 res = ast_waitstream(chan, argv[4]);
962 fdprintf(agi->fd, "200 result=%d (randomerror) endpos=%ld\n", res, sample_offset);
964 fs = ast_writefile(argv[2], argv[3], NULL, O_CREAT | O_WRONLY | (sample_offset ? O_APPEND : 0), 0, AST_FILE_MODE);
967 fdprintf(agi->fd, "200 result=%d (writefile)\n", res);
969 ast_dsp_free(sildet);
970 return RESULT_FAILURE;
973 /* Request a video update */
974 ast_indicate(chan, AST_CONTROL_VIDUPDATE);
977 ast_applystream(chan,fs);
978 /* really should have checks */
979 ast_seekstream(fs, sample_offset, SEEK_SET);
983 while ((ms < 0) || ast_tvdiff_ms(ast_tvnow(), start) < ms) {
984 res = ast_waitfor(chan, -1);
987 fdprintf(agi->fd, "200 result=%d (waitfor) endpos=%ld\n", res,sample_offset);
989 ast_dsp_free(sildet);
990 return RESULT_FAILURE;
994 fdprintf(agi->fd, "200 result=%d (hangup) endpos=%ld\n", 0, sample_offset);
997 ast_dsp_free(sildet);
998 return RESULT_FAILURE;
1000 switch(f->frametype) {
1001 case AST_FRAME_DTMF:
1002 if (strchr(argv[4], f->subclass)) {
1003 /* This is an interrupting chracter, so rewind to chop off any small
1004 amount of DTMF that may have been recorded
1006 ast_stream_rewind(fs, 200);
1007 ast_truncstream(fs);
1008 sample_offset = ast_tellstream(fs);
1009 fdprintf(agi->fd, "200 result=%d (dtmf) endpos=%ld\n", f->subclass, sample_offset);
1010 ast_closestream(fs);
1013 ast_dsp_free(sildet);
1014 return RESULT_SUCCESS;
1017 case AST_FRAME_VOICE:
1018 ast_writestream(fs, f);
1019 /* this is a safe place to check progress since we know that fs
1020 * is valid after a write, and it will then have our current
1022 sample_offset = ast_tellstream(fs);
1025 ast_dsp_silence(sildet, f, &dspsilence);
1027 totalsilence = dspsilence;
1031 if (totalsilence > silence) {
1032 /* Ended happily with silence */
1038 case AST_FRAME_VIDEO:
1039 ast_writestream(fs, f);
1041 /* Ignore all other frames */
1050 ast_stream_rewind(fs, silence-1000);
1051 ast_truncstream(fs);
1052 sample_offset = ast_tellstream(fs);
1054 fdprintf(agi->fd, "200 result=%d (timeout) endpos=%ld\n", res, sample_offset);
1055 ast_closestream(fs);
1059 res = ast_set_read_format(chan, rfmt);
1061 ast_log(LOG_WARNING, "Unable to restore read format on '%s'\n", chan->name);
1062 ast_dsp_free(sildet);
1064 return RESULT_SUCCESS;
1067 static int handle_autohangup(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
1072 return RESULT_SHOWUSAGE;
1073 if (sscanf(argv[2], "%d", &timeout) != 1)
1074 return RESULT_SHOWUSAGE;
1078 chan->whentohangup = time(NULL) + timeout;
1080 chan->whentohangup = 0;
1081 fdprintf(agi->fd, "200 result=0\n");
1082 return RESULT_SUCCESS;
1085 static int handle_hangup(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1087 struct ast_channel *c;
1089 /* no argument: hangup the current channel */
1090 ast_softhangup(chan,AST_SOFTHANGUP_EXPLICIT);
1091 fdprintf(agi->fd, "200 result=1\n");
1092 return RESULT_SUCCESS;
1093 } else if (argc == 2) {
1094 /* one argument: look for info on the specified channel */
1095 c = ast_get_channel_by_name_locked(argv[1]);
1097 /* we have a matching channel */
1098 ast_softhangup(c,AST_SOFTHANGUP_EXPLICIT);
1099 fdprintf(agi->fd, "200 result=1\n");
1100 ast_channel_unlock(c);
1101 return RESULT_SUCCESS;
1103 /* if we get this far no channel name matched the argument given */
1104 fdprintf(agi->fd, "200 result=-1\n");
1105 return RESULT_SUCCESS;
1107 return RESULT_SHOWUSAGE;
1111 static int handle_exec(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1114 struct ast_app *app;
1117 return RESULT_SHOWUSAGE;
1119 if (option_verbose > 2)
1120 ast_verbose(VERBOSE_PREFIX_3 "AGI Script Executing Application: (%s) Options: (%s)\n", argv[1], argv[2]);
1122 app = pbx_findapp(argv[1]);
1125 res = pbx_exec(chan, app, argv[2]);
1127 ast_log(LOG_WARNING, "Could not find application (%s)\n", argv[1]);
1130 fdprintf(agi->fd, "200 result=%d\n", res);
1135 static int handle_setcallerid(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1138 char *l = NULL, *n = NULL;
1141 ast_copy_string(tmp, argv[2], sizeof(tmp));
1142 ast_callerid_parse(tmp, &n, &l);
1144 ast_shrink_phone_number(l);
1149 ast_set_callerid(chan, l, n, NULL);
1152 fdprintf(agi->fd, "200 result=1\n");
1153 return RESULT_SUCCESS;
1156 static int handle_channelstatus(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1158 struct ast_channel *c;
1160 /* no argument: supply info on the current channel */
1161 fdprintf(agi->fd, "200 result=%d\n", chan->_state);
1162 return RESULT_SUCCESS;
1163 } else if (argc == 3) {
1164 /* one argument: look for info on the specified channel */
1165 c = ast_get_channel_by_name_locked(argv[2]);
1167 fdprintf(agi->fd, "200 result=%d\n", c->_state);
1168 ast_channel_unlock(c);
1169 return RESULT_SUCCESS;
1171 /* if we get this far no channel name matched the argument given */
1172 fdprintf(agi->fd, "200 result=-1\n");
1173 return RESULT_SUCCESS;
1175 return RESULT_SHOWUSAGE;
1179 static int handle_setvariable(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1182 pbx_builtin_setvar_helper(chan, argv[2], argv[3]);
1184 fdprintf(agi->fd, "200 result=1\n");
1185 return RESULT_SUCCESS;
1188 static int handle_getvariable(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1194 return RESULT_SHOWUSAGE;
1196 /* check if we want to execute an ast_custom_function */
1197 if (!ast_strlen_zero(argv[2]) && (argv[2][strlen(argv[2]) - 1] == ')')) {
1198 ret = ast_func_read(chan, argv[2], tempstr, sizeof(tempstr)) ? NULL : tempstr;
1200 pbx_retrieve_variable(chan, argv[2], &ret, tempstr, sizeof(tempstr), NULL);
1204 fdprintf(agi->fd, "200 result=1 (%s)\n", ret);
1206 fdprintf(agi->fd, "200 result=0\n");
1208 return RESULT_SUCCESS;
1211 static int handle_getvariablefull(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1213 char tmp[4096] = "";
1214 struct ast_channel *chan2=NULL;
1216 if ((argc != 4) && (argc != 5))
1217 return RESULT_SHOWUSAGE;
1219 chan2 = ast_get_channel_by_name_locked(argv[4]);
1223 if (chan) { /* XXX isn't this chan2 ? */
1224 pbx_substitute_variables_helper(chan2, argv[3], tmp, sizeof(tmp) - 1);
1225 fdprintf(agi->fd, "200 result=1 (%s)\n", tmp);
1227 fdprintf(agi->fd, "200 result=0\n");
1229 if (chan2 && (chan2 != chan))
1230 ast_channel_unlock(chan2);
1231 return RESULT_SUCCESS;
1234 static int handle_verbose(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1240 return RESULT_SHOWUSAGE;
1243 sscanf(argv[2], "%d", &level);
1247 prefix = VERBOSE_PREFIX_4;
1250 prefix = VERBOSE_PREFIX_3;
1253 prefix = VERBOSE_PREFIX_2;
1257 prefix = VERBOSE_PREFIX_1;
1261 if (level <= option_verbose)
1262 ast_verbose("%s %s: %s\n", prefix, chan->data, argv[1]);
1264 fdprintf(agi->fd, "200 result=1\n");
1266 return RESULT_SUCCESS;
1269 static int handle_dbget(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1275 return RESULT_SHOWUSAGE;
1276 res = ast_db_get(argv[2], argv[3], tmp, sizeof(tmp));
1278 fdprintf(agi->fd, "200 result=0\n");
1280 fdprintf(agi->fd, "200 result=1 (%s)\n", tmp);
1282 return RESULT_SUCCESS;
1285 static int handle_dbput(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1290 return RESULT_SHOWUSAGE;
1291 res = ast_db_put(argv[2], argv[3], argv[4]);
1292 fdprintf(agi->fd, "200 result=%c\n", res ? '0' : '1');
1293 return RESULT_SUCCESS;
1296 static int handle_dbdel(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1301 return RESULT_SHOWUSAGE;
1302 res = ast_db_del(argv[2], argv[3]);
1303 fdprintf(agi->fd, "200 result=%c\n", res ? '0' : '1');
1304 return RESULT_SUCCESS;
1307 static int handle_dbdeltree(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1310 if ((argc < 3) || (argc > 4))
1311 return RESULT_SHOWUSAGE;
1313 res = ast_db_deltree(argv[2], argv[3]);
1315 res = ast_db_deltree(argv[2], NULL);
1317 fdprintf(agi->fd, "200 result=%c\n", res ? '0' : '1');
1318 return RESULT_SUCCESS;
1321 static const char debug_usage[] =
1322 "Usage: agi debug\n"
1323 " Enables dumping of AGI transactions for debugging purposes\n";
1325 static const char no_debug_usage[] =
1326 "Usage: agi nodebug\n"
1327 " Disables dumping of AGI transactions for debugging purposes\n";
1329 static int agi_do_debug(int fd, int argc, char *argv[])
1332 return RESULT_SHOWUSAGE;
1334 ast_cli(fd, "AGI Debugging Enabled\n");
1335 return RESULT_SUCCESS;
1338 static int agi_no_debug(int fd, int argc, char *argv[])
1341 return RESULT_SHOWUSAGE;
1343 ast_cli(fd, "AGI Debugging Disabled\n");
1344 return RESULT_SUCCESS;
1347 static int handle_noop(struct ast_channel *chan, AGI *agi, int arg, char *argv[])
1349 fdprintf(agi->fd, "200 result=0\n");
1350 return RESULT_SUCCESS;
1353 static int handle_setmusic(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
1355 if (!strncasecmp(argv[2], "on", 2))
1356 ast_moh_start(chan, argc > 3 ? argv[3] : NULL, NULL);
1357 else if (!strncasecmp(argv[2], "off", 3))
1359 fdprintf(agi->fd, "200 result=0\n");
1360 return RESULT_SUCCESS;
1363 static char usage_setmusic[] =
1364 " Usage: SET MUSIC ON <on|off> <class>\n"
1365 " Enables/Disables the music on hold generator. If <class> is\n"
1366 " not specified, then the default music on hold class will be used.\n"
1367 " Always returns 0.\n";
1369 static char usage_dbput[] =
1370 " Usage: DATABASE PUT <family> <key> <value>\n"
1371 " Adds or updates an entry in the Asterisk database for a\n"
1372 " given family, key, and value.\n"
1373 " Returns 1 if successful, 0 otherwise.\n";
1375 static char usage_dbget[] =
1376 " Usage: DATABASE GET <family> <key>\n"
1377 " Retrieves an entry in the Asterisk database for a\n"
1378 " given family and key.\n"
1379 " Returns 0 if <key> is not set. Returns 1 if <key>\n"
1380 " is set and returns the variable in parentheses.\n"
1381 " Example return code: 200 result=1 (testvariable)\n";
1383 static char usage_dbdel[] =
1384 " Usage: DATABASE DEL <family> <key>\n"
1385 " Deletes an entry in the Asterisk database for a\n"
1386 " given family and key.\n"
1387 " Returns 1 if successful, 0 otherwise.\n";
1389 static char usage_dbdeltree[] =
1390 " Usage: DATABASE DELTREE <family> [keytree]\n"
1391 " Deletes a family or specific keytree within a family\n"
1392 " in the Asterisk database.\n"
1393 " Returns 1 if successful, 0 otherwise.\n";
1395 static char usage_verbose[] =
1396 " Usage: VERBOSE <message> <level>\n"
1397 " Sends <message> to the console via verbose message system.\n"
1398 " <level> is the the verbose level (1-4)\n"
1399 " Always returns 1.\n";
1401 static char usage_getvariable[] =
1402 " Usage: GET VARIABLE <variablename>\n"
1403 " Returns 0 if <variablename> is not set. Returns 1 if <variablename>\n"
1404 " is set and returns the variable in parentheses.\n"
1405 " example return code: 200 result=1 (testvariable)\n";
1407 static char usage_getvariablefull[] =
1408 " Usage: GET FULL VARIABLE <variablename> [<channel name>]\n"
1409 " Returns 0 if <variablename> is not set or channel does not exist. Returns 1\n"
1410 "if <variablename> is set and returns the variable in parenthesis. Understands\n"
1411 "complex variable names and builtin variables, unlike GET VARIABLE.\n"
1412 " example return code: 200 result=1 (testvariable)\n";
1414 static char usage_setvariable[] =
1415 " Usage: SET VARIABLE <variablename> <value>\n";
1417 static char usage_channelstatus[] =
1418 " Usage: CHANNEL STATUS [<channelname>]\n"
1419 " Returns the status of the specified channel.\n"
1420 " If no channel name is given the returns the status of the\n"
1421 " current channel. Return values:\n"
1422 " 0 Channel is down and available\n"
1423 " 1 Channel is down, but reserved\n"
1424 " 2 Channel is off hook\n"
1425 " 3 Digits (or equivalent) have been dialed\n"
1426 " 4 Line is ringing\n"
1427 " 5 Remote end is ringing\n"
1429 " 7 Line is busy\n";
1431 static char usage_setcallerid[] =
1432 " Usage: SET CALLERID <number>\n"
1433 " Changes the callerid of the current channel.\n";
1435 static char usage_exec[] =
1436 " Usage: EXEC <application> <options>\n"
1437 " Executes <application> with given <options>.\n"
1438 " Returns whatever the application returns, or -2 on failure to find application\n";
1440 static char usage_hangup[] =
1441 " Usage: HANGUP [<channelname>]\n"
1442 " Hangs up the specified channel.\n"
1443 " If no channel name is given, hangs up the current channel\n";
1445 static char usage_answer[] =
1447 " Answers channel if not already in answer state. Returns -1 on\n"
1448 " channel failure, or 0 if successful.\n";
1450 static char usage_waitfordigit[] =
1451 " Usage: WAIT FOR DIGIT <timeout>\n"
1452 " Waits up to 'timeout' milliseconds for channel to receive a DTMF digit.\n"
1453 " Returns -1 on channel failure, 0 if no digit is received in the timeout, or\n"
1454 " the numerical value of the ascii of the digit if one is received. Use -1\n"
1455 " for the timeout value if you desire the call to block indefinitely.\n";
1457 static char usage_sendtext[] =
1458 " Usage: SEND TEXT \"<text to send>\"\n"
1459 " Sends the given text on a channel. Most channels do not support the\n"
1460 " transmission of text. Returns 0 if text is sent, or if the channel does not\n"
1461 " support text transmission. Returns -1 only on error/hangup. Text\n"
1462 " consisting of greater than one word should be placed in quotes since the\n"
1463 " command only accepts a single argument.\n";
1465 static char usage_recvchar[] =
1466 " Usage: RECEIVE CHAR <timeout>\n"
1467 " Receives a character of text on a channel. Specify timeout to be the\n"
1468 " maximum time to wait for input in milliseconds, or 0 for infinite. Most channels\n"
1469 " do not support the reception of text. Returns the decimal value of the character\n"
1470 " if one is received, or 0 if the channel does not support text reception. Returns\n"
1471 " -1 only on error/hangup.\n";
1473 static char usage_recvtext[] =
1474 " Usage: RECEIVE TEXT <timeout>\n"
1475 " Receives a string of text on a channel. Specify timeout to be the\n"
1476 " maximum time to wait for input in milliseconds, or 0 for infinite. Most channels\n"
1477 " do not support the reception of text. Returns -1 for failure or 1 for success, and the string in parentheses.\n";
1479 static char usage_tddmode[] =
1480 " Usage: TDD MODE <on|off>\n"
1481 " Enable/Disable TDD transmission/reception on a channel. Returns 1 if\n"
1482 " successful, or 0 if channel is not TDD-capable.\n";
1484 static char usage_sendimage[] =
1485 " Usage: SEND IMAGE <image>\n"
1486 " Sends the given image on a channel. Most channels do not support the\n"
1487 " transmission of images. Returns 0 if image is sent, or if the channel does not\n"
1488 " support image transmission. Returns -1 only on error/hangup. Image names\n"
1489 " should not include extensions.\n";
1491 static char usage_streamfile[] =
1492 " Usage: STREAM FILE <filename> <escape digits> [sample offset]\n"
1493 " Send the given file, allowing playback to be interrupted by the given\n"
1494 " digits, if any. Use double quotes for the digits if you wish none to be\n"
1495 " permitted. If sample offset is provided then the audio will seek to sample\n"
1496 " offset before play starts. Returns 0 if playback completes without a digit\n"
1497 " being pressed, or the ASCII numerical value of the digit if one was pressed,\n"
1498 " or -1 on error or if the channel was disconnected. Remember, the file\n"
1499 " extension must not be included in the filename.\n";
1501 static char usage_controlstreamfile[] =
1502 " Usage: CONTROL STREAM FILE <filename> <escape digits> [skipms] [ffchar] [rewchr] [pausechr]\n"
1503 " Send the given file, allowing playback to be controled by the given\n"
1504 " digits, if any. Use double quotes for the digits if you wish none to be\n"
1505 " permitted. Returns 0 if playback completes without a digit\n"
1506 " being pressed, or the ASCII numerical value of the digit if one was pressed,\n"
1507 " or -1 on error or if the channel was disconnected. Remember, the file\n"
1508 " extension must not be included in the filename.\n\n"
1509 " Note: ffchar and rewchar default to * and # respectively.\n";
1511 static char usage_getoption[] =
1512 " Usage: GET OPTION <filename> <escape_digits> [timeout]\n"
1513 " Behaves similar to STREAM FILE but used with a timeout option.\n";
1515 static char usage_saynumber[] =
1516 " Usage: SAY NUMBER <number> <escape digits>\n"
1517 " Say a given number, returning early if any of the given DTMF digits\n"
1518 " are received on the channel. Returns 0 if playback completes without a digit\n"
1519 " being pressed, or the ASCII numerical value of the digit if one was pressed or\n"
1520 " -1 on error/hangup.\n";
1522 static char usage_saydigits[] =
1523 " Usage: SAY DIGITS <number> <escape digits>\n"
1524 " Say a given digit string, returning early if any of the given DTMF digits\n"
1525 " are received on the channel. Returns 0 if playback completes without a digit\n"
1526 " being pressed, or the ASCII numerical value of the digit if one was pressed or\n"
1527 " -1 on error/hangup.\n";
1529 static char usage_sayalpha[] =
1530 " Usage: SAY ALPHA <number> <escape digits>\n"
1531 " Say a given character string, returning early if any of the given DTMF digits\n"
1532 " are received on the channel. Returns 0 if playback completes without a digit\n"
1533 " being pressed, or the ASCII numerical value of the digit if one was pressed or\n"
1534 " -1 on error/hangup.\n";
1536 static char usage_saydate[] =
1537 " Usage: SAY DATE <date> <escape digits>\n"
1538 " Say a given date, returning early if any of the given DTMF digits are\n"
1539 " received on the channel. <date> is number of seconds elapsed since 00:00:00\n"
1540 " on January 1, 1970, Coordinated Universal Time (UTC). Returns 0 if playback\n"
1541 " completes without a digit being pressed, or the ASCII numerical value of the\n"
1542 " digit if one was pressed or -1 on error/hangup.\n";
1544 static char usage_saytime[] =
1545 " Usage: SAY TIME <time> <escape digits>\n"
1546 " Say a given time, returning early if any of the given DTMF digits are\n"
1547 " received on the channel. <time> is number of seconds elapsed since 00:00:00\n"
1548 " on January 1, 1970, Coordinated Universal Time (UTC). Returns 0 if playback\n"
1549 " completes without a digit being pressed, or the ASCII numerical value of the\n"
1550 " digit if one was pressed or -1 on error/hangup.\n";
1552 static char usage_saydatetime[] =
1553 " Usage: SAY DATETIME <time> <escape digits> [format] [timezone]\n"
1554 " Say a given time, returning early if any of the given DTMF digits are\n"
1555 " received on the channel. <time> is number of seconds elapsed since 00:00:00\n"
1556 " on January 1, 1970, Coordinated Universal Time (UTC). [format] is the format\n"
1557 " the time should be said in. See voicemail.conf (defaults to \"ABdY\n"
1558 " 'digits/at' IMp\"). Acceptable values for [timezone] can be found in\n"
1559 " /usr/share/zoneinfo. Defaults to machine default. Returns 0 if playback\n"
1560 " completes without a digit being pressed, or the ASCII numerical value of the\n"
1561 " digit if one was pressed or -1 on error/hangup.\n";
1563 static char usage_sayphonetic[] =
1564 " Usage: SAY PHONETIC <string> <escape digits>\n"
1565 " Say a given character string with phonetics, returning early if any of the\n"
1566 " given DTMF digits are received on the channel. Returns 0 if playback\n"
1567 " completes without a digit pressed, the ASCII numerical value of the digit\n"
1568 " if one was pressed, or -1 on error/hangup.\n";
1570 static char usage_getdata[] =
1571 " Usage: GET DATA <file to be streamed> [timeout] [max digits]\n"
1572 " Stream the given file, and recieve DTMF data. Returns the digits received\n"
1573 "from the channel at the other end.\n";
1575 static char usage_setcontext[] =
1576 " Usage: SET CONTEXT <desired context>\n"
1577 " Sets the context for continuation upon exiting the application.\n";
1579 static char usage_setextension[] =
1580 " Usage: SET EXTENSION <new extension>\n"
1581 " Changes the extension for continuation upon exiting the application.\n";
1583 static char usage_setpriority[] =
1584 " Usage: SET PRIORITY <priority>\n"
1585 " Changes the priority for continuation upon exiting the application.\n"
1586 " The priority must be a valid priority or label.\n";
1588 static char usage_recordfile[] =
1589 " Usage: RECORD FILE <filename> <format> <escape digits> <timeout> \\\n"
1590 " [offset samples] [BEEP] [s=silence]\n"
1591 " Record to a file until a given dtmf digit in the sequence is received\n"
1592 " Returns -1 on hangup or error. The format will specify what kind of file\n"
1593 " will be recorded. The timeout is the maximum record time in milliseconds, or\n"
1594 " -1 for no timeout. \"Offset samples\" is optional, and, if provided, will seek\n"
1595 " to the offset without exceeding the end of the file. \"silence\" is the number\n"
1596 " of seconds of silence allowed before the function returns despite the\n"
1597 " lack of dtmf digits or reaching timeout. Silence value must be\n"
1598 " preceeded by \"s=\" and is also optional.\n";
1600 static char usage_autohangup[] =
1601 " Usage: SET AUTOHANGUP <time>\n"
1602 " Cause the channel to automatically hangup at <time> seconds in the\n"
1603 " future. Of course it can be hungup before then as well. Setting to 0 will\n"
1604 " cause the autohangup feature to be disabled on this channel.\n";
1606 static char usage_noop[] =
1610 static agi_command commands[MAX_COMMANDS] = {
1611 { { "answer", NULL }, handle_answer, "Answer channel", usage_answer },
1612 { { "channel", "status", NULL }, handle_channelstatus, "Returns status of the connected channel", usage_channelstatus },
1613 { { "database", "del", NULL }, handle_dbdel, "Removes database key/value", usage_dbdel },
1614 { { "database", "deltree", NULL }, handle_dbdeltree, "Removes database keytree/value", usage_dbdeltree },
1615 { { "database", "get", NULL }, handle_dbget, "Gets database value", usage_dbget },
1616 { { "database", "put", NULL }, handle_dbput, "Adds/updates database value", usage_dbput },
1617 { { "exec", NULL }, handle_exec, "Executes a given Application", usage_exec },
1618 { { "get", "data", NULL }, handle_getdata, "Prompts for DTMF on a channel", usage_getdata },
1619 { { "get", "full", "variable", NULL }, handle_getvariablefull, "Evaluates a channel expression", usage_getvariablefull },
1620 { { "get", "option", NULL }, handle_getoption, "Stream file, prompt for DTMF, with timeout", usage_getoption },
1621 { { "get", "variable", NULL }, handle_getvariable, "Gets a channel variable", usage_getvariable },
1622 { { "hangup", NULL }, handle_hangup, "Hangup the current channel", usage_hangup },
1623 { { "noop", NULL }, handle_noop, "Does nothing", usage_noop },
1624 { { "receive", "char", NULL }, handle_recvchar, "Receives one character from channels supporting it", usage_recvchar },
1625 { { "receive", "text", NULL }, handle_recvtext, "Receives text from channels supporting it", usage_recvtext },
1626 { { "record", "file", NULL }, handle_recordfile, "Records to a given file", usage_recordfile },
1627 { { "say", "alpha", NULL }, handle_sayalpha, "Says a given character string", usage_sayalpha },
1628 { { "say", "digits", NULL }, handle_saydigits, "Says a given digit string", usage_saydigits },
1629 { { "say", "number", NULL }, handle_saynumber, "Says a given number", usage_saynumber },
1630 { { "say", "phonetic", NULL }, handle_sayphonetic, "Says a given character string with phonetics", usage_sayphonetic },
1631 { { "say", "date", NULL }, handle_saydate, "Says a given date", usage_saydate },
1632 { { "say", "time", NULL }, handle_saytime, "Says a given time", usage_saytime },
1633 { { "say", "datetime", NULL }, handle_saydatetime, "Says a given time as specfied by the format given", usage_saydatetime },
1634 { { "send", "image", NULL }, handle_sendimage, "Sends images to channels supporting it", usage_sendimage },
1635 { { "send", "text", NULL }, handle_sendtext, "Sends text to channels supporting it", usage_sendtext },
1636 { { "set", "autohangup", NULL }, handle_autohangup, "Autohangup channel in some time", usage_autohangup },
1637 { { "set", "callerid", NULL }, handle_setcallerid, "Sets callerid for the current channel", usage_setcallerid },
1638 { { "set", "context", NULL }, handle_setcontext, "Sets channel context", usage_setcontext },
1639 { { "set", "extension", NULL }, handle_setextension, "Changes channel extension", usage_setextension },
1640 { { "set", "music", NULL }, handle_setmusic, "Enable/Disable Music on hold generator", usage_setmusic },
1641 { { "set", "priority", NULL }, handle_setpriority, "Set channel dialplan priority", usage_setpriority },
1642 { { "set", "variable", NULL }, handle_setvariable, "Sets a channel variable", usage_setvariable },
1643 { { "stream", "file", NULL }, handle_streamfile, "Sends audio file on channel", usage_streamfile },
1644 { { "control", "stream", "file", NULL }, handle_controlstreamfile, "Sends audio file on channel and allows the listner to control the stream", usage_controlstreamfile },
1645 { { "tdd", "mode", NULL }, handle_tddmode, "Toggles TDD mode (for the deaf)", usage_tddmode },
1646 { { "verbose", NULL }, handle_verbose, "Logs a message to the asterisk verbose log", usage_verbose },
1647 { { "wait", "for", "digit", NULL }, handle_waitfordigit, "Waits for a digit to be pressed", usage_waitfordigit },
1650 static int help_workhorse(int fd, char *match[])
1655 struct agi_command *e;
1657 ast_join(matchstr, sizeof(matchstr), match);
1658 for (x=0;x<sizeof(commands)/sizeof(commands[0]);x++) {
1662 /* Hide commands that start with '_' */
1663 if ((e->cmda[0])[0] == '_')
1665 ast_join(fullcmd, sizeof(fullcmd), e->cmda);
1666 if (match && strncasecmp(matchstr, fullcmd, strlen(matchstr)))
1668 ast_cli(fd, "%20.20s %s\n", fullcmd, e->summary);
1673 int ast_agi_register(agi_command *agi)
1676 for (x=0; x<MAX_COMMANDS - 1; x++) {
1677 if (commands[x].cmda[0] == agi->cmda[0]) {
1678 ast_log(LOG_WARNING, "Command already registered!\n");
1682 for (x=0; x<MAX_COMMANDS - 1; x++) {
1683 if (!commands[x].cmda[0]) {
1688 ast_log(LOG_WARNING, "No more room for new commands!\n");
1692 void ast_agi_unregister(agi_command *agi)
1695 for (x=0; x<MAX_COMMANDS - 1; x++) {
1696 if (commands[x].cmda[0] == agi->cmda[0]) {
1697 memset(&commands[x], 0, sizeof(agi_command));
1702 static agi_command *find_command(char *cmds[], int exact)
1708 for (x=0; x < sizeof(commands) / sizeof(commands[0]); x++) {
1709 if (!commands[x].cmda[0])
1711 /* start optimistic */
1713 for (y=0; match && cmds[y]; y++) {
1714 /* If there are no more words in the command (and we're looking for
1715 an exact match) or there is a difference between the two words,
1716 then this is not a match */
1717 if (!commands[x].cmda[y] && !exact)
1719 /* don't segfault if the next part of a command doesn't exist */
1720 if (!commands[x].cmda[y])
1722 if (strcasecmp(commands[x].cmda[y], cmds[y]))
1725 /* If more words are needed to complete the command then this is not
1726 a candidate (unless we're looking for a really inexact answer */
1727 if ((exact > -1) && commands[x].cmda[y])
1730 return &commands[x];
1736 static int parse_args(char *s, int *max, char *argv[])
1748 /* If it's escaped, put a literal quote */
1753 if (quoted && whitespace) {
1754 /* If we're starting a quote, coming off white space start a new word, too */
1762 if (!quoted && !escaped) {
1763 /* If we're not quoted, mark this as whitespace, and
1764 end the previous argument */
1768 /* Otherwise, just treat it as anything else */
1772 /* If we're escaped, print a literal, otherwise enable escaping */
1782 if (x >= MAX_ARGS -1) {
1783 ast_log(LOG_WARNING, "Too many arguments, truncating\n");
1786 /* Coming off of whitespace, start the next argument */
1795 /* Null terminate */
1802 static int agi_handle_command(struct ast_channel *chan, AGI *agi, char *buf)
1804 char *argv[MAX_ARGS];
1805 int argc = MAX_ARGS;
1809 parse_args(buf, &argc, argv);
1810 c = find_command(argv, 0);
1812 res = c->handler(chan, agi, argc, argv);
1814 case RESULT_SHOWUSAGE:
1815 fdprintf(agi->fd, "520-Invalid command syntax. Proper usage follows:\n");
1816 fdprintf(agi->fd, c->usage);
1817 fdprintf(agi->fd, "520 End of proper usage.\n");
1819 case AST_PBX_KEEPALIVE:
1820 /* We've been asked to keep alive, so do so */
1821 return AST_PBX_KEEPALIVE;
1823 case RESULT_FAILURE:
1824 /* They've already given the failure. We've been hung up on so handle this
1829 fdprintf(agi->fd, "510 Invalid or unknown command\n");
1834 static enum agi_result run_agi(struct ast_channel *chan, char *request, AGI *agi, int pid, int *status, int dead, int argc, char *argv[])
1836 struct ast_channel *c;
1839 enum agi_result returnstatus = AGI_RESULT_SUCCESS;
1840 struct ast_frame *f;
1843 /* how many times we'll retry if ast_waitfor_nandfs will return without either
1844 channel or file descriptor in case select is interrupted by a system call (EINTR) */
1847 if (!(readf = fdopen(agi->ctrl, "r"))) {
1848 ast_log(LOG_WARNING, "Unable to fdopen file descriptor\n");
1852 return AGI_RESULT_FAILURE;
1855 setup_env(chan, request, agi->fd, (agi->audio > -1), argc, argv);
1858 c = ast_waitfor_nandfds(&chan, dead ? 0 : 1, &agi->ctrl, 1, NULL, &outfd, &ms);
1861 /* Idle the channel until we get a command */
1865 ast_log(LOG_DEBUG, "%s hungup\n", chan->name);
1866 returnstatus = AGI_RESULT_HANGUP;
1869 /* If it's voice, write it to the audio pipe */
1870 if ((agi->audio > -1) && (f->frametype == AST_FRAME_VOICE)) {
1871 /* Write, ignoring errors */
1872 write(agi->audio, f->data, f->datalen);
1876 } else if (outfd > -1) {
1878 if (!fgets(buf, sizeof(buf), readf)) {
1879 /* Program terminated */
1882 if (option_verbose > 2)
1883 ast_verbose(VERBOSE_PREFIX_3 "AGI Script %s completed, returning %d\n", request, returnstatus);
1885 waitpid(pid, status, 0);
1886 /* No need to kill the pid anymore, since they closed us */
1890 /* get rid of trailing newline, if any */
1891 if (*buf && buf[strlen(buf) - 1] == '\n')
1892 buf[strlen(buf) - 1] = 0;
1894 ast_verbose("AGI Rx << %s\n", buf);
1895 returnstatus |= agi_handle_command(chan, agi, buf);
1896 /* If the handle_command returns -1, we need to stop */
1897 if ((returnstatus < 0) || (returnstatus == AST_PBX_KEEPALIVE)) {
1902 ast_log(LOG_WARNING, "No channel, no fd?\n");
1903 returnstatus = AGI_RESULT_FAILURE;
1908 /* Notify process */
1910 const char *sighup = pbx_builtin_getvar_helper(chan, "AGISIGHUP");
1911 if (ast_strlen_zero(sighup) || !ast_false(sighup)) {
1912 if (kill(pid, SIGHUP))
1913 ast_log(LOG_WARNING, "unable to send SIGHUP to AGI process %d: %s\n", pid, strerror(errno));
1917 return returnstatus;
1920 static int handle_showagi(int fd, int argc, char *argv[])
1922 struct agi_command *e;
1925 return RESULT_SHOWUSAGE;
1927 e = find_command(argv + 2, 1);
1929 ast_cli(fd, e->usage);
1931 if (find_command(argv + 2, -1)) {
1932 return help_workhorse(fd, argv + 1);
1934 ast_join(fullcmd, sizeof(fullcmd), argv+1);
1935 ast_cli(fd, "No such command '%s'.\n", fullcmd);
1939 return help_workhorse(fd, NULL);
1941 return RESULT_SUCCESS;
1944 static int handle_agidumphtml(int fd, int argc, char *argv[])
1946 struct agi_command *e;
1952 return RESULT_SHOWUSAGE;
1954 if (!(htmlfile = fopen(argv[2], "wt"))) {
1955 ast_cli(fd, "Could not create file '%s'\n", argv[2]);
1956 return RESULT_SHOWUSAGE;
1959 fprintf(htmlfile, "<HTML>\n<HEAD>\n<TITLE>AGI Commands</TITLE>\n</HEAD>\n");
1960 fprintf(htmlfile, "<BODY>\n<CENTER><B><H1>AGI Commands</H1></B></CENTER>\n\n");
1963 fprintf(htmlfile, "<TABLE BORDER=\"0\" CELLSPACING=\"10\">\n");
1965 for (x=0;x<sizeof(commands)/sizeof(commands[0]);x++) {
1966 char *stringp, *tempstr;
1969 if (!e->cmda[0]) /* end ? */
1971 /* Hide commands that start with '_' */
1972 if ((e->cmda[0])[0] == '_')
1974 ast_join(fullcmd, sizeof(fullcmd), e->cmda);
1976 fprintf(htmlfile, "<TR><TD><TABLE BORDER=\"1\" CELLPADDING=\"5\" WIDTH=\"100%%\">\n");
1977 fprintf(htmlfile, "<TR><TH ALIGN=\"CENTER\"><B>%s - %s</B></TD></TR>\n", fullcmd,e->summary);
1980 tempstr = strsep(&stringp, "\n");
1982 fprintf(htmlfile, "<TR><TD ALIGN=\"CENTER\">%s</TD></TR>\n", tempstr);
1984 fprintf(htmlfile, "<TR><TD ALIGN=\"CENTER\">\n");
1985 while ((tempstr = strsep(&stringp, "\n")) != NULL)
1986 fprintf(htmlfile, "%s<BR>\n",tempstr);
1987 fprintf(htmlfile, "</TD></TR>\n");
1988 fprintf(htmlfile, "</TABLE></TD></TR>\n\n");
1992 fprintf(htmlfile, "</TABLE>\n</BODY>\n</HTML>\n");
1994 ast_cli(fd, "AGI HTML Commands Dumped to: %s\n", argv[2]);
1995 return RESULT_SUCCESS;
1998 static int agi_exec_full(struct ast_channel *chan, void *data, int enhanced, int dead)
2000 enum agi_result res;
2001 struct ast_module_user *u;
2002 char *argv[MAX_ARGS];
2012 if (ast_strlen_zero(data)) {
2013 ast_log(LOG_WARNING, "AGI requires an argument (script)\n");
2016 ast_copy_string(buf, data, sizeof(buf));
2018 memset(&agi, 0, sizeof(agi));
2019 while ((stringp = strsep(&tmp, "|")) && argc < MAX_ARGS-1)
2020 argv[argc++] = stringp;
2023 u = ast_module_user_add(chan);
2025 /* Answer if need be */
2026 if (chan->_state != AST_STATE_UP) {
2027 if (ast_answer(chan)) {
2028 LOCAL_USER_REMOVE(u);
2033 res = launch_script(argv[0], argv, fds, enhanced ? &efd : NULL, &pid);
2034 if (res == AGI_RESULT_SUCCESS) {
2039 res = run_agi(chan, argv[0], &agi, pid, &status, dead, argc, argv);
2040 /* If the fork'd process returns non-zero, set AGISTATUS to FAILURE */
2041 if (res == AGI_RESULT_SUCCESS && status)
2042 res = AGI_RESULT_FAILURE;
2043 if (fds[1] != fds[0])
2047 ast_unreplace_sigchld();
2049 ast_module_user_remove(u);
2052 case AGI_RESULT_SUCCESS:
2053 pbx_builtin_setvar_helper(chan, "AGISTATUS", "SUCCESS");
2055 case AGI_RESULT_FAILURE:
2056 pbx_builtin_setvar_helper(chan, "AGISTATUS", "FAILURE");
2058 case AGI_RESULT_HANGUP:
2059 pbx_builtin_setvar_helper(chan, "AGISTATUS", "HANGUP");
2066 static int agi_exec(struct ast_channel *chan, void *data)
2068 if (chan->_softhangup)
2069 ast_log(LOG_WARNING, "If you want to run AGI on hungup channels you should use DeadAGI!\n");
2070 return agi_exec_full(chan, data, 0, 0);
2073 static int eagi_exec(struct ast_channel *chan, void *data)
2078 if (chan->_softhangup)
2079 ast_log(LOG_WARNING, "If you want to run AGI on hungup channels you should use DeadAGI!\n");
2080 readformat = chan->readformat;
2081 if (ast_set_read_format(chan, AST_FORMAT_SLINEAR)) {
2082 ast_log(LOG_WARNING, "Unable to set channel '%s' to linear mode\n", chan->name);
2085 res = agi_exec_full(chan, data, 1, 0);
2087 if (ast_set_read_format(chan, readformat)) {
2088 ast_log(LOG_WARNING, "Unable to restore channel '%s' to format %s\n", chan->name, ast_getformatname(readformat));
2094 static int deadagi_exec(struct ast_channel *chan, void *data)
2096 return agi_exec_full(chan, data, 0, 1);
2099 static char showagi_help[] =
2100 "Usage: agi show [topic]\n"
2101 " When called with a topic as an argument, displays usage\n"
2102 " information on the given command. If called without a\n"
2103 " topic, it provides a list of AGI commands.\n";
2106 static char dumpagihtml_help[] =
2107 "Usage: agi dumphtml <filename>\n"
2108 " Dumps the agi command list in html format to given filename\n";
2110 static struct ast_cli_entry cli_agi[] = {
2111 { { "agi", "debug", NULL },
2112 agi_do_debug, "Enable AGI debugging",
2115 { { "agi", "debug", "off", NULL },
2116 agi_no_debug, "Disable AGI debugging",
2119 { { "agi", "show", NULL },
2120 handle_showagi, "List AGI commands or specific help",
2123 { { "agi", "dumphtml", NULL },
2124 handle_agidumphtml, "Dumps a list of agi commands in html format",
2128 static int unload_module(void)
2130 ast_module_user_hangup_all();
2131 ast_cli_unregister_multiple(cli_agi, sizeof(cli_agi) / sizeof(struct ast_cli_entry));
2132 ast_unregister_application(eapp);
2133 ast_unregister_application(deadapp);
2134 return ast_unregister_application(app);
2137 static int load_module(void)
2139 ast_cli_register_multiple(cli_agi, sizeof(cli_agi) / sizeof(struct ast_cli_entry));
2140 ast_register_application(deadapp, deadagi_exec, deadsynopsis, descrip);
2141 ast_register_application(eapp, eagi_exec, esynopsis, descrip);
2142 return ast_register_application(app, agi_exec, synopsis, descrip);
2145 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Asterisk Gateway Interface (AGI)");