Index: tests/test_gosub.c
===================================================================
--- tests/test_gosub.c	(revision 358080)
+++ tests/test_gosub.c	(working copy)
@@ -51,12 +51,24 @@
 		const char *args;
 		const char *expected_value;
 	} testplan[] = {
+		{ NULL, "${STACK_PEEK(1,e,1)}", "" },         /* Stack is empty */
 		{ "Gosub", "tests_test_gosub_virtual_context,s,1" },
+		{ NULL, "${PRIORITY}", "1" },
 		{ NULL, "${EXTEN}", "s" },
+		{ NULL, "${STACK_PEEK(1,e,1)}", "" },         /* No extension originally */
 		{ "Gosub", "test,dne,1", (const char *) -1 }, /* This is the only invocation that should fail. */
+		{ NULL, "${PRIORITY}", "1" },
 		{ NULL, "${EXTEN}", "s" },
 		{ "Gosub", "tests_test_gosub_virtual_context,s,1(5,5,5,5,5)" },
+		{ NULL, "${PRIORITY}", "1" },
 		{ NULL, "$[0${ARG1} + 0${ARG5}]", "10" },
+		{ NULL, "${STACK_PEEK(1,e)}", "s" },
+		{ NULL, "${STACK_PEEK(1,c)}", "tests_test_gosub_virtual_context" },
+		{ NULL, "${STACK_PEEK(1,p)}", "1" },
+		{ NULL, "${STACK_PEEK(1,l)}", "tests_test_gosub_virtual_context,s,1" },
+		{ "StackPop", "" },
+		{ NULL, "${STACK_PEEK(1,e,1)}", "" },         /* Only 1 frame deep, my caller is top-level */
+		{ "Gosub", "tests_test_gosub_virtual_context,s,1(5,5,5,5,5)" },
 		{ "Gosub", "tests_test_gosub_virtual_context,s,1(4,4,4,4)" },
 		{ NULL, "$[0${ARG1} + 0${ARG5}]", "4" },
 		{ NULL, "$[0${ARG1} + 0${ARG4}]", "8" },
Index: apps/app_stack.c
===================================================================
--- apps/app_stack.c	(revision 358080)
+++ apps/app_stack.c	(working copy)
@@ -165,6 +165,22 @@
 			<ref type="application">Return</ref>
 		</see-also>
 	</function>
+	<function name="STACK_PEEK" language="en_US">
+		<synopsis>
+			View info about the location which called Gosub
+		</synopsis>
+		<syntax>
+			<parameter name="n" required="true" />
+			<parameter name="which" required="true" />
+			<parameter name="suppress" required="false" />
+		</syntax>
+		<description>
+			<para>Read the calling context, extension, priority, or label, by going up
+			<replaceable>n</replaceable> frames in the Gosub stack.  If
+			<replaceable>suppress</replaceable> is true, then if the number of available stack
+			frames is exceeded, then no error message will be printed.</para>
+		</description>
+	</function>
 	<agi name="gosub" language="en_US">
 		<synopsis>
 			Cause the channel to execute the specified dialplan subroutine.
@@ -576,6 +592,86 @@
 	.read = peek_read,
 };
 
+static int stackpeek_read(struct ast_channel *chan, const char *cmd, char *data, struct ast_str **str, ssize_t len)
+{
+	struct ast_datastore *stack_store;
+	AST_LIST_HEAD(, gosub_stack_frame) *oldlist;
+	struct gosub_stack_frame *frame;
+	int n;
+	AST_DECLARE_APP_ARGS(args,
+		AST_APP_ARG(n);
+		AST_APP_ARG(which);
+		AST_APP_ARG(suppress);
+	);
+
+	if (!chan) {
+		ast_log(LOG_ERROR, "STACK_PEEK must be called on an active channel\n");
+		return -1;
+	}
+
+	data = ast_strdupa(data);
+	AST_STANDARD_APP_ARGS(args, data);
+
+	n = atoi(args.n);
+	if (n <= 0) {
+		ast_log(LOG_ERROR, "STACK_PEEK must be called with a positive peek value\n");
+		return -1;
+	}
+
+	stack_store = ast_channel_datastore_find(chan, &stack_info, NULL);
+	if (!stack_store) {
+		if (!ast_true(args.suppress)) {
+			ast_log(LOG_ERROR, "STACK_PEEK called on a channel without a gosub stack\n");
+		}
+		return -1;
+	}
+
+	oldlist = stack_store->data;
+
+	AST_LIST_LOCK(oldlist);
+	AST_LIST_TRAVERSE(oldlist, frame, entries) {
+		if (--n == 0) {
+			break;
+		}
+	}
+
+	if (!frame) {
+		/* Too deep */
+		if (!ast_true(args.suppress)) {
+			ast_log(LOG_ERROR, "Stack peek of '%s' is more stack frames than I have\n", args.n);
+		}
+		return -1;
+	}
+
+	while (args.which[0] == ' ') { args.which++; }
+
+	switch (args.which[0]) {
+	case 'l': /* label */
+		ast_str_set(str, len, "%s,%s,%d", frame->context, frame->extension, frame->priority - 1);
+		break;
+	case 'c': /* context */
+		ast_str_set(str, len, "%s", frame->context);
+		break;
+	case 'e': /* extension */
+		ast_str_set(str, len, "%s", frame->extension);
+		break;
+	case 'p': /* priority */
+		ast_str_set(str, len, "%d", frame->priority - 1);
+		break;
+	default:
+		ast_log(LOG_ERROR, "Unknown argument '%s' to STACK_PEEK\n", args.which);
+	}
+
+	AST_LIST_UNLOCK(oldlist);
+
+	return 0;
+}
+
+static struct ast_custom_function stackpeek_function = {
+	.name = "STACK_PEEK",
+	.read2 = stackpeek_read,
+};
+
 static int handle_gosub(struct ast_channel *chan, AGI *agi, int argc, const char * const *argv)
 {
 	int old_priority, priority;
@@ -687,6 +783,7 @@
 	ast_unregister_application(app_gosub);
 	ast_custom_function_unregister(&local_function);
 	ast_custom_function_unregister(&peek_function);
+	ast_custom_function_unregister(&stackpeek_function);
 
 	return 0;
 }
