Sat Mar 10 01:55:35 2012

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)
pvalfind_context (char *name)
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)
ael_extensionnew_exten (void)
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 = "88eaa8f5c1bd988bedd71113385e0886" , .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 4241 of file pval.c.

References AEL_APPCALL, AEL_CONTROL1, AEL_FOR_CONTROL, AEL_IF_CONTROL, AEL_IFTIME_CONTROL, AEL_LABEL, AEL_RAND_CONTROL, AEL_RETURN, app, ael_priority::app, ael_priority::appargs, ast_add_extension2(), ast_free_ptr, ast_log(), AST_MAX_EXTENSION, pval::else_statements, exten, ael_priority::exten, ael_priority::goto_false, ael_priority::goto_true, last, LOG_WARNING, ael_extension::name, ael_priority::next, ael_priority::origin, pbx_substitute_variables_helper(), PRIORITY_HINT, ael_priority::priority_num, PV_IFTIME, PV_SWITCH, strdup, ael_priority::type, pval::type, and pval::u3.

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

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 4427 of file pval.c.

References buf2, context, exten, pval::list, pval::next, pbx_builtin_setvar(), PV_GLOBALS, pval::str, pval::type, pval::u1, pval::u2, and pval::val.

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

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 
)

Definition at line 2127 of file pval.c.

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

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

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 2354 of file pval.c.

References pval::abstract, app, pval::arglist, ast_expr(), ast_expr_clear_extra_error_info(), ast_expr_register_extra_error_info(), ast_log(), check_abstract_reference(), check_app_args(), check_break(), check_continue(), check_day(), check_dow(), check_expr2_input(), check_goto(), check_includes(), check_label(), check_macro_returns(), check_month(), check_pval(), check_switch_expr(), check_timerange(), current_context, current_extension, E_MATCH, pval::else_statements, pval::endcol, pval::endline, pval::filename, find_context(), find_macro(), find_pval_gotos(), pval::for_inc, pval::for_init, pval::for_statements, pval::for_test, free, pval::list, localized_pbx_load_module(), LOG_ERROR, LOG_WARNING, pval::macro_statements, pval::next, pbx_find_extension(), PV_APPLICATION_CALL, PV_BREAK, PV_CASE, PV_CATCH, PV_CONTEXT, PV_CONTINUE, PV_DEFAULT, PV_ESWITCHES, PV_EXTENSION, PV_FOR, PV_GLOBALS, PV_GOTO, PV_IF, PV_IFTIME, PV_IGNOREPAT, PV_INCLUDES, PV_LABEL, PV_LOCALVARDEC, PV_MACRO, PV_MACRO_CALL, PV_PATTERN, PV_RANDOM, PV_RETURN, PV_STATEMENTBLOCK, PV_SWITCH, PV_SWITCHES, PV_VARDEC, PV_WHILE, PV_WORD, pbx_find_info::stacklen, pval::startcol, pval::startline, pval::statements, pbx_find_info::status, STATUS_SUCCESS, pval::str, pval::type, pval::u1, pval::u2, pval::u3, pval::u4, and pval::val.

