[asterisk-dev] [RFC][PATCH] export attended transfer functionality over AMI

Paolo Ornati ornati at fastwebnet.it
Sun Aug 26 02:58:43 CDT 2007


Hello,

currently there's no way (that I know) to activate an attended tranfer
through the AMI, it can be useful for "controlling" GUIs etc...

This patch export this functionality and seems to work.

I'm interested in any type of feedback. In particular I'd like to know
what the interface should look like: now it's really simple, it just
takes the "transferer" channel and the extension to transfer to. Should
I also add optional "Context" and "Priority"?


On the implementation side: I've reused the "AST_CONTROL" type of frame,
is it acceptable?


patch is for 1.4.11

--

diff --git a/include/asterisk/frame.h b/include/asterisk/frame.h
index cc3aa5d..ec0fbf2 100644
--- a/include/asterisk/frame.h
+++ b/include/asterisk/frame.h
@@ -281,6 +281,7 @@ enum ast_control_frame_type {
 	AST_CONTROL_HOLD = 16,		/*!< Indicate call is placed on hold */
 	AST_CONTROL_UNHOLD = 17,	/*!< Indicate call is left from hold */
 	AST_CONTROL_VIDUPDATE = 18,	/*!< Indicate video frame update */
+	AST_CONTROL_ATXFERCMD = 19,	/* Attended Transfer  */
 };
 
 #define AST_SMOOTHER_FLAG_G729		(1 << 0)
diff --git a/main/manager.c b/main/manager.c
index e46fafe..74539b6 100644
--- a/main/manager.c
+++ b/main/manager.c
@@ -1608,6 +1608,33 @@ static int action_redirect(struct mansession *s, const struct message *m)
 	return 0;
 }
 
+static char mandescr_atxfer[] = 
+"Description: do attended transfer.\n"
+"Variables: (Names marked with * are required)\n"
+"	*Channel: transferer Channel\n"
+"	Exten: Extension to transfer to (if not given it will be asked on the transferer channel)\n"
+"	ActionID: Optional Action id for message matching.\n";
+
+static int action_atxfer(struct mansession *s, const struct message *m)
+{
+	struct ast_channel *c = NULL;
+	const char *name = astman_get_header(m, "Channel");
+	const char *exten = S_OR(astman_get_header(m, "Exten"),"");
+	if (ast_strlen_zero(name)) {
+		astman_send_error(s, m, "No channel specified");
+		return 0;
+	}
+	c = ast_get_channel_by_name_locked(name);
+	if (!c) {
+		astman_send_error(s, m, "No such channel");
+		return 0;
+	}
+	ast_queue_control_data(c, AST_CONTROL_ATXFERCMD, exten, strlen(exten)+1);
+	ast_channel_unlock(c);
+	astman_send_ack(s, m, "Attended transfer started");
+	return 0;
+}
+
 static char mandescr_command[] = 
 "Description: Run a CLI command.\n"
 "Variables: (Names marked with * are required)\n"
@@ -2754,6 +2781,7 @@ int init_manager(void)
 		ast_manager_register2("GetConfig", EVENT_FLAG_CONFIG, action_getconfig, "Retrieve configuration", mandescr_getconfig);
 		ast_manager_register2("UpdateConfig", EVENT_FLAG_CONFIG, action_updateconfig, "Update basic configuration", mandescr_updateconfig);
 		ast_manager_register2("Redirect", EVENT_FLAG_CALL, action_redirect, "Redirect (transfer) a call", mandescr_redirect );
+		ast_manager_register2("Atxfer", EVENT_FLAG_CALL, action_atxfer, "Attended transfer", mandescr_atxfer );
 		ast_manager_register2("Originate", EVENT_FLAG_CALL, action_originate, "Originate Call", mandescr_originate);
 		ast_manager_register2("Command", EVENT_FLAG_COMMAND, action_command, "Execute Asterisk CLI Command", mandescr_command );
 		ast_manager_register2("ExtensionState", EVENT_FLAG_CALL, action_extensionstate, "Check Extension Status", mandescr_extensionstate );
