[asterisk-commits] dvossel: branch 1.4 r198891 - in /branches/1.4: include/asterisk/ main/ res/

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Wed Jun 3 10:49:51 CDT 2009


Author: dvossel
Date: Wed Jun  3 10:49:46 2009
New Revision: 198891

URL: http://svn.asterisk.org/svn-view/asterisk?view=rev&rev=198891
Log:
Generic call forward api, ast_call_forward()

The function ast_call_forward() forwards a call to an extension specified in an ast_channel's call_forward string.  After an ast_channel is called, if the channel's call_forward string is set this function can be used to forward the call to a new channel and terminate the original one.  I have included this api call in both channel.c's ast_request_and_dial() and res_feature.c's feature_request_and_dial().  App_dial and app_queue already contain call forward logic specific for their application and options.

(closes issue #13630)
Reported by: festr

Review: https://reviewboard.asterisk.org/r/271/


Modified:
    branches/1.4/include/asterisk/channel.h
    branches/1.4/main/channel.c
    branches/1.4/res/res_features.c

Modified: branches/1.4/include/asterisk/channel.h
URL: http://svn.asterisk.org/svn-view/asterisk/branches/1.4/include/asterisk/channel.h?view=diff&rev=198891&r1=198890&r2=198891
==============================================================================
--- branches/1.4/include/asterisk/channel.h (original)
+++ branches/1.4/include/asterisk/channel.h Wed Jun  3 10:49:46 2009
@@ -717,6 +717,18 @@
 
 struct ast_channel *__ast_request_and_dial(const char *type, int format, void *data, int timeout, int *reason, const char *cidnum, const char *cidname, struct outgoing_helper *oh);
 
+/*!
+* \brief Forwards a call to a new channel specified by the original channel's call_forward str.  If possible, the new forwarded channel is created and returned while the original one is terminated.
+* \param caller in channel that requested orig
+* \param orig channel being replaced by the call forward channel
+* \param timeout maximum amount of time to wait for setup of new forward channel
+* \param format requested channel format
+* \param oh outgoing helper used with original channel
+* \param outstate reason why unsuccessful (if uncuccessful)
+* \return Returns the forwarded call's ast_channel on success or NULL on failure
+*/
+struct ast_channel *ast_call_forward(struct ast_channel *caller, struct ast_channel *orig, int *timeout, int format, struct outgoing_helper *oh, int *outstate);
+
 /*!\brief Register a channel technology (a new channel driver)
  * Called by a channel module to register the kind of channels it supports.
  * \param tech Structure defining channel technology or "type"

Modified: branches/1.4/main/channel.c
URL: http://svn.asterisk.org/svn-view/asterisk/branches/1.4/main/channel.c?view=diff&rev=198891&r1=198890&r2=198891
==============================================================================
--- branches/1.4/main/channel.c (original)
+++ branches/1.4/main/channel.c Wed Jun  3 10:49:46 2009
@@ -3027,6 +3027,86 @@
 	}
 }
 
+static void handle_cause(int cause, int *outstate)
+{
+	if (outstate) {
+		/* compute error and return */
+		if (cause == AST_CAUSE_BUSY)
+			*outstate = AST_CONTROL_BUSY;
+		else if (cause == AST_CAUSE_CONGESTION)
+			*outstate = AST_CONTROL_CONGESTION;
+		else
+			*outstate = 0;
+	}
+}
+
+struct ast_channel *ast_call_forward(struct ast_channel *caller, struct ast_channel *orig, int *timeout, int format, struct outgoing_helper *oh, int *outstate)
+{
+	char tmpchan[256];
+	struct ast_channel *new = NULL;
+	char *data, *type;
+	int cause = 0;
+
+	/* gather data and request the new forward channel */
+	ast_copy_string(tmpchan, orig->call_forward, sizeof(tmpchan));
+	if ((data = strchr(tmpchan, '/'))) {
+		*data++ = '\0';
+		type = tmpchan;
+	} else {
+		const char *forward_context;
+		ast_channel_lock(orig);
+		forward_context = pbx_builtin_getvar_helper(orig, "FORWARD_CONTEXT");
+		snprintf(tmpchan, sizeof(tmpchan), "%s@%s", orig->call_forward, S_OR(forward_context, orig->context));
+		ast_channel_unlock(orig);
+		data = tmpchan;
+		type = "Local";
+	}
+	if (!(new = ast_request(type, format, data, &cause))) {
+		ast_log(LOG_NOTICE, "Unable to create channel for call forward to '%s/%s' (cause = %d)\n", type, data, cause);
+		handle_cause(cause, outstate);
+		ast_hangup(orig);
+		return NULL;
+	}
+
+	/* Copy/inherit important information into new channel */
+	if (oh) {
+		if (oh->vars) {
+			ast_set_variables(new, oh->vars);
+		}
+		if (!ast_strlen_zero(oh->cid_num) && !ast_strlen_zero(oh->cid_name)) {
+			ast_set_callerid(new, oh->cid_num, oh->cid_name, oh->cid_num);
+		}
+		if (oh->parent_channel) {
+			ast_channel_inherit_variables(oh->parent_channel, new);
+			ast_channel_datastore_inherit(oh->parent_channel, new);
+		}
+		if (oh->account) {
+			ast_cdr_setaccount(new, oh->account);
+		}
+	} else if (caller) { /* no outgoing helper so use caller if avaliable */
+		ast_channel_inherit_variables(caller, new);
+		ast_channel_datastore_inherit(caller, new);
+	}
+
+	ast_channel_lock(orig);
+	ast_string_field_set(new, accountcode, orig->accountcode);
+	if (!ast_strlen_zero(orig->cid.cid_num) && !ast_strlen_zero(new->cid.cid_name)) {
+		ast_set_callerid(new, orig->cid.cid_num, orig->cid.cid_name, orig->cid.cid_num);
+	}
+	ast_channel_unlock(orig);
+
+	/* call new channel */
+	if ((*timeout = ast_call(new, data, 0))) {
+		ast_log(LOG_NOTICE, "Unable to call forward to channel %s/%s\n", type, (char *)data);
+		ast_hangup(orig);
+		ast_hangup(new);
+		return NULL;
+	}
+	ast_hangup(orig);
+
+	return new;
+}
+
 struct ast_channel *__ast_request_and_dial(const char *type, int format, void *data, int timeout, int *outstate, const char *cid_num, const char *cid_name, struct outgoing_helper *oh)
 {
 	int dummy_outstate;
@@ -3043,11 +3123,7 @@
 	chan = ast_request(type, format, data, &cause);
 	if (!chan) {
 		ast_log(LOG_NOTICE, "Unable to request channel %s/%s\n", type, (char *)data);
-		/* compute error and return */
-		if (cause == AST_CAUSE_BUSY)
-			*outstate = AST_CONTROL_BUSY;
-		else if (cause == AST_CAUSE_CONGESTION)
-			*outstate = AST_CONTROL_CONGESTION;
+		handle_cause(cause, outstate);
 		return NULL;
 	}
 
@@ -3076,6 +3152,13 @@
 				break;
 			if (timeout > -1)
 				timeout = res;
+			if (!ast_strlen_zero(chan->call_forward)) {
+				if (!(chan = ast_call_forward(NULL, chan, &timeout, format, oh, outstate))) {
+					return NULL;
+				}
+				continue;
+			}
+
 			f = ast_read(chan);
 			if (!f) {
 				*outstate = AST_CONTROL_HANGUP;

Modified: branches/1.4/res/res_features.c
URL: http://svn.asterisk.org/svn-view/asterisk/branches/1.4/res/res_features.c?view=diff&rev=198891&r1=198890&r2=198891
==============================================================================
--- branches/1.4/res/res_features.c (original)
+++ branches/1.4/res/res_features.c Wed Jun  3 10:49:46 2009
@@ -1445,7 +1445,13 @@
 				if (!active_channel)
 					continue;
 
-				if (chan && (chan == active_channel)){
+				if (chan && (chan == active_channel)) {
+					if (!ast_strlen_zero(chan->call_forward)) {
+						if (!(chan = ast_call_forward(caller, chan, &to, format, NULL, outstate))) {
+							return NULL;
+						}
+						continue;
+					}
 					f = ast_read(chan);
 					if (f == NULL) { /*doh! where'd he go?*/
 						state = AST_CONTROL_HANGUP;




More information about the asterisk-commits mailing list