Asterisk - The Open Source Telephony Project GIT-master-27fb039
Loading...
Searching...
No Matches
Macros | Functions | Variables
pbx_ael.c File Reference

Compile symbolic Asterisk Extension Logic into Asterisk extensions, version 2. More...

#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"
Include dependency graph for pbx_ael.c:

Go to the source code of this file.

Macros

#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)
 
struct ast_moduleAST_MODULE_SELF_SYM (void)
 
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)
 
struct pvalfind_context (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)
 
struct ael_extensionnew_exten (void)
 
struct ael_prioritynew_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 = ASTERISK_GPL_KEY , .buildopt_sum = AST_BUILDOPT_SUM, .support_level = AST_MODULE_SUPPORT_EXTENDED, .load = load_module, .unload = unload_module, .reload = reload, .requires = "res_ael_share", }
 
static int aeldebug = 0
 
static char * aelsub = "AELSub"
 
static const struct ast_module_infoast_module_info = &__mod_info
 
static struct ast_cli_entry cli_ael []
 
static char * config = "extensions.ael"
 
static char * registrar = "pbx_ael"
 

Detailed Description

Compile symbolic Asterisk Extension Logic into Asterisk extensions, version 2.

Definition in file pbx_ael.c.

Macro Definition Documentation

◆ DEBUG_CONTEXTS

#define DEBUG_CONTEXTS   (1 << 3)

Definition at line 78 of file pbx_ael.c.

◆ DEBUG_MACROS

#define DEBUG_MACROS   (1 << 2)

Definition at line 77 of file pbx_ael.c.

◆ DEBUG_READ

#define DEBUG_READ   (1 << 0)

Definition at line 75 of file pbx_ael.c.

◆ DEBUG_TOKENS

#define DEBUG_TOKENS   (1 << 1)

Definition at line 76 of file pbx_ael.c.

Function Documentation

◆ __reg_module()

static void __reg_module ( void  )
static

Definition at line 312 of file pbx_ael.c.

315{
316 "AGENT",
317 "ARRAY",
318 "BASE64_DECODE",
319 "BASE64_ENCODE",
320 "CALLERID",
321 "CDR",
322 "CHANNEL",
323 "CHECKSIPDOMAIN",
324 "CHECK_MD5",
325 "CURL",
326 "CUT",
327 "DB",
328 "DB_EXISTS",
329 "DUNDILOOKUP",
330 "ENUMLOOKUP",
331 "ENV",
332 "EVAL",
333 "EXISTS",
334 "FIELDQTY",
335 "FILTER",
336 "GROUP",
337 "GROUP_COUNT",
338 "GROUP_LIST",
339 "GROUP_MATCH_COUNT",
340 "IAXPEER",
341 "IF",
342 "IFTIME",
343 "ISNULL",
344 "KEYPADHASH",
345 "LANGUAGE",
346 "LEN",
347 "MATH",
348 "MD5",
349 "MUSICCLASS",
350 "QUEUEAGENTCOUNT",
351 "QUEUE_MEMBER_COUNT",
352 "QUEUE_MEMBER_LIST",
353 "QUOTE",
354 "RAND",
355 "REGEX",
356 "SET",
357 "SHA1",
358 "SIPCHANINFO",
359 "SIPPEER",
360 "SIP_HEADER",
361 "SORT",
362 "STAT",
363 "STRFTIME",
364 "STRPTIME",
365 "TIMEOUT",
366 "TXTCIDNAME",
367 "URIDECODE",
368 "URIENCODE",
369 "VMCOUNT"
370};
371
372
373int ael_is_funcname(char *name)
374{
375 int s,t;
376 t = sizeof(ael_funclist)/sizeof(char*);
377 s = 0;
378 while ((s < t) && strcasecmp(name, ael_funclist[s]))
379 s++;
380 if ( s < t )
381 return 1;
382 else
383 return 0;
384}
385#endif
static const char name[]
Definition format_mp3.c:68

◆ __unreg_module()

static void __unreg_module ( void  )
static

Definition at line 312 of file pbx_ael.c.

◆ add_extensions()

void add_extensions ( struct ael_extension exten)

Definition at line 4213 of file pval.c.

4214{
4215 struct ael_priority *pr;
4216 char *label=0;
4217 char realext[AST_MAX_EXTENSION];
4218 if (!exten) {
4219 ast_log(LOG_WARNING, "This file is Empty!\n" );
4220 return;
4221 }
4222 do {
4223 struct ael_priority *last = 0;
4224
4225 pbx_substitute_variables_helper(NULL, exten->name, realext, sizeof(realext) - 1);
4226 if (exten->hints) {
4227 if (ast_add_extension2(exten->context, 0 /*no replace*/, realext, PRIORITY_HINT, NULL, exten->cidmatch,
4229 ast_log(LOG_WARNING, "Unable to add step at priority 'hint' of extension '%s'\n",
4230 exten->name);
4231 }
4232 }
4233
4234 for (pr=exten->plist; pr; pr=pr->next) {
4235 char app[2000];
4236 char appargs[2000];
4237
4238 /* before we can add the extension, we need to prep the app/appargs;
4239 the CONTROL types need to be done after the priority numbers are calculated.
4240 */
4241 if (pr->type == AEL_LABEL) /* don't try to put labels in the dialplan! */ {
4242 last = pr;
4243 continue;
4244 }
4245
4246 if (pr->app)
4247 strcpy(app, pr->app);
4248 else
4249 app[0] = 0;
4250 if (pr->appargs )
4251 strcpy(appargs, pr->appargs);
4252 else
4253 appargs[0] = 0;
4254 switch( pr->type ) {
4255 case AEL_APPCALL:
4256 /* easy case. Everything is all set up */
4257 break;
4258
4259 case AEL_CONTROL1: /* FOR loop, WHILE loop, BREAK, CONTINUE, IF, IFTIME */
4260 /* simple, unconditional goto. */
4261 strcpy(app,"Goto");
4262 if (pr->goto_true->origin && pr->goto_true->origin->type == PV_SWITCH ) {
4263 snprintf(appargs,sizeof(appargs),"%s,%d", pr->goto_true->exten->name, pr->goto_true->priority_num);
4264 } else if (pr->goto_true->origin && pr->goto_true->origin->type == PV_IFTIME && pr->goto_true->origin->u3.else_statements ) {
4265 snprintf(appargs,sizeof(appargs),"%d", pr->goto_true->priority_num+1);
4266 } else
4267 snprintf(appargs,sizeof(appargs),"%d", pr->goto_true->priority_num);
4268 break;
4269
4270 case AEL_FOR_CONTROL: /* WHILE loop test, FOR loop test */
4271 strcpy(app,"GotoIf");
4272 snprintf(appargs,sizeof(appargs),"%s?%d:%d", pr->appargs, pr->priority_num+1, pr->goto_false->priority_num);
4273 break;
4274
4275 case AEL_IF_CONTROL:
4276 strcpy(app,"GotoIf");
4277 if (pr->origin->u3.else_statements )
4278 snprintf(appargs,sizeof(appargs),"%s?%d:%d", pr->appargs, pr->priority_num+1, pr->goto_false->priority_num+1);
4279 else
4280 snprintf(appargs,sizeof(appargs),"%s?%d:%d", pr->appargs, pr->priority_num+1, pr->goto_false->priority_num);
4281 break;
4282
4283 case AEL_RAND_CONTROL:
4284 strcpy(app,"Random");
4285 snprintf(appargs,sizeof(appargs),"%s:%d", pr->appargs, pr->goto_true->priority_num+1);
4286 break;
4287
4288 case AEL_IFTIME_CONTROL:
4289 strcpy(app,"GotoIfTime");
4290 snprintf(appargs,sizeof(appargs),"%s?%d", pr->appargs, pr->priority_num+2);
4291 break;
4292
4293 case AEL_RETURN:
4294 strcpy(app,"Return");
4295 appargs[0] = 0;
4296 break;
4297
4298 default:
4299 break;
4300 }
4301 if (last && last->type == AEL_LABEL ) {
4302 label = last->origin->u1.str;
4303 }
4304 else
4305 label = 0;
4306
4307 if (ast_add_extension2(exten->context, 0 /*no replace*/, realext, pr->priority_num, (label?label:NULL), exten->cidmatch,
4308 app, strdup(appargs), ast_free_ptr, registrar, NULL, 0)) {
4309 ast_log(LOG_WARNING, "Unable to add step at priority '%d' of extension '%s'\n", pr->priority_num,
4310 exten->name);
4311 }
4312 last = pr;
4313 }
4315 } while ( exten );
4316}
@ AEL_FOR_CONTROL
Definition ael_structs.h:84
@ AEL_RAND_CONTROL
Definition ael_structs.h:84
@ AEL_RETURN
Definition ael_structs.h:84
@ AEL_IF_CONTROL
Definition ael_structs.h:84
@ AEL_IFTIME_CONTROL
Definition ael_structs.h:84
@ AEL_CONTROL1
Definition ael_structs.h:84
@ AEL_LABEL
Definition ael_structs.h:84
@ AEL_APPCALL
Definition ael_structs.h:84
static const char app[]
struct sla_ringing_trunk * last
Definition app_sla.c:338
void ast_free_ptr(void *ptr)
free() wrapper
Definition astmm.c:1739
#define ast_log
Definition astobj2.c:42
#define AST_MAX_EXTENSION
Definition channel.h:134
#define LOG_WARNING
int ast_add_extension2(struct ast_context *con, int replace, const char *extension, int priority, const char *label, const char *callerid, const char *application, void *data, void(*datad)(void *), const char *registrar, const char *registrar_file, int registrar_line)
Add an extension to an extension context, this time with an ast_context *.
Definition pbx.c:7282
#define PRIORITY_HINT
Definition pbx.h:54
void pbx_substitute_variables_helper(struct ast_channel *c, const char *cp1, char *cp2, int count)
Definition ael_main.c:211
static char * registrar
Definition pval.c:70
@ PV_SWITCH
Definition pval.h:32
@ PV_IFTIME
Definition pval.h:30
#define NULL
Definition resample.c:96
struct ael_priority * plist
struct ast_context * context
struct ael_extension * next_exten
struct ael_priority * goto_false
Definition ael_structs.h:99
struct ael_priority * goto_true
Definition ael_structs.h:98
struct pval * origin
Definition ael_structs.h:95
char * appargs
Definition ael_structs.h:93
ael_priority_type type
Definition ael_structs.h:90
struct ael_priority * next
struct ael_extension * exten
Definition ael_structs.h:96
union pval::@264 u3
struct pval * else_statements
Definition pval.h:78
pvaltype type
Definition pval.h:50

Referenced by ast_compile_ael2().

◆ aelsub_exec()

static int aelsub_exec ( struct ast_channel chan,
const char *  vdata 
)
static

Definition at line 127 of file pbx_ael.c.

128{
129 char buf[256], *data = ast_strdupa(vdata);
130 struct ast_app *gosub = pbx_findapp("Gosub");
134 );
135
136 if (gosub) {
138 snprintf(buf, sizeof(buf), "%s,~~s~~,1(%s)", args.name, args.args);
139 return pbx_exec(chan, gosub, buf);
140 }
141 return -1;
142}
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition astmm.h:298
char buf[BUFSIZE]
Definition eagi_proxy.c:66
#define AST_APP_ARG(name)
Define an application argument.
#define AST_STANDARD_RAW_ARGS(args, parse)
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application's arguments.
int pbx_exec(struct ast_channel *c, struct ast_app *app, const char *data)
Execute an application.
Definition pbx_app.c:471
struct ast_app * pbx_findapp(const char *app)
Look up an application.
Definition ael_main.c:165
static struct @519 args
ast_app: A registered application
Definition pbx_app.c:45

