2 * Asterisk -- A telephony toolkit for Linux.
4 * Asterisk Gateway Interface
6 * Copyright (C) 1999 - 2005, Digium, Inc.
8 * Mark Spencer <markster@digium.com>
10 * This program is free software, distributed under the terms of
11 * the GNU General Public License
14 #include <sys/types.h>
16 #include <sys/socket.h>
17 #include <netinet/in.h>
18 #include <netinet/tcp.h>
19 #include <arpa/inet.h>
20 #include "asterisk/file.h"
21 #include "asterisk/logger.h"
22 #include "asterisk/channel.h"
23 #include "asterisk/pbx.h"
24 #include "asterisk/module.h"
25 #include "asterisk/astdb.h"
26 #include "asterisk/callerid.h"
37 #include "asterisk/cli.h"
38 #include "asterisk/logger.h"
39 #include "asterisk/options.h"
40 #include "asterisk/image.h"
41 #include "asterisk/say.h"
42 #include "asterisk/app.h"
43 #include "asterisk/dsp.h"
44 #include "asterisk/musiconhold.h"
45 #include "asterisk/manager.h"
46 #include "asterisk/utils.h"
47 #include "asterisk/lock.h"
48 #include "asterisk/agi.h"
52 #include "asterisk/astmm.h"
56 #define MAX_COMMANDS 128
58 /* Recycle some stuff from the CLI interface */
59 #define fdprintf agi_debug_cli
61 static char *tdesc = "Asterisk Gateway Interface (AGI)";
63 static char *app = "AGI";
65 static char *eapp = "EAGI";
67 static char *deadapp = "DeadAGI";
69 static char *synopsis = "Executes an AGI compliant application";
70 static char *esynopsis = "Executes an EAGI compliant application";
71 static char *deadsynopsis = "Executes AGI on a hungup channel";
73 static char *descrip =
74 " [E|Dead]AGI(command|args): Executes an Asterisk Gateway Interface compliant\n"
75 "program on a channel. AGI allows Asterisk to launch external programs\n"
76 "written in any language to control a telephony channel, play audio,\n"
77 "read DTMF digits, etc. by communicating with the AGI protocol on stdin\n"
79 "Returns -1 on hangup (except for DeadAGI) or if application requested\n"
80 " hangup, or 0 on non-hangup exit. \n"
81 "Using 'EAGI' provides enhanced AGI, with incoming audio available out of band"
82 "on file descriptor 3\n\n"
83 "Use the CLI command 'show agi' to list available agi commands\n";
85 static int agidebug = 0;
92 #define TONE_BLOCK_SIZE 200
94 /* Max time to connect to an AGI remote host */
95 #define MAX_AGI_CONNECT 2000
99 static void agi_debug_cli(int fd, char *fmt, ...)
106 res = vasprintf(&stuff, fmt, ap);
109 ast_log(LOG_ERROR, "Out of memory\n");
112 ast_verbose("AGI Tx >> %s", stuff);
113 ast_carefulwrite(fd, stuff, strlen(stuff), 100);
118 /* launch_netscript: The fastagi handler.
119 FastAGI defaults to port 4573 */
120 static int launch_netscript(char *agiurl, char *argv[], int *fds, int *efd, int *opid)
124 struct pollfd pfds[1];
126 char *c; int port = AGI_PORT;
128 struct sockaddr_in sin;
130 struct ast_hostent ahp;
132 host = ast_strdupa(agiurl + 6); /* Remove agi:// */
135 /* Strip off any script name */
136 if ((c = strchr(host, '/'))) {
141 if ((c = strchr(host, ':'))) {
147 ast_log(LOG_WARNING, "AGI URI's don't support Enhanced AGI yet\n");
150 hp = ast_gethostbyname(host, &ahp);
152 ast_log(LOG_WARNING, "Unable to locate host '%s'\n", host);
155 s = socket(AF_INET, SOCK_STREAM, 0);
157 ast_log(LOG_WARNING, "Unable to create socket: %s\n", strerror(errno));
160 flags = fcntl(s, F_GETFL);
162 ast_log(LOG_WARNING, "Fcntl(F_GETFL) failed: %s\n", strerror(errno));
166 if (fcntl(s, F_SETFL, flags | O_NONBLOCK) < 0) {
167 ast_log(LOG_WARNING, "Fnctl(F_SETFL) failed: %s\n", strerror(errno));
171 memset(&sin, 0, sizeof(sin));
172 sin.sin_family = AF_INET;
173 sin.sin_port = htons(port);
174 memcpy(&sin.sin_addr, hp->h_addr, sizeof(sin.sin_addr));
175 if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) && (errno != EINPROGRESS)) {
176 ast_log(LOG_WARNING, "Connect failed with unexpected error: %s\n", strerror(errno));
181 pfds[0].events = POLLOUT;
182 if (poll(pfds, 1, MAX_AGI_CONNECT) != 1) {
183 ast_log(LOG_WARNING, "Connect to '%s' failed!\n", agiurl);
187 if (write(s, "agi_network: yes\n", strlen("agi_network: yes\n")) < 0) {
188 ast_log(LOG_WARNING, "Connect to '%s' failed: %s\n", agiurl, strerror(errno));
193 /* If we have a script parameter, relay it to the fastagi server */
194 if (!ast_strlen_zero(script))
195 fdprintf(s, "agi_network_script: %s\n", script);
197 if (option_debug > 3)
198 ast_log(LOG_DEBUG, "Wow, connected!\n");
205 static int launch_script(char *script, char *argv[], int *fds, int *efd, int *opid)
215 if (!strncasecmp(script, "agi://", 6))
216 return launch_netscript(script, argv, fds, efd, opid);
218 if (script[0] != '/') {
219 snprintf(tmp, sizeof(tmp), "%s/%s", (char *)ast_config_AST_AGI_DIR, script);
223 ast_log(LOG_WARNING, "Unable to create toast pipe: %s\n",strerror(errno));
227 ast_log(LOG_WARNING, "unable to create fromast pipe: %s\n", strerror(errno));
234 ast_log(LOG_WARNING, "unable to create audio pipe: %s\n", strerror(errno));
241 res = fcntl(audio[1], F_GETFL);
243 res = fcntl(audio[1], F_SETFL, res | O_NONBLOCK);
245 ast_log(LOG_WARNING, "unable to set audio pipe parameters: %s\n", strerror(errno));
257 ast_log(LOG_WARNING, "Failed to fork(): %s\n", strerror(errno));
261 /* Redirect stdin and out, provide enhanced audio channel if desired */
262 dup2(fromast[0], STDIN_FILENO);
263 dup2(toast[1], STDOUT_FILENO);
265 dup2(audio[0], STDERR_FILENO + 1);
267 close(STDERR_FILENO + 1);
269 /* Close everything but stdin/out/error */
270 for (x=STDERR_FILENO + 2;x<1024;x++)
274 /* Can't use ast_log since FD's are closed */
275 fprintf(stderr, "Failed to execute '%s': %s\n", script, strerror(errno));
278 if (option_verbose > 2)
279 ast_verbose(VERBOSE_PREFIX_3 "Launched AGI Script %s\n", script);
285 /* close what we're not using in the parent */
299 static void setup_env(struct ast_channel *chan, char *request, int fd, int enhanced)
301 /* Print initial environment, with agi_request always being the first
303 fdprintf(fd, "agi_request: %s\n", request);
304 fdprintf(fd, "agi_channel: %s\n", chan->name);
305 fdprintf(fd, "agi_language: %s\n", chan->language);
306 fdprintf(fd, "agi_type: %s\n", chan->type);
307 fdprintf(fd, "agi_uniqueid: %s\n", chan->uniqueid);
310 fdprintf(fd, "agi_callerid: %s\n", chan->cid.cid_num ? chan->cid.cid_num : "unknown");
311 fdprintf(fd, "agi_calleridname: %s\n", chan->cid.cid_name ? chan->cid.cid_name : "unknown");
312 fdprintf(fd, "agi_callingpres: %d\n", chan->cid.cid_pres);
313 fdprintf(fd, "agi_callingani2: %d\n", chan->cid.cid_ani2);
314 fdprintf(fd, "agi_callington: %d\n", chan->cid.cid_ton);
315 fdprintf(fd, "agi_callingtns: %d\n", chan->cid.cid_tns);
316 fdprintf(fd, "agi_dnid: %s\n", chan->cid.cid_dnid ? chan->cid.cid_dnid : "unknown");
317 fdprintf(fd, "agi_rdnis: %s\n", chan->cid.cid_rdnis ? chan->cid.cid_rdnis : "unknown");
319 /* Context information */
320 fdprintf(fd, "agi_context: %s\n", chan->context);
321 fdprintf(fd, "agi_extension: %s\n", chan->exten);
322 fdprintf(fd, "agi_priority: %d\n", chan->priority);
323 fdprintf(fd, "agi_enhanced: %s\n", enhanced ? "1.0" : "0.0");
325 /* User information */
326 fdprintf(fd, "agi_accountcode: %s\n", chan->accountcode ? chan->accountcode : "");
328 /* End with empty return */
332 static int handle_answer(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
336 if (chan->_state != AST_STATE_UP) {
337 /* Answer the chan */
338 res = ast_answer(chan);
340 fdprintf(agi->fd, "200 result=%d\n", res);
342 return RESULT_SUCCESS;
344 return RESULT_FAILURE;
347 static int handle_waitfordigit(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
352 return RESULT_SHOWUSAGE;
353 if (sscanf(argv[3], "%i", &to) != 1)
354 return RESULT_SHOWUSAGE;
355 res = ast_waitfordigit_full(chan, to, agi->audio, agi->ctrl);
356 fdprintf(agi->fd, "200 result=%d\n", res);
358 return RESULT_SUCCESS;
360 return RESULT_FAILURE;
363 static int handle_sendtext(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
367 return RESULT_SHOWUSAGE;
368 /* At the moment, the parser (perhaps broken) returns with
369 the last argument PLUS the newline at the end of the input
370 buffer. This probably needs to be fixed, but I wont do that
371 because other stuff may break as a result. The right way
372 would probably be to strip off the trailing newline before
373 parsing, then here, add a newline at the end of the string
374 before sending it to ast_sendtext --DUDE */
375 res = ast_sendtext(chan, argv[2]);
376 fdprintf(agi->fd, "200 result=%d\n", res);
378 return RESULT_SUCCESS;
380 return RESULT_FAILURE;
383 static int handle_recvchar(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
387 return RESULT_SHOWUSAGE;
388 res = ast_recvchar(chan,atoi(argv[2]));
390 fdprintf(agi->fd, "200 result=%d (timeout)\n", res);
391 return RESULT_SUCCESS;
394 fdprintf(agi->fd, "200 result=%d\n", res);
395 return RESULT_SUCCESS;
398 fdprintf(agi->fd, "200 result=%d (hangup)\n", res);
399 return RESULT_FAILURE;
403 static int handle_tddmode(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
407 return RESULT_SHOWUSAGE;
408 if (!strncasecmp(argv[2],"on",2))
412 if (!strncasecmp(argv[2],"mate",4))
414 if (!strncasecmp(argv[2],"tdd",3))
416 res = ast_channel_setoption(chan, AST_OPTION_TDD, &x, sizeof(char), 0);
417 fdprintf(agi->fd, "200 result=%d\n", res);
419 return RESULT_SUCCESS;
421 return RESULT_FAILURE;
424 static int handle_sendimage(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
428 return RESULT_SHOWUSAGE;
429 res = ast_send_image(chan, argv[2]);
430 if (!ast_check_hangup(chan))
432 fdprintf(agi->fd, "200 result=%d\n", res);
434 return RESULT_SUCCESS;
436 return RESULT_FAILURE;
439 static int handle_streamfile(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
442 struct ast_filestream *fs;
443 long sample_offset = 0;
447 return RESULT_SHOWUSAGE;
449 return RESULT_SHOWUSAGE;
450 if ((argc > 4) && (sscanf(argv[4], "%ld", &sample_offset) != 1))
451 return RESULT_SHOWUSAGE;
453 fs = ast_openstream(chan, argv[2], chan->language);
455 fdprintf(agi->fd, "200 result=%d endpos=%ld\n", 0, sample_offset);
456 return RESULT_SUCCESS;
458 ast_seekstream(fs, 0, SEEK_END);
459 max_length = ast_tellstream(fs);
460 ast_seekstream(fs, sample_offset, SEEK_SET);
461 res = ast_applystream(chan, fs);
462 res = ast_playstream(fs);
464 fdprintf(agi->fd, "200 result=%d endpos=%ld\n", res, sample_offset);
466 return RESULT_SHOWUSAGE;
468 return RESULT_FAILURE;
470 res = ast_waitstream_full(chan, argv[3], agi->audio, agi->ctrl);
471 /* this is to check for if ast_waitstream closed the stream, we probably are at
472 * the end of the stream, return that amount, else check for the amount */
473 sample_offset = (chan->stream) ? ast_tellstream(fs) : max_length;
474 ast_stopstream(chan);
476 /* Stop this command, don't print a result line, as there is a new command */
477 return RESULT_SUCCESS;
479 fdprintf(agi->fd, "200 result=%d endpos=%ld\n", res, sample_offset);
481 return RESULT_SUCCESS;
483 return RESULT_FAILURE;
486 /* get option - really similar to the handle_streamfile, but with a timeout */
487 static int handle_getoption(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
490 struct ast_filestream *fs;
491 long sample_offset = 0;
494 char *edigits = NULL;
496 if ( argc < 4 || argc > 5 )
497 return RESULT_SHOWUSAGE;
503 timeout = atoi(argv[4]);
504 else if (chan->pbx->dtimeout) {
505 /* by default dtimeout is set to 5sec */
506 timeout = chan->pbx->dtimeout * 1000; /* in msec */
509 fs = ast_openstream(chan, argv[2], chan->language);
511 fdprintf(agi->fd, "200 result=%d endpos=%ld\n", 0, sample_offset);
512 ast_log(LOG_WARNING, "Unable to open %s\n", argv[2]);
513 return RESULT_SUCCESS;
515 if (option_verbose > 2)
516 ast_verbose(VERBOSE_PREFIX_3 "Playing '%s' (escape_digits=%s) (timeout %d)\n", argv[2], edigits, timeout);
518 ast_seekstream(fs, 0, SEEK_END);
519 max_length = ast_tellstream(fs);
520 ast_seekstream(fs, sample_offset, SEEK_SET);
521 res = ast_applystream(chan, fs);
522 res = ast_playstream(fs);
524 fdprintf(agi->fd, "200 result=%d endpos=%ld\n", res, sample_offset);
526 return RESULT_SHOWUSAGE;
528 return RESULT_FAILURE;
530 res = ast_waitstream_full(chan, argv[3], agi->audio, agi->ctrl);
531 /* this is to check for if ast_waitstream closed the stream, we probably are at
532 * the end of the stream, return that amount, else check for the amount */
533 sample_offset = (chan->stream)?ast_tellstream(fs):max_length;
534 ast_stopstream(chan);
536 /* Stop this command, don't print a result line, as there is a new command */
537 return RESULT_SUCCESS;
540 /* If the user didnt press a key, wait for digitTimeout*/
542 res = ast_waitfordigit_full(chan, timeout, agi->audio, agi->ctrl);
543 /* Make sure the new result is in the escape digits of the GET OPTION */
544 if ( !strchr(edigits,res) )
548 fdprintf(agi->fd, "200 result=%d endpos=%ld\n", res, sample_offset);
550 return RESULT_SUCCESS;
552 return RESULT_FAILURE;
558 /*--- handle_saynumber: Say number in various language syntaxes ---*/
559 /* Need to add option for gender here as well. Coders wanted */
560 /* While waiting, we're sending a (char *) NULL. */
561 static int handle_saynumber(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
566 return RESULT_SHOWUSAGE;
567 if (sscanf(argv[2], "%d", &num) != 1)
568 return RESULT_SHOWUSAGE;
569 res = ast_say_number_full(chan, num, argv[3], chan->language, (char *) NULL, agi->audio, agi->ctrl);
571 return RESULT_SUCCESS;
572 fdprintf(agi->fd, "200 result=%d\n", res);
574 return RESULT_SUCCESS;
576 return RESULT_FAILURE;
579 static int handle_saydigits(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
585 return RESULT_SHOWUSAGE;
586 if (sscanf(argv[2], "%i", &num) != 1)
587 return RESULT_SHOWUSAGE;
589 res = ast_say_digit_str_full(chan, argv[2], argv[3], chan->language, agi->audio, agi->ctrl);
590 if (res == 1) /* New command */
591 return RESULT_SUCCESS;
592 fdprintf(agi->fd, "200 result=%d\n", res);
594 return RESULT_SUCCESS;
596 return RESULT_FAILURE;
599 static int handle_sayalpha(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
604 return RESULT_SHOWUSAGE;
606 res = ast_say_character_str_full(chan, argv[2], argv[3], chan->language, agi->audio, agi->ctrl);
607 if (res == 1) /* New command */
608 return RESULT_SUCCESS;
609 fdprintf(agi->fd, "200 result=%d\n", res);
611 return RESULT_SUCCESS;
613 return RESULT_FAILURE;
616 static int handle_saydate(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
621 return RESULT_SHOWUSAGE;
622 if (sscanf(argv[2], "%i", &num) != 1)
623 return RESULT_SHOWUSAGE;
624 res = ast_say_date(chan, num, argv[3], chan->language);
626 return RESULT_SUCCESS;
627 fdprintf(agi->fd, "200 result=%d\n", res);
629 return RESULT_SUCCESS;
631 return RESULT_FAILURE;
634 static int handle_saytime(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
639 return RESULT_SHOWUSAGE;
640 if (sscanf(argv[2], "%i", &num) != 1)
641 return RESULT_SHOWUSAGE;
642 res = ast_say_time(chan, num, argv[3], chan->language);
644 return RESULT_SUCCESS;
645 fdprintf(agi->fd, "200 result=%d\n", res);
647 return RESULT_SUCCESS;
649 return RESULT_FAILURE;
652 static int handle_saydatetime(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
656 char *format, *zone=NULL;
659 return RESULT_SHOWUSAGE;
664 if (!strcasecmp(chan->language, "de")) {
665 format = "A dBY HMS";
667 format = "ABdY 'digits/at' IMp";
671 if (argc > 5 && !ast_strlen_zero(argv[5]))
674 if (sscanf(argv[2], "%ld", &unixtime) != 1)
675 return RESULT_SHOWUSAGE;
677 res = ast_say_date_with_format(chan, (time_t) unixtime, argv[3], chan->language, format, zone);
679 return RESULT_SUCCESS;
681 fdprintf(agi->fd, "200 result=%d\n", res);
684 return RESULT_SUCCESS;
686 return RESULT_FAILURE;
689 static int handle_sayphonetic(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
694 return RESULT_SHOWUSAGE;
696 res = ast_say_phonetic_str_full(chan, argv[2], argv[3], chan->language, agi->audio, agi->ctrl);
697 if (res == 1) /* New command */
698 return RESULT_SUCCESS;
699 fdprintf(agi->fd, "200 result=%d\n", res);
701 return RESULT_SUCCESS;
703 return RESULT_FAILURE;
706 static int handle_getdata(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
714 return RESULT_SHOWUSAGE;
716 timeout = atoi(argv[3]);
723 res = ast_app_getdata_full(chan, argv[2], data, max, timeout, agi->audio, agi->ctrl);
724 if (res == 2) /* New command */
725 return RESULT_SUCCESS;
727 fdprintf(agi->fd, "200 result=%s (timeout)\n", data);
729 fdprintf(agi->fd, "200 result=-1\n");
731 fdprintf(agi->fd, "200 result=%s\n", data);
732 return RESULT_SUCCESS;
735 static int handle_setcontext(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
739 return RESULT_SHOWUSAGE;
740 strncpy(chan->context, argv[2], sizeof(chan->context)-1);
741 fdprintf(agi->fd, "200 result=0\n");
742 return RESULT_SUCCESS;
745 static int handle_setextension(struct ast_channel *chan, AGI *agi, int argc, char **argv)
748 return RESULT_SHOWUSAGE;
749 strncpy(chan->exten, argv[2], sizeof(chan->exten)-1);
750 fdprintf(agi->fd, "200 result=0\n");
751 return RESULT_SUCCESS;
754 static int handle_setpriority(struct ast_channel *chan, AGI *agi, int argc, char **argv)
758 return RESULT_SHOWUSAGE;
759 if (sscanf(argv[2], "%i", &pri) != 1)
760 return RESULT_SHOWUSAGE;
761 chan->priority = pri - 1;
762 fdprintf(agi->fd, "200 result=0\n");
763 return RESULT_SUCCESS;
766 static int handle_recordfile(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
768 struct ast_filestream *fs;
770 struct timeval tv, start;
771 long sample_offset = 0;
775 struct ast_dsp *sildet=NULL; /* silence detector dsp */
776 int totalsilence = 0;
778 int silence = 0; /* amount of silence to allow */
779 int gotsilence = 0; /* did we timeout for silence? */
780 char *silencestr=NULL;
784 /* XXX EAGI FIXME XXX */
787 return RESULT_SHOWUSAGE;
788 if (sscanf(argv[5], "%i", &ms) != 1)
789 return RESULT_SHOWUSAGE;
792 silencestr = strchr(argv[6],'s');
793 if ((argc > 7) && (!silencestr))
794 silencestr = strchr(argv[7],'s');
795 if ((argc > 8) && (!silencestr))
796 silencestr = strchr(argv[8],'s');
799 if (strlen(silencestr) > 2) {
800 if ((silencestr[0] == 's') && (silencestr[1] == '=')) {
804 silence = atoi(silencestr);
812 rfmt = chan->readformat;
813 res = ast_set_read_format(chan, AST_FORMAT_SLINEAR);
815 ast_log(LOG_WARNING, "Unable to set to linear mode, giving up\n");
818 sildet = ast_dsp_new();
820 ast_log(LOG_WARNING, "Unable to create silence detector :(\n");
823 ast_dsp_set_threshold(sildet, 256);
826 /* backward compatibility, if no offset given, arg[6] would have been
827 * caught below and taken to be a beep, else if it is a digit then it is a
829 if ((argc >6) && (sscanf(argv[6], "%ld", &sample_offset) != 1) && (!strchr(argv[6], '=')))
830 res = ast_streamfile(chan, "beep", chan->language);
832 if ((argc > 7) && (!strchr(argv[7], '=')))
833 res = ast_streamfile(chan, "beep", chan->language);
836 res = ast_waitstream(chan, argv[4]);
838 fs = ast_writefile(argv[2], argv[3], NULL, O_CREAT | O_WRONLY | (sample_offset ? O_APPEND : 0), 0, 0644);
841 fdprintf(agi->fd, "200 result=%d (writefile)\n", res);
843 ast_dsp_free(sildet);
844 return RESULT_FAILURE;
848 ast_applystream(chan,fs);
849 /* really should have checks */
850 ast_seekstream(fs, sample_offset, SEEK_SET);
853 gettimeofday(&start, NULL);
854 gettimeofday(&tv, NULL);
855 while ((ms < 0) || (((tv.tv_sec - start.tv_sec) * 1000 + (tv.tv_usec - start.tv_usec)/1000) < ms)) {
856 res = ast_waitfor(chan, -1);
859 fdprintf(agi->fd, "200 result=%d (waitfor) endpos=%ld\n", res,sample_offset);
861 ast_dsp_free(sildet);
862 return RESULT_FAILURE;
866 fdprintf(agi->fd, "200 result=%d (hangup) endpos=%ld\n", 0, sample_offset);
869 ast_dsp_free(sildet);
870 return RESULT_FAILURE;
872 switch(f->frametype) {
874 if (strchr(argv[4], f->subclass)) {
875 /* This is an interrupting chracter */
876 sample_offset = ast_tellstream(fs);
877 fdprintf(agi->fd, "200 result=%d (dtmf) endpos=%ld\n", f->subclass, sample_offset);
881 ast_dsp_free(sildet);
882 return RESULT_SUCCESS;
885 case AST_FRAME_VOICE:
886 ast_writestream(fs, f);
887 /* this is a safe place to check progress since we know that fs
888 * is valid after a write, and it will then have our current
890 sample_offset = ast_tellstream(fs);
893 ast_dsp_silence(sildet, f, &dspsilence);
895 totalsilence = dspsilence;
899 if (totalsilence > silence) {
900 /* Ended happily with silence */
909 gettimeofday(&tv, NULL);
915 ast_stream_rewind(fs, silence-1000);
917 sample_offset = ast_tellstream(fs);
919 fdprintf(agi->fd, "200 result=%d (timeout) endpos=%ld\n", res, sample_offset);
922 fdprintf(agi->fd, "200 result=%d (randomerror) endpos=%ld\n", res, sample_offset);
925 res = ast_set_read_format(chan, rfmt);
927 ast_log(LOG_WARNING, "Unable to restore read format on '%s'\n", chan->name);
928 ast_dsp_free(sildet);
930 return RESULT_SUCCESS;
933 static int handle_autohangup(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
938 return RESULT_SHOWUSAGE;
939 if (sscanf(argv[2], "%d", &timeout) != 1)
940 return RESULT_SHOWUSAGE;
944 chan->whentohangup = time(NULL) + timeout;
946 chan->whentohangup = 0;
947 fdprintf(agi->fd, "200 result=0\n");
948 return RESULT_SUCCESS;
951 static int handle_hangup(struct ast_channel *chan, AGI *agi, int argc, char **argv)
953 struct ast_channel *c;
955 /* no argument: hangup the current channel */
956 ast_softhangup(chan,AST_SOFTHANGUP_EXPLICIT);
957 fdprintf(agi->fd, "200 result=1\n");
958 return RESULT_SUCCESS;
959 } else if (argc == 2) {
960 /* one argument: look for info on the specified channel */
961 c = ast_channel_walk_locked(NULL);
963 if (strcasecmp(argv[1], c->name) == 0) {
964 /* we have a matching channel */
965 ast_softhangup(c,AST_SOFTHANGUP_EXPLICIT);
966 fdprintf(agi->fd, "200 result=1\n");
967 ast_mutex_unlock(&c->lock);
968 return RESULT_SUCCESS;
970 ast_mutex_unlock(&c->lock);
971 c = ast_channel_walk_locked(c);
973 /* if we get this far no channel name matched the argument given */
974 fdprintf(agi->fd, "200 result=-1\n");
975 return RESULT_SUCCESS;
977 return RESULT_SHOWUSAGE;
981 static int handle_exec(struct ast_channel *chan, AGI *agi, int argc, char **argv)
987 return RESULT_SHOWUSAGE;
989 if (option_verbose > 2)
990 ast_verbose(VERBOSE_PREFIX_3 "AGI Script Executing Application: (%s) Options: (%s)\n", argv[1], argv[2]);
992 app = pbx_findapp(argv[1]);
995 res = pbx_exec(chan, app, argv[2], 1);
997 ast_log(LOG_WARNING, "Could not find application (%s)\n", argv[1]);
1000 fdprintf(agi->fd, "200 result=%d\n", res);
1005 static int handle_setcallerid(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1008 char *l = NULL, *n = NULL;
1011 strncpy(tmp, argv[2], sizeof(tmp) - 1);
1012 ast_callerid_parse(tmp, &n, &l);
1014 ast_shrink_phone_number(l);
1019 ast_set_callerid(chan, l, n, NULL);
1022 fdprintf(agi->fd, "200 result=1\n");
1023 return RESULT_SUCCESS;
1026 static int handle_channelstatus(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1028 struct ast_channel *c;
1030 /* no argument: supply info on the current channel */
1031 fdprintf(agi->fd, "200 result=%d\n", chan->_state);
1032 return RESULT_SUCCESS;
1033 } else if (argc == 3) {
1034 /* one argument: look for info on the specified channel */
1035 c = ast_channel_walk_locked(NULL);
1037 if (strcasecmp(argv[2],c->name)==0) {
1038 fdprintf(agi->fd, "200 result=%d\n", c->_state);
1039 ast_mutex_unlock(&c->lock);
1040 return RESULT_SUCCESS;
1042 ast_mutex_unlock(&c->lock);
1043 c = ast_channel_walk_locked(c);
1045 /* if we get this far no channel name matched the argument given */
1046 fdprintf(agi->fd, "200 result=-1\n");
1047 return RESULT_SUCCESS;
1049 return RESULT_SHOWUSAGE;
1053 static int handle_setvariable(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1056 pbx_builtin_setvar_helper(chan, argv[2], argv[3]);
1058 fdprintf(agi->fd, "200 result=1\n");
1059 return RESULT_SUCCESS;
1062 static int handle_getvariable(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1068 return RESULT_SHOWUSAGE;
1069 pbx_retrieve_variable(chan, argv[2], &ret, tempstr, sizeof(tempstr), NULL);
1071 fdprintf(agi->fd, "200 result=1 (%s)\n", ret);
1073 fdprintf(agi->fd, "200 result=0\n");
1075 return RESULT_SUCCESS;
1078 static int handle_getvariablefull(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1081 struct ast_channel *chan2=NULL;
1083 if ((argc != 4) && (argc != 5))
1084 return RESULT_SHOWUSAGE;
1086 while((chan2 = ast_channel_walk_locked(chan2))) {
1087 if (!strcmp(chan2->name, argv[4]))
1089 ast_mutex_unlock(&chan2->lock);
1095 pbx_substitute_variables_helper(chan2, argv[3], tmp, sizeof(tmp) - 1);
1096 fdprintf(agi->fd, "200 result=1 (%s)\n", tmp);
1098 fdprintf(agi->fd, "200 result=0\n");
1100 if (chan2 && (chan2 != chan))
1101 ast_mutex_unlock(&chan2->lock);
1102 return RESULT_SUCCESS;
1105 static int handle_verbose(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1111 return RESULT_SHOWUSAGE;
1114 sscanf(argv[2], "%d", &level);
1118 prefix = VERBOSE_PREFIX_4;
1121 prefix = VERBOSE_PREFIX_3;
1124 prefix = VERBOSE_PREFIX_2;
1128 prefix = VERBOSE_PREFIX_1;
1132 if (level <= option_verbose)
1133 ast_verbose("%s %s: %s\n", prefix, chan->data, argv[1]);
1135 fdprintf(agi->fd, "200 result=1\n");
1137 return RESULT_SUCCESS;
1140 static int handle_dbget(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1146 return RESULT_SHOWUSAGE;
1147 res = ast_db_get(argv[2], argv[3], tmp, sizeof(tmp));
1149 fdprintf(agi->fd, "200 result=0\n");
1151 fdprintf(agi->fd, "200 result=1 (%s)\n", tmp);
1153 return RESULT_SUCCESS;
1156 static int handle_dbput(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1161 return RESULT_SHOWUSAGE;
1162 res = ast_db_put(argv[2], argv[3], argv[4]);
1164 fdprintf(agi->fd, "200 result=0\n");
1166 fdprintf(agi->fd, "200 result=1\n");
1168 return RESULT_SUCCESS;
1171 static int handle_dbdel(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1176 return RESULT_SHOWUSAGE;
1177 res = ast_db_del(argv[2], argv[3]);
1179 fdprintf(agi->fd, "200 result=0\n");
1181 fdprintf(agi->fd, "200 result=1\n");
1183 return RESULT_SUCCESS;
1186 static int handle_dbdeltree(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1189 if ((argc < 3) || (argc > 4))
1190 return RESULT_SHOWUSAGE;
1192 res = ast_db_deltree(argv[2], argv[3]);
1194 res = ast_db_deltree(argv[2], NULL);
1197 fdprintf(agi->fd, "200 result=0\n");
1199 fdprintf(agi->fd, "200 result=1\n");
1200 return RESULT_SUCCESS;
1203 static char debug_usage[] =
1204 "Usage: agi debug\n"
1205 " Enables dumping of AGI transactions for debugging purposes\n";
1207 static char no_debug_usage[] =
1208 "Usage: agi no debug\n"
1209 " Disables dumping of AGI transactions for debugging purposes\n";
1211 static int agi_do_debug(int fd, int argc, char *argv[])
1214 return RESULT_SHOWUSAGE;
1216 ast_cli(fd, "AGI Debugging Enabled\n");
1217 return RESULT_SUCCESS;
1220 static int agi_no_debug(int fd, int argc, char *argv[])
1223 return RESULT_SHOWUSAGE;
1225 ast_cli(fd, "AGI Debugging Disabled\n");
1226 return RESULT_SUCCESS;
1229 static struct ast_cli_entry cli_debug =
1230 { { "agi", "debug", NULL }, agi_do_debug, "Enable AGI debugging", debug_usage };
1232 static struct ast_cli_entry cli_no_debug =
1233 { { "agi", "no", "debug", NULL }, agi_no_debug, "Disable AGI debugging", no_debug_usage };
1235 static int handle_noop(struct ast_channel *chan, AGI *agi, int arg, char *argv[])
1237 fdprintf(agi->fd, "200 result=0\n");
1238 return RESULT_SUCCESS;
1241 static int handle_setmusic(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
1243 if (!strncasecmp(argv[2],"on",2)) {
1245 ast_moh_start(chan, argv[3]);
1247 ast_moh_start(chan, NULL);
1249 if (!strncasecmp(argv[2],"off",3)) {
1252 fdprintf(agi->fd, "200 result=0\n");
1253 return RESULT_SUCCESS;
1256 static char usage_setmusic[] =
1257 " Usage: SET MUSIC ON <on|off> <class>\n"
1258 " Enables/Disables the music on hold generator. If <class> is\n"
1259 " not specified, then the default music on hold class will be used.\n"
1260 " Always returns 0.\n";
1262 static char usage_dbput[] =
1263 " Usage: DATABASE PUT <family> <key> <value>\n"
1264 " Adds or updates an entry in the Asterisk database for a\n"
1265 " given family, key, and value.\n"
1266 " Returns 1 if successful, 0 otherwise.\n";
1268 static char usage_dbget[] =
1269 " Usage: DATABASE GET <family> <key>\n"
1270 " Retrieves an entry in the Asterisk database for a\n"
1271 " given family and key.\n"
1272 " Returns 0 if <key> is not set. Returns 1 if <key>\n"
1273 " is set and returns the variable in parentheses.\n"
1274 " Example return code: 200 result=1 (testvariable)\n";
1276 static char usage_dbdel[] =
1277 " Usage: DATABASE DEL <family> <key>\n"
1278 " Deletes an entry in the Asterisk database for a\n"
1279 " given family and key.\n"
1280 " Returns 1 if successful, 0 otherwise.\n";
1282 static char usage_dbdeltree[] =
1283 " Usage: DATABASE DELTREE <family> [keytree]\n"
1284 " Deletes a family or specific keytree within a family\n"
1285 " in the Asterisk database.\n"
1286 " Returns 1 if successful, 0 otherwise.\n";
1288 static char usage_verbose[] =
1289 " Usage: VERBOSE <message> <level>\n"
1290 " Sends <message> to the console via verbose message system.\n"
1291 " <level> is the the verbose level (1-4)\n"
1292 " Always returns 1.\n";
1294 static char usage_getvariable[] =
1295 " Usage: GET VARIABLE <variablename>\n"
1296 " Returns 0 if <variablename> is not set. Returns 1 if <variablename>\n"
1297 " is set and returns the variable in parentheses.\n"
1298 " example return code: 200 result=1 (testvariable)\n";
1300 static char usage_getvariablefull[] =
1301 " Usage: GET FULL VARIABLE <variablename> [<channel name>]\n"
1302 " Returns 0 if <variablename> is not set or channel does not exist. Returns 1\n"
1303 "if <variablename> is set and returns the variable in parenthesis. Understands\n"
1304 "complex variable names and builtin variables, unlike GET VARIABLE.\n"
1305 " example return code: 200 result=1 (testvariable)\n";
1307 static char usage_setvariable[] =
1308 " Usage: SET VARIABLE <variablename> <value>\n";
1310 static char usage_channelstatus[] =
1311 " Usage: CHANNEL STATUS [<channelname>]\n"
1312 " Returns the status of the specified channel.\n"
1313 " If no channel name is given the returns the status of the\n"
1314 " current channel. Return values:\n"
1315 " 0 Channel is down and available\n"
1316 " 1 Channel is down, but reserved\n"
1317 " 2 Channel is off hook\n"
1318 " 3 Digits (or equivalent) have been dialed\n"
1319 " 4 Line is ringing\n"
1320 " 5 Remote end is ringing\n"
1322 " 7 Line is busy\n";
1324 static char usage_setcallerid[] =
1325 " Usage: SET CALLERID <number>\n"
1326 " Changes the callerid of the current channel.\n";
1328 static char usage_exec[] =
1329 " Usage: EXEC <application> <options>\n"
1330 " Executes <application> with given <options>.\n"
1331 " Returns whatever the application returns, or -2 on failure to find application\n";
1333 static char usage_hangup[] =
1334 " Usage: HANGUP [<channelname>]\n"
1335 " Hangs up the specified channel.\n"
1336 " If no channel name is given, hangs up the current channel\n";
1338 static char usage_answer[] =
1340 " Answers channel if not already in answer state. Returns -1 on\n"
1341 " channel failure, or 0 if successful.\n";
1343 static char usage_waitfordigit[] =
1344 " Usage: WAIT FOR DIGIT <timeout>\n"
1345 " Waits up to 'timeout' milliseconds for channel to receive a DTMF digit.\n"
1346 " Returns -1 on channel failure, 0 if no digit is received in the timeout, or\n"
1347 " the numerical value of the ascii of the digit if one is received. Use -1\n"
1348 " for the timeout value if you desire the call to block indefinitely.\n";
1350 static char usage_sendtext[] =
1351 " Usage: SEND TEXT \"<text to send>\"\n"
1352 " Sends the given text on a channel. Most channels do not support the\n"
1353 " transmission of text. Returns 0 if text is sent, or if the channel does not\n"
1354 " support text transmission. Returns -1 only on error/hangup. Text\n"
1355 " consisting of greater than one word should be placed in quotes since the\n"
1356 " command only accepts a single argument.\n";
1358 static char usage_recvchar[] =
1359 " Usage: RECEIVE CHAR <timeout>\n"
1360 " Receives a character of text on a channel. Specify timeout to be the\n"
1361 " maximum time to wait for input in milliseconds, or 0 for infinite. Most channels\n"
1362 " do not support the reception of text. Returns the decimal value of the character\n"
1363 " if one is received, or 0 if the channel does not support text reception. Returns\n"
1364 " -1 only on error/hangup.\n";
1366 static char usage_tddmode[] =
1367 " Usage: TDD MODE <on|off>\n"
1368 " Enable/Disable TDD transmission/reception on a channel. Returns 1 if\n"
1369 " successful, or 0 if channel is not TDD-capable.\n";
1371 static char usage_sendimage[] =
1372 " Usage: SEND IMAGE <image>\n"
1373 " Sends the given image on a channel. Most channels do not support the\n"
1374 " transmission of images. Returns 0 if image is sent, or if the channel does not\n"
1375 " support image transmission. Returns -1 only on error/hangup. Image names\n"
1376 " should not include extensions.\n";
1378 static char usage_streamfile[] =
1379 " Usage: STREAM FILE <filename> <escape digits> [sample offset]\n"
1380 " Send the given file, allowing playback to be interrupted by the given\n"
1381 " digits, if any. Use double quotes for the digits if you wish none to be\n"
1382 " permitted. If sample offset is provided then the audio will seek to sample\n"
1383 " offset before play starts. Returns 0 if playback completes without a digit\n"
1384 " being pressed, or the ASCII numerical value of the digit if one was pressed,\n"
1385 " or -1 on error or if the channel was disconnected. Remember, the file\n"
1386 " extension must not be included in the filename.\n";
1388 static char usage_getoption[] =
1389 " Usage: GET OPTION <filename> <escape_digits> [timeout]\n"
1390 " Behaves similar to STREAM FILE but used with a timeout option.\n";
1392 static char usage_saynumber[] =
1393 " Usage: SAY NUMBER <number> <escape digits>\n"
1394 " Say a given number, returning early if any of the given DTMF digits\n"
1395 " are received on the channel. Returns 0 if playback completes without a digit\n"
1396 " being pressed, or the ASCII numerical value of the digit if one was pressed or\n"
1397 " -1 on error/hangup.\n";
1399 static char usage_saydigits[] =
1400 " Usage: SAY DIGITS <number> <escape digits>\n"
1401 " Say a given digit string, returning early if any of the given DTMF digits\n"
1402 " are received on the channel. Returns 0 if playback completes without a digit\n"
1403 " being pressed, or the ASCII numerical value of the digit if one was pressed or\n"
1404 " -1 on error/hangup.\n";
1406 static char usage_sayalpha[] =
1407 " Usage: SAY ALPHA <number> <escape digits>\n"
1408 " Say a given character string, returning early if any of the given DTMF digits\n"
1409 " are received on the channel. Returns 0 if playback completes without a digit\n"
1410 " being pressed, or the ASCII numerical value of the digit if one was pressed or\n"
1411 " -1 on error/hangup.\n";
1413 static char usage_saydate[] =
1414 " Usage: SAY DATE <date> <escape digits>\n"
1415 " Say a given date, returning early if any of the given DTMF digits are\n"
1416 " received on the channel. <date> is number of seconds elapsed since 00:00:00\n"
1417 " on January 1, 1970, Coordinated Universal Time (UTC). Returns 0 if playback\n"
1418 " completes without a digit being pressed, or the ASCII numerical value of the\n"
1419 " digit if one was pressed or -1 on error/hangup.\n";
1421 static char usage_saytime[] =
1422 " Usage: SAY TIME <time> <escape digits>\n"
1423 " Say a given time, returning early if any of the given DTMF digits are\n"
1424 " received on the channel. <time> is number of seconds elapsed since 00:00:00\n"
1425 " on January 1, 1970, Coordinated Universal Time (UTC). Returns 0 if playback\n"
1426 " completes without a digit being pressed, or the ASCII numerical value of the\n"
1427 " digit if one was pressed or -1 on error/hangup.\n";
1429 static char usage_saydatetime[] =
1430 " Usage: SAY DATETIME <time> <escape digits> [format] [timezone]\n"
1431 " Say a given time, returning early if any of the given DTMF digits are\n"
1432 " received on the channel. <time> is number of seconds elapsed since 00:00:00\n"
1433 " on January 1, 1970, Coordinated Universal Time (UTC). [format] is the format\n"
1434 " the time should be said in. See voicemail.conf (defaults to \"ABdY\n"
1435 " 'digits/at' IMp\"). Acceptable values for [timezone] can be found in\n"
1436 " /usr/share/zoneinfo. Defaults to machine default. Returns 0 if playback\n"
1437 " completes without a digit being pressed, or the ASCII numerical value of the\n"
1438 " digit if one was pressed or -1 on error/hangup.\n";
1440 static char usage_sayphonetic[] =
1441 " Usage: SAY PHONETIC <string> <escape digits>\n"
1442 " Say a given character string with phonetics, returning early if any of the\n"
1443 " given DTMF digits are received on the channel. Returns 0 if playback\n"
1444 " completes without a digit pressed, the ASCII numerical value of the digit\n"
1445 " if one was pressed, or -1 on error/hangup.\n";
1447 static char usage_getdata[] =
1448 " Usage: GET DATA <file to be streamed> [timeout] [max digits]\n"
1449 " Stream the given file, and recieve DTMF data. Returns the digits received\n"
1450 "from the channel at the other end.\n";
1452 static char usage_setcontext[] =
1453 " Usage: SET CONTEXT <desired context>\n"
1454 " Sets the context for continuation upon exiting the application.\n";
1456 static char usage_setextension[] =
1457 " Usage: SET EXTENSION <new extension>\n"
1458 " Changes the extension for continuation upon exiting the application.\n";
1460 static char usage_setpriority[] =
1461 " Usage: SET PRIORITY <num>\n"
1462 " Changes the priority for continuation upon exiting the application.\n";
1464 static char usage_recordfile[] =
1465 " Usage: RECORD FILE <filename> <format> <escape digits> <timeout> \\\n"
1466 " [offset samples] [BEEP] [s=silence]\n"
1467 " Record to a file until a given dtmf digit in the sequence is received\n"
1468 " Returns -1 on hangup or error. The format will specify what kind of file\n"
1469 " will be recorded. The timeout is the maximum record time in milliseconds, or\n"
1470 " -1 for no timeout. \"Offset samples\" is optional, and, if provided, will seek\n"
1471 " to the offset without exceeding the end of the file. \"silence\" is the number\n"
1472 " of seconds of silence allowed before the function returns despite the\n"
1473 " lack of dtmf digits or reaching timeout. Silence value must be\n"
1474 " preceeded by \"s=\" and is also optional.\n";
1476 static char usage_autohangup[] =
1477 " Usage: SET AUTOHANGUP <time>\n"
1478 " Cause the channel to automatically hangup at <time> seconds in the\n"
1479 " future. Of course it can be hungup before then as well. Setting to 0 will\n"
1480 " cause the autohangup feature to be disabled on this channel.\n";
1482 static char usage_noop[] =
1486 static agi_command commands[MAX_COMMANDS] = {
1487 { { "answer", NULL }, handle_answer, "Answer channel", usage_answer },
1488 { { "channel", "status", NULL }, handle_channelstatus, "Returns status of the connected channel", usage_channelstatus },
1489 { { "database", "del", NULL }, handle_dbdel, "Removes database key/value", usage_dbdel },
1490 { { "database", "deltree", NULL }, handle_dbdeltree, "Removes database keytree/value", usage_dbdeltree },
1491 { { "database", "get", NULL }, handle_dbget, "Gets database value", usage_dbget },
1492 { { "database", "put", NULL }, handle_dbput, "Adds/updates database value", usage_dbput },
1493 { { "exec", NULL }, handle_exec, "Executes a given Application", usage_exec },
1494 { { "get", "data", NULL }, handle_getdata, "Prompts for DTMF on a channel", usage_getdata },
1495 { { "get", "full", "variable", NULL }, handle_getvariablefull, "Evaluates a channel expression", usage_getvariablefull },
1496 { { "get", "option", NULL }, handle_getoption, "Stream file, prompt for DTMF, with timeout", usage_getoption },
1497 { { "get", "variable", NULL }, handle_getvariable, "Gets a channel variable", usage_getvariable },
1498 { { "hangup", NULL }, handle_hangup, "Hangup the current channel", usage_hangup },
1499 { { "noop", NULL }, handle_noop, "Does nothing", usage_noop },
1500 { { "receive", "char", NULL }, handle_recvchar, "Receives text from channels supporting it", usage_recvchar },
1501 { { "record", "file", NULL }, handle_recordfile, "Records to a given file", usage_recordfile },
1502 { { "say", "alpha", NULL }, handle_sayalpha, "Says a given character string", usage_sayalpha },
1503 { { "say", "digits", NULL }, handle_saydigits, "Says a given digit string", usage_saydigits },
1504 { { "say", "number", NULL }, handle_saynumber, "Says a given number", usage_saynumber },
1505 { { "say", "phonetic", NULL }, handle_sayphonetic, "Says a given character string with phonetics", usage_sayphonetic },
1506 { { "say", "date", NULL }, handle_saydate, "Says a given date", usage_saydate },
1507 { { "say", "time", NULL }, handle_saytime, "Says a given time", usage_saytime },
1508 { { "say", "datetime", NULL }, handle_saydatetime, "Says a given time as specfied by the format given", usage_saydatetime },
1509 { { "send", "image", NULL }, handle_sendimage, "Sends images to channels supporting it", usage_sendimage },
1510 { { "send", "text", NULL }, handle_sendtext, "Sends text to channels supporting it", usage_sendtext },
1511 { { "set", "autohangup", NULL }, handle_autohangup, "Autohangup channel in some time", usage_autohangup },
1512 { { "set", "callerid", NULL }, handle_setcallerid, "Sets callerid for the current channel", usage_setcallerid },
1513 { { "set", "context", NULL }, handle_setcontext, "Sets channel context", usage_setcontext },
1514 { { "set", "extension", NULL }, handle_setextension, "Changes channel extension", usage_setextension },
1515 { { "set", "music", NULL }, handle_setmusic, "Enable/Disable Music on hold generator", usage_setmusic },
1516 { { "set", "priority", NULL }, handle_setpriority, "Set channel dialplan priority", usage_setpriority },
1517 { { "set", "variable", NULL }, handle_setvariable, "Sets a channel variable", usage_setvariable },
1518 { { "stream", "file", NULL }, handle_streamfile, "Sends audio file on channel", usage_streamfile },
1519 { { "tdd", "mode", NULL }, handle_tddmode, "Toggles TDD mode (for the deaf)", usage_tddmode },
1520 { { "verbose", NULL }, handle_verbose, "Logs a message to the asterisk verbose log", usage_verbose },
1521 { { "wait", "for", "digit", NULL }, handle_waitfordigit, "Waits for a digit to be pressed", usage_waitfordigit },
1524 static void join(char *s, size_t len, char *w[])
1528 /* Join words into a string */
1533 for (x=0; w[x]; x++) {
1535 strncat(s, " ", len - strlen(s) - 1);
1536 strncat(s, w[x], len - strlen(s) - 1);
1540 static int help_workhorse(int fd, char *match[])
1545 struct agi_command *e;
1547 join(matchstr, sizeof(matchstr), match);
1548 for (x=0;x<sizeof(commands)/sizeof(commands[0]);x++) {
1549 if (!commands[x].cmda[0]) break;
1552 join(fullcmd, sizeof(fullcmd), e->cmda);
1553 /* Hide commands that start with '_' */
1554 if (fullcmd[0] == '_')
1557 if (strncasecmp(matchstr, fullcmd, strlen(matchstr))) {
1561 ast_cli(fd, "%20.20s %s\n", fullcmd, e->summary);
1566 int agi_register(agi_command *agi)
1569 for (x=0; x<MAX_COMMANDS - 1; x++) {
1570 if (commands[x].cmda[0] == agi->cmda[0]) {
1571 ast_log(LOG_WARNING, "Command already registered!\n");
1575 for (x=0; x<MAX_COMMANDS - 1; x++) {
1576 if (!commands[x].cmda[0]) {
1581 ast_log(LOG_WARNING, "No more room for new commands!\n");
1585 void agi_unregister(agi_command *agi)
1588 for (x=0; x<MAX_COMMANDS - 1; x++) {
1589 if (commands[x].cmda[0] == agi->cmda[0]) {
1590 memset(&commands[x], 0, sizeof(agi_command));
1595 static agi_command *find_command(char *cmds[], int exact)
1601 for (x=0; x < sizeof(commands) / sizeof(commands[0]); x++) {
1602 if (!commands[x].cmda[0])
1604 /* start optimistic */
1606 for (y=0; match && cmds[y]; y++) {
1607 /* If there are no more words in the command (and we're looking for
1608 an exact match) or there is a difference between the two words,
1609 then this is not a match */
1610 if (!commands[x].cmda[y] && !exact)
1612 /* don't segfault if the next part of a command doesn't exist */
1613 if (!commands[x].cmda[y])
1615 if (strcasecmp(commands[x].cmda[y], cmds[y]))
1618 /* If more words are needed to complete the command then this is not
1619 a candidate (unless we're looking for a really inexact answer */
1620 if ((exact > -1) && commands[x].cmda[y])
1623 return &commands[x];
1629 static int parse_args(char *s, int *max, char *argv[])
1641 /* If it's escaped, put a literal quote */
1646 if (quoted && whitespace) {
1647 /* If we're starting a quote, coming off white space start a new word, too */
1655 if (!quoted && !escaped) {
1656 /* If we're not quoted, mark this as whitespace, and
1657 end the previous argument */
1661 /* Otherwise, just treat it as anything else */
1665 /* If we're escaped, print a literal, otherwise enable escaping */
1675 if (x >= MAX_ARGS -1) {
1676 ast_log(LOG_WARNING, "Too many arguments, truncating\n");
1679 /* Coming off of whitespace, start the next argument */
1688 /* Null terminate */
1695 static int agi_handle_command(struct ast_channel *chan, AGI *agi, char *buf)
1697 char *argv[MAX_ARGS];
1703 parse_args(buf, &argc, argv);
1706 for (x=0; x<argc; x++)
1707 fprintf(stderr, "Got Arg%d: %s\n", x, argv[x]); }
1709 c = find_command(argv, 0);
1711 res = c->handler(chan, agi, argc, argv);
1713 case RESULT_SHOWUSAGE:
1714 fdprintf(agi->fd, "520-Invalid command syntax. Proper usage follows:\n");
1715 fdprintf(agi->fd, c->usage);
1716 fdprintf(agi->fd, "520 End of proper usage.\n");
1718 case AST_PBX_KEEPALIVE:
1719 /* We've been asked to keep alive, so do so */
1720 return AST_PBX_KEEPALIVE;
1722 case RESULT_FAILURE:
1723 /* They've already given the failure. We've been hung up on so handle this
1728 fdprintf(agi->fd, "510 Invalid or unknown command\n");
1733 static int run_agi(struct ast_channel *chan, char *request, AGI *agi, int pid, int dead)
1735 struct ast_channel *c;
1738 int returnstatus = 0;
1739 struct ast_frame *f;
1742 /* how many times we'll retry if ast_waitfor_nandfs will return without either
1743 channel or file descriptor in case select is interrupted by a system call (EINTR) */
1746 if (!(readf = fdopen(agi->ctrl, "r"))) {
1747 ast_log(LOG_WARNING, "Unable to fdopen file descriptor\n");
1754 setup_env(chan, request, agi->fd, (agi->audio > -1));
1757 c = ast_waitfor_nandfds(&chan, dead ? 0 : 1, &agi->ctrl, 1, NULL, &outfd, &ms);
1760 /* Idle the channel until we get a command */
1763 ast_log(LOG_DEBUG, "%s hungup\n", chan->name);
1767 /* If it's voice, write it to the audio pipe */
1768 if ((agi->audio > -1) && (f->frametype == AST_FRAME_VOICE)) {
1769 /* Write, ignoring errors */
1770 write(agi->audio, f->data, f->datalen);
1774 } else if (outfd > -1) {
1776 if (!fgets(buf, sizeof(buf), readf)) {
1777 /* Program terminated */
1780 if (option_verbose > 2)
1781 ast_verbose(VERBOSE_PREFIX_3 "AGI Script %s completed, returning %d\n", request, returnstatus);
1782 /* No need to kill the pid anymore, since they closed us */
1786 /* get rid of trailing newline, if any */
1787 if (*buf && buf[strlen(buf) - 1] == '\n')
1788 buf[strlen(buf) - 1] = 0;
1790 ast_verbose("AGI Rx << %s\n", buf);
1791 returnstatus |= agi_handle_command(chan, agi, buf);
1792 /* If the handle_command returns -1, we need to stop */
1793 if ((returnstatus < 0) || (returnstatus == AST_PBX_KEEPALIVE)) {
1798 ast_log(LOG_WARNING, "No channel, no fd?\n");
1804 /* Notify process */
1808 return returnstatus;
1811 static int handle_showagi(int fd, int argc, char *argv[]) {
1812 struct agi_command *e;
1815 return RESULT_SHOWUSAGE;
1817 e = find_command(argv + 2, 1);
1819 ast_cli(fd, e->usage);
1821 if (find_command(argv + 2, -1)) {
1822 return help_workhorse(fd, argv + 1);
1824 join(fullcmd, sizeof(fullcmd), argv+1);
1825 ast_cli(fd, "No such command '%s'.\n", fullcmd);
1829 return help_workhorse(fd, NULL);
1831 return RESULT_SUCCESS;
1834 static int handle_dumpagihtml(int fd, int argc, char *argv[]) {
1835 struct agi_command *e;
1842 return RESULT_SHOWUSAGE;
1844 if (!(htmlfile = fopen(argv[2], "wt"))) {
1845 ast_cli(fd, "Could not create file '%s'\n", argv[2]);
1846 return RESULT_SHOWUSAGE;
1849 fprintf(htmlfile, "<HTML>\n<HEAD>\n<TITLE>AGI Commands</TITLE>\n</HEAD>\n");
1850 fprintf(htmlfile, "<BODY>\n<CENTER><B><H1>AGI Commands</H1></B></CENTER>\n\n");
1853 fprintf(htmlfile, "<TABLE BORDER=\"0\" CELLSPACING=\"10\">\n");
1855 for (x=0;x<sizeof(commands)/sizeof(commands[0]);x++) {
1857 if (!commands[x].cmda[0]) break;
1860 join(fullcmd, sizeof(fullcmd), e->cmda);
1861 /* Hide commands that start with '_' */
1862 if (fullcmd[0] == '_')
1865 fprintf(htmlfile, "<TR><TD><TABLE BORDER=\"1\" CELLPADDING=\"5\" WIDTH=\"100%%\">\n");
1866 fprintf(htmlfile, "<TR><TH ALIGN=\"CENTER\"><B>%s - %s</B></TD></TR>\n", fullcmd,e->summary);
1870 tempstr = strsep(&stringp, "\n");
1872 fprintf(htmlfile, "<TR><TD ALIGN=\"CENTER\">%s</TD></TR>\n", tempstr);
1874 fprintf(htmlfile, "<TR><TD ALIGN=\"CENTER\">\n");
1875 while ((tempstr = strsep(&stringp, "\n")) != NULL) {
1876 fprintf(htmlfile, "%s<BR>\n",tempstr);
1879 fprintf(htmlfile, "</TD></TR>\n");
1880 fprintf(htmlfile, "</TABLE></TD></TR>\n\n");
1884 fprintf(htmlfile, "</TABLE>\n</BODY>\n</HTML>\n");
1886 ast_cli(fd, "AGI HTML Commands Dumped to: %s\n", argv[2]);
1887 return RESULT_SUCCESS;
1890 static int agi_exec_full(struct ast_channel *chan, void *data, int enhanced, int dead)
1893 struct localuser *u;
1894 char *argv[MAX_ARGS];
1896 char *tmp = (char *)buf;
1904 if (!data || ast_strlen_zero(data)) {
1905 ast_log(LOG_WARNING, "AGI requires an argument (script)\n");
1908 strncpy(buf, data, sizeof(buf) - 1);
1910 memset(&agi, 0, sizeof(agi));
1911 while ((stringp = strsep(&tmp, "|"))) {
1912 argv[argc++] = stringp;
1918 /* Answer if need be */
1919 if (chan->_state != AST_STATE_UP) {
1920 if (ast_answer(chan)) {
1921 LOCAL_USER_REMOVE(u);
1926 res = launch_script(argv[0], argv, fds, enhanced ? &efd : NULL, &pid);
1931 res = run_agi(chan, argv[0], &agi, pid, dead);
1936 LOCAL_USER_REMOVE(u);
1940 static int agi_exec(struct ast_channel *chan, void *data)
1942 if (chan->_softhangup)
1943 ast_log(LOG_WARNING, "If you want to run AGI on hungup channels you should use DeadAGI!\n");
1944 return agi_exec_full(chan, data, 0, 0);
1947 static int eagi_exec(struct ast_channel *chan, void *data)
1952 if (chan->_softhangup)
1953 ast_log(LOG_WARNING, "If you want to run AGI on hungup channels you should use DeadAGI!\n");
1954 readformat = chan->readformat;
1955 if (ast_set_read_format(chan, AST_FORMAT_SLINEAR)) {
1956 ast_log(LOG_WARNING, "Unable to set channel '%s' to linear mode\n", chan->name);
1959 res = agi_exec_full(chan, data, 1, 0);
1961 if (ast_set_read_format(chan, readformat)) {
1962 ast_log(LOG_WARNING, "Unable to restore channel '%s' to format %s\n", chan->name, ast_getformatname(readformat));
1968 static int deadagi_exec(struct ast_channel *chan, void *data)
1970 return agi_exec_full(chan, data, 0, 1);
1973 static char showagi_help[] =
1974 "Usage: show agi [topic]\n"
1975 " When called with a topic as an argument, displays usage\n"
1976 " information on the given command. If called without a\n"
1977 " topic, it provides a list of AGI commands.\n";
1980 static char dumpagihtml_help[] =
1981 "Usage: dump agihtml <filename>\n"
1982 " Dumps the agi command list in html format to given filename\n";
1984 static struct ast_cli_entry showagi =
1985 { { "show", "agi", NULL }, handle_showagi, "Show AGI commands or specific help", showagi_help };
1987 static struct ast_cli_entry dumpagihtml =
1988 { { "dump", "agihtml", NULL }, handle_dumpagihtml, "Dumps a list of agi command in html format", dumpagihtml_help };
1990 int unload_module(void)
1992 STANDARD_HANGUP_LOCALUSERS;
1993 ast_cli_unregister(&showagi);
1994 ast_cli_unregister(&dumpagihtml);
1995 ast_cli_unregister(&cli_debug);
1996 ast_cli_unregister(&cli_no_debug);
1997 ast_unregister_application(eapp);
1998 ast_unregister_application(deadapp);
1999 return ast_unregister_application(app);
2002 int load_module(void)
2004 ast_cli_register(&showagi);
2005 ast_cli_register(&dumpagihtml);
2006 ast_cli_register(&cli_debug);
2007 ast_cli_register(&cli_no_debug);
2008 ast_register_application(deadapp, deadagi_exec, deadsynopsis, descrip);
2009 ast_register_application(eapp, eagi_exec, esynopsis, descrip);
2010 return ast_register_application(app, agi_exec, synopsis, descrip);
2013 char *description(void)
2021 STANDARD_USECOUNT(res);
2027 return ASTERISK_GPL_KEY;