On Sunday 06 April 2003 14:09, John Todd wrote:
> There was a conversation last night on the IRC channel between
> myself, Corydon76, citats, and kram on the ability of a call
> process to access the error (or success?) codes underlying a
> call.  I'm uncertain if anything came out of it, but I'll
> re-hash here to solicit other comments.
>
> My idea: I'd like to be able to get to error codes when a call
> passes through some kind of action (with perhaps the exception
> of "Trying" or other "non-end-of-message" results) so that I
> can play error messages or take actions that are appropriate
> to the event.  As an example, currently Asterisk only supports
> "busy" or "unavailable" call codes back from any channel type.
>  However, chan_sip can provide a large array of codes that are
> more meaningful, such as "403 Forbidden" or "480 Temporarily
> unavailable" which can be more useful for both my internal
> logging as well as can trigger an appropriate recording to be
> played back to the user.  Why code individual cases inside of
> chan_blah when this can be extracted to allow the admin to
> handle them as required?
>
> Two solutions were discussed, one method using an application
> and the other simply setting a channel variable.
>
> METHOD 1:
> Corydon76 suggested creating an application that handled the
> redirection of the call process flow.  This would look
> something like this:
>
> OnResultGoto(201:+100,405:+200,480:+250)
>
> where "201", "405", and "480" are the numeric response codes
> corresponding to some useful error message from the channel. 
> This would be called immediately the Dial application.  Jumps
> would be done within the existing context, to the priority X
> within the same context where X is represented by "+X".

Here's the application and the patch needed in the pbx code to
support the result code accessed from the application.  In
addition to the relative branches mentioned in the channel, I
also made absolute branches work (in the usual [[con]|ext]|pri
format).

Again, untested code.

-Tilghman
Index: pbx.c
===================================================================
RCS file: /usr/cvsroot/asterisk/pbx.c,v
retrieving revision 1.8
diff -u -r1.8 pbx.c
--- pbx.c	3 Apr 2003 07:35:14 -0000	1.8
+++ pbx.c	6 Apr 2003 18:36:17 -0000
@@ -1428,7 +1428,6 @@
 	char exten[256];
 	int pos;
 	int waittime;
-	int res=0;
 
 	/* A little initial setup here */
 	if (c->pbx)
@@ -1479,17 +1478,17 @@
 				"Extension: %s\r\n"
 				"Priority: %d\r\n",
 				c->name, c->context, c->exten, c->priority);			
