diff --git a/apps/app_queue.c b/apps/app_queue.c
index b863f902b4448f75da95f334646117184fd6487c..ec04a2d525829e688b0e5ab18e430d7e5b6ffd95 100644
--- a/apps/app_queue.c
+++ b/apps/app_queue.c
@@ -135,6 +135,28 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 					<option name="d">
 						<para>data-quality (modem) call (minimum delay).</para>
 					</option>
+					<option name="F" argsep="^">
+						<argument name="context" required="false" />
+						<argument name="exten" required="false" />
+						<argument name="priority" required="true" />
+						<para>When the caller hangs up, transfer the <emphasis>called member</emphasis>
+						to the specified destination and <emphasis>start</emphasis> execution at that location.</para>
+						<note>
+							<para>Any channel variables you want the called channel to inherit from the caller channel must be
+							prefixed with one or two underbars ('_').</para>
+						</note>
+					</option>
+					<option name="F">
+						<para>When the caller hangs up, transfer the <emphasis>called member</emphasis> to the next priority of
+						the current extension and <emphasis>start</emphasis> execution at that location.</para>
+						<note>
+							<para>Any channel variables you want the called channel to inherit from the caller channel must be
+							prefixed with one or two underbars ('_').</para>
+						</note>
+						<note>
+							<para>Using this option from a Macro() or GoSub() might not make sense as there would be no return points.</para>
+						</note>
+					</option>
 					<option name="h">
 						<para>Allow <emphasis>callee</emphasis> to hang up by pressing <literal>*</literal>.</para>
 					</option>
@@ -848,6 +870,56 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 	</manager>
  ***/
 
+enum {
+	OPT_MARK_AS_ANSWERED =       (1 << 0),
+	OPT_GO_ON =                  (1 << 1),
+	OPT_DATA_QUALITY =           (1 << 2),
+	OPT_CALLEE_GO_ON =           (1 << 3),
+	OPT_CALLEE_HANGUP =          (1 << 4),
+	OPT_CALLER_HANGUP =          (1 << 5),
+	OPT_IGNORE_CALL_FW =         (1 << 6),
+	OPT_UPDATE_CONNECTED =       (1 << 7),
+	OPT_CALLEE_PARK =            (1 << 8),
+	OPT_CALLER_PARK =            (1 << 9),
+	OPT_NO_RETRY =               (1 << 10),
+	OPT_RINGING =                (1 << 11),
+	OPT_RING_WHEN_RINGING =      (1 << 12),
+	OPT_CALLEE_TRANSFER =        (1 << 13),
+	OPT_CALLER_TRANSFER =        (1 << 14),
+	OPT_CALLEE_AUTOMIXMON =      (1 << 15),
+	OPT_CALLER_AUTOMIXMON =      (1 << 16),
+	OPT_CALLEE_AUTOMON =         (1 << 17),
+	OPT_CALLER_AUTOMON =         (1 << 18),
+};
+
+enum {
+	OPT_ARG_CALLEE_GO_ON = 0,
+	/* note: this entry _MUST_ be the last one in the enum */
+	OPT_ARG_ARRAY_SIZE
+};
+
+AST_APP_OPTIONS(queue_exec_options, BEGIN_OPTIONS
+	AST_APP_OPTION('C', OPT_MARK_AS_ANSWERED),
+	AST_APP_OPTION('c', OPT_GO_ON),
+	AST_APP_OPTION('d', OPT_DATA_QUALITY),
+	AST_APP_OPTION_ARG('F', OPT_CALLEE_GO_ON, OPT_ARG_CALLEE_GO_ON),
+	AST_APP_OPTION('h', OPT_CALLEE_HANGUP),
+	AST_APP_OPTION('H', OPT_CALLER_HANGUP),
+	AST_APP_OPTION('i', OPT_IGNORE_CALL_FW),
+	AST_APP_OPTION('I', OPT_UPDATE_CONNECTED),
+	AST_APP_OPTION('k', OPT_CALLEE_PARK),
+	AST_APP_OPTION('K', OPT_CALLER_PARK),
+	AST_APP_OPTION('n', OPT_NO_RETRY),
+	AST_APP_OPTION('r', OPT_RINGING),
+	AST_APP_OPTION('R', OPT_RING_WHEN_RINGING),
+	AST_APP_OPTION('t', OPT_CALLEE_TRANSFER),
+	AST_APP_OPTION('T', OPT_CALLER_TRANSFER),
+	AST_APP_OPTION('x', OPT_CALLEE_AUTOMIXMON),
+	AST_APP_OPTION('X', OPT_CALLER_AUTOMIXMON),
+	AST_APP_OPTION('w', OPT_CALLEE_AUTOMON),
+	AST_APP_OPTION('W', OPT_CALLER_AUTOMON),
+END_OPTIONS);
+
 enum {
 	QUEUE_STRATEGY_RINGALL = 0,
 	QUEUE_STRATEGY_LEASTRECENT,
@@ -1233,6 +1305,21 @@ static void set_queue_result(struct ast_channel *chan, enum queue_result res)
 	}
 }
 