02355 {
02356    pval *lp;
02357 #ifdef AAL_ARGCHECK
02358    struct argapp *app, *found;
02359 #endif
02360    struct pval *macro_def;
02361    struct pval *app_def;
02362 
02363    char errmsg[4096];
02364    char *strp;
02365    
02366    switch (item->type) {
02367    case PV_WORD:
02368       /* fields: item->u1.str == string associated with this (word).
02369                  item->u2.arglist  == pval list of 4 PV_WORD elements for time values (only in PV_INCLUDES) */
02370       break;
02371       
02372    case PV_MACRO:
02373       /* fields: item->u1.str     == name of macro
02374                  item->u2.arglist == pval list of PV_WORD arguments of macro, as given by user
02375                item->u2.arglist->u1.str  == argument
02376                item->u2.arglist->next   == next arg
02377 
02378                item->u3.macro_statements == pval list of statements in macro body.
02379       */
02380       in_abstract_context = 0;
02381       current_context = item;
02382       current_extension = 0;
02383 
02384       check_macro_returns(item);
02385       
02386       for (lp=item->u2.arglist; lp; lp=lp->next) {
02387       
02388       }
02389       check_pval(item->u3.macro_statements, apps,in_globals);
02390       break;
02391          
02392    case PV_CONTEXT:
02393       /* fields: item->u1.str     == name of context
02394                  item->u2.statements == pval list of statements in context body
02395                item->u3.abstract == int 1 if an abstract keyword were present
02396       */
02397       current_context = item;
02398       current_extension = 0;
02399       if ( item->u3.abstract ) {
02400          in_abstract_context = 1;
02401          check_abstract_reference(item);
02402       } else
02403          in_abstract_context = 0;
02404       check_pval(item->u2.statements, apps,in_globals);
02405       break;
02406          
02407    case PV_MACRO_CALL:
02408       /* fields: item->u1.str     == name of macro to call
02409                  item->u2.arglist == pval list of PV_WORD arguments of macro call, as given by user
02410                item->u2.arglist->u1.str  == argument
02411                item->u2.arglist->next   == next arg
02412       */
02413 #ifdef STANDALONE
02414       /* if this is a standalone, we will need to make sure the 
02415          localized load of extensions.conf is done */
02416       if (!extensions_dot_conf_loaded) {
02417          localized_pbx_load_module();
02418          extensions_dot_conf_loaded++;
02419       }
02420 #endif
02421       macro_def = find_macro(item->u1.str);
02422       if (!macro_def) {
02423 #ifdef STANDALONE
02424          struct pbx_find_info pfiq = {.stacklen = 0 };
02425          struct pbx_find_info pfiq2 = {.stacklen = 0 };
02426 
02427          /* look for the macro in the extensions.conf world */
02428          pbx_find_extension(NULL, NULL, &pfiq, item->u1.str, "s", 1, NULL, NULL, E_MATCH);
02429          
02430          if (pfiq.status != STATUS_SUCCESS) {
02431             char namebuf2[256];
02432             snprintf(namebuf2, 256, "macro-%s", item->u1.str);
02433             
02434             /* look for the macro in the extensions.conf world */
02435             pbx_find_extension(NULL, NULL, &pfiq2, namebuf2, "s", 1, NULL, NULL, E_MATCH);
02436             
02437             if (pfiq2.status == STATUS_SUCCESS) {
02438                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",
02439                      item->filename, item->startline, item->endline, item->u1.str, item->u1.str);
02440                warns++;
02441             } else {
02442                ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: macro call to non-existent %s! (Not even in the extensions.conf stuff!)\n",
02443                      item->filename, item->startline, item->endline, item->u1.str);
02444                warns++;
02445             }
02446          }
02447 #else
02448          ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: macro call to %s cannot be found in the AEL code!\n",
02449                item->filename, item->startline, item->endline, item->u1.str);
02450          warns++;
02451          
02452 #endif
02453 #ifdef THIS_IS_1DOT4
02454          char namebuf2[256];
02455          snprintf(namebuf2, 256, "macro-%s", item->u1.str);
02456 
02457          /* look for the macro in the extensions.conf world */
02458          pbx_find_extension(NULL, NULL, &pfiq, namebuf2, "s", 1, NULL, NULL, E_MATCH);
02459          
02460          if (pfiq.status != STATUS_SUCCESS) {
02461             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",
02462                   item->filename, item->startline, item->endline, item->u1.str);
02463             warns++;
02464          }
02465          
02466 #endif
02467 
02468       } else if (macro_def->type != PV_MACRO) {
02469          ast_log(LOG_ERROR,"Error: file %s, line %d-%d: macro call to %s references a context, not a macro!\n",
02470                item->filename, item->startline, item->endline, item->u1.str);
02471          errs++;
02472       } else {
02473          /* macro_def is a MACRO, so do the args match in number? */
02474          int hereargs = 0;
02475          int thereargs = 0;
02476          
02477          for (lp=item->u2.arglist; lp; lp=lp->next) {
02478             hereargs++;
02479          }
02480          for (lp=macro_def->u2.arglist; lp; lp=lp->next) {
02481             thereargs++;
02482          }
02483          if (hereargs != thereargs ) {
02484             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",
02485                   item->filename, item->startline, item->endline, item->u1.str, hereargs, thereargs);
02486             errs++;
02487          }
02488       }
02489       break;
02490          
02491    case PV_APPLICATION_CALL:
02492       /* fields: item->u1.str     == name of application to call
02493                  item->u2.arglist == pval list of PV_WORD arguments of macro call, as given by user
02494                item->u2.arglist->u1.str  == argument
02495                item->u2.arglist->next   == next arg
02496       */
02497       /* Need to check to see if the application is available! */
02498       app_def = find_context(item->u1.str);
02499       if (app_def && app_def->type == PV_MACRO) {
02500          ast_log(LOG_ERROR,"Error: file %s, line %d-%d: application call to %s references an existing macro, but had no & preceding it!\n",
02501                item->filename, item->startline, item->endline, item->u1.str);
02502          errs++;
02503       }
02504       if (strcasecmp(item->u1.str,"GotoIf") == 0
02505          || strcasecmp(item->u1.str,"GotoIfTime") == 0
02506          || strcasecmp(item->u1.str,"while") == 0
02507          || strcasecmp(item->u1.str,"endwhile") == 0
02508          || strcasecmp(item->u1.str,"random") == 0
02509          || strcasecmp(item->u1.str,"gosub") == 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 2181 of file pval.c.

References ast_strdupa, argapp::next, pval::str, and pval::u1.

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

void destroy_extensions ( struct ael_extension exten  ) 

Definition at line 2975 of file pval.c.

References ael_priority::app, ael_priority::appargs, exten, free, ael_priority::goto_false, ael_priority::goto_true, ael_extension::hints, ael_extension::loop_break, ael_extension::loop_continue, ael_extension::name, ael_priority::next, ael_extension::next_exten, ael_priority::origin, ael_extension::plist, and ael_extension::plist_last.

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 4890 of file pval.c.

References destroy_pval_item(), and pval::next.

04891 {
04892    pval *i,*nxt;
04893    
04894    for (i=item; i; i=nxt) {
04895       nxt = i->next;
04896       
04897       destroy_pval_item(i);
04898    }
04899 }

void destroy_pval_item ( pval item  ) 

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

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

struct pval* find_context ( char *  name  ) 

Definition at line 1950 of file pval.c.

References current_db, and 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 }

