Wed Jan 8 2020 09:50:16

Asterisk developer's documentation


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"

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)
 
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)
 
struct pvalfind_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)
 
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 = "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_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

#define DEBUG_CONTEXTS   (1 << 3)

Definition at line 84 of file pbx_ael.c.

Referenced by handle_cli_ael_set_debug().

#define DEBUG_MACROS   (1 << 2)

Definition at line 83 of file pbx_ael.c.

Referenced by handle_cli_ael_set_debug().

#define DEBUG_READ   (1 << 0)

Definition at line 81 of file pbx_ael.c.

Referenced by handle_cli_ael_set_debug().

#define DEBUG_TOKENS   (1 << 1)

Definition at line 82 of file pbx_ael.c.

Referenced by handle_cli_ael_set_debug().

Function Documentation

static void __reg_module ( void  )
static

Definition at line 303 of file pbx_ael.c.

307 {
static void __unreg_module ( void  )
static

Definition at line 303 of file pbx_ael.c.

307 {
void add_extensions ( struct ael_extension exten)

Definition at line 4251 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, ael_priority::app, ael_priority::appargs, ast_add_extension2(), ast_free_ptr(), ast_log(), AST_MAX_EXTENSION, ael_extension::cidmatch, ael_extension::context, pval::else_statements, ael_priority::exten, ael_priority::goto_false, ael_priority::goto_true, ael_extension::hints, last, LOG_WARNING, ael_extension::name, ael_priority::next, ael_extension::next_exten, ael_priority::origin, pbx_substitute_variables_helper(), ael_extension::plist, PRIORITY_HINT, ael_priority::priority_num, PV_IFTIME, PV_SWITCH, pval::str, strdup, pval::type, ael_priority::type, pval::u1, and pval::u3.

4252 {
4253  struct ael_priority *pr;
4254  char *label=0;
4255  char realext[AST_MAX_EXTENSION];
4256  if (!exten) {
4257  ast_log(LOG_WARNING, "This file is Empty!\n" );
4258  return;
4259  }
4260  do {
4261  struct ael_priority *last = 0;
4262 
4263  pbx_substitute_variables_helper(NULL, exten->name, realext, sizeof(realext) - 1);
4264  if (exten->hints) {
4265  if (ast_add_extension2(exten->context, 0 /*no replace*/, realext, PRIORITY_HINT, NULL, exten->cidmatch,
4266  exten->hints, NULL, ast_free_ptr, registrar)) {
4267  ast_log(LOG_WARNING, "Unable to add step at priority 'hint' of extension '%s'\n",
4268  exten->name);
4269  }
4270  }
4271 
4272  for (pr=exten->plist; pr; pr=pr->next) {
4273  char app[2000];
4274  char appargs[2000];
4275 
4276  /* before we can add the extension, we need to prep the app/appargs;
4277  the CONTROL types need to be done after the priority numbers are calculated.
4278  */
4279  if (pr->type == AEL_LABEL) /* don't try to put labels in the dialplan! */ {
4280  last = pr;
4281  continue;
4282  }
4283 
4284  if (pr->app)
4285  strcpy(app, pr->app);
4286  else
4287  app[0] = 0;
4288  if (pr->appargs )
4289  strcpy(appargs, pr->appargs);
4290  else
4291  appargs[0] = 0;
4292  switch( pr->type ) {
4293  case AEL_APPCALL:
4294  /* easy case. Everything is all set up */
4295  break;
4296 
4297  case AEL_CONTROL1: /* FOR loop, WHILE loop, BREAK, CONTINUE, IF, IFTIME */
4298  /* simple, unconditional goto. */
4299  strcpy(app,"Goto");
4300  if (pr->goto_true->origin && pr->goto_true->origin->type == PV_SWITCH ) {
4301  snprintf(appargs,sizeof(appargs),"%s,%d", pr->goto_true->exten->name, pr->goto_true->priority_num);
4302  } else if (pr->goto_true->origin && pr->goto_true->origin->type == PV_IFTIME && pr->goto_true->origin->u3.else_statements ) {
4303  snprintf(appargs,sizeof(appargs),"%d", pr->goto_true->priority_num+1);
4304  } else
4305  snprintf(appargs,sizeof(appargs),"%d", pr->goto_true->priority_num);
4306  break;
4307 
4308  case AEL_FOR_CONTROL: /* WHILE loop test, FOR loop test */
4309  strcpy(app,"GotoIf");
4310  snprintf(appargs,sizeof(appargs),"%s?%d:%d", pr->appargs, pr->priority_num+1, pr->goto_false->priority_num);
4311  break;
4312 
4313  case AEL_IF_CONTROL:
4314  strcpy(app,"GotoIf");
4315  if (pr->origin->u3.else_statements )
4316  snprintf(appargs,sizeof(appargs),"%s?%d:%d", pr->appargs, pr->priority_num+1, pr->goto_false->priority_num+1);
4317  else
4318  snprintf(appargs,sizeof(appargs),"%s?%d:%d", pr->appargs, pr->priority_num+1, pr->goto_false->priority_num);
4319  break;
4320 
4321  case AEL_RAND_CONTROL:
4322  strcpy(app,"Random");
4323  snprintf(appargs,sizeof(appargs),"%s:%d", pr->appargs, pr->goto_true->priority_num+1);
4324  break;
4325 
4326  case AEL_IFTIME_CONTROL:
4327  strcpy(app,"GotoIfTime");
4328  snprintf(appargs,sizeof(appargs),"%s?%d", pr->appargs, pr->priority_num+2);
4329  break;
4330 
4331  case AEL_RETURN:
4332  strcpy(app,"Return");
4333  appargs[0] = 0;
4334  break;
4335 
4336  default:
4337  break;
4338  }
4339  if (last && last->type == AEL_LABEL ) {
4340  label = last->origin->u1.str;
4341  }
4342  else
4343  label = 0;
4344 
4345  if (ast_add_extension2(exten->context, 0 /*no replace*/, realext, pr->priority_num, (label?label:NULL), exten->cidmatch,
4346  app, strdup(appargs), ast_free_ptr, registrar)) {
4347  ast_log(LOG_WARNING, "Unable to add step at priority '%d' of extension '%s'\n", pr->priority_num,
4348  exten->name);
4349  }
4350  last = pr;
4351  }
4352  exten = exten->next_exten;
4353  } while ( exten );
4354 }
union pval::@198 u1
void pbx_substitute_variables_helper(struct ast_channel *c, const char *cp1, char *cp2, int count)
Definition: pbx.c:4676
struct pval * origin
Definition: ael_structs.h:95
Definition: pval.h:32
struct ael_priority * goto_true
Definition: ael_structs.h:98
#define LOG_WARNING
Definition: logger.h:144
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)
Add an extension to an extension context, this time with an ast_context *.
Definition: pbx.c:9052
struct ael_priority * plist
Definition: ael_structs.h:115
struct ael_priority * goto_false
Definition: ael_structs.h:99
char * appargs
Definition: ael_structs.h:93
void ast_free_ptr(void *ptr)
struct ael_extension * next_exten
Definition: ael_structs.h:117
union pval::@200 u3
struct ast_context * context
Definition: ael_structs.h:113
char * cidmatch
Definition: ael_structs.h:106
static const char app[]
Definition: app_adsiprog.c:49
struct sla_ringing_trunk * last
Definition: app_meetme.c:965
#define AST_MAX_EXTENSION
Definition: channel.h:135
struct ael_extension * exten
Definition: ael_structs.h:96
char * str
Definition: pval.h:59
#define PRIORITY_HINT
Definition: pbx.h:53
char * app
Definition: ael_structs.h:92
static char * registrar
Definition: pval.c:72
struct pval * else_statements
Definition: pval.h:78
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207
struct ael_priority * next
Definition: ael_structs.h:100
pvaltype type
Definition: pval.h:50
int priority_num
Definition: ael_structs.h:89
Definition: pval.h:30
ael_priority_type type
Definition: ael_structs.h:90
#define strdup(a)
Definition: astmm.h:106
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().

136 {
137  char buf[256], *data = ast_strdupa(vdata);
138  struct ast_app *gosub = pbx_findapp("Gosub");
140  AST_APP_ARG(name);
141  AST_APP_ARG(args);
142  );
143 
144  if (gosub) {
146  snprintf(buf, sizeof(buf), "%s,~~s~~,1(%s)", args.name, args.args);
147  return pbx_exec(chan, gosub, buf);
148  }
149  return -1;
150 }
struct ast_app * pbx_findapp(const char *app)
Look up an application.
Definition: pbx.c:1537
int pbx_exec(struct ast_channel *c, struct ast_app *app, const char *data)
Execute an application.
Definition: pbx.c:1497
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application&#39;s arguments.
Definition: app.h:572
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: utils.h:663
static struct @350 args
static const char name[]
ast_app: A registered application
Definition: pbx.c:971
#define AST_STANDARD_RAW_ARGS(args, parse)
Definition: app.h:606
#define AST_APP_ARG(name)
Define an application argument.
Definition: app.h:555
int ast_compile_ael2 ( struct ast_context **  local_contexts,
struct ast_hashtab local_table,
struct pval root 
)

