diff --git a/res/res_features.c b/res/res_features.c
index 11ab6ebe3e326bbe06af9a1fe2a264d6785a29c4..d5a6048923b4d6cd667f4f451c9d19dbb80d4cf1 100644
--- a/res/res_features.c
+++ b/res/res_features.c
@@ -406,6 +406,39 @@ int ast_masq_park_call(struct ast_channel *rchan, struct ast_channel *peer, int
 #define FEATURE_SENSE_CHAN	(1 << 0)
 #define FEATURE_SENSE_PEER	(1 << 1)
 
+/*
+ * if the file name is non-empty, try to play it.
+ * Return 0 if success, -1 if error, digit if interrupted by a digit.
+ * If digits == "" then we can simply check for non-zero.
+ *
+ * XXX there are probably many replicas of this function in the source tree,
+ * that should be merged.
+ */
+static int stream_and_wait(struct ast_channel *chan, const char *file, const char *language, const char *digits)
+{
+	int res = 0;
+	if (!ast_strlen_zero(file)) {
+		res =  ast_streamfile(chan, file, language);
+		if (!res)
+			res = ast_waitstream(chan, digits);
+	}
+	return res;
+}
+ 
+/*
+ * set caller and callee according to the direction
+ */
+static void set_peers(struct ast_channel **caller, struct ast_channel **callee,
+	struct ast_channel *peer, struct ast_channel *chan, int sense)
+{
+	if (sense == FEATURE_SENSE_PEER) {
+		*caller = peer;
+		*callee = chan;
+	} else {
+		*callee = peer;
+		*caller = chan;
+	}
+}
 
 static int builtin_automonitor(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense)
 {
@@ -414,15 +447,6 @@ static int builtin_automonitor(struct ast_channel *chan, struct ast_channel *pee
 	size_t len;
 	struct ast_channel *caller_chan = NULL, *callee_chan = NULL;
 
-
-	if(sense == 2) {
-		caller_chan = peer;
-		callee_chan = chan;
-	} else {
-		callee_chan = peer;
-		caller_chan = chan;
-	}
-	
 	if (!monitor_ok) {
 		ast_log(LOG_ERROR,"Cannot record the call. The monitor application is disabled.\n");
 		return -1;
@@ -433,6 +457,9 @@ static int builtin_automonitor(struct ast_channel *chan, struct ast_channel *pee
 		ast_log(LOG_ERROR,"Cannot record the call. The monitor application is disabled.\n");
 		return -1;
 	}
+
+	set_peers(&caller_chan, &callee_chan, peer, chan, sense);
+
 	if (!ast_strlen_zero(courtesytone)) {
 		if (ast_autoservice_start(callee_chan))
 			return -1;
@@ -506,6 +533,28 @@ static int builtin_disconnect(struct ast_channel *chan, struct ast_channel *peer
 	return FEATURE_RETURN_HANGUP;
 }
 
+static int finishup(struct ast_channel *chan)
+{
+        int res;
+  
+        ast_moh_stop(chan);
+        res = ast_autoservice_stop(chan);
+        ast_indicate(chan, AST_CONTROL_UNHOLD);
+        return res;
+}
+
+static const char *real_ctx(struct ast_channel *transferer, struct ast_channel *transferee)
+{
+        const char *s = pbx_builtin_getvar_helper(transferee, "TRANSFER_CONTEXT");
+        if (ast_strlen_zero(s))
+                s = pbx_builtin_getvar_helper(transferer, "TRANSFER_CONTEXT");
+        if (ast_strlen_zero(s)) /* Use the non-macro context to transfer the call XXX ? */
+                s = transferer->macrocontext;
+        if (ast_strlen_zero(s))
+                s = transferer->context;
+        return s;  
+}
+
 static int builtin_blindtransfer(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense)
 {
 	struct ast_channel *transferer;
@@ -514,21 +563,8 @@ static int builtin_blindtransfer(struct ast_channel *chan, struct ast_channel *p
 	char newext[256];
 	int res;
 
-	if (sense == FEATURE_SENSE_PEER) {
-		transferer = peer;
-		transferee = chan;
-	} else {
-		transferer = chan;
-		transferee = peer;
-	}
-	if (!(transferer_real_context = pbx_builtin_getvar_helper(transferee, "TRANSFER_CONTEXT")) &&
-	   !(transferer_real_context = pbx_builtin_getvar_helper(transferer, "TRANSFER_CONTEXT"))) {
-		/* Use the non-macro context to transfer the call */
-		if (!ast_strlen_zero(transferer->macrocontext))
-			transferer_real_context = transferer->macrocontext;
-		else
-			transferer_real_context = transferer->context;
-	}
+	set_peers(&transferer, &transferee, peer, chan, sense);
+	transferer_real_context = real_ctx(transferer, transferee);
 	/* Start autoservice on chan while we talk
 	   to the originator */
 	ast_indicate(transferee, AST_CONTROL_HOLD);
@@ -642,21 +678,8 @@ static int builtin_atxfer(struct ast_channel *chan, struct ast_channel *peer, st
 	struct ast_bridge_thread_obj *tobj;
 
 	ast_log(LOG_DEBUG, "Executing Attended Transfer %s, %s (sense=%d) XXX\n", chan->name, peer->name, sense);
-	if (sense == FEATURE_SENSE_PEER) {
-		transferer = peer;
-		transferee = chan;
-	} else {
-		transferer = chan;
-		transferee = peer;
-	}
-	if (!(transferer_real_context=pbx_builtin_getvar_helper(transferee, "TRANSFER_CONTEXT")) &&
-	   !(transferer_real_context=pbx_builtin_getvar_helper(transferer, "TRANSFER_CONTEXT"))) {
-		/* Use the non-macro context to transfer the call */
-		if (!ast_strlen_zero(transferer->macrocontext))
-			transferer_real_context = transferer->macrocontext;
-		else
-			transferer_real_context = transferer->context;
-	}
+	set_peers(&transferer, &transferee, peer, chan, sense);
+        transferer_real_context = real_ctx(transferer, transferee);
 	/* Start autoservice on chan while we talk
 	   to the originator */
 	ast_indicate(transferee, AST_CONTROL_HOLD);
@@ -664,21 +687,13 @@ static int builtin_atxfer(struct ast_channel *chan, struct ast_channel *peer, st
 	ast_moh_start(transferee, NULL);
 	memset(xferto, 0, sizeof(xferto));
 	/* Transfer */
-	if ((res = ast_streamfile(transferer, "pbx-transfer", transferer->language))) {
-		ast_moh_stop(transferee);
-		ast_autoservice_stop(transferee);
-		ast_indicate(transferee, AST_CONTROL_UNHOLD);
-		return res;
-	}
-	if ((res=ast_waitstream(transferer, AST_DIGIT_ANY)) < 0) {
-		ast_moh_stop(transferee);
-		ast_autoservice_stop(transferee);
-		ast_indicate(transferee, AST_CONTROL_UNHOLD);
-		return res;
-	} else if(res > 0) {
-		/* If they've typed a digit already, handle it */
-		xferto[0] = (char) res;
-	}
+	res = stream_and_wait(transferer, "pbx-transfer", transferer->language, AST_DIGIT_ANY);
+       if (res < 0) {
+                finishup(transferee);
+                return res;
+        } else if (res > 0) /* If they've typed a digit already, handle it */
+                xferto[0] = (char) res;
+
 	if ((ast_app_dtget(transferer, transferer_real_context, xferto, sizeof(xferto), 100, transferdigittimeout))) {
 		cid_num = transferer->cid.cid_num;
 		cid_name = transferer->cid.cid_name;