References args, AST_APP_ARG, AST_DECLARE_APP_ARGS, AST_STANDARD_RAW_ARGS, ast_strdupa, buf, name, pbx_exec(), and pbx_findapp().

Referenced by load_module().

◆ ast_compile_ael2()

int ast_compile_ael2 ( struct ast_context **  local_contexts,
struct ast_hashtab local_table,
struct pval root 
)

Definition at line 4413 of file pval.c.

4414{
4415 pval *p,*p2;
4416 struct ast_context *context;
4417 char buf[2000];
4418 struct ael_extension *exten;
4419 struct ael_extension *exten_list = 0;
4420
4421 /* Reset the counter so that we get consistent labels between reloads */
4423
4424 for (p=root; p; p=p->next ) { /* do the globals first, so they'll be there
4425 when we try to eval them */
4426 switch (p->type) {
4427 case PV_GLOBALS:
4428 /* just VARDEC elements */
4429 for (p2=p->u1.list; p2; p2=p2->next) {
4430 char buf2[2000];
4431 snprintf(buf2,sizeof(buf2),"%s=%s", p2->u1.str, p2->u2.val);
4432 pbx_builtin_setvar(NULL, buf2);
4433 }
4434 break;
4435 default:
4436 break;
4437 }
4438 }
4439
4440 for (p=root; p; p=p->next ) {
4441 pval *lp;
4442 int argc;
4443
4444 switch (p->type) {
4445 case PV_MACRO:
4446
4448
4449 exten = new_exten();
4450 exten->context = context;
4451 exten->name = strdup("~~s~~");
4452 argc = 1;
4453 for (lp=p->u2.arglist; lp; lp=lp->next) {
4454 /* for each arg, set up a "Set" command */
4455 struct ael_priority *np2 = new_prio();
4456 np2->type = AEL_APPCALL;
4457 np2->app = strdup("MSet");
4458 snprintf(buf,sizeof(buf),"LOCAL(%s)=${ARG%d}", lp->u1.str, argc++);
4460 np2->appargs = strdup(buf);
4461 linkprio(exten, np2, NULL);
4462 }
4463
4464 /* CONTAINS APPCALLS, CATCH, just like extensions... */
4465 if (gen_prios(exten, p->u1.str, p->u3.macro_statements, 0, context)) {
4466 return -1;
4467 }
4468 if (exten->return_needed) { /* most likely, this will go away */
4469 struct ael_priority *np2 = new_prio();
4470 np2->type = AEL_APPCALL;
4471 np2->app = strdup("NoOp");
4472 snprintf(buf,sizeof(buf),"End of Macro %s-%s",p->u1.str, exten->name);
4473 np2->appargs = strdup(buf);
4474 linkprio(exten, np2, NULL);
4475 exten-> return_target = np2;
4476 }
4477
4479 attach_exten(&exten_list, exten);
4480 break;
4481
4482 case PV_GLOBALS:
4483 /* already done */
4484 break;
4485
4486 case PV_CONTEXT:
4488
4489 /* contexts contain: ignorepat, includes, switches, eswitches, extensions, */
4490 for (p2=p->u2.statements; p2; p2=p2->next) {
4491 pval *p3;
4492 char *s3;
4493
4494 switch (p2->type) {
4495 case PV_EXTENSION:
4496 exten = new_exten();
4497 exten->name = strdup(p2->u1.str);
4499
4500 if( (s3=strchr(exten->name, '/') ) != 0 )
4501 {
4502 *s3 = 0;
4503 exten->cidmatch = s3+1;
4504 }
4505
4506 if ( p2->u3.hints )
4507 exten->hints = strdup(p2->u3.hints);
4508 exten->regexten = p2->u4.regexten;
4509 if (gen_prios(exten, p->u1.str, p2->u2.statements, 0, context)) {
4510 return -1;
4511 }
4512 if (exten->return_needed) { /* returns don't generate a goto eoe (end of extension) any more, just a Return() app call) */
4513 struct ael_priority *np2 = new_prio();
4514 np2->type = AEL_APPCALL;
4515 np2->app = strdup("NoOp");
4516 snprintf(buf,sizeof(buf),"End of Extension %s", exten->name);
4517 np2->appargs = strdup(buf);
4518 linkprio(exten, np2, NULL);
4519 exten-> return_target = np2;
4520 }
4521 /* is the last priority in the extension a label? Then add a trailing no-op */
4522 if ( exten->plist_last && exten->plist_last->type == AEL_LABEL ) {
4523 struct ael_priority *np2 = new_prio();
4524 np2->type = AEL_APPCALL;
4525 np2->app = strdup("NoOp");
4526 snprintf(buf,sizeof(buf),"A NoOp to follow a trailing label %s", exten->plist_last->origin->u1.str);
4527 np2->appargs = strdup(buf);
4528 linkprio(exten, np2, NULL);
4529 }
4530
4532 attach_exten(&exten_list, exten);
4533 break;
4534
4535 case PV_IGNOREPAT:
4537 break;
4538
4539 case PV_INCLUDES:
4540 for (p3 = p2->u1.list; p3 ;p3=p3->next) {
4541 if ( p3->u2.arglist ) {
4542 snprintf(buf,sizeof(buf), "%s,%s,%s,%s,%s",
4543 p3->u1.str,
4544 p3->u2.arglist->u1.str,
4545 p3->u2.arglist->next->u1.str,
4546 p3->u2.arglist->next->next->u1.str,
4547 p3->u2.arglist->next->next->next->u1.str);
4549 } else
4551 }
4552 break;
4553
4554 case PV_SWITCHES:
4555 for (p3 = p2->u1.list; p3 ;p3=p3->next) {
4556 char *c = strchr(p3->u1.str, '/');
4557 if (c) {
4558 *c = '\0';
4559 c++;
4560 } else
4561 c = "";
4562
4563 ast_context_add_switch2(context, p3->u1.str, c, 0, registrar);
4564 }
4565 break;
4566
4567 case PV_ESWITCHES:
4568 for (p3 = p2->u1.list; p3 ;p3=p3->next) {
4569 char *c = strchr(p3->u1.str, '/');
4570 if (c) {
4571 *c = '\0';
4572 c++;
4573 } else
4574 c = "";
4575
4576 ast_context_add_switch2(context, p3->u1.str, c, 1, registrar);
4577 }
4578 break;
4579 default:
4580 break;
4581 }
4582 }
4583
4584 break;
4585
4586 default:
4587 /* huh? what? */
4588 break;
4589
4590 }
4591 }
4592
4593 /* Create default "h" bubble context */
4594 if (ast_custom_function_find("DIALPLAN_EXISTS") && ast_custom_function_find("STACK_PEEK")) {
4595 int i;
4596 const char *h_context = "ael-builtin-h-bubble";
4597 struct ael_priority *np;
4598 struct {
4599 int priority;
4600 const char *app;
4601 const char *arg;
4602 } steps[] = {
4603 /* Start high, to avoid conflict with existing h extensions */
4604 { 1, "Goto", "9991" },
4605 /* Save the context, because after the StackPop, it disappears */
4606 { 9991, "Set", "~~parentcxt~~=${STACK_PEEK(1,c,1)}" },
4607 /* If we're not in a Gosub frame, exit */
4608 { 9992, "GotoIf", "$[\"${~~parentcxt~~}\"=\"\"]?9996" },
4609 /* Check for an "h" extension in that context */
4610 { 9993, "GotoIf", "${DIALPLAN_EXISTS(${~~parentcxt~~},h,1)}?9994:9996" },
4611 /* Pop off the stack frame to prevent an infinite loop */
4612 { 9994, "StackPop", "" },
4613 /* Finally, go there. */
4614 { 9995, "Goto", "${~~parentcxt~~},h,1" },
4615 /* Just an empty priority for jumping out early */
4616 { 9996, "NoOp", "" }
4617 };
4619 if (context_used(exten_list, context)) {
4620 int found = 0;
4621 while (!found) {
4622 /* Pick a new context name that is not used. */
4623 char h_context_template[] = "/tmp/ael-builtin-h-bubble-XXXXXX";
4624 int fd = mkstemp(h_context_template);
4625 unlink(h_context_template);
4626 close(fd);
4628 found = !context_used(exten_list, context);
4629 }
4630 h_context = ast_get_context_name(context);
4631 }
4632 exten = new_exten();
4633 exten->context = context;
4634 exten->name = strdup("h");
4635
4636 for (i = 0; i < ARRAY_LEN(steps); i++) {
4637 np = new_prio();
4638 np->type = AEL_APPCALL;
4639 np->priority_num = steps[i].priority;
4640 np->app = strdup(steps[i].app);
4641 np->appargs = strdup(steps[i].arg);
4642 linkprio(exten, np, NULL);
4643 }
4644 attach_exten(&exten_list, exten);
4645
4646 /* Include the default "h" bubble context in each macro context */
4647 for (exten = exten_list; exten; exten = exten->next_exten) {
4648 /* All macros contain a "~~s~~" extension, and it's the first created. If
4649 * we perchance get a non-macro context, it's no big deal; the logic is
4650 * designed to exit out smoothly if not called from within a Gosub. */
4651 if (!strcmp(exten->name, "~~s~~")) {
4652 ast_context_add_include2(exten->context, h_context, registrar);
4653 }
4654 }
4655 }
4656
4657 /* moved these from being done after a macro or extension were processed,
4658 to after all processing is done, for the sake of fixing gotos to labels inside cases... */
4659 /* I guess this would be considered 2nd pass of compiler now... */
4660 fix_gotos_in_extensions(exten_list); /* find and fix extension ref in gotos to labels that are in case statements */
4661 add_extensions(exten_list); /* actually makes calls to create priorities in ast_contexts -- feeds dialplan to asterisk */
4662 destroy_extensions(exten_list); /* all that remains is an empty husk, discard of it as is proper */
4663
4664 return 0;
4665}
static int priority
int pbx_builtin_setvar(struct ast_channel *chan, const char *data)
Parse and set a single channel variable, where the name and value are separated with an '=' character...
int ast_context_add_include2(struct ast_context *con, const char *value, const char *registrar)
Add a context include.
Definition ael_main.c:359
int ast_context_add_ignorepat2(struct ast_context *con, const char *ignorepat, const char *registrar)
Definition ael_main.c:348
struct ast_custom_function * ast_custom_function_find(const char *name)
Definition ael_main.c:173
struct ast_context * ast_context_find_or_create(struct ast_context **extcontexts, struct ast_hashtab *exttable, const char *name, const char *registrar)
Register a new context or find an existing one.
Definition pbx.c:6170
const char * ast_get_context_name(struct ast_context *con)
Definition ael_main.c:421
int ast_context_add_switch2(struct ast_context *con, const char *sw, const char *data, int eval, const char *registrar)
Adds a switch (first param is a ast_context)
Definition ael_main.c:370
static struct ast_context * local_contexts
Definition pbx_config.c:117
static struct ast_hashtab * local_table
Definition pbx_config.c:118
static void attach_exten(struct ael_extension **list, struct ael_extension *newmem)
Definition pval.c:4318
struct ael_priority * new_prio(void)
Definition pval.c:2924
static int context_used(struct ael_extension *exten_list, struct ast_context *context)
Definition pval.c:4398
static void remove_spaces_before_equals(char *str)
Definition pval.c:3038
void set_priorities(struct ael_extension *exten)
Definition pval.c:4187
struct ael_extension * new_exten(void)
Definition pval.c:2930
static int gen_prios(struct ael_extension *exten, char *label, pval *statement, struct ael_extension *mother_exten, struct ast_context *this_context)
Definition pval.c:3341
void destroy_extensions(struct ael_extension *exten)
Definition pval.c:2978
void linkprio(struct ael_extension *exten, struct ael_priority *prio, struct ael_extension *mother_exten)
Definition pval.c:2936
void add_extensions(struct ael_extension *exten)
Definition pval.c:4213
static int control_statement_count
Definition pval.c:2922
static void fix_gotos_in_extensions(struct ael_extension *exten)
Definition pval.c:4355
@ PV_GLOBALS
Definition pval.h:35
@ PV_CONTEXT
Definition pval.h:10
@ PV_INCLUDES
Definition pval.h:19
@ PV_MACRO
Definition pval.h:9
@ PV_SWITCHES
Definition pval.h:17
@ PV_IGNOREPAT
Definition pval.h:34
@ PV_ESWITCHES
Definition pval.h:18
@ PV_EXTENSION
Definition pval.h:33
struct ael_priority * plist_last
ast_context: An extension context
Definition pbx.c:299
Definition pval.h:49
struct pval * arglist
Definition pval.h:68
char * val
Definition pval.h:70
struct pval * next
Definition pval.h:93
char * hints
Definition pval.h:81
struct pval * statements
Definition pval.h:61
struct pval * macro_statements
Definition pval.h:79
char * str
Definition pval.h:59
union pval::@262 u1
union pval::@265 u4
union pval::@263 u2
int regexten
Definition pval.h:90
struct pval * list
Definition pval.h:60
static struct test_val c
#define ARRAY_LEN(a)
Definition utils.h:706