struct pval* find_macro ( char *  name  ) 

Definition at line 1940 of file pval.c.

References current_db, and match_pval().

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

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 1978 of file pval.c.

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

int is_float ( char *  arg  ) 

Definition at line 1960 of file pval.c.

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

int is_int ( char *  arg  ) 

Definition at line 1969 of file pval.c.

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

static int load_module ( void   )  [static]

Definition at line 275 of file pbx_ael.c.

References aelsub_exec(), ARRAY_LEN, ast_cli_register_multiple(), ast_register_application_xml, cli_ael, and pbx_load_module().

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

struct ael_extension* new_exten ( void   ) 

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

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 155 of file pbx_ael.c.

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

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

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

static int reload ( void   )  [static]

Definition at line 284 of file pbx_ael.c.

References pbx_load_module().

00285 {
00286    return pbx_load_module();
00287 }

void set_priorities ( struct ael_extension exten  ) 

Definition at line 4215 of file pval.c.

References exten, ael_priority::next, ael_priority::origin, ael_priority::priority_num, PV_LABEL, and pval::type.

04216 {
04217    int i;
04218    struct ael_priority *pr;
04219    do {
04220       if (exten->is_switch)
04221          i = 10;
04222       else if (exten->regexten)
04223          i=2;
04224       else
04225          i=1;
04226       
04227       for (pr=exten->plist; pr; pr=pr->next) {
04228          pr->priority_num = i;
04229          
04230          if (!pr->origin || (pr->origin && pr->origin->type != PV_LABEL) ) /* Labels don't show up in the dialplan,
04231                                       but we want them to point to the right
04232                                       priority, which would be the next line
04233                                       after the label; */
04234             i++;
04235       }
04236       
04237       exten = exten->next_exten;
04238    } while ( exten );
04239 }

static int unload_module ( void   )  [static]

Definition at line 265 of file pbx_ael.c.

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

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


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 = "88eaa8f5c1bd988bedd71113385e0886" , .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.

struct ast_module_info* ast_module_info = &__mod_info [static]

Definition at line 303 of file pbx_ael.c.

struct ast_cli_entry cli_ael[] [static]

Initial value:

 {
   { .handler =  handle_cli_ael_reload , .summary =  "Reload AEL configuration" ,__VA_ARGS__ },
   { .handler =  handle_cli_ael_set_debug , .summary =  "Enable AEL debugging flags" ,__VA_ARGS__ }
}

Definition at line 260 of file pbx_ael.c.

Referenced by load_module(), and unload_module().

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 Sat Mar 10 01:55:35 2012 for Asterisk - The Open Source Telephony Project by  doxygen 1.4.7