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>
33 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
35 #include "asterisk/file.h"
36 #include "asterisk/logger.h"
37 #include "asterisk/channel.h"
38 #include "asterisk/pbx.h"
39 #include "asterisk/module.h"
40 #include "asterisk/astdb.h"
41 #include "asterisk/callerid.h"
42 #include "asterisk/cli.h"
43 #include "asterisk/logger.h"
44 #include "asterisk/options.h"
45 #include "asterisk/image.h"
46 #include "asterisk/say.h"
47 #include "asterisk/app.h"
48 #include "asterisk/dsp.h"
49 #include "asterisk/musiconhold.h"
50 #include "asterisk/manager.h"
51 #include "asterisk/utils.h"
52 #include "asterisk/lock.h"
53 #include "asterisk/agi.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], "%d", &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_recvtext(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
408 return RESULT_SHOWUSAGE;
409 buf = ast_recvtext(chan,atoi(argv[2]));
411 fdprintf(agi->fd, "200 result=1 (%s)\n", buf);
414 fdprintf(agi->fd, "200 result=-1\n");
416 return RESULT_SUCCESS;
419 static int handle_tddmode(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
423 return RESULT_SHOWUSAGE;
424 if (!strncasecmp(argv[2],"on",2))
428 if (!strncasecmp(argv[2],"mate",4))
430 if (!strncasecmp(argv[2],"tdd",3))
432 res = ast_channel_setoption(chan, AST_OPTION_TDD, &x, sizeof(char), 0);
433 if(res != RESULT_SUCCESS)
434 fdprintf(agi->fd, "200 result=0\n");
436 fdprintf(agi->fd, "200 result=1\n");
437 return RESULT_SUCCESS;
440 static int handle_sendimage(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
444 return RESULT_SHOWUSAGE;
445 res = ast_send_image(chan, argv[2]);
446 if (!ast_check_hangup(chan))
448 fdprintf(agi->fd, "200 result=%d\n", res);
450 return RESULT_SUCCESS;
452 return RESULT_FAILURE;
455 static int handle_streamfile(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
458 struct ast_filestream *fs;
459 long sample_offset = 0;
463 return RESULT_SHOWUSAGE;
465 return RESULT_SHOWUSAGE;
466 if ((argc > 4) && (sscanf(argv[4], "%ld", &sample_offset) != 1))
467 return RESULT_SHOWUSAGE;
469 fs = ast_openstream(chan, argv[2], chan->language);
471 fdprintf(agi->fd, "200 result=%d endpos=%ld\n", 0, sample_offset);
472 return RESULT_SUCCESS;
474 ast_seekstream(fs, 0, SEEK_END);
475 max_length = ast_tellstream(fs);
476 ast_seekstream(fs, sample_offset, SEEK_SET);
477 res = ast_applystream(chan, fs);
478 res = ast_playstream(fs);
480 fdprintf(agi->fd, "200 result=%d endpos=%ld\n", res, sample_offset);
482 return RESULT_SHOWUSAGE;
484 return RESULT_FAILURE;
486 res = ast_waitstream_full(chan, argv[3], agi->audio, agi->ctrl);
487 /* this is to check for if ast_waitstream closed the stream, we probably are at
488 * the end of the stream, return that amount, else check for the amount */
489 sample_offset = (chan->stream) ? ast_tellstream(fs) : max_length;
490 ast_stopstream(chan);
492 /* Stop this command, don't print a result line, as there is a new command */
493 return RESULT_SUCCESS;
495 fdprintf(agi->fd, "200 result=%d endpos=%ld\n", res, sample_offset);
497 return RESULT_SUCCESS;
499 return RESULT_FAILURE;
502 /* get option - really similar to the handle_streamfile, but with a timeout */
503 static int handle_getoption(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
506 struct ast_filestream *fs;
507 long sample_offset = 0;
510 char *edigits = NULL;
512 if ( argc < 4 || argc > 5 )
513 return RESULT_SHOWUSAGE;
519 timeout = atoi(argv[4]);
520 else if (chan->pbx->dtimeout) {
521 /* by default dtimeout is set to 5sec */
522 timeout = chan->pbx->dtimeout * 1000; /* in msec */
525 fs = ast_openstream(chan, argv[2], chan->language);
527 fdprintf(agi->fd, "200 result=%d endpos=%ld\n", 0, sample_offset);
528 ast_log(LOG_WARNING, "Unable to open %s\n", argv[2]);
529 return RESULT_SUCCESS;
531 if (option_verbose > 2)
532 ast_verbose(VERBOSE_PREFIX_3 "Playing '%s' (escape_digits=%s) (timeout %d)\n", argv[2], edigits, timeout);
534 ast_seekstream(fs, 0, SEEK_END);
535 max_length = ast_tellstream(fs);
536 ast_seekstream(fs, sample_offset, SEEK_SET);
537 res = ast_applystream(chan, fs);
538 res = ast_playstream(fs);
540 fdprintf(agi->fd, "200 result=%d endpos=%ld\n", res, sample_offset);
542 return RESULT_SHOWUSAGE;
544 return RESULT_FAILURE;
546 res = ast_waitstream_full(chan, argv[3], agi->audio, agi->ctrl);
547 /* this is to check for if ast_waitstream closed the stream, we probably are at
548 * the end of the stream, return that amount, else check for the amount */
549 sample_offset = (chan->stream)?ast_tellstream(fs):max_length;
550 ast_stopstream(chan);
552 /* Stop this command, don't print a result line, as there is a new command */
553 return RESULT_SUCCESS;
556 /* If the user didnt press a key, wait for digitTimeout*/
558 res = ast_waitfordigit_full(chan, timeout, agi->audio, agi->ctrl);
559 /* Make sure the new result is in the escape digits of the GET OPTION */
560 if ( !strchr(edigits,res) )
564 fdprintf(agi->fd, "200 result=%d endpos=%ld\n", res, sample_offset);
566 return RESULT_SUCCESS;
568 return RESULT_FAILURE;
574 /*--- handle_saynumber: Say number in various language syntaxes ---*/
575 /* Need to add option for gender here as well. Coders wanted */
576 /* While waiting, we're sending a (char *) NULL. */
577 static int handle_saynumber(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
582 return RESULT_SHOWUSAGE;
583 if (sscanf(argv[2], "%d", &num) != 1)
584 return RESULT_SHOWUSAGE;
585 res = ast_say_number_full(chan, num, argv[3], chan->language, (char *) NULL, agi->audio, agi->ctrl);
587 return RESULT_SUCCESS;
588 fdprintf(agi->fd, "200 result=%d\n", res);
590 return RESULT_SUCCESS;
592 return RESULT_FAILURE;
595 static int handle_saydigits(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
601 return RESULT_SHOWUSAGE;
602 if (sscanf(argv[2], "%d", &num) != 1)
603 return RESULT_SHOWUSAGE;
605 res = ast_say_digit_str_full(chan, argv[2], argv[3], chan->language, agi->audio, agi->ctrl);
606 if (res == 1) /* New command */
607 return RESULT_SUCCESS;
608 fdprintf(agi->fd, "200 result=%d\n", res);
610 return RESULT_SUCCESS;
612 return RESULT_FAILURE;
615 static int handle_sayalpha(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
620 return RESULT_SHOWUSAGE;
622 res = ast_say_character_str_full(chan, argv[2], argv[3], chan->language, agi->audio, agi->ctrl);
623 if (res == 1) /* New command */
624 return RESULT_SUCCESS;
625 fdprintf(agi->fd, "200 result=%d\n", res);
627 return RESULT_SUCCESS;
629 return RESULT_FAILURE;
632 static int handle_saydate(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
637 return RESULT_SHOWUSAGE;
638 if (sscanf(argv[2], "%d", &num) != 1)
639 return RESULT_SHOWUSAGE;
640 res = ast_say_date(chan, num, argv[3], chan->language);
642 return RESULT_SUCCESS;
643 fdprintf(agi->fd, "200 result=%d\n", res);
645 return RESULT_SUCCESS;
647 return RESULT_FAILURE;
650 static int handle_saytime(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
655 return RESULT_SHOWUSAGE;
656 if (sscanf(argv[2], "%d", &num) != 1)
657 return RESULT_SHOWUSAGE;
658 res = ast_say_time(chan, num, argv[3], chan->language);
660 return RESULT_SUCCESS;
661 fdprintf(agi->fd, "200 result=%d\n", res);
663 return RESULT_SUCCESS;
665 return RESULT_FAILURE;
668 static int handle_saydatetime(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
672 char *format, *zone=NULL;
675 return RESULT_SHOWUSAGE;
680 if (!strcasecmp(chan->language, "de")) {
681 format = "A dBY HMS";
683 format = "ABdY 'digits/at' IMp";
687 if (argc > 5 && !ast_strlen_zero(argv[5]))
690 if (sscanf(argv[2], "%ld", &unixtime) != 1)
691 return RESULT_SHOWUSAGE;
693 res = ast_say_date_with_format(chan, (time_t) unixtime, argv[3], chan->language, format, zone);
695 return RESULT_SUCCESS;
697 fdprintf(agi->fd, "200 result=%d\n", res);
700 return RESULT_SUCCESS;
702 return RESULT_FAILURE;
705 static int handle_sayphonetic(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
710 return RESULT_SHOWUSAGE;
712 res = ast_say_phonetic_str_full(chan, argv[2], argv[3], chan->language, agi->audio, agi->ctrl);
713 if (res == 1) /* New command */
714 return RESULT_SUCCESS;
715 fdprintf(agi->fd, "200 result=%d\n", res);
717 return RESULT_SUCCESS;
719 return RESULT_FAILURE;
722 static int handle_getdata(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
730 return RESULT_SHOWUSAGE;
732 timeout = atoi(argv[3]);
739 res = ast_app_getdata_full(chan, argv[2], data, max, timeout, agi->audio, agi->ctrl);
740 if (res == 2) /* New command */
741 return RESULT_SUCCESS;
743 fdprintf(agi->fd, "200 result=%s (timeout)\n", data);
745 fdprintf(agi->fd, "200 result=-1\n");
747 fdprintf(agi->fd, "200 result=%s\n", data);
748 return RESULT_SUCCESS;
751 static int handle_setcontext(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
755 return RESULT_SHOWUSAGE;
756 ast_copy_string(chan->context, argv[2], sizeof(chan->context));
757 fdprintf(agi->fd, "200 result=0\n");
758 return RESULT_SUCCESS;
761 static int handle_setextension(struct ast_channel *chan, AGI *agi, int argc, char **argv)
764 return RESULT_SHOWUSAGE;
765 ast_copy_string(chan->exten, argv[2], sizeof(chan->exten));
766 fdprintf(agi->fd, "200 result=0\n");
767 return RESULT_SUCCESS;
770 static int handle_setpriority(struct ast_channel *chan, AGI *agi, int argc, char **argv)
774 return RESULT_SHOWUSAGE;
776 if (sscanf(argv[2], "%d", &pri) != 1) {
777 if ((pri = ast_findlabel_extension(chan, chan->context, chan->exten, argv[2], chan->cid.cid_num)) < 1)
778 return RESULT_SHOWUSAGE;
781 ast_explicit_goto(chan, NULL, NULL, pri);
782 fdprintf(agi->fd, "200 result=0\n");
783 return RESULT_SUCCESS;
786 static int handle_recordfile(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
788 struct ast_filestream *fs;
790 struct timeval tv, start;
791 long sample_offset = 0;
795 struct ast_dsp *sildet=NULL; /* silence detector dsp */
796 int totalsilence = 0;
798 int silence = 0; /* amount of silence to allow */
799 int gotsilence = 0; /* did we timeout for silence? */
800 char *silencestr=NULL;
804 /* XXX EAGI FIXME XXX */
807 return RESULT_SHOWUSAGE;
808 if (sscanf(argv[5], "%d", &ms) != 1)
809 return RESULT_SHOWUSAGE;
812 silencestr = strchr(argv[6],'s');
813 if ((argc > 7) && (!silencestr))
814 silencestr = strchr(argv[7],'s');
815 if ((argc > 8) && (!silencestr))
816 silencestr = strchr(argv[8],'s');
819 if (strlen(silencestr) > 2) {
820 if ((silencestr[0] == 's') && (silencestr[1] == '=')) {
824 silence = atoi(silencestr);
832 rfmt = chan->readformat;
833 res = ast_set_read_format(chan, AST_FORMAT_SLINEAR);
835 ast_log(LOG_WARNING, "Unable to set to linear mode, giving up\n");
838 sildet = ast_dsp_new();
840 ast_log(LOG_WARNING, "Unable to create silence detector :(\n");
843 ast_dsp_set_threshold(sildet, 256);
846 /* backward compatibility, if no offset given, arg[6] would have been
847 * caught below and taken to be a beep, else if it is a digit then it is a
849 if ((argc >6) && (sscanf(argv[6], "%ld", &sample_offset) != 1) && (!strchr(argv[6], '=')))
850 res = ast_streamfile(chan, "beep", chan->language);
852 if ((argc > 7) && (!strchr(argv[7], '=')))
853 res = ast_streamfile(chan, "beep", chan->language);
856 res = ast_waitstream(chan, argv[4]);
858 fs = ast_writefile(argv[2], argv[3], NULL, O_CREAT | O_WRONLY | (sample_offset ? O_APPEND : 0), 0, 0644);
861 fdprintf(agi->fd, "200 result=%d (writefile)\n", res);
863 ast_dsp_free(sildet);
864 return RESULT_FAILURE;
868 ast_applystream(chan,fs);
869 /* really should have checks */
870 ast_seekstream(fs, sample_offset, SEEK_SET);
873 gettimeofday(&start, NULL);
874 gettimeofday(&tv, NULL);
875 while ((ms < 0) || (((tv.tv_sec - start.tv_sec) * 1000 + (tv.tv_usec - start.tv_usec)/1000) < ms)) {
876 res = ast_waitfor(chan, -1);
879 fdprintf(agi->fd, "200 result=%d (waitfor) endpos=%ld\n", res,sample_offset);
881 ast_dsp_free(sildet);
882 return RESULT_FAILURE;
886 fdprintf(agi->fd, "200 result=%d (hangup) endpos=%ld\n", 0, sample_offset);
889 ast_dsp_free(sildet);
890 return RESULT_FAILURE;
892 switch(f->frametype) {
894 if (strchr(argv[4], f->subclass)) {
895 /* This is an interrupting chracter */
896 sample_offset = ast_tellstream(fs);
897 fdprintf(agi->fd, "200 result=%d (dtmf) endpos=%ld\n", f->subclass, sample_offset);
901 ast_dsp_free(sildet);
902 return RESULT_SUCCESS;
905 case AST_FRAME_VOICE:
906 ast_writestream(fs, f);
907 /* this is a safe place to check progress since we know that fs
908 * is valid after a write, and it will then have our current
910 sample_offset = ast_tellstream(fs);
913 ast_dsp_silence(sildet, f, &dspsilence);
915 totalsilence = dspsilence;
919 if (totalsilence > silence) {
920 /* Ended happily with silence */
929 gettimeofday(&tv, NULL);
935 ast_stream_rewind(fs, silence-1000);
937 sample_offset = ast_tellstream(fs);
939 fdprintf(agi->fd, "200 result=%d (timeout) endpos=%ld\n", res, sample_offset);
942 fdprintf(agi->fd, "200 result=%d (randomerror) endpos=%ld\n", res, sample_offset);
945 res = ast_set_read_format(chan, rfmt);
947 ast_log(LOG_WARNING, "Unable to restore read format on '%s'\n", chan->name);
948 ast_dsp_free(sildet);
950 return RESULT_SUCCESS;
953 static int handle_autohangup(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
958 return RESULT_SHOWUSAGE;
959 if (sscanf(argv[2], "%d", &timeout) != 1)
960 return RESULT_SHOWUSAGE;
964 chan->whentohangup = time(NULL) + timeout;
966 chan->whentohangup = 0;
967 fdprintf(agi->fd, "200 result=0\n");
968 return RESULT_SUCCESS;
971 static int handle_hangup(struct ast_channel *chan, AGI *agi, int argc, char **argv)
973 struct ast_channel *c;
975 /* no argument: hangup the current channel */
976 ast_softhangup(chan,AST_SOFTHANGUP_EXPLICIT);
977 fdprintf(agi->fd, "200 result=1\n");
978 return RESULT_SUCCESS;
979 } else if (argc == 2) {
980 /* one argument: look for info on the specified channel */
981 c = ast_get_channel_by_name_locked(argv[1]);
983 /* we have a matching channel */
984 ast_softhangup(c,AST_SOFTHANGUP_EXPLICIT);
985 fdprintf(agi->fd, "200 result=1\n");
986 ast_mutex_unlock(&c->lock);
987 return RESULT_SUCCESS;
989 /* if we get this far no channel name matched the argument given */
990 fdprintf(agi->fd, "200 result=-1\n");
991 return RESULT_SUCCESS;
993 return RESULT_SHOWUSAGE;
997 static int handle_exec(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1000 struct ast_app *app;
1003 return RESULT_SHOWUSAGE;
1005 if (option_verbose > 2)
1006 ast_verbose(VERBOSE_PREFIX_3 "AGI Script Executing Application: (%s) Options: (%s)\n", argv[1], argv[2]);
1008 app = pbx_findapp(argv[1]);
1011 res = pbx_exec(chan, app, argv[2], 1);
1013 ast_log(LOG_WARNING, "Could not find application (%s)\n", argv[1]);
1016 fdprintf(agi->fd, "200 result=%d\n", res);
1021 static int handle_setcallerid(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1024 char *l = NULL, *n = NULL;
1027 ast_copy_string(tmp, argv[2], sizeof(tmp));
1028 ast_callerid_parse(tmp, &n, &l);
1030 ast_shrink_phone_number(l);
1035 ast_set_callerid(chan, l, n, NULL);
1038 fdprintf(agi->fd, "200 result=1\n");
1039 return RESULT_SUCCESS;
1042 static int handle_channelstatus(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1044 struct ast_channel *c;
1046 /* no argument: supply info on the current channel */
1047 fdprintf(agi->fd, "200 result=%d\n", chan->_state);
1048 return RESULT_SUCCESS;
1049 } else if (argc == 3) {
1050 /* one argument: look for info on the specified channel */
1051 c = ast_get_channel_by_name_locked(argv[2]);
1053 fdprintf(agi->fd, "200 result=%d\n", c->_state);
1054 ast_mutex_unlock(&c->lock);
1055 return RESULT_SUCCESS;
1057 /* if we get this far no channel name matched the argument given */
1058 fdprintf(agi->fd, "200 result=-1\n");
1059 return RESULT_SUCCESS;
1061 return RESULT_SHOWUSAGE;
1065 static int handle_setvariable(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1068 pbx_builtin_setvar_helper(chan, argv[2], argv[3]);
1070 fdprintf(agi->fd, "200 result=1\n");
1071 return RESULT_SUCCESS;
1074 static int handle_getvariable(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1080 return RESULT_SHOWUSAGE;
1081 pbx_retrieve_variable(chan, argv[2], &ret, tempstr, sizeof(tempstr), NULL);
1083 fdprintf(agi->fd, "200 result=1 (%s)\n", ret);
1085 fdprintf(agi->fd, "200 result=0\n");
1087 return RESULT_SUCCESS;
1090 static int handle_getvariablefull(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1093 struct ast_channel *chan2=NULL;
1095 if ((argc != 4) && (argc != 5))
1096 return RESULT_SHOWUSAGE;
1098 chan2 = ast_get_channel_by_name_locked(argv[4]);
1102 if (chan) { /* XXX isn't this chan2 ? */
1103 pbx_substitute_variables_helper(chan2, argv[3], tmp, sizeof(tmp) - 1);
1104 fdprintf(agi->fd, "200 result=1 (%s)\n", tmp);
1106 fdprintf(agi->fd, "200 result=0\n");
1108 if (chan2 && (chan2 != chan))
1109 ast_mutex_unlock(&chan2->lock);
1110 return RESULT_SUCCESS;
1113 static int handle_verbose(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1119 return RESULT_SHOWUSAGE;
1122 sscanf(argv[2], "%d", &level);
1126 prefix = VERBOSE_PREFIX_4;
1129 prefix = VERBOSE_PREFIX_3;
1132 prefix = VERBOSE_PREFIX_2;
1136 prefix = VERBOSE_PREFIX_1;
1140 if (level <= option_verbose)
1141 ast_verbose("%s %s: %s\n", prefix, chan->data, argv[1]);
1143 fdprintf(agi->fd, "200 result=1\n");
1145 return RESULT_SUCCESS;
1148 static int handle_dbget(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1154 return RESULT_SHOWUSAGE;
1155 res = ast_db_get(argv[2], argv[3], tmp, sizeof(tmp));
1157 fdprintf(agi->fd, "200 result=0\n");
1159 fdprintf(agi->fd, "200 result=1 (%s)\n", tmp);
1161 return RESULT_SUCCESS;
1164 static int handle_dbput(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1169 return RESULT_SHOWUSAGE;
1170 res = ast_db_put(argv[2], argv[3], argv[4]);
1172 fdprintf(agi->fd, "200 result=0\n");
1174 fdprintf(agi->fd, "200 result=1\n");
1176 return RESULT_SUCCESS;
1179 static int handle_dbdel(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1184 return RESULT_SHOWUSAGE;
1185 res = ast_db_del(argv[2], argv[3]);
1187 fdprintf(agi->fd, "200 result=0\n");
1189 fdprintf(agi->fd, "200 result=1\n");
1191 return RESULT_SUCCESS;
1194 static int handle_dbdeltree(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1197 if ((argc < 3) || (argc > 4))
1198 return RESULT_SHOWUSAGE;
1200 res = ast_db_deltree(argv[2], argv[3]);
1202 res = ast_db_deltree(argv[2], NULL);
1205 fdprintf(agi->fd, "200 result=0\n");
1207 fdprintf(agi->fd, "200 result=1\n");
1208 return RESULT_SUCCESS;
1211 static char debug_usage[] =
1212 "Usage: agi debug\n"
1213 " Enables dumping of AGI transactions for debugging purposes\n";
1215 static char no_debug_usage[] =
1216 "Usage: agi no debug\n"
1217 " Disables dumping of AGI transactions for debugging purposes\n";
1219 static int agi_do_debug(int fd, int argc, char *argv[])
1222 return RESULT_SHOWUSAGE;
1224 ast_cli(fd, "AGI Debugging Enabled\n");
1225 return RESULT_SUCCESS;
1228 static int agi_no_debug(int fd, int argc, char *argv[])
1231 return RESULT_SHOWUSAGE;
1233 ast_cli(fd, "AGI Debugging Disabled\n");
1234 return RESULT_SUCCESS;
1237 static struct ast_cli_entry cli_debug =
1238 { { "agi", "debug", NULL }, agi_do_debug, "Enable AGI debugging", debug_usage };
1240 static struct ast_cli_entry cli_no_debug =
1241 { { "agi", "no", "debug", NULL }, agi_no_debug, "Disable AGI debugging", no_debug_usage };
1243 static int handle_noop(struct ast_channel *chan, AGI *agi, int arg, char *argv[])
1245 fdprintf(agi->fd, "200 result=0\n");
1246 return RESULT_SUCCESS;
1249 static int handle_setmusic(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
1251 if (!strncasecmp(argv[2],"on",2)) {
1253 ast_moh_start(chan, argv[3]);
1255 ast_moh_start(chan, NULL);
1257 if (!strncasecmp(argv[2],"off",3)) {
1260 fdprintf(agi->fd, "200 result=0\n");
1261 return RESULT_SUCCESS;
1264 static char usage_setmusic[] =
1265 " Usage: SET MUSIC ON <on|off> <class>\n"
1266 " Enables/Disables the music on hold generator. If <class> is\n"
1267 " not specified, then the default music on hold class will be used.\n"
1268 " Always returns 0.\n";
1270 static char usage_dbput[] =
1271 " Usage: DATABASE PUT <family> <key> <value>\n"
1272 " Adds or updates an entry in the Asterisk database for a\n"
1273 " given family, key, and value.\n"
1274 " Returns 1 if successful, 0 otherwise.\n";
1276 static char usage_dbget[] =
1277 " Usage: DATABASE GET <family> <key>\n"
1278 " Retrieves an entry in the Asterisk database for a\n"
1279 " given family and key.\n"
1280 " Returns 0 if <key> is not set. Returns 1 if <key>\n"
1281 " is set and returns the variable in parentheses.\n"
1282 " Example return code: 200 result=1 (testvariable)\n";
1284 static char usage_dbdel[] =
1285 " Usage: DATABASE DEL <family> <key>\n"
1286 " Deletes an entry in the Asterisk database for a\n"
1287 " given family and key.\n"
1288 " Returns 1 if successful, 0 otherwise.\n";
1290 static char usage_dbdeltree[] =
1291 " Usage: DATABASE DELTREE <family> [keytree]\n"
1292 " Deletes a family or specific keytree within a family\n"
1293 " in the Asterisk database.\n"
1294 " Returns 1 if successful, 0 otherwise.\n";
1296 static char usage_verbose[] =
1297 " Usage: VERBOSE <message> <level>\n"
1298 " Sends <message> to the console via verbose message system.\n"
1299 " <level> is the the verbose level (1-4)\n"
1300 " Always returns 1.\n";
1302 static char usage_getvariable[] =
1303 " Usage: GET VARIABLE <variablename>\n"
1304 " Returns 0 if <variablename> is not set. Returns 1 if <variablename>\n"
1305 " is set and returns the variable in parentheses.\n"
1306 " example return code: 200 result=1 (testvariable)\n";
1308 static char usage_getvariablefull[] =
1309 " Usage: GET FULL VARIABLE <variablename> [<channel name>]\n"
1310 " Returns 0 if <variablename> is not set or channel does not exist. Returns 1\n"
1311 "if <variablename> is set and returns the variable in parenthesis. Understands\n"
1312 "complex variable names and builtin variables, unlike GET VARIABLE.\n"
1313 " example return code: 200 result=1 (testvariable)\n";
1315 static char usage_setvariable[] =
1316 " Usage: SET VARIABLE <variablename> <value>\n";
1318 static char usage_channelstatus[] =
1319 " Usage: CHANNEL STATUS [<channelname>]\n"
1320 " Returns the status of the specified channel.\n"
1321 " If no channel name is given the returns the status of the\n"
1322 " current channel. Return values:\n"
1323 " 0 Channel is down and available\n"
1324 " 1 Channel is down, but reserved\n"
1325 " 2 Channel is off hook\n"
1326 " 3 Digits (or equivalent) have been dialed\n"
1327 " 4 Line is ringing\n"
1328 " 5 Remote end is ringing\n"
1330 " 7 Line is busy\n";
1332 static char usage_setcallerid[] =
1333 " Usage: SET CALLERID <number>\n"
1334 " Changes the callerid of the current channel.\n";
1336 static char usage_exec[] =
1337 " Usage: EXEC <application> <options>\n"
1338 " Executes <application> with given <options>.\n"
1339 " Returns whatever the application returns, or -2 on failure to find application\n";
1341 static char usage_hangup[] =
1342 " Usage: HANGUP [<channelname>]\n"
1343 " Hangs up the specified channel.\n"
1344 " If no channel name is given, hangs up the current channel\n";
1346 static char usage_answer[] =
1348 " Answers channel if not already in answer state. Returns -1 on\n"
1349 " channel failure, or 0 if successful.\n";
1351 static char usage_waitfordigit[] =
1352 " Usage: WAIT FOR DIGIT <timeout>\n"
1353 " Waits up to 'timeout' milliseconds for channel to receive a DTMF digit.\n"
1354 " Returns -1 on channel failure, 0 if no digit is received in the timeout, or\n"
1355 " the numerical value of the ascii of the digit if one is received. Use -1\n"
1356 " for the timeout value if you desire the call to block indefinitely.\n";
1358 static char usage_sendtext[] =
1359 " Usage: SEND TEXT \"<text to send>\"\n"
1360 " Sends the given text on a channel. Most channels do not support the\n"
1361 " transmission of text. Returns 0 if text is sent, or if the channel does not\n"
1362 " support text transmission. Returns -1 only on error/hangup. Text\n"
1363 " consisting of greater than one word should be placed in quotes since the\n"
1364 " command only accepts a single argument.\n";
1366 static char usage_recvchar[] =
1367 " Usage: RECEIVE CHAR <timeout>\n"
1368 " Receives a character of text on a channel. Specify timeout to be the\n"
1369 " maximum time to wait for input in milliseconds, or 0 for infinite. Most channels\n"
1370 " do not support the reception of text. Returns the decimal value of the character\n"
1371 " if one is received, or 0 if the channel does not support text reception. Returns\n"
1372 " -1 only on error/hangup.\n";
1374 static char usage_recvtext[] =
1375 " Usage: RECEIVE CHAR <timeout>\n"
1376 " Receives a string of text on a channel. Specify timeout to be the\n"
1377 " maximum time to wait for input in milliseconds, or 0 for infinite. Most channels\n"
1378 " do not support the reception of text. Returns -1 for failure or 1 for success, and the string in parentheses.\n";
1380 static char usage_tddmode[] =
1381 " Usage: TDD MODE <on|off>\n"
1382 " Enable/Disable TDD transmission/reception on a channel. Returns 1 if\n"
1383 " successful, or 0 if channel is not TDD-capable.\n";
1385 static char usage_sendimage[] =
1386 " Usage: SEND IMAGE <image>\n"
1387 " Sends the given image on a channel. Most channels do not support the\n"
1388 " transmission of images. Returns 0 if image is sent, or if the channel does not\n"
1389 " support image transmission. Returns -1 only on error/hangup. Image names\n"
1390 " should not include extensions.\n";
1392 static char usage_streamfile[] =
1393 " Usage: STREAM FILE <filename> <escape digits> [sample offset]\n"
1394 " Send the given file, allowing playback to be interrupted by the given\n"
1395 " digits, if any. Use double quotes for the digits if you wish none to be\n"
1396 " permitted. If sample offset is provided then the audio will seek to sample\n"
1397 " offset before play starts. Returns 0 if playback completes without a digit\n"
1398 " being pressed, or the ASCII numerical value of the digit if one was pressed,\n"
1399 " or -1 on error or if the channel was disconnected. Remember, the file\n"
1400 " extension must not be included in the filename.\n";
1402 static char usage_getoption[] =
1403 " Usage: GET OPTION <filename> <escape_digits> [timeout]\n"
1404 " Behaves similar to STREAM FILE but used with a timeout option.\n";
1406 static char usage_saynumber[] =
1407 " Usage: SAY NUMBER <number> <escape digits>\n"
1408 " Say a given number, 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_saydigits[] =
1414 " Usage: SAY DIGITS <number> <escape digits>\n"
1415 " Say a given digit string, returning early if any of the given DTMF digits\n"
1416 " are received on the channel. Returns 0 if playback completes without a digit\n"
1417 " being pressed, or the ASCII numerical value of the digit if one was pressed or\n"
1418 " -1 on error/hangup.\n";
1420 static char usage_sayalpha[] =
1421 " Usage: SAY ALPHA <number> <escape digits>\n"
1422 " Say a given character string, returning early if any of the given DTMF digits\n"
1423 " are received on the channel. Returns 0 if playback completes without a digit\n"
1424 " being pressed, or the ASCII numerical value of the digit if one was pressed or\n"
1425 " -1 on error/hangup.\n";
1427 static char usage_saydate[] =
1428 " Usage: SAY DATE <date> <escape digits>\n"
1429 " Say a given date, returning early if any of the given DTMF digits are\n"
1430 " received on the channel. <date> is number of seconds elapsed since 00:00:00\n"
1431 " on January 1, 1970, Coordinated Universal Time (UTC). Returns 0 if playback\n"
1432 " completes without a digit being pressed, or the ASCII numerical value of the\n"
1433 " digit if one was pressed or -1 on error/hangup.\n";
1435 static char usage_saytime[] =
1436 " Usage: SAY TIME <time> <escape digits>\n"
1437 " Say a given time, returning early if any of the given DTMF digits are\n"
1438 " received on the channel. <time> is number of seconds elapsed since 00:00:00\n"
1439 " on January 1, 1970, Coordinated Universal Time (UTC). Returns 0 if playback\n"
1440 " completes without a digit being pressed, or the ASCII numerical value of the\n"
1441 " digit if one was pressed or -1 on error/hangup.\n";
1443 static char usage_saydatetime[] =
1444 " Usage: SAY DATETIME <time> <escape digits> [format] [timezone]\n"
1445 " Say a given time, returning early if any of the given DTMF digits are\n"
1446 " received on the channel. <time> is number of seconds elapsed since 00:00:00\n"
1447 " on January 1, 1970, Coordinated Universal Time (UTC). [format] is the format\n"
1448 " the time should be said in. See voicemail.conf (defaults to \"ABdY\n"
1449 " 'digits/at' IMp\"). Acceptable values for [timezone] can be found in\n"
1450 " /usr/share/zoneinfo. Defaults to machine default. Returns 0 if playback\n"
1451 " completes without a digit being pressed, or the ASCII numerical value of the\n"
1452 " digit if one was pressed or -1 on error/hangup.\n";
1454 static char usage_sayphonetic[] =
1455 " Usage: SAY PHONETIC <string> <escape digits>\n"
1456 " Say a given character string with phonetics, returning early if any of the\n"
1457 " given DTMF digits are received on the channel. Returns 0 if playback\n"
1458 " completes without a digit pressed, the ASCII numerical value of the digit\n"
1459 " if one was pressed, or -1 on error/hangup.\n";
1461 static char usage_getdata[] =
1462 " Usage: GET DATA <file to be streamed> [timeout] [max digits]\n"
1463 " Stream the given file, and recieve DTMF data. Returns the digits received\n"
1464 "from the channel at the other end.\n";
1466 static char usage_setcontext[] =
1467 " Usage: SET CONTEXT <desired context>\n"
1468 " Sets the context for continuation upon exiting the application.\n";
1470 static char usage_setextension[] =
1471 " Usage: SET EXTENSION <new extension>\n"
1472 " Changes the extension for continuation upon exiting the application.\n";
1474 static char usage_setpriority[] =
1475 " Usage: SET PRIORITY <priority>\n"
1476 " Changes the priority for continuation upon exiting the application.\n"
1477 " The priority must be a valid priority or label.\n";
1479 static char usage_recordfile[] =
1480 " Usage: RECORD FILE <filename> <format> <escape digits> <timeout> \\\n"
1481 " [offset samples] [BEEP] [s=silence]\n"
1482 " Record to a file until a given dtmf digit in the sequence is received\n"
1483 " Returns -1 on hangup or error. The format will specify what kind of file\n"
1484 " will be recorded. The timeout is the maximum record time in milliseconds, or\n"
1485 " -1 for no timeout. \"Offset samples\" is optional, and, if provided, will seek\n"
1486 " to the offset without exceeding the end of the file. \"silence\" is the number\n"
1487 " of seconds of silence allowed before the function returns despite the\n"
1488 " lack of dtmf digits or reaching timeout. Silence value must be\n"
1489 " preceeded by \"s=\" and is also optional.\n";
1491 static char usage_autohangup[] =
1492 " Usage: SET AUTOHANGUP <time>\n"
1493 " Cause the channel to automatically hangup at <time> seconds in the\n"
1494 " future. Of course it can be hungup before then as well. Setting to 0 will\n"
1495 " cause the autohangup feature to be disabled on this channel.\n";
1497 static char usage_noop[] =
1501 static agi_command commands[MAX_COMMANDS] = {
1502 { { "answer", NULL }, handle_answer, "Answer channel", usage_answer },
1503 { { "channel", "status", NULL }, handle_channelstatus, "Returns status of the connected channel", usage_channelstatus },
1504 { { "database", "del", NULL }, handle_dbdel, "Removes database key/value", usage_dbdel },
1505 { { "database", "deltree", NULL }, handle_dbdeltree, "Removes database keytree/value", usage_dbdeltree },
1506 { { "database", "get", NULL }, handle_dbget, "Gets database value", usage_dbget },
1507 { { "database", "put", NULL }, handle_dbput, "Adds/updates database value", usage_dbput },
1508 { { "exec", NULL }, handle_exec, "Executes a given Application", usage_exec },
1509 { { "get", "data", NULL }, handle_getdata, "Prompts for DTMF on a channel", usage_getdata },
1510 { { "get", "full", "variable", NULL }, handle_getvariablefull, "Evaluates a channel expression", usage_getvariablefull },
1511 { { "get", "option", NULL }, handle_getoption, "Stream file, prompt for DTMF, with timeout", usage_getoption },
1512 { { "get", "variable", NULL }, handle_getvariable, "Gets a channel variable", usage_getvariable },
1513 { { "hangup", NULL }, handle_hangup, "Hangup the current channel", usage_hangup },
1514 { { "noop", NULL }, handle_noop, "Does nothing", usage_noop },
1515 { { "receive", "char", NULL }, handle_recvchar, "Receives one character from channels supporting it", usage_recvchar },
1516 { { "receive", "text", NULL }, handle_recvtext, "Receives text from channels supporting it", usage_recvtext },
1517 { { "record", "file", NULL }, handle_recordfile, "Records to a given file", usage_recordfile },
1518 { { "say", "alpha", NULL }, handle_sayalpha, "Says a given character string", usage_sayalpha },
1519 { { "say", "digits", NULL }, handle_saydigits, "Says a given digit string", usage_saydigits },
1520 { { "say", "number", NULL }, handle_saynumber, "Says a given number", usage_saynumber },
1521 { { "say", "phonetic", NULL }, handle_sayphonetic, "Says a given character string with phonetics", usage_sayphonetic },
1522 { { "say", "date", NULL }, handle_saydate, "Says a given date", usage_saydate },
1523 { { "say", "time", NULL }, handle_saytime, "Says a given time", usage_saytime },
1524 { { "say", "datetime", NULL }, handle_saydatetime, "Says a given time as specfied by the format given", usage_saydatetime },
1525 { { "send", "image", NULL }, handle_sendimage, "Sends images to channels supporting it", usage_sendimage },
1526 { { "send", "text", NULL }, handle_sendtext, "Sends text to channels supporting it", usage_sendtext },
1527 { { "set", "autohangup", NULL }, handle_autohangup, "Autohangup channel in some time", usage_autohangup },
1528 { { "set", "callerid", NULL }, handle_setcallerid, "Sets callerid for the current channel", usage_setcallerid },
1529 { { "set", "context", NULL }, handle_setcontext, "Sets channel context", usage_setcontext },
1530 { { "set", "extension", NULL }, handle_setextension, "Changes channel extension", usage_setextension },
1531 { { "set", "music", NULL }, handle_setmusic, "Enable/Disable Music on hold generator", usage_setmusic },
1532 { { "set", "priority", NULL }, handle_setpriority, "Set channel dialplan priority", usage_setpriority },
1533 { { "set", "variable", NULL }, handle_setvariable, "Sets a channel variable", usage_setvariable },
1534 { { "stream", "file", NULL }, handle_streamfile, "Sends audio file on channel", usage_streamfile },
1535 { { "tdd", "mode", NULL }, handle_tddmode, "Toggles TDD mode (for the deaf)", usage_tddmode },
1536 { { "verbose", NULL }, handle_verbose, "Logs a message to the asterisk verbose log", usage_verbose },
1537 { { "wait", "for", "digit", NULL }, handle_waitfordigit, "Waits for a digit to be pressed", usage_waitfordigit },
1540 static void join(char *s, size_t len, char *w[])
1544 /* Join words into a string */
1549 for (x=0; w[x]; x++) {
1551 strncat(s, " ", len - strlen(s) - 1);
1552 strncat(s, w[x], len - strlen(s) - 1);
1556 static int help_workhorse(int fd, char *match[])
1561 struct agi_command *e;
1563 join(matchstr, sizeof(matchstr), match);
1564 for (x=0;x<sizeof(commands)/sizeof(commands[0]);x++) {
1565 if (!commands[x].cmda[0]) break;
1568 join(fullcmd, sizeof(fullcmd), e->cmda);
1569 /* Hide commands that start with '_' */
1570 if (fullcmd[0] == '_')
1573 if (strncasecmp(matchstr, fullcmd, strlen(matchstr))) {
1577 ast_cli(fd, "%20.20s %s\n", fullcmd, e->summary);
1582 int agi_register(agi_command *agi)
1585 for (x=0; x<MAX_COMMANDS - 1; x++) {
1586 if (commands[x].cmda[0] == agi->cmda[0]) {
1587 ast_log(LOG_WARNING, "Command already registered!\n");
1591 for (x=0; x<MAX_COMMANDS - 1; x++) {
1592 if (!commands[x].cmda[0]) {
1597 ast_log(LOG_WARNING, "No more room for new commands!\n");
1601 void agi_unregister(agi_command *agi)
1604 for (x=0; x<MAX_COMMANDS - 1; x++) {
1605 if (commands[x].cmda[0] == agi->cmda[0]) {
1606 memset(&commands[x], 0, sizeof(agi_command));
1611 static agi_command *find_command(char *cmds[], int exact)
1617 for (x=0; x < sizeof(commands) / sizeof(commands[0]); x++) {
1618 if (!commands[x].cmda[0])
1620 /* start optimistic */
1622 for (y=0; match && cmds[y]; y++) {
1623 /* If there are no more words in the command (and we're looking for
1624 an exact match) or there is a difference between the two words,
1625 then this is not a match */
1626 if (!commands[x].cmda[y] && !exact)
1628 /* don't segfault if the next part of a command doesn't exist */
1629 if (!commands[x].cmda[y])
1631 if (strcasecmp(commands[x].cmda[y], cmds[y]))
1634 /* If more words are needed to complete the command then this is not
1635 a candidate (unless we're looking for a really inexact answer */
1636 if ((exact > -1) && commands[x].cmda[y])
1639 return &commands[x];
1645 static int parse_args(char *s, int *max, char *argv[])
1657 /* If it's escaped, put a literal quote */
1662 if (quoted && whitespace) {
1663 /* If we're starting a quote, coming off white space start a new word, too */
1671 if (!quoted && !escaped) {
1672 /* If we're not quoted, mark this as whitespace, and
1673 end the previous argument */
1677 /* Otherwise, just treat it as anything else */
1681 /* If we're escaped, print a literal, otherwise enable escaping */
1691 if (x >= MAX_ARGS -1) {
1692 ast_log(LOG_WARNING, "Too many arguments, truncating\n");
1695 /* Coming off of whitespace, start the next argument */
1704 /* Null terminate */
1711 static int agi_handle_command(struct ast_channel *chan, AGI *agi, char *buf)
1713 char *argv[MAX_ARGS];
1719 parse_args(buf, &argc, argv);
1722 for (x=0; x<argc; x++)
1723 fprintf(stderr, "Got Arg%d: %s\n", x, argv[x]); }
1725 c = find_command(argv, 0);
1727 res = c->handler(chan, agi, argc, argv);
1729 case RESULT_SHOWUSAGE:
1730 fdprintf(agi->fd, "520-Invalid command syntax. Proper usage follows:\n");
1731 fdprintf(agi->fd, c->usage);
1732 fdprintf(agi->fd, "520 End of proper usage.\n");
1734 case AST_PBX_KEEPALIVE:
1735 /* We've been asked to keep alive, so do so */
1736 return AST_PBX_KEEPALIVE;
1738 case RESULT_FAILURE:
1739 /* They've already given the failure. We've been hung up on so handle this
1744 fdprintf(agi->fd, "510 Invalid or unknown command\n");
1749 static int run_agi(struct ast_channel *chan, char *request, AGI *agi, int pid, int dead)
1751 struct ast_channel *c;
1754 int returnstatus = 0;
1755 struct ast_frame *f;
1758 /* how many times we'll retry if ast_waitfor_nandfs will return without either
1759 channel or file descriptor in case select is interrupted by a system call (EINTR) */
1762 if (!(readf = fdopen(agi->ctrl, "r"))) {
1763 ast_log(LOG_WARNING, "Unable to fdopen file descriptor\n");
1770 setup_env(chan, request, agi->fd, (agi->audio > -1));
1773 c = ast_waitfor_nandfds(&chan, dead ? 0 : 1, &agi->ctrl, 1, NULL, &outfd, &ms);
1776 /* Idle the channel until we get a command */
1779 ast_log(LOG_DEBUG, "%s hungup\n", chan->name);
1783 /* If it's voice, write it to the audio pipe */
1784 if ((agi->audio > -1) && (f->frametype == AST_FRAME_VOICE)) {
1785 /* Write, ignoring errors */
1786 write(agi->audio, f->data, f->datalen);
1790 } else if (outfd > -1) {
1792 if (!fgets(buf, sizeof(buf), readf)) {
1793 /* Program terminated */
1796 if (option_verbose > 2)
1797 ast_verbose(VERBOSE_PREFIX_3 "AGI Script %s completed, returning %d\n", request, returnstatus);
1798 /* No need to kill the pid anymore, since they closed us */
1802 /* get rid of trailing newline, if any */
1803 if (*buf && buf[strlen(buf) - 1] == '\n')
1804 buf[strlen(buf) - 1] = 0;
1806 ast_verbose("AGI Rx << %s\n", buf);
1807 returnstatus |= agi_handle_command(chan, agi, buf);
1808 /* If the handle_command returns -1, we need to stop */
1809 if ((returnstatus < 0) || (returnstatus == AST_PBX_KEEPALIVE)) {
1814 ast_log(LOG_WARNING, "No channel, no fd?\n");
1820 /* Notify process */
1824 return returnstatus;
1827 static int handle_showagi(int fd, int argc, char *argv[]) {
1828 struct agi_command *e;
1831 return RESULT_SHOWUSAGE;
1833 e = find_command(argv + 2, 1);
1835 ast_cli(fd, e->usage);
1837 if (find_command(argv + 2, -1)) {
1838 return help_workhorse(fd, argv + 1);
1840 join(fullcmd, sizeof(fullcmd), argv+1);
1841 ast_cli(fd, "No such command '%s'.\n", fullcmd);
1845 return help_workhorse(fd, NULL);
1847 return RESULT_SUCCESS;
1850 static int handle_dumpagihtml(int fd, int argc, char *argv[]) {
1851 struct agi_command *e;
1858 return RESULT_SHOWUSAGE;
1860 if (!(htmlfile = fopen(argv[2], "wt"))) {
1861 ast_cli(fd, "Could not create file '%s'\n", argv[2]);
1862 return RESULT_SHOWUSAGE;
1865 fprintf(htmlfile, "<HTML>\n<HEAD>\n<TITLE>AGI Commands</TITLE>\n</HEAD>\n");
1866 fprintf(htmlfile, "<BODY>\n<CENTER><B><H1>AGI Commands</H1></B></CENTER>\n\n");
1869 fprintf(htmlfile, "<TABLE BORDER=\"0\" CELLSPACING=\"10\">\n");
1871 for (x=0;x<sizeof(commands)/sizeof(commands[0]);x++) {
1873 if (!commands[x].cmda[0]) break;
1876 join(fullcmd, sizeof(fullcmd), e->cmda);
1877 /* Hide commands that start with '_' */
1878 if (fullcmd[0] == '_')
1881 fprintf(htmlfile, "<TR><TD><TABLE BORDER=\"1\" CELLPADDING=\"5\" WIDTH=\"100%%\">\n");
1882 fprintf(htmlfile, "<TR><TH ALIGN=\"CENTER\"><B>%s - %s</B></TD></TR>\n", fullcmd,e->summary);
1886 tempstr = strsep(&stringp, "\n");
1888 fprintf(htmlfile, "<TR><TD ALIGN=\"CENTER\">%s</TD></TR>\n", tempstr);
1890 fprintf(htmlfile, "<TR><TD ALIGN=\"CENTER\">\n");
1891 while ((tempstr = strsep(&stringp, "\n")) != NULL) {
1892 fprintf(htmlfile, "%s<BR>\n",tempstr);
1895 fprintf(htmlfile, "</TD></TR>\n");
1896 fprintf(htmlfile, "</TABLE></TD></TR>\n\n");
1900 fprintf(htmlfile, "</TABLE>\n</BODY>\n</HTML>\n");
1902 ast_cli(fd, "AGI HTML Commands Dumped to: %s\n", argv[2]);
1903 return RESULT_SUCCESS;
1906 static int agi_exec_full(struct ast_channel *chan, void *data, int enhanced, int dead)
1909 struct localuser *u;
1910 char *argv[MAX_ARGS];
1912 char *tmp = (char *)buf;
1920 if (!data || ast_strlen_zero(data)) {
1921 ast_log(LOG_WARNING, "AGI requires an argument (script)\n");
1924 ast_copy_string(buf, data, sizeof(buf));
1926 memset(&agi, 0, sizeof(agi));
1927 while ((stringp = strsep(&tmp, "|"))) {
1928 argv[argc++] = stringp;
1934 /* Answer if need be */
1935 if (chan->_state != AST_STATE_UP) {
1936 if (ast_answer(chan)) {
1937 LOCAL_USER_REMOVE(u);
1942 res = launch_script(argv[0], argv, fds, enhanced ? &efd : NULL, &pid);
1947 res = run_agi(chan, argv[0], &agi, pid, dead);
1952 LOCAL_USER_REMOVE(u);
1956 static int agi_exec(struct ast_channel *chan, void *data)
1958 if (chan->_softhangup)
1959 ast_log(LOG_WARNING, "If you want to run AGI on hungup channels you should use DeadAGI!\n");
1960 return agi_exec_full(chan, data, 0, 0);
1963 static int eagi_exec(struct ast_channel *chan, void *data)
1968 if (chan->_softhangup)
1969 ast_log(LOG_WARNING, "If you want to run AGI on hungup channels you should use DeadAGI!\n");
1970 readformat = chan->readformat;
1971 if (ast_set_read_format(chan, AST_FORMAT_SLINEAR)) {
1972 ast_log(LOG_WARNING, "Unable to set channel '%s' to linear mode\n", chan->name);
1975 res = agi_exec_full(chan, data, 1, 0);
1977 if (ast_set_read_format(chan, readformat)) {
1978 ast_log(LOG_WARNING, "Unable to restore channel '%s' to format %s\n", chan->name, ast_getformatname(readformat));
1984 static int deadagi_exec(struct ast_channel *chan, void *data)
1986 return agi_exec_full(chan, data, 0, 1);
1989 static char showagi_help[] =
1990 "Usage: show agi [topic]\n"
1991 " When called with a topic as an argument, displays usage\n"
1992 " information on the given command. If called without a\n"
1993 " topic, it provides a list of AGI commands.\n";
1996 static char dumpagihtml_help[] =
1997 "Usage: dump agihtml <filename>\n"
1998 " Dumps the agi command list in html format to given filename\n";
2000 static struct ast_cli_entry showagi =
2001 { { "show", "agi", NULL }, handle_showagi, "Show AGI commands or specific help", showagi_help };
2003 static struct ast_cli_entry dumpagihtml =
2004 { { "dump", "agihtml", NULL }, handle_dumpagihtml, "Dumps a list of agi command in html format", dumpagihtml_help };
2006 int unload_module(void)
2008 STANDARD_HANGUP_LOCALUSERS;
2009 ast_cli_unregister(&showagi);
2010 ast_cli_unregister(&dumpagihtml);
2011 ast_cli_unregister(&cli_debug);
2012 ast_cli_unregister(&cli_no_debug);
2013 ast_unregister_application(eapp);
2014 ast_unregister_application(deadapp);
2015 return ast_unregister_application(app);
2018 int load_module(void)
2020 ast_cli_register(&showagi);
2021 ast_cli_register(&dumpagihtml);
2022 ast_cli_register(&cli_debug);
2023 ast_cli_register(&cli_no_debug);
2024 ast_register_application(deadapp, deadagi_exec, deadsynopsis, descrip);
2025 ast_register_application(eapp, eagi_exec, esynopsis, descrip);
2026 return ast_register_application(app, agi_exec, synopsis, descrip);
2029 char *description(void)
2037 STANDARD_USECOUNT(res);
2043 return ASTERISK_GPL_KEY;