+/*!
+ * \internal
+ * \brief Converts delimited '^' characters in a target priority/extension/context string
+ *  to commas so that they can be used with ast_parseable_goto.
+ * \param s string that '^' characters are being replaced in.
+ */
+static void replace_macro_delimiter(char *s)
+{
+	for (; *s; s++) {
+		if (*s == '^') {
+			*s = ',';
+		}
+	}
+}
+
 static const char *int2strat(int strategy)
 {
 	int x;
@@ -4413,7 +4500,9 @@ static void end_bridge_callback(void *data)
 	}
 }
 
-/*! \brief A large function which calls members, updates statistics, and bridges the caller and a member
+/*!
+ * \internal
+ * \brief A large function which calls members, updates statistics, and bridges the caller and a member
  *
  * Here is the process of this function
  * 1. Process any options passed to the Queue() application. Options here mean the third argument to Queue()
@@ -4430,7 +4519,8 @@ static void end_bridge_callback(void *data)
  * 9. Do any post processing after the call has disconnected.
  *
  * \param[in] qe the queue_ent structure which corresponds to the caller attempting to reach members
- * \param[in] options the options passed as the third parameter to the Queue() application
+ * \param[in] opts the options passed as the third parameter to the Queue() application
+ * \param[in] opt_args the options passed as the third parameter to the Queue() application
  * \param[in] announceoverride filename to play to user when waiting 
  * \param[in] url the url passed as the fourth parameter to the Queue() application
  * \param[in,out] tries the number of times we have tried calling queue members
@@ -4440,7 +4530,7 @@ static void end_bridge_callback(void *data)
  * \param[in] gosub the gosub passed as the seventh parameter to the Queue() application
  * \param[in] ringing 1 if the 'r' option is set, otherwise 0
  */