Definition at line 4451 of file pval.c.

References add_extensions(), AEL_APPCALL, AEL_LABEL, ael_priority::app, ael_priority::appargs, pval::arglist, ARRAY_LEN, ast_compat_app_set, ast_context_add_ignorepat2(), ast_context_add_include2(), ast_context_add_switch2(), ast_context_find_or_create(), ast_custom_function_find(), ast_get_context_name(), attach_exten(), buf2, ael_extension::cidmatch, context, ael_extension::context, context_used(), destroy_extensions(), exten, fix_gotos_in_extensions(), gen_prios(), pval::hints, ael_extension::hints, linkprio(), pval::list, pval::macro_statements, ael_extension::name, new_exten(), new_prio(), pval::next, ael_extension::next_exten, ael_priority::origin, pbx_builtin_setvar(), ael_extension::plist_last, ael_priority::priority_num, PV_CONTEXT, PV_ESWITCHES, PV_EXTENSION, PV_GLOBALS, PV_IGNOREPAT, PV_INCLUDES, PV_MACRO, PV_SWITCHES, pval::regexten, ael_extension::regexten, remove_spaces_before_equals(), ael_extension::return_needed, set_priorities(), pval::statements, pval::str, strdup, pval::type, ael_priority::type, pval::u1, pval::u2, pval::u3, pval::u4, and pval::val.