Referenced by pbx_load_module().

◆ ast_expr_clear_extra_error_info()

void ast_expr_clear_extra_error_info ( void  )

Definition at line 2469 of file ast_expr2f.c.

2470{
2472 extra_error_message[0] = 0;
2473}
char extra_error_message[4095]
int extra_error_message_supplied

◆ ast_expr_register_extra_error_info()

void ast_expr_register_extra_error_info ( char *  errmsg)

Definition at line 2463 of file ast_expr2f.c.

2464{
2467}

◆ AST_MODULE_SELF_SYM()

struct ast_module * AST_MODULE_SELF_SYM ( void  )

Definition at line 312 of file pbx_ael.c.

◆ check_app_args()

int check_app_args ( pval appcall,
pval arglist,
struct argapp app 
)

Definition at line 2130 of file pval.c.

2131{
2132#ifdef AAL_ARGCHECK
2133 struct argdesc *ad = app->args;
2134 pval *pa;
2135 int z;
2136
2137 for (pa = arglist; pa; pa=pa->next) {
2138 if (!ad) {
2139 ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: Extra argument %s not in application call to %s !\n",
2140 arglist->filename, arglist->startline, arglist->endline, pa->u1.str, app->name);
2141 warns++;
2142 return 1;
2143 } else {
2144 /* find the first entry in the ad list that will match */
2145 do {
2146 if ( ad->dtype == ARGD_VARARG ) /* once we hit the VARARG, all bets are off. Discontinue the comparisons */
2147 break;
2148
2149 z= option_matches( ad, pa, app);
2150 if (!z) {
2151 if ( !arglist )
2152 arglist=appcall;
2153
2154 if (ad->type == ARGD_REQUIRED) {
2155 ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: Required argument %s not in application call to %s !\n",
2156 arglist->filename, arglist->startline, arglist->endline, ad->dtype==ARGD_OPTIONSET?"options":ad->name, app->name);
2157 warns++;
2158 return 1;
2159 }
2160 } else if (z && ad->dtype == ARGD_OPTIONSET) {
2161 option_matches_j( ad, pa, app);
2162 }
2163 ad = ad->next;
2164 } while (ad && !z);
2165 }
2166 }
2167 /* any app nodes left, that are not optional? */
2168 for ( ; ad; ad=ad->next) {
2169 if (ad->type == ARGD_REQUIRED && ad->dtype != ARGD_VARARG) {
2170 if ( !arglist )
2171 arglist=appcall;
2172 ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: Required argument %s not in application call to %s !\n",
2173 arglist->filename, arglist->startline, arglist->endline, ad->dtype==ARGD_OPTIONSET?"options":ad->name, app->name);
2174 warns++;
2175 return 1;
2176 }
2177 }
2178 return 0;
2179#else
2180 return 0;
2181#endif
2182}
static int warns
Definition pval.c:65
int endline
Definition pval.h:52
char * filename
Definition pval.h:55
int startline
Definition pval.h:51

Referenced by check_pval_item().

◆ check_pval()

void check_pval ( pval item,
struct argapp apps,
int  in_globals 
)

Definition at line 2865 of file pval.c.

2866{
2867 pval *i;
2868
2869 /* checks to do:
2870 1. Do goto's point to actual labels?
2871 2. Do macro calls reference a macro?
2872 3. Does the number of macro args match the definition?
2873 4. Is a macro call missing its & at the front?
2874 5. Application calls-- we could check syntax for existing applications,
2875 but I need some sort of universal description bnf for a general
2876 sort of method for checking arguments, in number, maybe even type, at least.
2877 Don't want to hand code checks for hundreds of applications.
2878 */
2879
2880 for (i=item; i; i=i->next) {
2881 check_pval_item(i,apps,in_globals);
2882 }
2883}
void check_pval_item(pval *item, struct argapp *apps, int in_globals)
Definition pval.c:2357
Registered applications container.
Definition pbx_app.c:68
static struct aco_type item

Referenced by ael2_semantic_check(), and check_pval_item().

◆ check_pval_item()

void check_pval_item ( pval item,
struct argapp apps,
int  in_globals 
)

Definition at line 2357 of file pval.c.