-			if ((res = ast_spawn_extension(c, c->context, c->exten, c->priority, c->callerid))) {
+			if ((c->res = ast_spawn_extension(c, c->context, c->exten, c->priority, c->callerid))) {
 				/* Something bad happened, or a hangup has been requested. */
-				if (((res >= '0') && (res <= '9')) || ((res >= 'A') && (res <= 'F')) ||
-					(res == '*') || (res == '#')) {
-					ast_log(LOG_DEBUG, "Oooh, got something to jump out with ('%c')!\n", res);
+				if (((c->res >= '0') && (c->res <= '9')) || ((c->res >= 'A') && (c->res <= 'F')) ||
+					(c->res == '*') || (c->res == '#')) {
+					ast_log(LOG_DEBUG, "Oooh, got something to jump out with ('%c')!\n", c->res);
 					memset(exten, 0, sizeof(exten));
 					pos = 0;
-					exten[pos++] = digit = res;
+					exten[pos++] = digit = c->res;
 					break;
 				}
-				switch(res) {
+				switch(c->res) {
 				case AST_PBX_KEEPALIVE:
 					if (option_debug)
 						ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited KEEPALIVE on '%s'\n", c->context, c->exten, c->priority, c->name);
@@ -1602,7 +1601,7 @@
 		strcpy(c->exten, "h");
 		c->priority = 1;
 		while(ast_exists_extension(c, c->context, c->exten, c->priority, c->callerid)) {
-			if ((res = ast_spawn_extension(c, c->context, c->exten, c->priority, c->callerid))) {
+			if ((c->res = ast_spawn_extension(c, c->context, c->exten, c->priority, c->callerid))) {
 				/* Something bad happened, or a hangup has been requested. */
 				if (option_debug)
 					ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
@@ -1616,7 +1615,7 @@
 
 	pbx_destroy(c->pbx);
 	c->pbx = NULL;
-	if (res != AST_PBX_KEEPALIVE)
+	if (c->res != AST_PBX_KEEPALIVE)
 		ast_hangup(c);
 	return 0;
 }
Index: include/asterisk/channel.h
===================================================================
RCS file: /usr/cvsroot/asterisk/include/asterisk/channel.h,v
retrieving revision 1.3
diff -u -r1.3 channel.h
--- include/asterisk/channel.h	30 Mar 2003 22:55:42 -0000	1.3
+++ include/asterisk/channel.h	6 Apr 2003 18:36:18 -0000
@@ -99,6 +99,8 @@
 	char *appl;				
 	/*! Data passed to current application */
 	char *data;				
+	/*! Result code from the prior executed application */
+	int res;
 	
 	/*! Has an exception been detected */
 	int exception;				
/*
 * Asterisk -- A telephony toolkit for Linux.
 *
 * OnResultGoto application
 *
 * Copyright (c) 2003 Tilghman Lesher.  All rights reserved.
 * 
 * Tilghman Lesher <[EMAIL PROTECTED]>
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO
 * EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include <asterisk/file.h>
#include <asterisk/options.h>
#include <asterisk/logger.h>
#include <asterisk/channel.h>
#include <asterisk/pbx.h>
#include <asterisk/module.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>

#include <pthread.h>


static char *tdesc = "Use result codes to branch";
static char *app_onresultgoto = "OnResultGoto";
static char *onresultgoto_synopsis = "Branch to a new priority/extension based upon the prior application's result code.";
static char *onresultgoto_descrip =
"OnResultGoto(res-code:[[context]|extension]|priority[&res-code:...])\n"
"            (res-code:+priority[&res-code:...])\n"
"  You may mix the two types of Gotos (i.e. absolute or relative) in the\n"
"same command.  Returns the same result code as the prior application (which\n"
"allows processing of result codes to occur over multiple lines).\n";

STANDARD_LOCAL_USER;

LOCAL_USER_DECL;

static int onresultgoto_exec(struct ast_channel *chan, void *data)
{
	struct localuser *u;
	char *arg, *nextarg, *thisarg;

	if (!data) {
		ast_log(LOG_WARNING, "OnResultGoto requires an argument (rescode:+priority[&rescode:...])\n");
		return chan->res;
	}
	LOCAL_USER_ADD(u);

	arg = strdup(data);
	nextarg = arg;
	while((thisarg = strsep(&nextarg,"&"))) {
		char *arg2, *gotopath, *resultcode;
		arg2 = strdup(thisarg);
		gotopath = arg2;
		resultcode = strsep(&gotopath,":");
		if ((resultcode != NULL) && (atoi(resultcode) == chan->res)) {
			if ((gotopath[0] == '+') || (gotopath[0] == '-')) {
				/* Relative goto */
				int pri = atoi(gotopath);
				if (chan->priority + pri - 1 >= 0)
					chan->priority += pri - 1;

				if (option_verbose > 2)
					ast_verbose( VERBOSE_PREFIX_3 "OnResultGoto (%s,%s,%d) resultcode=%i\n",
						chan->context,chan->exten, chan->priority+1, chan->res);
				/* Short-circuit */
				nextarg = NULL;
			} else {
				/* Absolute goto */
				char *context, *exten, *pri;

				context = strsep(&gotopath, "|");
				exten = strsep(&gotopath, "|");
				if (!exten) {
					/* Only a priority */
					pri = context;
					exten = NULL;
					context = NULL;
				} else {
					pri = strsep(&gotopath, "|");
					if (!pri) {
						pri = exten;
						exten = context;
						context = NULL;
					}
				}
				if (atoi(pri) < 0) {
					ast_log(LOG_WARNING, "Priority '%s' must be a number > 0\n", pri);
				} else {
					/* At this point we have a priority and */
					/* maybe an extension and a context     */
					chan->priority = atoi(pri) - 1;
					if (exten && strcasecmp(exten, "BYEXTENSION"))
						strncpy(chan->exten, exten, sizeof(chan->exten)-1);
					if (context)
						strncpy(chan->context, context, sizeof(chan->context)-1);
					if (option_verbose > 2)
						ast_verbose( VERBOSE_PREFIX_3 "OnResultGoto (%s,%s,%d) resultcode=%d\n",
							chan->context,chan->exten, chan->priority+1, chan->res);

					/* Short-circuit */
					nextarg = NULL;
				}
			}
		}
		free(arg2);
	}
	free(arg);
		
	LOCAL_USER_REMOVE(u);
	return chan->res;
}

int unload_module(void)
{
	STANDARD_HANGUP_LOCALUSERS;
	return ast_unregister_application(app_onresultgoto);
}

int load_module(void)
{
	return ast_register_application(app_onresultgoto, onresultgoto_exec, onresultgoto_synopsis, onresultgoto_descrip);
}

char *description(void)
{
	return tdesc;
}

int usecount(void)
{
	int res;
	STANDARD_USECOUNT(res);
	return res;
}

char *key()
{
	return ASTERISK_GPL_KEY;
}

Reply via email to