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>
15 #include <asterisk/file.h>
16 #include <asterisk/logger.h>
17 #include <asterisk/channel.h>
18 #include <asterisk/pbx.h>
19 #include <asterisk/module.h>
20 #include <asterisk/astdb.h>
32 #include <asterisk/cli.h>
33 #include <asterisk/logger.h>
34 #include <asterisk/options.h>
35 #include <asterisk/image.h>
36 #include <asterisk/say.h>
37 #include <asterisk/app.h>
38 #include <asterisk/dsp.h>
39 #include <asterisk/musiconhold.h>
40 #include <asterisk/utils.h>
41 #include <asterisk/lock.h>
42 #include <asterisk/agi.h>
43 #include "../asterisk.h"
44 #include "../astconf.h"
47 #define MAX_COMMANDS 128
49 /* Recycle some stuff from the CLI interface */
50 #define fdprintf ast_cli
52 static char *tdesc = "Asterisk Gateway Interface (AGI)";
54 static char *app = "AGI";
56 static char *eapp = "EAGI";
58 static char *deadapp = "DeadAGI";
60 static char *synopsis = "Executes an AGI compliant application";
61 static char *esynopsis = "Executes an EAGI compliant application";
62 static char *deadsynopsis = "Executes AGI on a hungup channel";
64 static char *descrip =
65 " [E|Dead]AGI(command|args): Executes an Asterisk Gateway Interface compliant\n"
66 "program on a channel. AGI allows Asterisk to launch external programs\n"
67 "written in any language to control a telephony channel, play audio,\n"
68 "read DTMF digits, etc. by communicating with the AGI protocol on stdin\n"
70 "Returns -1 on hangup (except for DeadAGI) or if application requested\n"
71 " hangup, or 0 on non-hangup exit. \n"
72 "Using 'EAGI' provides enhanced AGI, with incoming audio available out of band"
73 "on file descriptor 3\n\n"
74 "Use the CLI command 'show agi' to list available agi commands\n";
81 #define TONE_BLOCK_SIZE 200
83 /* Max time to connect to an AGI remote host */
84 #define MAX_AGI_CONNECT 2000
88 static int launch_netscript(char *agiurl, char *argv[], int *fds, int *efd, int *opid)
92 struct pollfd pfds[1];
94 char *c; int port = AGI_PORT;
96 struct sockaddr_in sin;
98 struct ast_hostent ahp;
99 ast_log(LOG_DEBUG, "Blah\n");
100 host = ast_strdupa(agiurl + 6);
103 /* Strip off any script name */
104 if ((c = strchr(host, '/'))) {
109 if ((c = strchr(host, ':'))) {
115 ast_log(LOG_WARNING, "AGI URI's don't support Enhanced AGI yet\n");
118 hp = ast_gethostbyname(host, &ahp);
120 ast_log(LOG_WARNING, "Unable to locate host '%s'\n", host);
123 s = socket(AF_INET, SOCK_STREAM, 0);
125 ast_log(LOG_WARNING, "Unable to create socket: %s\n", strerror(errno));
128 flags = fcntl(s, F_GETFL);
130 ast_log(LOG_WARNING, "Fcntl(F_GETFL) failed: %s\n", strerror(errno));
134 if (fcntl(s, F_SETFL, flags | O_NONBLOCK) < 0) {
135 ast_log(LOG_WARNING, "Fnctl(F_SETFL) failed: %s\n", strerror(errno));
139 memset(&sin, 0, sizeof(sin));
140 sin.sin_family = AF_INET;
141 sin.sin_port = htons(port);
142 memcpy(&sin.sin_addr, hp->h_addr, sizeof(sin.sin_addr));
143 if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) && (errno != EINPROGRESS)) {
144 ast_log(LOG_WARNING, "Connect failed with unexpected error: %s\n", strerror(errno));
149 pfds[0].events = POLLOUT;
150 if (poll(pfds, 1, MAX_AGI_CONNECT) != 1) {
151 ast_log(LOG_WARNING, "Connect to '%s' failed!\n", agiurl);
155 if (write(s, "agi_network: yes\n", strlen("agi_network: yes\n")) < 0) {
156 ast_log(LOG_WARNING, "Connect to '%s' failed: %s\n", agiurl, strerror(errno));
160 ast_log(LOG_DEBUG, "Wow, connected!\n");
167 static int launch_script(char *script, char *argv[], int *fds, int *efd, int *opid)
177 if (!strncasecmp(script, "agi://", 6))
178 return launch_netscript(script, argv, fds, efd, opid);
180 if (script[0] != '/') {
181 snprintf(tmp, sizeof(tmp), "%s/%s", (char *)ast_config_AST_AGI_DIR, script);
185 ast_log(LOG_WARNING, "Unable to create toast pipe: %s\n",strerror(errno));
189 ast_log(LOG_WARNING, "unable to create fromast pipe: %s\n", strerror(errno));
196 ast_log(LOG_WARNING, "unable to create audio pipe: %s\n", strerror(errno));
203 res = fcntl(audio[1], F_GETFL);
205 res = fcntl(audio[1], F_SETFL, res | O_NONBLOCK);
207 ast_log(LOG_WARNING, "unable to set audio pipe parameters: %s\n", strerror(errno));
219 ast_log(LOG_WARNING, "Failed to fork(): %s\n", strerror(errno));
223 /* Redirect stdin and out, provide enhanced audio channel if desired */
224 dup2(fromast[0], STDIN_FILENO);
225 dup2(toast[1], STDOUT_FILENO);
227 dup2(audio[0], STDERR_FILENO + 1);
229 close(STDERR_FILENO + 1);
231 /* Close everything but stdin/out/error */
232 for (x=STDERR_FILENO + 2;x<1024;x++)
236 /* Can't use ast_log since FD's are closed */
237 fprintf(stderr, "Failed to execute '%s': %s\n", script, strerror(errno));
240 if (option_verbose > 2)
241 ast_verbose(VERBOSE_PREFIX_3 "Launched AGI Script %s\n", script);
247 /* close what we're not using in the parent */
261 static void setup_env(struct ast_channel *chan, char *request, int fd, int enhanced)
263 /* Print initial environment, with agi_request always being the first
265 fdprintf(fd, "agi_request: %s\n", request);
266 fdprintf(fd, "agi_channel: %s\n", chan->name);
267 fdprintf(fd, "agi_language: %s\n", chan->language);
268 fdprintf(fd, "agi_type: %s\n", chan->type);
269 fdprintf(fd, "agi_uniqueid: %s\n", chan->uniqueid);
272 fdprintf(fd, "agi_callerid: %s\n", chan->callerid ? chan->callerid : "unknown");
273 fdprintf(fd, "agi_dnid: %s\n", chan->dnid ? chan->dnid : "unknown");
274 fdprintf(fd, "agi_rdnis: %s\n", chan->rdnis ? chan->rdnis : "unknown");
276 /* Context information */
277 fdprintf(fd, "agi_context: %s\n", chan->context);
278 fdprintf(fd, "agi_extension: %s\n", chan->exten);
279 fdprintf(fd, "agi_priority: %d\n", chan->priority);
280 fdprintf(fd, "agi_enhanced: %s\n", enhanced ? "1.0" : "0.0");
282 /* User information */
283 fdprintf(fd, "agi_accountcode: %s\n", chan->accountcode ? chan->accountcode : "");
285 /* End with empty return */
289 static int handle_answer(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
293 if (chan->_state != AST_STATE_UP) {
294 /* Answer the chan */
295 res = ast_answer(chan);
297 fdprintf(agi->fd, "200 result=%d\n", res);
299 return RESULT_SUCCESS;
301 return RESULT_FAILURE;
304 static int handle_waitfordigit(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
309 return RESULT_SHOWUSAGE;
310 if (sscanf(argv[3], "%i", &to) != 1)
311 return RESULT_SHOWUSAGE;
312 res = ast_waitfordigit_full(chan, to, agi->audio, agi->ctrl);
313 fdprintf(agi->fd, "200 result=%d\n", res);
315 return RESULT_SUCCESS;
317 return RESULT_FAILURE;
320 static int handle_sendtext(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
324 return RESULT_SHOWUSAGE;
325 /* At the moment, the parser (perhaps broken) returns with
326 the last argument PLUS the newline at the end of the input
327 buffer. This probably needs to be fixed, but I wont do that
328 because other stuff may break as a result. The right way
329 would probably be to strip off the trailing newline before
330 parsing, then here, add a newline at the end of the string
331 before sending it to ast_sendtext --DUDE */
332 res = ast_sendtext(chan, argv[2]);
333 fdprintf(agi->fd, "200 result=%d\n", res);
335 return RESULT_SUCCESS;
337 return RESULT_FAILURE;
340 static int handle_recvchar(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
344 return RESULT_SHOWUSAGE;
345 res = ast_recvchar(chan,atoi(argv[2]));
347 fdprintf(agi->fd, "200 result=%d (timeout)\n", res);
348 return RESULT_SUCCESS;
351 fdprintf(agi->fd, "200 result=%d\n", res);
352 return RESULT_SUCCESS;
355 fdprintf(agi->fd, "200 result=%d (hangup)\n", res);
356 return RESULT_FAILURE;
360 static int handle_tddmode(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
364 return RESULT_SHOWUSAGE;
365 if (!strncasecmp(argv[2],"on",2)) x = 1; else x = 0;
366 if (!strncasecmp(argv[2],"mate",4)) x = 2;
367 if (!strncasecmp(argv[2],"tdd",3)) x = 1;
368 res = ast_channel_setoption(chan,AST_OPTION_TDD,&x,sizeof(char),0);
369 fdprintf(agi->fd, "200 result=%d\n", res);
371 return RESULT_SUCCESS;
373 return RESULT_FAILURE;
376 static int handle_sendimage(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
380 return RESULT_SHOWUSAGE;
381 res = ast_send_image(chan, argv[2]);
382 if (!ast_check_hangup(chan))
384 fdprintf(agi->fd, "200 result=%d\n", res);
386 return RESULT_SUCCESS;
388 return RESULT_FAILURE;
391 static int handle_streamfile(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
394 struct ast_filestream *fs;
395 long sample_offset = 0;
399 return RESULT_SHOWUSAGE;
401 return RESULT_SHOWUSAGE;
402 if ((argc > 4) && (sscanf(argv[4], "%ld", &sample_offset) != 1))
403 return RESULT_SHOWUSAGE;
405 fs = ast_openstream(chan, argv[2], chan->language);
407 fdprintf(agi->fd, "200 result=%d endpos=%ld\n", 0, sample_offset);
408 ast_log(LOG_WARNING, "Unable to open %s\n", argv[2]);
409 return RESULT_FAILURE;
411 ast_seekstream(fs, 0, SEEK_END);
412 max_length = ast_tellstream(fs);
413 ast_seekstream(fs, sample_offset, SEEK_SET);
414 res = ast_applystream(chan, fs);
415 res = ast_playstream(fs);
417 fdprintf(agi->fd, "200 result=%d endpos=%ld\n", res, sample_offset);
419 return RESULT_SHOWUSAGE;
421 return RESULT_FAILURE;
423 res = ast_waitstream_full(chan, argv[3], agi->audio, agi->ctrl);
424 /* this is to check for if ast_waitstream closed the stream, we probably are at
425 * the end of the stream, return that amount, else check for the amount */
426 sample_offset = (chan->stream)?ast_tellstream(fs):max_length;
427 ast_stopstream(chan);
429 /* Stop this command, don't print a result line, as there is a new command */
430 return RESULT_SUCCESS;
432 fdprintf(agi->fd, "200 result=%d endpos=%ld\n", res, sample_offset);
434 return RESULT_SUCCESS;
436 return RESULT_FAILURE;
439 /*--- handle_saynumber: Say number in various language syntaxes ---*/
440 /* Need to add option for gender here as well. Coders wanted */
441 /* While waiting, we're sending a (char *) NULL. */
442 static int handle_saynumber(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
447 return RESULT_SHOWUSAGE;
448 if (sscanf(argv[2], "%i", &num) != 1)
449 return RESULT_SHOWUSAGE;
450 res = ast_say_number_full(chan, num, argv[3], chan->language, (char *) NULL, agi->audio, agi->ctrl);
452 return RESULT_SUCCESS;
453 fdprintf(agi->fd, "200 result=%d\n", res);
455 return RESULT_SUCCESS;
457 return RESULT_FAILURE;
460 static int handle_saydigits(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
466 return RESULT_SHOWUSAGE;
467 if (sscanf(argv[2], "%i", &num) != 1)
468 return RESULT_SHOWUSAGE;
470 res = ast_say_digit_str_full(chan, argv[2], argv[3], chan->language, agi->audio, agi->ctrl);
471 if (res == 1) /* New command */
472 return RESULT_SUCCESS;
473 fdprintf(agi->fd, "200 result=%d\n", res);
475 return RESULT_SUCCESS;
477 return RESULT_FAILURE;
480 static int handle_saytime(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
485 return RESULT_SHOWUSAGE;
486 if (sscanf(argv[2], "%i", &num) != 1)
487 return RESULT_SHOWUSAGE;
488 res = ast_say_time(chan, num, argv[3], chan->language);
490 return RESULT_SUCCESS;
491 fdprintf(agi->fd, "200 result=%d\n", res);
493 return RESULT_SUCCESS;
495 return RESULT_FAILURE;
498 static int handle_sayphonetic(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
503 return RESULT_SHOWUSAGE;
505 res = ast_say_phonetic_str_full(chan, argv[2], argv[3], chan->language, agi->audio, agi->ctrl);
506 if (res == 1) /* New command */
507 return RESULT_SUCCESS;
508 fdprintf(agi->fd, "200 result=%d\n", res);
510 return RESULT_SUCCESS;
512 return RESULT_FAILURE;
515 static int handle_getdata(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
523 return RESULT_SHOWUSAGE;
524 if (argc >= 4) timeout = atoi(argv[3]); else timeout = 0;
525 if (argc >= 5) max = atoi(argv[4]); else max = 1024;
526 res = ast_app_getdata_full(chan, argv[2], data, max, timeout, agi->audio, agi->ctrl);
527 if (res == 2) /* New command */
528 return RESULT_SUCCESS;
530 fdprintf(agi->fd, "200 result=%s (timeout)\n", data);
532 fdprintf(agi->fd, "200 result=-1\n");
534 fdprintf(agi->fd, "200 result=%s\n", data);
536 return RESULT_SUCCESS;
538 return RESULT_FAILURE;
541 static int handle_setcontext(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
545 return RESULT_SHOWUSAGE;
546 strncpy(chan->context, argv[2], sizeof(chan->context)-1);
547 fdprintf(agi->fd, "200 result=0\n");
548 return RESULT_SUCCESS;
551 static int handle_setextension(struct ast_channel *chan, AGI *agi, int argc, char **argv)
554 return RESULT_SHOWUSAGE;
555 strncpy(chan->exten, argv[2], sizeof(chan->exten)-1);
556 fdprintf(agi->fd, "200 result=0\n");
557 return RESULT_SUCCESS;
560 static int handle_setpriority(struct ast_channel *chan, AGI *agi, int argc, char **argv)
564 return RESULT_SHOWUSAGE;
565 if (sscanf(argv[2], "%i", &pri) != 1)
566 return RESULT_SHOWUSAGE;
567 chan->priority = pri - 1;
568 fdprintf(agi->fd, "200 result=0\n");
569 return RESULT_SUCCESS;
572 static int handle_recordfile(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
574 struct ast_filestream *fs;
576 struct timeval tv, start;
577 long sample_offset = 0;
581 struct ast_dsp *sildet=NULL; /* silence detector dsp */
582 int totalsilence = 0;
584 int silence = 0; /* amount of silence to allow */
585 int gotsilence = 0; /* did we timeout for silence? */
586 char *silencestr=NULL;
590 /* XXX EAGI FIXME XXX */
593 return RESULT_SHOWUSAGE;
594 if (sscanf(argv[5], "%i", &ms) != 1)
595 return RESULT_SHOWUSAGE;
598 silencestr = strchr(argv[6],'s');
599 if ((argc > 7) && (!silencestr))
600 silencestr = strchr(argv[7],'s');
601 if ((argc > 8) && (!silencestr))
602 silencestr = strchr(argv[8],'s');
605 if (strlen(silencestr) > 2) {
606 if ((silencestr[0] == 's') && (silencestr[1] == '=')) {
610 silence = atoi(silencestr);
618 rfmt = chan->readformat;
619 res = ast_set_read_format(chan, AST_FORMAT_SLINEAR);
621 ast_log(LOG_WARNING, "Unable to set to linear mode, giving up\n");
624 sildet = ast_dsp_new();
626 ast_log(LOG_WARNING, "Unable to create silence detector :(\n");
629 ast_dsp_set_threshold(sildet, 256);
632 /* backward compatibility, if no offset given, arg[6] would have been
633 * caught below and taken to be a beep, else if it is a digit then it is a
635 if ((argc >6) && (sscanf(argv[6], "%ld", &sample_offset) != 1) && (!strchr(argv[6], '=')))
636 res = ast_streamfile(chan, "beep", chan->language);
638 if ((argc > 7) && (!strchr(argv[7], '=')))
639 res = ast_streamfile(chan, "beep", chan->language);
642 res = ast_waitstream(chan, argv[4]);
644 fs = ast_writefile(argv[2], argv[3], NULL, O_CREAT | O_WRONLY | (sample_offset ? O_APPEND : 0), 0, 0644);
647 fdprintf(agi->fd, "200 result=%d (writefile)\n", res);
649 ast_dsp_free(sildet);
650 return RESULT_FAILURE;
654 ast_applystream(chan,fs);
655 /* really should have checks */
656 ast_seekstream(fs, sample_offset, SEEK_SET);
659 gettimeofday(&start, NULL);
660 gettimeofday(&tv, NULL);
661 while ((ms < 0) || (((tv.tv_sec - start.tv_sec) * 1000 + (tv.tv_usec - start.tv_usec)/1000) < ms)) {
662 res = ast_waitfor(chan, -1);
665 fdprintf(agi->fd, "200 result=%d (waitfor) endpos=%ld\n", res,sample_offset);
667 ast_dsp_free(sildet);
668 return RESULT_FAILURE;
672 fdprintf(agi->fd, "200 result=%d (hangup) endpos=%ld\n", 0, sample_offset);
675 ast_dsp_free(sildet);
676 return RESULT_FAILURE;
678 switch(f->frametype) {
680 if (strchr(argv[4], f->subclass)) {
681 /* This is an interrupting chracter */
682 sample_offset = ast_tellstream(fs);
683 fdprintf(agi->fd, "200 result=%d (dtmf) endpos=%ld\n", f->subclass, sample_offset);
687 ast_dsp_free(sildet);
688 return RESULT_SUCCESS;
691 case AST_FRAME_VOICE:
692 ast_writestream(fs, f);
693 /* this is a safe place to check progress since we know that fs
694 * is valid after a write, and it will then have our current
696 sample_offset = ast_tellstream(fs);
699 ast_dsp_silence(sildet, f, &dspsilence);
701 totalsilence = dspsilence;
705 if (totalsilence > silence) {
706 /* Ended happily with silence */
715 gettimeofday(&tv, NULL);
721 ast_stream_rewind(fs, silence-1000);
723 sample_offset = ast_tellstream(fs);
725 fdprintf(agi->fd, "200 result=%d (timeout) endpos=%ld\n", res, sample_offset);
728 fdprintf(agi->fd, "200 result=%d (randomerror) endpos=%ld\n", res, sample_offset);
731 res = ast_set_read_format(chan, rfmt);
733 ast_log(LOG_WARNING, "Unable to restore read format on '%s'\n", chan->name);
734 ast_dsp_free(sildet);
736 return RESULT_SUCCESS;
739 static int handle_autohangup(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
744 return RESULT_SHOWUSAGE;
745 if (sscanf(argv[2], "%d", &timeout) != 1)
746 return RESULT_SHOWUSAGE;
750 chan->whentohangup = time(NULL) + timeout;
752 chan->whentohangup = 0;
753 fdprintf(agi->fd, "200 result=0\n");
754 return RESULT_SUCCESS;
757 static int handle_hangup(struct ast_channel *chan, AGI *agi, int argc, char **argv)
759 struct ast_channel *c;
761 /* no argument: hangup the current channel */
762 ast_softhangup(chan,AST_SOFTHANGUP_EXPLICIT);
763 fdprintf(agi->fd, "200 result=1\n");
764 return RESULT_SUCCESS;
765 } else if (argc==2) {
766 /* one argument: look for info on the specified channel */
767 c = ast_channel_walk_locked(NULL);
769 if (strcasecmp(argv[1],c->name)==0) {
770 /* we have a matching channel */
771 ast_softhangup(c,AST_SOFTHANGUP_EXPLICIT);
772 fdprintf(agi->fd, "200 result=1\n");
773 ast_mutex_unlock(&c->lock);
774 return RESULT_SUCCESS;
776 ast_mutex_unlock(&c->lock);
777 c = ast_channel_walk_locked(c);
779 /* if we get this far no channel name matched the argument given */
780 fdprintf(agi->fd, "200 result=-1\n");
781 return RESULT_SUCCESS;
783 return RESULT_SHOWUSAGE;
787 static int handle_exec(struct ast_channel *chan, AGI *agi, int argc, char **argv)
793 return RESULT_SHOWUSAGE;
795 if (option_verbose > 2)
796 ast_verbose(VERBOSE_PREFIX_3 "AGI Script Executing Application: (%s) Options: (%s)\n", argv[1], argv[2]);
798 app = pbx_findapp(argv[1]);
801 res = pbx_exec(chan, app, argv[2], 1);
803 ast_log(LOG_WARNING, "Could not find application (%s)\n", argv[1]);
806 fdprintf(agi->fd, "200 result=%d\n", res);
811 static int handle_setcallerid(struct ast_channel *chan, AGI *agi, int argc, char **argv)
814 ast_set_callerid(chan, argv[2], 0);
816 fdprintf(agi->fd, "200 result=1\n");
817 return RESULT_SUCCESS;
820 static int handle_channelstatus(struct ast_channel *chan, AGI *agi, int argc, char **argv)
822 struct ast_channel *c;
824 /* no argument: supply info on the current channel */
825 fdprintf(agi->fd, "200 result=%d\n", chan->_state);
826 return RESULT_SUCCESS;
827 } else if (argc==3) {
828 /* one argument: look for info on the specified channel */
829 c = ast_channel_walk_locked(NULL);
831 if (strcasecmp(argv[2],c->name)==0) {
832 fdprintf(agi->fd, "200 result=%d\n", c->_state);
833 ast_mutex_unlock(&c->lock);
834 return RESULT_SUCCESS;
836 ast_mutex_unlock(&c->lock);
837 c = ast_channel_walk_locked(c);
839 /* if we get this far no channel name matched the argument given */
840 fdprintf(agi->fd, "200 result=-1\n");
841 return RESULT_SUCCESS;
843 return RESULT_SHOWUSAGE;
847 static int handle_setvariable(struct ast_channel *chan, AGI *agi, int argc, char **argv)
850 pbx_builtin_setvar_helper(chan, argv[2], argv[3]);
852 fdprintf(agi->fd, "200 result=1\n");
853 return RESULT_SUCCESS;
856 static int handle_getvariable(struct ast_channel *chan, AGI *agi, int argc, char **argv)
860 if ((tempstr = pbx_builtin_getvar_helper(chan, argv[2])))
861 fdprintf(agi->fd, "200 result=1 (%s)\n", tempstr);
863 fdprintf(agi->fd, "200 result=0\n");
865 return RESULT_SUCCESS;
868 static int handle_verbose(struct ast_channel *chan, AGI *agi, int argc, char **argv)
874 return RESULT_SHOWUSAGE;
877 sscanf(argv[2], "%d", &level);
881 prefix = VERBOSE_PREFIX_4;
884 prefix = VERBOSE_PREFIX_3;
887 prefix = VERBOSE_PREFIX_2;
891 prefix = VERBOSE_PREFIX_1;
895 if (level <= option_verbose)
896 ast_verbose("%s %s: %s\n", prefix, chan->data, argv[1]);
898 fdprintf(agi->fd, "200 result=1\n");
900 return RESULT_SUCCESS;
903 static int handle_dbget(struct ast_channel *chan, AGI *agi, int argc, char **argv)
908 return RESULT_SHOWUSAGE;
909 res = ast_db_get(argv[2], argv[3], tmp, sizeof(tmp));
911 fdprintf(agi->fd, "200 result=0\n");
913 fdprintf(agi->fd, "200 result=1 (%s)\n", tmp);
915 return RESULT_SUCCESS;
918 static int handle_dbput(struct ast_channel *chan, AGI *agi, int argc, char **argv)
922 return RESULT_SHOWUSAGE;
923 res = ast_db_put(argv[2], argv[3], argv[4]);
925 fdprintf(agi->fd, "200 result=0\n");
927 fdprintf(agi->fd, "200 result=1\n");
929 return RESULT_SUCCESS;
932 static int handle_dbdel(struct ast_channel *chan, AGI *agi, int argc, char **argv)
936 return RESULT_SHOWUSAGE;
937 res = ast_db_del(argv[2], argv[3]);
939 fdprintf(agi->fd, "200 result=0\n");
941 fdprintf(agi->fd, "200 result=1\n");
943 return RESULT_SUCCESS;
946 static int handle_dbdeltree(struct ast_channel *chan, AGI *agi, int argc, char **argv)
949 if ((argc < 3) || (argc > 4))
950 return RESULT_SHOWUSAGE;
952 res = ast_db_deltree(argv[2], argv[3]);
954 res = ast_db_deltree(argv[2], NULL);
957 fdprintf(agi->fd, "200 result=0\n");
959 fdprintf(agi->fd, "200 result=1\n");
960 return RESULT_SUCCESS;
963 static int handle_noop(struct ast_channel *chan, AGI *agi, int arg, char *argv[])
965 fdprintf(agi->fd, "200 result=0\n");
966 return RESULT_SUCCESS;
969 static int handle_setmusic(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
971 if (!strncasecmp(argv[2],"on",2)) {
973 ast_moh_start(chan, argv[3]);
975 ast_moh_start(chan, NULL);
977 if (!strncasecmp(argv[2],"off",3)) {
980 fdprintf(agi->fd, "200 result=0\n");
981 return RESULT_SUCCESS;
984 static char usage_setmusic[] =
985 " Usage: SET MUSIC ON <on|off> <class>\n"
986 " Enables/Disables the music on hold generator. If <class> is\n"
987 " not specified then the default music on hold class will be used.\n"
988 " Always returns 0\n";
990 static char usage_dbput[] =
991 " Usage: DATABASE PUT <family> <key> <value>\n"
992 " Adds or updates an entry in the Asterisk database for a\n"
993 " given family, key, and value.\n"
994 " Returns 1 if succesful, 0 otherwise\n";
996 static char usage_dbget[] =
997 " Usage: DATABASE GET <family> <key>\n"
998 " Retrieves an entry in the Asterisk database for a\n"
999 " given family and key.\n"
1000 " Returns 0 if <key> is not set. Returns 1 if <key>\n"
1001 " is set and returns the variable in parenthesis\n"
1002 " example return code: 200 result=1 (testvariable)\n";
1004 static char usage_dbdel[] =
1005 " Usage: DATABASE DEL <family> <key>\n"
1006 " Deletes an entry in the Asterisk database for a\n"
1007 " given family and key.\n"
1008 " Returns 1 if succesful, 0 otherwise\n";
1010 static char usage_dbdeltree[] =
1011 " Usage: DATABASE DELTREE <family> [keytree]\n"
1012 " Deletes a family or specific keytree withing a family\n"
1013 " in the Asterisk database.\n"
1014 " Returns 1 if succesful, 0 otherwise\n";
1016 static char usage_verbose[] =
1017 " Usage: VERBOSE <message> <level>\n"
1018 " Sends <message> to the console via verbose message system.\n"
1019 " <level> is the the verbose level (1-4)\n"
1020 " Always returns 1\n";
1022 static char usage_getvariable[] =
1023 " Usage: GET VARIABLE <variablename>\n"
1024 " Returns 0 if <variablename> is not set. Returns 1 if <variablename>\n"
1025 " is set and returns the variable in parenthesis\n"
1026 " example return code: 200 result=1 (testvariable)\n";
1028 static char usage_setvariable[] =
1029 " Usage: SET VARIABLE <variablename> <value>\n";
1031 static char usage_channelstatus[] =
1032 " Usage: CHANNEL STATUS [<channelname>]\n"
1033 " Returns the status of the specified channel.\n"
1034 " If no channel name is given the returns the status of the\n"
1035 " current channel.\n"
1037 " 0 Channel is down and available\n"
1038 " 1 Channel is down, but reserved\n"
1039 " 2 Channel is off hook\n"
1040 " 3 Digits (or equivalent) have been dialed\n"
1041 " 4 Line is ringing\n"
1042 " 5 Remote end is ringing\n"
1044 " 7 Line is busy\n";
1046 static char usage_setcallerid[] =
1047 " Usage: SET CALLERID <number>\n"
1048 " Changes the callerid of the current channel.\n";
1050 static char usage_exec[] =
1051 " Usage: EXEC <application> <options>\n"
1052 " Executes <application> with given <options>.\n"
1053 " Returns whatever the application returns, or -2 on failure to find application\n";
1055 static char usage_hangup[] =
1056 " Usage: HANGUP [<channelname>]\n"
1057 " Hangs up the specified channel.\n"
1058 " If no channel name is given, hangs up the current channel\n";
1060 static char usage_answer[] =
1062 " Answers channel if not already in answer state. Returns -1 on\n"
1063 " channel failure, or 0 if successful.\n";
1065 static char usage_waitfordigit[] =
1066 " Usage: WAIT FOR DIGIT <timeout>\n"
1067 " Waits up to 'timeout' milliseconds for channel to receive a DTMF digit.\n"
1068 " Returns -1 on channel failure, 0 if no digit is received in the timeout, or\n"
1069 " the numerical value of the ascii of the digit if one is received. Use -1\n"
1070 " for the timeout value if you desire the call to block indefinitely.\n";
1072 static char usage_sendtext[] =
1073 " Usage: SEND TEXT \"<text to send>\"\n"
1074 " Sends the given text on a channel. Most channels do not support the\n"
1075 " transmission of text. Returns 0 if text is sent, or if the channel does not\n"
1076 " support text transmission. Returns -1 only on error/hangup. Text\n"
1077 " consisting of greater than one word should be placed in quotes since the\n"
1078 " command only accepts a single argument.\n";
1080 static char usage_recvchar[] =
1081 " Usage: RECEIVE CHAR <timeout>\n"
1082 " Receives a character of text on a channel. Specify timeout to be the\n"
1083 " maximum time to wait for input in milliseconds, or 0 for infinite. Most channels\n"
1084 " do not support the reception of text. Returns the decimal value of the character\n"
1085 " if one is received, or 0 if the channel does not support text reception. Returns\n"
1086 " -1 only on error/hangup.\n";
1088 static char usage_tddmode[] =
1089 " Usage: TDD MODE <on|off>\n"
1090 " Enable/Disable TDD transmission/reception on a channel. Returns 1 if\n"
1091 " successful, or 0 if channel is not TDD-capable.\n";
1093 static char usage_sendimage[] =
1094 " Usage: SEND IMAGE <image>\n"
1095 " Sends the given image on a channel. Most channels do not support the\n"
1096 " transmission of images. Returns 0 if image is sent, or if the channel does not\n"
1097 " support image transmission. Returns -1 only on error/hangup. Image names\n"
1098 " should not include extensions.\n";
1100 static char usage_streamfile[] =
1101 " Usage: STREAM FILE <filename> <escape digits> [sample offset]\n"
1102 " Send the given file, allowing playback to be interrupted by the given\n"
1103 " digits, if any. Use double quotes for the digits if you wish none to be\n"
1104 " permitted. If sample offset is provided then the audio will seek to sample\n"
1105 " offset before play starts. Returns 0 if playback completes without a digit\n"
1106 " being pressed, or the ASCII numerical value of the digit if one was pressed,\n"
1107 " or -1 on error or if the channel was disconnected. Remember, the file\n"
1108 " extension must not be included in the filename.\n";
1110 static char usage_saynumber[] =
1111 " Usage: SAY NUMBER <number> <escape digits>\n"
1112 " Say a given number, returning early if any of the given DTMF digits\n"
1113 " are received on the channel. Returns 0 if playback completes without a digit\n"
1114 " being pressed, or the ASCII numerical value of the digit if one was pressed or\n"
1115 " -1 on error/hangup.\n";
1117 static char usage_saydigits[] =
1118 " Usage: SAY DIGITS <number> <escape digits>\n"
1119 " Say a given digit string, returning early if any of the given DTMF digits\n"
1120 " are received on the channel. Returns 0 if playback completes without a digit\n"
1121 " being pressed, or the ASCII numerical value of the digit if one was pressed or\n"
1122 " -1 on error/hangup.\n";
1124 static char usage_saytime[] =
1125 " Usage: SAY TIME <time> <escape digits>\n"
1126 " Say a given time, returning early if any of the given DTMF digits are\n"
1127 " received on the channel. <time> is number of seconds elapsed since 00:00:00\n"
1128 " on January 1, 1970, Coordinated Universal Time (UTC). Returns 0 if playback\n"
1129 " completes without a digit being pressed, or the ASCII numerical value of the\n"
1130 " digit if one was pressed or -1 on error/hangup.\n";
1132 static char usage_sayphonetic[] =
1133 " Usage: SAY PHONETIC <string> <escape digits>\n"
1134 " Say a given character string with phonetics, returning early if any of the given DTMF digits\n"
1135 " are received on the channel. Returns 0 if playback completes without a digit\n"
1136 " being pressed, or the ASCII numerical value of the digit if one was pressed or\n"
1137 " -1 on error/hangup.\n";
1139 static char usage_getdata[] =
1140 " Usage: GET DATA <file to be streamed> [timeout] [max digits]\n"
1141 " Stream the given file, and recieve DTMF data. Returns the digits recieved\n"
1142 "from the channel at the other end.\n";
1144 static char usage_setcontext[] =
1145 " Usage: SET CONTEXT <desired context>\n"
1146 " Sets the context for continuation upon exiting the application.\n";
1148 static char usage_setextension[] =
1149 " Usage: SET EXTENSION <new extension>\n"
1150 " Changes the extension for continuation upon exiting the application.\n";
1152 static char usage_setpriority[] =
1153 " Usage: SET PRIORITY <num>\n"
1154 " Changes the priority for continuation upon exiting the application.\n";
1156 static char usage_recordfile[] =
1157 " Usage: RECORD FILE <filename> <format> <escape digits> <timeout> [offset samples] [BEEP] [s=silence]\n"
1158 " Record to a file until a given dtmf digit in the sequence is received\n"
1159 " Returns -1 on hangup or error. The format will specify what kind of file\n"
1160 " will be recorded. The timeout is the maximum record time in milliseconds, or\n"
1161 " -1 for no timeout. Offset samples is optional, and if provided will seek to\n"
1162 " the offset without exceeding the end of the file. \"silence\" is the number\n"
1163 " of seconds of silence allowed before the function returns despite the\n"
1164 " lack of dtmf digits or reaching timeout. Silence value must be\n"
1165 " preceeded by \"s=\" and is optional.\n";
1168 static char usage_autohangup[] =
1169 " Usage: SET AUTOHANGUP <time>\n"
1170 " Cause the channel to automatically hangup at <time> seconds in the\n"
1171 "future. Of course it can be hungup before then as well. Setting to\n"
1172 "0 will cause the autohangup feature to be disabled on this channel.\n";
1174 static char usage_noop[] =
1178 static agi_command commands[MAX_COMMANDS] = {
1179 { { "answer", NULL }, handle_answer, "Asserts answer", usage_answer },
1180 { { "wait", "for", "digit", NULL }, handle_waitfordigit, "Waits for a digit to be pressed", usage_waitfordigit },
1181 { { "send", "text", NULL }, handle_sendtext, "Sends text to channels supporting it", usage_sendtext },
1182 { { "receive", "char", NULL }, handle_recvchar, "Receives text from channels supporting it", usage_recvchar },
1183 { { "tdd", "mode", NULL }, handle_tddmode, "Sends text to channels supporting it", usage_tddmode },
1184 { { "stream", "file", NULL }, handle_streamfile, "Sends audio file on channel", usage_streamfile },
1185 { { "send", "image", NULL }, handle_sendimage, "Sends images to channels supporting it", usage_sendimage },
1186 { { "say", "digits", NULL }, handle_saydigits, "Says a given digit string", usage_saydigits },
1187 { { "say", "number", NULL }, handle_saynumber, "Says a given number", usage_saynumber },
1188 { { "say", "phonetic", NULL }, handle_sayphonetic, "Says a given character string with phonetics", usage_sayphonetic },
1189 { { "say", "time", NULL }, handle_saytime, "Says a given time", usage_saytime },
1190 { { "get", "data", NULL }, handle_getdata, "Gets data on a channel", usage_getdata },
1191 { { "set", "context", NULL }, handle_setcontext, "Sets channel context", usage_setcontext },
1192 { { "set", "extension", NULL }, handle_setextension, "Changes channel extension", usage_setextension },
1193 { { "set", "priority", NULL }, handle_setpriority, "Prioritizes the channel", usage_setpriority },
1194 { { "record", "file", NULL }, handle_recordfile, "Records to a given file", usage_recordfile },
1195 { { "set", "autohangup", NULL }, handle_autohangup, "Autohangup channel in some time", usage_autohangup },
1196 { { "hangup", NULL }, handle_hangup, "Hangup the current channel", usage_hangup },
1197 { { "exec", NULL }, handle_exec, "Executes a given Application", usage_exec },
1198 { { "set", "callerid", NULL }, handle_setcallerid, "Sets callerid for the current channel", usage_setcallerid },
1199 { { "channel", "status", NULL }, handle_channelstatus, "Returns status of the connected channel", usage_channelstatus },
1200 { { "set", "variable", NULL }, handle_setvariable, "Sets a channel variable", usage_setvariable },
1201 { { "get", "variable", NULL }, handle_getvariable, "Gets a channel variable", usage_getvariable },
1202 { { "verbose", NULL }, handle_verbose, "Logs a message to the asterisk verbose log", usage_verbose },
1203 { { "database", "get", NULL }, handle_dbget, "Gets database value", usage_dbget },
1204 { { "database", "put", NULL }, handle_dbput, "Adds/updates database value", usage_dbput },
1205 { { "database", "del", NULL }, handle_dbdel, "Removes database key/value", usage_dbdel },
1206 { { "database", "deltree", NULL }, handle_dbdeltree, "Removes database keytree/value", usage_dbdeltree },
1207 { { "noop", NULL }, handle_noop, "Does nothing", usage_noop },
1208 { { "set", "music", NULL }, handle_setmusic, "Enable/Disable Music on hold generator", usage_setmusic }
1211 static void join(char *s, size_t len, char *w[])
1214 /* Join words into a string */
1219 for (x=0;w[x];x++) {
1221 strncat(s, " ", len - strlen(s) - 1);
1222 strncat(s, w[x], len - strlen(s) - 1);
1226 static int help_workhorse(int fd, char *match[])
1231 struct agi_command *e;
1233 join(matchstr, sizeof(matchstr), match);
1234 for (x=0;x<sizeof(commands)/sizeof(commands[0]);x++) {
1235 if (!commands[x].cmda[0]) break;
1238 join(fullcmd, sizeof(fullcmd), e->cmda);
1239 /* Hide commands that start with '_' */
1240 if (fullcmd[0] == '_')
1243 if (strncasecmp(matchstr, fullcmd, strlen(matchstr))) {
1247 ast_cli(fd, "%20.20s %s\n", fullcmd, e->summary);
1252 int agi_register(agi_command *agi)
1255 for (x=0;x<MAX_COMMANDS - 1;x++) {
1256 if (commands[x].cmda[0] == agi->cmda[0]) {
1257 ast_log(LOG_WARNING, "Command already registered!\n");
1261 for (x=0;x<MAX_COMMANDS - 1;x++) {
1262 if (!commands[x].cmda[0]) {
1267 ast_log(LOG_WARNING, "No more room for new commands!\n");
1271 void agi_unregister(agi_command *agi)
1274 for (x=0;x<MAX_COMMANDS - 1;x++) {
1275 if (commands[x].cmda[0] == agi->cmda[0]) {
1276 memset(&commands[x], 0, sizeof(agi_command));
1281 static agi_command *find_command(char *cmds[], int exact)
1286 for (x=0;x < sizeof(commands) / sizeof(commands[0]);x++) {
1287 if (!commands[x].cmda[0]) break;
1288 /* start optimistic */
1290 for (y=0;match && cmds[y]; y++) {
1291 /* If there are no more words in the command (and we're looking for
1292 an exact match) or there is a difference between the two words,
1293 then this is not a match */
1294 if (!commands[x].cmda[y] && !exact)
1296 /* don't segfault if the next part of a command doesn't exist */
1297 if (!commands[x].cmda[y]) return NULL;
1298 if (strcasecmp(commands[x].cmda[y], cmds[y]))
1301 /* If more words are needed to complete the command then this is not
1302 a candidate (unless we're looking for a really inexact answer */
1303 if ((exact > -1) && commands[x].cmda[y])
1306 return &commands[x];
1312 static int parse_args(char *s, int *max, char *argv[])
1324 /* If it's escaped, put a literal quote */
1329 if (quoted && whitespace) {
1330 /* If we're starting a quote, coming off white space start a new word, too */
1338 if (!quoted && !escaped) {
1339 /* If we're not quoted, mark this as whitespace, and
1340 end the previous argument */
1344 /* Otherwise, just treat it as anything else */
1348 /* If we're escaped, print a literal, otherwise enable escaping */
1358 if (x >= MAX_ARGS -1) {
1359 ast_log(LOG_WARNING, "Too many arguments, truncating\n");
1362 /* Coming off of whitespace, start the next argument */
1371 /* Null terminate */
1378 static int agi_handle_command(struct ast_channel *chan, AGI *agi, char *buf)
1380 char *argv[MAX_ARGS];
1385 parse_args(buf, &argc, argv);
1388 for (x=0;x<argc;x++)
1389 fprintf(stderr, "Got Arg%d: %s\n", x, argv[x]); }
1391 c = find_command(argv, 0);
1393 res = c->handler(chan, agi, argc, argv);
1395 case RESULT_SHOWUSAGE:
1396 fdprintf(agi->fd, "520-Invalid command syntax. Proper usage follows:\n");
1397 fdprintf(agi->fd, c->usage);
1398 fdprintf(agi->fd, "520 End of proper usage.\n");
1400 case AST_PBX_KEEPALIVE:
1401 /* We've been asked to keep alive, so do so */
1402 return AST_PBX_KEEPALIVE;
1404 case RESULT_FAILURE:
1405 /* They've already given the failure. We've been hung up on so handle this
1410 fdprintf(agi->fd, "510 Invalid or unknown command\n");
1415 static int run_agi(struct ast_channel *chan, char *request, AGI *agi, int pid, int dead)
1417 struct ast_channel *c;
1420 int returnstatus = 0;
1421 struct ast_frame *f;
1424 /* how many times we'll retry if ast_waitfor_nandfs will return without either
1425 channel or file descriptor in case select is interrupted by a system call (EINTR) */
1428 if (!(readf = fdopen(agi->ctrl, "r"))) {
1429 ast_log(LOG_WARNING, "Unable to fdopen file descriptor\n");
1436 setup_env(chan, request, agi->fd, (agi->audio > -1));
1439 c = ast_waitfor_nandfds(&chan, dead ? 0 : 1, &agi->ctrl, 1, NULL, &outfd, &ms);
1442 /* Idle the channel until we get a command */
1445 ast_log(LOG_DEBUG, "%s hungup\n", chan->name);
1449 /* If it's voice, write it to the audio pipe */
1450 if ((agi->audio > -1) && (f->frametype == AST_FRAME_VOICE)) {
1451 /* Write, ignoring errors */
1452 write(agi->audio, f->data, f->datalen);
1456 } else if (outfd > -1) {
1458 if (!fgets(buf, sizeof(buf), readf)) {
1459 /* Program terminated */
1462 if (option_verbose > 2)
1463 ast_verbose(VERBOSE_PREFIX_3 "AGI Script %s completed, returning %d\n", request, returnstatus);
1464 /* No need to kill the pid anymore, since they closed us */
1468 /* get rid of trailing newline, if any */
1469 if (*buf && buf[strlen(buf) - 1] == '\n')
1470 buf[strlen(buf) - 1] = 0;
1472 returnstatus |= agi_handle_command(chan, agi, buf);
1473 /* If the handle_command returns -1, we need to stop */
1474 if ((returnstatus < 0) || (returnstatus == AST_PBX_KEEPALIVE)) {
1479 ast_log(LOG_WARNING, "No channel, no fd?\n");
1485 /* Notify process */
1489 return returnstatus;
1492 static int handle_showagi(int fd, int argc, char *argv[]) {
1493 struct agi_command *e;
1496 return RESULT_SHOWUSAGE;
1498 e = find_command(argv + 2, 1);
1500 ast_cli(fd, e->usage);
1502 if (find_command(argv + 2, -1)) {
1503 return help_workhorse(fd, argv + 1);
1505 join(fullcmd, sizeof(fullcmd), argv+1);
1506 ast_cli(fd, "No such command '%s'.\n", fullcmd);
1510 return help_workhorse(fd, NULL);
1512 return RESULT_SUCCESS;
1515 static int handle_dumpagihtml(int fd, int argc, char *argv[]) {
1516 struct agi_command *e;
1523 return RESULT_SHOWUSAGE;
1525 if (!(htmlfile = fopen(argv[2], "wt"))) {
1526 ast_cli(fd, "Could not create file '%s'\n", argv[2]);
1527 return RESULT_SHOWUSAGE;
1530 fprintf(htmlfile, "<HTML>\n<HEAD>\n<TITLE>AGI Commands</TITLE>\n</HEAD>\n");
1531 fprintf(htmlfile, "<BODY>\n<CENTER><B><H1>AGI Commands</H1></B></CENTER>\n\n");
1534 fprintf(htmlfile, "<TABLE BORDER=\"0\" CELLSPACING=\"10\">\n");
1536 for (x=0;x<sizeof(commands)/sizeof(commands[0]);x++) {
1538 if (!commands[x].cmda[0]) break;
1541 join(fullcmd, sizeof(fullcmd), e->cmda);
1542 /* Hide commands that start with '_' */
1543 if (fullcmd[0] == '_')
1546 fprintf(htmlfile, "<TR><TD><TABLE BORDER=\"1\" CELLPADDING=\"5\" WIDTH=\"100%%\">\n");
1547 fprintf(htmlfile, "<TR><TH ALIGN=\"CENTER\"><B>%s - %s</B></TD></TR>\n", fullcmd,e->summary);
1551 tempstr = strsep(&stringp, "\n");
1553 fprintf(htmlfile, "<TR><TD ALIGN=\"CENTER\">%s</TD></TR>\n", tempstr);
1555 fprintf(htmlfile, "<TR><TD ALIGN=\"CENTER\">\n");
1556 while ((tempstr = strsep(&stringp, "\n")) != NULL) {
1557 fprintf(htmlfile, "%s<BR>\n",tempstr);
1560 fprintf(htmlfile, "</TD></TR>\n");
1561 fprintf(htmlfile, "</TABLE></TD></TR>\n\n");
1565 fprintf(htmlfile, "</TABLE>\n</BODY>\n</HTML>\n");
1567 ast_cli(fd, "AGI HTML Commands Dumped to: %s\n", argv[2]);
1568 return RESULT_SUCCESS;
1571 static int agi_exec_full(struct ast_channel *chan, void *data, int enhanced, int dead)
1574 struct localuser *u;
1575 char *argv[MAX_ARGS];
1577 char *tmp = (char *)buf;
1584 if (!data || ast_strlen_zero(data)) {
1585 ast_log(LOG_WARNING, "AGI requires an argument (script)\n");
1588 strncpy(buf, data, sizeof(buf) - 1);
1590 memset(&agi, 0, sizeof(agi));
1591 while ((stringp = strsep(&tmp, "|"))) {
1592 argv[argc++] = stringp;
1598 /* Answer if need be */
1599 if (chan->_state != AST_STATE_UP) {
1600 if (ast_answer(chan)) {
1601 LOCAL_USER_REMOVE(u);
1606 res = launch_script(argv[0], argv, fds, enhanced ? &efd : NULL, &pid);
1611 res = run_agi(chan, argv[0], &agi, pid, dead);
1616 LOCAL_USER_REMOVE(u);
1620 static int agi_exec(struct ast_channel *chan, void *data)
1622 if (chan->_softhangup)
1623 ast_log(LOG_WARNING, "If you want to run AGI on hungup channels you should use DeadAGI!\n");
1624 return agi_exec_full(chan, data, 0, 0);
1627 static int eagi_exec(struct ast_channel *chan, void *data)
1631 if (chan->_softhangup)
1632 ast_log(LOG_WARNING, "If you want to run AGI on hungup channels you should use DeadAGI!\n");
1633 readformat = chan->readformat;
1634 if (ast_set_read_format(chan, AST_FORMAT_SLINEAR)) {
1635 ast_log(LOG_WARNING, "Unable to set channel '%s' to linear mode\n", chan->name);
1638 res = agi_exec_full(chan, data, 1, 0);
1640 if (ast_set_read_format(chan, readformat)) {
1641 ast_log(LOG_WARNING, "Unable to restore channel '%s' to format %s\n", chan->name, ast_getformatname(readformat));
1647 static int deadagi_exec(struct ast_channel *chan, void *data)
1649 return agi_exec_full(chan, data, 0, 1);
1652 static char showagi_help[] =
1653 "Usage: show agi [topic]\n"
1654 " When called with a topic as an argument, displays usage\n"
1655 " information on the given command. If called without a\n"
1656 " topic, it provides a list of AGI commands.\n";
1659 static char dumpagihtml_help[] =
1660 "Usage: dump agihtml <filename>\n"
1661 " Dumps the agi command list in html format to given filename\n";
1663 static struct ast_cli_entry showagi =
1664 { { "show", "agi", NULL }, handle_showagi, "Show AGI commands or specific help", showagi_help };
1666 static struct ast_cli_entry dumpagihtml =
1667 { { "dump", "agihtml", NULL }, handle_dumpagihtml, "Dumps a list of agi command in html format", dumpagihtml_help };
1669 int unload_module(void)
1671 STANDARD_HANGUP_LOCALUSERS;
1672 ast_cli_unregister(&showagi);
1673 ast_cli_unregister(&dumpagihtml);
1674 ast_unregister_application(eapp);
1675 ast_unregister_application(deadapp);
1676 return ast_unregister_application(app);
1679 int load_module(void)
1681 ast_cli_register(&showagi);
1682 ast_cli_register(&dumpagihtml);
1683 ast_register_application(deadapp, deadagi_exec, deadsynopsis, descrip);
1684 ast_register_application(eapp, eagi_exec, esynopsis, descrip);
1685 return ast_register_application(app, agi_exec, synopsis, descrip);
1688 char *description(void)
1696 STANDARD_USECOUNT(res);
1702 return ASTERISK_GPL_KEY;