2358{
2359 pval *lp;
2360#ifdef AAL_ARGCHECK
2361 struct argapp *app, *found;
2362#endif
2363 struct pval *macro_def;
2364 struct pval *app_def;
2365
2366 char errmsg[4096];
2367 char *strp;
2368
2369 switch (item->type) {
2370 case PV_WORD:
2371 /* fields: item->u1.str == string associated with this (word).
2372 item->u2.arglist == pval list of 4 PV_WORD elements for time values (only in PV_INCLUDES) */
2373 break;
2374
2375 case PV_MACRO:
2376 /* fields: item->u1.str == name of macro
2377 item->u2.arglist == pval list of PV_WORD arguments of macro, as given by user
2378 item->u2.arglist->u1.str == argument
2379 item->u2.arglist->next == next arg
2380
2381 item->u3.macro_statements == pval list of statements in macro body.
2382 */
2386
2388
2389 for (lp=item->u2.arglist; lp; lp=lp->next) {
2390
2391 }
2392 check_pval(item->u3.macro_statements, apps,in_globals);
2393 break;
2394
2395 case PV_CONTEXT:
2396 /* fields: item->u1.str == name of context
2397 item->u2.statements == pval list of statements in context body
2398 item->u3.abstract == int 1 if an abstract keyword were present
2399 */
2402 if ( item->u3.abstract ) {
2405 } else
2407 check_pval(item->u2.statements, apps,in_globals);
2408 break;
2409
2410 case PV_MACRO_CALL:
2411 /* fields: item->u1.str == name of macro to call
2412 item->u2.arglist == pval list of PV_WORD arguments of macro call, as given by user
2413 item->u2.arglist->u1.str == argument
2414 item->u2.arglist->next == next arg
2415 */
2416#ifdef STANDALONE
2417 /* if this is a standalone, we will need to make sure the
2418 localized load of extensions.conf is done */
2419 if (!extensions_dot_conf_loaded) {
2421 extensions_dot_conf_loaded++;
2422 }
2423#endif
2424 macro_def = find_macro(item->u1.str);
2425 if (!macro_def) {
2426#ifdef STANDALONE
2427 struct pbx_find_info pfiq = {.stacklen = 0 };
2428 struct pbx_find_info pfiq2 = {.stacklen = 0 };
2429
2430 /* look for the macro in the extensions.conf world */
2431 pbx_find_extension(NULL, NULL, &pfiq, item->u1.str, "s", 1, NULL, NULL, E_MATCH);
2432
2433 if (pfiq.status != STATUS_SUCCESS) {
2434 char namebuf2[256];
2435 snprintf(namebuf2, 256, "macro-%s", item->u1.str);
2436
2437 /* look for the macro in the extensions.conf world */
2438 pbx_find_extension(NULL, NULL, &pfiq2, namebuf2, "s", 1, NULL, NULL, E_MATCH);
2439
2440 if (pfiq2.status == STATUS_SUCCESS) {
2441 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",
2442 item->filename, item->startline, item->endline, item->u1.str, item->u1.str);
2443 warns++;
2444 } else {
2445 ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: macro call to non-existent %s! (Not even in the extensions.conf stuff!)\n",
2446 item->filename, item->startline, item->endline, item->u1.str);
2447 warns++;
2448 }
2449 }
2450#else
2451 ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: macro call to %s cannot be found in the AEL code!\n",
2452 item->filename, item->startline, item->endline, item->u1.str);
2453 warns++;
2454
2455#endif
2456#ifdef THIS_IS_1DOT4
2457 char namebuf2[256];
2458 snprintf(namebuf2, 256, "macro-%s", item->u1.str);
2459
2460 /* look for the macro in the extensions.conf world */
2461 pbx_find_extension(NULL, NULL, &pfiq, namebuf2, "s", 1, NULL, NULL, E_MATCH);
2462
2463 if (pfiq.status != STATUS_SUCCESS) {
2464 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",
2465 item->filename, item->startline, item->endline, item->u1.str);
2466 warns++;
2467 }
2468
2469#endif
2470
2471 } else if (macro_def->type != PV_MACRO) {
2472 ast_log(LOG_ERROR,"Error: file %s, line %d-%d: macro call to %s references a context, not a macro!\n",
2473 item->filename, item->startline, item->endline, item->u1.str);
2474 errs++;
2475 } else {
2476 /* macro_def is a MACRO, so do the args match in number? */
2477 int hereargs = 0;
2478 int thereargs = 0;
2479
2480 for (lp=item->u2.arglist; lp; lp=lp->next) {
2481 hereargs++;
2482 }
2483 for (lp=macro_def->u2.arglist; lp; lp=lp->next) {
2484 thereargs++;
2485 }
2486 if (hereargs != thereargs ) {
2487 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",
2488 item->filename, item->startline, item->endline, item->u1.str, hereargs, thereargs);
2489 errs++;
2490 }
2491 }
2492 break;
2493
2495 /* fields: item->u1.str == name of application to call
2496 item->u2.arglist == pval list of PV_WORD arguments of macro call, as given by user
2497 item->u2.arglist->u1.str == argument
2498 item->u2.arglist->next == next arg
2499 */
2500 /* Need to check to see if the application is available! */
2501 app_def = find_context(item->u1.str);
2502 if (app_def && app_def->type == PV_MACRO) {
2503 ast_log(LOG_ERROR,"Error: file %s, line %d-%d: application call to %s references an existing macro, but had no & preceding it!\n",
2504 item->filename, item->startline, item->endline, item->u1.str);
2505 errs++;
2506 }
2507 if (strcasecmp(item->u1.str,"GotoIf") == 0
2508 || strcasecmp(item->u1.str,"GotoIfTime") == 0
2509 || strcasecmp(item->u1.str,"while") == 0
2510 || strcasecmp(item->u1.str,"endwhile") == 0
2511 || strcasecmp(item->u1.str,"random") == 0
2512 || strcasecmp(item->u1.str,"gosub") == 0
2513 || strcasecmp(item->u1.str,"gosubif") == 0
2514 || strcasecmp(item->u1.str,"continuewhile") == 0
2515 || strcasecmp(item->u1.str,"endwhile") == 0
2516 || strcasecmp(item->u1.str,"execif") == 0
2517 || strcasecmp(item->u1.str,"execiftime") == 0
2518 || strcasecmp(item->u1.str,"exitwhile") == 0
2519 || strcasecmp(item->u1.str,"goto") == 0
2520 || strcasecmp(item->u1.str,"macro") == 0
2521 || strcasecmp(item->u1.str,"macroexclusive") == 0
2522 || strcasecmp(item->u1.str,"macroif") == 0
2523 || strcasecmp(item->u1.str,"stackpop") == 0
2524 || strcasecmp(item->u1.str,"execIf") == 0 ) {
2525 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",
2526 item->filename, item->startline, item->endline, item->u1.str);
2527 warns++;
2528 }
2529 if (strcasecmp(item->u1.str,"macroexit") == 0) {
2530 ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: I am converting the MacroExit call here to a return statement.\n",
2531 item->filename, item->startline, item->endline);
2532 item->type = PV_RETURN;
2533 free(item->u1.str);
2534 item->u1.str = 0;
2535 }
2536
2537#ifdef AAL_ARGCHECK
2538 found = 0;
2539 for (app=apps; app; app=app->next) {
2540 if (strcasecmp(app->name, item->u1.str) == 0) {
2541 found =app;
2542 break;
2543 }
2544 }
2545 if (!found) {
2546 ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: application call to %s not listed in applist database!\n",
2547 item->filename, item->startline, item->endline, item->u1.str);
2548 warns++;
2549 } else
2550 check_app_args(item, item->u2.arglist, app);
2551#endif
2552 break;
2553
2554 case PV_CASE:
2555 /* fields: item->u1.str == value of case
2556 item->u2.statements == pval list of statements under the case
2557 */
2558 /* Make sure sequence of statements under case is terminated with goto, return, or break */
2559 /* find the last statement */
2560 check_pval(item->u2.statements, apps,in_globals);
2561 break;
2562
2563 case PV_PATTERN:
2564 /* fields: item->u1.str == value of case
2565 item->u2.statements == pval list of statements under the case
2566 */
2567 /* Make sure sequence of statements under case is terminated with goto, return, or break */
2568 /* find the last statement */
2569
2570 check_pval(item->u2.statements, apps,in_globals);
2571 break;
2572
2573 case PV_DEFAULT:
2574 /* fields:
2575 item->u2.statements == pval list of statements under the case
2576 */
2577
2578 check_pval(item->u2.statements, apps,in_globals);
2579 break;
2580
2581 case PV_CATCH:
2582 /* fields: item->u1.str == name of extension to catch
2583 item->u2.statements == pval list of statements in context body
2584 */
2585 check_pval(item->u2.statements, apps,in_globals);
2586 break;
2587
2588 case PV_SWITCHES:
2589 /* fields: item->u1.list == pval list of PV_WORD elements, one per entry in the list
2590 */
2591 check_pval(item->u1.list, apps,in_globals);
2592 break;
2593
2594 case PV_ESWITCHES:
2595 /* fields: item->u1.list == pval list of PV_WORD elements, one per entry in the list
2596 */
2597 check_pval(item->u1.list, apps,in_globals);
2598 break;
2599
2600 case PV_INCLUDES:
2601 /* fields: item->u1.list == pval list of PV_WORD elements, one per entry in the list
2602 */
2603 check_pval(item->u1.list, apps,in_globals);
2605 for (lp=item->u1.list; lp; lp=lp->next){
2606 char *incl_context = lp->u1.str;
2607 struct pval *that_context = find_context(incl_context);
2608
2609 if ( lp->u2.arglist ) {
2611 check_dow(lp->u2.arglist->next);
2612 check_day(lp->u2.arglist->next->next);
2614 }
2615
2616 if (that_context) {
2617 find_pval_gotos(that_context->u2.statements,0);
2618
2619 }
2620 }
2621 break;
2622
2623 case PV_STATEMENTBLOCK:
2624 /* fields: item->u1.list == pval list of statements in block, one per entry in the list
2625 */
2626 check_pval(item->u1.list, apps,in_globals);
2627 break;
2628
2629 case PV_VARDEC:
2630 /* fields: item->u1.str == variable name
2631 item->u2.val == variable value to assign
2632 */
2633 /* the RHS of a vardec is encapsulated in a $[] expr. Is it legal? */
2634 if( !in_globals ) { /* don't check stuff inside the globals context; no wrapping in $[ ] there... */
2635 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);
2637 ast_expr(item->u2.val, expr_output, sizeof(expr_output),NULL);
2639 if ( strpbrk(item->u2.val,"~!-+<>=*/&^") && !strstr(item->u2.val,"${") ) {
2640 ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: expression %s has operators, but no variables. Interesting...\n",
2641 item->filename, item->startline, item->endline, item->u2.val);
2642 warns++;
2643 }
2644 check_expr2_input(item,item->u2.val);
2645 }
2646 break;
2647
2648 case PV_LOCALVARDEC:
2649 /* fields: item->u1.str == variable name
2650 item->u2.val == variable value to assign
2651 */
2652 /* the RHS of a vardec is encapsulated in a $[] expr. Is it legal? */
2653 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);
2655 ast_expr(item->u2.val, expr_output, sizeof(expr_output),NULL);
2657 if ( strpbrk(item->u2.val,"~!-+<>=*/&^") && !strstr(item->u2.val,"${") ) {
2658 ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: expression %s has operators, but no variables. Interesting...\n",
2659 item->filename, item->startline, item->endline, item->u2.val);
2660 warns++;
2661 }
2662 check_expr2_input(item,item->u2.val);
2663 break;
2664
2665 case PV_GOTO:
2666 /* fields: item->u1.list == pval list of PV_WORD target names, up to 3, in order as given by user.
2667 item->u1.list->u1.str == where the data on a PV_WORD will always be.
2668 */
2669 /* don't check goto's in abstract contexts */
2670 if ( in_abstract_context )
2671 break;
2672
2674 break;
2675
2676 case PV_LABEL:
2677 /* fields: item->u1.str == label name
2678 */
2679 if ( strspn(item->u1.str, "0123456789") == strlen(item->u1.str) ) {
2680 ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: label '%s' is numeric, this is bad practice!\n",
2681 item->filename, item->startline, item->endline, item->u1.str);
2682 warns++;
2683 }
2684
2686 break;
2687
2688 case PV_FOR:
2689 /* fields: item->u1.for_init == a string containing the initializer
2690 item->u2.for_test == a string containing the loop test
2691 item->u3.for_inc == a string containing the loop increment
2692
2693 item->u4.for_statements == a pval list of statements in the for ()
2694 */
2695 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);
2697
2698 strp = strchr(item->u1.for_init, '=');
2699 if (strp) {
2700 ast_expr(strp+1, expr_output, sizeof(expr_output),NULL);
2701 }
2702 ast_expr(item->u2.for_test, expr_output, sizeof(expr_output),NULL);
2703 strp = strchr(item->u3.for_inc, '=');
2704 if (strp) {
2705 ast_expr(strp+1, expr_output, sizeof(expr_output),NULL);
2706 }
2707 if ( strpbrk(item->u2.for_test,"~!-+<>=*/&^") && !strstr(item->u2.for_test,"${") ) {
2708 ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: expression %s has operators, but no variables. Interesting...\n",
2709 item->filename, item->startline, item->endline, item->u2.for_test);
2710 warns++;
2711 }
2712 if ( strpbrk(item->u3.for_inc,"~!-+<>=*/&^") && !strstr(item->u3.for_inc,"${") ) {
2713 ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: expression %s has operators, but no variables. Interesting...\n",
2714 item->filename, item->startline, item->endline, item->u3.for_inc);
2715 warns++;
2716 }
2717 check_expr2_input(item,item->u2.for_test);
2718 check_expr2_input(item,item->u3.for_inc);
2719
2721 check_pval(item->u4.for_statements, apps,in_globals);
2722 break;
2723
2724 case PV_WHILE:
2725 /* fields: item->u1.str == the while conditional, as supplied by user
2726
2727 item->u2.statements == a pval list of statements in the while ()
2728 */
2729 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);
2731 ast_expr(item->u1.str, expr_output, sizeof(expr_output),NULL);
2733 if ( strpbrk(item->u1.str,"~!-+<>=*/&^") && !strstr(item->u1.str,"${") ) {
2734 ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: expression %s has operators, but no variables. Interesting...\n",
2735 item->filename, item->startline, item->endline, item->u1.str);
2736 warns++;
2737 }
2738 check_expr2_input(item,item->u1.str);
2739 check_pval(item->u2.statements, apps,in_globals);
2740 break;
2741
2742 case PV_BREAK:
2743 /* fields: none
2744 */
2746 break;
2747
2748 case PV_RETURN:
2749 /* fields: none
2750 */
2751 break;
2752
2753 case PV_CONTINUE:
2754 /* fields: none
2755 */
2757 break;
2758
2759 case PV_RANDOM:
2760 /* fields: item->u1.str == the random number expression, as supplied by user
2761
2762 item->u2.statements == a pval list of statements in the if ()
2763 item->u3.else_statements == a pval list of statements in the else
2764 (could be zero)
2765 */
2766 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);
2768 ast_expr(item->u1.str, expr_output, sizeof(expr_output),NULL);
2770 if ( strpbrk(item->u1.str,"~!-+<>=*/&^") && !strstr(item->u1.str,"${") ) {
2771 ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: random expression '%s' has operators, but no variables. Interesting...\n",
2772 item->filename, item->startline, item->endline, item->u1.str);
2773 warns++;
2774 }
2775 check_expr2_input(item,item->u1.str);
2776 check_pval(item->u2.statements, apps,in_globals);
2777 if (item->u3.else_statements) {
2778 check_pval(item->u3.else_statements, apps,in_globals);
2779 }
2780 break;
2781
2782 case PV_IFTIME:
2783 /* fields: item->u1.list == the if time values, 4 of them, each in PV_WORD, linked list
2784
2785 item->u2.statements == a pval list of statements in the if ()
2786 item->u3.else_statements == a pval list of statements in the else
2787 (could be zero)
2788 */
2789 if ( item->u2.arglist ) {
2790 check_timerange(item->u1.list);
2791 check_dow(item->u1.list->next);
2792 check_day(item->u1.list->next->next);
2793 check_month(item->u1.list->next->next->next);
2794 }
2795
2796 check_pval(item->u2.statements, apps,in_globals);
2797 if (item->u3.else_statements) {
2798 check_pval(item->u3.else_statements, apps,in_globals);
2799 }
2800 break;
2801
2802 case PV_IF:
2803 /* fields: item->u1.str == the if conditional, as supplied by user
2804
2805 item->u2.statements == a pval list of statements in the if ()
2806 item->u3.else_statements == a pval list of statements in the else
2807 (could be zero)
2808 */
2809 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);
2811 ast_expr(item->u1.str, expr_output, sizeof(expr_output),NULL);
2813 if ( strpbrk(item->u1.str,"~!-+<>=*/&^") && !strstr(item->u1.str,"${") ) {
2814 ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: expression '%s' has operators, but no variables. Interesting...\n",
2815 item->filename, item->startline, item->endline, item->u1.str);
2816 warns++;
2817 }
2818 check_expr2_input(item,item->u1.str);
2819 check_pval(item->u2.statements, apps,in_globals);
2820 if (item->u3.else_statements) {
2821 check_pval(item->u3.else_statements, apps,in_globals);
2822 }
2823 break;
2824
2825 case PV_SWITCH:
2826 /* fields: item->u1.str == the switch expression
2827
2828 item->u2.statements == a pval list of statements in the switch,
2829 (will be case statements, most likely!)
2830 */
2831 /* we can check the switch expression, see if it matches any of the app variables...
2832 if it does, then, are all the possible cases accounted for? */
2834 check_pval(item->u2.statements, apps,in_globals);
2835 break;
2836
2837 case PV_EXTENSION:
2838 /* fields: item->u1.str == the extension name, label, whatever it's called
2839
2840 item->u2.statements == a pval list of statements in the extension
2841 item->u3.hints == a char * hint argument
2842 item->u4.regexten == an int boolean. non-zero says that regexten was specified
2843 */
2845
2846 check_pval(item->u2.statements, apps,in_globals);
2847 break;
2848
2849 case PV_IGNOREPAT:
2850 /* fields: item->u1.str == the ignorepat data
2851 */
2852 break;
2853
2854 case PV_GLOBALS:
2855 /* fields: item->u1.statements == pval list of statements, usually vardecs
2856 */
2858 check_pval(item->u1.statements, apps, 1);
2859 break;
2860 default:
2861 break;
2862 }
2863}
int ast_expr(char *expr, char *buf, int length, struct ast_channel *chan)
Evaluate the given expression.
@ E_MATCH
Definition extconf.h:217
#define STATUS_SUCCESS
Definition extconf.h:248
void free()
#define LOG_ERROR
struct ast_exten * pbx_find_extension(struct ast_channel *chan, struct ast_context *bypass, struct pbx_find_info *q, const char *context, const char *exten, int priority, const char *label, const char *callerid, enum ext_match_t action)
Definition ael_main.c:152
static int check_continue(pval *item)
Definition pval.c:1058
void check_switch_expr(pval *item, struct argapp *apps)
Definition pval.c:2184
static void check_macro_returns(pval *macro)
Definition pval.c:650
static void check_day(pval *DAY)
Definition pval.c:937
struct pval * find_macro(char *name)
Definition pval.c:1943
static void check_label(pval *item)
Definition pval.c:1106
static void find_pval_gotos(pval *item, int lev)
Definition pval.c:1550
int check_app_args(pval *appcall, pval *arglist, struct argapp *app)
Definition pval.c:2130
static void check_dow(pval *DOW)
get_dow: Get day of week
Definition pval.c:898
static void check_goto(pval *item)
Definition pval.c:1225
static void check_abstract_reference(pval *abstract_context)
Definition pval.c:2329
static void check_timerange(pval *p)
Definition pval.c:830
static void check_includes(pval *includes)
Definition pval.c:811
static void check_month(pval *MON)
Definition pval.c:1000
static int errs
Definition pval.c:65
void check_pval(pval *item, struct argapp *apps, int in_globals)
Definition pval.c:2865
static int in_abstract_context
Definition pval.c:79
static pval * current_context
Definition pval.c:73
struct pval * find_context(char *name)
Definition pval.c:1953
int localized_pbx_load_module(void)
Definition extconf.c:5642
static pval * current_extension
Definition pval.c:74
static void check_expr2_input(pval *expr, char *str)
Definition pval.c:801
static int check_break(pval *item)
Definition pval.c:1038
static char expr_output[2096]
Definition pval.c:60
void ast_expr_clear_extra_error_info(void)
@ PV_CATCH
Definition pval.h:16
@ PV_WORD
Definition pval.h:8
@ PV_LOCALVARDEC
Definition pval.h:36
@ PV_DEFAULT
Definition pval.h:15
@ PV_CASE
Definition pval.h:13
@ PV_CONTINUE
Definition pval.h:28
@ PV_BREAK
Definition pval.h:26
@ PV_APPLICATION_CALL
Definition pval.h:12
@ PV_PATTERN
Definition pval.h:14
@ PV_RETURN
Definition pval.h:27
@ PV_IF
Definition pval.h:29
@ PV_VARDEC
Definition pval.h:21
@ PV_MACRO_CALL
Definition pval.h:11
@ PV_GOTO
Definition pval.h:22
@ PV_LABEL
Definition pval.h:23
@ PV_FOR
Definition pval.h:24
@ PV_RANDOM
Definition pval.h:31
@ PV_STATEMENTBLOCK
Definition pval.h:20
@ PV_WHILE
Definition pval.h:25
void ast_expr_register_extra_error_info(char *errmsg)
enum aco_type_t type
Definition pval.h:111

