Wed Aug 7 17:16:09 2019

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.

Defines

#define DEBUG_CONTEXTS   (1 << 3)
#define DEBUG_MACROS   (1 << 2)
#define DEBUG_READ   (1 << 0)
#define DEBUG_TOKENS   (1 << 1)

Functions

static void __reg_module (void)
static void __unreg_module (void)
void add_extensions (struct ael_extension *exten)
static int aelsub_exec (struct ast_channel *chan, const char *vdata)
int ast_compile_ael2 (struct ast_context **local_contexts, struct ast_hashtab *local_table, struct pval *root)
void ast_expr_clear_extra_error_info (void)
void ast_expr_register_extra_error_info (char *errmsg)
int check_app_args (pval *appcall, pval *arglist, struct argapp *app)
void check_pval (pval *item, struct argapp *apps, int in_globals)
void check_pval_item (pval *item, struct argapp *apps, int in_globals)
void check_switch_expr (pval *item, struct argapp *apps)
void destroy_extensions (struct ael_extension *exten)
void destroy_pval (pval *item)
void destroy_pval_item (pval *item)
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.


Define 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.

00307 {

static void __unreg_module ( void   )  [static]

Definition at line 303 of file pbx_ael.c.

00307 {

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.

04252 {
04253    struct ael_priority *pr;
04254    char *label=0;
04255    char realext[AST_MAX_EXTENSION];
04256    if (!exten) {
04257       ast_log(LOG_WARNING, "This file is Empty!\n" );
04258       return;
04259    }
04260    do {
04261       struct ael_priority *last = 0;
04262       
04263       pbx_substitute_variables_helper(NULL, exten->name, realext, sizeof(realext) - 1);
04264       if (exten->hints) {
04265          if (ast_add_extension2(exten->context, 0 /*no replace*/, realext, PRIORITY_HINT, NULL, exten->cidmatch, 
04266                           exten->hints, NULL, ast_free_ptr, registrar)) {
04267             ast_log(LOG_WARNING, "Unable to add step at priority 'hint' of extension '%s'\n",
04268                   exten->name);
04269          }
04270       }
04271       
04272       for (pr=exten->plist; pr; pr=pr->next) {
04273          char app[2000];
04274          char appargs[2000];
04275 
04276          /* before we can add the extension, we need to prep the app/appargs;
04277             the CONTROL types need to be done after the priority numbers are calculated.
04278          */
04279          if (pr->type == AEL_LABEL) /* don't try to put labels in the dialplan! */ {
04280             last = pr;
04281             continue;
04282          }
04283          
04284          if (pr->app)
04285             strcpy(app, pr->app);
04286          else
04287             app[0] = 0;
04288          if (pr->appargs )
04289             strcpy(appargs, pr->appargs);
04290          else
04291             appargs[0] = 0;
04292          switch( pr->type ) {
04293          case AEL_APPCALL:
04294             /* easy case. Everything is all set up */
04295             break;
04296             
04297          case AEL_CONTROL1: /* FOR loop, WHILE loop, BREAK, CONTINUE, IF, IFTIME */
04298             /* simple, unconditional goto. */
04299             strcpy(app,"Goto");
04300             if (pr->goto_true->origin && pr->goto_true->origin->type == PV_SWITCH ) {
04301                snprintf(appargs,sizeof(appargs),"%s,%d", pr->goto_true->exten->name, pr->goto_true->priority_num);
04302             } else if (pr->goto_true->origin && pr->goto_true->origin->type == PV_IFTIME && pr->goto_true->origin->u3.else_statements ) {
04303                snprintf(appargs,sizeof(appargs),"%d", pr->goto_true->priority_num+1);
04304             } else
04305                snprintf(appargs,sizeof(appargs),"%d", pr->goto_true->priority_num);
04306             break;
04307             
04308          case AEL_FOR_CONTROL:  /* WHILE loop test, FOR loop test */
04309             strcpy(app,"GotoIf");
04310             snprintf(appargs,sizeof(appargs),"%s?%d:%d", pr->appargs, pr->priority_num+1, pr->goto_false->priority_num);
04311             break;
04312             
04313          case AEL_IF_CONTROL:
04314             strcpy(app,"GotoIf");
04315             if (pr->origin->u3.else_statements )
04316                snprintf(appargs,sizeof(appargs),"%s?%d:%d", pr->appargs, pr->priority_num+1, pr->goto_false->priority_num+1);
04317             else
04318                snprintf(appargs,sizeof(appargs),"%s?%d:%d", pr->appargs, pr->priority_num+1, pr->goto_false->priority_num);
04319             break;
04320 
04321          case AEL_RAND_CONTROL:
04322             strcpy(app,"Random");
04323             snprintf(appargs,sizeof(appargs),"%s:%d", pr->appargs, pr->goto_true->priority_num+1);
04324             break;
04325 
04326          case AEL_IFTIME_CONTROL:
04327             strcpy(app,"GotoIfTime");
04328             snprintf(appargs,sizeof(appargs),"%s?%d", pr->appargs, pr->priority_num+2);
04329             break;
04330 
04331          case AEL_RETURN:
04332             strcpy(app,"Return");
04333             appargs[0] = 0;
04334             break;
04335             
04336          default:
04337             break;
04338          }
04339          if (last && last->type == AEL_LABEL ) {
04340             label = last->origin->u1.str;
04341          }
04342          else
04343             label = 0;
04344          
04345          if (ast_add_extension2(exten->context, 0 /*no replace*/, realext, pr->priority_num, (label?label:NULL), exten->cidmatch, 
04346                           app, strdup(appargs), ast_free_ptr, registrar)) {
04347             ast_log(LOG_WARNING, "Unable to add step at priority '%d' of extension '%s'\n", pr->priority_num, 
04348                   exten->name);
04349          }
04350          last = pr;
04351       }
04352       exten = exten->next_exten;
04353    } while ( exten );
04354 }

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

Definition at line 135 of file pbx_ael.c.

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

Referenced by load_module().

00136 {
00137    char buf[256], *data = ast_strdupa(vdata);
00138    struct ast_app *gosub = pbx_findapp("Gosub");
00139    AST_DECLARE_APP_ARGS(args,
00140       AST_APP_ARG(name);
00141       AST_APP_ARG(args);
00142    );
00143 
00144    if (gosub) {
00145       AST_STANDARD_RAW_ARGS(args, data);
00146       snprintf(buf, sizeof(buf), "%s,~~s~~,1(%s)", args.name, args.args);
00147       return pbx_exec(chan, gosub, buf);
00148    }
00149    return -1;
00150 }

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

Definition at line 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(), ael_extension::cidmatch, ael_extension::context, context, context_used(), destroy_extensions(), exten, fix_gotos_in_extensions(), gen_prios(), ael_extension::hints, pval::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, ael_priority::type, pval::type, pval::u1, pval::u2, pval::u3, pval::u4, and pval::val.

04452 {
04453    pval *p,*p2;
04454    struct ast_context *context;
04455    char buf[2000];
04456    struct ael_extension *exten;
04457    struct ael_extension *exten_list = 0;
04458 
04459    for (p=root; p; p=p->next ) { /* do the globals first, so they'll be there
04460                             when we try to eval them */
04461       switch (p->type) {
04462       case PV_GLOBALS:
04463          /* just VARDEC elements */
04464          for (p2=p->u1.list; p2; p2=p2->next) {
04465             char buf2[2000];
04466             snprintf(buf2,sizeof(buf2),"%s=%s", p2->u1.str, p2->u2.val);
04467             pbx_builtin_setvar(NULL, buf2);
04468          }
04469          break;
04470       default:
04471          break;
04472       }
04473    }
04474 
04475    for (p=root; p; p=p->next ) {
04476       pval *lp;
04477       int argc;
04478       
04479       switch (p->type) {
04480       case PV_MACRO:
04481          
04482          context = ast_context_find_or_create(local_contexts, local_table, p->u1.str, registrar);
04483          
04484          exten = new_exten();
04485          exten->context = context;
04486          exten->name = strdup("~~s~~");
04487          argc = 1;
04488          for (lp=p->u2.arglist; lp; lp=lp->next) {
04489             /* for each arg, set up a "Set" command */
04490             struct ael_priority *np2 = new_prio();
04491             np2->type = AEL_APPCALL;
04492             if (!ast_compat_app_set) {
04493                np2->app = strdup("MSet");
04494             } else {
04495                np2->app = strdup("Set");
04496             }
04497             snprintf(buf,sizeof(buf),"LOCAL(%s)=${ARG%d}", lp->u1.str, argc++);
04498             remove_spaces_before_equals(buf);
04499             np2->appargs = strdup(buf);
04500             linkprio(exten, np2, NULL);
04501          }
04502          
04503          /* CONTAINS APPCALLS, CATCH, just like extensions... */
04504          if (gen_prios(exten, p->u1.str, p->u3.macro_statements, 0, context)) {
04505             return -1;
04506          }
04507          if (exten->return_needed) {  /* most likely, this will go away */
04508             struct ael_priority *np2 = new_prio();
04509             np2->type = AEL_APPCALL;
04510             np2->app = strdup("NoOp");
04511             snprintf(buf,sizeof(buf),"End of Macro %s-%s",p->u1.str, exten->name);
04512             np2->appargs = strdup(buf);
04513             linkprio(exten, np2, NULL);
04514             exten-> return_target = np2;
04515          }
04516          
04517          set_priorities(exten);
04518          attach_exten(&exten_list, exten);
04519          break;
04520          
04521       case PV_GLOBALS:
04522          /* already done */
04523          break;
04524          
04525       case PV_CONTEXT:
04526          context = ast_context_find_or_create(local_contexts, local_table, p->u1.str, registrar);
04527          
04528          /* contexts contain: ignorepat, includes, switches, eswitches, extensions,  */
04529          for (p2=p->u2.statements; p2; p2=p2->next) {
04530             pval *p3;
04531             char *s3;
04532             
04533             switch (p2->type) {
04534             case PV_EXTENSION:
04535                exten = new_exten();
04536                exten->name = strdup(p2->u1.str);
04537                exten->context = context;
04538                
04539                if( (s3=strchr(exten->name, '/') ) != 0 )
04540                {
04541                   *s3 = 0;
04542                   exten->cidmatch = s3+1;
04543                }
04544                
04545                if ( p2->u3.hints )
04546                   exten->hints = strdup(p2->u3.hints);
04547                exten->regexten = p2->u4.regexten;
04548                if (gen_prios(exten, p->u1.str, p2->u2.statements, 0, context)) {
04549                   return -1;
04550                }
04551                if (exten->return_needed) { /* returns don't generate a goto eoe (end of extension) any more, just a Return() app call) */
04552                   struct ael_priority *np2 = new_prio();
04553                   np2->type = AEL_APPCALL;
04554                   np2->app = strdup("NoOp");
04555                   snprintf(buf,sizeof(buf),"End of Extension %s", exten->name);
04556                   np2->appargs = strdup(buf);
04557                   linkprio(exten, np2, NULL);
04558                   exten-> return_target = np2;
04559                }
04560                /* is the last priority in the extension a label? Then add a trailing no-op */
04561                if ( exten->plist_last && exten->plist_last->type == AEL_LABEL ) {
04562                   struct ael_priority *np2 = new_prio();
04563                   np2->type = AEL_APPCALL;
04564                   np2->app = strdup("NoOp");
04565                   snprintf(buf,sizeof(buf),"A NoOp to follow a trailing label %s", exten->plist_last->origin->u1.str);
04566                   np2->appargs = strdup(buf);
04567                   linkprio(exten, np2, NULL);
04568                }
04569 
04570                set_priorities(exten);
04571                attach_exten(&exten_list, exten);
04572                break;
04573                
04574             case PV_IGNOREPAT:
04575                ast_context_add_ignorepat2(context, p2->u1.str, registrar);
04576                break;
04577                
04578             case PV_INCLUDES:
04579                for (p3 = p2->u1.list; p3 ;p3=p3->next) {
04580                   if ( p3->u2.arglist ) {
04581                      snprintf(buf,sizeof(buf), "%s,%s,%s,%s,%s", 
04582                             p3->u1.str,
04583                             p3->u2.arglist->u1.str,
04584                             p3->u2.arglist->next->u1.str,
04585                             p3->u2.arglist->next->next->u1.str,
04586                             p3->u2.arglist->next->next->next->u1.str);
04587                      ast_context_add_include2(context, buf, registrar);
04588                   } else
04589                      ast_context_add_include2(context, p3->u1.str, registrar);
04590                }
04591                break;
04592                
04593             case PV_SWITCHES:
04594                for (p3 = p2->u1.list; p3 ;p3=p3->next) {
04595                   char *c = strchr(p3->u1.str, '/');
04596                   if (c) {
04597                      *c = '\0';
04598                      c++;
04599                   } else
04600                      c = "";
04601 
04602                   ast_context_add_switch2(context, p3->u1.str, c, 0, registrar);
04603                }
04604                break;
04605 
04606             case PV_ESWITCHES:
04607                for (p3 = p2->u1.list; p3 ;p3=p3->next) {
04608                   char *c = strchr(p3->u1.str, '/');
04609                   if (c) {
04610                      *c = '\0';
04611                      c++;
04612                   } else
04613                      c = "";
04614 
04615                   ast_context_add_switch2(context, p3->u1.str, c, 1, registrar);
04616                }
04617                break;
04618             default:
04619                break;
04620             }
04621          }
04622          
04623          break;
04624          
04625       default:
04626          /* huh? what? */
04627          break;
04628          
04629       }
04630    }
04631 
04632    /* Create default "h" bubble context */
04633    if (ast_custom_function_find("DIALPLAN_EXISTS") && ast_custom_function_find("STACK_PEEK")) {
04634       int i;
04635       const char *h_context = "ael-builtin-h-bubble";
04636       struct ael_priority *np;
04637       struct {
04638          int priority;
04639          const char *app;
04640          const char *arg;
04641       } steps[] = {
04642          /* Start high, to avoid conflict with existing h extensions */
04643          { 1, "Goto", "9991" },
04644          /* Save the context, because after the StackPop, it disappears */
04645          { 9991, "Set", "~~parentcxt~~=${STACK_PEEK(1,c,1)}" },
04646          /* If we're not in a Gosub frame, exit */
04647          { 9992, "GotoIf", "$[\"${~~parentcxt~~}\"=\"\"]?9996" },
04648          /* Check for an "h" extension in that context */
04649          { 9993, "GotoIf", "${DIALPLAN_EXISTS(${~~parentcxt~~},h,1)}?9994:9996" },
04650          /* Pop off the stack frame to prevent an infinite loop */
04651          { 9994, "StackPop", "" },
04652          /* Finally, go there. */
04653          { 9995, "Goto", "${~~parentcxt~~},h,1" },
04654          /* Just an empty priority for jumping out early */
04655          { 9996, "NoOp", "" }
04656       };
04657       context = ast_context_find_or_create(local_contexts, local_table, h_context, registrar);
04658       if (context_used(exten_list, context)) {
04659          int found = 0;
04660          while (!found) {
04661             /* Pick a new context name that is not used. */
04662             char h_context_template[] = "/tmp/ael-builtin-h-bubble-XXXXXX";
04663             int fd = mkstemp(h_context_template);
04664             unlink(h_context_template);
04665             close(fd);
04666             context = ast_context_find_or_create(local_contexts, local_table, h_context_template + 5, registrar);
04667             found = !context_used(exten_list, context);
04668          }
04669          h_context = ast_get_context_name(context);
04670       }
04671       exten = new_exten();
04672       exten->context = context;
04673       exten->name = strdup("h");
04674 
04675       for (i = 0; i < ARRAY_LEN(steps); i++) {
04676          np = new_prio();
04677          np->type = AEL_APPCALL;
04678          np->priority_num = steps[i].priority;
04679          np->app = strdup(steps[i].app);
04680          np->appargs = strdup(steps[i].arg);
04681          linkprio(exten, np, NULL);
04682       }
04683       attach_exten(&exten_list, exten);
04684 
04685       /* Include the default "h" bubble context in each macro context */
04686       for (exten = exten_list; exten; exten = exten->next_exten) {
04687          /* All macros contain a "~~s~~" extension, and it's the first created.  If
04688           * we perchance get a non-macro context, it's no big deal; the logic is
04689           * designed to exit out smoothly if not called from within a Gosub. */
04690          if (!strcmp(exten->name, "~~s~~")) {
04691             ast_context_add_include2(exten->context, h_context, registrar);
04692          }
04693       }
04694    }
04695 
04696    /* moved these from being done after a macro or extension were processed,
04697       to after all processing is done, for the sake of fixing gotos to labels inside cases... */
04698    /* I guess this would be considered 2nd pass of compiler now... */
04699    fix_gotos_in_extensions(exten_list); /* find and fix extension ref in gotos to labels that are in case statements */
04700    add_extensions(exten_list);   /* actually makes calls to create priorities in ast_contexts -- feeds dialplan to asterisk */
04701    destroy_extensions(exten_list);  /* all that remains is an empty husk, discard of it as is proper */
04702    
04703    return 0;
04704 }

void ast_expr_clear_extra_error_info ( void   ) 

Definition at line 2475 of file ast_expr2f.c.

02476 {
02477        extra_error_message_supplied=0;
02478        extra_error_message[0] = 0;
02479 }

void ast_expr_register_extra_error_info ( char *  errmsg  ) 

Definition at line 2469 of file ast_expr2f.c.

02470 {
02471        extra_error_message_supplied=1;
02472        strcpy(extra_error_message, message);
02473 }

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.

02138 {
02139 #ifdef AAL_ARGCHECK
02140    struct argdesc *ad = app->args;
02141    pval *pa;
02142    int z;
02143    
02144    for (pa = arglist; pa; pa=pa->next) {
02145       if (!ad) {
02146          ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: Extra argument %s not in application call to %s !\n",
02147                arglist->filename, arglist->startline, arglist->endline, pa->u1.str, app->name);
02148          warns++;
02149          return 1;
02150       } else {
02151          /* find the first entry in the ad list that will match */
02152          do {
02153             if ( ad->dtype == ARGD_VARARG ) /* once we hit the VARARG, all bets are off. Discontinue the comparisons */
02154                break;
02155             
02156             z= option_matches( ad, pa, app);
02157             if (!z) {
02158                if ( !arglist )
02159                   arglist=appcall;
02160                
02161                if (ad->type == ARGD_REQUIRED) {
02162                   ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: Required argument %s not in application call to %s !\n",
02163                         arglist->filename, arglist->startline, arglist->endline, ad->dtype==ARGD_OPTIONSET?"options":ad->name, app->name);
02164                   warns++;
02165                   return 1;
02166                }
02167             } else if (z && ad->dtype == ARGD_OPTIONSET) {
02168                option_matches_j( ad, pa, app);
02169             }
02170             ad = ad->next;
02171          } while (ad && !z);
02172       }
02173    }
02174    /* any app nodes left, that are not optional? */
02175    for ( ; ad; ad=ad->next) {
02176       if (ad->type == ARGD_REQUIRED && ad->dtype != ARGD_VARARG) {
02177          if ( !arglist ) 
02178             arglist=appcall;
02179          ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: Required argument %s not in application call to %s !\n",
02180                arglist->filename, arglist->startline, arglist->endline, ad->dtype==ARGD_OPTIONSET?"options":ad->name, app->name);
02181          warns++;
02182          return 1;
02183       }
02184    }
02185    return 0;
02186 #else
02187    return 0;
02188 #endif
02189 }

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.