-static int try_calling(struct queue_ent *qe, const char *options, char *announceoverride, const char *url, int *tries, int *noption, const char *agi, const char *macro, const char *gosub, int ringing)
+static int try_calling(struct queue_ent *qe, const struct ast_flags opts, char **opt_args, char *announceoverride, const char *url, int *tries, int *noption, const char *agi, const char *macro, const char *gosub, int ringing)
 {
 	struct member *cur;
 	struct callattempt *outgoing = NULL; /* the list of calls we are building */
@@ -4499,62 +4589,59 @@ static int try_calling(struct queue_ent *qe, const char *options, char *announce
 		res = 0;
 		goto out;
 	}
-		
-	for (; options && *options; options++)
-		switch (*options) {
-		case 't':
-			ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_REDIRECT);
-			break;
-		case 'T':
-			ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_REDIRECT);
-			break;
-		case 'w':
-			ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_AUTOMON);
-			break;
-		case 'W':
-			ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_AUTOMON);
-			break;
-		case 'c':
-			ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_NO_H_EXTEN);
-			break;
-		case 'd':
-			nondataquality = 0;
-			break;
-		case 'h':
-			ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_DISCONNECT);
-			break;
-		case 'H':
-			ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_DISCONNECT);
-			break;
-		case 'k':
-			ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_PARKCALL);
-			break;
-		case 'K':
-			ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_PARKCALL);
-			break;
-		case 'n':
-			if (qe->parent->strategy == QUEUE_STRATEGY_RRMEMORY || qe->parent->strategy == QUEUE_STRATEGY_LINEAR || qe->parent->strategy == QUEUE_STRATEGY_RRORDERED)
-				(*tries)++;
-			else
-				*tries = ao2_container_count(qe->parent->members);
-			*noption = 1;
-			break;
-		case 'i':
-			forwardsallowed = 0;
-			break;
-		case 'I':
-			update_connectedline = 0;
-			break;
-		case 'x':
-			ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_AUTOMIXMON);
-			break;
-		case 'X':
-			ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_AUTOMIXMON);
-			break;
-		case 'C':
-			qe->cancel_answered_elsewhere = 1;
-			break;
-		}
+
+	if (ast_test_flag(&opts, OPT_CALLEE_TRANSFER)) {
+		ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_REDIRECT);
+	}
+	if (ast_test_flag(&opts, OPT_CALLER_TRANSFER)) {
+		ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_REDIRECT);
+	}
+	if (ast_test_flag(&opts, OPT_CALLEE_AUTOMON)) {
+		ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_AUTOMON);
+	}
+	if (ast_test_flag(&opts, OPT_CALLER_AUTOMON)) {
+		ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_AUTOMON);
+	}
+	if (ast_test_flag(&opts, OPT_GO_ON)) {
+		ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_NO_H_EXTEN);
+	}
+	if (ast_test_flag(&opts, OPT_DATA_QUALITY)) {
+		nondataquality = 0;
+	}
+	if (ast_test_flag(&opts, OPT_CALLEE_HANGUP)) {
+		ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_DISCONNECT);
+	}
+	if (ast_test_flag(&opts, OPT_CALLER_HANGUP)) {
+		ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_DISCONNECT);
+	}
+	if (ast_test_flag(&opts, OPT_CALLEE_PARK)) {
+		ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_PARKCALL);
+	}
+	if (ast_test_flag(&opts, OPT_CALLER_PARK)) {
+		ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_PARKCALL);
+	}
+	if (ast_test_flag(&opts, OPT_NO_RETRY)) {
+		if (qe->parent->strategy == QUEUE_STRATEGY_RRMEMORY || qe->parent->strategy == QUEUE_STRATEGY_LINEAR || qe->parent->strategy == QUEUE_STRATEGY_RRORDERED)
+			(*tries)++;
+		else
+			*tries = ao2_container_count(qe->parent->members);
+		*noption = 1;
+	}
+	if (ast_test_flag(&opts, OPT_IGNORE_CALL_FW)) {
+		forwardsallowed = 0;
+	}
+	if (ast_test_flag(&opts, OPT_UPDATE_CONNECTED)) {
+		update_connectedline = 0;
+	}
+	if (ast_test_flag(&opts, OPT_CALLEE_AUTOMIXMON)) {
+		ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_AUTOMIXMON);
+	}
+	if (ast_test_flag(&opts, OPT_CALLER_AUTOMIXMON)) {
+		ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_AUTOMIXMON);
+	}
+	if (ast_test_flag(&opts, OPT_MARK_AS_ANSWERED)) {
+		qe->cancel_answered_elsewhere = 1;
+	}
 
 	/* if the calling channel has the ANSWERED_ELSEWHERE flag set, make sure this is inherited. 
 		(this is mainly to support chan_local)
@@ -4743,6 +4830,11 @@ static int try_calling(struct queue_ent *qe, const char *options, char *announce
 			}
 		}
 	} else { /* peer is valid */
+		/* These variables are used with the F option without arguments (callee jumps to next priority after queue) */
+		char *caller_context;
+		char *caller_extension;
+		int caller_priority;
+
 		/* Ah ha!  Someone answered within the desired timeframe.  Of course after this
 		   we will always return with -1 so that it is hung up properly after the
 		   conversation.  */
