mirror of
https://github.com/asterisk/asterisk.git
synced 2025-10-14 08:31:02 +00:00
- 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
This commit is contained in:
@@ -602,6 +602,7 @@ In Asterisk 1.2, many applications return the result in a variable
|
|||||||
instead of, as in Asterisk 1.0, changing the dial plan priority (+101).
|
instead of, as in Asterisk 1.0, changing the dial plan priority (+101).
|
||||||
For the various status values, see each application's help text.
|
For the various status values, see each application's help text.
|
||||||
|
|
||||||
|
${AGISTATUS} * agi()
|
||||||
${AQMSTATUS} * addqueuemember()
|
${AQMSTATUS} * addqueuemember()
|
||||||
${AVAILSTATUS} * chanisavail()
|
${AVAILSTATUS} * chanisavail()
|
||||||
${CHECKGROUPSTATUS} * checkgroup()
|
${CHECKGROUPSTATUS} * checkgroup()
|
||||||
|
@@ -86,11 +86,15 @@ static char *descrip =
|
|||||||
"written in any language to control a telephony channel, play audio,\n"
|
"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"
|
"read DTMF digits, etc. by communicating with the AGI protocol on stdin\n"
|
||||||
"and stdout.\n"
|
"and stdout.\n"
|
||||||
"Returns -1 on hangup (except for DeadAGI) or if application requested\n"
|
" This channel will stop dialplan execution on hangup inside of this\n"
|
||||||
" hangup, or 0 on non-hangup exit. \n"
|
"application, except when using DeadAGI. Otherwise, dialplan execution\n"
|
||||||
"Using 'EAGI' provides enhanced AGI, with incoming audio available out of band\n"
|
"will continue normally.\n"
|
||||||
|
" Using 'EAGI' provides enhanced AGI, with incoming audio available out of band\n"
|
||||||
"on file descriptor 3\n\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;
|
static int agidebug = 0;
|
||||||
|
|
||||||
@@ -103,6 +107,12 @@ struct module_symbols *me;
|
|||||||
|
|
||||||
#define AGI_PORT 4573
|
#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, ...)
|
static void agi_debug_cli(int fd, char *fmt, ...)
|
||||||
{
|
{
|
||||||
char *stuff;
|
char *stuff;
|
||||||
@@ -124,7 +134,7 @@ static void agi_debug_cli(int fd, char *fmt, ...)
|
|||||||
|
|
||||||
/* launch_netscript: The fastagi handler.
|
/* launch_netscript: The fastagi handler.
|
||||||
FastAGI defaults to port 4573 */
|
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 s;
|
||||||
int flags;
|
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)) {
|
if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) && (errno != EINPROGRESS)) {
|
||||||
ast_log(LOG_WARNING, "Connect failed with unexpected error: %s\n", strerror(errno));
|
ast_log(LOG_WARNING, "Connect failed with unexpected error: %s\n", strerror(errno));
|
||||||
close(s);
|
close(s);
|
||||||
return -1;
|
return AGI_RESULT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
pfds[0].fd = s;
|
pfds[0].fd = s;
|
||||||
@@ -190,7 +200,7 @@ static int launch_netscript(char *agiurl, char *argv[], int *fds, int *efd, int
|
|||||||
if (errno != EINTR) {
|
if (errno != EINTR) {
|
||||||
ast_log(LOG_WARNING, "Connect to '%s' failed: %s\n", agiurl, strerror(errno));
|
ast_log(LOG_WARNING, "Connect to '%s' failed: %s\n", agiurl, strerror(errno));
|
||||||
close(s);
|
close(s);
|
||||||
return -1;
|
return AGI_RESULT_FAILURE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* XXX in theory should check for partial writes... */
|
/* 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) {
|
if (errno != EINTR) {
|
||||||
ast_log(LOG_WARNING, "Connect to '%s' failed: %s\n", agiurl, strerror(errno));
|
ast_log(LOG_WARNING, "Connect to '%s' failed: %s\n", agiurl, strerror(errno));
|
||||||
close(s);
|
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[0] = s;
|
||||||
fds[1] = s;
|
fds[1] = s;
|
||||||
*opid = -1;
|
*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];
|
char tmp[256];
|
||||||
int pid;
|
int pid;
|
||||||
@@ -234,13 +244,13 @@ static int launch_script(char *script, char *argv[], int *fds, int *efd, int *op
|
|||||||
}
|
}
|
||||||
if (pipe(toast)) {
|
if (pipe(toast)) {
|
||||||
ast_log(LOG_WARNING, "Unable to create toast pipe: %s\n",strerror(errno));
|
ast_log(LOG_WARNING, "Unable to create toast pipe: %s\n",strerror(errno));
|
||||||
return -1;
|
return AGI_RESULT_FAILURE;
|
||||||
}
|
}
|
||||||
if (pipe(fromast)) {
|
if (pipe(fromast)) {
|
||||||
ast_log(LOG_WARNING, "unable to create fromast pipe: %s\n", strerror(errno));
|
ast_log(LOG_WARNING, "unable to create fromast pipe: %s\n", strerror(errno));
|
||||||
close(toast[0]);
|
close(toast[0]);
|
||||||
close(toast[1]);
|
close(toast[1]);
|
||||||
return -1;
|
return AGI_RESULT_FAILURE;
|
||||||
}
|
}
|
||||||
if (efd) {
|
if (efd) {
|
||||||
if (pipe(audio)) {
|
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(fromast[1]);
|
||||||
close(toast[0]);
|
close(toast[0]);
|
||||||
close(toast[1]);
|
close(toast[1]);
|
||||||
return -1;
|
return AGI_RESULT_FAILURE;
|
||||||
}
|
}
|
||||||
res = fcntl(audio[1], F_GETFL);
|
res = fcntl(audio[1], F_GETFL);
|
||||||
if (res > -1)
|
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(toast[1]);
|
||||||
close(audio[0]);
|
close(audio[0]);
|
||||||
close(audio[1]);
|
close(audio[1]);
|
||||||
return -1;
|
return AGI_RESULT_FAILURE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pid = fork();
|
pid = fork();
|
||||||
if (pid < 0) {
|
if (pid < 0) {
|
||||||
ast_log(LOG_WARNING, "Failed to fork(): %s\n", strerror(errno));
|
ast_log(LOG_WARNING, "Failed to fork(): %s\n", strerror(errno));
|
||||||
return -1;
|
return AGI_RESULT_FAILURE;
|
||||||
}
|
}
|
||||||
if (!pid) {
|
if (!pid) {
|
||||||
/* Pass paths to AGI via environmental variables */
|
/* 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(toast[1]);
|
||||||
close(fromast[0]);
|
close(fromast[0]);
|
||||||
|
|
||||||
if (efd) {
|
if (efd)
|
||||||
/* [PHM 12/18/03] */
|
|
||||||
close(audio[0]);
|
close(audio[0]);
|
||||||
}
|
|
||||||
|
|
||||||
*opid = pid;
|
*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;
|
return 0;
|
||||||
}
|
}
|
||||||
#define RETRY 3
|
#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;
|
struct ast_channel *c;
|
||||||
int outfd;
|
int outfd;
|
||||||
int ms;
|
int ms;
|
||||||
int returnstatus = 0;
|
enum agi_result returnstatus = AGI_RESULT_SUCCESS;
|
||||||
struct ast_frame *f;
|
struct ast_frame *f;
|
||||||
char buf[2048];
|
char buf[2048];
|
||||||
FILE *readf;
|
FILE *readf;
|
||||||
@@ -1791,7 +1799,7 @@ static int run_agi(struct ast_channel *chan, char *request, AGI *agi, int pid, i
|
|||||||
if (pid > -1)
|
if (pid > -1)
|
||||||
kill(pid, SIGHUP);
|
kill(pid, SIGHUP);
|
||||||
close(agi->ctrl);
|
close(agi->ctrl);
|
||||||
return -1;
|
return AGI_RESULT_FAILURE;
|
||||||
}
|
}
|
||||||
setlinebuf(readf);
|
setlinebuf(readf);
|
||||||
setup_env(chan, request, agi->fd, (agi->audio > -1));
|
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);
|
f = ast_read(c);
|
||||||
if (!f) {
|
if (!f) {
|
||||||
ast_log(LOG_DEBUG, "%s hungup\n", chan->name);
|
ast_log(LOG_DEBUG, "%s hungup\n", chan->name);
|
||||||
returnstatus = -1;
|
returnstatus = AGI_RESULT_HANGUP;
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
/* If it's voice, write it to the audio pipe */
|
/* 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 {
|
} else {
|
||||||
if (--retry <= 0) {
|
if (--retry <= 0) {
|
||||||
ast_log(LOG_WARNING, "No channel, no fd?\n");
|
ast_log(LOG_WARNING, "No channel, no fd?\n");
|
||||||
returnstatus = -1;
|
returnstatus = AGI_RESULT_FAILURE;
|
||||||
break;
|
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)
|
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;
|
struct localuser *u;
|
||||||
char *argv[MAX_ARGS];
|
char *argv[MAX_ARGS];
|
||||||
char buf[2048]="";
|
char buf[2048]="";
|
||||||
@@ -1967,7 +1975,7 @@ static int agi_exec_full(struct ast_channel *chan, void *data, int enhanced, int
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
res = launch_script(argv[0], argv, fds, enhanced ? &efd : NULL, &pid);
|
res = launch_script(argv[0], argv, fds, enhanced ? &efd : NULL, &pid);
|
||||||
if (!res) {
|
if (res == AGI_RESULT_SUCCESS) {
|
||||||
agi.fd = fds[1];
|
agi.fd = fds[1];
|
||||||
agi.ctrl = fds[0];
|
agi.ctrl = fds[0];
|
||||||
agi.audio = efd;
|
agi.audio = efd;
|
||||||
@@ -1977,7 +1985,20 @@ static int agi_exec_full(struct ast_channel *chan, void *data, int enhanced, int
|
|||||||
close(efd);
|
close(efd);
|
||||||
}
|
}
|
||||||
ast_localuser_remove(me, u);
|
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)
|
static int agi_exec(struct ast_channel *chan, void *data)
|
||||||
|
Reference in New Issue
Block a user