diff --git a/res/res_features.c b/res/res_features.c
index 6f8533c..5a0a28c 100644
--- a/res/res_features.c
+++ b/res/res_features.c
@@ -742,7 +742,7 @@ static int check_compat(struct ast_channel *c, struct ast_channel *newchan)
 	return 0;
 }
 
-static int builtin_atxfer(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense)
+static int full_atxfer(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, int sense, char *toExten)
 {
 	struct ast_channel *transferer;
 	struct ast_channel *transferee;
@@ -764,28 +764,32 @@ static int builtin_atxfer(struct ast_channel *chan, struct ast_channel *peer, st
 	/* Start autoservice on chan while we talk to the originator */
 	ast_autoservice_start(transferee);
 	ast_indicate(transferee, AST_CONTROL_HOLD);
-	
-	/* Transfer */
-	res = ast_stream_and_wait(transferer, "pbx-transfer", transferer->language, AST_DIGIT_ANY);
-	if (res < 0) {
-		finishup(transferee);
-		return res;
-	}
-	if (res > 0) /* If they've typed a digit already, handle it */
-		xferto[0] = (char) res;
 
-	/* this is specific of atxfer */
-	res = ast_app_dtget(transferer, transferer_real_context, xferto, sizeof(xferto), 100, transferdigittimeout);
-        if (res < 0) {  /* hangup, would be 0 for invalid and 1 for valid */
-                finishup(transferee);
-                return res;
-        }
-	if (res == 0) {
-		ast_log(LOG_WARNING, "Did not read data.\n");
-		finishup(transferee);
-		if (ast_stream_and_wait(transferer, "beeperr", transferer->language, ""))
-			return -1;
-		return FEATURE_RETURN_SUCCESS;
+	if (!ast_strlen_zero(toExten)) {
+		ast_copy_string(xferto, toExten, sizeof(xferto));
+	} else {
+		/* ask for extension to tranfer to on the transferer channel */
+		res = ast_stream_and_wait(transferer, "pbx-transfer", transferer->language, AST_DIGIT_ANY);
+		if (res < 0) {
+			finishup(transferee);
+			return res;
+		}
+		if (res > 0) /* If they've typed a digit already, handle it */
+			xferto[0] = (char) res;
+
+		/* this is specific of atxfer */
+		res = ast_app_dtget(transferer, transferer_real_context, xferto, sizeof(xferto), 100, transferdigittimeout);
+		if (res < 0) {  /* hangup, would be 0 for invalid and 1 for valid */
+			finishup(transferee);
+			return res;
+		}
+		if (res == 0) {
+			ast_log(LOG_WARNING, "Did not read data.\n");
+			finishup(transferee);
+			if (ast_stream_and_wait(transferer, "beeperr", transferer->language, ""))
+				return -1;
+			return FEATURE_RETURN_SUCCESS;
+		}
 	}
 
 	/* valid extension, res == 1 */
@@ -877,6 +881,10 @@ static int builtin_atxfer(struct ast_channel *chan, struct ast_channel *peer, st
 	return -1;	/* XXX meaning the channel is bridged ? */
 }
 
+static int builtin_atxfer(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense)
+{
+	return full_atxfer(chan, peer, config, sense, NULL);
+}
 
 /* add atxfer and automon as undefined so you can only use em if you configure them */
 #define FEATURES_COUNT (sizeof(builtin_features) / sizeof(builtin_features[0]))
@@ -1471,6 +1479,9 @@ int ast_bridge_call(struct ast_channel *chan,struct ast_channel *peer,struct ast
 		other = (who == chan) ? peer : chan;
 		if (f->frametype == AST_FRAME_CONTROL) {
 			switch (f->subclass) {
+			case AST_CONTROL_ATXFERCMD:
+				full_atxfer(chan, peer, config, FEATURE_SENSE_PEER, f->data);
+				break;
 			case AST_CONTROL_RINGING:
 			case AST_CONTROL_FLASH:
 			case -1:


-- 
	Paolo Ornati
	Linux 2.6.23-rc3-g1a8f4610-dirty on x86_64



More information about the asterisk-dev mailing list