4452 {
4453  pval *p,*p2;
4454  struct ast_context *context;
4455  char buf[2000];
4456  struct ael_extension *exten;
4457  struct ael_extension *exten_list = 0;
4458 
4459  for (p=root; p; p=p->next ) { /* do the globals first, so they'll be there
4460  when we try to eval them */
4461  switch (p->type) {
4462  case PV_GLOBALS:
4463  /* just VARDEC elements */
4464  for (p2=p->u1.list; p2; p2=p2->next) {
4465  char buf2[2000];
4466  snprintf(buf2,sizeof(buf2),"%s=%s", p2->u1.str, p2->u2.val);
4467  pbx_builtin_setvar(NULL, buf2);
4468  }
4469  break;
4470  default:
4471  break;
4472  }
4473  }
4474 
4475  for (p=root; p; p=p->next ) {
4476  pval *lp;
4477  int argc;
4478 
4479  switch (p->type) {
4480  case PV_MACRO:
4481 
4482  context = ast_context_find_or_create(local_contexts, local_table, p->u1.str, registrar);
4483 
4484  exten = new_exten();
4485  exten->context = context;
4486  exten->name = strdup("~~s~~");
4487  argc = 1;
4488  for (lp=p->u2.arglist; lp; lp=lp->next) {
4489  /* for each arg, set up a "Set" command */
4490  struct ael_priority *np2 = new_prio();
4491  np2->type = AEL_APPCALL;
4492  if (!ast_compat_app_set) {
4493  np2->app = strdup("MSet");
4494  } else {
4495  np2->app = strdup("Set");
4496  }
4497  snprintf(buf,sizeof(buf),"LOCAL(%s)=${ARG%d}", lp->u1.str, argc++);
4499  np2->appargs = strdup(buf);
4500  linkprio(exten, np2, NULL);
4501  }
4502 
4503  /* CONTAINS APPCALLS, CATCH, just like extensions... */
4504  if (gen_prios(exten, p->u1.str, p->u3.macro_statements, 0, context)) {
4505  return -1;
4506  }
4507  if (exten->return_needed) { /* most likely, this will go away */
4508  struct ael_priority *np2 = new_prio();
4509  np2->type = AEL_APPCALL;
4510  np2->app = strdup("NoOp");
4511  snprintf(buf,sizeof(buf),"End of Macro %s-%s",p->u1.str, exten->name);
4512  np2->appargs = strdup(buf);
4513  linkprio(exten, np2, NULL);
4514  exten-> return_target = np2;
4515  }
4516 
4517  set_priorities(exten);
4518  attach_exten(&exten_list, exten);
4519  break;
4520 
4521  case PV_GLOBALS:
4522  /* already done */
4523  break;
4524 
4525  case PV_CONTEXT:
4526  context = ast_context_find_or_create(local_contexts, local_table, p->u1.str, registrar);
4527 
4528  /* contexts contain: ignorepat, includes, switches, eswitches, extensions, */
4529  for (p2=p->u2.statements; p2; p2=p2->next) {
4530  pval *p3;
4531  char *s3;
4532 
4533  switch (p2->type) {
4534  case PV_EXTENSION:
4535  exten = new_exten();
4536  exten->name = strdup(p2->u1.str);
4537  exten->context = context;
4538 
4539  if( (s3=strchr(exten->name, '/') ) != 0 )
4540  {
4541  *s3 = 0;
4542  exten->cidmatch = s3+1;
4543  }
4544 
4545  if ( p2->u3.hints )
4546  exten->hints = strdup(p2->u3.hints);
4547  exten->regexten = p2->u4.regexten;
4548  if (gen_prios(exten, p->u1.str, p2->u2.statements, 0, context)) {
4549  return -1;
4550  }
4551  if (exten->return_needed) { /* returns don't generate a goto eoe (end of extension) any more, just a Return() app call) */
4552  struct ael_priority *np2 = new_prio();
4553  np2->type = AEL_APPCALL;
4554  np2->app = strdup("NoOp");
4555  snprintf(buf,sizeof(buf),"End of Extension %s", exten->name);
4556  np2->appargs = strdup(buf);
4557  linkprio(exten, np2, NULL);
4558  exten-> return_target = np2;
4559  }
4560  /* is the last priority in the extension a label? Then add a trailing no-op */
4561  if ( exten->plist_last && exten->plist_last->type == AEL_LABEL ) {
4562  struct ael_priority *np2 = new_prio();
4563  np2->type = AEL_APPCALL;
4564  np2->app = strdup("NoOp");
4565  snprintf(buf,sizeof(buf),"A NoOp to follow a trailing label %s", exten->plist_last->origin->u1.str);
4566  np2->appargs = strdup(buf);
4567  linkprio(exten, np2, NULL);
4568  }
4569 
4570  set_priorities(exten);
4571  attach_exten(&exten_list, exten);
4572  break;
4573 
4574  case PV_IGNOREPAT:
4575  ast_context_add_ignorepat2(context, p2->u1.str, registrar);
4576  break;
4577 
4578  case PV_INCLUDES:
4579  for (p3 = p2->u1.list; p3 ;p3=p3->next) {
4580  if ( p3->u2.arglist ) {
4581  snprintf(buf,sizeof(buf), "%s,%s,%s,%s,%s",
4582  p3->u1.str,
4583  p3->u2.arglist->u1.str,
4584  p3->u2.arglist->next->u1.str,
4585  p3->u2.arglist->next->next->u1.str,
4586  p3->u2.arglist->next->next->next->u1.str);
4587  ast_context_add_include2(context, buf, registrar);
4588  } else
4589  ast_context_add_include2(context, p3->u1.str, registrar);
4590  }
4591  break;
4592 
4593  case PV_SWITCHES:
4594  for (p3 = p2->u1.list; p3 ;p3=p3->next) {
4595  char *c = strchr(p3->u1.str, '/');
4596  if (c) {
4597  *c = '\0';
4598  c++;
4599  } else
4600  c = "";
4601 
4602  ast_context_add_switch2(context, p3->u1.str, c, 0, registrar);
4603  }
4604  break;
4605 
4606  case PV_ESWITCHES:
4607  for (p3 = p2->u1.list; p3 ;p3=p3->next) {
4608  char *c = strchr(p3->u1.str, '/');
4609  if (c) {
4610  *c = '\0';
4611  c++;
4612  } else
4613  c = "";
4614 
4615  ast_context_add_switch2(context, p3->u1.str, c, 1, registrar);
4616  }
4617  break;
4618  default:
4619  break;
4620  }
4621  }
4622 
4623  break;
4624 
4625  default:
4626  /* huh? what? */
4627  break;
4628 
4629  }
4630  }
4631 
4632  /* Create default "h" bubble context */
4633  if (ast_custom_function_find("DIALPLAN_EXISTS") && ast_custom_function_find("STACK_PEEK")) {
4634  int i;
4635  const char *h_context = "ael-builtin-h-bubble";
4636  struct ael_priority *np;
4637  struct {
4638  int priority;
4639  const char *app;
4640  const char *arg;
4641  } steps[] = {
4642  /* Start high, to avoid conflict with existing h extensions */
4643  { 1, "Goto", "9991" },
4644  /* Save the context, because after the StackPop, it disappears */
4645  { 9991, "Set", "~~parentcxt~~=${STACK_PEEK(1,c,1)}" },
4646  /* If we're not in a Gosub frame, exit */
4647  { 9992, "GotoIf", "$[\"${~~parentcxt~~}\"=\"\"]?9996" },
4648  /* Check for an "h" extension in that context */
4649  { 9993, "GotoIf", "${DIALPLAN_EXISTS(${~~parentcxt~~},h,1)}?9994:9996" },
4650  /* Pop off the stack frame to prevent an infinite loop */
4651  { 9994, "StackPop", "" },
4652  /* Finally, go there. */
4653  { 9995, "Goto", "${~~parentcxt~~},h,1" },
4654  /* Just an empty priority for jumping out early */
4655  { 9996, "NoOp", "" }
4656  };
4657  context = ast_context_find_or_create(local_contexts, local_table, h_context, registrar);
4658  if (context_used(exten_list, context)) {
4659  int found = 0;
4660  while (!found) {
4661  /* Pick a new context name that is not used. */
4662  char h_context_template[] = "/tmp/ael-builtin-h-bubble-XXXXXX";
4663  int fd = mkstemp(h_context_template);
4664  unlink(h_context_template);
4665  close(fd);
4666  context = ast_context_find_or_create(local_contexts, local_table, h_context_template + 5, registrar);
4667  found = !context_used(exten_list, context);
4668  }
4669  h_context = ast_get_context_name(context);
4670  }
4671  exten = new_exten();
4672  exten->context = context;
4673  exten->name = strdup("h");
4674 
4675  for (i = 0; i < ARRAY_LEN(steps); i++) {
4676  np = new_prio();
4677  np->type = AEL_APPCALL;
4678  np->priority_num = steps[i].priority;
4679  np->app = strdup(steps[i].app);
4680  np->appargs = strdup(steps[i].arg);
4681  linkprio(exten, np, NULL);
4682  }
4683  attach_exten(&exten_list, exten);
4684 
4685  /* Include the default "h" bubble context in each macro context */
4686  for (exten = exten_list; exten; exten = exten->next_exten) {
4687  /* All macros contain a "~~s~~" extension, and it's the first created. If
4688  * we perchance get a non-macro context, it's no big deal; the logic is
4689  * designed to exit out smoothly if not called from within a Gosub. */
4690  if (!strcmp(exten->name, "~~s~~")) {
4691  ast_context_add_include2(exten->context, h_context, registrar);
4692  }
4693  }
4694  }
4695 
4696  /* moved these from being done after a macro or extension were processed,
4697  to after all processing is done, for the sake of fixing gotos to labels inside cases... */
4698  /* I guess this would be considered 2nd pass of compiler now... */
4699  fix_gotos_in_extensions(exten_list); /* find and fix extension ref in gotos to labels that are in case statements */
4700  add_extensions(exten_list); /* actually makes calls to create priorities in ast_contexts -- feeds dialplan to asterisk */
4701  destroy_extensions(exten_list); /* all that remains is an empty husk, discard of it as is proper */
4702 
4703  return 0;
4704 }
union pval::@198 u1
static int context_used(struct ael_extension *exten_list, struct ast_context *context)
Definition: pval.c:4436
static char exten[AST_MAX_EXTENSION]
Definition: chan_alsa.c:109
int regexten
Definition: pval.h:90
int ast_context_add_include2(struct ast_context *con, const char *include, const char *registrar)
Add a context include.
Definition: pbx.c:8411
struct ael_priority * new_prio(void)
Definition: pval.c:2931
#define ARRAY_LEN(a)
Definition: isdn_lib.c:42
struct pval * origin
Definition: ael_structs.h:95
struct pval * list
Definition: pval.h:60
static void fix_gotos_in_extensions(struct ael_extension *exten)
Definition: pval.c:4393
struct ael_priority * plist_last
Definition: ael_structs.h:116
void add_extensions(struct ael_extension *exten)
Definition: pval.c:4251
struct pval * statements
Definition: pval.h:61
#define ast_compat_app_set
Definition: options.h:144
static struct ast_threadstorage buf2
char * appargs
Definition: ael_structs.h:93
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: pbx.c:8494
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:3348
struct ael_extension * next_exten
Definition: ael_structs.h:117
union pval::@200 u3
union pval::@199 u2
struct ast_context * context
Definition: ael_structs.h:113
struct ael_extension * new_exten(void)
Definition: pval.c:2937
char * cidmatch
Definition: ael_structs.h:106
char * val
Definition: pval.h:70
static const char app[]
Definition: app_adsiprog.c:49
char * str
Definition: pval.h:59
Definition: pval.h:48
int ast_context_add_ignorepat2(struct ast_context *con, const char *ignorepat, const char *registrar)
Definition: pbx.c:8611
const char * ast_get_context_name(struct ast_context *con)
Definition: pbx.c:11073
struct ast_custom_function * ast_custom_function_find(const char *name)
Definition: pbx.c:3800
char * hints
Definition: pval.h:81
char * app
Definition: ael_structs.h:92
static char * registrar
Definition: pval.c:72
union pval::@201 u4
struct pval * arglist
Definition: pval.h:68
Definition: pval.h:9
pvaltype type
Definition: pval.h:50
static void attach_exten(struct ael_extension **list, struct ael_extension *newmem)
Definition: pval.c:4356
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 &#39;=&#39; character...
Definition: pbx.c:10603
void destroy_extensions(struct ael_extension *exten)
Definition: pval.c:2985
int priority_num
Definition: ael_structs.h:89
static void remove_spaces_before_equals(char *str)
Definition: pval.c:3045
void set_priorities(struct ael_extension *exten)
Definition: pval.c:4225
struct pval * next
Definition: pval.h:93
ael_priority_type type
Definition: ael_structs.h:90
static char context[AST_MAX_CONTEXT]
Definition: chan_alsa.c:107
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:7726
#define strdup(a)
Definition: astmm.h:106
void linkprio(struct ael_extension *exten, struct ael_priority *prio, struct ael_extension *mother_exten)
Definition: pval.c:2943
ast_context: An extension context
Definition: pbx.c:955
struct pval * macro_statements
Definition: pval.h:79
void ast_expr_clear_extra_error_info ( void  )

