Fri Nov 12 12:06:27 2010

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

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)
void 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 = "0901e4e500243c855563a2d78b0c03e4" , .load = load_module, .unload = unload_module, .reload = reload, }
static int aeldebug = 0
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 63 of file pbx_ael.c.

Referenced by handle_cli_ael_set_debug().

#define DEBUG_MACROS   (1 << 2)

Definition at line 62 of file pbx_ael.c.

Referenced by handle_cli_ael_set_debug().

#define DEBUG_READ   (1 << 0)

Definition at line 60 of file pbx_ael.c.

Referenced by handle_cli_ael_set_debug().

#define DEBUG_TOKENS   (1 << 1)

Definition at line 61 of file pbx_ael.c.

Referenced by handle_cli_ael_set_debug().


Function Documentation

static void __reg_module ( void   )  [static]

Definition at line 251 of file pbx_ael.c.

00255 {

static void __unreg_module ( void   )  [static]

Definition at line 251 of file pbx_ael.c.

00255 {

void add_extensions ( struct ael_extension exten  ) 

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

04208 {
04209    struct ael_priority *pr;
04210    char *label=0;
04211    char realext[AST_MAX_EXTENSION];
04212    if (!exten) {
04213       ast_log(LOG_WARNING, "This file is Empty!\n" );
04214       return;
04215    }
04216    do {
04217       struct ael_priority *last = 0;
04218       
04219       pbx_substitute_variables_helper(NULL, exten->name, realext, sizeof(realext) - 1);
04220       if (exten->hints) {
04221          if (ast_add_extension2(exten->context, 0 /*no replace*/, realext, PRIORITY_HINT, NULL, exten->cidmatch, 
04222                           exten->hints, NULL, ast_free_ptr, registrar)) {
04223             ast_log(LOG_WARNING, "Unable to add step at priority 'hint' of extension '%s'\n",
04224                   exten->name);
04225          }
04226       }
04227       
04228       for (pr=exten->plist; pr; pr=pr->next) {
04229          char app[2000];
04230          char appargs[2000];
04231 
04232          /* before we can add the extension, we need to prep the app/appargs;
04233             the CONTROL types need to be done after the priority numbers are calculated.
04234          */
04235          if (pr->type == AEL_LABEL) /* don't try to put labels in the dialplan! */ {
04236             last = pr;
04237             continue;
04238          }
04239          
04240          if (pr->app)
04241             strcpy(app, pr->app);
04242          else
04243             app[0] = 0;
04244          if (pr->appargs )
04245             strcpy(appargs, pr->appargs);
04246          else
04247             appargs[0] = 0;
04248          switch( pr->type ) {
04249          case AEL_APPCALL:
04250             /* easy case. Everything is all set up */
04251             break;
04252             
04253          case AEL_CONTROL1: /* FOR loop, WHILE loop, BREAK, CONTINUE, IF, IFTIME */
04254             /* simple, unconditional goto. */
04255             strcpy(app,"Goto");
04256             if (pr->goto_true->origin && pr->goto_true->origin->type == PV_SWITCH ) {
04257                snprintf(appargs,sizeof(appargs),"%s,%d", pr->goto_true->exten->name, pr->goto_true->priority_num);
04258             } else if (pr->goto_true->origin && pr->goto_true->origin->type == PV_IFTIME && pr->goto_true->origin->u3.else_statements ) {
04259                snprintf(appargs,sizeof(appargs),"%d", pr->goto_true->priority_num+1);
04260             } else
04261                snprintf(appargs,sizeof(appargs),"%d", pr->goto_true->priority_num);
04262             break;
04263             
04264          case AEL_FOR_CONTROL:  /* WHILE loop test, FOR loop test */
04265             strcpy(app,"GotoIf");
04266             snprintf(appargs,sizeof(appargs),"%s?%d:%d", pr->appargs, pr->priority_num+1, pr->goto_false->priority_num);
04267             break;
04268             
04269          case AEL_IF_CONTROL:
04270             strcpy(app,"GotoIf");
04271             if (pr->origin->u3.else_statements )
04272                snprintf(appargs,sizeof(appargs),"%s?%d:%d", pr->appargs, pr->priority_num+1, pr->goto_false->priority_num+1);
04273             else
04274                snprintf(appargs,sizeof(appargs),"%s?%d:%d", pr->appargs, pr->priority_num+1, pr->goto_false->priority_num);
04275             break;
04276 
04277          case AEL_RAND_CONTROL:
04278             strcpy(app,"Random");
04279             snprintf(appargs,sizeof(appargs),"%s:%d", pr->appargs, pr->goto_true->priority_num+1);
04280             break;
04281 
04282          case AEL_IFTIME_CONTROL:
04283             strcpy(app,"GotoIfTime");
04284             snprintf(appargs,sizeof(appargs),"%s?%d", pr->appargs, pr->priority_num+2);
04285             break;
04286 
04287          case AEL_RETURN:
04288             strcpy(app,"Return");
04289             appargs[0] = 0;
04290             break;
04291             
04292          default:
04293             break;
04294          }
04295          if (last && last->type == AEL_LABEL ) {
04296             label = last->origin->u1.str;
04297          }
04298          else
04299             label = 0;
04300          
04301          if (ast_add_extension2(exten->context, 0 /*no replace*/, realext, pr->priority_num, (label?label:NULL), exten->cidmatch, 
04302                           app, strdup(appargs), ast_free_ptr, registrar)) {
04303             ast_log(LOG_WARNING, "Unable to add step at priority '%d' of extension '%s'\n", pr->priority_num, 
04304                   exten->name);
04305          }
04306          last = pr;
04307       }
04308       exten = exten->next_exten;
04309    } while ( exten );
04310 }

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

Definition at line 4393 of file pval.c.

References add_extensions(), AEL_APPCALL, AEL_LABEL, ael_priority::app, ael_priority::appargs, pval::arglist, ast_compat_app_set, ast_context_add_ignorepat2(), ast_context_add_include2(), ast_context_add_switch2(), ast_context_find_or_create(), attach_exten(), buf, buf2, ael_extension::cidmatch, ael_extension::context, context, 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_priority::origin, pbx_builtin_setvar(), ael_extension::plist_last, 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.

04394 {
04395    pval *p,*p2;
04396    struct ast_context *context;
04397    char buf[2000];
04398    struct ael_extension *exten;
04399    struct ael_extension *exten_list = 0;
04400 
04401    for (p=root; p; p=p->next ) { /* do the globals first, so they'll be there
04402                             when we try to eval them */
04403       switch (p->type) {
04404       case PV_GLOBALS:
04405          /* just VARDEC elements */
04406          for (p2=p->u1.list; p2; p2=p2->next) {
04407             char buf2[2000];
04408             snprintf(buf2,sizeof(buf2),"%s=%s", p2->u1.str, p2->u2.val);
04409             pbx_builtin_setvar(NULL, buf2);
04410          }
04411          break;
04412       default:
04413          break;
04414       }
04415    }
04416 
04417    for (p=root; p; p=p->next ) {
04418       pval *lp;
04419       int argc;
04420       
04421       switch (p->type) {
04422       case PV_MACRO:
04423          
04424          context = ast_context_find_or_create(local_contexts, local_table, p->u1.str, registrar);
04425          
04426          exten = new_exten();
04427          exten->context = context;
04428          exten->name = strdup("s");
04429          argc = 1;
04430          for (lp=p->u2.arglist; lp; lp=lp->next) {
04431             /* for each arg, set up a "Set" command */
04432             struct ael_priority *np2 = new_prio();
04433             np2->type = AEL_APPCALL;
04434             if (!ast_compat_app_set) {
04435                np2->app = strdup("MSet");
04436             } else {
04437                np2->app = strdup("Set");
04438             }
04439             snprintf(buf,sizeof(buf),"LOCAL(%s)=${ARG%d}", lp->u1.str, argc++);
04440             remove_spaces_before_equals(buf);
04441             np2->appargs = strdup(buf);
04442             linkprio(exten, np2, NULL);
04443          }
04444          
04445          /* CONTAINS APPCALLS, CATCH, just like extensions... */
04446          gen_prios(exten, p->u1.str, p->u3.macro_statements, 0, context );
04447          if (exten->return_needed) {  /* most likely, this will go away */
04448             struct ael_priority *np2 = new_prio();
04449             np2->type = AEL_APPCALL;
04450             np2->app = strdup("NoOp");
04451             snprintf(buf,sizeof(buf),"End of Macro %s-%s",p->u1.str, exten->name);
04452             np2->appargs = strdup(buf);
04453             linkprio(exten, np2, NULL);
04454             exten-> return_target = np2;
04455          }
04456          
04457          set_priorities(exten);
04458          attach_exten(&exten_list, exten);
04459          break;
04460          
04461       case PV_GLOBALS:
04462          /* already done */
04463          break;
04464          
04465       case PV_CONTEXT:
04466          context = ast_context_find_or_create(local_contexts, local_table, p->u1.str, registrar);
04467          
04468          /* contexts contain: ignorepat, includes, switches, eswitches, extensions,  */
04469          for (p2=p->u2.statements; p2; p2=p2->next) {
04470             pval *p3;
04471             char *s3;
04472             
04473             switch (p2->type) {
04474             case PV_EXTENSION:
04475                exten = new_exten();
04476                exten->name = strdup(p2->u1.str);
04477                exten->context = context;
04478                
04479                if( (s3=strchr(exten->name, '/') ) != 0 )
04480                {
04481                   *s3 = 0;
04482                   exten->cidmatch = s3+1;
04483                }
04484                
04485                if ( p2->u3.hints )
04486                   exten->hints = strdup(p2->u3.hints);
04487                exten->regexten = p2->u4.regexten;
04488                gen_prios(exten, p->u1.str, p2->u2.statements, 0, context );
04489                if (exten->return_needed) { /* returns don't generate a goto eoe (end of extension) any more, just a Return() app call) */
04490                   struct ael_priority *np2 = new_prio();
04491                   np2->type = AEL_APPCALL;
04492                   np2->app = strdup("NoOp");
04493                   snprintf(buf,sizeof(buf),"End of Extension %s", exten->name);
04494                   np2->appargs = strdup(buf);
04495                   linkprio(exten, np2, NULL);
04496                   exten-> return_target = np2;
04497                }
04498                /* is the last priority in the extension a label? Then add a trailing no-op */
04499                if ( exten->plist_last && exten->plist_last->type == AEL_LABEL ) {
04500                   struct ael_priority *np2 = new_prio();
04501                   np2->type = AEL_APPCALL;
04502                   np2->app = strdup("NoOp");
04503                   snprintf(buf,sizeof(buf),"A NoOp to follow a trailing label %s", exten->plist_last->origin->u1.str);
04504                   np2->appargs = strdup(buf);
04505                   linkprio(exten, np2, NULL);
04506                }
04507 
04508                set_priorities(exten);
04509                attach_exten(&exten_list, exten);
04510                break;
04511                
04512             case PV_IGNOREPAT:
04513                ast_context_add_ignorepat2(context, p2->u1.str, registrar);
04514                break;
04515                
04516             case PV_INCLUDES:
04517                for (p3 = p2->u1.list; p3 ;p3=p3->next) {
04518                   if ( p3->u2.arglist ) {
04519                      snprintf(buf,sizeof(buf), "%s,%s,%s,%s,%s", 
04520                             p3->u1.str,
04521                             p3->u2.arglist->u1.str,
04522                             p3->u2.arglist->next->u1.str,
04523                             p3->u2.arglist->next->next->u1.str,
04524                             p3->u2.arglist->next->next->next->u1.str);
04525                      ast_context_add_include2(context, buf, registrar);
04526                   } else
04527                      ast_context_add_include2(context, p3->u1.str, registrar);
04528                }
04529                break;
04530                
04531             case PV_SWITCHES:
04532                for (p3 = p2->u1.list; p3 ;p3=p3->next) {
04533                   char *c = strchr(p3->u1.str, '/');
04534                   if (c) {
04535                      *c = '\0';
04536                      c++;
04537                   } else
04538                      c = "";
04539 
04540                   ast_context_add_switch2(context, p3->u1.str, c, 0, registrar);
04541                }
04542                break;
04543 
04544             case PV_ESWITCHES:
04545                for (p3 = p2->u1.list; p3 ;p3=p3->next) {
04546                   char *c = strchr(p3->u1.str, '/');
04547                   if (c) {
04548                      *c = '\0';
04549                      c++;
04550                   } else
04551                      c = "";
04552 
04553                   ast_context_add_switch2(context, p3->u1.str, c, 1, registrar);
04554                }
04555                break;
04556             default:
04557                break;
04558             }
04559          }
04560          
04561          break;
04562          
04563       default:
04564          /* huh? what? */
04565          break;
04566          
04567       }
04568    }
04569    /* moved these from being done after a macro or extension were processed,
04570       to after all processing is done, for the sake of fixing gotos to labels inside cases... */
04571    /* I guess this would be considered 2nd pass of compiler now... */
04572    fix_gotos_in_extensions(exten_list); /* find and fix extension ref in gotos to labels that are in case statements */
04573    add_extensions(exten_list);   /* actually makes calls to create priorities in ast_contexts -- feeds dialplan to asterisk */
04574    destroy_extensions(exten_list);  /* all that remains is an empty husk, discard of it as is proper */
04575    
04576 }

void ast_expr_clear_extra_error_info ( void   ) 

Definition at line 2456 of file ast_expr2f.c.

02457 {
02458        extra_error_message_supplied=0;
02459        extra_error_message[0] = 0;
02460 }

void ast_expr_register_extra_error_info ( char *  errmsg  ) 

Definition at line 2450 of file ast_expr2f.c.

02451 {
02452        extra_error_message_supplied=1;
02453        strcpy(extra_error_message, message);
02454 }

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

Definition at line 2126 of file pval.c.

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

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

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

Definition at line 2862 of file pval.c.

References check_pval_item(), and pval::next.

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

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

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

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

void check_switch_expr ( pval item,
struct argapp apps 
)

Definition at line 2180 of file pval.c.

References ast_log(), 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.

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

void destroy_extensions ( struct ael_extension exten  ) 

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

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

void destroy_pval ( pval item  ) 

Definition at line 4851 of file pval.c.

References destroy_pval_item(), and pval::next.

04852 {
04853    pval *i,*nxt;
04854    
04855    for (i=item; i; i=nxt) {
04856       nxt = i->next;
04857       
04858       destroy_pval_item(i);
04859    }
04860 }

void destroy_pval_item ( pval item  ) 

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

04584 {
04585    if (item == NULL) {
04586       ast_log(LOG_WARNING, "null item\n");
04587       return;
04588    }
04589 
04590    if (item->filename)
04591       free(item->filename);
04592    
04593    switch (item->type) {
04594    case PV_WORD:
04595       /* fields: item->u1.str == string associated with this (word). */
04596       if (item->u1.str )
04597          free(item->u1.str);
04598       if ( item->u2.arglist )
04599          destroy_pval(item->u2.arglist);
04600       break;
04601       
04602    case PV_MACRO:
04603       /* fields: item->u1.str     == name of macro
04604                  item->u2.arglist == pval list of PV_WORD arguments of macro, as given by user
04605                item->u2.arglist->u1.str  == argument
04606                item->u2.arglist->next   == next arg
04607 
04608                item->u3.macro_statements == pval list of statements in macro body.
04609       */
04610       destroy_pval(item->u2.arglist);
04611       if (item->u1.str )
04612          free(item->u1.str);
04613       destroy_pval(item->u3.macro_statements);
04614       break;
04615          
04616    case PV_CONTEXT:
04617       /* fields: item->u1.str     == name of context
04618                  item->u2.statements == pval list of statements in context body
04619                item->u3.abstract == int 1 if an abstract keyword were present
04620       */
04621       if (item->u1.str)
04622          free(item->u1.str);
04623       destroy_pval(item->u2.statements);
04624       break;
04625          
04626    case PV_MACRO_CALL:
04627       /* fields: item->u1.str     == name of macro to call
04628                  item->u2.arglist == pval list of PV_WORD arguments of macro call, as given by user
04629                item->u2.arglist->u1.str  == argument
04630                item->u2.arglist->next   == next arg
04631       */
04632       if (item->u1.str)
04633          free(item->u1.str);
04634       destroy_pval(item->u2.arglist);
04635       break;
04636          
04637    case PV_APPLICATION_CALL:
04638       /* fields: item->u1.str     == name of application to call
04639                  item->u2.arglist == pval list of PV_WORD arguments of macro call, as given by user
04640                item->u2.arglist->u1.str  == argument
04641                item->u2.arglist->next   == next arg
04642       */
04643       if (item->u1.str)
04644          free(item->u1.str);
04645       destroy_pval(item->u2.arglist);
04646       break;
04647          
04648    case PV_CASE:
04649       /* fields: item->u1.str     == value of case
04650                  item->u2.statements == pval list of statements under the case
04651       */
04652       if (item->u1.str)
04653          free(item->u1.str);
04654       destroy_pval(item->u2.statements);
04655       break;
04656          
04657    case PV_PATTERN:
04658       /* fields: item->u1.str     == value of case
04659                  item->u2.statements == pval list of statements under the case
04660       */
04661       if (item->u1.str)
04662          free(item->u1.str);
04663       destroy_pval(item->u2.statements);
04664       break;
04665          
04666    case PV_DEFAULT:
04667       /* fields: 
04668                  item->u2.statements == pval list of statements under the case
04669       */
04670       destroy_pval(item->u2.statements);
04671       break;
04672          
04673    case PV_CATCH:
04674       /* fields: item->u1.str     == name of extension to catch
04675                  item->u2.statements == pval list of statements in context body
04676       */
04677       if (item->u1.str)
04678          free(item->u1.str);
04679       destroy_pval(item->u2.statements);
04680       break;
04681          
04682    case PV_SWITCHES:
04683       /* fields: item->u1.list     == pval list of PV_WORD elements, one per entry in the list
04684       */
04685       destroy_pval(item->u1.list);
04686       break;
04687          
04688    case PV_ESWITCHES:
04689       /* fields: item->u1.list     == pval list of PV_WORD elements, one per entry in the list
04690       */
04691       destroy_pval(item->u1.list);
04692       break;
04693          
04694    case PV_INCLUDES:
04695       /* fields: item->u1.list     == pval list of PV_WORD elements, one per entry in the list
04696                  item->u2.arglist  == pval list of 4 PV_WORD elements for time values
04697       */
04698       destroy_pval(item->u1.list);
04699       break;
04700          
04701    case PV_STATEMENTBLOCK:
04702       /* fields: item->u1.list     == pval list of statements in block, one per entry in the list
04703       */
04704       destroy_pval(item->u1.list);
04705       break;
04706          
04707    case PV_LOCALVARDEC:
04708    case PV_VARDEC:
04709       /* fields: item->u1.str     == variable name
04710                  item->u2.val     == variable value to assign
04711       */
04712       if (item->u1.str)
04713          free(item->u1.str);
04714       if (item->u2.val)
04715          free(item->u2.val);
04716       break;
04717          
04718    case PV_GOTO:
04719       /* fields: item->u1.list     == pval list of PV_WORD target names, up to 3, in order as given by user.
04720                  item->u1.list->u1.str  == where the data on a PV_WORD will always be.
04721       */
04722       
04723       destroy_pval(item->u1.list);
04724       break;
04725          
04726    case PV_LABEL:
04727       /* fields: item->u1.str     == label name
04728       */
04729       if (item->u1.str)
04730          free(item->u1.str);
04731       break;
04732          
04733    case PV_FOR:
04734       /* fields: item->u1.for_init     == a string containing the initalizer
04735                  item->u2.for_test     == a string containing the loop test
04736                  item->u3.for_inc      == a string containing the loop increment
04737 
04738                item->u4.for_statements == a pval list of statements in the for ()
04739       */
04740       if (item->u1.for_init)
04741          free(item->u1.for_init);
04742       if (item->u2.for_test)
04743          free(item->u2.for_test);
04744       if (item->u3.for_inc)
04745          free(item->u3.for_inc);
04746       destroy_pval(item->u4.for_statements);
04747       break;
04748          
04749    case PV_WHILE:
04750       /* fields: item->u1.str        == the while conditional, as supplied by user
04751 
04752                item->u2.statements == a pval list of statements in the while ()
04753       */
04754       if (item->u1.str)
04755          free(item->u1.str);
04756       destroy_pval(item->u2.statements);
04757       break;
04758          
04759    case PV_BREAK:
04760       /* fields: none
04761       */
04762       break;
04763          
04764    case PV_RETURN:
04765       /* fields: none
04766       */
04767       break;
04768          
04769    case PV_CONTINUE:
04770       /* fields: none
04771       */
04772       break;
04773          
04774    case PV_IFTIME:
04775       /* fields: item->u1.list        == the 4 time values, in PV_WORD structs, linked list
04776 
04777                item->u2.statements == a pval list of statements in the if ()
04778                item->u3.else_statements == a pval list of statements in the else
04779                                     (could be zero)
04780       */
04781       destroy_pval(item->u1.list);
04782       destroy_pval(item->u2.statements);
04783       if (item->u3.else_statements) {
04784          destroy_pval(item->u3.else_statements);
04785       }
04786       break;
04787          
04788    case PV_RANDOM:
04789       /* fields: item->u1.str        == the random percentage, as supplied by user
04790 
04791                item->u2.statements == a pval list of statements in the true part ()
04792                item->u3.else_statements == a pval list of statements in the else
04793                                     (could be zero)
04794       fall thru to If */
04795    case PV_IF:
04796       /* fields: item->u1.str        == the if conditional, as supplied by user
04797 
04798                item->u2.statements == a pval list of statements in the if ()
04799                item->u3.else_statements == a pval list of statements in the else
04800                                     (could be zero)
04801       */
04802       if (item->u1.str)
04803          free(item->u1.str);
04804       destroy_pval(item->u2.statements);
04805       if (item->u3.else_statements) {
04806          destroy_pval(item->u3.else_statements);
04807       }
04808       break;
04809          
04810    case PV_SWITCH:
04811       /* fields: item->u1.str        == the switch expression
04812 
04813                item->u2.statements == a pval list of statements in the switch, 
04814                                     (will be case statements, most likely!)
04815       */
04816       if (item->u1.str)
04817          free(item->u1.str);
04818       destroy_pval(item->u2.statements);
04819       break;
04820          
04821    case PV_EXTENSION:
04822       /* fields: item->u1.str        == the extension name, label, whatever it's called
04823 
04824                item->u2.statements == a pval list of statements in the extension
04825                item->u3.hints      == a char * hint argument
04826                item->u4.regexten   == an int boolean. non-zero says that regexten was specified
04827       */
04828       if (item->u1.str)
04829          free(item->u1.str);
04830       if (item->u3.hints)
04831          free(item->u3.hints);
04832       destroy_pval(item->u2.statements);
04833       break;
04834          
04835    case PV_IGNOREPAT:
04836       /* fields: item->u1.str        == the ignorepat data
04837       */
04838       if (item->u1.str)
04839          free(item->u1.str);
04840       break;
04841          
04842    case PV_GLOBALS:
04843       /* fields: item->u1.statements     == pval list of statements, usually vardecs
04844       */
04845       destroy_pval(item->u1.statements);
04846       break;
04847    }
04848    free(item);
04849 }

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

Definition at line 1949 of file pval.c.

References match_pval().

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

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

Definition at line 1939 of file pval.c.

References match_pval().

01940 {
01941    return_on_context_match = 1;
01942    count_labels = 0;
01943    match_context = name;
01944    match_exten = "*";  /* don't really need to set these, shouldn't be reached */
01945    match_label = "*";
01946    return match_pval(current_db);
01947 }

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

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

00196 {
00197    switch (cmd) {
00198    case CLI_INIT:
00199       e->command = "ael reload";
00200       e->usage =
00201          "Usage: ael reload\n"
00202          "       Reloads AEL configuration.\n";
00203       return NULL;
00204    case CLI_GENERATE:
00205       return NULL;
00206    }
00207 
00208    if (a->argc != 2)
00209       return CLI_SHOWUSAGE;
00210 
00211    return (pbx_load_module() ? CLI_FAILURE : CLI_SUCCESS);
00212 }

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

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

00162 {
00163    switch (cmd) {
00164    case CLI_INIT:
00165       e->command = "ael set debug {read|tokens|macros|contexts|off}";
00166       e->usage =
00167          "Usage: ael set debug {read|tokens|macros|contexts|off}\n"
00168          "       Enable AEL read, token, macro, or context debugging,\n"
00169          "       or disable all AEL debugging messages.  Note: this\n"
00170          "       currently does nothing.\n";
00171       return NULL;
00172    case CLI_GENERATE:
00173       return NULL;
00174    }
00175 
00176    if (a->argc != e->args)
00177       return CLI_SHOWUSAGE;
00178 
00179    if (!strcasecmp(a->argv[3], "read"))
00180       aeldebug |= DEBUG_READ;
00181    else if (!strcasecmp(a->argv[3], "tokens"))
00182       aeldebug |= DEBUG_TOKENS;
00183    else if (!strcasecmp(a->argv[3], "macros"))
00184       aeldebug |= DEBUG_MACROS;
00185    else if (!strcasecmp(a->argv[3], "contexts"))
00186       aeldebug |= DEBUG_CONTEXTS;
00187    else if (!strcasecmp(a->argv[3], "off"))
00188       aeldebug = 0;
00189    else
00190       return CLI_SHOWUSAGE;
00191 
00192    return CLI_SUCCESS;
00193 }

int is_empty ( char *  arg  ) 

Definition at line 1977 of file pval.c.

01978 {
01979    if (!arg)
01980       return 1;
01981    if (*arg == 0)
01982       return 1;
01983    while (*arg) {
01984       if (*arg != ' ' && *arg != '\t')
01985          return 0;
01986       arg++;
01987    }
01988    return 1;
01989 }

int is_float ( char *  arg  ) 

Definition at line 1959 of file pval.c.

References s.

01960 {
01961    char *s;
01962    for (s=arg; *s; s++) {
01963       if (*s != '.' && (*s < '0' || *s > '9'))
01964          return 0;
01965    }
01966    return 1;
01967 }

int is_int ( char *  arg  ) 

Definition at line 1968 of file pval.c.

References s.

01969 {
01970    char *s;
01971    for (s=arg; *s; s++) {
01972       if (*s < '0' || *s > '9')
01973          return 0;
01974    }
01975    return 1;
01976 }

static int load_module ( void   )  [static]

Definition at line 226 of file pbx_ael.c.

References ARRAY_LEN, ast_cli_register_multiple(), and pbx_load_module().

00227 {
00228    ast_cli_register_multiple(cli_ael, ARRAY_LEN(cli_ael));
00229    return (pbx_load_module());
00230 }

struct ael_extension* new_exten ( void   )  [read]

Definition at line 2927 of file pval.c.

References calloc.

02928 {
02929    struct ael_extension *x = (struct ael_extension *)calloc(sizeof(struct ael_extension),1);
02930    return x;
02931 }

struct ael_priority* new_prio ( void   )  [read]

Definition at line 2921 of file pval.c.

References calloc.

02922 {
02923    struct ael_priority *x = (struct ael_priority *)calloc(sizeof(struct ael_priority),1);
02924    return x;
02925 }

static int pbx_load_module ( void   )  [static]

Definition at line 113 of file pbx_ael.c.

References ael2_parse(), ael2_semantic_check(), ast_compile_ael2(), ast_config_AST_CONFIG_DIR, ast_context_verify_includes(), ast_hashtab_compare_contexts(), ast_hashtab_create(), ast_hashtab_hash_contexts(), ast_hashtab_newsize_java(), ast_hashtab_resize_java(), ast_log(), ast_merge_contexts_and_delete(), AST_MODULE_LOAD_DECLINE, AST_MODULE_LOAD_SUCCESS, ast_walk_contexts(), destroy_pval(), errs, local_contexts, local_table, LOG_ERROR, and LOG_NOTICE.

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

00114 {
00115    int errs=0, sem_err=0, sem_warn=0, sem_note=0;
00116    char *rfilename;
00117    struct ast_context *local_contexts=NULL, *con;
00118    struct ast_hashtab *local_table=NULL;
00119    
00120    struct pval *parse_tree;
00121 
00122    ast_log(LOG_NOTICE, "Starting AEL load process.\n");
00123    if (config[0] == '/')
00124       rfilename = (char *)config;
00125    else {
00126       rfilename = alloca(strlen(config) + strlen(ast_config_AST_CONFIG_DIR) + 2);
00127       sprintf(rfilename, "%s/%s", ast_config_AST_CONFIG_DIR, config);
00128    }
00129    if (access(rfilename,R_OK) != 0) {
00130       ast_log(LOG_NOTICE, "File %s not found; AEL declining load\n", rfilename);
00131       return AST_MODULE_LOAD_DECLINE;
00132    }
00133    
00134    parse_tree = ael2_parse(rfilename, &errs);
00135    ast_log(LOG_NOTICE, "AEL load process: parsed config file name '%s'.\n", rfilename);
00136    ael2_semantic_check(parse_tree, &sem_err, &sem_warn, &sem_note);
00137    if (errs == 0 && sem_err == 0) {
00138       ast_log(LOG_NOTICE, "AEL load process: checked config file name '%s'.\n", rfilename);
00139       local_table = ast_hashtab_create(11, ast_hashtab_compare_contexts, ast_hashtab_resize_java, ast_hashtab_newsize_java, ast_hashtab_hash_contexts, 0);
00140       ast_compile_ael2(&local_contexts, local_table, parse_tree);
00141       ast_log(LOG_NOTICE, "AEL load process: compiled config file name '%s'.\n", rfilename);
00142       
00143       ast_merge_contexts_and_delete(&local_contexts, local_table, registrar);
00144       local_table = NULL; /* it's the dialplan global now */
00145       local_contexts = NULL;
00146       ast_log(LOG_NOTICE, "AEL load process: merged config file name '%s'.\n", rfilename);
00147       for (con = ast_walk_contexts(NULL); con; con = ast_walk_contexts(con))
00148          ast_context_verify_includes(con);
00149       ast_log(LOG_NOTICE, "AEL load process: verified config file name '%s'.\n", rfilename);
00150    } else {
00151       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);
00152       destroy_pval(parse_tree); /* free up the memory */
00153       return AST_MODULE_LOAD_DECLINE;
00154    }
00155    destroy_pval(parse_tree); /* free up the memory */
00156    
00157    return AST_MODULE_LOAD_SUCCESS;
00158 }

static int reload ( void   )  [static]

Definition at line 232 of file pbx_ael.c.

References pbx_load_module().

00233 {
00234    return pbx_load_module();
00235 }

void set_priorities ( struct ael_extension exten  ) 

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

04182 {
04183    int i;
04184    struct ael_priority *pr;
04185    do {
04186       if (exten->is_switch)
04187          i = 10;
04188       else if (exten->regexten)
04189          i=2;
04190       else
04191          i=1;
04192       
04193       for (pr=exten->plist; pr; pr=pr->next) {
04194          pr->priority_num = i;
04195          
04196          if (!pr->origin || (pr->origin && pr->origin->type != PV_LABEL) ) /* Labels don't show up in the dialplan,
04197                                       but we want them to point to the right
04198                                       priority, which would be the next line
04199                                       after the label; */
04200             i++;
04201       }
04202       
04203       exten = exten->next_exten;
04204    } while ( exten );
04205 }

static int unload_module ( void   )  [static]

Definition at line 219 of file pbx_ael.c.

References ARRAY_LEN, ast_cli_unregister_multiple(), and ast_context_destroy().

00220 {
00221    ast_context_destroy(NULL, registrar);
00222    ast_cli_unregister_multiple(cli_ael, ARRAY_LEN(cli_ael));
00223    return 0;
00224 }


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 = "0901e4e500243c855563a2d78b0c03e4" , .load = load_module, .unload = unload_module, .reload = reload, } [static]

Definition at line 251 of file pbx_ael.c.

int aeldebug = 0 [static]

Definition at line 107 of file pbx_ael.c.

Definition at line 251 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 214 of file pbx_ael.c.

char* config = "extensions.ael" [static]

Definition at line 65 of file pbx_ael.c.

char* registrar = "pbx_ael" [static]

Definition at line 66 of file pbx_ael.c.


Generated by  doxygen 1.6.2