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>
49 #include "../asterisk.h"
50 #include "../astconf.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_dnid: %s\n", chan->cid.cid_dnid ? chan->cid.cid_dnid : "unknown");
313 fdprintf(fd, "agi_rdnis: %s\n", chan->cid.cid_rdnis ? chan->cid.cid_rdnis : "unknown");
315 /* Context information */
316 fdprintf(fd, "agi_context: %s\n", chan->context);
317 fdprintf(fd, "agi_extension: %s\n", chan->exten);
318 fdprintf(fd, "agi_priority: %d\n", chan->priority);
319 fdprintf(fd, "agi_enhanced: %s\n", enhanced ? "1.0" : "0.0");
321 /* User information */
322 fdprintf(fd, "agi_accountcode: %s\n", chan->accountcode ? chan->accountcode : "");
324 /* End with empty return */
328 static int handle_answer(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
332 if (chan->_state != AST_STATE_UP) {
333 /* Answer the chan */
334 res = ast_answer(chan);
336 fdprintf(agi->fd, "200 result=%d\n", res);
338 return RESULT_SUCCESS;
340 return RESULT_FAILURE;
343 static int handle_waitfordigit(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
348 return RESULT_SHOWUSAGE;
349 if (sscanf(argv[3], "%i", &to) != 1)
350 return RESULT_SHOWUSAGE;
351 res = ast_waitfordigit_full(chan, to, agi->audio, agi->ctrl);
352 fdprintf(agi->fd, "200 result=%d\n", res);
354 return RESULT_SUCCESS;
356 return RESULT_FAILURE;
359 static int handle_sendtext(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
363 return RESULT_SHOWUSAGE;
364 /* At the moment, the parser (perhaps broken) returns with
365 the last argument PLUS the newline at the end of the input
366 buffer. This probably needs to be fixed, but I wont do that
367 because other stuff may break as a result. The right way
368 would probably be to strip off the trailing newline before
369 parsing, then here, add a newline at the end of the string
370 before sending it to ast_sendtext --DUDE */
371 res = ast_sendtext(chan, argv[2]);
372 fdprintf(agi->fd, "200 result=%d\n", res);
374 return RESULT_SUCCESS;
376 return RESULT_FAILURE;
379 static int handle_recvchar(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
383 return RESULT_SHOWUSAGE;
384 res = ast_recvchar(chan,atoi(argv[2]));
386 fdprintf(agi->fd, "200 result=%d (timeout)\n", res);
387 return RESULT_SUCCESS;
390 fdprintf(agi->fd, "200 result=%d\n", res);
391 return RESULT_SUCCESS;
394 fdprintf(agi->fd, "200 result=%d (hangup)\n", res);
395 return RESULT_FAILURE;
399 static int handle_tddmode(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
403 return RESULT_SHOWUSAGE;
404 if (!strncasecmp(argv[2],"on",2))
408 if (!strncasecmp(argv[2],"mate",4))
410 if (!strncasecmp(argv[2],"tdd",3))
412 res = ast_channel_setoption(chan, AST_OPTION_TDD, &x, sizeof(char), 0);
413 fdprintf(agi->fd, "200 result=%d\n", res);
415 return RESULT_SUCCESS;
417 return RESULT_FAILURE;
420 static int handle_sendimage(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
424 return RESULT_SHOWUSAGE;
425 res = ast_send_image(chan, argv[2]);
426 if (!ast_check_hangup(chan))
428 fdprintf(agi->fd, "200 result=%d\n", res);
430 return RESULT_SUCCESS;
432 return RESULT_FAILURE;
435 static int handle_streamfile(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
438 struct ast_filestream *fs;
439 long sample_offset = 0;
443 return RESULT_SHOWUSAGE;
445 return RESULT_SHOWUSAGE;
446 if ((argc > 4) && (sscanf(argv[4], "%ld", &sample_offset) != 1))
447 return RESULT_SHOWUSAGE;
449 fs = ast_openstream(chan, argv[2], chan->language);
451 fdprintf(agi->fd, "200 result=%d endpos=%ld\n", 0, sample_offset);
452 return RESULT_SUCCESS;
454 ast_seekstream(fs, 0, SEEK_END);
455 max_length = ast_tellstream(fs);
456 ast_seekstream(fs, sample_offset, SEEK_SET);
457 res = ast_applystream(chan, fs);
458 res = ast_playstream(fs);
460 fdprintf(agi->fd, "200 result=%d endpos=%ld\n", res, sample_offset);
462 return RESULT_SHOWUSAGE;
464 return RESULT_FAILURE;
466 res = ast_waitstream_full(chan, argv[3], agi->audio, agi->ctrl);
467 /* this is to check for if ast_waitstream closed the stream, we probably are at
468 * the end of the stream, return that amount, else check for the amount */
469 sample_offset = (chan->stream) ? ast_tellstream(fs) : max_length;
470 ast_stopstream(chan);
472 /* Stop this command, don't print a result line, as there is a new command */
473 return RESULT_SUCCESS;
475 fdprintf(agi->fd, "200 result=%d endpos=%ld\n", res, sample_offset);
477 return RESULT_SUCCESS;
479 return RESULT_FAILURE;
482 /* get option - really similar to the handle_streamfile, but with a timeout */
483 static int handle_getoption(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
486 struct ast_filestream *fs;
487 long sample_offset = 0;
490 char *edigits = NULL;
492 if ( argc < 4 || argc > 5 )
493 return RESULT_SHOWUSAGE;
499 timeout = atoi(argv[4]);
500 else if (chan->pbx->dtimeout) {
501 /* by default dtimeout is set to 5sec */
502 timeout = chan->pbx->dtimeout * 1000; /* in msec */
505 fs = ast_openstream(chan, argv[2], chan->language);
507 fdprintf(agi->fd, "200 result=%d endpos=%ld\n", 0, sample_offset);
508 ast_log(LOG_WARNING, "Unable to open %s\n", argv[2]);
509 return RESULT_FAILURE;
511 if (option_verbose > 2)
512 ast_verbose(VERBOSE_PREFIX_3 "Playing '%s' (escape_digits=%s) (timeout %d)\n", argv[2], edigits, timeout);
514 ast_seekstream(fs, 0, SEEK_END);
515 max_length = ast_tellstream(fs);
516 ast_seekstream(fs, sample_offset, SEEK_SET);
517 res = ast_applystream(chan, fs);
518 res = ast_playstream(fs);
520 fdprintf(agi->fd, "200 result=%d endpos=%ld\n", res, sample_offset);
522 return RESULT_SHOWUSAGE;
524 return RESULT_FAILURE;
526 res = ast_waitstream_full(chan, argv[3], agi->audio, agi->ctrl);
527 /* this is to check for if ast_waitstream closed the stream, we probably are at
528 * the end of the stream, return that amount, else check for the amount */
529 sample_offset = (chan->stream)?ast_tellstream(fs):max_length;
530 ast_stopstream(chan);
532 /* Stop this command, don't print a result line, as there is a new command */
533 return RESULT_SUCCESS;
536 /* If the user didnt press a key, wait for digitTimeout*/
538 res = ast_waitfordigit_full(chan, timeout, agi->audio, agi->ctrl);
539 /* Make sure the new result is in the escape digits of the GET OPTION */
540 if ( !strchr(edigits,res) )
544 fdprintf(agi->fd, "200 result=%d endpos=%ld\n", res, sample_offset);
546 return RESULT_SUCCESS;
548 return RESULT_FAILURE;
554 /*--- handle_saynumber: Say number in various language syntaxes ---*/
555 /* Need to add option for gender here as well. Coders wanted */
556 /* While waiting, we're sending a (char *) NULL. */
557 static int handle_saynumber(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
562 return RESULT_SHOWUSAGE;
563 if (sscanf(argv[2], "%i", &num) != 1)
564 return RESULT_SHOWUSAGE;
565 res = ast_say_number_full(chan, num, argv[3], chan->language, (char *) NULL, agi->audio, agi->ctrl);
567 return RESULT_SUCCESS;
568 fdprintf(agi->fd, "200 result=%d\n", res);
570 return RESULT_SUCCESS;
572 return RESULT_FAILURE;
575 static int handle_saydigits(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
581 return RESULT_SHOWUSAGE;
582 if (sscanf(argv[2], "%i", &num) != 1)
583 return RESULT_SHOWUSAGE;
585 res = ast_say_digit_str_full(chan, argv[2], argv[3], chan->language, agi->audio, agi->ctrl);
586 if (res == 1) /* New command */
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_sayalpha(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
600 return RESULT_SHOWUSAGE;
602 res = ast_say_character_str_full(chan, argv[2], argv[3], chan->language, agi->audio, agi->ctrl);
603 if (res == 1) /* New command */
604 return RESULT_SUCCESS;
605 fdprintf(agi->fd, "200 result=%d\n", res);
607 return RESULT_SUCCESS;
609 return RESULT_FAILURE;
612 static int handle_saytime(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
617 return RESULT_SHOWUSAGE;
618 if (sscanf(argv[2], "%i", &num) != 1)
619 return RESULT_SHOWUSAGE;
620 res = ast_say_time(chan, num, argv[3], chan->language);
622 return RESULT_SUCCESS;
623 fdprintf(agi->fd, "200 result=%d\n", res);
625 return RESULT_SUCCESS;
627 return RESULT_FAILURE;
630 static int handle_sayphonetic(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
635 return RESULT_SHOWUSAGE;
637 res = ast_say_phonetic_str_full(chan, argv[2], argv[3], chan->language, agi->audio, agi->ctrl);
638 if (res == 1) /* New command */
639 return RESULT_SUCCESS;
640 fdprintf(agi->fd, "200 result=%d\n", res);
642 return RESULT_SUCCESS;
644 return RESULT_FAILURE;
647 static int handle_getdata(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
655 return RESULT_SHOWUSAGE;
657 timeout = atoi(argv[3]);
664 res = ast_app_getdata_full(chan, argv[2], data, max, timeout, agi->audio, agi->ctrl);
665 if (res == 2) /* New command */
666 return RESULT_SUCCESS;
668 fdprintf(agi->fd, "200 result=%s (timeout)\n", data);
670 fdprintf(agi->fd, "200 result=-1\n");
672 fdprintf(agi->fd, "200 result=%s\n", data);
674 return RESULT_SUCCESS;
676 return RESULT_FAILURE;
679 static int handle_setcontext(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
683 return RESULT_SHOWUSAGE;
684 strncpy(chan->context, argv[2], sizeof(chan->context)-1);
685 fdprintf(agi->fd, "200 result=0\n");
686 return RESULT_SUCCESS;
689 static int handle_setextension(struct ast_channel *chan, AGI *agi, int argc, char **argv)
692 return RESULT_SHOWUSAGE;
693 strncpy(chan->exten, argv[2], sizeof(chan->exten)-1);
694 fdprintf(agi->fd, "200 result=0\n");
695 return RESULT_SUCCESS;
698 static int handle_setpriority(struct ast_channel *chan, AGI *agi, int argc, char **argv)
702 return RESULT_SHOWUSAGE;
703 if (sscanf(argv[2], "%i", &pri) != 1)
704 return RESULT_SHOWUSAGE;
705 chan->priority = pri - 1;
706 fdprintf(agi->fd, "200 result=0\n");
707 return RESULT_SUCCESS;
710 static int handle_recordfile(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
712 struct ast_filestream *fs;
714 struct timeval tv, start;
715 long sample_offset = 0;
719 struct ast_dsp *sildet=NULL; /* silence detector dsp */
720 int totalsilence = 0;
722 int silence = 0; /* amount of silence to allow */
723 int gotsilence = 0; /* did we timeout for silence? */
724 char *silencestr=NULL;
728 /* XXX EAGI FIXME XXX */
731 return RESULT_SHOWUSAGE;
732 if (sscanf(argv[5], "%i", &ms) != 1)
733 return RESULT_SHOWUSAGE;
736 silencestr = strchr(argv[6],'s');
737 if ((argc > 7) && (!silencestr))
738 silencestr = strchr(argv[7],'s');
739 if ((argc > 8) && (!silencestr))
740 silencestr = strchr(argv[8],'s');
743 if (strlen(silencestr) > 2) {
744 if ((silencestr[0] == 's') && (silencestr[1] == '=')) {
748 silence = atoi(silencestr);
756 rfmt = chan->readformat;
757 res = ast_set_read_format(chan, AST_FORMAT_SLINEAR);
759 ast_log(LOG_WARNING, "Unable to set to linear mode, giving up\n");
762 sildet = ast_dsp_new();
764 ast_log(LOG_WARNING, "Unable to create silence detector :(\n");
767 ast_dsp_set_threshold(sildet, 256);
770 /* backward compatibility, if no offset given, arg[6] would have been
771 * caught below and taken to be a beep, else if it is a digit then it is a
773 if ((argc >6) && (sscanf(argv[6], "%ld", &sample_offset) != 1) && (!strchr(argv[6], '=')))
774 res = ast_streamfile(chan, "beep", chan->language);
776 if ((argc > 7) && (!strchr(argv[7], '=')))
777 res = ast_streamfile(chan, "beep", chan->language);
780 res = ast_waitstream(chan, argv[4]);
782 fs = ast_writefile(argv[2], argv[3], NULL, O_CREAT | O_WRONLY | (sample_offset ? O_APPEND : 0), 0, 0644);
785 fdprintf(agi->fd, "200 result=%d (writefile)\n", res);
787 ast_dsp_free(sildet);
788 return RESULT_FAILURE;
792 ast_applystream(chan,fs);
793 /* really should have checks */
794 ast_seekstream(fs, sample_offset, SEEK_SET);
797 gettimeofday(&start, NULL);
798 gettimeofday(&tv, NULL);
799 while ((ms < 0) || (((tv.tv_sec - start.tv_sec) * 1000 + (tv.tv_usec - start.tv_usec)/1000) < ms)) {
800 res = ast_waitfor(chan, -1);
803 fdprintf(agi->fd, "200 result=%d (waitfor) endpos=%ld\n", res,sample_offset);
805 ast_dsp_free(sildet);
806 return RESULT_FAILURE;
810 fdprintf(agi->fd, "200 result=%d (hangup) endpos=%ld\n", 0, sample_offset);
813 ast_dsp_free(sildet);
814 return RESULT_FAILURE;
816 switch(f->frametype) {
818 if (strchr(argv[4], f->subclass)) {
819 /* This is an interrupting chracter */
820 sample_offset = ast_tellstream(fs);
821 fdprintf(agi->fd, "200 result=%d (dtmf) endpos=%ld\n", f->subclass, sample_offset);
825 ast_dsp_free(sildet);
826 return RESULT_SUCCESS;
829 case AST_FRAME_VOICE:
830 ast_writestream(fs, f);
831 /* this is a safe place to check progress since we know that fs
832 * is valid after a write, and it will then have our current
834 sample_offset = ast_tellstream(fs);
837 ast_dsp_silence(sildet, f, &dspsilence);
839 totalsilence = dspsilence;
843 if (totalsilence > silence) {
844 /* Ended happily with silence */
853 gettimeofday(&tv, NULL);
859 ast_stream_rewind(fs, silence-1000);
861 sample_offset = ast_tellstream(fs);
863 fdprintf(agi->fd, "200 result=%d (timeout) endpos=%ld\n", res, sample_offset);
866 fdprintf(agi->fd, "200 result=%d (randomerror) endpos=%ld\n", res, sample_offset);
869 res = ast_set_read_format(chan, rfmt);
871 ast_log(LOG_WARNING, "Unable to restore read format on '%s'\n", chan->name);
872 ast_dsp_free(sildet);
874 return RESULT_SUCCESS;
877 static int handle_autohangup(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
882 return RESULT_SHOWUSAGE;
883 if (sscanf(argv[2], "%d", &timeout) != 1)
884 return RESULT_SHOWUSAGE;
888 chan->whentohangup = time(NULL) + timeout;
890 chan->whentohangup = 0;
891 fdprintf(agi->fd, "200 result=0\n");
892 return RESULT_SUCCESS;
895 static int handle_hangup(struct ast_channel *chan, AGI *agi, int argc, char **argv)
897 struct ast_channel *c;
899 /* no argument: hangup the current channel */
900 ast_softhangup(chan,AST_SOFTHANGUP_EXPLICIT);
901 fdprintf(agi->fd, "200 result=1\n");
902 return RESULT_SUCCESS;
903 } else if (argc == 2) {
904 /* one argument: look for info on the specified channel */
905 c = ast_channel_walk_locked(NULL);
907 if (strcasecmp(argv[1], c->name) == 0) {
908 /* we have a matching channel */
909 ast_softhangup(c,AST_SOFTHANGUP_EXPLICIT);
910 fdprintf(agi->fd, "200 result=1\n");
911 ast_mutex_unlock(&c->lock);
912 return RESULT_SUCCESS;
914 ast_mutex_unlock(&c->lock);
915 c = ast_channel_walk_locked(c);
917 /* if we get this far no channel name matched the argument given */
918 fdprintf(agi->fd, "200 result=-1\n");
919 return RESULT_SUCCESS;
921 return RESULT_SHOWUSAGE;
925 static int handle_exec(struct ast_channel *chan, AGI *agi, int argc, char **argv)
931 return RESULT_SHOWUSAGE;
933 if (option_verbose > 2)
934 ast_verbose(VERBOSE_PREFIX_3 "AGI Script Executing Application: (%s) Options: (%s)\n", argv[1], argv[2]);
936 app = pbx_findapp(argv[1]);
939 res = pbx_exec(chan, app, argv[2], 1);
941 ast_log(LOG_WARNING, "Could not find application (%s)\n", argv[1]);
944 fdprintf(agi->fd, "200 result=%d\n", res);
949 static int handle_setcallerid(struct ast_channel *chan, AGI *agi, int argc, char **argv)
952 char *l = NULL, *n = NULL;
955 strncpy(tmp, argv[2], sizeof(tmp) - 1);
956 ast_callerid_parse(tmp, &n, &l);
958 ast_shrink_phone_number(l);
963 ast_set_callerid(chan, l, n, NULL);
966 fdprintf(agi->fd, "200 result=1\n");
967 return RESULT_SUCCESS;
970 static int handle_channelstatus(struct ast_channel *chan, AGI *agi, int argc, char **argv)
972 struct ast_channel *c;
974 /* no argument: supply info on the current channel */
975 fdprintf(agi->fd, "200 result=%d\n", chan->_state);
976 return RESULT_SUCCESS;
977 } else if (argc == 3) {
978 /* one argument: look for info on the specified channel */
979 c = ast_channel_walk_locked(NULL);
981 if (strcasecmp(argv[2],c->name)==0) {
982 fdprintf(agi->fd, "200 result=%d\n", c->_state);
983 ast_mutex_unlock(&c->lock);
984 return RESULT_SUCCESS;
986 ast_mutex_unlock(&c->lock);
987 c = ast_channel_walk_locked(c);
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_setvariable(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1000 pbx_builtin_setvar_helper(chan, argv[2], argv[3]);
1002 fdprintf(agi->fd, "200 result=1\n");
1003 return RESULT_SUCCESS;
1006 static int handle_getvariable(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1012 return RESULT_SHOWUSAGE;
1013 pbx_retrieve_variable(chan, argv[2], &ret, tempstr, sizeof(tempstr), NULL);
1015 fdprintf(agi->fd, "200 result=1 (%s)\n", ret);
1017 fdprintf(agi->fd, "200 result=0\n");
1019 return RESULT_SUCCESS;
1022 static int handle_getvariablefull(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1025 struct ast_channel *chan2=NULL;
1027 if ((argc != 4) && (argc != 5))
1028 return RESULT_SHOWUSAGE;
1030 while((chan2 = ast_channel_walk_locked(chan2))) {
1031 if (!strcmp(chan2->name, argv[4]))
1033 ast_mutex_unlock(&chan2->lock);
1039 pbx_substitute_variables_helper(chan2, argv[3], tmp, sizeof(tmp) - 1);
1040 fdprintf(agi->fd, "200 result=1 (%s)\n", tmp);
1042 fdprintf(agi->fd, "200 result=0\n");
1044 if (chan2 && (chan2 != chan))
1045 ast_mutex_unlock(&chan2->lock);
1046 return RESULT_SUCCESS;
1049 static int handle_verbose(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1055 return RESULT_SHOWUSAGE;
1058 sscanf(argv[2], "%d", &level);
1062 prefix = VERBOSE_PREFIX_4;
1065 prefix = VERBOSE_PREFIX_3;
1068 prefix = VERBOSE_PREFIX_2;
1072 prefix = VERBOSE_PREFIX_1;
1076 if (level <= option_verbose)
1077 ast_verbose("%s %s: %s\n", prefix, chan->data, argv[1]);
1079 fdprintf(agi->fd, "200 result=1\n");
1081 return RESULT_SUCCESS;
1084 static int handle_dbget(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1090 return RESULT_SHOWUSAGE;
1091 res = ast_db_get(argv[2], argv[3], tmp, sizeof(tmp));
1093 fdprintf(agi->fd, "200 result=0\n");
1095 fdprintf(agi->fd, "200 result=1 (%s)\n", tmp);
1097 return RESULT_SUCCESS;
1100 static int handle_dbput(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1105 return RESULT_SHOWUSAGE;
1106 res = ast_db_put(argv[2], argv[3], argv[4]);
1108 fdprintf(agi->fd, "200 result=0\n");
1110 fdprintf(agi->fd, "200 result=1\n");
1112 return RESULT_SUCCESS;
1115 static int handle_dbdel(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1120 return RESULT_SHOWUSAGE;
1121 res = ast_db_del(argv[2], argv[3]);
1123 fdprintf(agi->fd, "200 result=0\n");
1125 fdprintf(agi->fd, "200 result=1\n");
1127 return RESULT_SUCCESS;
1130 static int handle_dbdeltree(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1133 if ((argc < 3) || (argc > 4))
1134 return RESULT_SHOWUSAGE;
1136 res = ast_db_deltree(argv[2], argv[3]);
1138 res = ast_db_deltree(argv[2], NULL);
1141 fdprintf(agi->fd, "200 result=0\n");
1143 fdprintf(agi->fd, "200 result=1\n");
1144 return RESULT_SUCCESS;
1147 static char debug_usage[] =
1148 "Usage: agi debug\n"
1149 " Enables dumping of AGI transactions for debugging purposes\n";
1151 static char no_debug_usage[] =
1152 "Usage: agi no debug\n"
1153 " Disables dumping of AGI transactions for debugging purposes\n";
1155 static int agi_do_debug(int fd, int argc, char *argv[])
1158 return RESULT_SHOWUSAGE;
1160 ast_cli(fd, "AGI Debugging Enabled\n");
1161 return RESULT_SUCCESS;
1164 static int agi_no_debug(int fd, int argc, char *argv[])
1167 return RESULT_SHOWUSAGE;
1169 ast_cli(fd, "AGI Debugging Disabled\n");
1170 return RESULT_SUCCESS;
1173 static struct ast_cli_entry cli_debug =
1174 { { "agi", "debug", NULL }, agi_do_debug, "Enable AGI debugging", debug_usage };
1176 static struct ast_cli_entry cli_no_debug =
1177 { { "agi", "no", "debug", NULL }, agi_no_debug, "Disable AGI debugging", no_debug_usage };
1179 static int handle_noop(struct ast_channel *chan, AGI *agi, int arg, char *argv[])
1181 fdprintf(agi->fd, "200 result=0\n");
1182 return RESULT_SUCCESS;
1185 static int handle_setmusic(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
1187 if (!strncasecmp(argv[2],"on",2)) {
1189 ast_moh_start(chan, argv[3]);
1191 ast_moh_start(chan, NULL);
1193 if (!strncasecmp(argv[2],"off",3)) {
1196 fdprintf(agi->fd, "200 result=0\n");
1197 return RESULT_SUCCESS;
1200 static char usage_setmusic[] =
1201 " Usage: SET MUSIC ON <on|off> <class>\n"
1202 " Enables/Disables the music on hold generator. If <class> is\n"
1203 " not specified, then the default music on hold class will be used.\n"
1204 " Always returns 0.\n";
1206 static char usage_dbput[] =
1207 " Usage: DATABASE PUT <family> <key> <value>\n"
1208 " Adds or updates an entry in the Asterisk database for a\n"
1209 " given family, key, and value.\n"
1210 " Returns 1 if successful, 0 otherwise.\n";
1212 static char usage_dbget[] =
1213 " Usage: DATABASE GET <family> <key>\n"
1214 " Retrieves an entry in the Asterisk database for a\n"
1215 " given family and key.\n"
1216 " Returns 0 if <key> is not set. Returns 1 if <key>\n"
1217 " is set and returns the variable in parentheses.\n"
1218 " Example return code: 200 result=1 (testvariable)\n";
1220 static char usage_dbdel[] =
1221 " Usage: DATABASE DEL <family> <key>\n"
1222 " Deletes an entry in the Asterisk database for a\n"
1223 " given family and key.\n"
1224 " Returns 1 if successful, 0 otherwise.\n";
1226 static char usage_dbdeltree[] =
1227 " Usage: DATABASE DELTREE <family> [keytree]\n"
1228 " Deletes a family or specific keytree within a family\n"
1229 " in the Asterisk database.\n"
1230 " Returns 1 if successful, 0 otherwise.\n";
1232 static char usage_verbose[] =
1233 " Usage: VERBOSE <message> <level>\n"
1234 " Sends <message> to the console via verbose message system.\n"
1235 " <level> is the the verbose level (1-4)\n"
1236 " Always returns 1.\n";
1238 static char usage_getvariable[] =
1239 " Usage: GET VARIABLE <variablename>\n"
1240 " Returns 0 if <variablename> is not set. Returns 1 if <variablename>\n"
1241 " is set and returns the variable in parentheses.\n"
1242 " example return code: 200 result=1 (testvariable)\n";
1244 static char usage_getvariablefull[] =
1245 " Usage: GET FULL VARIABLE <variablename> [<channel name>]\n"
1246 " Returns 0 if <variablename> is not set or channel does not exist. Returns 1\n"
1247 "if <variablename> is set and returns the variable in parenthesis. Understands\n"
1248 "complex variable names and builtin variables, unlike GET VARIABLE.\n"
1249 " example return code: 200 result=1 (testvariable)\n";
1251 static char usage_setvariable[] =
1252 " Usage: SET VARIABLE <variablename> <value>\n";
1254 static char usage_channelstatus[] =
1255 " Usage: CHANNEL STATUS [<channelname>]\n"
1256 " Returns the status of the specified channel.\n"
1257 " If no channel name is given the returns the status of the\n"
1258 " current channel. Return values:\n"
1259 " 0 Channel is down and available\n"
1260 " 1 Channel is down, but reserved\n"
1261 " 2 Channel is off hook\n"
1262 " 3 Digits (or equivalent) have been dialed\n"
1263 " 4 Line is ringing\n"
1264 " 5 Remote end is ringing\n"
1266 " 7 Line is busy\n";
1268 static char usage_setcallerid[] =
1269 " Usage: SET CALLERID <number>\n"
1270 " Changes the callerid of the current channel.\n";
1272 static char usage_exec[] =
1273 " Usage: EXEC <application> <options>\n"
1274 " Executes <application> with given <options>.\n"
1275 " Returns whatever the application returns, or -2 on failure to find application\n";
1277 static char usage_hangup[] =
1278 " Usage: HANGUP [<channelname>]\n"
1279 " Hangs up the specified channel.\n"
1280 " If no channel name is given, hangs up the current channel\n";
1282 static char usage_answer[] =
1284 " Answers channel if not already in answer state. Returns -1 on\n"
1285 " channel failure, or 0 if successful.\n";
1287 static char usage_waitfordigit[] =
1288 " Usage: WAIT FOR DIGIT <timeout>\n"
1289 " Waits up to 'timeout' milliseconds for channel to receive a DTMF digit.\n"
1290 " Returns -1 on channel failure, 0 if no digit is received in the timeout, or\n"
1291 " the numerical value of the ascii of the digit if one is received. Use -1\n"
1292 " for the timeout value if you desire the call to block indefinitely.\n";
1294 static char usage_sendtext[] =
1295 " Usage: SEND TEXT \"<text to send>\"\n"
1296 " Sends the given text on a channel. Most channels do not support the\n"
1297 " transmission of text. Returns 0 if text is sent, or if the channel does not\n"
1298 " support text transmission. Returns -1 only on error/hangup. Text\n"
1299 " consisting of greater than one word should be placed in quotes since the\n"
1300 " command only accepts a single argument.\n";
1302 static char usage_recvchar[] =
1303 " Usage: RECEIVE CHAR <timeout>\n"
1304 " Receives a character of text on a channel. Specify timeout to be the\n"
1305 " maximum time to wait for input in milliseconds, or 0 for infinite. Most channels\n"
1306 " do not support the reception of text. Returns the decimal value of the character\n"
1307 " if one is received, or 0 if the channel does not support text reception. Returns\n"
1308 " -1 only on error/hangup.\n";
1310 static char usage_tddmode[] =
1311 " Usage: TDD MODE <on|off>\n"
1312 " Enable/Disable TDD transmission/reception on a channel. Returns 1 if\n"
1313 " successful, or 0 if channel is not TDD-capable.\n";
1315 static char usage_sendimage[] =
1316 " Usage: SEND IMAGE <image>\n"
1317 " Sends the given image on a channel. Most channels do not support the\n"
1318 " transmission of images. Returns 0 if image is sent, or if the channel does not\n"
1319 " support image transmission. Returns -1 only on error/hangup. Image names\n"
1320 " should not include extensions.\n";
1322 static char usage_streamfile[] =
1323 " Usage: STREAM FILE <filename> <escape digits> [sample offset]\n"
1324 " Send the given file, allowing playback to be interrupted by the given\n"
1325 " digits, if any. Use double quotes for the digits if you wish none to be\n"
1326 " permitted. If sample offset is provided then the audio will seek to sample\n"
1327 " offset before play starts. Returns 0 if playback completes without a digit\n"
1328 " being pressed, or the ASCII numerical value of the digit if one was pressed,\n"
1329 " or -1 on error or if the channel was disconnected. Remember, the file\n"
1330 " extension must not be included in the filename.\n";
1332 static char usage_getoption[] =
1333 " Usage: GET OPTION <filename> <escape_digits> [timeout]\n"
1334 " Behaves similar to STREAM FILE but used with a timeout option.\n";
1336 static char usage_saynumber[] =
1337 " Usage: SAY NUMBER <number> <escape digits>\n"
1338 " Say a given number, returning early if any of the given DTMF digits\n"
1339 " are received on the channel. Returns 0 if playback completes without a digit\n"
1340 " being pressed, or the ASCII numerical value of the digit if one was pressed or\n"
1341 " -1 on error/hangup.\n";
1343 static char usage_saydigits[] =
1344 " Usage: SAY DIGITS <number> <escape digits>\n"
1345 " Say a given digit string, returning early if any of the given DTMF digits\n"
1346 " are received on the channel. Returns 0 if playback completes without a digit\n"
1347 " being pressed, or the ASCII numerical value of the digit if one was pressed or\n"
1348 " -1 on error/hangup.\n";
1350 static char usage_sayalpha[] =
1351 " Usage: SAY ALPHA <number> <escape digits>\n"
1352 " Say a given character string, returning early if any of the given DTMF digits\n"
1353 " are received on the channel. Returns 0 if playback completes without a digit\n"
1354 " being pressed, or the ASCII numerical value of the digit if one was pressed or\n"
1355 " -1 on error/hangup.\n";
1357 static char usage_saytime[] =
1358 " Usage: SAY TIME <time> <escape digits>\n"
1359 " Say a given time, returning early if any of the given DTMF digits are\n"
1360 " received on the channel. <time> is number of seconds elapsed since 00:00:00\n"
1361 " on January 1, 1970, Coordinated Universal Time (UTC). Returns 0 if playback\n"
1362 " completes without a digit being pressed, or the ASCII numerical value of the\n"
1363 " digit if one was pressed or -1 on error/hangup.\n";
1365 static char usage_sayphonetic[] =
1366 " Usage: SAY PHONETIC <string> <escape digits>\n"
1367 " Say a given character string with phonetics, returning early if any of the\n"
1368 " given DTMF digits are received on the channel. Returns 0 if playback\n"
1369 " completes without a digit pressed, the ASCII numerical value of the digit\n"
1370 " if one was pressed, or -1 on error/hangup.\n";
1372 static char usage_getdata[] =
1373 " Usage: GET DATA <file to be streamed> [timeout] [max digits]\n"
1374 " Stream the given file, and recieve DTMF data. Returns the digits received\n"
1375 "from the channel at the other end.\n";
1377 static char usage_setcontext[] =
1378 " Usage: SET CONTEXT <desired context>\n"
1379 " Sets the context for continuation upon exiting the application.\n";
1381 static char usage_setextension[] =
1382 " Usage: SET EXTENSION <new extension>\n"
1383 " Changes the extension for continuation upon exiting the application.\n";
1385 static char usage_setpriority[] =
1386 " Usage: SET PRIORITY <num>\n"
1387 " Changes the priority for continuation upon exiting the application.\n";
1389 static char usage_recordfile[] =
1390 " Usage: RECORD FILE <filename> <format> <escape digits> <timeout> \\\n"
1391 " [offset samples] [BEEP] [s=silence]\n"
1392 " Record to a file until a given dtmf digit in the sequence is received\n"
1393 " Returns -1 on hangup or error. The format will specify what kind of file\n"
1394 " will be recorded. The timeout is the maximum record time in milliseconds, or\n"
1395 " -1 for no timeout. \"Offset samples\" is optional, and, if provided, will seek\n"
1396 " to the offset without exceeding the end of the file. \"silence\" is the number\n"
1397 " of seconds of silence allowed before the function returns despite the\n"
1398 " lack of dtmf digits or reaching timeout. Silence value must be\n"
1399 " preceeded by \"s=\" and is also optional.\n";
1401 static char usage_autohangup[] =
1402 " Usage: SET AUTOHANGUP <time>\n"
1403 " Cause the channel to automatically hangup at <time> seconds in the\n"
1404 " future. Of course it can be hungup before then as well. Setting to 0 will\n"
1405 " cause the autohangup feature to be disabled on this channel.\n";
1407 static char usage_noop[] =
1411 static agi_command commands[MAX_COMMANDS] = {
1412 { { "answer", NULL }, handle_answer, "Answer channel", usage_answer },
1413 { { "channel", "status", NULL }, handle_channelstatus, "Returns status of the connected channel", usage_channelstatus },
1414 { { "database", "del", NULL }, handle_dbdel, "Removes database key/value", usage_dbdel },
1415 { { "database", "deltree", NULL }, handle_dbdeltree, "Removes database keytree/value", usage_dbdeltree },
1416 { { "database", "get", NULL }, handle_dbget, "Gets database value", usage_dbget },
1417 { { "database", "put", NULL }, handle_dbput, "Adds/updates database value", usage_dbput },
1418 { { "exec", NULL }, handle_exec, "Executes a given Application", usage_exec },
1419 { { "get", "data", NULL }, handle_getdata, "Prompts for DTMF on a channel", usage_getdata },
1420 { { "get", "full", "variable", NULL }, handle_getvariablefull, "Evaluates a channel expression", usage_getvariablefull },
1421 { { "get", "option", NULL }, handle_getoption, "Stream file, prompt for DTMF, with timeout", usage_getoption },
1422 { { "get", "variable", NULL }, handle_getvariable, "Gets a channel variable", usage_getvariable },
1423 { { "hangup", NULL }, handle_hangup, "Hangup the current channel", usage_hangup },
1424 { { "noop", NULL }, handle_noop, "Does nothing", usage_noop },
1425 { { "receive", "char", NULL }, handle_recvchar, "Receives text from channels supporting it", usage_recvchar },
1426 { { "record", "file", NULL }, handle_recordfile, "Records to a given file", usage_recordfile },
1427 { { "say", "alpha", NULL }, handle_sayalpha, "Says a given character string", usage_sayalpha },
1428 { { "say", "digits", NULL }, handle_saydigits, "Says a given digit string", usage_saydigits },
1429 { { "say", "number", NULL }, handle_saynumber, "Says a given number", usage_saynumber },
1430 { { "say", "phonetic", NULL }, handle_sayphonetic, "Says a given character string with phonetics", usage_sayphonetic },
1431 { { "say", "time", NULL }, handle_saytime, "Says a given time", usage_saytime },
1432 { { "send", "image", NULL }, handle_sendimage, "Sends images to channels supporting it", usage_sendimage },
1433 { { "send", "text", NULL }, handle_sendtext, "Sends text to channels supporting it", usage_sendtext },
1434 { { "set", "autohangup", NULL }, handle_autohangup, "Autohangup channel in some time", usage_autohangup },
1435 { { "set", "callerid", NULL }, handle_setcallerid, "Sets callerid for the current channel", usage_setcallerid },
1436 { { "set", "context", NULL }, handle_setcontext, "Sets channel context", usage_setcontext },
1437 { { "set", "extension", NULL }, handle_setextension, "Changes channel extension", usage_setextension },
1438 { { "set", "music", NULL }, handle_setmusic, "Enable/Disable Music on hold generator", usage_setmusic },
1439 { { "set", "priority", NULL }, handle_setpriority, "Set channel dialplan priority", usage_setpriority },
1440 { { "set", "variable", NULL }, handle_setvariable, "Sets a channel variable", usage_setvariable },
1441 { { "stream", "file", NULL }, handle_streamfile, "Sends audio file on channel", usage_streamfile },
1442 { { "tdd", "mode", NULL }, handle_tddmode, "Toggles TDD mode (for the deaf)", usage_tddmode },
1443 { { "verbose", NULL }, handle_verbose, "Logs a message to the asterisk verbose log", usage_verbose },
1444 { { "wait", "for", "digit", NULL }, handle_waitfordigit, "Waits for a digit to be pressed", usage_waitfordigit },
1447 static void join(char *s, size_t len, char *w[])
1451 /* Join words into a string */
1456 for (x=0; w[x]; x++) {
1458 strncat(s, " ", len - strlen(s) - 1);
1459 strncat(s, w[x], len - strlen(s) - 1);
1463 static int help_workhorse(int fd, char *match[])
1468 struct agi_command *e;
1470 join(matchstr, sizeof(matchstr), match);
1471 for (x=0;x<sizeof(commands)/sizeof(commands[0]);x++) {
1472 if (!commands[x].cmda[0]) break;
1475 join(fullcmd, sizeof(fullcmd), e->cmda);
1476 /* Hide commands that start with '_' */
1477 if (fullcmd[0] == '_')
1480 if (strncasecmp(matchstr, fullcmd, strlen(matchstr))) {
1484 ast_cli(fd, "%20.20s %s\n", fullcmd, e->summary);
1489 int agi_register(agi_command *agi)
1492 for (x=0; x<MAX_COMMANDS - 1; x++) {
1493 if (commands[x].cmda[0] == agi->cmda[0]) {
1494 ast_log(LOG_WARNING, "Command already registered!\n");
1498 for (x=0; x<MAX_COMMANDS - 1; x++) {
1499 if (!commands[x].cmda[0]) {
1504 ast_log(LOG_WARNING, "No more room for new commands!\n");
1508 void agi_unregister(agi_command *agi)
1511 for (x=0; x<MAX_COMMANDS - 1; x++) {
1512 if (commands[x].cmda[0] == agi->cmda[0]) {
1513 memset(&commands[x], 0, sizeof(agi_command));
1518 static agi_command *find_command(char *cmds[], int exact)
1524 for (x=0; x < sizeof(commands) / sizeof(commands[0]); x++) {
1525 if (!commands[x].cmda[0])
1527 /* start optimistic */
1529 for (y=0; match && cmds[y]; y++) {
1530 /* If there are no more words in the command (and we're looking for
1531 an exact match) or there is a difference between the two words,
1532 then this is not a match */
1533 if (!commands[x].cmda[y] && !exact)
1535 /* don't segfault if the next part of a command doesn't exist */
1536 if (!commands[x].cmda[y])
1538 if (strcasecmp(commands[x].cmda[y], cmds[y]))
1541 /* If more words are needed to complete the command then this is not
1542 a candidate (unless we're looking for a really inexact answer */
1543 if ((exact > -1) && commands[x].cmda[y])
1546 return &commands[x];
1552 static int parse_args(char *s, int *max, char *argv[])
1564 /* If it's escaped, put a literal quote */
1569 if (quoted && whitespace) {
1570 /* If we're starting a quote, coming off white space start a new word, too */
1578 if (!quoted && !escaped) {
1579 /* If we're not quoted, mark this as whitespace, and
1580 end the previous argument */
1584 /* Otherwise, just treat it as anything else */
1588 /* If we're escaped, print a literal, otherwise enable escaping */
1598 if (x >= MAX_ARGS -1) {
1599 ast_log(LOG_WARNING, "Too many arguments, truncating\n");
1602 /* Coming off of whitespace, start the next argument */
1611 /* Null terminate */
1618 static int agi_handle_command(struct ast_channel *chan, AGI *agi, char *buf)
1620 char *argv[MAX_ARGS];
1626 parse_args(buf, &argc, argv);
1629 for (x=0; x<argc; x++)
1630 fprintf(stderr, "Got Arg%d: %s\n", x, argv[x]); }
1632 c = find_command(argv, 0);
1634 res = c->handler(chan, agi, argc, argv);
1636 case RESULT_SHOWUSAGE:
1637 fdprintf(agi->fd, "520-Invalid command syntax. Proper usage follows:\n");
1638 fdprintf(agi->fd, c->usage);
1639 fdprintf(agi->fd, "520 End of proper usage.\n");
1641 case AST_PBX_KEEPALIVE:
1642 /* We've been asked to keep alive, so do so */
1643 return AST_PBX_KEEPALIVE;
1645 case RESULT_FAILURE:
1646 /* They've already given the failure. We've been hung up on so handle this
1651 fdprintf(agi->fd, "510 Invalid or unknown command\n");
1656 static int run_agi(struct ast_channel *chan, char *request, AGI *agi, int pid, int dead)
1658 struct ast_channel *c;
1661 int returnstatus = 0;
1662 struct ast_frame *f;
1665 /* how many times we'll retry if ast_waitfor_nandfs will return without either
1666 channel or file descriptor in case select is interrupted by a system call (EINTR) */
1669 if (!(readf = fdopen(agi->ctrl, "r"))) {
1670 ast_log(LOG_WARNING, "Unable to fdopen file descriptor\n");
1677 setup_env(chan, request, agi->fd, (agi->audio > -1));
1680 c = ast_waitfor_nandfds(&chan, dead ? 0 : 1, &agi->ctrl, 1, NULL, &outfd, &ms);
1683 /* Idle the channel until we get a command */
1686 ast_log(LOG_DEBUG, "%s hungup\n", chan->name);
1690 /* If it's voice, write it to the audio pipe */
1691 if ((agi->audio > -1) && (f->frametype == AST_FRAME_VOICE)) {
1692 /* Write, ignoring errors */
1693 write(agi->audio, f->data, f->datalen);
1697 } else if (outfd > -1) {
1699 if (!fgets(buf, sizeof(buf), readf)) {
1700 /* Program terminated */
1703 if (option_verbose > 2)
1704 ast_verbose(VERBOSE_PREFIX_3 "AGI Script %s completed, returning %d\n", request, returnstatus);
1705 /* No need to kill the pid anymore, since they closed us */
1709 /* get rid of trailing newline, if any */
1710 if (*buf && buf[strlen(buf) - 1] == '\n')
1711 buf[strlen(buf) - 1] = 0;
1713 ast_verbose("AGI Rx << %s\n", buf);
1714 returnstatus |= agi_handle_command(chan, agi, buf);
1715 /* If the handle_command returns -1, we need to stop */
1716 if ((returnstatus < 0) || (returnstatus == AST_PBX_KEEPALIVE)) {
1721 ast_log(LOG_WARNING, "No channel, no fd?\n");
1727 /* Notify process */
1731 return returnstatus;
1734 static int handle_showagi(int fd, int argc, char *argv[]) {
1735 struct agi_command *e;
1738 return RESULT_SHOWUSAGE;
1740 e = find_command(argv + 2, 1);
1742 ast_cli(fd, e->usage);
1744 if (find_command(argv + 2, -1)) {
1745 return help_workhorse(fd, argv + 1);
1747 join(fullcmd, sizeof(fullcmd), argv+1);
1748 ast_cli(fd, "No such command '%s'.\n", fullcmd);
1752 return help_workhorse(fd, NULL);
1754 return RESULT_SUCCESS;
1757 static int handle_dumpagihtml(int fd, int argc, char *argv[]) {
1758 struct agi_command *e;
1765 return RESULT_SHOWUSAGE;
1767 if (!(htmlfile = fopen(argv[2], "wt"))) {
1768 ast_cli(fd, "Could not create file '%s'\n", argv[2]);
1769 return RESULT_SHOWUSAGE;
1772 fprintf(htmlfile, "<HTML>\n<HEAD>\n<TITLE>AGI Commands</TITLE>\n</HEAD>\n");
1773 fprintf(htmlfile, "<BODY>\n<CENTER><B><H1>AGI Commands</H1></B></CENTER>\n\n");
1776 fprintf(htmlfile, "<TABLE BORDER=\"0\" CELLSPACING=\"10\">\n");
1778 for (x=0;x<sizeof(commands)/sizeof(commands[0]);x++) {
1780 if (!commands[x].cmda[0]) break;
1783 join(fullcmd, sizeof(fullcmd), e->cmda);
1784 /* Hide commands that start with '_' */
1785 if (fullcmd[0] == '_')
1788 fprintf(htmlfile, "<TR><TD><TABLE BORDER=\"1\" CELLPADDING=\"5\" WIDTH=\"100%%\">\n");
1789 fprintf(htmlfile, "<TR><TH ALIGN=\"CENTER\"><B>%s - %s</B></TD></TR>\n", fullcmd,e->summary);
1793 tempstr = strsep(&stringp, "\n");
1795 fprintf(htmlfile, "<TR><TD ALIGN=\"CENTER\">%s</TD></TR>\n", tempstr);
1797 fprintf(htmlfile, "<TR><TD ALIGN=\"CENTER\">\n");
1798 while ((tempstr = strsep(&stringp, "\n")) != NULL) {
1799 fprintf(htmlfile, "%s<BR>\n",tempstr);
1802 fprintf(htmlfile, "</TD></TR>\n");
1803 fprintf(htmlfile, "</TABLE></TD></TR>\n\n");
1807 fprintf(htmlfile, "</TABLE>\n</BODY>\n</HTML>\n");
1809 ast_cli(fd, "AGI HTML Commands Dumped to: %s\n", argv[2]);
1810 return RESULT_SUCCESS;
1813 static int agi_exec_full(struct ast_channel *chan, void *data, int enhanced, int dead)
1816 struct localuser *u;
1817 char *argv[MAX_ARGS];
1819 char *tmp = (char *)buf;
1827 if (!data || ast_strlen_zero(data)) {
1828 ast_log(LOG_WARNING, "AGI requires an argument (script)\n");
1831 strncpy(buf, data, sizeof(buf) - 1);
1833 memset(&agi, 0, sizeof(agi));
1834 while ((stringp = strsep(&tmp, "|"))) {
1835 argv[argc++] = stringp;
1841 /* Answer if need be */
1842 if (chan->_state != AST_STATE_UP) {
1843 if (ast_answer(chan)) {
1844 LOCAL_USER_REMOVE(u);
1849 res = launch_script(argv[0], argv, fds, enhanced ? &efd : NULL, &pid);
1854 res = run_agi(chan, argv[0], &agi, pid, dead);
1859 LOCAL_USER_REMOVE(u);
1863 static int agi_exec(struct ast_channel *chan, void *data)
1865 if (chan->_softhangup)
1866 ast_log(LOG_WARNING, "If you want to run AGI on hungup channels you should use DeadAGI!\n");
1867 return agi_exec_full(chan, data, 0, 0);
1870 static int eagi_exec(struct ast_channel *chan, void *data)
1875 if (chan->_softhangup)
1876 ast_log(LOG_WARNING, "If you want to run AGI on hungup channels you should use DeadAGI!\n");
1877 readformat = chan->readformat;
1878 if (ast_set_read_format(chan, AST_FORMAT_SLINEAR)) {
1879 ast_log(LOG_WARNING, "Unable to set channel '%s' to linear mode\n", chan->name);
1882 res = agi_exec_full(chan, data, 1, 0);
1884 if (ast_set_read_format(chan, readformat)) {
1885 ast_log(LOG_WARNING, "Unable to restore channel '%s' to format %s\n", chan->name, ast_getformatname(readformat));
1891 static int deadagi_exec(struct ast_channel *chan, void *data)
1893 return agi_exec_full(chan, data, 0, 1);
1896 static char showagi_help[] =
1897 "Usage: show agi [topic]\n"
1898 " When called with a topic as an argument, displays usage\n"
1899 " information on the given command. If called without a\n"
1900 " topic, it provides a list of AGI commands.\n";
1903 static char dumpagihtml_help[] =
1904 "Usage: dump agihtml <filename>\n"
1905 " Dumps the agi command list in html format to given filename\n";
1907 static struct ast_cli_entry showagi =
1908 { { "show", "agi", NULL }, handle_showagi, "Show AGI commands or specific help", showagi_help };
1910 static struct ast_cli_entry dumpagihtml =
1911 { { "dump", "agihtml", NULL }, handle_dumpagihtml, "Dumps a list of agi command in html format", dumpagihtml_help };
1913 int unload_module(void)
1915 STANDARD_HANGUP_LOCALUSERS;
1916 ast_cli_unregister(&showagi);
1917 ast_cli_unregister(&dumpagihtml);
1918 ast_cli_unregister(&cli_debug);
1919 ast_cli_unregister(&cli_no_debug);
1920 ast_unregister_application(eapp);
1921 ast_unregister_application(deadapp);
1922 return ast_unregister_application(app);
1925 int load_module(void)
1927 ast_cli_register(&showagi);
1928 ast_cli_register(&dumpagihtml);
1929 ast_cli_register(&cli_debug);
1930 ast_cli_register(&cli_no_debug);
1931 ast_register_application(deadapp, deadagi_exec, deadsynopsis, descrip);
1932 ast_register_application(eapp, eagi_exec, esynopsis, descrip);
1933 return ast_register_application(app, agi_exec, synopsis, descrip);
1936 char *description(void)
1944 STANDARD_USECOUNT(res);
1950 return ASTERISK_GPL_KEY;