diff --git a/addons/app_mysql.c b/addons/app_mysql.c
index dda45243bfdb079d47e4c98d90f694e22bd1a625..2e1b4f4dcf7a053a1ce738f44e9140f11b312b7d 100644
--- a/addons/app_mysql.c
+++ b/addons/app_mysql.c
@@ -292,16 +292,17 @@ static int safe_scan_int(char **data, char *delim, int def)
 	return res;
 }
 
-static int aMYSQL_set(struct ast_channel *chan, char *data)
+static int aMYSQL_set(struct ast_channel *chan, const char *data)
 {
-	char *var, *tmp;
+	char *var, *tmp, *parse;
 	AST_DECLARE_APP_ARGS(args,
 		AST_APP_ARG(set);
 		AST_APP_ARG(variable);
 		AST_APP_ARG(value);
 	);
 
-	AST_NONSTANDARD_APP_ARGS(args, data, ' ');
+	parse = ast_strdupa(data);
+	AST_NONSTANDARD_APP_ARGS(args, parse, ' ');
 
 	if (args.argc == 3) {
 		var = ast_alloca(6 + strlen(args.variable) + 1);
@@ -317,7 +318,7 @@ static int aMYSQL_set(struct ast_channel *chan, char *data)
 }
 
 /* MYSQL operations */
-static int aMYSQL_connect(struct ast_channel *chan, char *data)
+static int aMYSQL_connect(struct ast_channel *chan, const char *data)
 {
 	AST_DECLARE_APP_ARGS(args,
 		AST_APP_ARG(connect);
@@ -333,8 +334,9 @@ static int aMYSQL_connect(struct ast_channel *chan, char *data)
 	const char *ctimeout;
 	unsigned int port = 0;
 	char *port_str;
-
-	AST_NONSTANDARD_APP_ARGS(args, data, ' ');
+	char *parse = ast_strdupa(data);
+ 
+	AST_NONSTANDARD_APP_ARGS(args, parse, ' ');
 
 	if (args.argc < 6) {
 		ast_log(LOG_WARNING, "MYSQL_connect is missing some arguments\n");
@@ -385,7 +387,7 @@ static int aMYSQL_connect(struct ast_channel *chan, char *data)
 	return 0;
 }
 
-static int aMYSQL_query(struct ast_channel *chan, char *data)
+static int aMYSQL_query(struct ast_channel *chan, const char *data)
 {
 	AST_DECLARE_APP_ARGS(args,
 		AST_APP_ARG(query);
@@ -397,8 +399,9 @@ static int aMYSQL_query(struct ast_channel *chan, char *data)
 	MYSQL_RES   *mysqlres;
 	int connid;
 	int mysql_query_res;
+	char *parse = ast_strdupa(data);
 
-	AST_NONSTANDARD_APP_ARGS(args, data, ' ');
+	AST_NONSTANDARD_APP_ARGS(args, parse, ' ');
 
 	if (args.argc != 4 || (connid = atoi(args.connid)) == 0) {
 		ast_log(LOG_WARNING, "missing some arguments\n");
@@ -426,7 +429,7 @@ static int aMYSQL_query(struct ast_channel *chan, char *data)
 	return -1;
 }
 
-static int aMYSQL_nextresult(struct ast_channel *chan, char *data)
+static int aMYSQL_nextresult(struct ast_channel *chan, const char *data)
 {
 	MYSQL       *mysql;
 	MYSQL_RES   *mysqlres;
@@ -436,8 +439,9 @@ static int aMYSQL_nextresult(struct ast_channel *chan, char *data)
 		AST_APP_ARG(connid);
 	);
 	int connid = -1;
+	char *parse = ast_strdupa(data);
 
-	AST_NONSTANDARD_APP_ARGS(args, data, ' ');
+	AST_NONSTANDARD_APP_ARGS(args, parse, ' ');
 	sscanf(args.connid, "%30d", &connid);
 
 	if (args.argc != 3 || connid <= 0) {
@@ -466,7 +470,7 @@ static int aMYSQL_nextresult(struct ast_channel *chan, char *data)
 }
 
 
-static int aMYSQL_fetch(struct ast_channel *chan, char *data)
+static int aMYSQL_fetch(struct ast_channel *chan, const char *data)
 {
 	MYSQL_RES *mysqlres;
 	MYSQL_ROW mysqlrow;
@@ -518,13 +522,14 @@ static int aMYSQL_fetch(struct ast_channel *chan, char *data)
 	return -1;
 }
 
-static int aMYSQL_clear(struct ast_channel *chan, char *data)
+static int aMYSQL_clear(struct ast_channel *chan, const char *data)
 {
 	MYSQL_RES *mysqlres;
 
 	int id;
-	strsep(&data, " "); /* eat the first token, we already know it :P */
-	id = safe_scan_int(&data, " \n", -1);
+	char *parse = ast_strdupa(data);
+	strsep(&parse, " "); /* eat the first token, we already know it :P */
+	id = safe_scan_int(&parse, " \n", -1);
 	if ((mysqlres = find_identifier(id, AST_MYSQL_ID_RESID)) == NULL) {
 		ast_log(LOG_WARNING, "Invalid result identifier %d passed in aMYSQL_clear\n", id);
 	} else {
@@ -535,13 +540,14 @@ static int aMYSQL_clear(struct ast_channel *chan, char *data)
 	return 0;
 }
 
-static int aMYSQL_disconnect(struct ast_channel *chan, char *data)
+static int aMYSQL_disconnect(struct ast_channel *chan, const char *data)
 {
 	MYSQL *mysql;
 	int id;
-	strsep(&data, " "); /* eat the first token, we already know it :P */
+	char *parse = ast_strdupa(data);
+	strsep(&parse, " "); /* eat the first token, we already know it :P */
 
-	id = safe_scan_int(&data, " \n", -1);
+	id = safe_scan_int(&parse, " \n", -1);
 	if ((mysql = find_identifier(id, AST_MYSQL_ID_CONNID)) == NULL) {
 		ast_log(LOG_WARNING, "Invalid connection identifier %d passed in aMYSQL_disconnect\n", id);
 	} else {
@@ -584,19 +590,19 @@ static int MYSQL_exec(struct ast_channel *chan, const char *data)
 	ast_mutex_lock(&_mysql_mutex);
 
 	if (strncasecmp("connect", data, strlen("connect")) == 0) {
-		result = aMYSQL_connect(chan, ast_strdupa(data));
+		result = aMYSQL_connect(chan, data);
 	} else if (strncasecmp("query", data, strlen("query")) == 0) {
-		result = aMYSQL_query(chan, ast_strdupa(data));
+		result = aMYSQL_query(chan, data);
 	} else if (strncasecmp("nextresult", data, strlen("nextresult")) == 0) {
-		result = aMYSQL_nextresult(chan, ast_strdupa(data));
+		result = aMYSQL_nextresult(chan, data);
 	} else if (strncasecmp("fetch", data, strlen("fetch")) == 0) {
-		result = aMYSQL_fetch(chan, ast_strdupa(data));
+		result = aMYSQL_fetch(chan, data);
 	} else if (strncasecmp("clear", data, strlen("clear")) == 0) {
-		result = aMYSQL_clear(chan, ast_strdupa(data));
+		result = aMYSQL_clear(chan, data);
 	} else if (strncasecmp("disconnect", data, strlen("disconnect")) == 0) {
-		result = aMYSQL_disconnect(chan, ast_strdupa(data));
+		result = aMYSQL_disconnect(chan, data);
 	} else if (strncasecmp("set", data, 3) == 0) {
-		result = aMYSQL_set(chan, ast_strdupa(data));
+		result = aMYSQL_set(chan, data);
 	} else {
 		ast_log(LOG_WARNING, "Unknown argument to MYSQL application : %s\n", data);
 		result = -1;
diff --git a/funcs/func_realtime.c b/funcs/func_realtime.c
index bd4b37dfe0ff7497d91b6a3f532f0f0818a62baf..886b5b4566c749035ae7a35cae3293e04285fdff 100644
--- a/funcs/func_realtime.c
+++ b/funcs/func_realtime.c
@@ -219,6 +219,13 @@ static int function_realtime_read(struct ast_channel *chan, const char *cmd, cha
 	/* add space for delimiters and final '\0' */
 	resultslen += n * (strlen(args.delim1) + strlen(args.delim2)) + 1;
 
+	if (resultslen > len) {
+		ast_log(LOG_WARNING, "Failed to fetch. Realtime data is too large: need %zu, have %zu.\n", resultslen, len);
+		return -1;
+	}
+
+	/* len is going to be sensible, so we don't need to check for stack
+	 * overflows here. */
 	out = ast_str_alloca(resultslen);
 	for (var = head; var; var = var->next)
 		ast_str_append(&out, 0, "%s%s%s%s", var->name, args.delim2, var->value, args.delim1);
@@ -439,6 +446,16 @@ static int function_realtime_readdestroy(struct ast_channel *chan, const char *c
 	/* add space for delimiters and final '\0' */
 	resultslen += n * (strlen(args.delim1) + strlen(args.delim2)) + 1;
 
+	if (resultslen > len) {
+		/* Unfortunately this does mean that we cannot destroy the row
+		 * anymore. But OTOH, we're not destroying someones data without
+		 * giving him the chance to look at it. */
+		ast_log(LOG_WARNING, "Failed to fetch/destroy. Realtime data is too large: need %zu, have %zu.\n", resultslen, len);
+		return -1;
+	}
+
+	/* len is going to be sensible, so we don't need to check for stack
+	 * overflows here. */
 	out = ast_str_alloca(resultslen);
 	for (var = head; var; var = var->next) {
 		ast_str_append(&out, 0, "%s%s%s%s", var->name, args.delim2, var->value, args.delim1);
diff --git a/include/asterisk/channel.h b/include/asterisk/channel.h
index 9b408660bc31d0df7336fbe7a7bdd351c7d39bf2..858657ab05f81bb7b83a4a795800921136786905 100644
--- a/include/asterisk/channel.h
+++ b/include/asterisk/channel.h
@@ -903,12 +903,19 @@ enum {
 	 *  some non-traditional dialplans (like AGI) to continue to function.
 	 */
 	AST_FLAG_DISABLE_WORKAROUNDS = (1 << 20),
-	/*! Disable device state event caching.  This allows allows channel
-	 * drivers to selectively prevent device state events from being cached
-	 * by certain channels such as anonymous calls which have no persistent
-	 * represenatation that can be tracked.
+	/*!
+	 * Disable device state event caching.  This allows channel
+	 * drivers to selectively prevent device state events from being
+	 * cached by certain channels such as anonymous calls which have
+	 * no persistent represenatation that can be tracked.
 	 */
 	AST_FLAG_DISABLE_DEVSTATE_CACHE = (1 << 21),
+	/*!
+	 * This flag indicates that a dual channel redirect is in
+	 * progress.  The bridge needs to wait until the flag is cleared
+	 * to continue.
+	 */
+	AST_FLAG_BRIDGE_DUAL_REDIRECT_WAIT = (1 << 22),
 };
 
 /*! \brief ast_bridge_config flags */
diff --git a/main/config.c b/main/config.c
index f56421ee042c36f8d60a65da12e122bab9a5ae7c..cf2b84c72bc11fefc48f9414aa5fe6d2ebaece95 100644
--- a/main/config.c
+++ b/main/config.c
@@ -1646,6 +1646,17 @@ static struct ast_config *config_text_file_load(const char *database, const char
 		while (!feof(f)) {
 			lineno++;
 			if (fgets(buf, sizeof(buf), f)) {
+				/* Skip lines that are too long */
+				if (strlen(buf) == sizeof(buf) - 1 && buf[sizeof(buf) - 1] != '\n') {
+					ast_log(LOG_WARNING, "Line %d too long, skipping. It begins with: %.32s...\n", lineno, buf);
+					while (fgets(buf, sizeof(buf), f)) {
+						if (strlen(buf) != sizeof(buf) - 1 || buf[sizeof(buf) - 1] == '\n') {
+							break;
+						}
+					}
+					continue;
+				}
+
 				if (ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS) && lline_buffer && ast_str_strlen(lline_buffer)) {
 					CB_ADD(&comment_buffer, ast_str_buffer(lline_buffer));       /* add the current lline buffer to the comment buffer */
 					ast_str_reset(lline_buffer);        /* erase the lline buffer */
diff --git a/main/features.c b/main/features.c
index 44f140e16c0777751e9821c5bd0eced0005dcb88..2f2716eb7c732ed36dd17060f8f51be087f88e2f 100644
--- a/main/features.c
+++ b/main/features.c
@@ -4772,6 +4772,11 @@ before_you_go:
 		silgen = NULL;
 	}
 
+	/* Wait for any dual redirect to complete. */
+	while (ast_test_flag(ast_channel_flags(chan), AST_FLAG_BRIDGE_DUAL_REDIRECT_WAIT)) {
+		sched_yield();
+	}
+
 	if (ast_test_flag(ast_channel_flags(chan), AST_FLAG_BRIDGE_HANGUP_DONT)) {
 		ast_clear_flag(ast_channel_flags(chan), AST_FLAG_BRIDGE_HANGUP_DONT); /* its job is done */
 		if (bridge_cdr) {
diff --git a/main/manager.c b/main/manager.c
index ba5beb42e8dd8bb7116bc09d0a4e3b421d03a491..99d03fbcf792a730def1d4702d35c6a452a4f650 100644
--- a/main/manager.c
+++ b/main/manager.c
@@ -3709,6 +3709,7 @@ static int action_sendtext(struct mansession *s, const struct message *m)
 /*! \brief  action_redirect: The redirect manager command */
 static int action_redirect(struct mansession *s, const struct message *m)
 {
+	char buf[256];
 	const char *name = astman_get_header(m, "Channel");
 	const char *name2 = astman_get_header(m, "ExtraChannel");
 	const char *exten = astman_get_header(m, "Exten");
@@ -3717,8 +3718,10 @@ static int action_redirect(struct mansession *s, const struct message *m)
 	const char *context2 = astman_get_header(m, "ExtraContext");
 	const char *priority = astman_get_header(m, "Priority");
 	const char *priority2 = astman_get_header(m, "ExtraPriority");
-	struct ast_channel *chan, *chan2 = NULL;
-	int pi, pi2 = 0;
+	struct ast_channel *chan;
+	struct ast_channel *chan2;
+	int pi = 0;
+	int pi2 = 0;
 	int res;
 
 	if (ast_strlen_zero(name)) {
@@ -3726,84 +3729,134 @@ static int action_redirect(struct mansession *s, const struct message *m)
 		return 0;
 	}
 
-	if (!ast_strlen_zero(priority) && (sscanf(priority, "%30d", &pi) != 1)) {
-		if ((pi = ast_findlabel_extension(NULL, context, exten, priority, NULL)) < 1) {
-			astman_send_error(s, m, "Invalid priority");
-			return 0;
-		}
+	if (ast_strlen_zero(context)) {
+		astman_send_error(s, m, "Context not specified");
+		return 0;
+	}
+	if (ast_strlen_zero(exten)) {
+		astman_send_error(s, m, "Exten not specified");
+		return 0;
+	}
+	if (ast_strlen_zero(priority)) {
+		astman_send_error(s, m, "Priority not specified");
+		return 0;
+	}
+	if (sscanf(priority, "%30d", &pi) != 1) {
+		pi = ast_findlabel_extension(NULL, context, exten, priority, NULL);
+	}
+	if (pi < 1) {
+		astman_send_error(s, m, "Priority is invalid");
+		return 0;
 	}
 
-	if (!ast_strlen_zero(priority2) && (sscanf(priority2, "%30d", &pi2) != 1)) {
-		if ((pi2 = ast_findlabel_extension(NULL, context2, exten2, priority2, NULL)) < 1) {
-			astman_send_error(s, m, "Invalid ExtraPriority");
+	if (!ast_strlen_zero(name2) && !ast_strlen_zero(context2)) {
+		/* We have an ExtraChannel and an ExtraContext */
+		if (ast_strlen_zero(exten2)) {
+			astman_send_error(s, m, "ExtraExten not specified");
+			return 0;
+		}
+		if (ast_strlen_zero(priority2)) {
+			astman_send_error(s, m, "ExtraPriority not specified");
+			return 0;
+		}
+		if (sscanf(priority2, "%30d", &pi2) != 1) {
+			pi2 = ast_findlabel_extension(NULL, context2, exten2, priority2, NULL);
+		}
+		if (pi2 < 1) {
+			astman_send_error(s, m, "ExtraPriority is invalid");
 			return 0;
 		}
 	}
 
-	if (!(chan = ast_channel_get_by_name(name))) {
-		char buf[256];
+	chan = ast_channel_get_by_name(name);
+	if (!chan) {
 		snprintf(buf, sizeof(buf), "Channel does not exist: %s", name);
 		astman_send_error(s, m, buf);
 		return 0;
 	}
-
 	if (ast_check_hangup_locked(chan)) {
 		astman_send_error(s, m, "Redirect failed, channel not up.");
 		chan = ast_channel_unref(chan);
 		return 0;
 	}
 
-	if (!ast_strlen_zero(name2)) {
-		chan2 = ast_channel_get_by_name(name2);
+	if (ast_strlen_zero(name2)) {
+		/* Single channel redirect in progress. */
+		if (ast_channel_pbx(chan)) {
+			ast_channel_lock(chan);
+			/* don't let the after-bridge code run the h-exten */
+			ast_set_flag(ast_channel_flags(chan), AST_FLAG_BRIDGE_HANGUP_DONT);
+			ast_channel_unlock(chan);
+		}
+		res = ast_async_goto(chan, context, exten, pi);
+		if (!res) {
+			astman_send_ack(s, m, "Redirect successful");
+		} else {
+			astman_send_error(s, m, "Redirect failed");
+		}
+		chan = ast_channel_unref(chan);
+		return 0;
 	}
 
-	if (chan2 && ast_check_hangup_locked(chan2)) {
-		astman_send_error(s, m, "Redirect failed, extra channel not up.");
+	chan2 = ast_channel_get_by_name(name2);
+	if (!chan2) {
+		snprintf(buf, sizeof(buf), "ExtraChannel does not exist: %s", name2);
+		astman_send_error(s, m, buf);
 		chan = ast_channel_unref(chan);
+		return 0;
+	}
+	if (ast_check_hangup_locked(chan2)) {
+		astman_send_error(s, m, "Redirect failed, extra channel not up.");
 		chan2 = ast_channel_unref(chan2);
+		chan = ast_channel_unref(chan);
 		return 0;
 	}
 
+	/* Dual channel redirect in progress. */
 	if (ast_channel_pbx(chan)) {
 		ast_channel_lock(chan);
-		ast_set_flag(ast_channel_flags(chan), AST_FLAG_BRIDGE_HANGUP_DONT); /* don't let the after-bridge code run the h-exten */
+		/* don't let the after-bridge code run the h-exten */
+		ast_set_flag(ast_channel_flags(chan), AST_FLAG_BRIDGE_HANGUP_DONT
+			| AST_FLAG_BRIDGE_DUAL_REDIRECT_WAIT);
 		ast_channel_unlock(chan);
 	}
-
+	if (ast_channel_pbx(chan2)) {
+		ast_channel_lock(chan2);
+		/* don't let the after-bridge code run the h-exten */
+		ast_set_flag(ast_channel_flags(chan2), AST_FLAG_BRIDGE_HANGUP_DONT
+			| AST_FLAG_BRIDGE_DUAL_REDIRECT_WAIT);
+		ast_channel_unlock(chan2);
+	}
 	res = ast_async_goto(chan, context, exten, pi);
 	if (!res) {
-		if (!ast_strlen_zero(name2)) {
-			if (chan2) {
-				if (ast_channel_pbx(chan2)) {
-					ast_channel_lock(chan2);
-					ast_set_flag(ast_channel_flags(chan2), AST_FLAG_BRIDGE_HANGUP_DONT); /* don't let the after-bridge code run the h-exten */
-					ast_channel_unlock(chan2);
-				}
-				if (!ast_strlen_zero(context2)) {
-					res = ast_async_goto(chan2, context2, exten2, pi2);
-				} else {
-					res = ast_async_goto(chan2, context, exten, pi);
-				}
-			} else {
-				res = -1;
-			}
-			if (!res) {
-				astman_send_ack(s, m, "Dual Redirect successful");
-			} else {
-				astman_send_error(s, m, "Secondary redirect failed");
-			}
+		if (!ast_strlen_zero(context2)) {
+			res = ast_async_goto(chan2, context2, exten2, pi2);
 		} else {
-			astman_send_ack(s, m, "Redirect successful");
+			res = ast_async_goto(chan2, context, exten, pi);
+		}
+		if (!res) {
+			astman_send_ack(s, m, "Dual Redirect successful");
+		} else {
+			astman_send_error(s, m, "Secondary redirect failed");
 		}
 	} else {
 		astman_send_error(s, m, "Redirect failed");
 	}
 
-	chan = ast_channel_unref(chan);
-	if (chan2) {
-		chan2 = ast_channel_unref(chan2);
+	/* Release the bridge wait. */
+	if (ast_channel_pbx(chan)) {
+		ast_channel_lock(chan);
+		ast_clear_flag(ast_channel_flags(chan), AST_FLAG_BRIDGE_DUAL_REDIRECT_WAIT);
+		ast_channel_unlock(chan);
+	}
+	if (ast_channel_pbx(chan2)) {
+		ast_channel_lock(chan2);
+		ast_clear_flag(ast_channel_flags(chan2), AST_FLAG_BRIDGE_DUAL_REDIRECT_WAIT);
+		ast_channel_unlock(chan2);
 	}
 
+	chan2 = ast_channel_unref(chan2);
+	chan = ast_channel_unref(chan);
 	return 0;
 }