Definition at line 2475 of file ast_expr2f.c.

2476 {
2478  extra_error_message[0] = 0;
2479 }
int extra_error_message_supplied
Definition: ast_expr2f.c:2465
char extra_error_message[4095]
Definition: ast_expr2f.c:2464
void ast_expr_register_extra_error_info ( char *  errmsg)

Definition at line 2469 of file ast_expr2f.c.

2470 {
2472  strcpy(extra_error_message, message);
2473 }
int extra_error_message_supplied
Definition: ast_expr2f.c:2465
char extra_error_message[4095]
Definition: ast_expr2f.c:2464
int check_app_args ( pval appcall,
pval arglist,
struct argapp app 
)

Definition at line 2137 of file pval.c.

References ast_log(), pval::endline, pval::filename, LOG_WARNING, pval::next, pval::startline, pval::str, and pval::u1.

2138 {
2139 #ifdef AAL_ARGCHECK
2140  struct argdesc *ad = app->args;
2141  pval *pa;
2142  int z;
2143 
2144  for (pa = arglist; pa; pa=pa->next) {
2145  if (!ad) {
2146  ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: Extra argument %s not in application call to %s !\n",
2147  arglist->filename, arglist->startline, arglist->endline, pa->u1.str, app->name);
2148  warns++;
2149  return 1;
2150  } else {
2151  /* find the first entry in the ad list that will match */
2152  do {
2153  if ( ad->dtype == ARGD_VARARG ) /* once we hit the VARARG, all bets are off. Discontinue the comparisons */
2154  break;
2155 
2156  z= option_matches( ad, pa, app);
2157  if (!z) {
2158  if ( !arglist )
2159  arglist=appcall;
2160 
2161  if (ad->type == ARGD_REQUIRED) {
2162  ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: Required argument %s not in application call to %s !\n",
2163  arglist->filename, arglist->startline, arglist->endline, ad->dtype==ARGD_OPTIONSET?"options":ad->name, app->name);
2164  warns++;
2165  return 1;
2166  }
2167  } else if (z && ad->dtype == ARGD_OPTIONSET) {
2168  option_matches_j( ad, pa, app);
2169  }
2170  ad = ad->next;
2171  } while (ad && !z);
2172  }
2173  }
2174  /* any app nodes left, that are not optional? */
2175  for ( ; ad; ad=ad->next) {
2176  if (ad->type == ARGD_REQUIRED && ad->dtype != ARGD_VARARG) {
2177  if ( !arglist )
2178  arglist=appcall;
2179  ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: Required argument %s not in application call to %s !\n",
2180  arglist->filename, arglist->startline, arglist->endline, ad->dtype==ARGD_OPTIONSET?"options":ad->name, app->name);
2181  warns++;
2182  return 1;
2183  }
2184  }
2185  return 0;
2186 #else
2187  return 0;
2188 #endif
2189 }
union pval::@198 u1
#define LOG_WARNING
Definition: logger.h:144
int startline
Definition: pval.h:51
char * filename
Definition: pval.h:55
char * str
Definition: pval.h:59
Definition: pval.h:48
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207
static int warns
Definition: pval.c:67
struct pval * next
Definition: pval.h:93
int endline
Definition: pval.h:52
void check_pval ( pval item,
struct argapp apps,
int  in_globals 
)

Definition at line 2872 of file pval.c.

References check_pval_item(), and pval::next.

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