02873 {
02874    pval *i;
02875 
02876    /* checks to do:
02877       1. Do goto's point to actual labels? 
02878       2. Do macro calls reference a macro?
02879       3. Does the number of macro args match the definition?
02880       4. Is a macro call missing its & at the front?
02881       5. Application calls-- we could check syntax for existing applications,
02882          but I need some some sort of universal description bnf for a general
02883         sort of method for checking arguments, in number, maybe even type, at least. 
02884         Don't want to hand code checks for hundreds of applications.
02885    */
02886    
02887    for (i=item; i; i=i->next) {
02888       check_pval_item(i,apps,in_globals);
02889    }
02890 }

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

Definition at line 2364 of file pval.c.

References pval::abstract, 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, argapp::next, pval::next, pbx_find_extension(), PV_APPLICATION_CALL, PV_BREAK, PV_CASE, PV_CATCH, PV_CONTEXT, PV_CONTINUE, PV_DEFAULT, PV_ESWITCHES, PV_EXTENSION, PV_FOR, PV_GLOBALS, PV_GOTO, PV_IF, PV_IFTIME, PV_IGNOREPAT, PV_INCLUDES, PV_LABEL, PV_LOCALVARDEC, PV_MACRO, PV_MACRO_CALL, PV_PATTERN, PV_RANDOM, PV_RETURN, PV_STATEMENTBLOCK, PV_SWITCH, PV_SWITCHES, PV_VARDEC, PV_WHILE, PV_WORD, pbx_find_info::stacklen, pval::startcol, pval::startline, pval::statements, pbx_find_info::status, STATUS_SUCCESS, pval::str, pval::type, pval::u1, pval::u2, pval::u3, pval::u4, and pval::val.