@@ -701,12 +798,14 @@
 	ast_register_application_xml(app_gosub, gosub_exec);
 	ast_custom_function_register(&local_function);
 	ast_custom_function_register(&peek_function);
+	ast_custom_function_register(&stackpeek_function);
 
 	return 0;
 }
 
-AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Dialplan subroutines (Gosub, Return, etc)",
+AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT | AST_MODFLAG_LOAD_ORDER, "Dialplan subroutines (Gosub, Return, etc)",
 		.load = load_module,
 		.unload = unload_module,
+		.load_pri = AST_MODPRI_APP_DEPEND,
 		.nonoptreq = "res_agi",
 		);
Index: funcs/func_dialplan.c
===================================================================
--- funcs/func_dialplan.c	(revision 358080)
+++ funcs/func_dialplan.c	(working copy)
@@ -185,4 +185,8 @@
 	return res;
 }
 
-AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Dialplan Context/Extension/Priority Checking Functions");
+AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Dialplan Context/Extension/Priority Checking Functions",
+	.load = load_module,
+	.unload = unload_module,
+	.load_pri = AST_MODPRI_APP_DEPEND,
+	);
Index: res/ael/pval.c
===================================================================
--- res/ael/pval.c	(revision 358080)
+++ res/ael/pval.c	(working copy)
@@ -4604,6 +4604,30 @@
 			
 		}
 	}
+
+	/* Create default "h" bubble context */
+	if (ast_custom_function_find("DIALPLAN_EXISTS") && ast_custom_function_find("STACK_PEEK")) {
+		const char *h_context = "__ael_default_h_bubble";
+		struct ael_priority *np = new_prio();
+		np->type = AEL_APPCALL;
+		np->app = strdup("GotoIf");
+		np->appargs = strdup("${DIALPLAN_EXISTS(${STACK_PEEK(1,c,1)},h,1)}?${STACK_PEEK(1,c,1)},h,1");
+		context = ast_context_find_or_create(local_contexts, local_table, h_context, registrar);
+		exten = new_exten();
+		exten->context = context;
+		exten->name = strdup("h");
+		linkprio(exten, np, NULL);
+		set_priorities(exten);
+		attach_exten(&exten_list, exten);
+
+		/* Include the default "h" bubble context in each context */
+		for (context = *local_contexts; context; context = ast_walk_contexts(context)) {
+			if (strcmp(ast_get_context_name(context), h_context)) {
+				ast_context_add_include2(context, h_context, registrar);
+			}
+		}
+	}
+
 	/* moved these from being done after a macro or extension were processed,
 	   to after all processing is done, for the sake of fixing gotos to labels inside cases... */
 	/* I guess this would be considered 2nd pass of compiler now... */
Index: utils/ael_main.c
===================================================================
--- utils/ael_main.c	(revision 358080)
+++ utils/ael_main.c	(working copy)
@@ -425,6 +425,12 @@
 		printf("Executed ast_context_destroy();\n");
 }
 
+const char *ast_get_context_name(struct ast_context *con);
+const char *ast_get_context_name(struct ast_context *con)
+{
+	return con ? con->name : NULL;
+}
+
 void filter_leading_space_from_exprs(char *str)
 {
 	/*  Mainly for aesthetics */
Index: utils/conf2ael.c
===================================================================
--- utils/conf2ael.c	(revision 358080)
+++ utils/conf2ael.c	(working copy)
@@ -668,6 +668,12 @@
 	localized_merge_contexts_and_delete(extcontexts, exttable, registrar);
 }
 
+const char *ast_get_context_name(struct ast_context *con);
+const char *ast_get_context_name(struct ast_context *con)
+{
+	return con ? con->name : NULL;
+}
+
 struct ast_exten *pbx_find_extension(struct ast_channel *chan,
 									 struct ast_context *bypass,
 									 struct pbx_find_info *q,