Definition at line 2364 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(), 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, argapp::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.

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

Definition at line 2191 of file pval.c.

References ast_log(), ast_strdupa, calloc, pval::endcol, pval::endline, pval::filename, LOG_WARNING, pval::next, argapp::next, PV_APPLICATION_CALL, PV_CASE, PV_DEFAULT, PV_PATTERN, PV_STATEMENTBLOCK, pval::startcol, pval::startline, pval::statements, pval::str, strdup, pval::type, pval::u1, and pval::u2.

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

Definition at line 2985 of file pval.c.

References ael_priority::app, ael_priority::appargs, 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.

2986 {
2987  struct ael_extension *ne, *nen;
2988  for (ne=exten; ne; ne=nen) {
2989  struct ael_priority *pe, *pen;
2990 
2991  if (ne->name)
2992  free(ne->name);
2993 
2994  /* cidmatch fields are allocated with name, and freed when
2995  the name field is freed. Don't do a free for this field,
2996  unless you LIKE to see a crash! */
2997 
2998  if (ne->hints)
2999  free(ne->hints);
3000 
3001  for (pe=ne->plist; pe; pe=pen) {
3002  pen = pe->next;
3003  if (pe->app)
3004  free(pe->app);
3005  pe->app = 0;
3006  if (pe->appargs)
3007  free(pe->appargs);
3008  pe->appargs = 0;
3009  pe->origin = 0;
3010  pe->goto_true = 0;
3011  pe->goto_false = 0;
3012  free(pe);
3013  }
3014  nen = ne->next_exten;
3015  ne->next_exten = 0;
3016  ne->plist =0;
3017  ne->plist_last = 0;
3018  ne->next_exten = 0;
3019  ne->loop_break = 0;
3020  ne->loop_continue = 0;
3021  free(ne);
3022  }
3023 }
struct pval * origin
Definition: ael_structs.h:95
struct ael_priority * goto_true
Definition: ael_structs.h:98
struct ael_priority * plist_last
Definition: ael_structs.h:116
struct ael_priority * plist
Definition: ael_structs.h:115
struct ael_priority * goto_false
Definition: ael_structs.h:99
char * appargs
Definition: ael_structs.h:93
struct ael_extension * next_exten
Definition: ael_structs.h:117
struct ael_priority * loop_break
Definition: ael_structs.h:119
char * app
Definition: ael_structs.h:92
#define free(a)
Definition: astmm.h:94
struct ael_priority * loop_continue
Definition: ael_structs.h:120
struct ael_priority * next
Definition: ael_structs.h:100
void destroy_pval ( pval item)

Definition at line 4979 of file pval.c.

References destroy_pval_item(), and pval::next.

4980 {
4981  pval *i,*nxt;
4982 
4983  for (i=item; i; i=nxt) {
4984  nxt = i->next;
4985 
4986  destroy_pval_item(i);
4987  }
4988 }
void destroy_pval_item(pval *item)
Definition: pval.c:4711
Definition: pval.h:48
struct pval * next
Definition: pval.h:93
void destroy_pval_item ( pval item)

Definition at line 4711 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.