Referenced by check_pval().

◆ check_switch_expr()

void check_switch_expr ( pval item,
struct argapp apps 
)

Definition at line 2184 of file pval.c.

2185{
2186#ifdef AAL_ARGCHECK
2187 /* get and clean the variable name */
2188 char *buff1, *p;
2189 struct argapp *a,*a2;
2190 struct appsetvar *v,*v2;
2191 struct argchoice *c;
2192 pval *t;
2193
2194 p = item->u1.str;
2195 while (p && *p && (*p == ' ' || *p == '\t' || *p == '$' || *p == '{' ) )
2196 p++;
2197
2198 buff1 = ast_strdupa(p);
2199
2200 while (strlen(buff1) > 0 && ( buff1[strlen(buff1)-1] == '}' || buff1[strlen(buff1)-1] == ' ' || buff1[strlen(buff1)-1] == '\t'))
2201 buff1[strlen(buff1)-1] = 0;
2202 /* buff1 now contains the variable name */
2203 v = 0;
2204 for (a=apps; a; a=a->next) {
2205 for (v=a->setvars;v;v=v->next) {
2206 if (strcmp(v->name,buff1) == 0) {
2207 break;
2208 }
2209 }
2210 if ( v )
2211 break;
2212 }
2213 if (v && v->vals) {
2214 /* we have a match, to a variable that has a set of determined values */
2215 int def= 0;
2216 int pat = 0;
2217 int f1 = 0;
2218
2219 /* first of all, does this switch have a default case ? */
2220 for (t=item->u2.statements; t; t=t->next) {
2221 if (t->type == PV_DEFAULT) {
2222 def =1;
2223 break;
2224 }
2225 if (t->type == PV_PATTERN) {
2226 pat++;
2227 }
2228 }
2229 if (def || pat) /* nothing to check. All cases accounted for! */
2230 return;
2231 for (c=v->vals; c; c=c->next) {
2232 f1 = 0;
2233 for (t=item->u2.statements; t; t=t->next) {
2234 if (t->type == PV_CASE || t->type == PV_PATTERN) {
2235 if (!strcmp(t->u1.str,c->name)) {
2236 f1 = 1;
2237 break;
2238 }
2239 }
2240 }
2241 if (!f1) {
2242 ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: switch with expression(%s) does not handle the case of %s !\n",
2243 item->filename, item->startline, item->endline, item->u1.str, c->name);
2244 warns++;
2245 }
2246 }
2247 /* next, is there an app call in the current exten, that would set this var? */
2248 f1 = 0;
2250 if ( t && t->type == PV_STATEMENTBLOCK )
2251 t = t->u1.statements;
2252 for (; t && t != item; t=t->next) {
2253 if (t->type == PV_APPLICATION_CALL) {
2254 /* find the application that matches the u1.str */
2255 for (a2=apps; a2; a2=a2->next) {
2256 if (strcasecmp(a2->name, t->u1.str)==0) {
2257 for (v2=a2->setvars; v2; v2=v2->next) {
2258 if (strcmp(v2->name, buff1) == 0) {
2259 /* found an app that sets the var */
2260 f1 = 1;
2261 break;
2262 }
2263 }
2264 }
2265 if (f1)
2266 break;
2267 }
2268 }
2269 if (f1)
2270 break;
2271 }
2272
2273 /* see if it sets the var */
2274 if (!f1) {
2275 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",
2276 item->filename, item->startline, item->endline, item->u1.str);
2277 warns++;
2278 }
2279 }
2280#else
2281 pval *t,*tl=0,*p2;
2282 int def= 0;
2283
2284 /* first of all, does this switch have a default case ? */
2285 for (t=item->u2.statements; t; t=t->next) {
2286 if (t->type == PV_DEFAULT) {
2287 def =1;
2288 break;
2289 }
2290 tl = t;
2291 }
2292 if (def) /* nothing to check. All cases accounted for! */
2293 return;
2294 /* if no default, warn and insert a default case at the end */
2295 p2 = tl->next = calloc(1, sizeof(struct pval));
2296
2297 p2->type = PV_DEFAULT;
2298 p2->startline = tl->startline;
2299 p2->endline = tl->endline;
2300 p2->startcol = tl->startcol;
2301 p2->endcol = tl->endcol;
2302 p2->filename = strdup(tl->filename);
2303 ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: A default case was automatically added to the switch.\n",
2304 p2->filename, p2->startline, p2->endline);
2305 warns++;
2306
2307#endif
2308}
struct argapp * next
Definition pval.h:112
int startcol
Definition pval.h:53
int endcol
Definition pval.h:54
struct test_val * next
const char * name
static struct test_val a

