--- apps/app_queue.c	(revision 353454)
+++ apps/app_queue.c	(working copy)
@@ -849,6 +849,56 @@
  ***/
 
 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,
 	QUEUE_STRATEGY_FEWESTCALLS,
@@ -1233,6 +1283,13 @@
 	}
 }
 
+static void replace_macro_delimiter(char *s)
+{
+	for (; *s; s++)
+		if (*s == '^')
+			*s = ',';
+}
+
 static const char *int2strat(int strategy)
 {
 	int x;
@@ -4411,7 +4468,8 @@
  * 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
@@ -4421,7 +4479,7 @@
  * \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 */
@@ -4481,61 +4539,43 @@
 		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_callee), 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)
@@ -5201,7 +5241,15 @@
 		if (transfer_ds) {
 			ast_datastore_free(transfer_ds);
 		}
-		ast_hangup(peer);
+
+		if (!ast_check_hangup(peer) && ast_test_flag(&opts, OPT_CALLEE_GO_ON)) {
+			replace_macro_delimiter(opt_args[OPT_ARG_CALLEE_GO_ON]);
+			ast_parseable_goto(peer, opt_args[OPT_ARG_CALLEE_GO_ON]);
+			ast_pbx_start(peer);
+		} else {
+			ast_hangup(peer);
+		}
+
 		res = bridge ? bridge : 1;
 		ao2_ref(member, -1);
 	}
@@ -6018,6 +6066,8 @@
 	);
 	/* 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");
@@ -6027,6 +6077,9 @@
 	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);
 
@@ -6079,14 +6132,14 @@
 	}
 	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) {
@@ -6179,7 +6232,7 @@
 		}
 
 		/* 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;
 		}
