#include "asterisk.h"
#include <ctype.h>
#include <regex.h>
#include <sys/stat.h>
#include "asterisk/pbx.h"
#include "asterisk/config.h"
#include "asterisk/module.h"
#include "asterisk/logger.h"
#include "asterisk/cli.h"
#include "asterisk/app.h"
#include "asterisk/callerid.h"
#include "asterisk/hashtab.h"
#include "asterisk/ael_structs.h"
#include "asterisk/pval.h"
Go to the source code of this file.
Defines | |
#define | DEBUG_CONTEXTS (1 << 3) |
#define | DEBUG_MACROS (1 << 2) |
#define | DEBUG_READ (1 << 0) |
#define | DEBUG_TOKENS (1 << 1) |
Functions | |
static void | __reg_module (void) |
static void | __unreg_module (void) |
void | add_extensions (struct ael_extension *exten) |
static int | aelsub_exec (struct ast_channel *chan, const char *vdata) |
int | ast_compile_ael2 (struct ast_context **local_contexts, struct ast_hashtab *local_table, struct pval *root) |
void | ast_expr_clear_extra_error_info (void) |
void | ast_expr_register_extra_error_info (char *errmsg) |
int | check_app_args (pval *appcall, pval *arglist, struct argapp *app) |
void | check_pval (pval *item, struct argapp *apps, int in_globals) |
void | check_pval_item (pval *item, struct argapp *apps, int in_globals) |
void | check_switch_expr (pval *item, struct argapp *apps) |
void | destroy_extensions (struct ael_extension *exten) |
void | destroy_pval (pval *item) |
void | destroy_pval_item (pval *item) |
pval * | find_context (char *name) |
pval * | find_macro (char *name) |
static char * | handle_cli_ael_reload (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) |
static char * | handle_cli_ael_set_debug (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) |
int | is_empty (char *arg) |
int | is_float (char *arg) |
int | is_int (char *arg) |
static int | load_module (void) |
ael_extension * | new_exten (void) |
ael_priority * | new_prio (void) |
static int | pbx_load_module (void) |
static int | reload (void) |
void | set_priorities (struct ael_extension *exten) |
static int | unload_module (void) |
Variables | |
static struct ast_module_info | __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "Asterisk Extension Language Compiler" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "ac1f6a56484a8820659555499174e588" , .load = load_module, .unload = unload_module, .reload = reload, } |
static int | aeldebug = 0 |
static char * | aelsub = "AELSub" |
static struct ast_module_info * | ast_module_info = &__mod_info |
static struct ast_cli_entry | cli_ael [] |
static char * | config = "extensions.ael" |
static char * | registrar = "pbx_ael" |
Definition in file pbx_ael.c.
#define DEBUG_CONTEXTS (1 << 3) |
#define DEBUG_MACROS (1 << 2) |
#define DEBUG_READ (1 << 0) |
#define DEBUG_TOKENS (1 << 1) |
void add_extensions | ( | struct ael_extension * | exten | ) |
Definition at line 4252 of file pval.c.
References AEL_APPCALL, AEL_CONTROL1, AEL_FOR_CONTROL, AEL_IF_CONTROL, AEL_IFTIME_CONTROL, AEL_LABEL, AEL_RAND_CONTROL, AEL_RETURN, app, ael_priority::app, ael_priority::appargs, ast_add_extension2(), ast_free_ptr, ast_log(), AST_MAX_EXTENSION, pval::else_statements, exten, ael_priority::exten, ael_priority::goto_false, ael_priority::goto_true, last, LOG_WARNING, ael_extension::name, ael_priority::next, ael_priority::origin, pbx_substitute_variables_helper(), PRIORITY_HINT, ael_priority::priority_num, PV_IFTIME, PV_SWITCH, strdup, ael_priority::type, pval::type, and pval::u3.
04253 { 04254 struct ael_priority *pr; 04255 char *label=0; 04256 char realext[AST_MAX_EXTENSION]; 04257 if (!exten) { 04258 ast_log(LOG_WARNING, "This file is Empty!\n" ); 04259 return; 04260 } 04261 do { 04262 struct ael_priority *last = 0; 04263 04264 pbx_substitute_variables_helper(NULL, exten->name, realext, sizeof(realext) - 1); 04265 if (exten->hints) { 04266 if (ast_add_extension2(exten->context, 0 /*no replace*/, realext, PRIORITY_HINT, NULL, exten->cidmatch, 04267 exten->hints, NULL, ast_free_ptr, registrar)) { 04268 ast_log(LOG_WARNING, "Unable to add step at priority 'hint' of extension '%s'\n", 04269 exten->name); 04270 } 04271 } 04272 04273 for (pr=exten->plist; pr; pr=pr->next) { 04274 char app[2000]; 04275 char appargs[2000]; 04276 04277 /* before we can add the extension, we need to prep the app/appargs; 04278 the CONTROL types need to be done after the priority numbers are calculated. 04279 */ 04280 if (pr->type == AEL_LABEL) /* don't try to put labels in the dialplan! */ { 04281 last = pr; 04282 continue; 04283 } 04284 04285 if (pr->app) 04286 strcpy(app, pr->app); 04287 else 04288 app[0] = 0; 04289 if (pr->appargs ) 04290 strcpy(appargs, pr->appargs); 04291 else 04292 appargs[0] = 0; 04293 switch( pr->type ) { 04294 case AEL_APPCALL: 04295 /* easy case. Everything is all set up */ 04296 break; 04297 04298 case AEL_CONTROL1: /* FOR loop, WHILE loop, BREAK, CONTINUE, IF, IFTIME */ 04299 /* simple, unconditional goto. */ 04300 strcpy(app,"Goto"); 04301 if (pr->goto_true->origin && pr->goto_true->origin->type == PV_SWITCH ) { 04302 snprintf(appargs,sizeof(appargs),"%s,%d", pr->goto_true->exten->name, pr->goto_true->priority_num); 04303 } else if (pr->goto_true->origin && pr->goto_true->origin->type == PV_IFTIME && pr->goto_true->origin->u3.else_statements ) { 04304 snprintf(appargs,sizeof(appargs),"%d", pr->goto_true->priority_num+1); 04305 } else 04306 snprintf(appargs,sizeof(appargs),"%d", pr->goto_true->priority_num); 04307 break; 04308 04309 case AEL_FOR_CONTROL: /* WHILE loop test, FOR loop test */ 04310 strcpy(app,"GotoIf"); 04311 snprintf(appargs,sizeof(appargs),"%s?%d:%d", pr->appargs, pr->priority_num+1, pr->goto_false->priority_num); 04312 break; 04313 04314 case AEL_IF_CONTROL: 04315 strcpy(app,"GotoIf"); 04316 if (pr->origin->u3.else_statements ) 04317 snprintf(appargs,sizeof(appargs),"%s?%d:%d", pr->appargs, pr->priority_num+1, pr->goto_false->priority_num+1); 04318 else 04319 snprintf(appargs,sizeof(appargs),"%s?%d:%d", pr->appargs, pr->priority_num+1, pr->goto_false->priority_num); 04320 break; 04321 04322 case AEL_RAND_CONTROL: 04323 strcpy(app,"Random"); 04324 snprintf(appargs,sizeof(appargs),"%s:%d", pr->appargs, pr->goto_true->priority_num+1); 04325 break; 04326 04327 case AEL_IFTIME_CONTROL: 04328 strcpy(app,"GotoIfTime"); 04329 snprintf(appargs,sizeof(appargs),"%s?%d", pr->appargs, pr->priority_num+2); 04330 break; 04331 04332 case AEL_RETURN: 04333 strcpy(app,"Return"); 04334 appargs[0] = 0; 04335 break; 04336 04337 default: 04338 break; 04339 } 04340 if (last && last->type == AEL_LABEL ) { 04341 label = last->origin->u1.str; 04342 } 04343 else 04344 label = 0; 04345 04346 if (ast_add_extension2(exten->context, 0 /*no replace*/, realext, pr->priority_num, (label?label:NULL), exten->cidmatch, 04347 app, strdup(appargs), ast_free_ptr, registrar)) { 04348 ast_log(LOG_WARNING, "Unable to add step at priority '%d' of extension '%s'\n", pr->priority_num, 04349 exten->name); 04350 } 04351 last = pr; 04352 } 04353 exten = exten->next_exten; 04354 } while ( exten ); 04355 }
static int aelsub_exec | ( | struct ast_channel * | chan, | |
const char * | vdata | |||
) | [static] |
Definition at line 135 of file pbx_ael.c.
References args, AST_APP_ARG, AST_DECLARE_APP_ARGS, AST_STANDARD_RAW_ARGS, ast_strdupa, name, pbx_exec(), and pbx_findapp().
Referenced by load_module().
00136 { 00137 char buf[256], *data = ast_strdupa(vdata); 00138 struct ast_app *gosub = pbx_findapp("Gosub"); 00139 AST_DECLARE_APP_ARGS(args, 00140 AST_APP_ARG(name); 00141 AST_APP_ARG(args); 00142 ); 00143 00144 if (gosub) { 00145 AST_STANDARD_RAW_ARGS(args, data); 00146 snprintf(buf, sizeof(buf), "%s,~~s~~,1(%s)", args.name, args.args); 00147 return pbx_exec(chan, gosub, buf); 00148 } 00149 return -1; 00150 }
int ast_compile_ael2 | ( | struct ast_context ** | local_contexts, | |
struct ast_hashtab * | local_table, | |||
struct pval * | root | |||
) |
Definition at line 4452 of file pval.c.
References buf2, context, exten, pval::list, pval::next, pbx_builtin_setvar(), PV_GLOBALS, pval::str, pval::type, pval::u1, pval::u2, and pval::val.
04453 { 04454 pval *p,*p2; 04455 struct ast_context *context; 04456 char buf[2000]; 04457 struct ael_extension *exten; 04458 struct ael_extension *exten_list = 0; 04459 04460 for (p=root; p; p=p->next ) { /* do the globals first, so they'll be there 04461 when we try to eval them */ 04462 switch (p->type) { 04463 case PV_GLOBALS: 04464 /* just VARDEC elements */ 04465 for (p2=p->u1.list; p2; p2=p2->next) { 04466 char buf2[2000]; 04467 snprintf(buf2,sizeof(buf2),"%s=%s", p2->u1.str, p2->u2.val); 04468 pbx_builtin_setvar(NULL, buf2); 04469 } 04470 break; 04471 default: 04472 break; 04473 } 04474 } 04475 04476 for (p=root; p; p=p->next ) { 04477 pval *lp; 04478 int argc; 04479 04480 switch (p->type) { 04481 case PV_MACRO: 04482 04483 context = ast_context_find_or_create(local_contexts, local_table, p->u1.str, registrar); 04484 04485 exten = new_exten(); 04486 exten->context = context; 04487 exten->name = strdup("~~s~~"); 04488 argc = 1; 04489 for (lp=p->u2.arglist; lp; lp=lp->next) { 04490 /* for each arg, set up a "Set" command */ 04491 struct ael_priority *np2 = new_prio(); 04492 np2->type = AEL_APPCALL; 04493 if (!ast_compat_app_set) { 04494 np2->app = strdup("MSet"); 04495 } else { 04496 np2->app = strdup("Set"); 04497 } 04498 snprintf(buf,sizeof(buf),"LOCAL(%s)=${ARG%d}", lp->u1.str, argc++); 04499 remove_spaces_before_equals(buf); 04500 np2->appargs = strdup(buf); 04501 linkprio(exten, np2, NULL); 04502 } 04503 04504 /* CONTAINS APPCALLS, CATCH, just like extensions... */ 04505 if (gen_prios(exten, p->u1.str, p->u3.macro_statements, 0, context)) { 04506 return -1; 04507 } 04508 if (exten->return_needed) { /* most likely, this will go away */ 04509 struct ael_priority *np2 = new_prio(); 04510 np2->type = AEL_APPCALL; 04511 np2->app = strdup("NoOp"); 04512 snprintf(buf,sizeof(buf),"End of Macro %s-%s",p->u1.str, exten->name); 04513 np2->appargs = strdup(buf); 04514 linkprio(exten, np2, NULL); 04515 exten-> return_target = np2; 04516 } 04517 04518 set_priorities(exten); 04519 attach_exten(&exten_list, exten); 04520 break; 04521 04522 case PV_GLOBALS: 04523 /* already done */ 04524 break; 04525 04526 case PV_CONTEXT: 04527 context = ast_context_find_or_create(local_contexts, local_table, p->u1.str, registrar); 04528 04529 /* contexts contain: ignorepat, includes, switches, eswitches, extensions, */ 04530 for (p2=p->u2.statements; p2; p2=p2->next) { 04531 pval *p3; 04532 char *s3; 04533 04534 switch (p2->type) { 04535 case PV_EXTENSION: 04536 exten = new_exten(); 04537 exten->name = strdup(p2->u1.str); 04538 exten->context = context; 04539 04540 if( (s3=strchr(exten->name, '/') ) != 0 ) 04541 { 04542 *s3 = 0; 04543 exten->cidmatch = s3+1; 04544 } 04545 04546 if ( p2->u3.hints ) 04547 exten->hints = strdup(p2->u3.hints); 04548 exten->regexten = p2->u4.regexten; 04549 if (gen_prios(exten, p->u1.str, p2->u2.statements, 0, context)) { 04550 return -1; 04551 } 04552 if (exten->return_needed) { /* returns don't generate a goto eoe (end of extension) any more, just a Return() app call) */ 04553 struct ael_priority *np2 = new_prio(); 04554 np2->type = AEL_APPCALL; 04555 np2->app = strdup("NoOp"); 04556 snprintf(buf,sizeof(buf),"End of Extension %s", exten->name); 04557 np2->appargs = strdup(buf); 04558 linkprio(exten, np2, NULL); 04559 exten-> return_target = np2; 04560 } 04561 /* is the last priority in the extension a label? Then add a trailing no-op */ 04562 if ( exten->plist_last && exten->plist_last->type == AEL_LABEL ) { 04563 struct ael_priority *np2 = new_prio(); 04564 np2->type = AEL_APPCALL; 04565 np2->app = strdup("NoOp"); 04566 snprintf(buf,sizeof(buf),"A NoOp to follow a trailing label %s", exten->plist_last->origin->u1.str); 04567 np2->appargs = strdup(buf); 04568 linkprio(exten, np2, NULL); 04569 } 04570 04571 set_priorities(exten); 04572 attach_exten(&exten_list, exten); 04573 break; 04574 04575 case PV_IGNOREPAT: 04576 ast_context_add_ignorepat2(context, p2->u1.str, registrar); 04577 break; 04578 04579 case PV_INCLUDES: 04580 for (p3 = p2->u1.list; p3 ;p3=p3->next) { 04581 if ( p3->u2.arglist ) { 04582 snprintf(buf,sizeof(buf), "%s,%s,%s,%s,%s", 04583 p3->u1.str, 04584 p3->u2.arglist->u1.str, 04585 p3->u2.arglist->next->u1.str, 04586 p3->u2.arglist->next->next->u1.str, 04587 p3->u2.arglist->next->next->next->u1.str); 04588 ast_context_add_include2(context, buf, registrar); 04589 } else 04590 ast_context_add_include2(context, p3->u1.str, registrar); 04591 } 04592 break; 04593 04594 case PV_SWITCHES: 04595 for (p3 = p2->u1.list; p3 ;p3=p3->next) { 04596 char *c = strchr(p3->u1.str, '/'); 04597 if (c) { 04598 *c = '\0'; 04599 c++; 04600 } else 04601 c = ""; 04602 04603 ast_context_add_switch2(context, p3->u1.str, c, 0, registrar); 04604 } 04605 break; 04606 04607 case PV_ESWITCHES: 04608 for (p3 = p2->u1.list; p3 ;p3=p3->next) { 04609 char *c = strchr(p3->u1.str, '/'); 04610 if (c) { 04611 *c = '\0'; 04612 c++; 04613 } else 04614 c = ""; 04615 04616 ast_context_add_switch2(context, p3->u1.str, c, 1, registrar); 04617 } 04618 break; 04619 default: 04620 break; 04621 } 04622 } 04623 04624 break; 04625 04626 default: 04627 /* huh? what? */ 04628 break; 04629 04630 } 04631 } 04632 04633 /* Create default "h" bubble context */ 04634 if (ast_custom_function_find("DIALPLAN_EXISTS") && ast_custom_function_find("STACK_PEEK")) { 04635 int i; 04636 const char *h_context = "ael-builtin-h-bubble"; 04637 struct ael_priority *np; 04638 struct { 04639 int priority; 04640 const char *app; 04641 const char *arg; 04642 } steps[] = { 04643 /* Start high, to avoid conflict with existing h extensions */ 04644 { 1, "Goto", "9991" }, 04645 /* Save the context, because after the StackPop, it disappears */ 04646 { 9991, "Set", "~~parentcxt~~=${STACK_PEEK(1,c,1)}" }, 04647 /* If we're not in a Gosub frame, exit */ 04648 { 9992, "GotoIf", "$[\"${~~parentcxt~~}\"=\"\"]?9996" }, 04649 /* Check for an "h" extension in that context */ 04650 { 9993, "GotoIf", "${DIALPLAN_EXISTS(${~~parentcxt~~},h,1)}?9994:9996" }, 04651 /* Pop off the stack frame to prevent an infinite loop */ 04652 { 9994, "StackPop", "" }, 04653 /* Finally, go there. */ 04654 { 9995, "Goto", "${~~parentcxt~~},h,1" }, 04655 /* Just an empty priority for jumping out early */ 04656 { 9996, "NoOp", "" } 04657 }; 04658 context = ast_context_find_or_create(local_contexts, local_table, h_context, registrar); 04659 if (context_used(exten_list, context)) { 04660 int found = 0; 04661 while (!found) { 04662 /* Pick a new context name that is not used. */ 04663 char h_context_template[] = "/tmp/ael-builtin-h-bubble-XXXXXX"; 04664 int fd = mkstemp(h_context_template); 04665 unlink(h_context_template); 04666 close(fd); 04667 context = ast_context_find_or_create(local_contexts, local_table, h_context_template + 5, registrar); 04668 found = !context_used(exten_list, context); 04669 } 04670 h_context = ast_get_context_name(context); 04671 } 04672 exten = new_exten(); 04673 exten->context = context; 04674 exten->name = strdup("h"); 04675 04676 for (i = 0; i < ARRAY_LEN(steps); i++) { 04677 np = new_prio(); 04678 np->type = AEL_APPCALL; 04679 np->priority_num = steps[i].priority; 04680 np->app = strdup(steps[i].app); 04681 np->appargs = strdup(steps[i].arg); 04682 linkprio(exten, np, NULL); 04683 } 04684 attach_exten(&exten_list, exten); 04685 04686 /* Include the default "h" bubble context in each macro context */ 04687 for (exten = exten_list; exten; exten = exten->next_exten) { 04688 /* All macros contain a "~~s~~" extension, and it's the first created. If 04689 * we perchance get a non-macro context, it's no big deal; the logic is 04690 * designed to exit out smoothly if not called from within a Gosub. */ 04691 if (!strcmp(exten->name, "~~s~~")) { 04692 ast_context_add_include2(exten->context, h_context, registrar); 04693 } 04694 } 04695 } 04696 04697 /* moved these from being done after a macro or extension were processed, 04698 to after all processing is done, for the sake of fixing gotos to labels inside cases... */ 04699 /* I guess this would be considered 2nd pass of compiler now... */ 04700 fix_gotos_in_extensions(exten_list); /* find and fix extension ref in gotos to labels that are in case statements */ 04701 add_extensions(exten_list); /* actually makes calls to create priorities in ast_contexts -- feeds dialplan to asterisk */ 04702 destroy_extensions(exten_list); /* all that remains is an empty husk, discard of it as is proper */ 04703 04704 return 0; 04705 }
void ast_expr_clear_extra_error_info | ( | void | ) |
void ast_expr_register_extra_error_info | ( | char * | errmsg | ) |
Definition at line 2138 of file pval.c.
References app, ast_log(), pval::endline, pval::filename, LOG_WARNING, pval::next, pval::startline, pval::str, and pval::u1.
02139 { 02140 #ifdef AAL_ARGCHECK 02141 struct argdesc *ad = app->args; 02142 pval *pa; 02143 int z; 02144 02145 for (pa = arglist; pa; pa=pa->next) { 02146 if (!ad) { 02147 ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: Extra argument %s not in application call to %s !\n", 02148 arglist->filename, arglist->startline, arglist->endline, pa->u1.str, app->name); 02149 warns++; 02150 return 1; 02151 } else { 02152 /* find the first entry in the ad list that will match */ 02153 do { 02154 if ( ad->dtype == ARGD_VARARG ) /* once we hit the VARARG, all bets are off. Discontinue the comparisons */ 02155 break; 02156 02157 z= option_matches( ad, pa, app); 02158 if (!z) { 02159 if ( !arglist ) 02160 arglist=appcall; 02161 02162 if (ad->type == ARGD_REQUIRED) { 02163 ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: Required argument %s not in application call to %s !\n", 02164 arglist->filename, arglist->startline, arglist->endline, ad->dtype==ARGD_OPTIONSET?"options":ad->name, app->name); 02165 warns++; 02166 return 1; 02167 } 02168 } else if (z && ad->dtype == ARGD_OPTIONSET) { 02169 option_matches_j( ad, pa, app); 02170 } 02171 ad = ad->next; 02172 } while (ad && !z); 02173 } 02174 } 02175 /* any app nodes left, that are not optional? */ 02176 for ( ; ad; ad=ad->next) { 02177 if (ad->type == ARGD_REQUIRED && ad->dtype != ARGD_VARARG) { 02178 if ( !arglist ) 02179 arglist=appcall; 02180 ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: Required argument %s not in application call to %s !\n", 02181 arglist->filename, arglist->startline, arglist->endline, ad->dtype==ARGD_OPTIONSET?"options":ad->name, app->name); 02182 warns++; 02183 return 1; 02184 } 02185 } 02186 return 0; 02187 #else 02188 return 0; 02189 #endif 02190 }
Definition at line 2873 of file pval.c.
References check_pval_item(), and pval::next.
02874 { 02875 pval *i; 02876 02877 /* checks to do: 02878 1. Do goto's point to actual labels? 02879 2. Do macro calls reference a macro? 02880 3. Does the number of macro args match the definition? 02881 4. Is a macro call missing its & at the front? 02882 5. Application calls-- we could check syntax for existing applications, 02883 but I need some some sort of universal description bnf for a general 02884 sort of method for checking arguments, in number, maybe even type, at least. 02885 Don't want to hand code checks for hundreds of applications. 02886 */ 02887 02888 for (i=item; i; i=i->next) { 02889 check_pval_item(i,apps,in_globals); 02890 } 02891 }
Definition at line 2365 of file pval.c.
References pval::abstract, app, pval::arglist, ast_expr(), ast_expr_clear_extra_error_info(), ast_expr_register_extra_error_info(), ast_log(), check_abstract_reference(), check_app_args(), check_break(), check_continue(), check_day(), check_dow(), check_expr2_input(), check_goto(), check_includes(), check_label(), check_macro_returns(), check_month(), check_pval(), check_switch_expr(), check_timerange(), current_context, current_extension, E_MATCH, pval::else_statements, pval::endcol, pval::endline, pval::filename, find_context(), find_macro(), find_pval_gotos(), pval::for_inc, pval::for_init, pval::for_statements, pval::for_test, free, pval::list, localized_pbx_load_module(), LOG_ERROR, LOG_WARNING, pval::macro_statements, pval::next, pbx_find_extension(), PV_APPLICATION_CALL, PV_BREAK, PV_CASE, PV_CATCH, PV_CONTEXT, PV_CONTINUE, PV_DEFAULT, PV_ESWITCHES, PV_EXTENSION, PV_FOR, PV_GLOBALS, PV_GOTO, PV_IF, PV_IFTIME, PV_IGNOREPAT, PV_INCLUDES, PV_LABEL, PV_LOCALVARDEC, PV_MACRO, PV_MACRO_CALL, PV_PATTERN, PV_RANDOM, PV_RETURN, PV_STATEMENTBLOCK, PV_SWITCH, PV_SWITCHES, PV_VARDEC, PV_WHILE, PV_WORD, pbx_find_info::stacklen, pval::startcol, pval::startline, pval::statements, pbx_find_info::status, STATUS_SUCCESS, pval::str, pval::type, pval::u1, pval::u2, pval::u3, pval::u4, and pval::val.
02366 { 02367 pval *lp; 02368 #ifdef AAL_ARGCHECK 02369 struct argapp *app, *found; 02370 #endif 02371 struct pval *macro_def; 02372 struct pval *app_def; 02373 02374 char errmsg[4096]; 02375 char *strp; 02376 02377 switch (item->type) { 02378 case PV_WORD: 02379 /* fields: item->u1.str == string associated with this (word). 02380 item->u2.arglist == pval list of 4 PV_WORD elements for time values (only in PV_INCLUDES) */ 02381 break; 02382 02383 case PV_MACRO: 02384 /* fields: item->u1.str == name of macro 02385 item->u2.arglist == pval list of PV_WORD arguments of macro, as given by user 02386 item->u2.arglist->u1.str == argument 02387 item->u2.arglist->next == next arg 02388 02389 item->u3.macro_statements == pval list of statements in macro body. 02390 */ 02391 in_abstract_context = 0; 02392 current_context = item; 02393 current_extension = 0; 02394 02395 check_macro_returns(item); 02396 02397 for (lp=item->u2.arglist; lp; lp=lp->next) { 02398 02399 } 02400 check_pval(item->u3.macro_statements, apps,in_globals); 02401 break; 02402 02403 case PV_CONTEXT: 02404 /* fields: item->u1.str == name of context 02405 item->u2.statements == pval list of statements in context body 02406 item->u3.abstract == int 1 if an abstract keyword were present 02407 */ 02408 current_context = item; 02409 current_extension = 0; 02410 if ( item->u3.abstract ) { 02411 in_abstract_context = 1; 02412 check_abstract_reference(item); 02413 } else 02414 in_abstract_context = 0; 02415 check_pval(item->u2.statements, apps,in_globals); 02416 break; 02417 02418 case PV_MACRO_CALL: 02419 /* fields: item->u1.str == name of macro to call 02420 item->u2.arglist == pval list of PV_WORD arguments of macro call, as given by user 02421 item->u2.arglist->u1.str == argument 02422 item->u2.arglist->next == next arg 02423 */ 02424 #ifdef STANDALONE 02425 /* if this is a standalone, we will need to make sure the 02426 localized load of extensions.conf is done */ 02427 if (!extensions_dot_conf_loaded) { 02428 localized_pbx_load_module(); 02429 extensions_dot_conf_loaded++; 02430 } 02431 #endif 02432 macro_def = find_macro(item->u1.str); 02433 if (!macro_def) { 02434 #ifdef STANDALONE 02435 struct pbx_find_info pfiq = {.stacklen = 0 }; 02436 struct pbx_find_info pfiq2 = {.stacklen = 0 }; 02437 02438 /* look for the macro in the extensions.conf world */ 02439 pbx_find_extension(NULL, NULL, &pfiq, item->u1.str, "s", 1, NULL, NULL, E_MATCH); 02440 02441 if (pfiq.status != STATUS_SUCCESS) { 02442 char namebuf2[256]; 02443 snprintf(namebuf2, 256, "macro-%s", item->u1.str); 02444 02445 /* look for the macro in the extensions.conf world */ 02446 pbx_find_extension(NULL, NULL, &pfiq2, namebuf2, "s", 1, NULL, NULL, E_MATCH); 02447 02448 if (pfiq2.status == STATUS_SUCCESS) { 02449 ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: macro call to non-existent %s! (macro-%s was found in the extensions.conf stuff, but we are using gosubs!)\n", 02450 item->filename, item->startline, item->endline, item->u1.str, item->u1.str); 02451 warns++; 02452 } else { 02453 ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: macro call to non-existent %s! (Not even in the extensions.conf stuff!)\n", 02454 item->filename, item->startline, item->endline, item->u1.str); 02455 warns++; 02456 } 02457 } 02458 #else 02459 ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: macro call to %s cannot be found in the AEL code!\n", 02460 item->filename, item->startline, item->endline, item->u1.str); 02461 warns++; 02462 02463 #endif 02464 #ifdef THIS_IS_1DOT4 02465 char namebuf2[256]; 02466 snprintf(namebuf2, 256, "macro-%s", item->u1.str); 02467 02468 /* look for the macro in the extensions.conf world */ 02469 pbx_find_extension(NULL, NULL, &pfiq, namebuf2, "s", 1, NULL, NULL, E_MATCH); 02470 02471 if (pfiq.status != STATUS_SUCCESS) { 02472 ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: macro call to %s was not found in the AEL, nor the extensions.conf !\n", 02473 item->filename, item->startline, item->endline, item->u1.str); 02474 warns++; 02475 } 02476 02477 #endif 02478 02479 } else if (macro_def->type != PV_MACRO) { 02480 ast_log(LOG_ERROR,"Error: file %s, line %d-%d: macro call to %s references a context, not a macro!\n", 02481 item->filename, item->startline, item->endline, item->u1.str); 02482 errs++; 02483 } else { 02484 /* macro_def is a MACRO, so do the args match in number? */ 02485 int hereargs = 0; 02486 int thereargs = 0; 02487 02488 for (lp=item->u2.arglist; lp; lp=lp->next) { 02489 hereargs++; 02490 } 02491 for (lp=macro_def->u2.arglist; lp; lp=lp->next) { 02492 thereargs++; 02493 } 02494 if (hereargs != thereargs ) { 02495 ast_log(LOG_ERROR, "Error: file %s, line %d-%d: The macro call to %s has %d arguments, but the macro definition has %d arguments\n", 02496 item->filename, item->startline, item->endline, item->u1.str, hereargs, thereargs); 02497 errs++; 02498 } 02499 } 02500 break; 02501 02502 case PV_APPLICATION_CALL: 02503 /* fields: item->u1.str == name of application to call 02504 item->u2.arglist == pval list of PV_WORD arguments of macro call, as given by user 02505 item->u2.arglist->u1.str == argument 02506 item->u2.arglist->next == next arg 02507 */ 02508 /* Need to check to see if the application is available! */ 02509 app_def = find_context(item->u1.str); 02510 if (app_def && app_def->type == PV_MACRO) { 02511 ast_log(LOG_ERROR,"Error: file %s, line %d-%d: application call to %s references an existing macro, but had no & preceding it!\n", 02512 item->filename, item->startline, item->endline, item->u1.str); 02513 errs++; 02514 } 02515 if (strcasecmp(item->u1.str,"GotoIf") == 0 02516 || strcasecmp(item->u1.str,"GotoIfTime") == 0 02517 || strcasecmp(item->u1.str,"while") == 0 02518 || strcasecmp(item->u1.str,"endwhile") == 0 02519 || strcasecmp(item->u1.str,"random") == 0 02520 || strcasecmp(item->u1.str,"gosub") == 0 02521 || strcasecmp(item->u1.str,"gosubif") == 0 02522 || strcasecmp(item->u1.str,"continuewhile") == 0 02523 || strcasecmp(item->u1.str,"endwhile") == 0 02524 || strcasecmp(item->u1.str,"execif") == 0 02525 || strcasecmp(item->u1.str,"execiftime") == 0 02526 || strcasecmp(item->u1.str,"exitwhile") == 0 02527 || strcasecmp(item->u1.str,"goto") == 0 02528 || strcasecmp(item->u1.str,"macro") == 0 02529 || strcasecmp(item->u1.str,"macroexclusive") == 0 02530 || strcasecmp(item->u1.str,"macroif") == 0 02531 || strcasecmp(item->u1.str,"stackpop") == 0 02532 || strcasecmp(item->u1.str,"execIf") == 0 ) { 02533 ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: application call to %s affects flow of control, and needs to be re-written using AEL if, while, goto, etc. keywords instead!\n", 02534 item->filename, item->startline, item->endline, item->u1.str); 02535 warns++; 02536 } 02537 if (strcasecmp(item->u1.str,"macroexit") == 0) { 02538 ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: I am converting the MacroExit call here to a return statement.\n", 02539 item->filename, item->startline, item->endline); 02540 item->type = PV_RETURN; 02541 free(item->u1.str); 02542 item->u1.str = 0; 02543 } 02544 02545 #ifdef AAL_ARGCHECK 02546 found = 0; 02547 for (app=apps; app; app=app->next) { 02548 if (strcasecmp(app->name, item->u1.str) == 0) { 02549 found =app; 02550 break; 02551 } 02552 } 02553 if (!found) { 02554 ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: application call to %s not listed in applist database!\n", 02555 item->filename, item->startline, item->endline, item->u1.str); 02556 warns++; 02557 } else 02558 check_app_args(item, item->u2.arglist, app); 02559 #endif 02560 break; 02561 02562 case PV_CASE: 02563 /* fields: item->u1.str == value of case 02564 item->u2.statements == pval list of statements under the case 02565 */ 02566 /* Make sure sequence of statements under case is terminated with goto, return, or break */ 02567 /* find the last statement */ 02568 check_pval(item->u2.statements, apps,in_globals); 02569 break; 02570 02571 case PV_PATTERN: 02572 /* fields: item->u1.str == value of case 02573 item->u2.statements == pval list of statements under the case 02574 */ 02575 /* Make sure sequence of statements under case is terminated with goto, return, or break */ 02576 /* find the last statement */ 02577 02578 check_pval(item->u2.statements, apps,in_globals); 02579 break; 02580 02581 case PV_DEFAULT: 02582 /* fields: 02583 item->u2.statements == pval list of statements under the case 02584 */ 02585 02586 check_pval(item->u2.statements, apps,in_globals); 02587 break; 02588 02589 case PV_CATCH: 02590 /* fields: item->u1.str == name of extension to catch 02591 item->u2.statements == pval list of statements in context body 02592 */ 02593 check_pval(item->u2.statements, apps,in_globals); 02594 break; 02595 02596 case PV_SWITCHES: 02597 /* fields: item->u1.list == pval list of PV_WORD elements, one per entry in the list 02598 */ 02599 check_pval(item->u1.list, apps,in_globals); 02600 break; 02601 02602 case PV_ESWITCHES: 02603 /* fields: item->u1.list == pval list of PV_WORD elements, one per entry in the list 02604 */ 02605 check_pval(item->u1.list, apps,in_globals); 02606 break; 02607 02608 case PV_INCLUDES: 02609 /* fields: item->u1.list == pval list of PV_WORD elements, one per entry in the list 02610 */ 02611 check_pval(item->u1.list, apps,in_globals); 02612 check_includes(item); 02613 for (lp=item->u1.list; lp; lp=lp->next){ 02614 char *incl_context = lp->u1.str; 02615 struct pval *that_context = find_context(incl_context); 02616 02617 if ( lp->u2.arglist ) { 02618 check_timerange(lp->u2.arglist); 02619 check_dow(lp->u2.arglist->next); 02620 check_day(lp->u2.arglist->next->next); 02621 check_month(lp->u2.arglist->next->next->next); 02622 } 02623 02624 if (that_context) { 02625 find_pval_gotos(that_context->u2.statements,0); 02626 02627 } 02628 } 02629 break; 02630 02631 case PV_STATEMENTBLOCK: 02632 /* fields: item->u1.list == pval list of statements in block, one per entry in the list 02633 */ 02634 check_pval(item->u1.list, apps,in_globals); 02635 break; 02636 02637 case PV_VARDEC: 02638 /* fields: item->u1.str == variable name 02639 item->u2.val == variable value to assign 02640 */ 02641 /* the RHS of a vardec is encapsulated in a $[] expr. Is it legal? */ 02642 if( !in_globals ) { /* don't check stuff inside the globals context; no wrapping in $[ ] there... */ 02643 snprintf(errmsg,sizeof(errmsg), "file %s, line %d, columns %d-%d, variable declaration expr '%s':", item->filename, item->startline, item->startcol, item->endcol, item->u2.val); 02644 ast_expr_register_extra_error_info(errmsg); 02645 ast_expr(item->u2.val, expr_output, sizeof(expr_output),NULL); 02646 ast_expr_clear_extra_error_info(); 02647 if ( strpbrk(item->u2.val,"~!-+<>=*/&^") && !strstr(item->u2.val,"${") ) { 02648 ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: expression %s has operators, but no variables. Interesting...\n", 02649 item->filename, item->startline, item->endline, item->u2.val); 02650 warns++; 02651 } 02652 check_expr2_input(item,item->u2.val); 02653 } 02654 break; 02655 02656 case PV_LOCALVARDEC: 02657 /* fields: item->u1.str == variable name 02658 item->u2.val == variable value to assign 02659 */ 02660 /* the RHS of a vardec is encapsulated in a $[] expr. Is it legal? */ 02661 snprintf(errmsg,sizeof(errmsg), "file %s, line %d, columns %d-%d, variable declaration expr '%s':", item->filename, item->startline, item->startcol, item->endcol, item->u2.val); 02662 ast_expr_register_extra_error_info(errmsg); 02663 ast_expr(item->u2.val, expr_output, sizeof(expr_output),NULL); 02664 ast_expr_clear_extra_error_info(); 02665 if ( strpbrk(item->u2.val,"~!-+<>=*/&^") && !strstr(item->u2.val,"${") ) { 02666 ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: expression %s has operators, but no variables. Interesting...\n", 02667 item->filename, item->startline, item->endline, item->u2.val); 02668 warns++; 02669 } 02670 check_expr2_input(item,item->u2.val); 02671 break; 02672 02673 case PV_GOTO: 02674 /* fields: item->u1.list == pval list of PV_WORD target names, up to 3, in order as given by user. 02675 item->u1.list->u1.str == where the data on a PV_WORD will always be. 02676 */ 02677 /* don't check goto's in abstract contexts */ 02678 if ( in_abstract_context ) 02679 break; 02680 02681 check_goto(item); 02682 break; 02683 02684 case PV_LABEL: 02685 /* fields: item->u1.str == label name 02686 */ 02687 if ( strspn(item->u1.str, "0123456789") == strlen(item->u1.str) ) { 02688 ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: label '%s' is numeric, this is bad practice!\n", 02689 item->filename, item->startline, item->endline, item->u1.str); 02690 warns++; 02691 } 02692 02693 check_label(item); 02694 break; 02695 02696 case PV_FOR: 02697 /* fields: item->u1.for_init == a string containing the initalizer 02698 item->u2.for_test == a string containing the loop test 02699 item->u3.for_inc == a string containing the loop increment 02700 02701 item->u4.for_statements == a pval list of statements in the for () 02702 */ 02703 snprintf(errmsg,sizeof(errmsg),"file %s, line %d, columns %d-%d, for test expr '%s':", item->filename, item->startline, item->startcol, item->endcol, item->u2.for_test); 02704 ast_expr_register_extra_error_info(errmsg); 02705 02706 strp = strchr(item->u1.for_init, '='); 02707 if (strp) { 02708 ast_expr(strp+1, expr_output, sizeof(expr_output),NULL); 02709 } 02710 ast_expr(item->u2.for_test, expr_output, sizeof(expr_output),NULL); 02711 strp = strchr(item->u3.for_inc, '='); 02712 if (strp) { 02713 ast_expr(strp+1, expr_output, sizeof(expr_output),NULL); 02714 } 02715 if ( strpbrk(item->u2.for_test,"~!-+<>=*/&^") && !strstr(item->u2.for_test,"${") ) { 02716 ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: expression %s has operators, but no variables. Interesting...\n", 02717 item->filename, item->startline, item->endline, item->u2.for_test); 02718 warns++; 02719 } 02720 if ( strpbrk(item->u3.for_inc,"~!-+<>=*/&^") && !strstr(item->u3.for_inc,"${") ) { 02721 ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: expression %s has operators, but no variables. Interesting...\n", 02722 item->filename, item->startline, item->endline, item->u3.for_inc); 02723 warns++; 02724 } 02725 check_expr2_input(item,item->u2.for_test); 02726 check_expr2_input(item,item->u3.for_inc); 02727 02728 ast_expr_clear_extra_error_info(); 02729 check_pval(item->u4.for_statements, apps,in_globals); 02730 break; 02731 02732 case PV_WHILE: 02733 /* fields: item->u1.str == the while conditional, as supplied by user 02734 02735 item->u2.statements == a pval list of statements in the while () 02736 */ 02737 snprintf(errmsg,sizeof(errmsg),"file %s, line %d, columns %d-%d, while expr '%s':", item->filename, item->startline, item->startcol, item->endcol, item->u1.str); 02738 ast_expr_register_extra_error_info(errmsg); 02739 ast_expr(item->u1.str, expr_output, sizeof(expr_output),NULL); 02740 ast_expr_clear_extra_error_info(); 02741 if ( strpbrk(item->u1.str,"~!-+<>=*/&^") && !strstr(item->u1.str,"${") ) { 02742 ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: expression %s has operators, but no variables. Interesting...\n", 02743 item->filename, item->startline, item->endline, item->u1.str); 02744 warns++; 02745 } 02746 check_expr2_input(item,item->u1.str); 02747 check_pval(item->u2.statements, apps,in_globals); 02748 break; 02749 02750 case PV_BREAK: 02751 /* fields: none 02752 */ 02753 check_break(item); 02754 break; 02755 02756 case PV_RETURN: 02757 /* fields: none 02758 */ 02759 break; 02760 02761 case PV_CONTINUE: 02762 /* fields: none 02763 */ 02764 check_continue(item); 02765 break; 02766 02767 case PV_RANDOM: 02768 /* fields: item->u1.str == the random number expression, as supplied by user 02769 02770 item->u2.statements == a pval list of statements in the if () 02771 item->u3.else_statements == a pval list of statements in the else 02772 (could be zero) 02773 */ 02774 snprintf(errmsg,sizeof(errmsg),"file %s, line %d, columns %d-%d, random expr '%s':", item->filename, item->startline, item->startcol, item->endcol, item->u1.str); 02775 ast_expr_register_extra_error_info(errmsg); 02776 ast_expr(item->u1.str, expr_output, sizeof(expr_output),NULL); 02777 ast_expr_clear_extra_error_info(); 02778 if ( strpbrk(item->u1.str,"~!-+<>=*/&^") && !strstr(item->u1.str,"${") ) { 02779 ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: random expression '%s' has operators, but no variables. Interesting...\n", 02780 item->filename, item->startline, item->endline, item->u1.str); 02781 warns++; 02782 } 02783 check_expr2_input(item,item->u1.str); 02784 check_pval(item->u2.statements, apps,in_globals); 02785 if (item->u3.else_statements) { 02786 check_pval(item->u3.else_statements, apps,in_globals); 02787 } 02788 break; 02789 02790 case PV_IFTIME: 02791 /* fields: item->u1.list == the if time values, 4 of them, each in PV_WORD, linked list 02792 02793 item->u2.statements == a pval list of statements in the if () 02794 item->u3.else_statements == a pval list of statements in the else 02795 (could be zero) 02796 */ 02797 if ( item->u2.arglist ) { 02798 check_timerange(item->u1.list); 02799 check_dow(item->u1.list->next); 02800 check_day(item->u1.list->next->next); 02801 check_month(item->u1.list->next->next->next); 02802 } 02803 02804 check_pval(item->u2.statements, apps,in_globals); 02805 if (item->u3.else_statements) { 02806 check_pval(item->u3.else_statements, apps,in_globals); 02807 } 02808 break; 02809 02810 case PV_IF: 02811 /* fields: item->u1.str == the if conditional, as supplied by user 02812 02813 item->u2.statements == a pval list of statements in the if () 02814 item->u3.else_statements == a pval list of statements in the else 02815 (could be zero) 02816 */ 02817 snprintf(errmsg,sizeof(errmsg),"file %s, line %d, columns %d-%d, if expr '%s':", item->filename, item->startline, item->startcol, item->endcol, item->u1.str); 02818 ast_expr_register_extra_error_info(errmsg); 02819 ast_expr(item->u1.str, expr_output, sizeof(expr_output),NULL); 02820 ast_expr_clear_extra_error_info(); 02821 if ( strpbrk(item->u1.str,"~!-+<>=*/&^") && !strstr(item->u1.str,"${") ) { 02822 ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: expression '%s' has operators, but no variables. Interesting...\n", 02823 item->filename, item->startline, item->endline, item->u1.str); 02824 warns++; 02825 } 02826 check_expr2_input(item,item->u1.str); 02827 check_pval(item->u2.statements, apps,in_globals); 02828 if (item->u3.else_statements) { 02829 check_pval(item->u3.else_statements, apps,in_globals); 02830 } 02831 break; 02832 02833 case PV_SWITCH: 02834 /* fields: item->u1.str == the switch expression 02835 02836 item->u2.statements == a pval list of statements in the switch, 02837 (will be case statements, most likely!) 02838 */ 02839 /* we can check the switch expression, see if it matches any of the app variables... 02840 if it does, then, are all the possible cases accounted for? */ 02841 check_switch_expr(item, apps); 02842 check_pval(item->u2.statements, apps,in_globals); 02843 break; 02844 02845 case PV_EXTENSION: 02846 /* fields: item->u1.str == the extension name, label, whatever it's called 02847 02848 item->u2.statements == a pval list of statements in the extension 02849 item->u3.hints == a char * hint argument 02850 item->u4.regexten == an int boolean. non-zero says that regexten was specified 02851 */ 02852 current_extension = item ; 02853 02854 check_pval(item->u2.statements, apps,in_globals); 02855 break; 02856 02857 case PV_IGNOREPAT: 02858 /* fields: item->u1.str == the ignorepat data 02859 */ 02860 break; 02861 02862 case PV_GLOBALS: 02863 /* fields: item->u1.statements == pval list of statements, usually vardecs 02864 */ 02865 in_abstract_context = 0; 02866 check_pval(item->u1.statements, apps, 1); 02867 break; 02868 default: 02869 break; 02870 } 02871 }
Definition at line 2192 of file pval.c.
References ast_strdupa, argapp::next, pval::str, and pval::u1.
02193 { 02194 #ifdef AAL_ARGCHECK 02195 /* get and clean the variable name */ 02196 char *buff1, *p; 02197 struct argapp *a,*a2; 02198 struct appsetvar *v,*v2; 02199 struct argchoice *c; 02200 pval *t; 02201 02202 p = item->u1.str; 02203 while (p && *p && (*p == ' ' || *p == '\t' || *p == '$' || *p == '{' ) ) 02204 p++; 02205 02206 buff1 = ast_strdupa(p); 02207 02208 while (strlen(buff1) > 0 && ( buff1[strlen(buff1)-1] == '}' || buff1[strlen(buff1)-1] == ' ' || buff1[strlen(buff1)-1] == '\t')) 02209 buff1[strlen(buff1)-1] = 0; 02210 /* buff1 now contains the variable name */ 02211 v = 0; 02212 for (a=apps; a; a=a->next) { 02213 for (v=a->setvars;v;v=v->next) { 02214 if (strcmp(v->name,buff1) == 0) { 02215 break; 02216 } 02217 } 02218 if ( v ) 02219 break; 02220 } 02221 if (v && v->vals) { 02222 /* we have a match, to a variable that has a set of determined values */ 02223 int def= 0; 02224 int pat = 0; 02225 int f1 = 0; 02226 02227 /* first of all, does this switch have a default case ? */ 02228 for (t=item->u2.statements; t; t=t->next) { 02229 if (t->type == PV_DEFAULT) { 02230 def =1; 02231 break; 02232 } 02233 if (t->type == PV_PATTERN) { 02234 pat++; 02235 } 02236 } 02237 if (def || pat) /* nothing to check. All cases accounted for! */ 02238 return; 02239 for (c=v->vals; c; c=c->next) { 02240 f1 = 0; 02241 for (t=item->u2.statements; t; t=t->next) { 02242 if (t->type == PV_CASE || t->type == PV_PATTERN) { 02243 if (!strcmp(t->u1.str,c->name)) { 02244 f1 = 1; 02245 break; 02246 } 02247 } 02248 } 02249 if (!f1) { 02250 ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: switch with expression(%s) does not handle the case of %s !\n", 02251 item->filename, item->startline, item->endline, item->u1.str, c->name); 02252 warns++; 02253 } 02254 } 02255 /* next, is there an app call in the current exten, that would set this var? */ 02256 f1 = 0; 02257 t = current_extension->u2.statements; 02258 if ( t && t->type == PV_STATEMENTBLOCK ) 02259 t = t->u1.statements; 02260 for (; t && t != item; t=t->next) { 02261 if (t->type == PV_APPLICATION_CALL) { 02262 /* find the application that matches the u1.str */ 02263 for (a2=apps; a2; a2=a2->next) { 02264 if (strcasecmp(a2->name, t->u1.str)==0) { 02265 for (v2=a2->setvars; v2; v2=v2->next) { 02266 if (strcmp(v2->name, buff1) == 0) { 02267 /* found an app that sets the var */ 02268 f1 = 1; 02269 break; 02270 } 02271 } 02272 } 02273 if (f1) 02274 break; 02275 } 02276 } 02277 if (f1) 02278 break; 02279 } 02280 02281 /* see if it sets the var */ 02282 if (!f1) { 02283 ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: Couldn't find an application call in this extension that sets the expression (%s) value!\n", 02284 item->filename, item->startline, item->endline, item->u1.str); 02285 warns++; 02286 } 02287 } 02288 #else 02289 pval *t,*tl=0,*p2; 02290 int def= 0; 02291 02292 /* first of all, does this switch have a default case ? */ 02293 for (t=item->u2.statements; t; t=t->next) { 02294 if (t->type == PV_DEFAULT) { 02295 def =1; 02296 break; 02297 } 02298 tl = t; 02299 } 02300 if (def) /* nothing to check. All cases accounted for! */ 02301 return; 02302 /* if no default, warn and insert a default case at the end */ 02303 p2 = tl->next = calloc(1, sizeof(struct pval)); 02304 02305 p2->type = PV_DEFAULT; 02306 p2->startline = tl->startline; 02307 p2->endline = tl->endline; 02308 p2->startcol = tl->startcol; 02309 p2->endcol = tl->endcol; 02310 p2->filename = strdup(tl->filename); 02311 ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: A default case was automatically added to the switch.\n", 02312 p2->filename, p2->startline, p2->endline); 02313 warns++; 02314 02315 #endif 02316 }
void destroy_extensions | ( | struct ael_extension * | exten | ) |
Definition at line 2986 of file pval.c.
References ael_priority::app, ael_priority::appargs, exten, free, ael_priority::goto_false, ael_priority::goto_true, ael_extension::hints, ael_extension::loop_break, ael_extension::loop_continue, ael_extension::name, ael_priority::next, ael_extension::next_exten, ael_priority::origin, ael_extension::plist, and ael_extension::plist_last.
02987 { 02988 struct ael_extension *ne, *nen; 02989 for (ne=exten; ne; ne=nen) { 02990 struct ael_priority *pe, *pen; 02991 02992 if (ne->name) 02993 free(ne->name); 02994 02995 /* cidmatch fields are allocated with name, and freed when 02996 the name field is freed. Don't do a free for this field, 02997 unless you LIKE to see a crash! */ 02998 02999 if (ne->hints) 03000 free(ne->hints); 03001 03002 for (pe=ne->plist; pe; pe=pen) { 03003 pen = pe->next; 03004 if (pe->app) 03005 free(pe->app); 03006 pe->app = 0; 03007 if (pe->appargs) 03008 free(pe->appargs); 03009 pe->appargs = 0; 03010 pe->origin = 0; 03011 pe->goto_true = 0; 03012 pe->goto_false = 0; 03013 free(pe); 03014 } 03015 nen = ne->next_exten; 03016 ne->next_exten = 0; 03017 ne->plist =0; 03018 ne->plist_last = 0; 03019 ne->next_exten = 0; 03020 ne->loop_break = 0; 03021 ne->loop_continue = 0; 03022 free(ne); 03023 } 03024 }
void destroy_pval | ( | pval * | item | ) |
Definition at line 4980 of file pval.c.
References destroy_pval_item(), and pval::next.
04981 { 04982 pval *i,*nxt; 04983 04984 for (i=item; i; i=nxt) { 04985 nxt = i->next; 04986 04987 destroy_pval_item(i); 04988 } 04989 }
void destroy_pval_item | ( | pval * | item | ) |
Definition at line 4712 of file pval.c.
References pval::arglist, ast_log(), destroy_pval(), pval::else_statements, pval::filename, pval::for_inc, pval::for_init, pval::for_statements, pval::for_test, free, pval::hints, pval::list, LOG_WARNING, pval::macro_statements, PV_APPLICATION_CALL, PV_BREAK, PV_CASE, PV_CATCH, PV_CONTEXT, PV_CONTINUE, PV_DEFAULT, PV_ESWITCHES, PV_EXTENSION, PV_FOR, PV_GLOBALS, PV_GOTO, PV_IF, PV_IFTIME, PV_IGNOREPAT, PV_INCLUDES, PV_LABEL, PV_LOCALVARDEC, PV_MACRO, PV_MACRO_CALL, PV_PATTERN, PV_RANDOM, PV_RETURN, PV_STATEMENTBLOCK, PV_SWITCH, PV_SWITCHES, PV_VARDEC, PV_WHILE, PV_WORD, pval::statements, pval::str, pval::type, pval::u1, pval::u2, pval::u3, pval::u4, and pval::val.
04713 { 04714 if (item == NULL) { 04715 ast_log(LOG_WARNING, "null item\n"); 04716 return; 04717 } 04718 04719 if (item->filename) 04720 free(item->filename); 04721 04722 switch (item->type) { 04723 case PV_WORD: 04724 /* fields: item->u1.str == string associated with this (word). */ 04725 if (item->u1.str ) 04726 free(item->u1.str); 04727 if ( item->u2.arglist ) 04728 destroy_pval(item->u2.arglist); 04729 break; 04730 04731 case PV_MACRO: 04732 /* fields: item->u1.str == name of macro 04733 item->u2.arglist == pval list of PV_WORD arguments of macro, as given by user 04734 item->u2.arglist->u1.str == argument 04735 item->u2.arglist->next == next arg 04736 04737 item->u3.macro_statements == pval list of statements in macro body. 04738 */ 04739 destroy_pval(item->u2.arglist); 04740 if (item->u1.str ) 04741 free(item->u1.str); 04742 destroy_pval(item->u3.macro_statements); 04743 break; 04744 04745 case PV_CONTEXT: 04746 /* fields: item->u1.str == name of context 04747 item->u2.statements == pval list of statements in context body 04748 item->u3.abstract == int 1 if an abstract keyword were present 04749 */ 04750 if (item->u1.str) 04751 free(item->u1.str); 04752 destroy_pval(item->u2.statements); 04753 break; 04754 04755 case PV_MACRO_CALL: 04756 /* fields: item->u1.str == name of macro to call 04757 item->u2.arglist == pval list of PV_WORD arguments of macro call, as given by user 04758 item->u2.arglist->u1.str == argument 04759 item->u2.arglist->next == next arg 04760 */ 04761 if (item->u1.str) 04762 free(item->u1.str); 04763 destroy_pval(item->u2.arglist); 04764 break; 04765 04766 case PV_APPLICATION_CALL: 04767 /* fields: item->u1.str == name of application to call 04768 item->u2.arglist == pval list of PV_WORD arguments of macro call, as given by user 04769 item->u2.arglist->u1.str == argument 04770 item->u2.arglist->next == next arg 04771 */ 04772 if (item->u1.str) 04773 free(item->u1.str); 04774 destroy_pval(item->u2.arglist); 04775 break; 04776 04777 case PV_CASE: 04778 /* fields: item->u1.str == value of case 04779 item->u2.statements == pval list of statements under the case 04780 */ 04781 if (item->u1.str) 04782 free(item->u1.str); 04783 destroy_pval(item->u2.statements); 04784 break; 04785 04786 case PV_PATTERN: 04787 /* fields: item->u1.str == value of case 04788 item->u2.statements == pval list of statements under the case 04789 */ 04790 if (item->u1.str) 04791 free(item->u1.str); 04792 destroy_pval(item->u2.statements); 04793 break; 04794 04795 case PV_DEFAULT: 04796 /* fields: 04797 item->u2.statements == pval list of statements under the case 04798 */ 04799 destroy_pval(item->u2.statements); 04800 break; 04801 04802 case PV_CATCH: 04803 /* fields: item->u1.str == name of extension to catch 04804 item->u2.statements == pval list of statements in context body 04805 */ 04806 if (item->u1.str) 04807 free(item->u1.str); 04808 destroy_pval(item->u2.statements); 04809 break; 04810 04811 case PV_SWITCHES: 04812 /* fields: item->u1.list == pval list of PV_WORD elements, one per entry in the list 04813 */ 04814 destroy_pval(item->u1.list); 04815 break; 04816 04817 case PV_ESWITCHES: 04818 /* fields: item->u1.list == pval list of PV_WORD elements, one per entry in the list 04819 */ 04820 destroy_pval(item->u1.list); 04821 break; 04822 04823 case PV_INCLUDES: 04824 /* fields: item->u1.list == pval list of PV_WORD elements, one per entry in the list 04825 item->u2.arglist == pval list of 4 PV_WORD elements for time values 04826 */ 04827 destroy_pval(item->u1.list); 04828 break; 04829 04830 case PV_STATEMENTBLOCK: 04831 /* fields: item->u1.list == pval list of statements in block, one per entry in the list 04832 */ 04833 destroy_pval(item->u1.list); 04834 break; 04835 04836 case PV_LOCALVARDEC: 04837 case PV_VARDEC: 04838 /* fields: item->u1.str == variable name 04839 item->u2.val == variable value to assign 04840 */ 04841 if (item->u1.str) 04842 free(item->u1.str); 04843 if (item->u2.val) 04844 free(item->u2.val); 04845 break; 04846 04847 case PV_GOTO: 04848 /* fields: item->u1.list == pval list of PV_WORD target names, up to 3, in order as given by user. 04849 item->u1.list->u1.str == where the data on a PV_WORD will always be. 04850 */ 04851 04852 destroy_pval(item->u1.list); 04853 break; 04854 04855 case PV_LABEL: 04856 /* fields: item->u1.str == label name 04857 */ 04858 if (item->u1.str) 04859 free(item->u1.str); 04860 break; 04861 04862 case PV_FOR: 04863 /* fields: item->u1.for_init == a string containing the initalizer 04864 item->u2.for_test == a string containing the loop test 04865 item->u3.for_inc == a string containing the loop increment 04866 04867 item->u4.for_statements == a pval list of statements in the for () 04868 */ 04869 if (item->u1.for_init) 04870 free(item->u1.for_init); 04871 if (item->u2.for_test) 04872 free(item->u2.for_test); 04873 if (item->u3.for_inc) 04874 free(item->u3.for_inc); 04875 destroy_pval(item->u4.for_statements); 04876 break; 04877 04878 case PV_WHILE: 04879 /* fields: item->u1.str == the while conditional, as supplied by user 04880 04881 item->u2.statements == a pval list of statements in the while () 04882 */ 04883 if (item->u1.str) 04884 free(item->u1.str); 04885 destroy_pval(item->u2.statements); 04886 break; 04887 04888 case PV_BREAK: 04889 /* fields: none 04890 */ 04891 break; 04892 04893 case PV_RETURN: 04894 /* fields: none 04895 */ 04896 break; 04897 04898 case PV_CONTINUE: 04899 /* fields: none 04900 */ 04901 break; 04902 04903 case PV_IFTIME: 04904 /* fields: item->u1.list == the 4 time values, in PV_WORD structs, linked list 04905 04906 item->u2.statements == a pval list of statements in the if () 04907 item->u3.else_statements == a pval list of statements in the else 04908 (could be zero) 04909 */ 04910 destroy_pval(item->u1.list); 04911 destroy_pval(item->u2.statements); 04912 if (item->u3.else_statements) { 04913 destroy_pval(item->u3.else_statements); 04914 } 04915 break; 04916 04917 case PV_RANDOM: 04918 /* fields: item->u1.str == the random percentage, as supplied by user 04919 04920 item->u2.statements == a pval list of statements in the true part () 04921 item->u3.else_statements == a pval list of statements in the else 04922 (could be zero) 04923 fall thru to If */ 04924 case PV_IF: 04925 /* fields: item->u1.str == the if conditional, as supplied by user 04926 04927 item->u2.statements == a pval list of statements in the if () 04928 item->u3.else_statements == a pval list of statements in the else 04929 (could be zero) 04930 */ 04931 if (item->u1.str) 04932 free(item->u1.str); 04933 destroy_pval(item->u2.statements); 04934 if (item->u3.else_statements) { 04935 destroy_pval(item->u3.else_statements); 04936 } 04937 break; 04938 04939 case PV_SWITCH: 04940 /* fields: item->u1.str == the switch expression 04941 04942 item->u2.statements == a pval list of statements in the switch, 04943 (will be case statements, most likely!) 04944 */ 04945 if (item->u1.str) 04946 free(item->u1.str); 04947 destroy_pval(item->u2.statements); 04948 break; 04949 04950 case PV_EXTENSION: 04951 /* fields: item->u1.str == the extension name, label, whatever it's called 04952 04953 item->u2.statements == a pval list of statements in the extension 04954 item->u3.hints == a char * hint argument 04955 item->u4.regexten == an int boolean. non-zero says that regexten was specified 04956 */ 04957 if (item->u1.str) 04958 free(item->u1.str); 04959 if (item->u3.hints) 04960 free(item->u3.hints); 04961 destroy_pval(item->u2.statements); 04962 break; 04963 04964 case PV_IGNOREPAT: 04965 /* fields: item->u1.str == the ignorepat data 04966 */ 04967 if (item->u1.str) 04968 free(item->u1.str); 04969 break; 04970 04971 case PV_GLOBALS: 04972 /* fields: item->u1.statements == pval list of statements, usually vardecs 04973 */ 04974 destroy_pval(item->u1.statements); 04975 break; 04976 } 04977 free(item); 04978 }
struct pval* find_context | ( | char * | name | ) |
Definition at line 1961 of file pval.c.
References current_db, and match_pval().
01962 { 01963 return_on_context_match = 1; 01964 count_labels = 0; 01965 match_context = name; 01966 match_exten = "*"; /* don't really need to set these, shouldn't be reached */ 01967 match_label = "*"; 01968 return match_pval(current_db); 01969 }
struct pval* find_macro | ( | char * | name | ) |
Definition at line 1951 of file pval.c.
References current_db, and match_pval().
01952 { 01953 return_on_context_match = 1; 01954 count_labels = 0; 01955 match_context = name; 01956 match_exten = "*"; /* don't really need to set these, shouldn't be reached */ 01957 match_label = "*"; 01958 return match_pval(current_db); 01959 }
static char* handle_cli_ael_reload | ( | struct ast_cli_entry * | e, | |
int | cmd, | |||
struct ast_cli_args * | a | |||
) | [static] |
Definition at line 241 of file pbx_ael.c.
References ast_cli_args::argc, CLI_FAILURE, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, pbx_load_module(), and ast_cli_entry::usage.
00242 { 00243 switch (cmd) { 00244 case CLI_INIT: 00245 e->command = "ael reload"; 00246 e->usage = 00247 "Usage: ael reload\n" 00248 " Reloads AEL configuration.\n"; 00249 return NULL; 00250 case CLI_GENERATE: 00251 return NULL; 00252 } 00253 00254 if (a->argc != 2) 00255 return CLI_SHOWUSAGE; 00256 00257 return (pbx_load_module() ? CLI_FAILURE : CLI_SUCCESS); 00258 }
static char* handle_cli_ael_set_debug | ( | struct ast_cli_entry * | e, | |
int | cmd, | |||
struct ast_cli_args * | a | |||
) | [static] |
Definition at line 207 of file pbx_ael.c.
References ast_cli_args::argc, ast_cli_entry::args, ast_cli_args::argv, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, DEBUG_CONTEXTS, DEBUG_MACROS, DEBUG_READ, DEBUG_TOKENS, and ast_cli_entry::usage.
00208 { 00209 switch (cmd) { 00210 case CLI_INIT: 00211 e->command = "ael set debug {read|tokens|macros|contexts|off}"; 00212 e->usage = 00213 "Usage: ael set debug {read|tokens|macros|contexts|off}\n" 00214 " Enable AEL read, token, macro, or context debugging,\n" 00215 " or disable all AEL debugging messages. Note: this\n" 00216 " currently does nothing.\n"; 00217 return NULL; 00218 case CLI_GENERATE: 00219 return NULL; 00220 } 00221 00222 if (a->argc != e->args) 00223 return CLI_SHOWUSAGE; 00224 00225 if (!strcasecmp(a->argv[3], "read")) 00226 aeldebug |= DEBUG_READ; 00227 else if (!strcasecmp(a->argv[3], "tokens")) 00228 aeldebug |= DEBUG_TOKENS; 00229 else if (!strcasecmp(a->argv[3], "macros")) 00230 aeldebug |= DEBUG_MACROS; 00231 else if (!strcasecmp(a->argv[3], "contexts")) 00232 aeldebug |= DEBUG_CONTEXTS; 00233 else if (!strcasecmp(a->argv[3], "off")) 00234 aeldebug = 0; 00235 else 00236 return CLI_SHOWUSAGE; 00237 00238 return CLI_SUCCESS; 00239 }
int is_empty | ( | char * | arg | ) |
int is_float | ( | char * | arg | ) |
int is_int | ( | char * | arg | ) |
static int load_module | ( | void | ) | [static] |
Definition at line 275 of file pbx_ael.c.
References aelsub_exec(), ARRAY_LEN, ast_cli_register_multiple(), ast_register_application_xml, cli_ael, and pbx_load_module().
00276 { 00277 ast_cli_register_multiple(cli_ael, ARRAY_LEN(cli_ael)); 00278 #ifndef STANDALONE 00279 ast_register_application_xml(aelsub, aelsub_exec); 00280 #endif 00281 return (pbx_load_module()); 00282 }
struct ael_extension* new_exten | ( | void | ) |
Definition at line 2938 of file pval.c.
References calloc.
02939 { 02940 struct ael_extension *x = (struct ael_extension *)calloc(sizeof(struct ael_extension),1); 02941 return x; 02942 }
struct ael_priority* new_prio | ( | void | ) |
Definition at line 2932 of file pval.c.
References calloc.
02933 { 02934 struct ael_priority *x = (struct ael_priority *)calloc(sizeof(struct ael_priority),1); 02935 return x; 02936 }
static int pbx_load_module | ( | void | ) | [static] |
Definition at line 155 of file pbx_ael.c.
References ael2_parse(), ael2_semantic_check(), ast_compile_ael2(), ast_config_AST_CONFIG_DIR, ast_context_verify_includes(), ast_hashtab_compare_contexts(), ast_hashtab_create(), ast_hashtab_hash_contexts(), ast_hashtab_newsize_java(), ast_hashtab_resize_java(), ast_log(), ast_merge_contexts_and_delete(), AST_MODULE_LOAD_DECLINE, AST_MODULE_LOAD_SUCCESS, ast_walk_contexts(), destroy_pval(), errs, local_contexts, local_table, LOG_ERROR, and LOG_NOTICE.
Referenced by handle_cli_ael_reload(), handle_cli_dialplan_reload(), load_module(), and reload().
00156 { 00157 int errs=0, sem_err=0, sem_warn=0, sem_note=0; 00158 char *rfilename; 00159 struct ast_context *local_contexts=NULL, *con; 00160 struct ast_hashtab *local_table=NULL; 00161 00162 struct pval *parse_tree; 00163 00164 ast_log(LOG_NOTICE, "Starting AEL load process.\n"); 00165 if (config[0] == '/') 00166 rfilename = (char *)config; 00167 else { 00168 rfilename = alloca(strlen(config) + strlen(ast_config_AST_CONFIG_DIR) + 2); 00169 sprintf(rfilename, "%s/%s", ast_config_AST_CONFIG_DIR, config); 00170 } 00171 if (access(rfilename,R_OK) != 0) { 00172 ast_log(LOG_NOTICE, "File %s not found; AEL declining load\n", rfilename); 00173 return AST_MODULE_LOAD_DECLINE; 00174 } 00175 00176 parse_tree = ael2_parse(rfilename, &errs); 00177 ast_log(LOG_NOTICE, "AEL load process: parsed config file name '%s'.\n", rfilename); 00178 ael2_semantic_check(parse_tree, &sem_err, &sem_warn, &sem_note); 00179 if (errs == 0 && sem_err == 0) { 00180 ast_log(LOG_NOTICE, "AEL load process: checked config file name '%s'.\n", rfilename); 00181 local_table = ast_hashtab_create(11, ast_hashtab_compare_contexts, ast_hashtab_resize_java, ast_hashtab_newsize_java, ast_hashtab_hash_contexts, 0); 00182 if (ast_compile_ael2(&local_contexts, local_table, parse_tree)) { 00183 ast_log(LOG_ERROR, "AEL compile failed! Aborting.\n"); 00184 destroy_pval(parse_tree); /* free up the memory */ 00185 return AST_MODULE_LOAD_DECLINE; 00186 } 00187 ast_log(LOG_NOTICE, "AEL load process: compiled config file name '%s'.\n", rfilename); 00188 00189 ast_merge_contexts_and_delete(&local_contexts, local_table, registrar); 00190 local_table = NULL; /* it's the dialplan global now */ 00191 local_contexts = NULL; 00192 ast_log(LOG_NOTICE, "AEL load process: merged config file name '%s'.\n", rfilename); 00193 for (con = ast_walk_contexts(NULL); con; con = ast_walk_contexts(con)) 00194 ast_context_verify_includes(con); 00195 ast_log(LOG_NOTICE, "AEL load process: verified config file name '%s'.\n", rfilename); 00196 } else { 00197 ast_log(LOG_ERROR, "Sorry, but %d syntax errors and %d semantic errors were detected. It doesn't make sense to compile.\n", errs, sem_err); 00198 destroy_pval(parse_tree); /* free up the memory */ 00199 return AST_MODULE_LOAD_DECLINE; 00200 } 00201 destroy_pval(parse_tree); /* free up the memory */ 00202 00203 return AST_MODULE_LOAD_SUCCESS; 00204 }
static int reload | ( | void | ) | [static] |
Definition at line 284 of file pbx_ael.c.
References pbx_load_module().
00285 { 00286 return pbx_load_module(); 00287 }
void set_priorities | ( | struct ael_extension * | exten | ) |
Definition at line 4226 of file pval.c.
References exten, ael_priority::next, ael_priority::origin, ael_priority::priority_num, PV_LABEL, and pval::type.
04227 { 04228 int i; 04229 struct ael_priority *pr; 04230 do { 04231 if (exten->is_switch) 04232 i = 10; 04233 else if (exten->regexten) 04234 i=2; 04235 else 04236 i=1; 04237 04238 for (pr=exten->plist; pr; pr=pr->next) { 04239 pr->priority_num = i; 04240 04241 if (!pr->origin || (pr->origin && pr->origin->type != PV_LABEL) ) /* Labels don't show up in the dialplan, 04242 but we want them to point to the right 04243 priority, which would be the next line 04244 after the label; */ 04245 i++; 04246 } 04247 04248 exten = exten->next_exten; 04249 } while ( exten ); 04250 }
static int unload_module | ( | void | ) | [static] |
Definition at line 265 of file pbx_ael.c.
References ARRAY_LEN, ast_cli_unregister_multiple(), ast_context_destroy(), ast_unregister_application(), and cli_ael.
00266 { 00267 ast_context_destroy(NULL, registrar); 00268 ast_cli_unregister_multiple(cli_ael, ARRAY_LEN(cli_ael)); 00269 #ifndef STANDALONE 00270 ast_unregister_application(aelsub); 00271 #endif 00272 return 0; 00273 }
struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "Asterisk Extension Language Compiler" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "ac1f6a56484a8820659555499174e588" , .load = load_module, .unload = unload_module, .reload = reload, } [static] |
struct ast_module_info* ast_module_info = &__mod_info [static] |
struct ast_cli_entry cli_ael[] [static] |
Initial value:
{ { .handler = handle_cli_ael_reload , .summary = "Reload AEL configuration" ,__VA_ARGS__ }, { .handler = handle_cli_ael_set_debug , .summary = "Enable AEL debugging flags" ,__VA_ARGS__ } }
Definition at line 260 of file pbx_ael.c.
Referenced by load_module(), and unload_module().