02365 {
02366    pval *lp;
02367 #ifdef AAL_ARGCHECK
02368    struct argapp *app, *found;
02369 #endif
02370    struct pval *macro_def;
02371    struct pval *app_def;
02372 
02373    char errmsg[4096];
02374    char *strp;
02375    
02376    switch (item->type) {
02377    case PV_WORD:
02378       /* fields: item->u1.str == string associated with this (word).
02379                  item->u2.arglist  == pval list of 4 PV_WORD elements for time values (only in PV_INCLUDES) */
02380       break;
02381       
02382    case PV_MACRO:
02383       /* fields: item->u1.str     == name of macro
02384                  item->u2.arglist == pval list of PV_WORD arguments of macro, as given by user
02385                item->u2.arglist->u1.str  == argument
02386                item->u2.arglist->next   == next arg
02387 
02388                item->u3.macro_statements == pval list of statements in macro body.
02389       */
02390       in_abstract_context = 0;
02391       current_context = item;
02392       current_extension = 0;
02393 
02394       check_macro_returns(item);
02395       
02396       for (lp=item->u2.arglist; lp; lp=lp->next) {
02397       
02398       }
02399       check_pval(item->u3.macro_statements, apps,in_globals);
02400       break;
02401          
02402    case PV_CONTEXT:
02403       /* fields: item->u1.str     == name of context
02404                  item->u2.statements == pval list of statements in context body
02405                item->u3.abstract == int 1 if an abstract keyword were present
02406       */
02407       current_context = item;
02408       current_extension = 0;
02409       if ( item->u3.abstract ) {
02410          in_abstract_context = 1;
02411          check_abstract_reference(item);
02412       } else
02413          in_abstract_context = 0;
02414       check_pval(item->u2.statements, apps,in_globals);
02415       break;
02416          
02417    case PV_MACRO_CALL:
02418       /* fields: item->u1.str     == name of macro to call
02419                  item->u2.arglist == pval list of PV_WORD arguments of macro call, as given by user
02420                item->u2.arglist->u1.str  == argument
02421                item->u2.arglist->next   == next arg
02422       */
02423 #ifdef STANDALONE
02424       /* if this is a standalone, we will need to make sure the 
02425          localized load of extensions.conf is done */
02426       if (!extensions_dot_conf_loaded) {
02427          localized_pbx_load_module();
02428          extensions_dot_conf_loaded++;
02429       }
02430 #endif
02431       macro_def = find_macro(item->u1.str);
02432       if (!macro_def) {
02433 #ifdef STANDALONE
02434          struct pbx_find_info pfiq = {.stacklen = 0 };
02435          struct pbx_find_info pfiq2 = {.stacklen = 0 };
02436 
02437          /* look for the macro in the extensions.conf world */
02438          pbx_find_extension(NULL, NULL, &pfiq, item->u1.str, "s", 1, NULL, NULL, E_MATCH);
02439          
02440          if (pfiq.status != STATUS_SUCCESS) {
02441             char namebuf2[256];
02442             snprintf(namebuf2, 256, "macro-%s", item->u1.str);
02443             
02444             /* look for the macro in the extensions.conf world */
02445             pbx_find_extension(NULL, NULL, &pfiq2, namebuf2, "s", 1, NULL, NULL, E_MATCH);
02446             
02447             if (pfiq2.status == STATUS_SUCCESS) {
02448                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",
02449                      item->filename, item->startline, item->endline, item->u1.str, item->u1.str);
02450                warns++;
02451             } else {
02452                ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: macro call to non-existent %s! (Not even in the extensions.conf stuff!)\n",
02453                      item->filename, item->startline, item->endline, item->u1.str);
02454                warns++;
02455             }
02456          }
02457 #else
02458          ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: macro call to %s cannot be found in the AEL code!\n",
02459                item->filename, item->startline, item->endline, item->u1.str);
02460          warns++;
02461          
02462 #endif
02463 #ifdef THIS_IS_1DOT4
02464          char namebuf2[256];
02465          snprintf(namebuf2, 256, "macro-%s", item->u1.str);
02466 
02467          /* look for the macro in the extensions.conf world */
02468          pbx_find_extension(NULL, NULL, &pfiq, namebuf2, "s", 1, NULL, NULL, E_MATCH);
02469          
02470          if (pfiq.status != STATUS_SUCCESS) {
02471             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",
02472                   item->filename, item->startline, item->endline, item->u1.str);
02473             warns++;
02474          }
02475          
02476 #endif
02477 
02478       } else if (macro_def->type != PV_MACRO) {
02479          ast_log(LOG_ERROR,"Error: file %s, line %d-%d: macro call to %s references a context, not a macro!\n",
02480                item->filename, item->startline, item->endline, item->u1.str);
02481          errs++;
02482       } else {
02483          /* macro_def is a MACRO, so do the args match in number? */
02484          int hereargs = 0;
02485          int thereargs = 0;
02486          
02487          for (lp=item->u2.arglist; lp; lp=lp->next) {
02488             hereargs++;
02489          }
02490          for (lp=macro_def->u2.arglist; lp; lp=lp->next) {
02491             thereargs++;
02492          }
02493          if (hereargs != thereargs ) {
02494             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",
02495                   item->filename, item->startline, item->endline, item->u1.str, hereargs, thereargs);
02496             errs++;
02497          }
02498       }
02499       break;
02500          
02501    case PV_APPLICATION_CALL:
02502       /* fields: item->u1.str     == name of application to call
02503                  item->u2.arglist == pval list of PV_WORD arguments of macro call, as given by user
02504                item->u2.arglist->u1.str  == argument
02505                item->u2.arglist->next   == next arg
02506       */
02507       /* Need to check to see if the application is available! */
02508       app_def = find_context(item->u1.str);
02509       if (app_def && app_def->type == PV_MACRO) {
02510          ast_log(LOG_ERROR,"Error: file %s, line %d-%d: application call to %s references an existing macro, but had no & preceding it!\n",
02511                item->filename, item->startline, item->endline, item->u1.str);
02512          errs++;
02513       }
02514       if (strcasecmp(item->u1.str,"GotoIf") == 0
02515          || strcasecmp(item->u1.str,"GotoIfTime") == 0
02516          || strcasecmp(item->u1.str,"while") == 0
02517          || strcasecmp(item->u1.str,"endwhile") == 0
02518          || strcasecmp(item->u1.str,"random") == 0
02519          || strcasecmp(item->u1.str,"gosub") == 0
02520          || strcasecmp(item->u1.str,"gosubif") == 0
02521          || strcasecmp(item->u1.str,"continuewhile") == 0
02522          || strcasecmp(item->u1.str,"endwhile") == 0
02523          || strcasecmp(item->u1.str,"execif") == 0
02524          || strcasecmp(item->u1.str,"execiftime") == 0
02525          || strcasecmp(item->u1.str,"exitwhile") == 0
02526          || strcasecmp(item->u1.str,"goto") == 0
02527          || strcasecmp(item->u1.str,"macro") == 0
02528          || strcasecmp(item->u1.str,"macroexclusive") == 0
02529          || strcasecmp(item->u1.str,"macroif") == 0
02530          || strcasecmp(item->u1.str,"stackpop") == 0
02531          || strcasecmp(item->u1.str,"execIf") == 0 ) {
02532          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",
02533                item->filename, item->startline, item->endline, item->u1.str);
02534          warns++;
02535       }
02536       if (strcasecmp(item->u1.str,"macroexit") == 0) {
02537             ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: I am converting the MacroExit call here to a return statement.\n",
02538                   item->filename, item->startline, item->endline);
02539             item->type = PV_RETURN;
02540             free(item->u1.str);
02541             item->u1.str = 0;
02542       }
02543       
02544 #ifdef AAL_ARGCHECK
02545       found = 0;
02546       for (app=apps; app; app=app->next) {
02547          if (strcasecmp(app->name, item->u1.str) == 0) {
02548             found =app;
02549             break;
02550          }
02551       }
02552       if (!found) {
02553          ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: application call to %s not listed in applist database!\n",
02554                item->filename, item->startline, item->endline, item->u1.str);
02555          warns++;
02556       } else
02557          check_app_args(item, item->u2.arglist, app);
02558 #endif
02559       break;
02560       
02561    case PV_CASE:
02562       /* fields: item->u1.str     == value of case
02563                  item->u2.statements == pval list of statements under the case
02564       */
02565       /* Make sure sequence of statements under case is terminated with  goto, return, or break */
02566       /* find the last statement */
02567       check_pval(item->u2.statements, apps,in_globals);
02568       break;
02569          
02570    case PV_PATTERN:
02571       /* fields: item->u1.str     == value of case
02572                  item->u2.statements == pval list of statements under the case
02573       */
02574       /* Make sure sequence of statements under case is terminated with  goto, return, or break */
02575       /* find the last statement */
02576       
02577       check_pval(item->u2.statements, apps,in_globals);
02578       break;
02579          
02580    case PV_DEFAULT:
02581       /* fields: 
02582                  item->u2.statements == pval list of statements under the case
02583       */
02584 
02585       check_pval(item->u2.statements, apps,in_globals);
02586       break;
02587          
02588    case PV_CATCH:
02589       /* fields: item->u1.str     == name of extension to catch
02590                  item->u2.statements == pval list of statements in context body
02591       */
02592       check_pval(item->u2.statements, apps,in_globals);
02593       break;
02594          
02595    case PV_SWITCHES:
02596       /* fields: item->u1.list     == pval list of PV_WORD elements, one per entry in the list
02597       */
02598       check_pval(item->u1.list, apps,in_globals);
02599       break;
02600          
02601    case PV_ESWITCHES:
02602       /* fields: item->u1.list     == pval list of PV_WORD elements, one per entry in the list
02603       */
02604       check_pval(item->u1.list, apps,in_globals);
02605       break;
02606          
02607    case PV_INCLUDES:
02608       /* fields: item->u1.list     == pval list of PV_WORD elements, one per entry in the list
02609       */
02610       check_pval(item->u1.list, apps,in_globals);
02611       check_includes(item);
02612       for (lp=item->u1.list; lp; lp=lp->next){
02613          char *incl_context = lp->u1.str;
02614          struct pval *that_context = find_context(incl_context);
02615 
02616          if ( lp->u2.arglist ) {
02617             check_timerange(lp->u2.arglist);
02618             check_dow(lp->u2.arglist->next);
02619             check_day(lp->u2.arglist->next->next);
02620             check_month(lp->u2.arglist->next->next->next);
02621          }
02622          
02623          if (that_context) {
02624             find_pval_gotos(that_context->u2.statements,0);
02625             
02626          }
02627       }
02628       break;
02629          
02630    case PV_STATEMENTBLOCK:
02631       /* fields: item->u1.list     == pval list of statements in block, one per entry in the list
02632       */
02633       check_pval(item->u1.list, apps,in_globals);
02634       break;
02635          
02636    case PV_VARDEC:
02637       /* fields: item->u1.str     == variable name
02638                  item->u2.val     == variable value to assign
02639       */
02640       /* the RHS of a vardec is encapsulated in a $[] expr. Is it legal? */
02641       if( !in_globals ) { /* don't check stuff inside the globals context; no wrapping in $[ ] there... */
02642          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);
02643          ast_expr_register_extra_error_info(errmsg);
02644          ast_expr(item->u2.val, expr_output, sizeof(expr_output),NULL);
02645          ast_expr_clear_extra_error_info();
02646          if ( strpbrk(item->u2.val,"~!-+<>=*/&^") && !strstr(item->u2.val,"${") ) {
02647             ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: expression %s has operators, but no variables. Interesting...\n",
02648                   item->filename, item->startline, item->endline, item->u2.val);
02649             warns++;
02650          }
02651          check_expr2_input(item,item->u2.val);
02652       }
02653       break;
02654          
02655    case PV_LOCALVARDEC:
02656       /* fields: item->u1.str     == variable name
02657                  item->u2.val     == variable value to assign
02658       */
02659       /* the RHS of a vardec is encapsulated in a $[] expr. Is it legal? */
02660       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);
02661       ast_expr_register_extra_error_info(errmsg);
02662       ast_expr(item->u2.val, expr_output, sizeof(expr_output),NULL);
02663       ast_expr_clear_extra_error_info();
02664       if ( strpbrk(item->u2.val,"~!-+<>=*/&^") && !strstr(item->u2.val,"${") ) {
02665          ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: expression %s has operators, but no variables. Interesting...\n",
02666                item->filename, item->startline, item->endline, item->u2.val);
02667          warns++;
02668       }
02669       check_expr2_input(item,item->u2.val);
02670       break;
02671          
02672    case PV_GOTO:
02673       /* fields: item->u1.list     == pval list of PV_WORD target names, up to 3, in order as given by user.
02674                  item->u1.list->u1.str  == where the data on a PV_WORD will always be.
02675       */
02676       /* don't check goto's in abstract contexts */
02677       if ( in_abstract_context )
02678          break;
02679       
02680       check_goto(item);
02681       break;
02682          
02683    case PV_LABEL:
02684       /* fields: item->u1.str     == label name
02685       */
02686       if ( strspn(item->u1.str, "0123456789") == strlen(item->u1.str) ) {
02687          ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: label '%s' is numeric, this is bad practice!\n",
02688                item->filename, item->startline, item->endline, item->u1.str);
02689          warns++;
02690       }
02691 
02692       check_label(item);
02693       break;
02694          
02695    case PV_FOR:
02696       /* fields: item->u1.for_init     == a string containing the initalizer
02697                  item->u2.for_test     == a string containing the loop test
02698                  item->u3.for_inc      == a string containing the loop increment
02699 
02700                item->u4.for_statements == a pval list of statements in the for ()
02701       */
02702       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);
02703       ast_expr_register_extra_error_info(errmsg);
02704 
02705       strp = strchr(item->u1.for_init, '=');
02706       if (strp) {
02707          ast_expr(strp+1, expr_output, sizeof(expr_output),NULL);
02708       }
02709       ast_expr(item->u2.for_test, expr_output, sizeof(expr_output),NULL);
02710       strp = strchr(item->u3.for_inc, '=');
02711       if (strp) {
02712          ast_expr(strp+1, expr_output, sizeof(expr_output),NULL);
02713       }
02714       if ( strpbrk(item->u2.for_test,"~!-+<>=*/&^") && !strstr(item->u2.for_test,"${") ) {
02715          ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: expression %s has operators, but no variables. Interesting...\n",
02716                item->filename, item->startline, item->endline, item->u2.for_test);
02717          warns++;
02718       }
02719       if ( strpbrk(item->u3.for_inc,"~!-+<>=*/&^") && !strstr(item->u3.for_inc,"${") ) {
02720          ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: expression %s has operators, but no variables. Interesting...\n",
02721                item->filename, item->startline, item->endline, item->u3.for_inc);
02722          warns++;
02723       }
02724       check_expr2_input(item,item->u2.for_test);
02725       check_expr2_input(item,item->u3.for_inc);
02726       
02727       ast_expr_clear_extra_error_info();
02728       check_pval(item->u4.for_statements, apps,in_globals);
02729       break;
02730          
02731    case PV_WHILE:
02732       /* fields: item->u1.str        == the while conditional, as supplied by user
02733 
02734                item->u2.statements == a pval list of statements in the while ()
02735       */
02736       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);
02737       ast_expr_register_extra_error_info(errmsg);
02738       ast_expr(item->u1.str, expr_output, sizeof(expr_output),NULL);
02739       ast_expr_clear_extra_error_info();
02740       if ( strpbrk(item->u1.str,"~!-+<>=*/&^") && !strstr(item->u1.str,"${") ) {
02741          ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: expression %s has operators, but no variables. Interesting...\n",
02742                item->filename, item->startline, item->endline, item->u1.str);
02743          warns++;
02744       }
02745       check_expr2_input(item,item->u1.str);
02746       check_pval(item->u2.statements, apps,in_globals);
02747       break;
02748          
02749    case PV_BREAK:
02750       /* fields: none
02751       */
02752       check_break(item);
02753       break;
02754          
02755    case PV_RETURN:
02756       /* fields: none
02757       */
02758       break;
02759          
02760    case PV_CONTINUE:
02761       /* fields: none
02762       */
02763       check_continue(item);
02764       break;
02765          
02766    case PV_RANDOM:
02767       /* fields: item->u1.str        == the random number expression, as supplied by user
02768 
02769                item->u2.statements == a pval list of statements in the if ()
02770                item->u3.else_statements == a pval list of statements in the else
02771                                     (could be zero)
02772       */
02773       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);
02774       ast_expr_register_extra_error_info(errmsg);
02775       ast_expr(item->u1.str, expr_output, sizeof(expr_output),NULL);
02776       ast_expr_clear_extra_error_info();
02777       if ( strpbrk(item->u1.str,"~!-+<>=*/&^") && !strstr(item->u1.str,"${") ) {
02778          ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: random expression '%s' has operators, but no variables. Interesting...\n",
02779                item->filename, item->startline, item->endline, item->u1.str);
02780          warns++;
02781       }
02782       check_expr2_input(item,item->u1.str);
02783       check_pval(item->u2.statements, apps,in_globals);
02784       if (item->u3.else_statements) {
02785          check_pval(item->u3.else_statements, apps,in_globals);
02786       }
02787       break;
02788 
02789    case PV_IFTIME:
02790       /* fields: item->u1.list        == the if time values, 4 of them, each in PV_WORD, linked list 
02791 
02792                item->u2.statements == a pval list of statements in the if ()
02793                item->u3.else_statements == a pval list of statements in the else
02794                                     (could be zero)
02795       */
02796       if ( item->u2.arglist ) {
02797          check_timerange(item->u1.list);
02798          check_dow(item->u1.list->next);
02799          check_day(item->u1.list->next->next);
02800          check_month(item->u1.list->next->next->next);
02801       }
02802 
02803       check_pval(item->u2.statements, apps,in_globals);
02804       if (item->u3.else_statements) {
02805          check_pval(item->u3.else_statements, apps,in_globals);
02806       }
02807       break;
02808          
02809    case PV_IF:
02810       /* fields: item->u1.str        == the if conditional, as supplied by user
02811 
02812                item->u2.statements == a pval list of statements in the if ()
02813                item->u3.else_statements == a pval list of statements in the else
02814                                     (could be zero)
02815       */
02816       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);
02817       ast_expr_register_extra_error_info(errmsg);
02818       ast_expr(item->u1.str, expr_output, sizeof(expr_output),NULL);
02819       ast_expr_clear_extra_error_info();
02820       if ( strpbrk(item->u1.str,"~!-+<>=*/&^") && !strstr(item->u1.str,"${") ) {
02821          ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: expression '%s' has operators, but no variables. Interesting...\n",
02822                item->filename, item->startline, item->endline, item->u1.str);
02823          warns++;
02824       }
02825       check_expr2_input(item,item->u1.str);
02826       check_pval(item->u2.statements, apps,in_globals);
02827       if (item->u3.else_statements) {
02828          check_pval(item->u3.else_statements, apps,in_globals);
02829       }
02830       break;
02831          
02832    case PV_SWITCH:
02833       /* fields: item->u1.str        == the switch expression
02834 
02835                item->u2.statements == a pval list of statements in the switch, 
02836                                     (will be case statements, most likely!)
02837       */
02838       /* we can check the switch expression, see if it matches any of the app variables...
02839            if it does, then, are all the possible cases accounted for? */
02840       check_switch_expr(item, apps);
02841       check_pval(item->u2.statements, apps,in_globals);
02842       break;
02843          
02844    case PV_EXTENSION:
02845       /* fields: item->u1.str        == the extension name, label, whatever it's called
02846 
02847                item->u2.statements == a pval list of statements in the extension
02848                item->u3.hints      == a char * hint argument
02849                item->u4.regexten   == an int boolean. non-zero says that regexten was specified
02850       */
02851       current_extension = item ;
02852       
02853       check_pval(item->u2.statements, apps,in_globals);
02854       break;
02855          
02856    case PV_IGNOREPAT:
02857       /* fields: item->u1.str        == the ignorepat data
02858       */
02859       break;
02860          
02861    case PV_GLOBALS:
02862       /* fields: item->u1.statements     == pval list of statements, usually vardecs
02863       */
02864       in_abstract_context = 0;
02865       check_pval(item->u1.statements, apps, 1);
02866       break;
02867    default:
02868       break;
02869    }
02870 }

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.