4712 {
4713  if (item == NULL) {
4714  ast_log(LOG_WARNING, "null item\n");
4715  return;
4716  }
4717 
4718  if (item->filename)
4719  free(item->filename);
4720 
4721  switch (item->type) {
4722  case PV_WORD:
4723  /* fields: item->u1.str == string associated with this (word). */
4724  if (item->u1.str )
4725  free(item->u1.str);
4726  if ( item->u2.arglist )
4727  destroy_pval(item->u2.arglist);
4728  break;
4729 
4730  case PV_MACRO:
4731  /* fields: item->u1.str == name of macro
4732  item->u2.arglist == pval list of PV_WORD arguments of macro, as given by user
4733  item->u2.arglist->u1.str == argument
4734  item->u2.arglist->next == next arg
4735 
4736  item->u3.macro_statements == pval list of statements in macro body.
4737  */
4738  destroy_pval(item->u2.arglist);
4739  if (item->u1.str )
4740  free(item->u1.str);
4742  break;
4743 
4744  case PV_CONTEXT:
4745  /* fields: item->u1.str == name of context
4746  item->u2.statements == pval list of statements in context body
4747  item->u3.abstract == int 1 if an abstract keyword were present
4748  */
4749  if (item->u1.str)
4750  free(item->u1.str);
4751  destroy_pval(item->u2.statements);
4752  break;
4753 
4754  case PV_MACRO_CALL:
4755  /* fields: item->u1.str == name of macro to call
4756  item->u2.arglist == pval list of PV_WORD arguments of macro call, as given by user
4757  item->u2.arglist->u1.str == argument
4758  item->u2.arglist->next == next arg
4759  */
4760  if (item->u1.str)
4761  free(item->u1.str);
4762  destroy_pval(item->u2.arglist);
4763  break;
4764 
4765  case PV_APPLICATION_CALL:
4766  /* fields: item->u1.str == name of application to call
4767  item->u2.arglist == pval list of PV_WORD arguments of macro call, as given by user
4768  item->u2.arglist->u1.str == argument
4769  item->u2.arglist->next == next arg
4770  */
4771  if (item->u1.str)
4772  free(item->u1.str);
4773  destroy_pval(item->u2.arglist);
4774  break;
4775 
4776  case PV_CASE:
4777  /* fields: item->u1.str == value of case
4778  item->u2.statements == pval list of statements under the case
4779  */
4780  if (item->u1.str)
4781  free(item->u1.str);
4782  destroy_pval(item->u2.statements);
4783  break;
4784 
4785  case PV_PATTERN:
4786  /* fields: item->u1.str == value of case
4787  item->u2.statements == pval list of statements under the case
4788  */
4789  if (item->u1.str)
4790  free(item->u1.str);
4791  destroy_pval(item->u2.statements);
4792  break;
4793 
4794  case PV_DEFAULT:
4795  /* fields:
4796  item->u2.statements == pval list of statements under the case
4797  */
4798  destroy_pval(item->u2.statements);
4799  break;
4800 
4801  case PV_CATCH:
4802  /* fields: item->u1.str == name of extension to catch
4803  item->u2.statements == pval list of statements in context body
4804  */
4805  if (item->u1.str)
4806  free(item->u1.str);
4807  destroy_pval(item->u2.statements);
4808  break;
4809 
4810  case PV_SWITCHES:
4811  /* fields: item->u1.list == pval list of PV_WORD elements, one per entry in the list
4812  */
4813  destroy_pval(item->u1.list);
4814  break;
4815 
4816  case PV_ESWITCHES:
4817  /* fields: item->u1.list == pval list of PV_WORD elements, one per entry in the list
4818  */
4819  destroy_pval(item->u1.list);
4820  break;
4821 
4822  case PV_INCLUDES:
4823  /* fields: item->u1.list == pval list of PV_WORD elements, one per entry in the list
4824  item->u2.arglist == pval list of 4 PV_WORD elements for time values
4825  */
4826  destroy_pval(item->u1.list);
4827  break;
4828 
4829  case PV_STATEMENTBLOCK:
4830  /* fields: item->u1.list == pval list of statements in block, one per entry in the list
4831  */
4832  destroy_pval(item->u1.list);
4833  break;
4834 
4835  case PV_LOCALVARDEC:
4836  case PV_VARDEC:
4837  /* fields: item->u1.str == variable name
4838  item->u2.val == variable value to assign
4839  */
4840  if (item->u1.str)
4841  free(item->u1.str);
4842  if (item->u2.val)
4843  free(item->u2.val);
4844  break;
4845 
4846  case PV_GOTO:
4847  /* fields: item->u1.list == pval list of PV_WORD target names, up to 3, in order as given by user.
4848  item->u1.list->u1.str == where the data on a PV_WORD will always be.
4849  */
4850 
4851  destroy_pval(item->u1.list);
4852  break;
4853 
4854  case PV_LABEL:
4855  /* fields: item->u1.str == label name
4856  */
4857  if (item->u1.str)
4858  free(item->u1.str);
4859  break;
4860 
4861  case PV_FOR:
4862  /* fields: item->u1.for_init == a string containing the initalizer
4863  item->u2.for_test == a string containing the loop test
4864  item->u3.for_inc == a string containing the loop increment
4865 
4866  item->u4.for_statements == a pval list of statements in the for ()
4867  */
4868  if (item->u1.for_init)
4869  free(item->u1.for_init);
4870  if (item->u2.for_test)
4871  free(item->u2.for_test);
4872  if (item->u3.for_inc)
4873  free(item->u3.for_inc);
4875  break;
4876 
4877  case PV_WHILE:
4878  /* fields: item->u1.str == the while conditional, as supplied by user
4879 
4880  item->u2.statements == a pval list of statements in the while ()
4881  */
4882  if (item->u1.str)
4883  free(item->u1.str);
4884  destroy_pval(item->u2.statements);
4885  break;
4886 
4887  case PV_BREAK:
4888  /* fields: none
4889  */
4890  break;
4891 
4892  case PV_RETURN:
4893  /* fields: none
4894  */
4895  break;
4896 
4897  case PV_CONTINUE:
4898  /* fields: none
4899  */
4900  break;
4901 
4902  case PV_IFTIME:
4903  /* fields: item->u1.list == the 4 time values, in PV_WORD structs, linked list
4904 
4905  item->u2.statements == a pval list of statements in the if ()
4906  item->u3.else_statements == a pval list of statements in the else
4907  (could be zero)
4908  */
4909  destroy_pval(item->u1.list);
4910  destroy_pval(item->u2.statements);
4911  if (item->u3.else_statements) {
4913  }
4914  break;
4915 
4916  case PV_RANDOM:
4917  /* fields: item->u1.str == the random percentage, as supplied by user
4918 
4919  item->u2.statements == a pval list of statements in the true part ()
4920  item->u3.else_statements == a pval list of statements in the else
4921  (could be zero)
4922  fall thru to If */
4923  case PV_IF:
4924  /* fields: item->u1.str == the if conditional, as supplied by user
4925 
4926  item->u2.statements == a pval list of statements in the if ()
4927  item->u3.else_statements == a pval list of statements in the else
4928  (could be zero)
4929  */
4930  if (item->u1.str)
4931  free(item->u1.str);
4932  destroy_pval(item->u2.statements);
4933  if (item->u3.else_statements) {
4935  }
4936  break;
4937 
4938  case PV_SWITCH:
4939  /* fields: item->u1.str == the switch expression
4940 
4941  item->u2.statements == a pval list of statements in the switch,
4942  (will be case statements, most likely!)
4943  */
4944  if (item->u1.str)
4945  free(item->u1.str);
4946  destroy_pval(item->u2.statements);
4947  break;
4948 
4949  case PV_EXTENSION:
4950  /* fields: item->u1.str == the extension name, label, whatever it's called
4951 
4952  item->u2.statements == a pval list of statements in the extension
4953  item->u3.hints == a char * hint argument
4954  item->u4.regexten == an int boolean. non-zero says that regexten was specified
4955  */
4956  if (item->u1.str)
4957  free(item->u1.str);
4958  if (item->u3.hints)
4959  free(item->u3.hints);
4960  destroy_pval(item->u2.statements);
4961  break;
4962 
4963  case PV_IGNOREPAT:
4964  /* fields: item->u1.str == the ignorepat data
4965  */
4966  if (item->u1.str)
4967  free(item->u1.str);
4968  break;
4969 
4970  case PV_GLOBALS:
4971  /* fields: item->u1.statements == pval list of statements, usually vardecs
4972  */
4973  destroy_pval(item->u1.statements);
4974  break;
4975  }
4976  free(item);
4977 }
union pval::@198 u1
char * for_inc
Definition: pval.h:77
struct pval * list
Definition: pval.h:60
Definition: pval.h:32
Definition: pval.h:29
#define LOG_WARNING
Definition: logger.h:144
struct pval * statements
Definition: pval.h:61
Definition: pval.h:22
Definition: pval.h:8
union pval::@200 u3
union pval::@199 u2
char * val
Definition: pval.h:70
Definition: pval.h:13
char * filename
Definition: pval.h:55
Definition: pval.h:21
char * str
Definition: pval.h:59
void destroy_pval(pval *item)
Definition: pval.c:4979
char * for_test
Definition: pval.h:71
char * hints
Definition: pval.h:81
struct pval * else_statements
Definition: pval.h:78
#define free(a)
Definition: astmm.h:94
Definition: pval.h:24
union pval::@201 u4
struct pval * arglist
Definition: pval.h:68
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207
Definition: pval.h:9
Definition: pval.h:31
Definition: pval.h:25
pvaltype type
Definition: pval.h:50
Definition: pval.h:30
Definition: pval.h:23
Definition: pval.h:27
struct pval * for_statements
Definition: pval.h:89
Definition: pval.h:26
char * for_init
Definition: pval.h:62
Definition: pval.h:16
struct pval * macro_statements
Definition: pval.h:79
struct pval* find_context ( char *  name)

Definition at line 1960 of file pval.c.

References match_pval(), and name.

1961 {
1963  count_labels = 0;
1964  match_context = name;
1965  match_exten = "*"; /* don't really need to set these, shouldn't be reached */
1966  match_label = "*";
1967  return match_pval(current_db);
1968 }
static int count_labels
Definition: pval.c:82
static const char name[]
static const char * match_exten
Definition: pval.c:79
static int return_on_context_match
Definition: pval.c:84
static pval * current_db
Definition: pval.c:74
struct pval * match_pval(pval *item)
Definition: pval.c:1818
static const char * match_context
Definition: pval.c:78
static const char * match_label
Definition: pval.c:80
struct pval* find_macro ( char *  name)

