Index: include/asterisk/frame.h
===================================================================
--- include/asterisk/frame.h	(revision 81262)
+++ include/asterisk/frame.h	(working copy)
@@ -289,6 +289,7 @@
 	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,	/*!< AMI triggered attended transfer */
 };
 
 #define AST_SMOOTHER_FLAG_G729		(1 << 0)
Index: main/manager.c
===================================================================
--- main/manager.c	(revision 81262)
+++ main/manager.c	(working copy)
@@ -1827,6 +1827,33 @@
 	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"
@@ -3278,6 +3305,7 @@
 		ast_manager_register2("GetConfigJSON", EVENT_FLAG_CONFIG, action_getconfigjson, "Retrieve configuration (JSON format)", mandescr_getconfigjson);
 		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 );
Index: res/res_features.c
===================================================================
--- res/res_features.c	(revision 81262)
+++ res/res_features.c	(working copy)
@@ -855,19 +855,18 @@
 }
 
 /*!
- * \brief Attended transfer
+ * \brief Attended transfer implementation
  * \param chan
  * \param peer
  * \param config
- * \param code
  * \param sense
- * \param data
- * Get extension to transfer to, if you cannot generate channel (or find extension) 
- * return to host channel. After called channel answered wait for hangup of transferer,
- * bridge call between transfer peer (taking them off hold) to attended transfer channel.
+ * \param toExten
+ * This is the actual implementation of attended transfer.
+ * "toExten" is the extension to transfer to, if not given it will be asked for
+ * on the transferer channel.
  * \return -1 means what failure/success both?
 */
-static int builtin_atxfer(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data)
+static int do_atxfer(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, int sense, const char *toExten)
 {
 	struct ast_channel *transferer;
 	struct ast_channel *transferee;
@@ -889,28 +888,32 @@
 	/* 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", 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", ""))
-			return -1;
-		return FEATURE_RETURN_SUCCESS;
+	if (!ast_strlen_zero(toExten)) {
+		ast_copy_string(xferto, toExten, sizeof(xferto));
+	} else {
+		/* Ask for extension to transfer to on the transferer channel */
+		res = ast_stream_and_wait(transferer, "pbx-transfer", 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", ""))
+				return -1;
+			return FEATURE_RETURN_SUCCESS;
+		}
 	}
 
 	/* valid extension, res == 1 */
@@ -1095,6 +1098,24 @@
 	}
 }
 
+/*!
+ * \brief Attended transfer ()
+ * \param chan
+ * \param peer
+ * \param config
+ * \param code
+ * \param sense
+ * \param data
+ * Get extension to transfer to, if you cannot generate channel (or find extension)
+ * return to host channel. After called channel answered wait for hangup of transferer,
+ * bridge call between transfer peer (taking them off hold) to attended transfer channel.
+ * \return -1 means what failure/success both?
+*/
+static int builtin_atxfer(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data)
+{
+	return do_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 ARRAY_LEN(builtin_features)
 
@@ -1870,6 +1891,8 @@
 		/* many things should be sent to the 'other' channel */
 		other = (who == chan) ? peer : chan;
 		if (f->frametype == AST_FRAME_CONTROL) {
+			int sense;
+
 			switch (f->subclass) {
 			case AST_CONTROL_RINGING:
 			case AST_CONTROL_FLASH:
@@ -1888,6 +1911,10 @@
 						f->datalen - sizeof(struct ast_option_header), 0);
 				}
 				break;
+			case AST_CONTROL_ATXFERCMD:
+				sense = (who == chan) ? FEATURE_SENSE_CHAN : FEATURE_SENSE_PEER;
+				do_atxfer(chan, peer, config, sense, f->data);
+				break;
 			}
 		} else if (f->frametype == AST_FRAME_DTMF_BEGIN) {
 			/* eat it */