02192 {
02193 #ifdef AAL_ARGCHECK
02194    /* get and clean the variable name */
02195    char *buff1, *p;
02196    struct argapp *a,*a2;
02197    struct appsetvar *v,*v2;
02198    struct argchoice *c;
02199    pval *t;
02200    
02201    p = item->u1.str;
02202    while (p && *p && (*p == ' ' || *p == '\t' || *p == '$' || *p == '{' ) )
02203       p++;
02204    
02205    buff1 = ast_strdupa(p);
02206 
02207    while (strlen(buff1) > 0 && ( buff1[strlen(buff1)-1] == '}' || buff1[strlen(buff1)-1] == ' ' || buff1[strlen(buff1)-1] == '\t'))
02208       buff1[strlen(buff1)-1] = 0;
02209    /* buff1 now contains the variable name */
02210    v = 0;
02211    for (a=apps; a; a=a->next) {
02212       for (v=a->setvars;v;v=v->next) {
02213          if (strcmp(v->name,buff1) == 0) {
02214             break;
02215          }
02216       }
02217       if ( v )
02218          break;
02219    }
02220    if (v && v->vals) {
02221       /* we have a match, to a variable that has a set of determined values */
02222       int def= 0;
02223       int pat = 0;
02224       int f1 = 0;
02225       
02226       /* first of all, does this switch have a default case ? */
02227       for (t=item->u2.statements; t; t=t->next) {
02228          if (t->type == PV_DEFAULT) {
02229             def =1;
02230             break;
02231          }
02232          if (t->type == PV_PATTERN) {
02233             pat++;
02234          }
02235       }
02236       if (def || pat) /* nothing to check. All cases accounted for! */
02237          return;
02238       for (c=v->vals; c; c=c->next) {
02239          f1 = 0;
02240          for (t=item->u2.statements; t; t=t->next) {
02241             if (t->type == PV_CASE || t->type == PV_PATTERN) {
02242                if (!strcmp(t->u1.str,c->name)) {
02243                   f1 = 1;
02244                   break;
02245                }
02246             }
02247          }
02248          if (!f1) {
02249             ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: switch with expression(%s) does not handle the case of %s !\n",
02250                   item->filename, item->startline, item->endline, item->u1.str, c->name);
02251             warns++;
02252          }
02253       }
02254       /* next, is there an app call in the current exten, that would set this var? */
02255       f1 = 0;
02256       t = current_extension->u2.statements;
02257       if ( t && t->type == PV_STATEMENTBLOCK )
02258          t = t->u1.statements;
02259       for (; t && t != item; t=t->next) {
02260          if (t->type == PV_APPLICATION_CALL) {
02261             /* find the application that matches the u1.str */
02262             for (a2=apps; a2; a2=a2->next) {
02263                if (strcasecmp(a2->name, t->u1.str)==0) {
02264                   for (v2=a2->setvars; v2; v2=v2->next) {
02265                      if (strcmp(v2->name, buff1) == 0) {
02266                         /* found an app that sets the var */
02267                         f1 = 1;
02268                         break;
02269                      }
02270                   }
02271                }
02272                if (f1)
02273                   break;
02274             }
02275          }
02276          if (f1)
02277             break;
02278       }
02279             
02280       /* see if it sets the var */
02281       if (!f1) {
02282          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",
02283                item->filename, item->startline, item->endline, item->u1.str);
02284          warns++;
02285       }
02286    }
02287 #else
02288    pval *t,*tl=0,*p2;
02289    int def= 0;
02290    
02291    /* first of all, does this switch have a default case ? */
02292    for (t=item->u2.statements; t; t=t->next) {
02293       if (t->type == PV_DEFAULT) {
02294          def =1;
02295          break;
02296       }
02297       tl = t;
02298    }
02299    if (def) /* nothing to check. All cases accounted for! */
02300       return;
02301    /* if no default, warn and insert a default case at the end */
02302    p2 = tl->next = calloc(1, sizeof(struct pval));
02303    
02304    p2->type = PV_DEFAULT;
02305    p2->startline = tl->startline;
02306    p2->endline = tl->endline;
02307    p2->startcol = tl->startcol;
02308    p2->endcol = tl->endcol;
02309    p2->filename = strdup(tl->filename);
02310    ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: A default case was automatically added to the switch.\n",
02311          p2->filename, p2->startline, p2->endline);
02312    warns++;
02313    
02314 #endif
02315 }

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.

