2 * Asterisk -- A telephony toolkit for Linux.
4 * Asterisk Gateway Interface
6 * Copyright (C) 1999-2004, 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"
53 #define MAX_COMMANDS 128
55 /* Recycle some stuff from the CLI interface */
56 #define fdprintf agi_debug_cli
58 static char *tdesc = "Asterisk Gateway Interface (AGI)";
60 static char *app = "AGI";
62 static char *eapp = "EAGI";
64 static char *deadapp = "DeadAGI";
66 static char *synopsis = "Executes an AGI compliant application";
67 static char *esynopsis = "Executes an EAGI compliant application";
68 static char *deadsynopsis = "Executes AGI on a hungup channel";
70 static char *descrip =
71 " [E|Dead]AGI(command|args): Executes an Asterisk Gateway Interface compliant\n"
72 "program on a channel. AGI allows Asterisk to launch external programs\n"
73 "written in any language to control a telephony channel, play audio,\n"
74 "read DTMF digits, etc. by communicating with the AGI protocol on stdin\n"
76 "Returns -1 on hangup (except for DeadAGI) or if application requested\n"
77 " hangup, or 0 on non-hangup exit. \n"
78 "Using 'EAGI' provides enhanced AGI, with incoming audio available out of band"
79 "on file descriptor 3\n\n"
80 "Use the CLI command 'show agi' to list available agi commands\n";
82 static int agidebug = 0;
89 #define TONE_BLOCK_SIZE 200
91 /* Max time to connect to an AGI remote host */
92 #define MAX_AGI_CONNECT 2000
96 static void agi_debug_cli(int fd, char *fmt, ...)
103 res = vasprintf(&stuff, fmt, ap);
106 ast_log(LOG_ERROR, "Out of memory\n");
109 ast_verbose("AGI Tx >> %s", stuff);
110 ast_carefulwrite(fd, stuff, strlen(stuff), 100);
115 /* launch_netscript: The fastagi handler.
116 FastAGI defaults to port 4573 */
117 static int launch_netscript(char *agiurl, char *argv[], int *fds, int *efd, int *opid)
121 struct pollfd pfds[1];
123 char *c; int port = AGI_PORT;
125 struct sockaddr_in sin;
127 struct ast_hostent ahp;
129 host = ast_strdupa(agiurl + 6); /* Remove agi:// */
132 /* Strip off any script name */
133 if ((c = strchr(host, '/'))) {
138 if ((c = strchr(host, ':'))) {
144 ast_log(LOG_WARNING, "AGI URI's don't support Enhanced AGI yet\n");
147 hp = ast_gethostbyname(host, &ahp);
149 ast_log(LOG_WARNING, "Unable to locate host '%s'\n", host);
152 s = socket(AF_INET, SOCK_STREAM, 0);
154 ast_log(LOG_WARNING, "Unable to create socket: %s\n", strerror(errno));
157 flags = fcntl(s, F_GETFL);
159 ast_log(LOG_WARNING, "Fcntl(F_GETFL) failed: %s\n", strerror(errno));
163 if (fcntl(s, F_SETFL, flags | O_NONBLOCK) < 0) {
164 ast_log(LOG_WARNING, "Fnctl(F_SETFL) failed: %s\n", strerror(errno));
168 memset(&sin, 0, sizeof(sin));
169 sin.sin_family = AF_INET;
170 sin.sin_port = htons(port);
171 memcpy(&sin.sin_addr, hp->h_addr, sizeof(sin.sin_addr));
172 if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) && (errno != EINPROGRESS)) {
173 ast_log(LOG_WARNING, "Connect failed with unexpected error: %s\n", strerror(errno));
178 pfds[0].events = POLLOUT;
179 if (poll(pfds, 1, MAX_AGI_CONNECT) != 1) {
180 ast_log(LOG_WARNING, "Connect to '%s' failed!\n", agiurl);
184 if (write(s, "agi_network: yes\n", strlen("agi_network: yes\n")) < 0) {
185 ast_log(LOG_WARNING, "Connect to '%s' failed: %s\n", agiurl, strerror(errno));
190 /* If we have a script parameter, relay it to the fastagi server */
191 if (!ast_strlen_zero(script))
192 fdprintf(s, "agi_network_script: %s\n", script);
194 if (option_debug > 3)
195 ast_log(LOG_DEBUG, "Wow, connected!\n");
202 static int launch_script(char *script, char *argv[], int *fds, int *efd, int *opid)
212 if (!strncasecmp(script, "agi://", 6))
213 return launch_netscript(script, argv, fds, efd, opid);
215 if (script[0] != '/') {
216 snprintf(tmp, sizeof(tmp), "%s/%s", (char *)ast_config_AST_AGI_DIR, script);
220 ast_log(LOG_WARNING, "Unable to create toast pipe: %s\n",strerror(errno));
224 ast_log(LOG_WARNING, "unable to create fromast pipe: %s\n", strerror(errno));
231 ast_log(LOG_WARNING, "unable to create audio pipe: %s\n", strerror(errno));
238 res = fcntl(audio[1], F_GETFL);
240 res = fcntl(audio[1], F_SETFL, res | O_NONBLOCK);
242 ast_log(LOG_WARNING, "unable to set audio pipe parameters: %s\n", strerror(errno));
254 ast_log(LOG_WARNING, "Failed to fork(): %s\n", strerror(errno));
258 /* Redirect stdin and out, provide enhanced audio channel if desired */
259 dup2(fromast[0], STDIN_FILENO);
260 dup2(toast[1], STDOUT_FILENO);
262 dup2(audio[0], STDERR_FILENO + 1);
264 close(STDERR_FILENO + 1);
266 /* Close everything but stdin/out/error */
267 for (x=STDERR_FILENO + 2;x<1024;x++)
271 /* Can't use ast_log since FD's are closed */
272 fprintf(stderr, "Failed to execute '%s': %s\n", script, strerror(errno));
275 if (option_verbose > 2)
276 ast_verbose(VERBOSE_PREFIX_3 "Launched AGI Script %s\n", script);
282 /* close what we're not using in the parent */
296 static void setup_env(struct ast_channel *chan, char *request, int fd, int enhanced)
298 /* Print initial environment, with agi_request always being the first
300 fdprintf(fd, "agi_request: %s\n", request);
301 fdprintf(fd, "agi_channel: %s\n", chan->name);
302 fdprintf(fd, "agi_language: %s\n", chan->language);
303 fdprintf(fd, "agi_type: %s\n", chan->type);
304 fdprintf(fd, "agi_uniqueid: %s\n", chan->uniqueid);
307 fdprintf(fd, "agi_callerid: %s\n", chan->cid.cid_num ? chan->cid.cid_num : "unknown");
308 fdprintf(fd, "agi_calleridname: %s\n", chan->cid.cid_name ? chan->cid.cid_name : "unknown");
309 fdprintf(fd, "agi_dnid: %s\n", chan->cid.cid_dnid ? chan->cid.cid_dnid : "unknown");
310 fdprintf(fd, "agi_rdnis: %s\n", chan->cid.cid_rdnis ? chan->cid.cid_rdnis : "unknown");
312 /* Context information */
313 fdprintf(fd, "agi_context: %s\n", chan->context);
314 fdprintf(fd, "agi_extension: %s\n", chan->exten);
315 fdprintf(fd, "agi_priority: %d\n", chan->priority);
316 fdprintf(fd, "agi_enhanced: %s\n", enhanced ? "1.0" : "0.0");
318 /* User information */
319 fdprintf(fd, "agi_accountcode: %s\n", chan->accountcode ? chan->accountcode : "");
321 /* End with empty return */
325 static int handle_answer(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
329 if (chan->_state != AST_STATE_UP) {
330 /* Answer the chan */
331 res = ast_answer(chan);
333 fdprintf(agi->fd, "200 result=%d\n", res);
335 return RESULT_SUCCESS;
337 return RESULT_FAILURE;
340 static int handle_waitfordigit(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
345 return RESULT_SHOWUSAGE;
346 if (sscanf(argv[3], "%i", &to) != 1)
347 return RESULT_SHOWUSAGE;
348 res = ast_waitfordigit_full(chan, to, agi->audio, agi->ctrl);
349 fdprintf(agi->fd, "200 result=%d\n", res);
351 return RESULT_SUCCESS;
353 return RESULT_FAILURE;
356 static int handle_sendtext(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
360 return RESULT_SHOWUSAGE;
361 /* At the moment, the parser (perhaps broken) returns with
362 the last argument PLUS the newline at the end of the input
363 buffer. This probably needs to be fixed, but I wont do that
364 because other stuff may break as a result. The right way
365 would probably be to strip off the trailing newline before
366 parsing, then here, add a newline at the end of the string
367 before sending it to ast_sendtext --DUDE */
368 res = ast_sendtext(chan, argv[2]);
369 fdprintf(agi->fd, "200 result=%d\n", res);
371 return RESULT_SUCCESS;
373 return RESULT_FAILURE;
376 static int handle_recvchar(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
380 return RESULT_SHOWUSAGE;
381 res = ast_recvchar(chan,atoi(argv[2]));
383 fdprintf(agi->fd, "200 result=%d (timeout)\n", res);
384 return RESULT_SUCCESS;
387 fdprintf(agi->fd, "200 result=%d\n", res);
388 return RESULT_SUCCESS;
391 fdprintf(agi->fd, "200 result=%d (hangup)\n", res);
392 return RESULT_FAILURE;
396 static int handle_tddmode(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
400 return RESULT_SHOWUSAGE;
401 if (!strncasecmp(argv[2],"on",2))
405 if (!strncasecmp(argv[2],"mate",4))
407 if (!strncasecmp(argv[2],"tdd",3))
409 res = ast_channel_setoption(chan, AST_OPTION_TDD, &x, sizeof(char), 0);
410 fdprintf(agi->fd, "200 result=%d\n", res);
412 return RESULT_SUCCESS;
414 return RESULT_FAILURE;
417 static int handle_sendimage(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
421 return RESULT_SHOWUSAGE;
422 res = ast_send_image(chan, argv[2]);
423 if (!ast_check_hangup(chan))
425 fdprintf(agi->fd, "200 result=%d\n", res);
427 return RESULT_SUCCESS;
429 return RESULT_FAILURE;
432 static int handle_streamfile(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
435 struct ast_filestream *fs;
436 long sample_offset = 0;
440 return RESULT_SHOWUSAGE;
442 return RESULT_SHOWUSAGE;
443 if ((argc > 4) && (sscanf(argv[4], "%ld", &sample_offset) != 1))
444 return RESULT_SHOWUSAGE;
446 fs = ast_openstream(chan, argv[2], chan->language);
448 fdprintf(agi->fd, "200 result=%d endpos=%ld\n", 0, sample_offset);
449 return RESULT_SUCCESS;
451 ast_seekstream(fs, 0, SEEK_END);
452 max_length = ast_tellstream(fs);
453 ast_seekstream(fs, sample_offset, SEEK_SET);
454 res = ast_applystream(chan, fs);
455 res = ast_playstream(fs);
457 fdprintf(agi->fd, "200 result=%d endpos=%ld\n", res, sample_offset);
459 return RESULT_SHOWUSAGE;
461 return RESULT_FAILURE;
463 res = ast_waitstream_full(chan, argv[3], agi->audio, agi->ctrl);
464 /* this is to check for if ast_waitstream closed the stream, we probably are at
465 * the end of the stream, return that amount, else check for the amount */
466 sample_offset = (chan->stream) ? ast_tellstream(fs) : max_length;
467 ast_stopstream(chan);
469 /* Stop this command, don't print a result line, as there is a new command */
470 return RESULT_SUCCESS;
472 fdprintf(agi->fd, "200 result=%d endpos=%ld\n", res, sample_offset);
474 return RESULT_SUCCESS;
476 return RESULT_FAILURE;
479 /* get option - really similar to the handle_streamfile, but with a timeout */
480 static int handle_getoption(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
483 struct ast_filestream *fs;
484 long sample_offset = 0;
487 char *edigits = NULL;
489 if ( argc < 4 || argc > 5 )
490 return RESULT_SHOWUSAGE;
496 timeout = atoi(argv[4]);
497 else if (chan->pbx->dtimeout) {
498 /* by default dtimeout is set to 5sec */
499 timeout = chan->pbx->dtimeout * 1000; /* in msec */
502 fs = ast_openstream(chan, argv[2], chan->language);
504 fdprintf(agi->fd, "200 result=%d endpos=%ld\n", 0, sample_offset);
505 ast_log(LOG_WARNING, "Unable to open %s\n", argv[2]);
506 return RESULT_FAILURE;
508 if (option_verbose > 2)
509 ast_verbose(VERBOSE_PREFIX_3 "Playing '%s' (escape_digits=%s) (timeout %d)\n", argv[2], edigits, timeout);
511 ast_seekstream(fs, 0, SEEK_END);
512 max_length = ast_tellstream(fs);
513 ast_seekstream(fs, sample_offset, SEEK_SET);
514 res = ast_applystream(chan, fs);
515 res = ast_playstream(fs);
517 fdprintf(agi->fd, "200 result=%d endpos=%ld\n", res, sample_offset);
519 return RESULT_SHOWUSAGE;
521 return RESULT_FAILURE;
523 res = ast_waitstream_full(chan, argv[3], agi->audio, agi->ctrl);
524 /* this is to check for if ast_waitstream closed the stream, we probably are at
525 * the end of the stream, return that amount, else check for the amount */
526 sample_offset = (chan->stream)?ast_tellstream(fs):max_length;
527 ast_stopstream(chan);
529 /* Stop this command, don't print a result line, as there is a new command */
530 return RESULT_SUCCESS;
533 /* If the user didnt press a key, wait for digitTimeout*/
535 res = ast_waitfordigit_full(chan, timeout, agi->audio, agi->ctrl);
536 /* Make sure the new result is in the escape digits of the GET OPTION */
537 if ( !strchr(edigits,res) )
541 fdprintf(agi->fd, "200 result=%d endpos=%ld\n", res, sample_offset);
543 return RESULT_SUCCESS;
545 return RESULT_FAILURE;
551 /*--- handle_saynumber: Say number in various language syntaxes ---*/
552 /* Need to add option for gender here as well. Coders wanted */
553 /* While waiting, we're sending a (char *) NULL. */
554 static int handle_saynumber(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
559 return RESULT_SHOWUSAGE;
560 if (sscanf(argv[2], "%i", &num) != 1)
561 return RESULT_SHOWUSAGE;
562 res = ast_say_number_full(chan, num, argv[3], chan->language, (char *) NULL, agi->audio, agi->ctrl);
564 return RESULT_SUCCESS;
565 fdprintf(agi->fd, "200 result=%d\n", res);
567 return RESULT_SUCCESS;
569 return RESULT_FAILURE;
572 static int handle_saydigits(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
578 return RESULT_SHOWUSAGE;
579 if (sscanf(argv[2], "%i", &num) != 1)
580 return RESULT_SHOWUSAGE;
582 res = ast_say_digit_str_full(chan, argv[2], argv[3], chan->language, agi->audio, agi->ctrl);
583 if (res == 1) /* New command */
584 return RESULT_SUCCESS;
585 fdprintf(agi->fd, "200 result=%d\n", res);
587 return RESULT_SUCCESS;
589 return RESULT_FAILURE;
592 static int handle_sayalpha(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
597 return RESULT_SHOWUSAGE;
599 res = ast_say_character_str_full(chan, argv[2], argv[3], chan->language, agi->audio, agi->ctrl);
600 if (res == 1) /* New command */
601 return RESULT_SUCCESS;
602 fdprintf(agi->fd, "200 result=%d\n", res);
604 return RESULT_SUCCESS;
606 return RESULT_FAILURE;
609 static int handle_saytime(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
614 return RESULT_SHOWUSAGE;
615 if (sscanf(argv[2], "%i", &num) != 1)
616 return RESULT_SHOWUSAGE;
617 res = ast_say_time(chan, num, argv[3], chan->language);
619 return RESULT_SUCCESS;
620 fdprintf(agi->fd, "200 result=%d\n", res);
622 return RESULT_SUCCESS;
624 return RESULT_FAILURE;
627 static int handle_sayphonetic(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
632 return RESULT_SHOWUSAGE;
634 res = ast_say_phonetic_str_full(chan, argv[2], argv[3], chan->language, agi->audio, agi->ctrl);
635 if (res == 1) /* New command */
636 return RESULT_SUCCESS;
637 fdprintf(agi->fd, "200 result=%d\n", res);
639 return RESULT_SUCCESS;
641 return RESULT_FAILURE;
644 static int handle_getdata(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
652 return RESULT_SHOWUSAGE;
654 timeout = atoi(argv[3]);
661 res = ast_app_getdata_full(chan, argv[2], data, max, timeout, agi->audio, agi->ctrl);
662 if (res == 2) /* New command */
663 return RESULT_SUCCESS;
665 fdprintf(agi->fd, "200 result=%s (timeout)\n", data);
667 fdprintf(agi->fd, "200 result=-1\n");
669 fdprintf(agi->fd, "200 result=%s\n", data);
671 return RESULT_SUCCESS;
673 return RESULT_FAILURE;
676 static int handle_setcontext(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
680 return RESULT_SHOWUSAGE;
681 strncpy(chan->context, argv[2], sizeof(chan->context)-1);
682 fdprintf(agi->fd, "200 result=0\n");
683 return RESULT_SUCCESS;
686 static int handle_setextension(struct ast_channel *chan, AGI *agi, int argc, char **argv)
689 return RESULT_SHOWUSAGE;
690 strncpy(chan->exten, argv[2], sizeof(chan->exten)-1);
691 fdprintf(agi->fd, "200 result=0\n");
692 return RESULT_SUCCESS;
695 static int handle_setpriority(struct ast_channel *chan, AGI *agi, int argc, char **argv)
699 return RESULT_SHOWUSAGE;
700 if (sscanf(argv[2], "%i", &pri) != 1)
701 return RESULT_SHOWUSAGE;
702 chan->priority = pri - 1;
703 fdprintf(agi->fd, "200 result=0\n");
704 return RESULT_SUCCESS;
707 static int handle_recordfile(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
709 struct ast_filestream *fs;
711 struct timeval tv, start;
712 long sample_offset = 0;
716 struct ast_dsp *sildet=NULL; /* silence detector dsp */
717 int totalsilence = 0;
719 int silence = 0; /* amount of silence to allow */
720 int gotsilence = 0; /* did we timeout for silence? */
721 char *silencestr=NULL;
725 /* XXX EAGI FIXME XXX */
728 return RESULT_SHOWUSAGE;
729 if (sscanf(argv[5], "%i", &ms) != 1)
730 return RESULT_SHOWUSAGE;
733 silencestr = strchr(argv[6],'s');
734 if ((argc > 7) && (!silencestr))
735 silencestr = strchr(argv[7],'s');
736 if ((argc > 8) && (!silencestr))
737 silencestr = strchr(argv[8],'s');
740 if (strlen(silencestr) > 2) {
741 if ((silencestr[0] == 's') && (silencestr[1] == '=')) {
745 silence = atoi(silencestr);
753 rfmt = chan->readformat;
754 res = ast_set_read_format(chan, AST_FORMAT_SLINEAR);
756 ast_log(LOG_WARNING, "Unable to set to linear mode, giving up\n");
759 sildet = ast_dsp_new();
761 ast_log(LOG_WARNING, "Unable to create silence detector :(\n");
764 ast_dsp_set_threshold(sildet, 256);
767 /* backward compatibility, if no offset given, arg[6] would have been
768 * caught below and taken to be a beep, else if it is a digit then it is a
770 if ((argc >6) && (sscanf(argv[6], "%ld", &sample_offset) != 1) && (!strchr(argv[6], '=')))
771 res = ast_streamfile(chan, "beep", chan->language);
773 if ((argc > 7) && (!strchr(argv[7], '=')))
774 res = ast_streamfile(chan, "beep", chan->language);
777 res = ast_waitstream(chan, argv[4]);
779 fs = ast_writefile(argv[2], argv[3], NULL, O_CREAT | O_WRONLY | (sample_offset ? O_APPEND : 0), 0, 0644);
782 fdprintf(agi->fd, "200 result=%d (writefile)\n", res);
784 ast_dsp_free(sildet);
785 return RESULT_FAILURE;
789 ast_applystream(chan,fs);
790 /* really should have checks */
791 ast_seekstream(fs, sample_offset, SEEK_SET);
794 gettimeofday(&start, NULL);
795 gettimeofday(&tv, NULL);
796 while ((ms < 0) || (((tv.tv_sec - start.tv_sec) * 1000 + (tv.tv_usec - start.tv_usec)/1000) < ms)) {
797 res = ast_waitfor(chan, -1);
800 fdprintf(agi->fd, "200 result=%d (waitfor) endpos=%ld\n", res,sample_offset);
802 ast_dsp_free(sildet);
803 return RESULT_FAILURE;
807 fdprintf(agi->fd, "200 result=%d (hangup) endpos=%ld\n", 0, sample_offset);
810 ast_dsp_free(sildet);
811 return RESULT_FAILURE;
813 switch(f->frametype) {
815 if (strchr(argv[4], f->subclass)) {
816 /* This is an interrupting chracter */
817 sample_offset = ast_tellstream(fs);
818 fdprintf(agi->fd, "200 result=%d (dtmf) endpos=%ld\n", f->subclass, sample_offset);
822 ast_dsp_free(sildet);
823 return RESULT_SUCCESS;
826 case AST_FRAME_VOICE:
827 ast_writestream(fs, f);
828 /* this is a safe place to check progress since we know that fs
829 * is valid after a write, and it will then have our current
831 sample_offset = ast_tellstream(fs);
834 ast_dsp_silence(sildet, f, &dspsilence);
836 totalsilence = dspsilence;
840 if (totalsilence > silence) {
841 /* Ended happily with silence */
850 gettimeofday(&tv, NULL);
856 ast_stream_rewind(fs, silence-1000);
858 sample_offset = ast_tellstream(fs);
860 fdprintf(agi->fd, "200 result=%d (timeout) endpos=%ld\n", res, sample_offset);
863 fdprintf(agi->fd, "200 result=%d (randomerror) endpos=%ld\n", res, sample_offset);
866 res = ast_set_read_format(chan, rfmt);
868 ast_log(LOG_WARNING, "Unable to restore read format on '%s'\n", chan->name);
869 ast_dsp_free(sildet);
871 return RESULT_SUCCESS;
874 static int handle_autohangup(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
879 return RESULT_SHOWUSAGE;
880 if (sscanf(argv[2], "%d", &timeout) != 1)
881 return RESULT_SHOWUSAGE;
885 chan->whentohangup = time(NULL) + timeout;
887 chan->whentohangup = 0;
888 fdprintf(agi->fd, "200 result=0\n");
889 return RESULT_SUCCESS;
892 static int handle_hangup(struct ast_channel *chan, AGI *agi, int argc, char **argv)
894 struct ast_channel *c;
896 /* no argument: hangup the current channel */
897 ast_softhangup(chan,AST_SOFTHANGUP_EXPLICIT);
898 fdprintf(agi->fd, "200 result=1\n");
899 return RESULT_SUCCESS;
900 } else if (argc == 2) {
901 /* one argument: look for info on the specified channel */
902 c = ast_channel_walk_locked(NULL);
904 if (strcasecmp(argv[1], c->name) == 0) {
905 /* we have a matching channel */
906 ast_softhangup(c,AST_SOFTHANGUP_EXPLICIT);
907 fdprintf(agi->fd, "200 result=1\n");
908 ast_mutex_unlock(&c->lock);
909 return RESULT_SUCCESS;
911 ast_mutex_unlock(&c->lock);
912 c = ast_channel_walk_locked(c);
914 /* if we get this far no channel name matched the argument given */
915 fdprintf(agi->fd, "200 result=-1\n");
916 return RESULT_SUCCESS;
918 return RESULT_SHOWUSAGE;
922 static int handle_exec(struct ast_channel *chan, AGI *agi, int argc, char **argv)
928 return RESULT_SHOWUSAGE;
930 if (option_verbose > 2)
931 ast_verbose(VERBOSE_PREFIX_3 "AGI Script Executing Application: (%s) Options: (%s)\n", argv[1], argv[2]);
933 app = pbx_findapp(argv[1]);
936 res = pbx_exec(chan, app, argv[2], 1);
938 ast_log(LOG_WARNING, "Could not find application (%s)\n", argv[1]);
941 fdprintf(agi->fd, "200 result=%d\n", res);
946 static int handle_setcallerid(struct ast_channel *chan, AGI *agi, int argc, char **argv)
949 char *l = NULL, *n = NULL;
952 strncpy(tmp, argv[2], sizeof(tmp) - 1);
953 ast_callerid_parse(tmp, &n, &l);
955 ast_shrink_phone_number(l);
960 ast_set_callerid(chan, l, n, NULL);
963 fdprintf(agi->fd, "200 result=1\n");
964 return RESULT_SUCCESS;
967 static int handle_channelstatus(struct ast_channel *chan, AGI *agi, int argc, char **argv)
969 struct ast_channel *c;
971 /* no argument: supply info on the current channel */
972 fdprintf(agi->fd, "200 result=%d\n", chan->_state);
973 return RESULT_SUCCESS;
974 } else if (argc == 3) {
975 /* one argument: look for info on the specified channel */
976 c = ast_channel_walk_locked(NULL);
978 if (strcasecmp(argv[2],c->name)==0) {
979 fdprintf(agi->fd, "200 result=%d\n", c->_state);
980 ast_mutex_unlock(&c->lock);
981 return RESULT_SUCCESS;
983 ast_mutex_unlock(&c->lock);
984 c = ast_channel_walk_locked(c);
986 /* if we get this far no channel name matched the argument given */
987 fdprintf(agi->fd, "200 result=-1\n");
988 return RESULT_SUCCESS;
990 return RESULT_SHOWUSAGE;
994 static int handle_setvariable(struct ast_channel *chan, AGI *agi, int argc, char **argv)
997 pbx_builtin_setvar_helper(chan, argv[2], argv[3]);
999 fdprintf(agi->fd, "200 result=1\n");
1000 return RESULT_SUCCESS;
1003 static int handle_getvariable(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1009 return RESULT_SHOWUSAGE;
1010 pbx_retrieve_variable(chan, argv[2], &ret, tempstr, sizeof(tempstr), NULL);
1012 fdprintf(agi->fd, "200 result=1 (%s)\n", ret);
1014 fdprintf(agi->fd, "200 result=0\n");
1016 return RESULT_SUCCESS;
1019 static int handle_getvariablefull(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1022 struct ast_channel *chan2=NULL;
1024 if ((argc != 4) && (argc != 5))
1025 return RESULT_SHOWUSAGE;
1027 while((chan2 = ast_channel_walk_locked(chan2))) {
1028 if (!strcmp(chan2->name, argv[4]))
1030 ast_mutex_unlock(&chan2->lock);
1036 pbx_substitute_variables_helper(chan2, argv[3], tmp, sizeof(tmp) - 1);
1037 fdprintf(agi->fd, "200 result=1 (%s)\n", tmp);
1039 fdprintf(agi->fd, "200 result=0\n");
1041 if (chan2 && (chan2 != chan))
1042 ast_mutex_unlock(&chan2->lock);
1043 return RESULT_SUCCESS;
1046 static int handle_verbose(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1052 return RESULT_SHOWUSAGE;
1055 sscanf(argv[2], "%d", &level);
1059 prefix = VERBOSE_PREFIX_4;
1062 prefix = VERBOSE_PREFIX_3;
1065 prefix = VERBOSE_PREFIX_2;
1069 prefix = VERBOSE_PREFIX_1;
1073 if (level <= option_verbose)
1074 ast_verbose("%s %s: %s\n", prefix, chan->data, argv[1]);
1076 fdprintf(agi->fd, "200 result=1\n");
1078 return RESULT_SUCCESS;
1081 static int handle_dbget(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1087 return RESULT_SHOWUSAGE;
1088 res = ast_db_get(argv[2], argv[3], tmp, sizeof(tmp));
1090 fdprintf(agi->fd, "200 result=0\n");
1092 fdprintf(agi->fd, "200 result=1 (%s)\n", tmp);
1094 return RESULT_SUCCESS;
1097 static int handle_dbput(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1102 return RESULT_SHOWUSAGE;
1103 res = ast_db_put(argv[2], argv[3], argv[4]);
1105 fdprintf(agi->fd, "200 result=0\n");
1107 fdprintf(agi->fd, "200 result=1\n");
1109 return RESULT_SUCCESS;
1112 static int handle_dbdel(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1117 return RESULT_SHOWUSAGE;
1118 res = ast_db_del(argv[2], argv[3]);
1120 fdprintf(agi->fd, "200 result=0\n");
1122 fdprintf(agi->fd, "200 result=1\n");
1124 return RESULT_SUCCESS;
1127 static int handle_dbdeltree(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1130 if ((argc < 3) || (argc > 4))
1131 return RESULT_SHOWUSAGE;
1133 res = ast_db_deltree(argv[2], argv[3]);
1135 res = ast_db_deltree(argv[2], NULL);
1138 fdprintf(agi->fd, "200 result=0\n");
1140 fdprintf(agi->fd, "200 result=1\n");
1141 return RESULT_SUCCESS;
1144 static char debug_usage[] =
1145 "Usage: agi debug\n"
1146 " Enables dumping of AGI transactions for debugging purposes\n";
1148 static char no_debug_usage[] =
1149 "Usage: agi no debug\n"
1150 " Disables dumping of AGI transactions for debugging purposes\n";
1152 static int agi_do_debug(int fd, int argc, char *argv[])
1155 return RESULT_SHOWUSAGE;
1157 ast_cli(fd, "AGI Debugging Enabled\n");
1158 return RESULT_SUCCESS;
1161 static int agi_no_debug(int fd, int argc, char *argv[])
1164 return RESULT_SHOWUSAGE;
1166 ast_cli(fd, "AGI Debugging Disabled\n");
1167 return RESULT_SUCCESS;
1170 static struct ast_cli_entry cli_debug =
1171 { { "agi", "debug", NULL }, agi_do_debug, "Enable AGI debugging", debug_usage };
1173 static struct ast_cli_entry cli_no_debug =
1174 { { "agi", "no", "debug", NULL }, agi_no_debug, "Disable AGI debugging", no_debug_usage };
1176 static int handle_noop(struct ast_channel *chan, AGI *agi, int arg, char *argv[])
1178 fdprintf(agi->fd, "200 result=0\n");
1179 return RESULT_SUCCESS;
1182 static int handle_setmusic(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
1184 if (!strncasecmp(argv[2],"on",2)) {
1186 ast_moh_start(chan, argv[3]);
1188 ast_moh_start(chan, NULL);
1190 if (!strncasecmp(argv[2],"off",3)) {
1193 fdprintf(agi->fd, "200 result=0\n");
1194 return RESULT_SUCCESS;
1197 static char usage_setmusic[] =
1198 " Usage: SET MUSIC ON <on|off> <class>\n"
1199 " Enables/Disables the music on hold generator. If <class> is\n"
1200 " not specified, then the default music on hold class will be used.\n"
1201 " Always returns 0.\n";
1203 static char usage_dbput[] =
1204 " Usage: DATABASE PUT <family> <key> <value>\n"
1205 " Adds or updates an entry in the Asterisk database for a\n"
1206 " given family, key, and value.\n"
1207 " Returns 1 if successful, 0 otherwise.\n";
1209 static char usage_dbget[] =
1210 " Usage: DATABASE GET <family> <key>\n"
1211 " Retrieves an entry in the Asterisk database for a\n"
1212 " given family and key.\n"
1213 " Returns 0 if <key> is not set. Returns 1 if <key>\n"
1214 " is set and returns the variable in parentheses.\n"
1215 " Example return code: 200 result=1 (testvariable)\n";
1217 static char usage_dbdel[] =
1218 " Usage: DATABASE DEL <family> <key>\n"
1219 " Deletes an entry in the Asterisk database for a\n"
1220 " given family and key.\n"
1221 " Returns 1 if successful, 0 otherwise.\n";
1223 static char usage_dbdeltree[] =
1224 " Usage: DATABASE DELTREE <family> [keytree]\n"
1225 " Deletes a family or specific keytree within a family\n"
1226 " in the Asterisk database.\n"
1227 " Returns 1 if successful, 0 otherwise.\n";
1229 static char usage_verbose[] =
1230 " Usage: VERBOSE <message> <level>\n"
1231 " Sends <message> to the console via verbose message system.\n"
1232 " <level> is the the verbose level (1-4)\n"
1233 " Always returns 1.\n";
1235 static char usage_getvariable[] =
1236 " Usage: GET VARIABLE <variablename>\n"
1237 " Returns 0 if <variablename> is not set. Returns 1 if <variablename>\n"
1238 " is set and returns the variable in parentheses.\n"
1239 " example return code: 200 result=1 (testvariable)\n";
1241 static char usage_getvariablefull[] =
1242 " Usage: GET FULL VARIABLE <variablename> [<channel name>]\n"
1243 " Returns 0 if <variablename> is not set or channel does not exist. Returns 1\n"
1244 "if <variablename> is set and returns the variable in parenthesis. Understands\n"
1245 "complex variable names and builtin variables, unlike GET VARIABLE.\n"
1246 " example return code: 200 result=1 (testvariable)\n";
1248 static char usage_setvariable[] =
1249 " Usage: SET VARIABLE <variablename> <value>\n";
1251 static char usage_channelstatus[] =
1252 " Usage: CHANNEL STATUS [<channelname>]\n"
1253 " Returns the status of the specified channel.\n"
1254 " If no channel name is given the returns the status of the\n"
1255 " current channel. Return values:\n"
1256 " 0 Channel is down and available\n"
1257 " 1 Channel is down, but reserved\n"
1258 " 2 Channel is off hook\n"
1259 " 3 Digits (or equivalent) have been dialed\n"
1260 " 4 Line is ringing\n"
1261 " 5 Remote end is ringing\n"
1263 " 7 Line is busy\n";
1265 static char usage_setcallerid[] =
1266 " Usage: SET CALLERID <number>\n"
1267 " Changes the callerid of the current channel.\n";
1269 static char usage_exec[] =
1270 " Usage: EXEC <application> <options>\n"
1271 " Executes <application> with given <options>.\n"
1272 " Returns whatever the application returns, or -2 on failure to find application\n";
1274 static char usage_hangup[] =
1275 " Usage: HANGUP [<channelname>]\n"
1276 " Hangs up the specified channel.\n"
1277 " If no channel name is given, hangs up the current channel\n";
1279 static char usage_answer[] =
1281 " Answers channel if not already in answer state. Returns -1 on\n"
1282 " channel failure, or 0 if successful.\n";
1284 static char usage_waitfordigit[] =
1285 " Usage: WAIT FOR DIGIT <timeout>\n"
1286 " Waits up to 'timeout' milliseconds for channel to receive a DTMF digit.\n"
1287 " Returns -1 on channel failure, 0 if no digit is received in the timeout, or\n"
1288 " the numerical value of the ascii of the digit if one is received. Use -1\n"
1289 " for the timeout value if you desire the call to block indefinitely.\n";
1291 static char usage_sendtext[] =
1292 " Usage: SEND TEXT \"<text to send>\"\n"
1293 " Sends the given text on a channel. Most channels do not support the\n"
1294 " transmission of text. Returns 0 if text is sent, or if the channel does not\n"
1295 " support text transmission. Returns -1 only on error/hangup. Text\n"
1296 " consisting of greater than one word should be placed in quotes since the\n"
1297 " command only accepts a single argument.\n";
1299 static char usage_recvchar[] =
1300 " Usage: RECEIVE CHAR <timeout>\n"
1301 " Receives a character of text on a channel. Specify timeout to be the\n"
1302 " maximum time to wait for input in milliseconds, or 0 for infinite. Most channels\n"
1303 " do not support the reception of text. Returns the decimal value of the character\n"
1304 " if one is received, or 0 if the channel does not support text reception. Returns\n"
1305 " -1 only on error/hangup.\n";
1307 static char usage_tddmode[] =
1308 " Usage: TDD MODE <on|off>\n"
1309 " Enable/Disable TDD transmission/reception on a channel. Returns 1 if\n"
1310 " successful, or 0 if channel is not TDD-capable.\n";
1312 static char usage_sendimage[] =
1313 " Usage: SEND IMAGE <image>\n"
1314 " Sends the given image on a channel. Most channels do not support the\n"
1315 " transmission of images. Returns 0 if image is sent, or if the channel does not\n"
1316 " support image transmission. Returns -1 only on error/hangup. Image names\n"
1317 " should not include extensions.\n";
1319 static char usage_streamfile[] =
1320 " Usage: STREAM FILE <filename> <escape digits> [sample offset]\n"
1321 " Send the given file, allowing playback to be interrupted by the given\n"
1322 " digits, if any. Use double quotes for the digits if you wish none to be\n"
1323 " permitted. If sample offset is provided then the audio will seek to sample\n"
1324 " offset before play starts. Returns 0 if playback completes without a digit\n"
1325 " being pressed, or the ASCII numerical value of the digit if one was pressed,\n"
1326 " or -1 on error or if the channel was disconnected. Remember, the file\n"
1327 " extension must not be included in the filename.\n";
1329 static char usage_getoption[] =
1330 " Usage: GET OPTION <filename> <escape_digits> [timeout]\n"
1331 " Behaves similar to STREAM FILE but used with a timeout option.\n";
1333 static char usage_saynumber[] =
1334 " Usage: SAY NUMBER <number> <escape digits>\n"
1335 " Say a given number, returning early if any of the given DTMF digits\n"
1336 " are received on the channel. Returns 0 if playback completes without a digit\n"
1337 " being pressed, or the ASCII numerical value of the digit if one was pressed or\n"
1338 " -1 on error/hangup.\n";
1340 static char usage_saydigits[] =
1341 " Usage: SAY DIGITS <number> <escape digits>\n"
1342 " Say a given digit string, returning early if any of the given DTMF digits\n"
1343 " are received on the channel. Returns 0 if playback completes without a digit\n"
1344 " being pressed, or the ASCII numerical value of the digit if one was pressed or\n"
1345 " -1 on error/hangup.\n";
1347 static char usage_sayalpha[] =
1348 " Usage: SAY ALPHA <number> <escape digits>\n"
1349 " Say a given character string, returning early if any of the given DTMF digits\n"
1350 " are received on the channel. Returns 0 if playback completes without a digit\n"
1351 " being pressed, or the ASCII numerical value of the digit if one was pressed or\n"
1352 " -1 on error/hangup.\n";
1354 static char usage_saytime[] =
1355 " Usage: SAY TIME <time> <escape digits>\n"
1356 " Say a given time, returning early if any of the given DTMF digits are\n"
1357 " received on the channel. <time> is number of seconds elapsed since 00:00:00\n"
1358 " on January 1, 1970, Coordinated Universal Time (UTC). Returns 0 if playback\n"
1359 " completes without a digit being pressed, or the ASCII numerical value of the\n"
1360 " digit if one was pressed or -1 on error/hangup.\n";
1362 static char usage_sayphonetic[] =
1363 " Usage: SAY PHONETIC <string> <escape digits>\n"
1364 " Say a given character string with phonetics, returning early if any of the\n"
1365 " given DTMF digits are received on the channel. Returns 0 if playback\n"
1366 " completes without a digit pressed, the ASCII numerical value of the digit\n"
1367 " if one was pressed, or -1 on error/hangup.\n";
1369 static char usage_getdata[] =
1370 " Usage: GET DATA <file to be streamed> [timeout] [max digits]\n"
1371 " Stream the given file, and recieve DTMF data. Returns the digits received\n"
1372 "from the channel at the other end.\n";
1374 static char usage_setcontext[] =
1375 " Usage: SET CONTEXT <desired context>\n"
1376 " Sets the context for continuation upon exiting the application.\n";
1378 static char usage_setextension[] =
1379 " Usage: SET EXTENSION <new extension>\n"
1380 " Changes the extension for continuation upon exiting the application.\n";
1382 static char usage_setpriority[] =
1383 " Usage: SET PRIORITY <num>\n"
1384 " Changes the priority for continuation upon exiting the application.\n";
1386 static char usage_recordfile[] =
1387 " Usage: RECORD FILE <filename> <format> <escape digits> <timeout> \\\n"
1388 " [offset samples] [BEEP] [s=silence]\n"
1389 " Record to a file until a given dtmf digit in the sequence is received\n"
1390 " Returns -1 on hangup or error. The format will specify what kind of file\n"
1391 " will be recorded. The timeout is the maximum record time in milliseconds, or\n"
1392 " -1 for no timeout. \"Offset samples\" is optional, and, if provided, will seek\n"
1393 " to the offset without exceeding the end of the file. \"silence\" is the number\n"
1394 " of seconds of silence allowed before the function returns despite the\n"
1395 " lack of dtmf digits or reaching timeout. Silence value must be\n"
1396 " preceeded by \"s=\" and is also optional.\n";
1398 static char usage_autohangup[] =
1399 " Usage: SET AUTOHANGUP <time>\n"
1400 " Cause the channel to automatically hangup at <time> seconds in the\n"
1401 " future. Of course it can be hungup before then as well. Setting to 0 will\n"
1402 " cause the autohangup feature to be disabled on this channel.\n";
1404 static char usage_noop[] =
1408 static agi_command commands[MAX_COMMANDS] = {
1409 { { "answer", NULL }, handle_answer, "Answer channel", usage_answer },
1410 { { "channel", "status", NULL }, handle_channelstatus, "Returns status of the connected channel", usage_channelstatus },
1411 { { "database", "del", NULL }, handle_dbdel, "Removes database key/value", usage_dbdel },
1412 { { "database", "deltree", NULL }, handle_dbdeltree, "Removes database keytree/value", usage_dbdeltree },
1413 { { "database", "get", NULL }, handle_dbget, "Gets database value", usage_dbget },
1414 { { "database", "put", NULL }, handle_dbput, "Adds/updates database value", usage_dbput },
1415 { { "exec", NULL }, handle_exec, "Executes a given Application", usage_exec },
1416 { { "get", "data", NULL }, handle_getdata, "Prompts for DTMF on a channel", usage_getdata },
1417 { { "get", "full", "variable", NULL }, handle_getvariablefull, "Evaluates a channel expression", usage_getvariablefull },
1418 { { "get", "option", NULL }, handle_getoption, "Stream file, prompt for DTMF, with timeout", usage_getoption },
1419 { { "get", "variable", NULL }, handle_getvariable, "Gets a channel variable", usage_getvariable },
1420 { { "hangup", NULL }, handle_hangup, "Hangup the current channel", usage_hangup },
1421 { { "noop", NULL }, handle_noop, "Does nothing", usage_noop },
1422 { { "receive", "char", NULL }, handle_recvchar, "Receives text from channels supporting it", usage_recvchar },
1423 { { "record", "file", NULL }, handle_recordfile, "Records to a given file", usage_recordfile },
1424 { { "say", "alpha", NULL }, handle_sayalpha, "Says a given character string", usage_sayalpha },
1425 { { "say", "digits", NULL }, handle_saydigits, "Says a given digit string", usage_saydigits },
1426 { { "say", "number", NULL }, handle_saynumber, "Says a given number", usage_saynumber },
1427 { { "say", "phonetic", NULL }, handle_sayphonetic, "Says a given character string with phonetics", usage_sayphonetic },
1428 { { "say", "time", NULL }, handle_saytime, "Says a given time", usage_saytime },
1429 { { "send", "image", NULL }, handle_sendimage, "Sends images to channels supporting it", usage_sendimage },
1430 { { "send", "text", NULL }, handle_sendtext, "Sends text to channels supporting it", usage_sendtext },
1431 { { "set", "autohangup", NULL }, handle_autohangup, "Autohangup channel in some time", usage_autohangup },
1432 { { "set", "callerid", NULL }, handle_setcallerid, "Sets callerid for the current channel", usage_setcallerid },
1433 { { "set", "context", NULL }, handle_setcontext, "Sets channel context", usage_setcontext },
1434 { { "set", "extension", NULL }, handle_setextension, "Changes channel extension", usage_setextension },
1435 { { "set", "music", NULL }, handle_setmusic, "Enable/Disable Music on hold generator", usage_setmusic },
1436 { { "set", "priority", NULL }, handle_setpriority, "Set channel dialplan priority", usage_setpriority },
1437 { { "set", "variable", NULL }, handle_setvariable, "Sets a channel variable", usage_setvariable },
1438 { { "stream", "file", NULL }, handle_streamfile, "Sends audio file on channel", usage_streamfile },
1439 { { "tdd", "mode", NULL }, handle_tddmode, "Toggles TDD mode (for the deaf)", usage_tddmode },
1440 { { "verbose", NULL }, handle_verbose, "Logs a message to the asterisk verbose log", usage_verbose },
1441 { { "wait", "for", "digit", NULL }, handle_waitfordigit, "Waits for a digit to be pressed", usage_waitfordigit },
1444 static void join(char *s, size_t len, char *w[])
1448 /* Join words into a string */
1453 for (x=0; w[x]; x++) {
1455 strncat(s, " ", len - strlen(s) - 1);
1456 strncat(s, w[x], len - strlen(s) - 1);
1460 static int help_workhorse(int fd, char *match[])
1465 struct agi_command *e;
1467 join(matchstr, sizeof(matchstr), match);
1468 for (x=0;x<sizeof(commands)/sizeof(commands[0]);x++) {
1469 if (!commands[x].cmda[0]) break;
1472 join(fullcmd, sizeof(fullcmd), e->cmda);
1473 /* Hide commands that start with '_' */
1474 if (fullcmd[0] == '_')
1477 if (strncasecmp(matchstr, fullcmd, strlen(matchstr))) {
1481 ast_cli(fd, "%20.20s %s\n", fullcmd, e->summary);
1486 int agi_register(agi_command *agi)
1489 for (x=0; x<MAX_COMMANDS - 1; x++) {
1490 if (commands[x].cmda[0] == agi->cmda[0]) {
1491 ast_log(LOG_WARNING, "Command already registered!\n");
1495 for (x=0; x<MAX_COMMANDS - 1; x++) {
1496 if (!commands[x].cmda[0]) {
1501 ast_log(LOG_WARNING, "No more room for new commands!\n");
1505 void agi_unregister(agi_command *agi)
1508 for (x=0; x<MAX_COMMANDS - 1; x++) {
1509 if (commands[x].cmda[0] == agi->cmda[0]) {
1510 memset(&commands[x], 0, sizeof(agi_command));
1515 static agi_command *find_command(char *cmds[], int exact)
1521 for (x=0; x < sizeof(commands) / sizeof(commands[0]); x++) {
1522 if (!commands[x].cmda[0])
1524 /* start optimistic */
1526 for (y=0; match && cmds[y]; y++) {
1527 /* If there are no more words in the command (and we're looking for
1528 an exact match) or there is a difference between the two words,
1529 then this is not a match */
1530 if (!commands[x].cmda[y] && !exact)
1532 /* don't segfault if the next part of a command doesn't exist */
1533 if (!commands[x].cmda[y])
1535 if (strcasecmp(commands[x].cmda[y], cmds[y]))
1538 /* If more words are needed to complete the command then this is not
1539 a candidate (unless we're looking for a really inexact answer */
1540 if ((exact > -1) && commands[x].cmda[y])
1543 return &commands[x];
1549 static int parse_args(char *s, int *max, char *argv[])
1561 /* If it's escaped, put a literal quote */
1566 if (quoted && whitespace) {
1567 /* If we're starting a quote, coming off white space start a new word, too */
1575 if (!quoted && !escaped) {
1576 /* If we're not quoted, mark this as whitespace, and
1577 end the previous argument */
1581 /* Otherwise, just treat it as anything else */
1585 /* If we're escaped, print a literal, otherwise enable escaping */
1595 if (x >= MAX_ARGS -1) {
1596 ast_log(LOG_WARNING, "Too many arguments, truncating\n");
1599 /* Coming off of whitespace, start the next argument */
1608 /* Null terminate */
1615 static int agi_handle_command(struct ast_channel *chan, AGI *agi, char *buf)
1617 char *argv[MAX_ARGS];
1623 parse_args(buf, &argc, argv);
1626 for (x=0; x<argc; x++)
1627 fprintf(stderr, "Got Arg%d: %s\n", x, argv[x]); }
1629 c = find_command(argv, 0);
1631 res = c->handler(chan, agi, argc, argv);
1633 case RESULT_SHOWUSAGE:
1634 fdprintf(agi->fd, "520-Invalid command syntax. Proper usage follows:\n");
1635 fdprintf(agi->fd, c->usage);
1636 fdprintf(agi->fd, "520 End of proper usage.\n");
1638 case AST_PBX_KEEPALIVE:
1639 /* We've been asked to keep alive, so do so */
1640 return AST_PBX_KEEPALIVE;
1642 case RESULT_FAILURE:
1643 /* They've already given the failure. We've been hung up on so handle this
1648 fdprintf(agi->fd, "510 Invalid or unknown command\n");
1653 static int run_agi(struct ast_channel *chan, char *request, AGI *agi, int pid, int dead)
1655 struct ast_channel *c;
1658 int returnstatus = 0;
1659 struct ast_frame *f;
1662 /* how many times we'll retry if ast_waitfor_nandfs will return without either
1663 channel or file descriptor in case select is interrupted by a system call (EINTR) */
1666 if (!(readf = fdopen(agi->ctrl, "r"))) {
1667 ast_log(LOG_WARNING, "Unable to fdopen file descriptor\n");
1674 setup_env(chan, request, agi->fd, (agi->audio > -1));
1677 c = ast_waitfor_nandfds(&chan, dead ? 0 : 1, &agi->ctrl, 1, NULL, &outfd, &ms);
1680 /* Idle the channel until we get a command */
1683 ast_log(LOG_DEBUG, "%s hungup\n", chan->name);
1687 /* If it's voice, write it to the audio pipe */
1688 if ((agi->audio > -1) && (f->frametype == AST_FRAME_VOICE)) {
1689 /* Write, ignoring errors */
1690 write(agi->audio, f->data, f->datalen);
1694 } else if (outfd > -1) {
1696 if (!fgets(buf, sizeof(buf), readf)) {
1697 /* Program terminated */
1700 if (option_verbose > 2)
1701 ast_verbose(VERBOSE_PREFIX_3 "AGI Script %s completed, returning %d\n", request, returnstatus);
1702 /* No need to kill the pid anymore, since they closed us */
1706 /* get rid of trailing newline, if any */
1707 if (*buf && buf[strlen(buf) - 1] == '\n')
1708 buf[strlen(buf) - 1] = 0;
1710 ast_verbose("AGI Rx << %s\n", buf);
1711 returnstatus |= agi_handle_command(chan, agi, buf);
1712 /* If the handle_command returns -1, we need to stop */
1713 if ((returnstatus < 0) || (returnstatus == AST_PBX_KEEPALIVE)) {
1718 ast_log(LOG_WARNING, "No channel, no fd?\n");
1724 /* Notify process */
1728 return returnstatus;
1731 static int handle_showagi(int fd, int argc, char *argv[]) {
1732 struct agi_command *e;
1735 return RESULT_SHOWUSAGE;
1737 e = find_command(argv + 2, 1);
1739 ast_cli(fd, e->usage);
1741 if (find_command(argv + 2, -1)) {
1742 return help_workhorse(fd, argv + 1);
1744 join(fullcmd, sizeof(fullcmd), argv+1);
1745 ast_cli(fd, "No such command '%s'.\n", fullcmd);
1749 return help_workhorse(fd, NULL);
1751 return RESULT_SUCCESS;
1754 static int handle_dumpagihtml(int fd, int argc, char *argv[]) {
1755 struct agi_command *e;
1762 return RESULT_SHOWUSAGE;
1764 if (!(htmlfile = fopen(argv[2], "wt"))) {
1765 ast_cli(fd, "Could not create file '%s'\n", argv[2]);
1766 return RESULT_SHOWUSAGE;
1769 fprintf(htmlfile, "<HTML>\n<HEAD>\n<TITLE>AGI Commands</TITLE>\n</HEAD>\n");
1770 fprintf(htmlfile, "<BODY>\n<CENTER><B><H1>AGI Commands</H1></B></CENTER>\n\n");
1773 fprintf(htmlfile, "<TABLE BORDER=\"0\" CELLSPACING=\"10\">\n");
1775 for (x=0;x<sizeof(commands)/sizeof(commands[0]);x++) {
1777 if (!commands[x].cmda[0]) break;
1780 join(fullcmd, sizeof(fullcmd), e->cmda);
1781 /* Hide commands that start with '_' */
1782 if (fullcmd[0] == '_')
1785 fprintf(htmlfile, "<TR><TD><TABLE BORDER=\"1\" CELLPADDING=\"5\" WIDTH=\"100%%\">\n");
1786 fprintf(htmlfile, "<TR><TH ALIGN=\"CENTER\"><B>%s - %s</B></TD></TR>\n", fullcmd,e->summary);
1790 tempstr = strsep(&stringp, "\n");
1792 fprintf(htmlfile, "<TR><TD ALIGN=\"CENTER\">%s</TD></TR>\n", tempstr);
1794 fprintf(htmlfile, "<TR><TD ALIGN=\"CENTER\">\n");
1795 while ((tempstr = strsep(&stringp, "\n")) != NULL) {
1796 fprintf(htmlfile, "%s<BR>\n",tempstr);
1799 fprintf(htmlfile, "</TD></TR>\n");
1800 fprintf(htmlfile, "</TABLE></TD></TR>\n\n");
1804 fprintf(htmlfile, "</TABLE>\n</BODY>\n</HTML>\n");
1806 ast_cli(fd, "AGI HTML Commands Dumped to: %s\n", argv[2]);
1807 return RESULT_SUCCESS;
1810 static int agi_exec_full(struct ast_channel *chan, void *data, int enhanced, int dead)
1813 struct localuser *u;
1814 char *argv[MAX_ARGS];
1816 char *tmp = (char *)buf;
1824 if (!data || ast_strlen_zero(data)) {
1825 ast_log(LOG_WARNING, "AGI requires an argument (script)\n");
1828 strncpy(buf, data, sizeof(buf) - 1);
1830 memset(&agi, 0, sizeof(agi));
1831 while ((stringp = strsep(&tmp, "|"))) {
1832 argv[argc++] = stringp;
1838 /* Answer if need be */
1839 if (chan->_state != AST_STATE_UP) {
1840 if (ast_answer(chan)) {
1841 LOCAL_USER_REMOVE(u);
1846 res = launch_script(argv[0], argv, fds, enhanced ? &efd : NULL, &pid);
1851 res = run_agi(chan, argv[0], &agi, pid, dead);
1856 LOCAL_USER_REMOVE(u);
1860 static int agi_exec(struct ast_channel *chan, void *data)
1862 if (chan->_softhangup)
1863 ast_log(LOG_WARNING, "If you want to run AGI on hungup channels you should use DeadAGI!\n");
1864 return agi_exec_full(chan, data, 0, 0);
1867 static int eagi_exec(struct ast_channel *chan, void *data)
1872 if (chan->_softhangup)
1873 ast_log(LOG_WARNING, "If you want to run AGI on hungup channels you should use DeadAGI!\n");
1874 readformat = chan->readformat;
1875 if (ast_set_read_format(chan, AST_FORMAT_SLINEAR)) {
1876 ast_log(LOG_WARNING, "Unable to set channel '%s' to linear mode\n", chan->name);
1879 res = agi_exec_full(chan, data, 1, 0);
1881 if (ast_set_read_format(chan, readformat)) {
1882 ast_log(LOG_WARNING, "Unable to restore channel '%s' to format %s\n", chan->name, ast_getformatname(readformat));
1888 static int deadagi_exec(struct ast_channel *chan, void *data)
1890 return agi_exec_full(chan, data, 0, 1);
1893 static char showagi_help[] =
1894 "Usage: show agi [topic]\n"
1895 " When called with a topic as an argument, displays usage\n"
1896 " information on the given command. If called without a\n"
1897 " topic, it provides a list of AGI commands.\n";
1900 static char dumpagihtml_help[] =
1901 "Usage: dump agihtml <filename>\n"
1902 " Dumps the agi command list in html format to given filename\n";
1904 static struct ast_cli_entry showagi =
1905 { { "show", "agi", NULL }, handle_showagi, "Show AGI commands or specific help", showagi_help };
1907 static struct ast_cli_entry dumpagihtml =
1908 { { "dump", "agihtml", NULL }, handle_dumpagihtml, "Dumps a list of agi command in html format", dumpagihtml_help };
1910 int unload_module(void)
1912 STANDARD_HANGUP_LOCALUSERS;
1913 ast_cli_unregister(&showagi);
1914 ast_cli_unregister(&dumpagihtml);
1915 ast_cli_unregister(&cli_debug);
1916 ast_cli_unregister(&cli_no_debug);
1917 ast_unregister_application(eapp);
1918 ast_unregister_application(deadapp);
1919 return ast_unregister_application(app);
1922 int load_module(void)
1924 ast_cli_register(&showagi);
1925 ast_cli_register(&dumpagihtml);
1926 ast_cli_register(&cli_debug);
1927 ast_cli_register(&cli_no_debug);
1928 ast_register_application(deadapp, deadagi_exec, deadsynopsis, descrip);
1929 ast_register_application(eapp, eagi_exec, esynopsis, descrip);
1930 return ast_register_application(app, agi_exec, synopsis, descrip);
1933 char *description(void)
1941 STANDARD_USECOUNT(res);
1947 return ASTERISK_GPL_KEY;