Referenced by check_pval_item().

◆ destroy_extensions()

void destroy_extensions ( struct ael_extension exten)

Definition at line 2978 of file pval.c.

2979{
2980 struct ael_extension *ne, *nen;
2981 for (ne=exten; ne; ne=nen) {
2982 struct ael_priority *pe, *pen;
2983
2984 if (ne->name)
2985 free(ne->name);
2986
2987 /* cidmatch fields are allocated with name, and freed when
2988 the name field is freed. Don't do a free for this field,
2989 unless you LIKE to see a crash! */
2990
2991 if (ne->hints)
2992 free(ne->hints);
2993
2994 for (pe=ne->plist; pe; pe=pen) {
2995 pen = pe->next;
2996 if (pe->app)
2997 free(pe->app);
2998 pe->app = 0;
2999 if (pe->appargs)
3000 free(pe->appargs);
3001 pe->appargs = 0;
3002 pe->origin = 0;
3003 pe->goto_true = 0;
3004 pe->goto_false = 0;
3005 free(pe);
3006 }
3007 nen = ne->next_exten;
3008 ne->next_exten = 0;
3009 ne->plist =0;
3010 ne->plist_last = 0;
3011 ne->next_exten = 0;
3012 ne->loop_break = 0;
3013 ne->loop_continue = 0;
3014 free(ne);
3015 }
3016}
struct ael_priority * loop_break
struct ael_priority * loop_continue

Referenced by ast_compile_ael2().

◆ destroy_pval()

void destroy_pval ( pval item)

Definition at line 4940 of file pval.c.

4941{
4942 pval *i,*nxt;
4943
4944 for (i=item; i; i=nxt) {
4945 nxt = i->next;
4946
4948 }
4949}
void destroy_pval_item(pval *item)
Definition pval.c:4672

Referenced by destroy_pval_item(), pbx_load_module(), pvalIfTimeSetCondition(), and pvalIncludesAddIncludeWithTimeConstraints().

◆ destroy_pval_item()

void destroy_pval_item ( pval item)

Definition at line 4672 of file pval.c.

4673{
4674 if (item == NULL) {
4675 ast_log(LOG_WARNING, "null item\n");
4676 return;
4677 }
4678
4679 if (item->filename)
4680 free(item->filename);
4681
4682 switch (item->type) {
4683 case PV_WORD:
4684 /* fields: item->u1.str == string associated with this (word). */
4685 if (item->u1.str )
4686 free(item->u1.str);
4687 if ( item->u2.arglist )
4688 destroy_pval(item->u2.arglist);
4689 break;
4690
4691 case PV_MACRO:
4692 /* fields: item->u1.str == name of macro
4693 item->u2.arglist == pval list of PV_WORD arguments of macro, as given by user
4694 item->u2.arglist->u1.str == argument
4695 item->u2.arglist->next == next arg
4696
4697 item->u3.macro_statements == pval list of statements in macro body.
4698 */
4699 destroy_pval(item->u2.arglist);
4700 if (item->u1.str )
4701 free(item->u1.str);
4702 destroy_pval(item->u3.macro_statements);
4703 break;
4704
4705 case PV_CONTEXT:
4706 /* fields: item->u1.str == name of context
4707 item->u2.statements == pval list of statements in context body
4708 item->u3.abstract == int 1 if an abstract keyword were present
4709 */
4710 if (item->u1.str)
4711 free(item->u1.str);
4712 destroy_pval(item->u2.statements);
4713 break;
4714
4715 case PV_MACRO_CALL:
4716 /* fields: item->u1.str == name of macro to call
4717 item->u2.arglist == pval list of PV_WORD arguments of macro call, as given by user
4718 item->u2.arglist->u1.str == argument
4719 item->u2.arglist->next == next arg
4720 */
4721 if (item->u1.str)
4722 free(item->u1.str);
4723 destroy_pval(item->u2.arglist);
4724 break;
4725
4727 /* fields: item->u1.str == name of application to call
4728 item->u2.arglist == pval list of PV_WORD arguments of macro call, as given by user
4729 item->u2.arglist->u1.str == argument
4730 item->u2.arglist->next == next arg
4731 */
4732 if (item->u1.str)
4733 free(item->u1.str);
4734 destroy_pval(item->u2.arglist);
4735 break;
4736
4737 case PV_CASE:
4738 /* fields: item->u1.str == value of case
4739 item->u2.statements == pval list of statements under the case
4740 */
4741 if (item->u1.str)
4742 free(item->u1.str);
4743 destroy_pval(item->u2.statements);
4744 break;
4745
4746 case PV_PATTERN:
4747 /* fields: item->u1.str == value of case
4748 item->u2.statements == pval list of statements under the case
4749 */
4750 if (item->u1.str)
4751 free(item->u1.str);
4752 destroy_pval(item->u2.statements);
4753 break;
4754
4755 case PV_DEFAULT:
4756 /* fields:
4757 item->u2.statements == pval list of statements under the case
4758 */
4759 destroy_pval(item->u2.statements);
4760 break;
4761
4762 case PV_CATCH:
4763 /* fields: item->u1.str == name of extension to catch
4764 item->u2.statements == pval list of statements in context body
4765 */
4766 if (item->u1.str)
4767 free(item->u1.str);
4768 destroy_pval(item->u2.statements);
4769 break;
4770
4771 case PV_SWITCHES:
4772 /* fields: item->u1.list == pval list of PV_WORD elements, one per entry in the list
4773 */
4774 destroy_pval(item->u1.list);
4775 break;
4776
4777 case PV_ESWITCHES:
4778 /* fields: item->u1.list == pval list of PV_WORD elements, one per entry in the list
4779 */
4780 destroy_pval(item->u1.list);
4781 break;
4782
4783 case PV_INCLUDES:
4784 /* fields: item->u1.list == pval list of PV_WORD elements, one per entry in the list
4785 item->u2.arglist == pval list of 4 PV_WORD elements for time values
4786 */
4787 destroy_pval(item->u1.list);
4788 break;
4789
4790 case PV_STATEMENTBLOCK:
4791 /* fields: item->u1.list == pval list of statements in block, one per entry in the list
4792 */
4793 destroy_pval(item->u1.list);
4794 break;
4795
4796 case PV_LOCALVARDEC:
4797 case PV_VARDEC:
4798 /* fields: item->u1.str == variable name
4799 item->u2.val == variable value to assign
4800 */
4801 if (item->u1.str)
4802 free(item->u1.str);
4803 if (item->u2.val)
4804 free(item->u2.val);
4805 break;
4806
4807 case PV_GOTO:
4808 /* fields: item->u1.list == pval list of PV_WORD target names, up to 3, in order as given by user.
4809 item->u1.list->u1.str == where the data on a PV_WORD will always be.
4810 */
4811
4812 destroy_pval(item->u1.list);
4813 break;
4814
4815 case PV_LABEL:
4816 /* fields: item->u1.str == label name
4817 */
4818 if (item->u1.str)
4819 free(item->u1.str);
4820 break;
4821
4822 case PV_FOR:
4823 /* fields: item->u1.for_init == a string containing the initializer
4824 item->u2.for_test == a string containing the loop test
4825 item->u3.for_inc == a string containing the loop increment
4826
4827 item->u4.for_statements == a pval list of statements in the for ()
4828 */
4829 if (item->u1.for_init)
4830 free(item->u1.for_init);
4831 if (item->u2.for_test)
4832 free(item->u2.for_test);
4833 if (item->u3.for_inc)
4834 free(item->u3.for_inc);
4835 destroy_pval(item->u4.for_statements);
4836 break;
4837
4838 case PV_WHILE:
4839 /* fields: item->u1.str == the while conditional, as supplied by user
4840
4841 item->u2.statements == a pval list of statements in the while ()
4842 */
4843 if (item->u1.str)
4844 free(item->u1.str);
4845 destroy_pval(item->u2.statements);
4846 break;
4847
4848 case PV_BREAK:
4849 /* fields: none
4850 */
4851 break;
4852
4853 case PV_RETURN:
4854 /* fields: none
4855 */
4856 break;
4857
4858 case PV_CONTINUE:
4859 /* fields: none
4860 */
4861 break;
4862
4863 case PV_IFTIME:
4864 /* fields: item->u1.list == the 4 time values, in PV_WORD structs, linked list
4865
4866 item->u2.statements == a pval list of statements in the if ()
4867 item->u3.else_statements == a pval list of statements in the else
4868 (could be zero)
4869 */
4870 destroy_pval(item->u1.list);
4871 destroy_pval(item->u2.statements);
4872 if (item->u3.else_statements) {
4873 destroy_pval(item->u3.else_statements);
4874 }
4875 break;
4876
4877 case PV_RANDOM:
4878 /* fields: item->u1.str == the random percentage, as supplied by user
4879
4880 item->u2.statements == a pval list of statements in the true part ()
4881 item->u3.else_statements == a pval list of statements in the else
4882 (could be zero)
4883 fall thru to If */
4884 case PV_IF:
4885 /* fields: item->u1.str == the if conditional, as supplied by user
4886
4887 item->u2.statements == a pval list of statements in the if ()
4888 item->u3.else_statements == a pval list of statements in the else
4889 (could be zero)
4890 */
4891 if (item->u1.str)
4892 free(item->u1.str);
4893 destroy_pval(item->u2.statements);
4894 if (item->u3.else_statements) {
4895 destroy_pval(item->u3.else_statements);
4896 }
4897 break;
4898
4899 case PV_SWITCH:
4900 /* fields: item->u1.str == the switch expression
4901
4902 item->u2.statements == a pval list of statements in the switch,
4903 (will be case statements, most likely!)
4904 */
4905 if (item->u1.str)
4906 free(item->u1.str);
4907 destroy_pval(item->u2.statements);
4908 break;
4909
4910 case PV_EXTENSION:
4911 /* fields: item->u1.str == the extension name, label, whatever it's called
4912
4913 item->u2.statements == a pval list of statements in the extension
4914 item->u3.hints == a char * hint argument
4915 item->u4.regexten == an int boolean. non-zero says that regexten was specified
4916 */
4917 if (item->u1.str)
4918 free(item->u1.str);
4919 if (item->u3.hints)
4920 free(item->u3.hints);
4921 destroy_pval(item->u2.statements);
4922 break;
4923
4924 case PV_IGNOREPAT:
4925 /* fields: item->u1.str == the ignorepat data
4926 */
4927 if (item->u1.str)
4928 free(item->u1.str);
4929 break;
4930
4931 case PV_GLOBALS:
4932 /* fields: item->u1.statements == pval list of statements, usually vardecs
4933 */
4934 destroy_pval(item->u1.statements);
4935 break;
4936 }
4937 free(item);
4938}
void destroy_pval(pval *item)
Definition pval.c:4940