02986 {
02987    struct ael_extension *ne, *nen;
02988    for (ne=exten; ne; ne=nen) {
02989       struct ael_priority *pe, *pen;
02990       
02991       if (ne->name)
02992          free(ne->name);
02993       
02994       /* cidmatch fields are allocated with name, and freed when
02995          the name field is freed. Don't do a free for this field,
02996          unless you LIKE to see a crash! */
02997 
02998       if (ne->hints)
02999          free(ne->hints);
03000       
03001       for (pe=ne->plist; pe; pe=pen) {
03002          pen = pe->next;
03003          if (pe->app)
03004             free(pe->app);
03005          pe->app = 0;
03006          if (pe->appargs)
03007             free(pe->appargs);
03008          pe->appargs = 0;
03009          pe->origin = 0;
03010          pe->goto_true = 0;
03011          pe->goto_false = 0;
03012          free(pe);
03013       }
03014       nen = ne->next_exten;
03015       ne->next_exten = 0;
03016       ne->plist =0;
03017       ne->plist_last = 0;
03018       ne->next_exten = 0;
03019       ne->loop_break = 0;
03020       ne->loop_continue = 0;
03021       free(ne);
03022    }
03023 }

void destroy_pval ( pval item  ) 

Definition at line 4979 of file pval.c.