Definition at line 1950 of file pval.c.

References match_pval(), and name.

1951 {
1953  count_labels = 0;
1954  match_context = name;
1955  match_exten = "*"; /* don't really need to set these, shouldn't be reached */
1956  match_label = "*";
1957  return match_pval(current_db);
1958 }
static int count_labels
Definition: pval.c:82
static const char name[]
static const char * match_exten
Definition: pval.c:79
static int return_on_context_match
Definition: pval.c:84
static pval * current_db
Definition: pval.c:74
struct pval * match_pval(pval *item)
Definition: pval.c:1818
static const char * match_context
Definition: pval.c:78
static const char * match_label
Definition: pval.c:80
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.

242 {
243  switch (cmd) {
244  case CLI_INIT:
245  e->command = "ael reload";
246  e->usage =
247  "Usage: ael reload\n"
248  " Reloads AEL configuration.\n";
249  return NULL;
250  case CLI_GENERATE:
251  return NULL;
252  }
253 
254  if (a->argc != 2)
255  return CLI_SHOWUSAGE;
256 
257  return (pbx_load_module() ? CLI_FAILURE : CLI_SUCCESS);
258 }
const int argc
Definition: cli.h:154
Definition: cli.h:146
#define CLI_SHOWUSAGE
Definition: cli.h:44
#define CLI_FAILURE
Definition: cli.h:45
char * command
Definition: cli.h:180
const char * usage
Definition: cli.h:171
#define CLI_SUCCESS
Definition: cli.h:43
static int pbx_load_module(void)
Definition: pbx_ael.c:155
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.

208 {
209  switch (cmd) {
210  case CLI_INIT:
211  e->command = "ael set debug {read|tokens|macros|contexts|off}";
212  e->usage =
213  "Usage: ael set debug {read|tokens|macros|contexts|off}\n"
214  " Enable AEL read, token, macro, or context debugging,\n"
215  " or disable all AEL debugging messages. Note: this\n"
216  " currently does nothing.\n";
217  return NULL;
218  case CLI_GENERATE:
219  return NULL;
220  }
221 
222  if (a->argc != e->args)
223  return CLI_SHOWUSAGE;
224 
225  if (!strcasecmp(a->argv[3], "read"))
226  aeldebug |= DEBUG_READ;
227  else if (!strcasecmp(a->argv[3], "tokens"))
229  else if (!strcasecmp(a->argv[3], "macros"))
231  else if (!strcasecmp(a->argv[3], "contexts"))
233  else if (!strcasecmp(a->argv[3], "off"))
234  aeldebug = 0;
235  else
236  return CLI_SHOWUSAGE;
237 
238  return CLI_SUCCESS;
239 }
const int argc
Definition: cli.h:154
Definition: cli.h:146
static int aeldebug
Definition: pbx_ael.c:128
#define DEBUG_MACROS
Definition: pbx_ael.c:83
int args
This gets set in ast_cli_register()
Definition: cli.h:179
const char *const * argv
Definition: cli.h:155
#define CLI_SHOWUSAGE
Definition: cli.h:44
#define DEBUG_CONTEXTS
Definition: pbx_ael.c:84
char * command
Definition: cli.h:180
#define DEBUG_TOKENS
Definition: pbx_ael.c:82
const char * usage
Definition: cli.h:171
#define CLI_SUCCESS
Definition: cli.h:43
#define DEBUG_READ
Definition: pbx_ael.c:81
int is_empty ( char *  arg)

Definition at line 1988 of file pval.c.

1989 {
1990  if (!arg)
1991  return 1;
1992  if (*arg == 0)
1993  return 1;
1994  while (*arg) {
1995  if (*arg != ' ' && *arg != '\t')
1996  return 0;
1997  arg++;
1998  }
1999  return 1;
2000 }
int is_float ( char *  arg)

Definition at line 1970 of file pval.c.

1971 {
1972  char *s;
1973  for (s=arg; *s; s++) {
1974  if (*s != '.' && (*s < '0' || *s > '9'))
1975  return 0;
1976  }
1977  return 1;
1978 }
int is_int ( char *  arg)

Definition at line 1979 of file pval.c.

1980 {
1981  char *s;
1982  for (s=arg; *s; s++) {
1983  if (*s < '0' || *s > '9')
1984  return 0;
1985  }
1986  return 1;
1987 }
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, and pbx_load_module().

276 {
278 #ifndef STANDALONE
280 #endif
281  return (pbx_load_module());
282 }
#define ARRAY_LEN(a)
Definition: isdn_lib.c:42
static char * aelsub
Definition: pbx_ael.c:133
int ast_cli_register_multiple(struct ast_cli_entry *e, int len)
Register multiple commands.
Definition: cli.c:2167
static int aelsub_exec(struct ast_channel *chan, const char *vdata)
Definition: pbx_ael.c:135
static struct ast_cli_entry cli_ael[]
Definition: pbx_ael.c:260
#define ast_register_application_xml(app, execute)
Register an application using XML documentation.
Definition: module.h:437
static int pbx_load_module(void)
Definition: pbx_ael.c:155
struct ael_extension* new_exten ( void  )

Definition at line 2937 of file pval.c.

References calloc.

2938 {
2939  struct ael_extension *x = (struct ael_extension *)calloc(sizeof(struct ael_extension),1);
2940  return x;
2941 }
#define calloc(a, b)
Definition: astmm.h:79
struct ael_priority* new_prio ( void  )

Definition at line 2931 of file pval.c.

References calloc.

2932 {
2933  struct ael_priority *x = (struct ael_priority *)calloc(sizeof(struct ael_priority),1);
2934  return x;
2935 }
#define calloc(a, b)
Definition: astmm.h:79
static int pbx_load_module ( void  )
static

Definition at line 155 of file pbx_ael.c.

References ael2_parse(), ael2_semantic_check(), ast_alloca, 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(), load_module(), and reload().