Referenced by destroy_pval().

◆ find_context()

struct pval * find_context ( char *  name)

Definition at line 1953 of file pval.c.

1954{
1956 count_labels = 0;
1958 match_exten = "*"; /* don't really need to set these, shouldn't be reached */
1959 match_label = "*";
1960 return match_pval(current_db);
1961}
static const char * match_context
Definition pval.c:76
struct pval * match_pval(pval *item)
Definition pval.c:1811
static pval * current_db
Definition pval.c:72
static int count_labels
Definition pval.c:80
static int return_on_context_match
Definition pval.c:82
static const char * match_label
Definition pval.c:78
static const char * match_exten
Definition pval.c:77

Referenced by check_goto(), check_includes(), check_pval_item(), find_first_label_in_current_context(), find_label_in_current_context(), find_pval_goto_item(), and get_goto_target().

◆ handle_cli_ael_reload()

static char * handle_cli_ael_reload ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
)
static

Definition at line 231 of file pbx_ael.c.

232{
233 switch (cmd) {
234 case CLI_INIT:
235 e->command = "ael reload";
236 e->usage =
237 "Usage: ael reload\n"
238 " Reloads AEL configuration.\n";
239 return NULL;
240 case CLI_GENERATE:
241 return NULL;
242 }
243
244 if (a->argc != 2)
245 return CLI_SHOWUSAGE;
246
247#ifndef STANDALONE
248 /* Lock-Protected reload. It is VERY BAD to have simultaneous ael load_module() executing at the same time */
250#else
251 /* Lock-Protected reload not needed (and not available) when running standalone (Example: via aelparse cli tool). No reload contention is possible */
253#endif
254}
#define CLI_SHOWUSAGE
Definition cli.h:45
#define CLI_SUCCESS
Definition cli.h:44
@ CLI_INIT
Definition cli.h:152
@ CLI_GENERATE
Definition cli.h:153
#define CLI_FAILURE
Definition cli.h:46
@ AST_MODULE_RELOAD_SUCCESS
Definition module.h:110
enum ast_module_reload_result ast_module_reload(const char *name)
Reload asterisk modules.
Definition loader.c:1730
static int pbx_load_module(void)
Definition pbx_ael.c:147
char * command
Definition cli.h:186
const char * usage
Definition cli.h:177

References a, ast_module_reload(), AST_MODULE_RELOAD_SUCCESS, CLI_FAILURE, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, NULL, pbx_load_module(), and ast_cli_entry::usage.

◆ handle_cli_ael_set_debug()

static char * handle_cli_ael_set_debug ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
)
static

Definition at line 199 of file pbx_ael.c.

200{
201 switch (cmd) {
202 case CLI_INIT:
203 e->command = "ael set debug {read|tokens|contexts|off}";
204 e->usage =
205 "Usage: ael set debug {read|tokens|contexts|off}\n"
206 " Enable AEL read, token, or context debugging,\n"
207 " or disable all AEL debugging messages. Note: this\n"
208 " currently does nothing.\n";
209 return NULL;
210 case CLI_GENERATE:
211 return NULL;
212 }
213
214 if (a->argc != e->args)
215 return CLI_SHOWUSAGE;
216
217 if (!strcasecmp(a->argv[3], "read"))
219 else if (!strcasecmp(a->argv[3], "tokens"))
221 else if (!strcasecmp(a->argv[3], "contexts"))
223 else if (!strcasecmp(a->argv[3], "off"))
224 aeldebug = 0;
225 else
226 return CLI_SHOWUSAGE;
227
228 return CLI_SUCCESS;
229}
#define DEBUG_CONTEXTS
Definition pbx_ael.c:78
#define DEBUG_TOKENS
Definition pbx_ael.c:76
#define DEBUG_READ
Definition pbx_ael.c:75
static int aeldebug
Definition pbx_ael.c:120
int args
This gets set in ast_cli_register()
Definition cli.h:185

References a, aeldebug, ast_cli_entry::args, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, DEBUG_CONTEXTS, DEBUG_READ, DEBUG_TOKENS, NULL, and ast_cli_entry::usage.

◆ is_empty()

int is_empty ( char *  arg)

Definition at line 1981 of file pval.c.

1982{
1983 if (!arg)
1984 return 1;
1985 if (*arg == 0)
1986 return 1;
1987 while (*arg) {
1988 if (*arg != ' ' && *arg != '\t')
1989 return 0;
1990 arg++;
1991 }
1992 return 1;
1993}

◆ is_float()

int is_float ( char *  arg)

Definition at line 1963 of file pval.c.

1964{
1965 char *s;
1966 for (s=arg; *s; s++) {
1967 if (*s != '.' && (*s < '0' || *s > '9'))
1968 return 0;
1969 }
1970 return 1;
1971}

◆ is_int()

int is_int ( char *  arg)

Definition at line 1972 of file pval.c.

1973{
1974 char *s;
1975 for (s=arg; *s; s++) {
1976 if (*s < '0' || *s > '9')
1977 return 0;
1978 }
1979 return 1;
1980}

◆ load_module()

static int load_module ( void  )
static

Definition at line 271 of file pbx_ael.c.

272{
273 int pbx_load_res = AST_MODULE_LOAD_SUCCESS;
274
276#ifndef STANDALONE
278#endif
279 pbx_load_res = pbx_load_module();
280 if (AST_MODULE_LOAD_SUCCESS != pbx_load_res) {
281#ifndef STANDALONE
283#endif
285 }
286
287 return pbx_load_res;
288}
void ast_cli_unregister_multiple(void)
Definition ael_main.c:408
#define ast_cli_register_multiple(e, len)
Register multiple commands.
Definition cli.h:265
int ast_unregister_application(const char *app)
Unregister an application.
Definition pbx_app.c:392
@ AST_MODULE_LOAD_SUCCESS
Definition module.h:70
#define ast_register_application_xml(app, execute)
Register an application using XML documentation.
Definition module.h:640
static char * aelsub
Definition pbx_ael.c:125
static struct ast_cli_entry cli_ael[]
Definition pbx_ael.c:256
static int aelsub_exec(struct ast_channel *chan, const char *vdata)
Definition pbx_ael.c:127