References destroy_pval_item(), and pval::next.

04980 {
04981    pval *i,*nxt;
04982    
04983    for (i=item; i; i=nxt) {
04984       nxt = i->next;
04985       
04986       destroy_pval_item(i);
04987    }
04988 }

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.

04712 {
04713    if (item == NULL) {
04714       ast_log(LOG_WARNING, "null item\n");
04715       return;
04716    }
04717 
04718    if (item->filename)
04719       free(item->filename);
04720    
04721    switch (item->type) {
04722    case PV_WORD:
04723       /* fields: item->u1.str == string associated with this (word). */
04724       if (item->u1.str )
04725          free(item->u1.str);
04726       if ( item->u2.arglist )
04727          destroy_pval(item->u2.arglist);
04728       break;
04729       
04730    case PV_MACRO:
04731       /* fields: item->u1.str     == name of macro
04732                  item->u2.arglist == pval list of PV_WORD arguments of macro, as given by user
04733                item->u2.arglist->u1.str  == argument
04734                item->u2.arglist->next   == next arg
04735 
04736                item->u3.macro_statements == pval list of statements in macro body.
04737       */
04738       destroy_pval(item->u2.arglist);
04739       if (item->u1.str )
04740          free(item->u1.str);
04741       destroy_pval(item->u3.macro_statements);
04742       break;
04743          
04744    case PV_CONTEXT:
04745       /* fields: item->u1.str     == name of context
04746                  item->u2.statements == pval list of statements in context body
04747                item->u3.abstract == int 1 if an abstract keyword were present
04748       */
04749       if (item->u1.str)
04750          free(item->u1.str);
04751       destroy_pval(item->u2.statements);
04752       break;
04753          
04754    case PV_MACRO_CALL:
04755       /* fields: item->u1.str     == name of macro to call
04756                  item->u2.arglist == pval list of PV_WORD arguments of macro call, as given by user
04757                item->u2.arglist->u1.str  == argument
04758                item->u2.arglist->next   == next arg
04759       */
04760       if (item->u1.str)
04761          free(item->u1.str);
04762       destroy_pval(item->u2.arglist);
04763       break;
04764          
04765    case PV_APPLICATION_CALL:
04766       /* fields: item->u1.str     == name of application to call
04767                  item->u2.arglist == pval list of PV_WORD arguments of macro call, as given by user
04768                item->u2.arglist->u1.str  == argument
04769                item->u2.arglist->next   == next arg
04770       */
04771       if (item->u1.str)
04772          free(item->u1.str);
04773       destroy_pval(item->u2.arglist);
04774       break;
04775          
04776    case PV_CASE:
04777       /* fields: item->u1.str     == value of case
04778                  item->u2.statements == pval list of statements under the case
04779       */
04780       if (item->u1.str)
04781          free(item->u1.str);
04782       destroy_pval(item->u2.statements);
04783       break;
04784          
04785    case PV_PATTERN:
04786       /* fields: item->u1.str     == value of case
04787                  item->u2.statements == pval list of statements under the case
04788       */
04789       if (item->u1.str)
04790          free(item->u1.str);
04791       destroy_pval(item->u2.statements);
04792       break;
04793          
04794    case PV_DEFAULT:
04795       /* fields: 
04796                  item->u2.statements == pval list of statements under the case
04797       */
04798       destroy_pval(item->u2.statements);
04799       break;
04800          
04801    case PV_CATCH:
04802       /* fields: item->u1.str     == name of extension to catch
04803                  item->u2.statements == pval list of statements in context body
04804       */
04805       if (item->u1.str)
04806          free(item->u1.str);
04807       destroy_pval(item->u2.statements);
04808       break;
04809          
04810    case PV_SWITCHES:
04811       /* fields: item->u1.list     == pval list of PV_WORD elements, one per entry in the list
04812       */
04813       destroy_pval(item->u1.list);
04814       break;
04815          
04816    case PV_ESWITCHES:
04817       /* fields: item->u1.list     == pval list of PV_WORD elements, one per entry in the list
04818       */
04819       destroy_pval(item->u1.list);
04820       break;
04821          
04822    case PV_INCLUDES:
04823       /* fields: item->u1.list     == pval list of PV_WORD elements, one per entry in the list
04824                  item->u2.arglist  == pval list of 4 PV_WORD elements for time values
04825       */
04826       destroy_pval(item->u1.list);
04827       break;
04828          
04829    case PV_STATEMENTBLOCK:
04830       /* fields: item->u1.list     == pval list of statements in block, one per entry in the list
04831       */
04832       destroy_pval(item->u1.list);
04833       break;
04834          
04835    case PV_LOCALVARDEC:
04836    case PV_VARDEC:
04837       /* fields: item->u1.str     == variable name
04838                  item->u2.val     == variable value to assign
04839       */
04840       if (item->u1.str)
04841          free(item->u1.str);
04842       if (item->u2.val)
04843          free(item->u2.val);
04844       break;
04845          
04846    case PV_GOTO:
04847       /* fields: item->u1.list     == pval list of PV_WORD target names, up to 3, in order as given by user.
04848                  item->u1.list->u1.str  == where the data on a PV_WORD will always be.
04849       */
04850       
04851       destroy_pval(item->u1.list);
04852       break;
04853          
04854    case PV_LABEL:
04855       /* fields: item->u1.str     == label name
04856       */
04857       if (item->u1.str)
04858          free(item->u1.str);
04859       break;
04860          
04861    case PV_FOR:
04862       /* fields: item->u1.for_init     == a string containing the initalizer
04863                  item->u2.for_test     == a string containing the loop test
04864                  item->u3.for_inc      == a string containing the loop increment
04865 
04866                item->u4.for_statements == a pval list of statements in the for ()
04867       */
04868       if (item->u1.for_init)
04869          free(item->u1.for_init);
04870       if (item->u2.for_test)
04871          free(item->u2.for_test);
04872       if (item->u3.for_inc)
04873          free(item->u3.for_inc);
04874       destroy_pval(item->u4.for_statements);
04875       break;
04876          
04877    case PV_WHILE:
04878       /* fields: item->u1.str        == the while conditional, as supplied by user
04879 
04880                item->u2.statements == a pval list of statements in the while ()
04881       */
04882       if (item->u1.str)
04883          free(item->u1.str);
04884       destroy_pval(item->u2.statements);
04885       break;
04886          
04887    case PV_BREAK:
04888       /* fields: none
04889       */
04890       break;
04891          
04892    case PV_RETURN:
04893       /* fields: none
04894       */
04895       break;
04896          
04897    case PV_CONTINUE:
04898       /* fields: none
04899       */
04900       break;
04901          
04902    case PV_IFTIME:
04903       /* fields: item->u1.list        == the 4 time values, in PV_WORD structs, linked list
04904 
04905                item->u2.statements == a pval list of statements in the if ()
04906                item->u3.else_statements == a pval list of statements in the else
04907                                     (could be zero)
04908       */
04909       destroy_pval(item->u1.list);
04910       destroy_pval(item->u2.statements);
04911       if (item->u3.else_statements) {
04912          destroy_pval(item->u3.else_statements);
04913       }
04914       break;
04915          
04916    case PV_RANDOM:
04917       /* fields: item->u1.str        == the random percentage, as supplied by user
04918 
04919                item->u2.statements == a pval list of statements in the true part ()
04920                item->u3.else_statements == a pval list of statements in the else
04921                                     (could be zero)
04922       fall thru to If */
04923    case PV_IF:
04924       /* fields: item->u1.str        == the if conditional, as supplied by user
04925 
04926                item->u2.statements == a pval list of statements in the if ()
04927                item->u3.else_statements == a pval list of statements in the else
04928                                     (could be zero)
04929       */
04930       if (item->u1.str)
04931          free(item->u1.str);
04932       destroy_pval(item->u2.statements);
04933       if (item->u3.else_statements) {
04934          destroy_pval(item->u3.else_statements);
04935       }
04936       break;
04937          
04938    case PV_SWITCH:
04939       /* fields: item->u1.str        == the switch expression
04940 
04941                item->u2.statements == a pval list of statements in the switch, 
04942                                     (will be case statements, most likely!)
04943       */
04944       if (item->u1.str)
04945          free(item->u1.str);
04946       destroy_pval(item->u2.statements);
04947       break;
04948          
04949    case PV_EXTENSION:
04950       /* fields: item->u1.str        == the extension name, label, whatever it's called
04951 
04952                item->u2.statements == a pval list of statements in the extension
04953                item->u3.hints      == a char * hint argument
04954                item->u4.regexten   == an int boolean. non-zero says that regexten was specified
04955       */
04956       if (item->u1.str)
04957          free(item->u1.str);
04958       if (item->u3.hints)
04959          free(item->u3.hints);
04960       destroy_pval(item->u2.statements);
04961       break;
04962          
04963    case PV_IGNOREPAT:
04964       /* fields: item->u1.str        == the ignorepat data
04965       */
04966       if (item->u1.str)
04967          free(item->u1.str);
04968       break;
04969          
04970    case PV_GLOBALS:
04971       /* fields: item->u1.statements     == pval list of statements, usually vardecs
04972       */
04973       destroy_pval(item->u1.statements);
04974       break;
04975    }
04976    free(item);
04977 }