156 {
157  int errs=0, sem_err=0, sem_warn=0, sem_note=0;
158  char *rfilename;
159  struct ast_context *local_contexts=NULL, *con;
160  struct ast_hashtab *local_table=NULL;
161 
162  struct pval *parse_tree;
163 
164  ast_log(LOG_NOTICE, "Starting AEL load process.\n");
165  if (config[0] == '/')
166  rfilename = (char *)config;
167  else {
168  rfilename = ast_alloca(strlen(config) + strlen(ast_config_AST_CONFIG_DIR) + 2);
169  sprintf(rfilename, "%s/%s", ast_config_AST_CONFIG_DIR, config);
170  }
171  if (access(rfilename,R_OK) != 0) {
172  ast_log(LOG_NOTICE, "File %s not found; AEL declining load\n", rfilename);
174  }
175 
176  parse_tree = ael2_parse(rfilename, &errs);
177  ast_log(LOG_NOTICE, "AEL load process: parsed config file name '%s'.\n", rfilename);
178  ael2_semantic_check(parse_tree, &sem_err, &sem_warn, &sem_note);
179  if (errs == 0 && sem_err == 0) {
180  ast_log(LOG_NOTICE, "AEL load process: checked config file name '%s'.\n", rfilename);
182  if (ast_compile_ael2(&local_contexts, local_table, parse_tree)) {
183  ast_log(LOG_ERROR, "AEL compile failed! Aborting.\n");
184  destroy_pval(parse_tree); /* free up the memory */
186  }
187  ast_log(LOG_NOTICE, "AEL load process: compiled config file name '%s'.\n", rfilename);
188 
189  ast_merge_contexts_and_delete(&local_contexts, local_table, registrar);
190  local_table = NULL; /* it's the dialplan global now */
191  local_contexts = NULL;
192  ast_log(LOG_NOTICE, "AEL load process: merged config file name '%s'.\n", rfilename);
193  for (con = ast_walk_contexts(NULL); con; con = ast_walk_contexts(con))
195  ast_log(LOG_NOTICE, "AEL load process: verified config file name '%s'.\n", rfilename);
196  } else {
197  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);
198  destroy_pval(parse_tree); /* free up the memory */
200  }
201  destroy_pval(parse_tree); /* free up the memory */
202 
204 }
int ast_hashtab_compare_contexts(const void *ah_a, const void *ah_b)
hashtable functions for contexts
Definition: pbx.c:1136
int ast_hashtab_newsize_java(struct ast_hashtab *tab)
Create a prime number roughly 2x the current table size.
Definition: hashtab.c:131
static int errs
Definition: pval.c:67
#define ast_alloca(size)
call __builtin_alloca to ensure we get gcc builtin semantics
Definition: utils.h:653
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:88
struct ast_hashtab * ast_hashtab_create(int initial_buckets, int(*compare)(const void *a, const void *b), int(*resize)(struct ast_hashtab *), int(*newsize)(struct ast_hashtab *tab), unsigned int(*hash)(const void *obj), int do_locking)
Create the hashtable list.
Definition: hashtab.c:226
Definition: pval.h:48
struct ast_context * ast_walk_contexts(struct ast_context *con)
Definition: pbx.c:11174
void destroy_pval(pval *item)
Definition: pval.c:4979
#define LOG_ERROR
Definition: logger.h:155
int ast_compile_ael2(struct ast_context **local_contexts, struct ast_hashtab *local_table, struct pval *root)
Definition: pval.c:4451
const char * ast_config_AST_CONFIG_DIR
Definition: asterisk.c:256
void ast_merge_contexts_and_delete(struct ast_context **extcontexts, struct ast_hashtab *exttable, const char *registrar)
Merge the temporary contexts into a global contexts list and delete from the global list the ones tha...
Definition: pbx.c:7937
static char * config
Definition: pbx_ael.c:86
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207
#define LOG_NOTICE
Definition: logger.h:133
static struct ast_hashtab * local_table
Definition: pbx_config.c:61
static char * registrar
Definition: pbx_ael.c:87
unsigned int ast_hashtab_hash_contexts(const void *obj)
Definition: pbx.c:1188
static struct ast_context * local_contexts
Definition: pbx_config.c:60
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:2892
int ast_context_verify_includes(struct ast_context *con)
Verifies includes in an ast_contect structure.
Definition: pbx.c:11221
ast_context: An extension context
Definition: pbx.c:955
static int reload ( void  )
static

Definition at line 284 of file pbx_ael.c.

References pbx_load_module().

285 {
286  return pbx_load_module();
287 }
static int pbx_load_module(void)
Definition: pbx_ael.c:155
void set_priorities ( struct ael_extension exten)

Definition at line 4225 of file pval.c.

References ael_extension::is_switch, ael_priority::next, ael_extension::next_exten, ael_priority::origin, ael_extension::plist, ael_priority::priority_num, PV_LABEL, ael_extension::regexten, and pval::type.

4226 {
4227  int i;
4228  struct ael_priority *pr;
4229  do {
4230  if (exten->is_switch)
4231  i = 10;
4232  else if (exten->regexten)
4233  i=2;
4234  else
4235  i=1;
4236 
4237  for (pr=exten->plist; pr; pr=pr->next) {
4238  pr->priority_num = i;
4239 
4240  if (!pr->origin || (pr->origin && pr->origin->type != PV_LABEL) ) /* Labels don't show up in the dialplan,
4241  but we want them to point to the right
4242  priority, which would be the next line
4243  after the label; */
4244  i++;
4245  }
4246 
4247  exten = exten->next_exten;
4248  } while ( exten );
4249 }
struct pval * origin
Definition: ael_structs.h:95
struct ael_priority * plist
Definition: ael_structs.h:115
struct ael_extension * next_exten
Definition: ael_structs.h:117
struct ael_priority * next
Definition: ael_structs.h:100
pvaltype type
Definition: pval.h:50
int priority_num
Definition: ael_structs.h:89
Definition: pval.h:23
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(), and ast_unregister_application().

266 {
269 #ifndef STANDALONE
271 #endif
272  return 0;
273 }
#define ARRAY_LEN(a)
Definition: isdn_lib.c:42
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
Definition: cli.c:2177
int ast_unregister_application(const char *app)
Unregister an application.
Definition: pbx.c:7705
static char * aelsub
Definition: pbx_ael.c:133
static char * registrar
Definition: pbx_ael.c:87
void ast_context_destroy(struct ast_context *con, const char *registrar)
Destroy a context (matches the specified context (or ANY context if NULL)
Definition: pbx.c:9875
static struct ast_cli_entry cli_ael[]
Definition: pbx_ael.c:260

Variable Documentation

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

Definition at line 303 of file pbx_ael.c.

int aeldebug = 0
static

Definition at line 128 of file pbx_ael.c.

char* aelsub = "AELSub"
static

Definition at line 133 of file pbx_ael.c.

Definition at line 303 of file pbx_ael.c.

struct ast_cli_entry cli_ael[]
static
Initial value:
= {
AST_CLI_DEFINE(handle_cli_ael_reload, "Reload AEL configuration"),
AST_CLI_DEFINE(handle_cli_ael_set_debug, "Enable AEL debugging flags")
}
#define AST_CLI_DEFINE(fn, txt,...)
Definition: cli.h:191
static char * handle_cli_ael_set_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: pbx_ael.c:207
static char * handle_cli_ael_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: pbx_ael.c:241

Definition at line 260 of file pbx_ael.c.

char* config = "extensions.ael"
static

Definition at line 86 of file pbx_ael.c.

char* registrar = "pbx_ael"
static

Definition at line 87 of file pbx_ael.c.