References aelsub, aelsub_exec(), ARRAY_LEN, ast_cli_register_multiple, ast_cli_unregister_multiple(), AST_MODULE_LOAD_SUCCESS, ast_register_application_xml, ast_unregister_application(), cli_ael, and pbx_load_module().

◆ new_exten()

struct ael_extension * new_exten ( void  )

Definition at line 2930 of file pval.c.

2931{
2932 struct ael_extension *x = (struct ael_extension *)calloc(sizeof(struct ael_extension),1);
2933 return x;
2934}

Referenced by ast_compile_ael2(), and gen_prios().

◆ new_prio()

struct ael_priority * new_prio ( void  )

Definition at line 2924 of file pval.c.

2925{
2926 struct ael_priority *x = (struct ael_priority *)calloc(sizeof(struct ael_priority),1);
2927 return x;
2928}

Referenced by ast_compile_ael2(), and gen_prios().

◆ pbx_load_module()

static int pbx_load_module ( void  )
static

Definition at line 147 of file pbx_ael.c.

148{
149 int errs=0, sem_err=0, sem_warn=0, sem_note=0;
150 char *rfilename;
151 struct ast_context *local_contexts=NULL, *con;
153
154 struct pval *parse_tree;
155
156 ast_debug(1, "Starting AEL load process.\n");
157 if (config[0] == '/')
158 rfilename = (char *)config;
159 else {
160 rfilename = ast_alloca(strlen(config) + strlen(ast_config_AST_CONFIG_DIR) + 2);
161 sprintf(rfilename, "%s/%s", ast_config_AST_CONFIG_DIR, config);
162 }
163 if (access(rfilename,R_OK) != 0) {
164 ast_log(LOG_NOTICE, "File %s not found; AEL declining load\n", rfilename);
166 }
167
168 parse_tree = ael2_parse(rfilename, &errs);
169 ast_debug(1, "AEL load process: parsed config file name '%s'.\n", rfilename);
170 ael2_semantic_check(parse_tree, &sem_err, &sem_warn, &sem_note);
171 if (errs == 0 && sem_err == 0) {
172 ast_debug(1, "AEL load process: checked config file name '%s'.\n", rfilename);
174 if (ast_compile_ael2(&local_contexts, local_table, parse_tree)) {
175 ast_log(LOG_ERROR, "AEL compile failed! Aborting.\n");
176 destroy_pval(parse_tree); /* free up the memory */
178 }
179 ast_debug(1, "AEL load process: compiled config file name '%s'.\n", rfilename);
180
182 local_table = NULL; /* it's the dialplan global now */
184 ast_debug(1, "AEL load process: merged config file name '%s'.\n", rfilename);
185 for (con = ast_walk_contexts(NULL); con; con = ast_walk_contexts(con))
187 ast_debug(1, "AEL load process: verified config file name '%s'.\n", rfilename);
188 } else {
189 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);
190 destroy_pval(parse_tree); /* free up the memory */
192 }
193 destroy_pval(parse_tree); /* free up the memory */
194
196}
void ast_context_verify_includes(void)
Definition ael_main.c:395
void ast_merge_contexts_and_delete(void)
Definition ael_main.c:389
struct ast_context * ast_walk_contexts(void)
Definition ael_main.c:401
struct pval * ael2_parse(char *fname, int *errs)
Definition ael_lex.c:3344
void ael2_semantic_check(pval *item, int *errs, int *warns, int *notes)
Definition pval.c:2885
#define ast_alloca(size)
call __builtin_alloca to ensure we get gcc builtin semantics
Definition astmm.h:288
int ast_hashtab_newsize_java(struct ast_hashtab *tab)
Create a prime number roughly 2x the current table size.
Definition hashtab.c:127
#define ast_hashtab_create(initial_buckets, compare, resize, newsize, hash, do_locking)
Create the hashtable list.
Definition hashtab.h:254
int ast_hashtab_resize_java(struct ast_hashtab *tab)
Determines if a table resize should occur using the Java algorithm (if the table load factor is 75% o...
Definition hashtab.c:84
#define ast_debug(level,...)
Log a DEBUG message.
#define LOG_NOTICE
#define R_OK
@ AST_MODULE_LOAD_DECLINE
Module has failed to load, may be in an inconsistent state.
Definition module.h:78
const char * ast_config_AST_CONFIG_DIR
Definition options.c:152
int ast_hashtab_compare_contexts(const void *ah_a, const void *ah_b)
hashtable functions for contexts
Definition ael_main.c:589
unsigned int ast_hashtab_hash_contexts(const void *obj)
Definition ael_main.c:596
int ast_compile_ael2(struct ast_context **local_contexts, struct ast_hashtab *local_table, struct pval *root)
Definition pval.c:4413
static char * config
Definition pbx_ael.c:80
void destroy_pval(pval *item)
Definition pval.c:4940
static char * registrar
Definition pbx_ael.c:81

References ael2_parse(), ael2_semantic_check(), ast_alloca, ast_compile_ael2(), ast_config_AST_CONFIG_DIR, ast_context_verify_includes(), ast_debug, 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(), config, destroy_pval(), errs, local_contexts, local_table, LOG_ERROR, LOG_NOTICE, NULL, R_OK, and registrar.

Referenced by handle_cli_ael_reload(), load_module(), and reload().

◆ reload()

static int reload ( void  )
static

Definition at line 290 of file pbx_ael.c.

291{
292 /* Lock-Protected reload not needed because we're already being called from ast_module_reload() */
293 return pbx_load_module();
294}

References pbx_load_module().

◆ set_priorities()

void set_priorities ( struct ael_extension exten)

Definition at line 4187 of file pval.c.

4188{
4189 int i;
4190 struct ael_priority *pr;
4191 do {
4192 if (exten->is_switch)
4193 i = 10;
4194 else if (exten->regexten)
4195 i=2;
4196 else
4197 i=1;
4198
4199 for (pr=exten->plist; pr; pr=pr->next) {
4200 pr->priority_num = i;
4201
4202 if (!pr->origin || (pr->origin && pr->origin->type != PV_LABEL) ) /* Labels don't show up in the dialplan,
4203 but we want them to point to the right
4204 priority, which would be the next line
4205 after the label; */
4206 i++;
4207 }
4208
4210 } while ( exten );
4211}

Referenced by ast_compile_ael2().

◆ unload_module()

static int unload_module ( void  )
static

Definition at line 261 of file pbx_ael.c.

262{
265#ifndef STANDALONE
267#endif
268 return 0;
269}
void ast_context_destroy(void)
Definition ael_main.c:414

References aelsub, ARRAY_LEN, ast_cli_unregister_multiple(), ast_context_destroy(), ast_unregister_application(), cli_ael, NULL, and registrar.

Variable Documentation

◆ __mod_info

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "Asterisk Extension Language Compiler" , .key = ASTERISK_GPL_KEY , .buildopt_sum = AST_BUILDOPT_SUM, .support_level = AST_MODULE_SUPPORT_EXTENDED, .load = load_module, .unload = unload_module, .reload = reload, .requires = "res_ael_share", }
static

Definition at line 312 of file pbx_ael.c.

◆ aeldebug

int aeldebug = 0
static

Definition at line 120 of file pbx_ael.c.

Referenced by handle_cli_ael_set_debug().

◆ aelsub

char* aelsub = "AELSub"
static

Definition at line 125 of file pbx_ael.c.

Referenced by load_module(), and unload_module().

◆ ast_module_info

const struct ast_module_info* ast_module_info = &__mod_info
static

Definition at line 312 of file pbx_ael.c.

◆ cli_ael

struct ast_cli_entry cli_ael[]
static
Initial value:
= {
{ .handler = handle_cli_ael_reload , .summary = "Reload AEL configuration" ,},
{ .handler = handle_cli_ael_set_debug , .summary = "Enable AEL debugging flags" ,}
}
static char * handle_cli_ael_set_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition pbx_ael.c:199
static char * handle_cli_ael_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition pbx_ael.c:231

Definition at line 256 of file pbx_ael.c.

256 {
257 AST_CLI_DEFINE(handle_cli_ael_reload, "Reload AEL configuration"),
258 AST_CLI_DEFINE(handle_cli_ael_set_debug, "Enable AEL debugging flags")
259};
#define AST_CLI_DEFINE(fn, txt,...)
Definition cli.h:197

Referenced by load_module(), and unload_module().

◆ config

char* config = "extensions.ael"
static

Definition at line 80 of file pbx_ael.c.

Referenced by pbx_load_module().

◆ registrar

char* registrar = "pbx_ael"
static

Definition at line 81 of file pbx_ael.c.

Referenced by __ast_context_create(), __ast_context_destroy(), __ast_context_destroy(), ast_add_extension(), ast_add_extension2(), ast_add_extension2(), ast_add_extension2(), ast_add_extension2_lockopt(), ast_add_extension2_nolock(), ast_add_extension_nolock(), ast_context_add_ignorepat(), ast_context_add_ignorepat2(), ast_context_add_ignorepat2(), ast_context_add_ignorepat2(), ast_context_add_include(), ast_context_add_include2(), ast_context_add_include2(), ast_context_add_switch(), ast_context_add_switch2(), ast_context_add_switch2(), ast_context_add_switch2(), ast_context_create(), ast_context_destroy(), ast_context_destroy_by_name(), ast_context_find_or_create(), ast_context_find_or_create(), ast_context_find_or_create(), ast_context_remove_extension(), ast_context_remove_extension2(), ast_context_remove_extension_callerid(), ast_context_remove_extension_callerid2(), ast_context_remove_ignorepat(), ast_context_remove_ignorepat2(), ast_context_remove_include(), ast_context_remove_include2(), ast_context_remove_switch(), ast_context_remove_switch2(), ast_merge_contexts_and_delete(), ast_merge_contexts_and_delete(), AST_TEST_DEFINE(), context_merge(), context_merge_incls_swits_igps_other_registrars(), ignorepat_alloc(), include_alloc(), localized_add_extension2(), localized_context_add_ignorepat2(), localized_context_add_include2(), localized_context_add_switch2(), localized_context_destroy(), localized_context_find_or_create(), localized_merge_contexts_and_delete(), parking_add_extension(), parking_lot_cfg_create_extensions(), parking_lot_cfg_remove_extensions(), pbx_load_module(), sw_alloc(), and unload_module().