@@ -4870,12 +4962,17 @@ static int try_calling(struct queue_ent *qe, const char *options, char *announce
 		/* try to set queue variables if configured to do so*/
 		set_queue_variables(qe->parent, qe->chan);
 		set_queue_variables(qe->parent, peer);
-		
+
 		ast_channel_lock(qe->chan);
+		/* Copy next destination data for 'F' option (no args) */
+		caller_context = ast_strdupa(ast_channel_context(qe->chan));
+		caller_extension = ast_strdupa(ast_channel_exten(qe->chan));
+		caller_priority = ast_channel_priority(qe->chan);
 		if ((monitorfilename = pbx_builtin_getvar_helper(qe->chan, "MONITOR_FILENAME"))) {
 				monitorfilename = ast_strdupa(monitorfilename);
 		}
 		ast_channel_unlock(qe->chan);
+
 		/* Begin Monitoring */
 		if (qe->parent->monfmt && *qe->parent->monfmt) {
 			if (!qe->parent->montype) {
@@ -5220,7 +5317,30 @@ static int try_calling(struct queue_ent *qe, const char *options, char *announce
 		if (transfer_ds) {
 			ast_datastore_free(transfer_ds);
 		}
-		ast_hangup(peer);
+
+		if (!ast_check_hangup(peer) && ast_test_flag(&opts, OPT_CALLEE_GO_ON)) {
+			if (!ast_strlen_zero(opt_args[OPT_ARG_CALLEE_GO_ON])) {
+				int res;
+				replace_macro_delimiter(opt_args[OPT_ARG_CALLEE_GO_ON]);
+				res = ast_parseable_goto(peer, opt_args[OPT_ARG_CALLEE_GO_ON]);
+				if (res == AST_PBX_SUCCESS) {
+					ast_pbx_start(peer);
+				} else {
+					ast_hangup(peer);
+				}
+			} else { /* F() */
+				int res;
+				res = ast_goto_if_exists(peer, caller_context, caller_extension, caller_priority + 1);
+				if (res == AST_PBX_GOTO_FAILED) {
+					ast_hangup(peer);
+				} else {
+					ast_pbx_start(peer);
+				}
+			}
+		} else {
+			ast_hangup(peer);
+		}
+
 		res = bridge ? bridge : 1;
 		ao2_ref(member, -1);
 	}
@@ -6037,15 +6157,21 @@ static int queue_exec(struct ast_channel *chan, const char *data)
 	);
 	/* Our queue entry */
 	struct queue_ent qe = { 0 };
-	
+	struct ast_flags opts = { 0, };
+	char *opt_args[OPT_ARG_ARRAY_SIZE];
+
 	if (ast_strlen_zero(data)) {
 		ast_log(LOG_WARNING, "Queue requires an argument: queuename[,options[,URL[,announceoverride[,timeout[,agi[,macro[,gosub[,rule[,position]]]]]]]]]\n");
 		return -1;
 	}
-	
+
 	parse = ast_strdupa(data);
 	AST_STANDARD_APP_ARGS(args, parse);
 
+	if (!ast_strlen_zero(args.options)) {
+		ast_app_parse_options(queue_exec_options, &opts, opt_args, args.options);
+	}
+
 	/* Setup our queue entry */
 	qe.start = time(NULL);
 
@@ -6098,15 +6224,17 @@ static int queue_exec(struct ast_channel *chan, const char *data)
 	}
 	ast_channel_unlock(chan);
 
-	if (args.options && (strchr(args.options, 'r')))
+	if (ast_test_flag(&opts, OPT_RINGING)) {
 		ringing = 1;
+	}
 
-	if (ringing != 1 && args.options && (strchr(args.options, 'R'))) {
+	if (ringing != 1 && ast_test_flag(&opts, OPT_RING_WHEN_RINGING)) {
 		qe.ring_when_ringing = 1;
 	}
 
-	if (args.options && (strchr(args.options, 'c')))
+	if (ast_test_flag(&opts, OPT_GO_ON)) {
 		qcontinue = 1;
+	}
 
 	if (args.position) {
 		position = atoi(args.position);
@@ -6198,7 +6326,7 @@ check_turns:
 		}
 
 		/* Try calling all queue members for 'timeout' seconds */
-		res = try_calling(&qe, args.options, args.announceoverride, args.url, &tries, &noption, args.agi, args.macro, args.gosub, ringing);
+		res = try_calling(&qe, opts, opt_args, args.announceoverride, args.url, &tries, &noption, args.agi, args.macro, args.gosub, ringing);
 		if (res) {
 			goto stop;
 		}