From 0cccaf84089ebb20b630e392778f9da9f5cc2856 Mon Sep 17 00:00:00 2001 From: Russell Bryant Date: Thu, 25 May 2006 16:44:22 +0000 Subject: - add support for setting an AGISTATUS variable that indicates successful execution, failure, or if the channel requested hangup. - only return -1 from the application if the application requested hangup. If there was just a failure in execution of the AGI, just set the status variable appropriately and move on in the dialplan. (issue #7121, original patch by Alessandro Polverini, updated patch by srt, committed patch is heavily modified to allow still returning -1 on hangup) git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@30272 65c4cc65-6c06-0410-ace0-fbb531ad65f3 --- res/res_agi.c | 75 ++++++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 48 insertions(+), 27 deletions(-) (limited to 'res/res_agi.c') diff --git a/res/res_agi.c b/res/res_agi.c index 9d082ef6d..481edc5bc 100644 --- a/res/res_agi.c +++ b/res/res_agi.c @@ -86,11 +86,15 @@ static char *descrip = "written in any language to control a telephony channel, play audio,\n" "read DTMF digits, etc. by communicating with the AGI protocol on stdin\n" "and stdout.\n" -"Returns -1 on hangup (except for DeadAGI) or if application requested\n" -" hangup, or 0 on non-hangup exit. \n" -"Using 'EAGI' provides enhanced AGI, with incoming audio available out of band\n" +" This channel will stop dialplan execution on hangup inside of this\n" +"application, except when using DeadAGI. Otherwise, dialplan execution\n" +"will continue normally.\n" +" Using 'EAGI' provides enhanced AGI, with incoming audio available out of band\n" "on file descriptor 3\n\n" -"Use the CLI command 'show agi' to list available agi commands\n"; +" Use the CLI command 'show agi' to list available agi commands\n" +" This application sets the following channel variable upon completion:\n" +" AGISTATUS The status of the attempt to the run the AGI script\n" +" text string, one of SUCCESS | FAILED | HANGUP\n"; static int agidebug = 0; @@ -103,6 +107,12 @@ struct module_symbols *me; #define AGI_PORT 4573 +enum agi_result { + AGI_RESULT_SUCCESS, + AGI_RESULT_FAILURE, + AGI_RESULT_HANGUP +}; + static void agi_debug_cli(int fd, char *fmt, ...) { char *stuff; @@ -124,7 +134,7 @@ static void agi_debug_cli(int fd, char *fmt, ...) /* launch_netscript: The fastagi handler. FastAGI defaults to port 4573 */ -static int launch_netscript(char *agiurl, char *argv[], int *fds, int *efd, int *opid) +static enum agi_result launch_netscript(char *agiurl, char *argv[], int *fds, int *efd, int *opid) { int s; int flags; @@ -181,7 +191,7 @@ static int launch_netscript(char *agiurl, char *argv[], int *fds, int *efd, int if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) && (errno != EINPROGRESS)) { ast_log(LOG_WARNING, "Connect failed with unexpected error: %s\n", strerror(errno)); close(s); - return -1; + return AGI_RESULT_FAILURE; } pfds[0].fd = s; @@ -190,7 +200,7 @@ static int launch_netscript(char *agiurl, char *argv[], int *fds, int *efd, int if (errno != EINTR) { ast_log(LOG_WARNING, "Connect to '%s' failed: %s\n", agiurl, strerror(errno)); close(s); - return -1; + return AGI_RESULT_FAILURE; } } /* XXX in theory should check for partial writes... */ @@ -198,7 +208,7 @@ static int launch_netscript(char *agiurl, char *argv[], int *fds, int *efd, int if (errno != EINTR) { ast_log(LOG_WARNING, "Connect to '%s' failed: %s\n", agiurl, strerror(errno)); close(s); - return -1; + return AGI_RESULT_FAILURE; } } @@ -211,10 +221,10 @@ static int launch_netscript(char *agiurl, char *argv[], int *fds, int *efd, int fds[0] = s; fds[1] = s; *opid = -1; - return 0; + return AGI_RESULT_SUCCESS; } -static int launch_script(char *script, char *argv[], int *fds, int *efd, int *opid) +static enum agi_result launch_script(char *script, char *argv[], int *fds, int *efd, int *opid) { char tmp[256]; int pid; @@ -234,13 +244,13 @@ static int launch_script(char *script, char *argv[], int *fds, int *efd, int *op } if (pipe(toast)) { ast_log(LOG_WARNING, "Unable to create toast pipe: %s\n",strerror(errno)); - return -1; + return AGI_RESULT_FAILURE; } if (pipe(fromast)) { ast_log(LOG_WARNING, "unable to create fromast pipe: %s\n", strerror(errno)); close(toast[0]); close(toast[1]); - return -1; + return AGI_RESULT_FAILURE; } if (efd) { if (pipe(audio)) { @@ -249,7 +259,7 @@ static int launch_script(char *script, char *argv[], int *fds, int *efd, int *op close(fromast[1]); close(toast[0]); close(toast[1]); - return -1; + return AGI_RESULT_FAILURE; } res = fcntl(audio[1], F_GETFL); if (res > -1) @@ -262,13 +272,13 @@ static int launch_script(char *script, char *argv[], int *fds, int *efd, int *op close(toast[1]); close(audio[0]); close(audio[1]); - return -1; + return AGI_RESULT_FAILURE; } } pid = fork(); if (pid < 0) { ast_log(LOG_WARNING, "Failed to fork(): %s\n", strerror(errno)); - return -1; + return AGI_RESULT_FAILURE; } if (!pid) { /* Pass paths to AGI via environmental variables */ @@ -324,13 +334,11 @@ static int launch_script(char *script, char *argv[], int *fds, int *efd, int *op close(toast[1]); close(fromast[0]); - if (efd) { - /* [PHM 12/18/03] */ + if (efd) close(audio[0]); - } *opid = pid; - return 0; + return AGI_RESULT_SUCCESS; } @@ -1773,12 +1781,12 @@ static int agi_handle_command(struct ast_channel *chan, AGI *agi, char *buf) return 0; } #define RETRY 3 -static int run_agi(struct ast_channel *chan, char *request, AGI *agi, int pid, int dead) +static enum agi_result run_agi(struct ast_channel *chan, char *request, AGI *agi, int pid, int dead) { struct ast_channel *c; int outfd; int ms; - int returnstatus = 0; + enum agi_result returnstatus = AGI_RESULT_SUCCESS; struct ast_frame *f; char buf[2048]; FILE *readf; @@ -1791,7 +1799,7 @@ static int run_agi(struct ast_channel *chan, char *request, AGI *agi, int pid, i if (pid > -1) kill(pid, SIGHUP); close(agi->ctrl); - return -1; + return AGI_RESULT_FAILURE; } setlinebuf(readf); setup_env(chan, request, agi->fd, (agi->audio > -1)); @@ -1804,7 +1812,7 @@ static int run_agi(struct ast_channel *chan, char *request, AGI *agi, int pid, i f = ast_read(c); if (!f) { ast_log(LOG_DEBUG, "%s hungup\n", chan->name); - returnstatus = -1; + returnstatus = AGI_RESULT_HANGUP; break; } else { /* If it's voice, write it to the audio pipe */ @@ -1839,7 +1847,7 @@ static int run_agi(struct ast_channel *chan, char *request, AGI *agi, int pid, i } else { if (--retry <= 0) { ast_log(LOG_WARNING, "No channel, no fd?\n"); - returnstatus = -1; + returnstatus = AGI_RESULT_FAILURE; break; } } @@ -1933,7 +1941,7 @@ static int handle_dumpagihtml(int fd, int argc, char *argv[]) static int agi_exec_full(struct ast_channel *chan, void *data, int enhanced, int dead) { - int res=0; + enum agi_result res; struct localuser *u; char *argv[MAX_ARGS]; char buf[2048]=""; @@ -1967,7 +1975,7 @@ static int agi_exec_full(struct ast_channel *chan, void *data, int enhanced, int } #endif res = launch_script(argv[0], argv, fds, enhanced ? &efd : NULL, &pid); - if (!res) { + if (res == AGI_RESULT_SUCCESS) { agi.fd = fds[1]; agi.ctrl = fds[0]; agi.audio = efd; @@ -1977,7 +1985,20 @@ static int agi_exec_full(struct ast_channel *chan, void *data, int enhanced, int close(efd); } ast_localuser_remove(me, u); - return res; + + switch (res) { + case AGI_RESULT_SUCCESS: + pbx_builtin_setvar_helper(chan, "AGISTATUS", "SUCCESS"); + break; + case AGI_RESULT_FAILURE: + pbx_builtin_setvar_helper(chan, "AGISTATUS", "FAILURE"); + break; + case AGI_RESULT_HANGUP: + pbx_builtin_setvar_helper(chan, "AGISTATUS", "HANGUP"); + return -1; + } + + return 0; } static int agi_exec(struct ast_channel *chan, void *data) -- cgit v1.2.3