diff options
Diffstat (limited to 'res/ael')
-rw-r--r-- | res/ael/pval.c | 79 |
1 files changed, 79 insertions, 0 deletions
diff --git a/res/ael/pval.c b/res/ael/pval.c index 6fe21b5ca..8dd1f7cf6 100644 --- a/res/ael/pval.c +++ b/res/ael/pval.c @@ -4423,6 +4423,20 @@ static void fix_gotos_in_extensions(struct ael_extension *exten) } } +static int context_used(struct ael_extension *exten_list, struct ast_context *context) +{ + struct ael_extension *exten; + /* Check the simple elements first */ + if (ast_walk_context_extensions(context, NULL) || ast_walk_context_includes(context, NULL) || ast_walk_context_ignorepats(context, NULL) || ast_walk_context_switches(context, NULL)) { + return 1; + } + for (exten = exten_list; exten; exten = exten->next_exten) { + if (exten->context == context) { + return 1; + } + } + return 0; +} int ast_compile_ael2(struct ast_context **local_contexts, struct ast_hashtab *local_table, struct pval *root) { @@ -4604,6 +4618,71 @@ int ast_compile_ael2(struct ast_context **local_contexts, struct ast_hashtab *lo } } + + /* Create default "h" bubble context */ + if (ast_custom_function_find("DIALPLAN_EXISTS") && ast_custom_function_find("STACK_PEEK")) { + int i; + const char *h_context = "ael-builtin-h-bubble"; + struct ael_priority *np; + struct { + int priority; + const char *app; + const char *arg; + } steps[] = { + /* Start high, to avoid conflict with existing h extensions */ + { 1, "Goto", "9991" }, + /* Save the context, because after the StackPop, it disappears */ + { 9991, "Set", "~~parentcxt~~=${STACK_PEEK(1,c,1)}" }, + /* If we're not in a Gosub frame, exit */ + { 9992, "GotoIf", "$[\"${~~parentcxt~~}\"=\"\"]?9996" }, + /* Check for an "h" extension in that context */ + { 9993, "GotoIf", "${DIALPLAN_EXISTS(${~~parentcxt~~},h,1)}?9994:9996" }, + /* Pop off the stack frame to prevent an infinite loop */ + { 9994, "StackPop", "" }, + /* Finally, go there. */ + { 9995, "Goto", "${~~parentcxt~~},h,1" }, + /* Just an empty priority for jumping out early */ + { 9996, "NoOp", "" } + }; + context = ast_context_find_or_create(local_contexts, local_table, h_context, registrar); + if (context_used(exten_list, context)) { + int found = 0; + while (!found) { + /* Pick a new context name that is not used. */ + char h_context_template[] = "/tmp/ael-builtin-h-bubble-XXXXXX"; + int fd = mkstemp(h_context_template); + unlink(h_context_template); + close(fd); + context = ast_context_find_or_create(local_contexts, local_table, h_context_template + 5, registrar); + found = !context_used(exten_list, context); + } + h_context = ast_get_context_name(context); + } + exten = new_exten(); + exten->context = context; + exten->name = strdup("h"); + + for (i = 0; i < ARRAY_LEN(steps); i++) { + np = new_prio(); + np->type = AEL_APPCALL; + np->priority_num = steps[i].priority; + np->app = strdup(steps[i].app); + np->appargs = strdup(steps[i].arg); + linkprio(exten, np, NULL); + } + attach_exten(&exten_list, exten); + + /* Include the default "h" bubble context in each macro context */ + for (exten = exten_list; exten; exten = exten->next_exten) { + /* All macros contain a "~~s~~" extension, and it's the first created. If + * we perchance get a non-macro context, it's no big deal; the logic is + * designed to exit out smoothly if not called from within a Gosub. */ + if (!strcmp(exten->name, "~~s~~")) { + ast_context_add_include2(exten->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... */ |