struct pval* find_context ( char *  name  )  [read]

Definition at line 1960 of file pval.c.

References match_pval().

01961 {
01962    return_on_context_match = 1;
01963    count_labels = 0;
01964    match_context = name;
01965    match_exten = "*";  /* don't really need to set these, shouldn't be reached */
01966    match_label = "*";
01967    return match_pval(current_db);
01968 }

struct pval* find_macro ( char *  name  )  [read]

Definition at line 1950 of file pval.c.

References match_pval().

01951 {
01952    return_on_context_match = 1;
01953    count_labels = 0;
01954    match_context = name;
01955    match_exten = "*";  /* don't really need to set these, shouldn't be reached */
01956    match_label = "*";
01957    return match_pval(current_db);
01958 }

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

Definition at line 241 of file pbx_ael.c.

References ast_cli_args::argc, CLI_FAILURE, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, pbx_load_module(), and ast_cli_entry::usage.

00242 {
00243    switch (cmd) {
00244    case CLI_INIT:
00245       e->command = "ael reload";
00246       e->usage =
00247          "Usage: ael reload\n"
00248          "       Reloads AEL configuration.\n";
00249       return NULL;
00250    case CLI_GENERATE:
00251       return NULL;
00252    }
00253 
00254    if (a->argc != 2)
00255       return CLI_SHOWUSAGE;
00256 
00257    return (pbx_load_module() ? CLI_FAILURE : CLI_SUCCESS);
00258 }

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

