2 * Asterisk -- An open source telephony toolkit.
4 * Copyright (C) 1999 - 2006, Digium, Inc.
6 * Mark Spencer <markster@digium.com>
8 * See http://www.asterisk.org for more information about
9 * the Asterisk project. Please do not directly contact
10 * any of the maintainers of this project for assistance;
11 * the project provides a web site, mailing lists and IRC
12 * channels for your use.
14 * This program is free software, distributed under the terms of
15 * the GNU General Public License Version 2. See the LICENSE file
16 * at the top of the source tree.
21 * \brief AGI - the Asterisk Gateway Interface
23 * \author Mark Spencer <markster@digium.com>
26 #include <sys/types.h>
28 #include <sys/socket.h>
29 #include <netinet/in.h>
30 #include <netinet/tcp.h>
31 #include <arpa/inet.h>
45 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
47 #include "asterisk/file.h"
48 #include "asterisk/logger.h"
49 #include "asterisk/channel.h"
50 #include "asterisk/pbx.h"
51 #include "asterisk/module.h"
52 #include "asterisk/astdb.h"
53 #include "asterisk/callerid.h"
54 #include "asterisk/cli.h"
55 #include "asterisk/logger.h"
56 #include "asterisk/options.h"
57 #include "asterisk/image.h"
58 #include "asterisk/say.h"
59 #include "asterisk/app.h"
60 #include "asterisk/dsp.h"
61 #include "asterisk/musiconhold.h"
62 #include "asterisk/manager.h"
63 #include "asterisk/utils.h"
64 #include "asterisk/lock.h"
65 #include "asterisk/strings.h"
66 #include "asterisk/agi.h"
69 #define MAX_COMMANDS 128
71 /* Recycle some stuff from the CLI interface */
72 #define fdprintf agi_debug_cli
74 static char *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 "Returns -1 on hangup (except for DeadAGI) or if application requested\n"
91 " hangup, or 0 on non-hangup exit. \n"
92 "Using 'EAGI' provides enhanced AGI, with incoming audio available out of band\n"
93 "on file descriptor 3\n\n"
94 "Use the CLI command 'show agi' to list available agi commands\n";
96 static int agidebug = 0;
98 struct module_symbols *me;
100 #define TONE_BLOCK_SIZE 200
102 /* Max time to connect to an AGI remote host */
103 #define MAX_AGI_CONNECT 2000
105 #define AGI_PORT 4573
107 static void agi_debug_cli(int fd, char *fmt, ...)
114 res = vasprintf(&stuff, fmt, ap);
117 ast_log(LOG_ERROR, "Out of memory\n");
120 ast_verbose("AGI Tx >> %s", stuff);
121 ast_carefulwrite(fd, stuff, strlen(stuff), 100);
126 /* launch_netscript: The fastagi handler.
127 FastAGI defaults to port 4573 */
128 static int launch_netscript(char *agiurl, char *argv[], int *fds, int *efd, int *opid)
132 struct pollfd pfds[1];
134 char *c; int port = AGI_PORT;
136 struct sockaddr_in sin;
138 struct ast_hostent ahp;
140 /* agiusl is "agi://host.domain[:port][/script/name]" */
141 host = ast_strdupa(agiurl + 6); /* Remove agi:// */
144 /* Strip off any script name */
145 if ((c = strchr(host, '/'))) {
150 if ((c = strchr(host, ':'))) {
156 ast_log(LOG_WARNING, "AGI URI's don't support Enhanced AGI yet\n");
159 hp = ast_gethostbyname(host, &ahp);
161 ast_log(LOG_WARNING, "Unable to locate host '%s'\n", host);
164 s = socket(AF_INET, SOCK_STREAM, 0);
166 ast_log(LOG_WARNING, "Unable to create socket: %s\n", strerror(errno));
169 flags = fcntl(s, F_GETFL);
171 ast_log(LOG_WARNING, "Fcntl(F_GETFL) failed: %s\n", strerror(errno));
175 if (fcntl(s, F_SETFL, flags | O_NONBLOCK) < 0) {
176 ast_log(LOG_WARNING, "Fnctl(F_SETFL) failed: %s\n", strerror(errno));
180 memset(&sin, 0, sizeof(sin));
181 sin.sin_family = AF_INET;
182 sin.sin_port = htons(port);
183 memcpy(&sin.sin_addr, hp->h_addr, sizeof(sin.sin_addr));
184 if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) && (errno != EINPROGRESS)) {
185 ast_log(LOG_WARNING, "Connect failed with unexpected error: %s\n", strerror(errno));
191 pfds[0].events = POLLOUT;
192 while (poll(pfds, 1, MAX_AGI_CONNECT) != 1) {
193 if (errno != EINTR) {
194 ast_log(LOG_WARNING, "Connect to '%s' failed: %s\n", agiurl, strerror(errno));
199 /* XXX in theory should check for partial writes... */
200 while (write(s, "agi_network: yes\n", strlen("agi_network: yes\n")) < 0) {
201 if (errno != EINTR) {
202 ast_log(LOG_WARNING, "Connect to '%s' failed: %s\n", agiurl, strerror(errno));
208 /* If we have a script parameter, relay it to the fastagi server */
209 if (!ast_strlen_zero(script))
210 fdprintf(s, "agi_network_script: %s\n", script);
212 if (option_debug > 3)
213 ast_log(LOG_DEBUG, "Wow, connected!\n");
220 static int launch_script(char *script, char *argv[], int *fds, int *efd, int *opid)
231 if (!strncasecmp(script, "agi://", 6))
232 return launch_netscript(script, argv, fds, efd, opid);
234 if (script[0] != '/') {
235 snprintf(tmp, sizeof(tmp), "%s/%s", (char *)ast_config_AST_AGI_DIR, script);
239 ast_log(LOG_WARNING, "Unable to create toast pipe: %s\n",strerror(errno));
243 ast_log(LOG_WARNING, "unable to create fromast pipe: %s\n", strerror(errno));
250 ast_log(LOG_WARNING, "unable to create audio pipe: %s\n", strerror(errno));
257 res = fcntl(audio[1], F_GETFL);
259 res = fcntl(audio[1], F_SETFL, res | O_NONBLOCK);
261 ast_log(LOG_WARNING, "unable to set audio pipe parameters: %s\n", strerror(errno));
273 ast_log(LOG_WARNING, "Failed to fork(): %s\n", strerror(errno));
277 /* Pass paths to AGI via environmental variables */
278 setenv("AST_CONFIG_DIR", ast_config_AST_CONFIG_DIR, 1);
279 setenv("AST_CONFIG_FILE", ast_config_AST_CONFIG_FILE, 1);
280 setenv("AST_MODULE_DIR", ast_config_AST_MODULE_DIR, 1);
281 setenv("AST_SPOOL_DIR", ast_config_AST_SPOOL_DIR, 1);
282 setenv("AST_MONITOR_DIR", ast_config_AST_MONITOR_DIR, 1);
283 setenv("AST_VAR_DIR", ast_config_AST_VAR_DIR, 1);
284 setenv("AST_DATA_DIR", ast_config_AST_DATA_DIR, 1);
285 setenv("AST_LOG_DIR", ast_config_AST_LOG_DIR, 1);
286 setenv("AST_AGI_DIR", ast_config_AST_AGI_DIR, 1);
287 setenv("AST_KEY_DIR", ast_config_AST_KEY_DIR, 1);
288 setenv("AST_RUN_DIR", ast_config_AST_RUN_DIR, 1);
290 /* Redirect stdin and out, provide enhanced audio channel if desired */
291 dup2(fromast[0], STDIN_FILENO);
292 dup2(toast[1], STDOUT_FILENO);
294 dup2(audio[0], STDERR_FILENO + 1);
296 close(STDERR_FILENO + 1);
299 /* unblock important signal handlers */
300 if (sigfillset(&signal_set) || pthread_sigmask(SIG_UNBLOCK, &signal_set, NULL)) {
301 ast_log(LOG_WARNING, "unable to unblock signals for AGI script: %s\n", strerror(errno));
305 /* Close everything but stdin/out/error */
306 for (x=STDERR_FILENO + 2;x<1024;x++)
309 /* Don't run AGI scripts with realtime priority -- it causes audio stutter */
314 /* Can't use ast_log since FD's are closed */
315 fprintf(stdout, "verbose \"Failed to execute '%s': %s\" 2\n", script, strerror(errno));
319 if (option_verbose > 2)
320 ast_verbose(VERBOSE_PREFIX_3 "Launched AGI Script %s\n", script);
326 /* close what we're not using in the parent */
340 static void setup_env(struct ast_channel *chan, char *request, int fd, int enhanced)
342 /* Print initial environment, with agi_request always being the first
344 fdprintf(fd, "agi_request: %s\n", request);
345 fdprintf(fd, "agi_channel: %s\n", chan->name);
346 fdprintf(fd, "agi_language: %s\n", chan->language);
347 fdprintf(fd, "agi_type: %s\n", chan->tech->type);
348 fdprintf(fd, "agi_uniqueid: %s\n", chan->uniqueid);
351 fdprintf(fd, "agi_callerid: %s\n", S_OR(chan->cid.cid_num, "unknown"));
352 fdprintf(fd, "agi_calleridname: %s\n", S_OR(chan->cid.cid_name, "unknown"));
353 fdprintf(fd, "agi_callingpres: %d\n", chan->cid.cid_pres);
354 fdprintf(fd, "agi_callingani2: %d\n", chan->cid.cid_ani2);
355 fdprintf(fd, "agi_callington: %d\n", chan->cid.cid_ton);
356 fdprintf(fd, "agi_callingtns: %d\n", chan->cid.cid_tns);
357 fdprintf(fd, "agi_dnid: %s\n", S_OR(chan->cid.cid_dnid, "unknown"));
358 fdprintf(fd, "agi_rdnis: %s\n", S_OR(chan->cid.cid_rdnis, "unknown"));
360 /* Context information */
361 fdprintf(fd, "agi_context: %s\n", chan->context);
362 fdprintf(fd, "agi_extension: %s\n", chan->exten);
363 fdprintf(fd, "agi_priority: %d\n", chan->priority);
364 fdprintf(fd, "agi_enhanced: %s\n", enhanced ? "1.0" : "0.0");
366 /* User information */
367 fdprintf(fd, "agi_accountcode: %s\n", chan->accountcode ? chan->accountcode : "");
369 /* End with empty return */
373 static int handle_answer(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
377 if (chan->_state != AST_STATE_UP) {
378 /* Answer the chan */
379 res = ast_answer(chan);
381 fdprintf(agi->fd, "200 result=%d\n", res);
382 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
385 static int handle_waitfordigit(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
390 return RESULT_SHOWUSAGE;
391 if (sscanf(argv[3], "%d", &to) != 1)
392 return RESULT_SHOWUSAGE;
393 res = ast_waitfordigit_full(chan, to, agi->audio, agi->ctrl);
394 fdprintf(agi->fd, "200 result=%d\n", res);
395 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
398 static int handle_sendtext(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
402 return RESULT_SHOWUSAGE;
403 /* At the moment, the parser (perhaps broken) returns with
404 the last argument PLUS the newline at the end of the input
405 buffer. This probably needs to be fixed, but I wont do that
406 because other stuff may break as a result. The right way
407 would probably be to strip off the trailing newline before
408 parsing, then here, add a newline at the end of the string
409 before sending it to ast_sendtext --DUDE */
410 res = ast_sendtext(chan, argv[2]);
411 fdprintf(agi->fd, "200 result=%d\n", res);
412 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
415 static int handle_recvchar(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
419 return RESULT_SHOWUSAGE;
420 res = ast_recvchar(chan,atoi(argv[2]));
422 fdprintf(agi->fd, "200 result=%d (timeout)\n", res);
423 return RESULT_SUCCESS;
426 fdprintf(agi->fd, "200 result=%d\n", res);
427 return RESULT_SUCCESS;
430 fdprintf(agi->fd, "200 result=%d (hangup)\n", res);
431 return RESULT_FAILURE;
435 static int handle_recvtext(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
440 return RESULT_SHOWUSAGE;
441 buf = ast_recvtext(chan,atoi(argv[2]));
443 fdprintf(agi->fd, "200 result=1 (%s)\n", buf);
446 fdprintf(agi->fd, "200 result=-1\n");
448 return RESULT_SUCCESS;
451 static int handle_tddmode(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
455 return RESULT_SHOWUSAGE;
456 if (!strncasecmp(argv[2],"on",2))
460 if (!strncasecmp(argv[2],"mate",4))
462 if (!strncasecmp(argv[2],"tdd",3))
464 res = ast_channel_setoption(chan, AST_OPTION_TDD, &x, sizeof(char), 0);
465 if (res != RESULT_SUCCESS)
466 fdprintf(agi->fd, "200 result=0\n");
468 fdprintf(agi->fd, "200 result=1\n");
469 return RESULT_SUCCESS;
472 static int handle_sendimage(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
476 return RESULT_SHOWUSAGE;
477 res = ast_send_image(chan, argv[2]);
478 if (!ast_check_hangup(chan))
480 fdprintf(agi->fd, "200 result=%d\n", res);
481 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
484 static int handle_controlstreamfile(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
493 if (argc < 5 || argc > 9)
494 return RESULT_SHOWUSAGE;
496 if (!ast_strlen_zero(argv[4]))
501 if ((argc > 5) && (sscanf(argv[5], "%d", &skipms) != 1))
502 return RESULT_SHOWUSAGE;
504 if (argc > 6 && !ast_strlen_zero(argv[8]))
509 if (argc > 7 && !ast_strlen_zero(argv[8]))
514 if (argc > 8 && !ast_strlen_zero(argv[8]))
519 res = ast_control_streamfile(chan, argv[3], fwd, rev, stop, pause, NULL, skipms);
521 fdprintf(agi->fd, "200 result=%d\n", res);
523 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
526 static int handle_streamfile(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
529 struct ast_filestream *fs;
530 long sample_offset = 0;
533 if (argc < 4 || argc > 5)
534 return RESULT_SHOWUSAGE;
535 if ((argc > 4) && (sscanf(argv[4], "%ld", &sample_offset) != 1))
536 return RESULT_SHOWUSAGE;
538 fs = ast_openstream(chan, argv[2], chan->language);
540 fdprintf(agi->fd, "200 result=%d endpos=%ld\n", 0, sample_offset);
541 return RESULT_SUCCESS;
543 ast_seekstream(fs, 0, SEEK_END);
544 max_length = ast_tellstream(fs);
545 ast_seekstream(fs, sample_offset, SEEK_SET);
546 res = ast_applystream(chan, fs);
547 res = ast_playstream(fs);
549 fdprintf(agi->fd, "200 result=%d endpos=%ld\n", res, sample_offset);
550 return (res >= 0) ? RESULT_SHOWUSAGE : RESULT_FAILURE;
552 res = ast_waitstream_full(chan, argv[3], agi->audio, agi->ctrl);
553 /* this is to check for if ast_waitstream closed the stream, we probably are at
554 * the end of the stream, return that amount, else check for the amount */
555 sample_offset = (chan->stream) ? ast_tellstream(fs) : max_length;
556 ast_stopstream(chan);
558 /* Stop this command, don't print a result line, as there is a new command */
559 return RESULT_SUCCESS;
561 fdprintf(agi->fd, "200 result=%d endpos=%ld\n", res, sample_offset);
562 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
565 /* get option - really similar to the handle_streamfile, but with a timeout */
566 static int handle_getoption(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
569 struct ast_filestream *fs;
570 long sample_offset = 0;
573 char *edigits = NULL;
575 if ( argc < 4 || argc > 5 )
576 return RESULT_SHOWUSAGE;
582 timeout = atoi(argv[4]);
583 else if (chan->pbx->dtimeout) {
584 /* by default dtimeout is set to 5sec */
585 timeout = chan->pbx->dtimeout * 1000; /* in msec */
588 fs = ast_openstream(chan, argv[2], chan->language);
590 fdprintf(agi->fd, "200 result=%d endpos=%ld\n", 0, sample_offset);
591 ast_log(LOG_WARNING, "Unable to open %s\n", argv[2]);
592 return RESULT_SUCCESS;
594 if (option_verbose > 2)
595 ast_verbose(VERBOSE_PREFIX_3 "Playing '%s' (escape_digits=%s) (timeout %d)\n", argv[2], edigits, timeout);
597 ast_seekstream(fs, 0, SEEK_END);
598 max_length = ast_tellstream(fs);
599 ast_seekstream(fs, sample_offset, SEEK_SET);
600 res = ast_applystream(chan, fs);
601 res = ast_playstream(fs);
603 fdprintf(agi->fd, "200 result=%d endpos=%ld\n", res, sample_offset);
605 return RESULT_SHOWUSAGE;
607 return RESULT_FAILURE;
609 res = ast_waitstream_full(chan, argv[3], agi->audio, agi->ctrl);
610 /* this is to check for if ast_waitstream closed the stream, we probably are at
611 * the end of the stream, return that amount, else check for the amount */
612 sample_offset = (chan->stream)?ast_tellstream(fs):max_length;
613 ast_stopstream(chan);
615 /* Stop this command, don't print a result line, as there is a new command */
616 return RESULT_SUCCESS;
619 /* If the user didnt press a key, wait for digitTimeout*/
621 res = ast_waitfordigit_full(chan, timeout, agi->audio, agi->ctrl);
622 /* Make sure the new result is in the escape digits of the GET OPTION */
623 if ( !strchr(edigits,res) )
627 fdprintf(agi->fd, "200 result=%d endpos=%ld\n", res, sample_offset);
628 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
634 /*--- handle_saynumber: Say number in various language syntaxes ---*/
635 /* Need to add option for gender here as well. Coders wanted */
636 /* While waiting, we're sending a (char *) NULL. */
637 static int handle_saynumber(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
642 return RESULT_SHOWUSAGE;
643 if (sscanf(argv[2], "%d", &num) != 1)
644 return RESULT_SHOWUSAGE;
645 res = ast_say_number_full(chan, num, argv[3], chan->language, (char *) NULL, agi->audio, agi->ctrl);
647 return RESULT_SUCCESS;
648 fdprintf(agi->fd, "200 result=%d\n", res);
649 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
652 static int handle_saydigits(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
658 return RESULT_SHOWUSAGE;
659 if (sscanf(argv[2], "%d", &num) != 1)
660 return RESULT_SHOWUSAGE;
662 res = ast_say_digit_str_full(chan, argv[2], argv[3], chan->language, agi->audio, agi->ctrl);
663 if (res == 1) /* New command */
664 return RESULT_SUCCESS;
665 fdprintf(agi->fd, "200 result=%d\n", res);
666 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
669 static int handle_sayalpha(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
674 return RESULT_SHOWUSAGE;
676 res = ast_say_character_str_full(chan, argv[2], argv[3], chan->language, agi->audio, agi->ctrl);
677 if (res == 1) /* New command */
678 return RESULT_SUCCESS;
679 fdprintf(agi->fd, "200 result=%d\n", res);
680 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
683 static int handle_saydate(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
688 return RESULT_SHOWUSAGE;
689 if (sscanf(argv[2], "%d", &num) != 1)
690 return RESULT_SHOWUSAGE;
691 res = ast_say_date(chan, num, argv[3], chan->language);
693 return RESULT_SUCCESS;
694 fdprintf(agi->fd, "200 result=%d\n", res);
695 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
698 static int handle_saytime(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
703 return RESULT_SHOWUSAGE;
704 if (sscanf(argv[2], "%d", &num) != 1)
705 return RESULT_SHOWUSAGE;
706 res = ast_say_time(chan, num, argv[3], chan->language);
708 return RESULT_SUCCESS;
709 fdprintf(agi->fd, "200 result=%d\n", res);
710 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
713 static int handle_saydatetime(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
717 char *format, *zone=NULL;
720 return RESULT_SHOWUSAGE;
725 /* XXX this doesn't belong here, but in the 'say' module */
726 if (!strcasecmp(chan->language, "de")) {
727 format = "A dBY HMS";
729 format = "ABdY 'digits/at' IMp";
733 if (argc > 5 && !ast_strlen_zero(argv[5]))
736 if (ast_get_time_t(argv[2], &unixtime, 0, NULL))
737 return RESULT_SHOWUSAGE;
739 res = ast_say_date_with_format(chan, unixtime, argv[3], chan->language, format, zone);
741 return RESULT_SUCCESS;
743 fdprintf(agi->fd, "200 result=%d\n", res);
744 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
747 static int handle_sayphonetic(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
752 return RESULT_SHOWUSAGE;
754 res = ast_say_phonetic_str_full(chan, argv[2], argv[3], chan->language, agi->audio, agi->ctrl);
755 if (res == 1) /* New command */
756 return RESULT_SUCCESS;
757 fdprintf(agi->fd, "200 result=%d\n", res);
758 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
761 static int handle_getdata(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
769 return RESULT_SHOWUSAGE;
771 timeout = atoi(argv[3]);
778 res = ast_app_getdata_full(chan, argv[2], data, max, timeout, agi->audio, agi->ctrl);
779 if (res == 2) /* New command */
780 return RESULT_SUCCESS;
782 fdprintf(agi->fd, "200 result=%s (timeout)\n", data);
784 fdprintf(agi->fd, "200 result=-1\n");
786 fdprintf(agi->fd, "200 result=%s\n", data);
787 return RESULT_SUCCESS;
790 static int handle_setcontext(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
794 return RESULT_SHOWUSAGE;
795 ast_copy_string(chan->context, argv[2], sizeof(chan->context));
796 fdprintf(agi->fd, "200 result=0\n");
797 return RESULT_SUCCESS;
800 static int handle_setextension(struct ast_channel *chan, AGI *agi, int argc, char **argv)
803 return RESULT_SHOWUSAGE;
804 ast_copy_string(chan->exten, argv[2], sizeof(chan->exten));
805 fdprintf(agi->fd, "200 result=0\n");
806 return RESULT_SUCCESS;
809 static int handle_setpriority(struct ast_channel *chan, AGI *agi, int argc, char **argv)
813 return RESULT_SHOWUSAGE;
815 if (sscanf(argv[2], "%d", &pri) != 1) {
816 if ((pri = ast_findlabel_extension(chan, chan->context, chan->exten, argv[2], chan->cid.cid_num)) < 1)
817 return RESULT_SHOWUSAGE;
820 ast_explicit_goto(chan, NULL, NULL, pri);
821 fdprintf(agi->fd, "200 result=0\n");
822 return RESULT_SUCCESS;
825 static int handle_recordfile(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
827 struct ast_filestream *fs;
829 struct timeval start;
830 long sample_offset = 0;
834 struct ast_dsp *sildet=NULL; /* silence detector dsp */
835 int totalsilence = 0;
837 int silence = 0; /* amount of silence to allow */
838 int gotsilence = 0; /* did we timeout for silence? */
839 char *silencestr=NULL;
843 /* XXX EAGI FIXME XXX */
846 return RESULT_SHOWUSAGE;
847 if (sscanf(argv[5], "%d", &ms) != 1)
848 return RESULT_SHOWUSAGE;
851 silencestr = strchr(argv[6],'s');
852 if ((argc > 7) && (!silencestr))
853 silencestr = strchr(argv[7],'s');
854 if ((argc > 8) && (!silencestr))
855 silencestr = strchr(argv[8],'s');
858 if (strlen(silencestr) > 2) {
859 if ((silencestr[0] == 's') && (silencestr[1] == '=')) {
863 silence = atoi(silencestr);
871 rfmt = chan->readformat;
872 res = ast_set_read_format(chan, AST_FORMAT_SLINEAR);
874 ast_log(LOG_WARNING, "Unable to set to linear mode, giving up\n");
877 sildet = ast_dsp_new();
879 ast_log(LOG_WARNING, "Unable to create silence detector :(\n");
882 ast_dsp_set_threshold(sildet, 256);
885 /* backward compatibility, if no offset given, arg[6] would have been
886 * caught below and taken to be a beep, else if it is a digit then it is a
888 if ((argc >6) && (sscanf(argv[6], "%ld", &sample_offset) != 1) && (!strchr(argv[6], '=')))
889 res = ast_streamfile(chan, "beep", chan->language);
891 if ((argc > 7) && (!strchr(argv[7], '=')))
892 res = ast_streamfile(chan, "beep", chan->language);
895 res = ast_waitstream(chan, argv[4]);
897 fdprintf(agi->fd, "200 result=%d (randomerror) endpos=%ld\n", res, sample_offset);
899 fs = ast_writefile(argv[2], argv[3], NULL, O_CREAT | O_WRONLY | (sample_offset ? O_APPEND : 0), 0, 0644);
902 fdprintf(agi->fd, "200 result=%d (writefile)\n", res);
904 ast_dsp_free(sildet);
905 return RESULT_FAILURE;
909 ast_applystream(chan,fs);
910 /* really should have checks */
911 ast_seekstream(fs, sample_offset, SEEK_SET);
915 while ((ms < 0) || ast_tvdiff_ms(ast_tvnow(), start) < ms) {
916 res = ast_waitfor(chan, -1);
919 fdprintf(agi->fd, "200 result=%d (waitfor) endpos=%ld\n", res,sample_offset);
921 ast_dsp_free(sildet);
922 return RESULT_FAILURE;
926 fdprintf(agi->fd, "200 result=%d (hangup) endpos=%ld\n", 0, sample_offset);
929 ast_dsp_free(sildet);
930 return RESULT_FAILURE;
932 switch(f->frametype) {
934 if (strchr(argv[4], f->subclass)) {
935 /* This is an interrupting chracter, so rewind to chop off any small
936 amount of DTMF that may have been recorded
938 ast_stream_rewind(fs, 200);
940 sample_offset = ast_tellstream(fs);
941 fdprintf(agi->fd, "200 result=%d (dtmf) endpos=%ld\n", f->subclass, sample_offset);
945 ast_dsp_free(sildet);
946 return RESULT_SUCCESS;
949 case AST_FRAME_VOICE:
950 ast_writestream(fs, f);
951 /* this is a safe place to check progress since we know that fs
952 * is valid after a write, and it will then have our current
954 sample_offset = ast_tellstream(fs);
957 ast_dsp_silence(sildet, f, &dspsilence);
959 totalsilence = dspsilence;
963 if (totalsilence > silence) {
964 /* Ended happily with silence */
978 ast_stream_rewind(fs, silence-1000);
980 sample_offset = ast_tellstream(fs);
982 fdprintf(agi->fd, "200 result=%d (timeout) endpos=%ld\n", res, sample_offset);
987 res = ast_set_read_format(chan, rfmt);
989 ast_log(LOG_WARNING, "Unable to restore read format on '%s'\n", chan->name);
990 ast_dsp_free(sildet);
992 return RESULT_SUCCESS;
995 static int handle_autohangup(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
1000 return RESULT_SHOWUSAGE;
1001 if (sscanf(argv[2], "%d", &timeout) != 1)
1002 return RESULT_SHOWUSAGE;
1006 chan->whentohangup = time(NULL) + timeout;
1008 chan->whentohangup = 0;
1009 fdprintf(agi->fd, "200 result=0\n");
1010 return RESULT_SUCCESS;
1013 static int handle_hangup(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1015 struct ast_channel *c;
1017 /* no argument: hangup the current channel */
1018 ast_softhangup(chan,AST_SOFTHANGUP_EXPLICIT);
1019 fdprintf(agi->fd, "200 result=1\n");
1020 return RESULT_SUCCESS;
1021 } else if (argc == 2) {
1022 /* one argument: look for info on the specified channel */
1023 c = ast_get_channel_by_name_locked(argv[1]);
1025 /* we have a matching channel */
1026 ast_softhangup(c,AST_SOFTHANGUP_EXPLICIT);
1027 fdprintf(agi->fd, "200 result=1\n");
1028 ast_mutex_unlock(&c->lock);
1029 return RESULT_SUCCESS;
1031 /* if we get this far no channel name matched the argument given */
1032 fdprintf(agi->fd, "200 result=-1\n");
1033 return RESULT_SUCCESS;
1035 return RESULT_SHOWUSAGE;
1039 static int handle_exec(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1042 struct ast_app *app;
1045 return RESULT_SHOWUSAGE;
1047 if (option_verbose > 2)
1048 ast_verbose(VERBOSE_PREFIX_3 "AGI Script Executing Application: (%s) Options: (%s)\n", argv[1], argv[2]);
1050 app = pbx_findapp(argv[1]);
1053 res = pbx_exec(chan, app, argv[2]);
1055 ast_log(LOG_WARNING, "Could not find application (%s)\n", argv[1]);
1058 fdprintf(agi->fd, "200 result=%d\n", res);
1063 static int handle_setcallerid(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1066 char *l = NULL, *n = NULL;
1069 ast_copy_string(tmp, argv[2], sizeof(tmp));
1070 ast_callerid_parse(tmp, &n, &l);
1072 ast_shrink_phone_number(l);
1077 ast_set_callerid(chan, l, n, NULL);
1080 fdprintf(agi->fd, "200 result=1\n");
1081 return RESULT_SUCCESS;
1084 static int handle_channelstatus(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1086 struct ast_channel *c;
1088 /* no argument: supply info on the current channel */
1089 fdprintf(agi->fd, "200 result=%d\n", chan->_state);
1090 return RESULT_SUCCESS;
1091 } else if (argc == 3) {
1092 /* one argument: look for info on the specified channel */
1093 c = ast_get_channel_by_name_locked(argv[2]);
1095 fdprintf(agi->fd, "200 result=%d\n", c->_state);
1096 ast_mutex_unlock(&c->lock);
1097 return RESULT_SUCCESS;
1099 /* if we get this far no channel name matched the argument given */
1100 fdprintf(agi->fd, "200 result=-1\n");
1101 return RESULT_SUCCESS;
1103 return RESULT_SHOWUSAGE;
1107 static int handle_setvariable(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1110 pbx_builtin_setvar_helper(chan, argv[2], argv[3]);
1112 fdprintf(agi->fd, "200 result=1\n");
1113 return RESULT_SUCCESS;
1116 static int handle_getvariable(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1122 return RESULT_SHOWUSAGE;
1124 /* check if we want to execute an ast_custom_function */
1125 if (!ast_strlen_zero(argv[2]) && (argv[2][strlen(argv[2]) - 1] == ')')) {
1126 ret = ast_func_read(chan, argv[2], tempstr, sizeof(tempstr)) ? NULL : tempstr;
1128 pbx_retrieve_variable(chan, argv[2], &ret, tempstr, sizeof(tempstr), NULL);
1132 fdprintf(agi->fd, "200 result=1 (%s)\n", ret);
1134 fdprintf(agi->fd, "200 result=0\n");
1136 return RESULT_SUCCESS;
1139 static int handle_getvariablefull(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1141 char tmp[4096] = "";
1142 struct ast_channel *chan2=NULL;
1144 if ((argc != 4) && (argc != 5))
1145 return RESULT_SHOWUSAGE;
1147 chan2 = ast_get_channel_by_name_locked(argv[4]);
1151 if (chan) { /* XXX isn't this chan2 ? */
1152 pbx_substitute_variables_helper(chan2, argv[3], tmp, sizeof(tmp) - 1);
1153 fdprintf(agi->fd, "200 result=1 (%s)\n", tmp);
1155 fdprintf(agi->fd, "200 result=0\n");
1157 if (chan2 && (chan2 != chan))
1158 ast_mutex_unlock(&chan2->lock);
1159 return RESULT_SUCCESS;
1162 static int handle_verbose(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1168 return RESULT_SHOWUSAGE;
1171 sscanf(argv[2], "%d", &level);
1175 prefix = VERBOSE_PREFIX_4;
1178 prefix = VERBOSE_PREFIX_3;
1181 prefix = VERBOSE_PREFIX_2;
1185 prefix = VERBOSE_PREFIX_1;
1189 if (level <= option_verbose)
1190 ast_verbose("%s %s: %s\n", prefix, chan->data, argv[1]);
1192 fdprintf(agi->fd, "200 result=1\n");
1194 return RESULT_SUCCESS;
1197 static int handle_dbget(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1203 return RESULT_SHOWUSAGE;
1204 res = ast_db_get(argv[2], argv[3], tmp, sizeof(tmp));
1206 fdprintf(agi->fd, "200 result=0\n");
1208 fdprintf(agi->fd, "200 result=1 (%s)\n", tmp);
1210 return RESULT_SUCCESS;
1213 static int handle_dbput(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1218 return RESULT_SHOWUSAGE;
1219 res = ast_db_put(argv[2], argv[3], argv[4]);
1220 fdprintf(agi->fd, "200 result=%c\n", res ? '0' : '1');
1221 return RESULT_SUCCESS;
1224 static int handle_dbdel(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1229 return RESULT_SHOWUSAGE;
1230 res = ast_db_del(argv[2], argv[3]);
1231 fdprintf(agi->fd, "200 result=%c\n", res ? '0' : '1');
1232 return RESULT_SUCCESS;
1235 static int handle_dbdeltree(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1238 if ((argc < 3) || (argc > 4))
1239 return RESULT_SHOWUSAGE;
1241 res = ast_db_deltree(argv[2], argv[3]);
1243 res = ast_db_deltree(argv[2], NULL);
1245 fdprintf(agi->fd, "200 result=%c\n", res ? '0' : '1');
1246 return RESULT_SUCCESS;
1249 static char debug_usage[] =
1250 "Usage: agi debug\n"
1251 " Enables dumping of AGI transactions for debugging purposes\n";
1253 static char no_debug_usage[] =
1254 "Usage: agi no debug\n"
1255 " Disables dumping of AGI transactions for debugging purposes\n";
1257 static int agi_do_debug(int fd, int argc, char *argv[])
1260 return RESULT_SHOWUSAGE;
1262 ast_cli(fd, "AGI Debugging Enabled\n");
1263 return RESULT_SUCCESS;
1266 static int agi_no_debug(int fd, int argc, char *argv[])
1269 return RESULT_SHOWUSAGE;
1271 ast_cli(fd, "AGI Debugging Disabled\n");
1272 return RESULT_SUCCESS;
1275 static struct ast_cli_entry cli_debug =
1276 { { "agi", "debug", NULL }, agi_do_debug, "Enable AGI debugging", debug_usage };
1278 static struct ast_cli_entry cli_no_debug =
1279 { { "agi", "no", "debug", NULL }, agi_no_debug, "Disable AGI debugging", no_debug_usage };
1281 static int handle_noop(struct ast_channel *chan, AGI *agi, int arg, char *argv[])
1283 fdprintf(agi->fd, "200 result=0\n");
1284 return RESULT_SUCCESS;
1287 static int handle_setmusic(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
1289 if (!strncasecmp(argv[2], "on", 2))
1290 ast_moh_start(chan, argc > 3 ? argv[3] : NULL);
1291 else if (!strncasecmp(argv[2], "off", 3))
1293 fdprintf(agi->fd, "200 result=0\n");
1294 return RESULT_SUCCESS;
1297 static char usage_setmusic[] =
1298 " Usage: SET MUSIC ON <on|off> <class>\n"
1299 " Enables/Disables the music on hold generator. If <class> is\n"
1300 " not specified, then the default music on hold class will be used.\n"
1301 " Always returns 0.\n";
1303 static char usage_dbput[] =
1304 " Usage: DATABASE PUT <family> <key> <value>\n"
1305 " Adds or updates an entry in the Asterisk database for a\n"
1306 " given family, key, and value.\n"
1307 " Returns 1 if successful, 0 otherwise.\n";
1309 static char usage_dbget[] =
1310 " Usage: DATABASE GET <family> <key>\n"
1311 " Retrieves an entry in the Asterisk database for a\n"
1312 " given family and key.\n"
1313 " Returns 0 if <key> is not set. Returns 1 if <key>\n"
1314 " is set and returns the variable in parentheses.\n"
1315 " Example return code: 200 result=1 (testvariable)\n";
1317 static char usage_dbdel[] =
1318 " Usage: DATABASE DEL <family> <key>\n"
1319 " Deletes an entry in the Asterisk database for a\n"
1320 " given family and key.\n"
1321 " Returns 1 if successful, 0 otherwise.\n";
1323 static char usage_dbdeltree[] =
1324 " Usage: DATABASE DELTREE <family> [keytree]\n"
1325 " Deletes a family or specific keytree within a family\n"
1326 " in the Asterisk database.\n"
1327 " Returns 1 if successful, 0 otherwise.\n";
1329 static char usage_verbose[] =
1330 " Usage: VERBOSE <message> <level>\n"
1331 " Sends <message> to the console via verbose message system.\n"
1332 " <level> is the the verbose level (1-4)\n"
1333 " Always returns 1.\n";
1335 static char usage_getvariable[] =
1336 " Usage: GET VARIABLE <variablename>\n"
1337 " Returns 0 if <variablename> is not set. Returns 1 if <variablename>\n"
1338 " is set and returns the variable in parentheses.\n"
1339 " example return code: 200 result=1 (testvariable)\n";
1341 static char usage_getvariablefull[] =
1342 " Usage: GET FULL VARIABLE <variablename> [<channel name>]\n"
1343 " Returns 0 if <variablename> is not set or channel does not exist. Returns 1\n"
1344 "if <variablename> is set and returns the variable in parenthesis. Understands\n"
1345 "complex variable names and builtin variables, unlike GET VARIABLE.\n"
1346 " example return code: 200 result=1 (testvariable)\n";
1348 static char usage_setvariable[] =
1349 " Usage: SET VARIABLE <variablename> <value>\n";
1351 static char usage_channelstatus[] =
1352 " Usage: CHANNEL STATUS [<channelname>]\n"
1353 " Returns the status of the specified channel.\n"
1354 " If no channel name is given the returns the status of the\n"
1355 " current channel. Return values:\n"
1356 " 0 Channel is down and available\n"
1357 " 1 Channel is down, but reserved\n"
1358 " 2 Channel is off hook\n"
1359 " 3 Digits (or equivalent) have been dialed\n"
1360 " 4 Line is ringing\n"
1361 " 5 Remote end is ringing\n"
1363 " 7 Line is busy\n";
1365 static char usage_setcallerid[] =
1366 " Usage: SET CALLERID <number>\n"
1367 " Changes the callerid of the current channel.\n";
1369 static char usage_exec[] =
1370 " Usage: EXEC <application> <options>\n"
1371 " Executes <application> with given <options>.\n"
1372 " Returns whatever the application returns, or -2 on failure to find application\n";
1374 static char usage_hangup[] =
1375 " Usage: HANGUP [<channelname>]\n"
1376 " Hangs up the specified channel.\n"
1377 " If no channel name is given, hangs up the current channel\n";
1379 static char usage_answer[] =
1381 " Answers channel if not already in answer state. Returns -1 on\n"
1382 " channel failure, or 0 if successful.\n";
1384 static char usage_waitfordigit[] =
1385 " Usage: WAIT FOR DIGIT <timeout>\n"
1386 " Waits up to 'timeout' milliseconds for channel to receive a DTMF digit.\n"
1387 " Returns -1 on channel failure, 0 if no digit is received in the timeout, or\n"
1388 " the numerical value of the ascii of the digit if one is received. Use -1\n"
1389 " for the timeout value if you desire the call to block indefinitely.\n";
1391 static char usage_sendtext[] =
1392 " Usage: SEND TEXT \"<text to send>\"\n"
1393 " Sends the given text on a channel. Most channels do not support the\n"
1394 " transmission of text. Returns 0 if text is sent, or if the channel does not\n"
1395 " support text transmission. Returns -1 only on error/hangup. Text\n"
1396 " consisting of greater than one word should be placed in quotes since the\n"
1397 " command only accepts a single argument.\n";
1399 static char usage_recvchar[] =
1400 " Usage: RECEIVE CHAR <timeout>\n"
1401 " Receives a character of text on a channel. Specify timeout to be the\n"
1402 " maximum time to wait for input in milliseconds, or 0 for infinite. Most channels\n"
1403 " do not support the reception of text. Returns the decimal value of the character\n"
1404 " if one is received, or 0 if the channel does not support text reception. Returns\n"
1405 " -1 only on error/hangup.\n";
1407 static char usage_recvtext[] =
1408 " Usage: RECEIVE TEXT <timeout>\n"
1409 " Receives a string of text on a channel. Specify timeout to be the\n"
1410 " maximum time to wait for input in milliseconds, or 0 for infinite. Most channels\n"
1411 " do not support the reception of text. Returns -1 for failure or 1 for success, and the string in parentheses.\n";
1413 static char usage_tddmode[] =
1414 " Usage: TDD MODE <on|off>\n"
1415 " Enable/Disable TDD transmission/reception on a channel. Returns 1 if\n"
1416 " successful, or 0 if channel is not TDD-capable.\n";
1418 static char usage_sendimage[] =
1419 " Usage: SEND IMAGE <image>\n"
1420 " Sends the given image on a channel. Most channels do not support the\n"
1421 " transmission of images. Returns 0 if image is sent, or if the channel does not\n"
1422 " support image transmission. Returns -1 only on error/hangup. Image names\n"
1423 " should not include extensions.\n";
1425 static char usage_streamfile[] =
1426 " Usage: STREAM FILE <filename> <escape digits> [sample offset]\n"
1427 " Send the given file, allowing playback to be interrupted by the given\n"
1428 " digits, if any. Use double quotes for the digits if you wish none to be\n"
1429 " permitted. If sample offset is provided then the audio will seek to sample\n"
1430 " offset before play starts. Returns 0 if playback completes without a digit\n"
1431 " being pressed, or the ASCII numerical value of the digit if one was pressed,\n"
1432 " or -1 on error or if the channel was disconnected. Remember, the file\n"
1433 " extension must not be included in the filename.\n";
1435 static char usage_controlstreamfile[] =
1436 " Usage: CONTROL STREAM FILE <filename> <escape digits> [skipms] [ffchar] [rewchr] [pausechr]\n"
1437 " Send the given file, allowing playback to be controled by the given\n"
1438 " digits, if any. Use double quotes for the digits if you wish none to be\n"
1439 " permitted. Returns 0 if playback completes without a digit\n"
1440 " being pressed, or the ASCII numerical value of the digit if one was pressed,\n"
1441 " or -1 on error or if the channel was disconnected. Remember, the file\n"
1442 " extension must not be included in the filename.\n\n"
1443 " Note: ffchar and rewchar default to * and # respectively.\n";
1445 static char usage_getoption[] =
1446 " Usage: GET OPTION <filename> <escape_digits> [timeout]\n"
1447 " Behaves similar to STREAM FILE but used with a timeout option.\n";
1449 static char usage_saynumber[] =
1450 " Usage: SAY NUMBER <number> <escape digits>\n"
1451 " Say a given number, returning early if any of the given DTMF digits\n"
1452 " are received on the channel. Returns 0 if playback completes without a digit\n"
1453 " being pressed, or the ASCII numerical value of the digit if one was pressed or\n"
1454 " -1 on error/hangup.\n";
1456 static char usage_saydigits[] =
1457 " Usage: SAY DIGITS <number> <escape digits>\n"
1458 " Say a given digit string, returning early if any of the given DTMF digits\n"
1459 " are received on the channel. Returns 0 if playback completes without a digit\n"
1460 " being pressed, or the ASCII numerical value of the digit if one was pressed or\n"
1461 " -1 on error/hangup.\n";
1463 static char usage_sayalpha[] =
1464 " Usage: SAY ALPHA <number> <escape digits>\n"
1465 " Say a given character string, returning early if any of the given DTMF digits\n"
1466 " are received on the channel. Returns 0 if playback completes without a digit\n"
1467 " being pressed, or the ASCII numerical value of the digit if one was pressed or\n"
1468 " -1 on error/hangup.\n";
1470 static char usage_saydate[] =
1471 " Usage: SAY DATE <date> <escape digits>\n"
1472 " Say a given date, returning early if any of the given DTMF digits are\n"
1473 " received on the channel. <date> is number of seconds elapsed since 00:00:00\n"
1474 " on January 1, 1970, Coordinated Universal Time (UTC). Returns 0 if playback\n"
1475 " completes without a digit being pressed, or the ASCII numerical value of the\n"
1476 " digit if one was pressed or -1 on error/hangup.\n";
1478 static char usage_saytime[] =
1479 " Usage: SAY TIME <time> <escape digits>\n"
1480 " Say a given time, returning early if any of the given DTMF digits are\n"
1481 " received on the channel. <time> is number of seconds elapsed since 00:00:00\n"
1482 " on January 1, 1970, Coordinated Universal Time (UTC). Returns 0 if playback\n"
1483 " completes without a digit being pressed, or the ASCII numerical value of the\n"
1484 " digit if one was pressed or -1 on error/hangup.\n";
1486 static char usage_saydatetime[] =
1487 " Usage: SAY DATETIME <time> <escape digits> [format] [timezone]\n"
1488 " Say a given time, returning early if any of the given DTMF digits are\n"
1489 " received on the channel. <time> is number of seconds elapsed since 00:00:00\n"
1490 " on January 1, 1970, Coordinated Universal Time (UTC). [format] is the format\n"
1491 " the time should be said in. See voicemail.conf (defaults to \"ABdY\n"
1492 " 'digits/at' IMp\"). Acceptable values for [timezone] can be found in\n"
1493 " /usr/share/zoneinfo. Defaults to machine default. Returns 0 if playback\n"
1494 " completes without a digit being pressed, or the ASCII numerical value of the\n"
1495 " digit if one was pressed or -1 on error/hangup.\n";
1497 static char usage_sayphonetic[] =
1498 " Usage: SAY PHONETIC <string> <escape digits>\n"
1499 " Say a given character string with phonetics, returning early if any of the\n"
1500 " given DTMF digits are received on the channel. Returns 0 if playback\n"
1501 " completes without a digit pressed, the ASCII numerical value of the digit\n"
1502 " if one was pressed, or -1 on error/hangup.\n";
1504 static char usage_getdata[] =
1505 " Usage: GET DATA <file to be streamed> [timeout] [max digits]\n"
1506 " Stream the given file, and recieve DTMF data. Returns the digits received\n"
1507 "from the channel at the other end.\n";
1509 static char usage_setcontext[] =
1510 " Usage: SET CONTEXT <desired context>\n"
1511 " Sets the context for continuation upon exiting the application.\n";
1513 static char usage_setextension[] =
1514 " Usage: SET EXTENSION <new extension>\n"
1515 " Changes the extension for continuation upon exiting the application.\n";
1517 static char usage_setpriority[] =
1518 " Usage: SET PRIORITY <priority>\n"
1519 " Changes the priority for continuation upon exiting the application.\n"
1520 " The priority must be a valid priority or label.\n";
1522 static char usage_recordfile[] =
1523 " Usage: RECORD FILE <filename> <format> <escape digits> <timeout> \\\n"
1524 " [offset samples] [BEEP] [s=silence]\n"
1525 " Record to a file until a given dtmf digit in the sequence is received\n"
1526 " Returns -1 on hangup or error. The format will specify what kind of file\n"
1527 " will be recorded. The timeout is the maximum record time in milliseconds, or\n"
1528 " -1 for no timeout. \"Offset samples\" is optional, and, if provided, will seek\n"
1529 " to the offset without exceeding the end of the file. \"silence\" is the number\n"
1530 " of seconds of silence allowed before the function returns despite the\n"
1531 " lack of dtmf digits or reaching timeout. Silence value must be\n"
1532 " preceeded by \"s=\" and is also optional.\n";
1534 static char usage_autohangup[] =
1535 " Usage: SET AUTOHANGUP <time>\n"
1536 " Cause the channel to automatically hangup at <time> seconds in the\n"
1537 " future. Of course it can be hungup before then as well. Setting to 0 will\n"
1538 " cause the autohangup feature to be disabled on this channel.\n";
1540 static char usage_noop[] =
1544 static agi_command commands[MAX_COMMANDS] = {
1545 { { "answer", NULL }, handle_answer, "Answer channel", usage_answer },
1546 { { "channel", "status", NULL }, handle_channelstatus, "Returns status of the connected channel", usage_channelstatus },
1547 { { "database", "del", NULL }, handle_dbdel, "Removes database key/value", usage_dbdel },
1548 { { "database", "deltree", NULL }, handle_dbdeltree, "Removes database keytree/value", usage_dbdeltree },
1549 { { "database", "get", NULL }, handle_dbget, "Gets database value", usage_dbget },
1550 { { "database", "put", NULL }, handle_dbput, "Adds/updates database value", usage_dbput },
1551 { { "exec", NULL }, handle_exec, "Executes a given Application", usage_exec },
1552 { { "get", "data", NULL }, handle_getdata, "Prompts for DTMF on a channel", usage_getdata },
1553 { { "get", "full", "variable", NULL }, handle_getvariablefull, "Evaluates a channel expression", usage_getvariablefull },
1554 { { "get", "option", NULL }, handle_getoption, "Stream file, prompt for DTMF, with timeout", usage_getoption },
1555 { { "get", "variable", NULL }, handle_getvariable, "Gets a channel variable", usage_getvariable },
1556 { { "hangup", NULL }, handle_hangup, "Hangup the current channel", usage_hangup },
1557 { { "noop", NULL }, handle_noop, "Does nothing", usage_noop },
1558 { { "receive", "char", NULL }, handle_recvchar, "Receives one character from channels supporting it", usage_recvchar },
1559 { { "receive", "text", NULL }, handle_recvtext, "Receives text from channels supporting it", usage_recvtext },
1560 { { "record", "file", NULL }, handle_recordfile, "Records to a given file", usage_recordfile },
1561 { { "say", "alpha", NULL }, handle_sayalpha, "Says a given character string", usage_sayalpha },
1562 { { "say", "digits", NULL }, handle_saydigits, "Says a given digit string", usage_saydigits },
1563 { { "say", "number", NULL }, handle_saynumber, "Says a given number", usage_saynumber },
1564 { { "say", "phonetic", NULL }, handle_sayphonetic, "Says a given character string with phonetics", usage_sayphonetic },
1565 { { "say", "date", NULL }, handle_saydate, "Says a given date", usage_saydate },
1566 { { "say", "time", NULL }, handle_saytime, "Says a given time", usage_saytime },
1567 { { "say", "datetime", NULL }, handle_saydatetime, "Says a given time as specfied by the format given", usage_saydatetime },
1568 { { "send", "image", NULL }, handle_sendimage, "Sends images to channels supporting it", usage_sendimage },
1569 { { "send", "text", NULL }, handle_sendtext, "Sends text to channels supporting it", usage_sendtext },
1570 { { "set", "autohangup", NULL }, handle_autohangup, "Autohangup channel in some time", usage_autohangup },
1571 { { "set", "callerid", NULL }, handle_setcallerid, "Sets callerid for the current channel", usage_setcallerid },
1572 { { "set", "context", NULL }, handle_setcontext, "Sets channel context", usage_setcontext },
1573 { { "set", "extension", NULL }, handle_setextension, "Changes channel extension", usage_setextension },
1574 { { "set", "music", NULL }, handle_setmusic, "Enable/Disable Music on hold generator", usage_setmusic },
1575 { { "set", "priority", NULL }, handle_setpriority, "Set channel dialplan priority", usage_setpriority },
1576 { { "set", "variable", NULL }, handle_setvariable, "Sets a channel variable", usage_setvariable },
1577 { { "stream", "file", NULL }, handle_streamfile, "Sends audio file on channel", usage_streamfile },
1578 { { "control", "stream", "file", NULL }, handle_controlstreamfile, "Sends audio file on channel and allows the listner to control the stream", usage_controlstreamfile },
1579 { { "tdd", "mode", NULL }, handle_tddmode, "Toggles TDD mode (for the deaf)", usage_tddmode },
1580 { { "verbose", NULL }, handle_verbose, "Logs a message to the asterisk verbose log", usage_verbose },
1581 { { "wait", "for", "digit", NULL }, handle_waitfordigit, "Waits for a digit to be pressed", usage_waitfordigit },
1584 static int help_workhorse(int fd, char *match[])
1589 struct agi_command *e;
1591 ast_join(matchstr, sizeof(matchstr), match);
1592 for (x=0;x<sizeof(commands)/sizeof(commands[0]);x++) {
1596 /* Hide commands that start with '_' */
1597 if ((e->cmda[0])[0] == '_')
1599 ast_join(fullcmd, sizeof(fullcmd), e->cmda);
1600 if (match && strncasecmp(matchstr, fullcmd, strlen(matchstr)))
1602 ast_cli(fd, "%20.20s %s\n", fullcmd, e->summary);
1607 int agi_register(agi_command *agi)
1610 for (x=0; x<MAX_COMMANDS - 1; x++) {
1611 if (commands[x].cmda[0] == agi->cmda[0]) {
1612 ast_log(LOG_WARNING, "Command already registered!\n");
1616 for (x=0; x<MAX_COMMANDS - 1; x++) {
1617 if (!commands[x].cmda[0]) {
1622 ast_log(LOG_WARNING, "No more room for new commands!\n");
1626 void agi_unregister(agi_command *agi)
1629 for (x=0; x<MAX_COMMANDS - 1; x++) {
1630 if (commands[x].cmda[0] == agi->cmda[0]) {
1631 memset(&commands[x], 0, sizeof(agi_command));
1636 static agi_command *find_command(char *cmds[], int exact)
1642 for (x=0; x < sizeof(commands) / sizeof(commands[0]); x++) {
1643 if (!commands[x].cmda[0])
1645 /* start optimistic */
1647 for (y=0; match && cmds[y]; y++) {
1648 /* If there are no more words in the command (and we're looking for
1649 an exact match) or there is a difference between the two words,
1650 then this is not a match */
1651 if (!commands[x].cmda[y] && !exact)
1653 /* don't segfault if the next part of a command doesn't exist */
1654 if (!commands[x].cmda[y])
1656 if (strcasecmp(commands[x].cmda[y], cmds[y]))
1659 /* If more words are needed to complete the command then this is not
1660 a candidate (unless we're looking for a really inexact answer */
1661 if ((exact > -1) && commands[x].cmda[y])
1664 return &commands[x];
1670 static int parse_args(char *s, int *max, char *argv[])
1682 /* If it's escaped, put a literal quote */
1687 if (quoted && whitespace) {
1688 /* If we're starting a quote, coming off white space start a new word, too */
1696 if (!quoted && !escaped) {
1697 /* If we're not quoted, mark this as whitespace, and
1698 end the previous argument */
1702 /* Otherwise, just treat it as anything else */
1706 /* If we're escaped, print a literal, otherwise enable escaping */
1716 if (x >= MAX_ARGS -1) {
1717 ast_log(LOG_WARNING, "Too many arguments, truncating\n");
1720 /* Coming off of whitespace, start the next argument */
1729 /* Null terminate */
1736 static int agi_handle_command(struct ast_channel *chan, AGI *agi, char *buf)
1738 char *argv[MAX_ARGS];
1739 int argc = MAX_ARGS;
1743 parse_args(buf, &argc, argv);
1746 for (x=0; x<argc; x++)
1747 fprintf(stderr, "Got Arg%d: %s\n", x, argv[x]); }
1749 c = find_command(argv, 0);
1751 res = c->handler(chan, agi, argc, argv);
1753 case RESULT_SHOWUSAGE:
1754 fdprintf(agi->fd, "520-Invalid command syntax. Proper usage follows:\n");
1755 fdprintf(agi->fd, c->usage);
1756 fdprintf(agi->fd, "520 End of proper usage.\n");
1758 case AST_PBX_KEEPALIVE:
1759 /* We've been asked to keep alive, so do so */
1760 return AST_PBX_KEEPALIVE;
1762 case RESULT_FAILURE:
1763 /* They've already given the failure. We've been hung up on so handle this
1768 fdprintf(agi->fd, "510 Invalid or unknown command\n");
1773 static int run_agi(struct ast_channel *chan, char *request, AGI *agi, int pid, int dead)
1775 struct ast_channel *c;
1778 int returnstatus = 0;
1779 struct ast_frame *f;
1782 /* how many times we'll retry if ast_waitfor_nandfs will return without either
1783 channel or file descriptor in case select is interrupted by a system call (EINTR) */
1786 if (!(readf = fdopen(agi->ctrl, "r"))) {
1787 ast_log(LOG_WARNING, "Unable to fdopen file descriptor\n");
1794 setup_env(chan, request, agi->fd, (agi->audio > -1));
1797 c = ast_waitfor_nandfds(&chan, dead ? 0 : 1, &agi->ctrl, 1, NULL, &outfd, &ms);
1800 /* Idle the channel until we get a command */
1803 ast_log(LOG_DEBUG, "%s hungup\n", chan->name);
1807 /* If it's voice, write it to the audio pipe */
1808 if ((agi->audio > -1) && (f->frametype == AST_FRAME_VOICE)) {
1809 /* Write, ignoring errors */
1810 write(agi->audio, f->data, f->datalen);
1814 } else if (outfd > -1) {
1816 if (!fgets(buf, sizeof(buf), readf)) {
1817 /* Program terminated */
1820 if (option_verbose > 2)
1821 ast_verbose(VERBOSE_PREFIX_3 "AGI Script %s completed, returning %d\n", request, returnstatus);
1822 /* No need to kill the pid anymore, since they closed us */
1826 /* get rid of trailing newline, if any */
1827 if (*buf && buf[strlen(buf) - 1] == '\n')
1828 buf[strlen(buf) - 1] = 0;
1830 ast_verbose("AGI Rx << %s\n", buf);
1831 returnstatus |= agi_handle_command(chan, agi, buf);
1832 /* If the handle_command returns -1, we need to stop */
1833 if ((returnstatus < 0) || (returnstatus == AST_PBX_KEEPALIVE)) {
1838 ast_log(LOG_WARNING, "No channel, no fd?\n");
1844 /* Notify process */
1846 if (kill(pid, SIGHUP))
1847 ast_log(LOG_WARNING, "unable to send SIGHUP to AGI process %d: %s\n", pid, strerror(errno));
1850 return returnstatus;
1853 static int handle_showagi(int fd, int argc, char *argv[])
1855 struct agi_command *e;
1858 return RESULT_SHOWUSAGE;
1860 e = find_command(argv + 2, 1);
1862 ast_cli(fd, e->usage);
1864 if (find_command(argv + 2, -1)) {
1865 return help_workhorse(fd, argv + 1);
1867 ast_join(fullcmd, sizeof(fullcmd), argv+1);
1868 ast_cli(fd, "No such command '%s'.\n", fullcmd);
1872 return help_workhorse(fd, NULL);
1874 return RESULT_SUCCESS;
1877 static int handle_dumpagihtml(int fd, int argc, char *argv[])
1879 struct agi_command *e;
1885 return RESULT_SHOWUSAGE;
1887 if (!(htmlfile = fopen(argv[2], "wt"))) {
1888 ast_cli(fd, "Could not create file '%s'\n", argv[2]);
1889 return RESULT_SHOWUSAGE;
1892 fprintf(htmlfile, "<HTML>\n<HEAD>\n<TITLE>AGI Commands</TITLE>\n</HEAD>\n");
1893 fprintf(htmlfile, "<BODY>\n<CENTER><B><H1>AGI Commands</H1></B></CENTER>\n\n");
1896 fprintf(htmlfile, "<TABLE BORDER=\"0\" CELLSPACING=\"10\">\n");
1898 for (x=0;x<sizeof(commands)/sizeof(commands[0]);x++) {
1899 char *stringp, *tempstr;
1902 if (!e->cmda[0]) /* end ? */
1904 /* Hide commands that start with '_' */
1905 if ((e->cmda[0])[0] == '_')
1907 ast_join(fullcmd, sizeof(fullcmd), e->cmda);
1909 fprintf(htmlfile, "<TR><TD><TABLE BORDER=\"1\" CELLPADDING=\"5\" WIDTH=\"100%%\">\n");
1910 fprintf(htmlfile, "<TR><TH ALIGN=\"CENTER\"><B>%s - %s</B></TD></TR>\n", fullcmd,e->summary);
1913 tempstr = strsep(&stringp, "\n");
1915 fprintf(htmlfile, "<TR><TD ALIGN=\"CENTER\">%s</TD></TR>\n", tempstr);
1917 fprintf(htmlfile, "<TR><TD ALIGN=\"CENTER\">\n");
1918 while ((tempstr = strsep(&stringp, "\n")) != NULL)
1919 fprintf(htmlfile, "%s<BR>\n",tempstr);
1920 fprintf(htmlfile, "</TD></TR>\n");
1921 fprintf(htmlfile, "</TABLE></TD></TR>\n\n");
1925 fprintf(htmlfile, "</TABLE>\n</BODY>\n</HTML>\n");
1927 ast_cli(fd, "AGI HTML Commands Dumped to: %s\n", argv[2]);
1928 return RESULT_SUCCESS;
1931 static int agi_exec_full(struct ast_channel *chan, void *data, int enhanced, int dead)
1934 struct localuser *u;
1935 char *argv[MAX_ARGS];
1937 char *tmp = (char *)buf;
1945 if (ast_strlen_zero(data)) {
1946 ast_log(LOG_WARNING, "AGI requires an argument (script)\n");
1949 ast_copy_string(buf, data, sizeof(buf));
1951 memset(&agi, 0, sizeof(agi));
1952 while ((stringp = strsep(&tmp, "|")) && argc < MAX_ARGS-1)
1953 argv[argc++] = stringp;
1956 u = ast_localuser_add(me, chan);
1958 /* Answer if need be */
1959 if (chan->_state != AST_STATE_UP) {
1960 if (ast_answer(chan)) {
1961 LOCAL_USER_REMOVE(u);
1966 res = launch_script(argv[0], argv, fds, enhanced ? &efd : NULL, &pid);
1971 res = run_agi(chan, argv[0], &agi, pid, dead);
1976 ast_localuser_remove(me, u);
1980 static int agi_exec(struct ast_channel *chan, void *data)
1982 if (chan->_softhangup)
1983 ast_log(LOG_WARNING, "If you want to run AGI on hungup channels you should use DeadAGI!\n");
1984 return agi_exec_full(chan, data, 0, 0);
1987 static int eagi_exec(struct ast_channel *chan, void *data)
1992 if (chan->_softhangup)
1993 ast_log(LOG_WARNING, "If you want to run AGI on hungup channels you should use DeadAGI!\n");
1994 readformat = chan->readformat;
1995 if (ast_set_read_format(chan, AST_FORMAT_SLINEAR)) {
1996 ast_log(LOG_WARNING, "Unable to set channel '%s' to linear mode\n", chan->name);
1999 res = agi_exec_full(chan, data, 1, 0);
2001 if (ast_set_read_format(chan, readformat)) {
2002 ast_log(LOG_WARNING, "Unable to restore channel '%s' to format %s\n", chan->name, ast_getformatname(readformat));
2008 static int deadagi_exec(struct ast_channel *chan, void *data)
2010 return agi_exec_full(chan, data, 0, 1);
2013 static char showagi_help[] =
2014 "Usage: show agi [topic]\n"
2015 " When called with a topic as an argument, displays usage\n"
2016 " information on the given command. If called without a\n"
2017 " topic, it provides a list of AGI commands.\n";
2020 static char dumpagihtml_help[] =
2021 "Usage: dump agihtml <filename>\n"
2022 " Dumps the agi command list in html format to given filename\n";
2024 static struct ast_cli_entry showagi =
2025 { { "show", "agi", NULL }, handle_showagi, "Show AGI commands or specific help", showagi_help };
2027 static struct ast_cli_entry dumpagihtml =
2028 { { "dump", "agihtml", NULL }, handle_dumpagihtml, "Dumps a list of agi command in html format", dumpagihtml_help };
2030 static int unload_module(void *mod)
2032 ast_hangup_localusers(mod);
2033 ast_cli_unregister(&showagi);
2034 ast_cli_unregister(&dumpagihtml);
2035 ast_cli_unregister(&cli_debug);
2036 ast_cli_unregister(&cli_no_debug);
2037 ast_unregister_application(eapp);
2038 ast_unregister_application(deadapp);
2039 return ast_unregister_application(app);
2042 static int load_module(void *mod)
2045 ast_cli_register(&showagi);
2046 ast_cli_register(&dumpagihtml);
2047 ast_cli_register(&cli_debug);
2048 ast_cli_register(&cli_no_debug);
2049 ast_register_application(deadapp, deadagi_exec, deadsynopsis, descrip);
2050 ast_register_application(eapp, eagi_exec, esynopsis, descrip);
2051 return ast_register_application(app, agi_exec, synopsis, descrip);
2054 static const char *description(void)
2056 return "Asterisk Gateway Interface (AGI)";
2059 static const char *key(void)
2061 return ASTERISK_GPL_KEY;
2064 STD_MOD(MOD_0, NULL, NULL, NULL);