Definition at line 207 of file pbx_ael.c.

References ast_cli_args::argc, ast_cli_entry::args, ast_cli_args::argv, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, DEBUG_CONTEXTS, DEBUG_MACROS, DEBUG_READ, DEBUG_TOKENS, and ast_cli_entry::usage.

00208 {
00209    switch (cmd) {
00210    case CLI_INIT:
00211       e->command = "ael set debug {read|tokens|macros|contexts|off}";
00212       e->usage =
00213          "Usage: ael set debug {read|tokens|macros|contexts|off}\n"
00214          "       Enable AEL read, token, macro, or context debugging,\n"
00215          "       or disable all AEL debugging messages.  Note: this\n"
00216          "       currently does nothing.\n";
00217       return NULL;
00218    case CLI_GENERATE:
00219       return NULL;
00220    }
00221 
00222    if (a->argc != e->args)
00223       return CLI_SHOWUSAGE;
00224 
00225    if (!strcasecmp(a->argv[3], "read"))
00226       aeldebug |= DEBUG_READ;
00227    else if (!strcasecmp(a->argv[3], "tokens"))
00228       aeldebug |= DEBUG_TOKENS;
00229    else if (!strcasecmp(a->argv[3], "macros"))
00230       aeldebug |= DEBUG_MACROS;
00231    else if (!strcasecmp(a->argv[3], "contexts"))
00232       aeldebug |= DEBUG_CONTEXTS;
00233    else if (!strcasecmp(a->argv[3], "off"))
00234       aeldebug = 0;
00235    else
00236       return CLI_SHOWUSAGE;
00237 
00238    return CLI_SUCCESS;
00239 }

int is_empty ( char *  arg  ) 

Definition at line 1988 of file pval.c.

01989 {
01990    if (!arg)
01991       return 1;
01992    if (*arg == 0)
01993       return 1;
01994    while (*arg) {
01995       if (*arg != ' ' && *arg != '\t')
01996          return 0;
01997       arg++;
01998    }
01999    return 1;
02000 }

int is_float ( char *  arg  ) 

Definition at line 1970 of file pval.c.

01971 {
01972    char *s;
01973    for (s=arg; *s; s++) {
01974       if (*s != '.' && (*s < '0' || *s > '9'))
01975          return 0;
01976    }
01977    return 1;
01978 }

int is_int ( char *  arg  ) 

Definition at line 1979 of file pval.c.

01980 {
01981    char *s;
01982    for (s=arg; *s; s++) {
01983       if (*s < '0' || *s > '9')
01984          return 0;
01985    }
01986    return 1;
01987 }

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().

00276 {
00277    ast_cli_register_multiple(cli_ael, ARRAY_LEN(cli_ael));
00278 #ifndef STANDALONE
00279    ast_register_application_xml(aelsub, aelsub_exec);
00280 #endif
00281    return (pbx_load_module());
00282 }

struct ael_extension* new_exten ( void   )  [read]

Definition at line 2937 of file pval.c.

References calloc.

02938 {
02939    struct ael_extension *x = (struct ael_extension *)calloc(sizeof(struct ael_extension),1);
02940    return x;
02941 }

struct ael_priority* new_prio ( void   )  [read]

Definition at line 2931 of file pval.c.

References calloc.

02932 {
02933    struct ael_priority *x = (struct ael_priority *)calloc(sizeof(struct ael_priority),1);
02934    return x;
02935 }

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().

00156 {
00157    int errs=0, sem_err=0, sem_warn=0, sem_note=0;
00158    char *rfilename;
00159    struct ast_context *local_contexts=NULL, *con;
00160    struct ast_hashtab *local_table=NULL;
00161    
00162    struct pval *parse_tree;
00163 
00164    ast_log(LOG_NOTICE, "Starting AEL load process.\n");
00165    if (config[0] == '/')
00166       rfilename = (char *)config;
00167    else {
00168       rfilename = ast_alloca(strlen(config) + strlen(ast_config_AST_CONFIG_DIR) + 2);
00169       sprintf(rfilename, "%s/%s", ast_config_AST_CONFIG_DIR, config);
00170    }
00171    if (access(rfilename,R_OK) != 0) {
00172       ast_log(LOG_NOTICE, "File %s not found; AEL declining load\n", rfilename);
00173       return AST_MODULE_LOAD_DECLINE;
00174    }
00175    
00176    parse_tree = ael2_parse(rfilename, &errs);
00177    ast_log(LOG_NOTICE, "AEL load process: parsed config file name '%s'.\n", rfilename);
00178    ael2_semantic_check(parse_tree, &sem_err, &sem_warn, &sem_note);
00179    if (errs == 0 && sem_err == 0) {
00180       ast_log(LOG_NOTICE, "AEL load process: checked config file name '%s'.\n", rfilename);
00181       local_table = ast_hashtab_create(11, ast_hashtab_compare_contexts, ast_hashtab_resize_java, ast_hashtab_newsize_java, ast_hashtab_hash_contexts, 0);
00182       if (ast_compile_ael2(&local_contexts, local_table, parse_tree)) {
00183          ast_log(LOG_ERROR, "AEL compile failed! Aborting.\n");
00184          destroy_pval(parse_tree); /* free up the memory */
00185          return AST_MODULE_LOAD_DECLINE;
00186       }
00187       ast_log(LOG_NOTICE, "AEL load process: compiled config file name '%s'.\n", rfilename);
00188       
00189       ast_merge_contexts_and_delete(&local_contexts, local_table, registrar);
00190       local_table = NULL; /* it's the dialplan global now */
00191       local_contexts = NULL;
00192       ast_log(LOG_NOTICE, "AEL load process: merged config file name '%s'.\n", rfilename);
00193       for (con = ast_walk_contexts(NULL); con; con = ast_walk_contexts(con))
00194          ast_context_verify_includes(con);
00195       ast_log(LOG_NOTICE, "AEL load process: verified config file name '%s'.\n", rfilename);
00196    } else {
00197       ast_log(LOG_ERROR, "Sorry, but %d syntax errors and %d semantic errors were detected. It doesn't make sense to compile.\n", errs, sem_err);
00198       destroy_pval(parse_tree); /* free up the memory */
00199       return AST_MODULE_LOAD_DECLINE;
00200    }
00201    destroy_pval(parse_tree); /* free up the memory */
00202    
00203    return AST_MODULE_LOAD_SUCCESS;
00204 }

static int reload ( void   )  [static]

Definition at line 284 of file pbx_ael.c.

References pbx_load_module().

00285 {
00286    return pbx_load_module();
00287 }

void set_priorities ( struct ael_extension exten  ) 

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

04226 {
04227    int i;
04228    struct ael_priority *pr;
04229    do {
04230       if (exten->is_switch)
04231          i = 10;
04232       else if (exten->regexten)
04233          i=2;
04234       else
04235          i=1;
04236       
04237       for (pr=exten->plist; pr; pr=pr->next) {
04238          pr->priority_num = i;
04239          
04240          if (!pr->origin || (pr->origin && pr->origin->type != PV_LABEL) ) /* Labels don't show up in the dialplan,
04241                                       but we want them to point to the right
04242                                       priority, which would be the next line
04243                                       after the label; */
04244             i++;
04245       }
04246       
04247       exten = exten->next_exten;
04248    } while ( exten );
04249 }

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().

00266 {
00267    ast_context_destroy(NULL, registrar);
00268    ast_cli_unregister_multiple(cli_ael, ARRAY_LEN(cli_ael));
00269 #ifndef STANDALONE
00270    ast_unregister_application(aelsub);
00271 #endif
00272    return 0;
00273 }


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")
}

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.


Generated on 7 Aug 2019 for Asterisk - The Open Source Telephony Project by  doxygen 1.6.1