Wed Oct 28 15:47:55 2009

Asterisk developer's documentation


pbx_ael.c

Go to the documentation of this file.
00001 /*
00002  * Asterisk -- An open source telephony toolkit.
00003  *
00004  * Copyright (C) 1999 - 2005, Digium, Inc.
00005  *
00006  * Mark Spencer <markster@digium.com>
00007  *
00008  * See http://www.asterisk.org for more information about
00009  * the Asterisk project. Please do not directly contact
00010  * any of the maintainers of this project for assistance;
00011  * the project provides a web site, mailing lists and IRC
00012  * channels for your use.
00013  *
00014  * This program is free software, distributed under the terms of
00015  * the GNU General Public License Version 2. See the LICENSE file
00016  * at the top of the source tree.
00017  */
00018 
00019 /*! \file
00020  *
00021  * \brief Compile symbolic Asterisk Extension Logic into Asterisk extensions
00022  * 
00023  */
00024 
00025 #include <sys/types.h>
00026 #include <stdlib.h>
00027 #include <stdio.h>
00028 #include <string.h>
00029 #include <ctype.h>
00030 #include <errno.h>
00031 
00032 #include "asterisk.h"
00033 
00034 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 45134 $")
00035 
00036 #include "asterisk/pbx.h"
00037 #include "asterisk/config.h"
00038 #include "asterisk/module.h"
00039 #include "asterisk/logger.h"
00040 #include "asterisk/cli.h"
00041 #include "asterisk/callerid.h"
00042 
00043 struct stringlink {
00044    struct stringlink *next;
00045    char data[0];
00046 };
00047 
00048 #define FILLIN_BREAK    1
00049 #define FILLIN_CONTINUE    2
00050 
00051 struct fillin {
00052    struct fillin *next;
00053    char exten[AST_MAX_EXTENSION];
00054    int priority;
00055    int type;
00056 };
00057 
00058 #ifdef __AST_DEBUG_MALLOC
00059 static void FREE(void *ptr)
00060 {
00061    free(ptr);
00062 }
00063 #else
00064 #define FREE free
00065 #endif
00066 
00067 #define DEBUG_READ   (1 << 0)
00068 #define DEBUG_TOKENS (1 << 1)
00069 #define DEBUG_MACROS (1 << 2)
00070 #define DEBUG_CONTEXTS (1 << 3)
00071 
00072 static int aeldebug = 0;
00073 
00074 static char *dtext = "Asterisk Extension Language Compiler";
00075 static char *config = "extensions.ael";
00076 static char *registrar = "pbx_ael";
00077 
00078 static char *__grab_token(char *src, const char *filename, int lineno, int link)
00079 {
00080    char *c;
00081    char *b;
00082    char *a;
00083    int level = 0;
00084    char *ret;
00085 #if 0
00086    if (aeldebug || DEBUG_TOKENS) 
00087       ast_verbose("Searching for token in '%s'!\n", src);
00088 #endif
00089    c = src;
00090    while(*c) {
00091       if ((*c == '\\')) {
00092          c++;
00093          if (!*c)
00094             c--;
00095       } else {
00096          if ((*c == '{') || (*c == '(')) {
00097             level++;
00098          } else if ((*c == '}') || (*c == ')')) {
00099             if (level)
00100                level--;
00101             else
00102                ast_log(LOG_WARNING, "Syntax error at line %d of '%s', too many closing braces!\n", lineno, filename);
00103          } else if ((*c == ';') && !level) {
00104             /* Got a token! */
00105             *c = '\0';
00106             b = c;
00107             b--;
00108             c++;
00109             while((b > src) && (*b < 33)) { 
00110                *b = '\0'; 
00111                b--; 
00112             }
00113             a = ast_skip_blanks(src);
00114             if (link) {
00115                ret = malloc(strlen(a) + sizeof(struct stringlink) + 1);
00116                if (ret)
00117                   strcpy(ret + sizeof(struct stringlink), a);
00118             } else
00119                ret = strdup(a);
00120             /* Save remainder */
00121             memmove(src, c, strlen(c) + 1);
00122             return ret;
00123          }
00124       }
00125       c++;
00126    }
00127    return NULL;      
00128 }
00129 
00130 static char *grab_token(char *src, const char *filename, int lineno)
00131 {
00132    return __grab_token(src, filename, lineno, 0);
00133 }
00134 
00135 static struct stringlink *arg_parse(char *args, const char *filename, int lineno)
00136 {
00137    struct stringlink *cur, *prev=NULL, *root=NULL;
00138    if (args) {
00139       if (aeldebug & DEBUG_TOKENS) 
00140          ast_verbose("Parsing args '%s'!\n", args);
00141       if (args[0] == '{') {
00142          /* Strip mandatory '}' from end */
00143          args[strlen(args) - 1] = '\0';
00144          while ((cur = (struct stringlink *)__grab_token(args + 1, filename, lineno, 1))) {
00145             cur->next = NULL;
00146             if (prev)
00147                prev->next = cur;
00148             else
00149                root = cur;
00150             prev = cur;
00151          }
00152       } else if (*args) {
00153          root = malloc(sizeof(struct stringlink) + strlen(args) + 1);
00154          if (root) {
00155             strcpy(root->data, args);
00156             root->next = NULL;
00157          }
00158       }
00159    }
00160    return root;
00161 }
00162 
00163 static char *grab_else(char *args, const char *filename, int lineno)
00164 {
00165    char *ret = NULL;
00166    int level=0;
00167    char *c;
00168    if (args) {
00169       if (args[0] == '{') {
00170          c = args;
00171          while(*c) {
00172             if (*c == '{')
00173                level++;
00174             else if (*c == '}') {
00175                level--;
00176                if (!level) {
00177                   c++;
00178                   while(*c && (*c < 33)) { *c = '\0'; c++; };
00179                   if (!strncasecmp(c, "else", 4) && 
00180                      ((c[4] == '{') || (c[4] < 33))) {
00181                         /* Ladies and gentlemen, we have an else clause */
00182                      *c = '\0';
00183                      c += 4;
00184                      c = ast_skip_blanks(c);
00185                      ret = c;
00186                      if (aeldebug & DEBUG_TOKENS)
00187                         ast_verbose("Returning else clause '%s'\n", c);
00188                   }
00189                   break;
00190                }
00191             }
00192             c++;
00193          }
00194       }
00195    }
00196    return ret;
00197 }
00198 
00199 static struct stringlink *param_parse(char *parms, const char *macro, const char *filename, int lineno)
00200 {
00201    char *s, *e;
00202    struct stringlink *root = NULL, *prev=NULL, *cur;
00203    if (!parms || !*parms)
00204       return NULL;
00205    if (*parms != '(') {
00206       ast_log(LOG_NOTICE, "Syntax error in parameter list for macro '%s' at about line %d of %s: Expecting '(' but got '%c'\n", macro, lineno, filename, *parms);
00207       return NULL;
00208    }
00209    s = parms + 1;
00210    while(*s) {
00211       s = ast_skip_blanks(s);
00212       e = s;
00213       while(*e &&  (*e != ')') && (*e != ',')) {
00214          if (*e < 33)
00215             *e = '\0';
00216          e++;
00217       }
00218       if (*e) {
00219          /* Strip token */
00220          *e = '\0';
00221          e++;
00222          /* Skip over whitespace */
00223          e = ast_skip_blanks(e);
00224          /* Link */
00225          cur = malloc(strlen(s) + sizeof(struct stringlink) + 1);
00226          if (cur) {
00227             cur->next = NULL;
00228             strcpy(cur->data, s);
00229             if (prev)
00230                prev->next = cur;
00231             else
00232                root = cur;
00233             prev = cur;
00234          }
00235          s = e;
00236       }
00237    }
00238    return root;
00239 }
00240 
00241 static void arg_free(struct stringlink *cur)
00242 {
00243    struct stringlink *last;
00244    while(cur) {
00245       last = cur;
00246       cur = cur->next;
00247       free(last);
00248    }
00249 }
00250 
00251 static void handle_globals(struct stringlink *vars)
00252 {
00253    while(vars) {
00254       pbx_builtin_setvar(NULL, vars->data);
00255       vars = vars->next;
00256    }
00257 }
00258 
00259 static struct stringlink *split_token(char *token, const char *filename, int lineno)
00260 {
00261    char *args, *p;
00262    struct stringlink *argv;
00263    args = token;
00264    while (*args && (*args > 32) && (*args != '{') && (*args != '(')) args++;
00265    if (*args) {
00266       p = args;
00267       args = ast_skip_blanks(args);
00268       if (*args != '(') {
00269          *p = '\0';
00270       } else {
00271          while (*args && (*args != ')')) args++;
00272          if (*args == ')') {
00273             args++;
00274             args = ast_skip_blanks(args);
00275          }
00276       }
00277       if (!*args)
00278          args = NULL;
00279    } else args = NULL;
00280    argv = arg_parse(args, filename, lineno);
00281    if (args)
00282       *args = '\0';
00283    return argv;
00284 }
00285 
00286 static int matches_keyword(const char *data, const char *keyword)
00287 {
00288    char c;
00289    if (!strncasecmp(data, keyword, strlen(keyword))) {
00290       c = data[strlen(keyword)];
00291       if ((c < 33) || (c == '(') || (c == '{'))
00292          return 1;
00293    }
00294    return 0;
00295 }
00296 
00297 static struct stringlink *split_params(char *token, const char *filename, int lineno)
00298 {
00299    char *params;
00300    struct stringlink *paramv;
00301    params = token;
00302    while(*params && (*params > 32) && (*params != '(')) params++;
00303    if (*params) {
00304       if (*params != '(') {
00305          *params = '\0';
00306          params++;
00307          params = ast_skip_blanks(params);
00308       }
00309       if (!*params)
00310          params = NULL;
00311    } else params = NULL;
00312    paramv = param_parse(params, token, filename, lineno);
00313    if (params)
00314       *params = '\0';
00315    return paramv;
00316 }
00317 
00318 static const char *get_case(char *s, char **restout, int *pattern)
00319 {
00320    char *newcase=NULL;
00321    char *rest=NULL;
00322    if (!strncasecmp(s, "case", 4) && s[4] && ((s[4] < 33) || (s[4] == ':'))) {
00323       newcase = s + 4;
00324       newcase = ast_skip_blanks(newcase);
00325       rest = newcase;
00326       *pattern = 0;
00327    } else if (!strncasecmp(s, "pattern", 7) && s[7] && ((s[7] < 33) || (s[7] == ':'))) {
00328       newcase = s + 8;
00329       newcase = ast_skip_blanks(newcase);
00330       rest = newcase;
00331       *pattern = 1;
00332    } else if (!strncasecmp(s, "default", 7) && ((s[7] < 33) || (s[7] == ':'))) {
00333       newcase = ".";
00334       rest = s + 7;
00335       rest = ast_skip_blanks(rest);
00336       *pattern = 1;
00337    }
00338 
00339    if (rest) {
00340       while (*rest && (*rest > 32) && (*rest != ':')) rest++;
00341       if (*rest) {
00342          *rest = 0;
00343          rest++;
00344          while (*rest && ((*rest == ':') || (*rest < 33))) rest++;
00345          *restout = rest;
00346       } else {
00347          *restout = "";
00348       }
00349    } else
00350       *restout = s;
00351    if (aeldebug & DEBUG_TOKENS)
00352       ast_verbose("GETCASE: newcase is '%s', rest = '%s'\n", newcase, *restout);
00353    return newcase;
00354 }
00355 
00356 static void fillin_free(struct fillin *fillin)
00357 {
00358    struct fillin *cur, *next;
00359    cur =  fillin;
00360    while(cur) {
00361       next = cur->next;
00362       free(cur);
00363       cur = next;
00364    }
00365 }
00366 
00367 static void fillin_process(struct ast_context *con, struct fillin *fillin, const char *filename, int lineno, const char *breakexten, int breakprio, const char *contexten, int contprio)
00368 {
00369    struct fillin *cur;
00370    char *app;
00371    char mdata[AST_MAX_EXTENSION + 20];
00372    cur = fillin;
00373    while(cur) {
00374       if (cur->type == FILLIN_BREAK) {
00375          if (breakexten && breakprio) {
00376             app = "Goto";
00377             snprintf(mdata, sizeof(mdata), "%s|%d", breakexten, breakprio);
00378          } else {
00379             app = "NoOp";
00380             snprintf(mdata, sizeof(mdata), "Invalid break");
00381             ast_log(LOG_NOTICE, "Ignoring inappropriate break around line %d of %s\n", lineno, filename);
00382          }
00383          if (ast_add_extension2(con, 0, cur->exten, cur->priority, NULL, NULL, app, strdup(mdata), FREE, registrar))
00384             ast_log(LOG_WARNING, "Unable to add step at priority '%d' of break '%s'\n", cur->priority, cur->exten);
00385       } else if (cur->type == FILLIN_CONTINUE) {
00386          if (contexten && contprio) {
00387             app = "Goto";
00388             snprintf(mdata, sizeof(mdata), "%s|%d", contexten, contprio);
00389          } else {
00390             app = "NoOp";
00391             snprintf(mdata, sizeof(mdata), "Invalid continue");
00392             ast_log(LOG_NOTICE, "Ignoring inappropriate continue around line %d of %s\n", lineno, filename);
00393          }
00394          if (ast_add_extension2(con, 0, cur->exten, cur->priority, NULL, NULL, app, strdup(mdata), FREE, registrar))
00395             ast_log(LOG_WARNING, "Unable to add step at priority '%d' of continue '%s'\n", cur->priority, cur->exten);
00396       } else {
00397          ast_log(LOG_WARNING, "Whoa, unknown fillin type '%d'\n", cur->type);
00398       }
00399       cur = cur->next;
00400    }
00401 }
00402 
00403 static int match_assignment(char *variable, char **value)
00404 {
00405    char *c;
00406    char *ws;
00407    int inpar = 0;
00408    c = variable;
00409    
00410    while (*c) {
00411       if(*c == ')' && (inpar > 0)) {
00412          inpar--;
00413       } else if(*c == '(' && (inpar >= 0)) {
00414          inpar++;
00415       } else if(*c == '=' && (inpar == 0)) {
00416          break;
00417       }
00418       c++;
00419    } 
00420    ws = c;
00421    c = ast_skip_blanks(c);
00422    if (*c == '=') {
00423       *ws = '\0';
00424       *c = '\0';
00425       c++;
00426       c = ast_skip_blanks(c);
00427       *value = c;
00428       return 1;
00429    }
00430    return 0;
00431 }
00432 
00433 static int matches_label(char *data, char **rest)
00434 {
00435    char last = 0;
00436    char *start = data;
00437    while (*data > 32) {
00438       last = *data;
00439       data++;
00440    }
00441    if (last != ':') {
00442       data = ast_skip_blanks(data);
00443       last = *data;
00444       data++;
00445    }
00446    if (last == ':') {
00447       *rest = data;
00448       /* Go back and trim up the label */
00449       while(*start && ((*start > 32) && (*start != ':'))) start++;
00450       *start = '\0';
00451       return 1;
00452    }
00453    return 0;
00454 }
00455 
00456 static char *argument_end(char *str)
00457 {
00458    int level=0;
00459    while(*++str) {
00460       switch(*str) {
00461       case '(':
00462          level++;
00463          break;
00464       case ')':
00465          if(level)
00466             level--;
00467          else
00468             return str;
00469          break;
00470       default:
00471          break;
00472       }
00473    }
00474    return NULL;
00475 }
00476 
00477 static void gen_match_to_pattern(const char *pattern, char *result)
00478 {
00479        /* the result will be a string that will be matched by pattern */
00480        char *p=(char *)pattern, *t=result;
00481        while (*p) {
00482                if (*p == 'x' || *p == 'n' || *p == 'z' || *p == 'X' || *p == 'N' || *p == 'Z')
00483                        *t++ = '9';
00484                else if (*p == '[') {
00485                        char *z = p+1;
00486                        while (*z != ']')
00487                                z++;
00488                        if (*(z+1)== ']')
00489                                z++;
00490                        *t++=*(p+1); /* use the first char in the set */
00491                        p = z;
00492                } else {
00493                        *t++ = *p;
00494                }
00495                p++;
00496        }
00497        *t++ = 0; /* cap it off */
00498 }
00499 
00500 static int build_step(const char *what, const char *name, const char *filename, int lineno, struct ast_context *con, char *exten, int *pos, char *data, struct fillin **fillout, char **label);
00501 static int __build_step(const char *what, const char *name, const char *filename, int lineno, struct ast_context *con, char *exten, int *pos, char *data, struct fillin **fillout, char **label)
00502 {
00503    char *app;
00504    char *args;
00505    char *c;
00506    char *margs=NULL;
00507    char *oargs;
00508    char *rest;
00509    const char *curcase, *newcase;
00510    struct stringlink *swargs, *cur;
00511    int cpos;
00512    int mlen;
00513    int pattern = 0;
00514    struct fillin *fillin;
00515    
00516    data = ast_skip_blanks(data);
00517    if (matches_label(data, &c)) {
00518       *label = data;
00519       data = c;
00520       data = ast_skip_blanks(data);
00521    }
00522    if (ast_strlen_zero(data))
00523       return 0;
00524    if (matches_keyword(data, "switch")) {
00525       fillin = NULL;
00526       /* Switch */
00527       args = data + strlen("switch");
00528       while ((*args < 33) && (*args != '(')) args++;
00529       if ((*args == '(') && (c = argument_end(args))) {
00530          args++;
00531          *c = '\0';
00532          c++;
00533          if (aeldebug & DEBUG_TOKENS)
00534             ast_verbose("--SWITCH on : %s\n", args);
00535          mlen = strlen(exten) + 128 + strlen(args) + strlen(name);
00536          margs = alloca(mlen);
00537          app = "Goto";
00538          sprintf(margs, "sw-%d-%s|1", *pos, args);
00539          ast_process_quotes_and_slashes(margs, ',', '|');
00540          oargs = args;
00541          args = margs;
00542          if (ast_add_extension2(con, 0, exten, *pos, *label, NULL, app, strdup(args), FREE, registrar))
00543             ast_log(LOG_WARNING, "Unable to add step at priority '%d' of %s '%s'\n", *pos, what, name);
00544          else {
00545             *label = NULL;
00546             (*pos)++;
00547          }
00548          app = "NoOp";
00549          sprintf(margs, "Finish switch-%d", *pos - 1);
00550          if (ast_add_extension2(con, 0, exten, *pos, *label, NULL, app, strdup(args), FREE, registrar))
00551             ast_log(LOG_WARNING, "Unable to add step at priority '%d' of %s '%s'\n", *pos, what, name);
00552          else {
00553             *label = NULL;
00554             (*pos)++;
00555          }
00556          c = ast_skip_blanks(c);
00557          if (aeldebug & DEBUG_TOKENS)
00558             ast_verbose("ARG Parsing '%s'\n", c);
00559          swargs = arg_parse(c, filename, lineno);
00560          cur = swargs;
00561          curcase = NULL;
00562          while(cur) {
00563             if ((newcase = get_case(cur->data, &rest, &pattern))) {
00564                if (aeldebug & DEBUG_TOKENS)
00565                   ast_verbose("--NEWCASE: '%s'!\n", newcase);
00566                if (curcase) {
00567                   char zbuf[256];
00568 
00569                   /* Handle fall through */
00570                   char tmp[strlen(newcase) + strlen(name) + 40];
00571                   gen_match_to_pattern(newcase,zbuf);
00572                   sprintf(tmp, "sw-%d-%s|%d", *pos - 2, zbuf, 1);
00573                   ast_add_extension2(con, 0, margs, cpos, NULL, NULL, "Goto", strdup(tmp), FREE, registrar);
00574                }
00575                curcase = newcase;
00576                cpos = 1;
00577                if (pattern)
00578                   snprintf(margs, mlen, "_sw-%d-%s", *pos - 2, curcase);
00579                else
00580                   snprintf(margs, mlen, "sw-%d-%s", *pos - 2, curcase);
00581                if (!strcasecmp(rest, "break")) {
00582                   char tmp[strlen(exten) + 10];
00583                   sprintf(tmp, "%s|%d", exten, *pos - 1);
00584                   ast_add_extension2(con, 0, exten, cpos, *label, NULL, "Goto", strdup(tmp), FREE, registrar);
00585                   curcase = NULL;
00586                   *label = NULL;
00587                } else
00588                   build_step("switch", margs, filename, lineno, con, margs, &cpos, rest, &fillin, label);
00589             } else if (curcase) {
00590                if (aeldebug & DEBUG_TOKENS)
00591                   ast_verbose("Building statement from '%s'\n", rest);
00592                if (!strcasecmp(rest, "break")) {
00593                   char tmp[strlen(exten) + 10];
00594                   sprintf(tmp, "%s|%d", exten, *pos - 1);
00595                   ast_add_extension2(con, 0, margs, cpos, *label, NULL, "Goto", strdup(tmp), FREE, registrar);
00596                   curcase = NULL;
00597                   *label = NULL;
00598                } else
00599                   build_step("switch", margs, filename, lineno, con, margs, &cpos, rest, &fillin, label);
00600             } else 
00601                ast_log(LOG_WARNING, "Unreachable code in switch at about line %d of %s\n", lineno, filename);
00602             if (aeldebug & DEBUG_TOKENS)
00603                ast_verbose("--SWARG: %s\n", cur->data);
00604             cur = cur->next;
00605          }
00606          /* Can't do anything with these */
00607          fillin_process(con, fillin, filename, lineno, NULL, 0, NULL, 0);
00608          fillin_free(fillin);
00609          arg_free(swargs);
00610       } else
00611          ast_log(LOG_WARNING, "Syntax error in switch declaration in %s around line %d!\n", filename, lineno); 
00612          
00613    } else if (matches_keyword(data, "if")) {
00614       /* If... */
00615       args = data + strlen("if");
00616       while ((*args < 33) && (*args != '(')) args++;
00617       if ((*args == '(') && (c = argument_end(args))) {
00618          int ifblock;
00619          int ifstart;
00620          int elsestart;
00621          int ifend;
00622          int ifskip;
00623          char *elses;
00624          char *iflabel;
00625          args++;
00626          *c = '\0';
00627          c++;
00628          c = ast_skip_blanks(c);
00629          if (aeldebug & DEBUG_TOKENS)
00630             ast_verbose("--IF on : '%s' : '%s'\n", args, c);
00631          mlen = strlen(exten) + 128 + strlen(args) + strlen(name);
00632          margs = alloca(mlen);
00633          /* Remember where the ifblock starts, and skip over */
00634          ifblock = (*pos)++;
00635          iflabel = *label;
00636          *label = NULL;
00637          /* Remember where the start of the ifblock is */
00638          ifstart = *pos;
00639          snprintf(margs, mlen, "if-%s-%d", name, ifblock);
00640          /* Now process the block of the if */
00641          if (aeldebug & DEBUG_TOKENS)
00642             ast_verbose("Searching for elses in '%s'\n", c);
00643          elses = grab_else(c, filename, lineno);
00644          build_step("if", margs, filename, lineno, con, exten, pos, c, fillout, label);
00645          if (elses) {
00646             /* Reserve a goto to exit the if */
00647             ifskip = *pos;
00648             (*pos)++;
00649             elsestart = *pos;
00650             build_step("else", margs, filename, lineno, con, exten, pos, elses, fillout, label);
00651          } else {
00652             elsestart = *pos;
00653             ifskip = 0;
00654          }
00655          ifend = *pos;
00656          (*pos)++;
00657          app = "NoOp";
00658          snprintf(margs, mlen, "Finish if-%s-%d", name, ifblock);
00659          if (ast_add_extension2(con, 0, exten, ifend, *label, NULL, app, strdup(margs), FREE, registrar))
00660             ast_log(LOG_WARNING, "Unable to add step at priority '%d' of %s '%s'\n", *pos, what, name);
00661          *label = NULL;
00662          app = "GotoIf";
00663          snprintf(margs, mlen, "$[ %s ]?%d:%d", args, ifstart, elsestart);
00664          if (ast_add_extension2(con, 0, exten, ifblock, iflabel, NULL, app, strdup(margs), FREE, registrar))
00665             ast_log(LOG_WARNING, "Unable to add step at priority '%d' of %s '%s'\n", *pos, what, name);
00666          if (ifskip) {
00667             /* Skip as appropriate around else clause */
00668             snprintf(margs, mlen, "%d", ifend);
00669             if (ast_add_extension2(con, 0, exten, ifskip, NULL, NULL, "Goto", strdup(margs), FREE, registrar))
00670                ast_log(LOG_WARNING, "Unable to add step at priority '%d' of %s '%s'\n", *pos, what, name);
00671          }
00672       } else
00673          ast_log(LOG_WARNING, "Syntax error in if declaration in %s around line %d!\n", filename, lineno); 
00674    } else if (matches_keyword(data, "while")) {
00675       /* While... */
00676       fillin = NULL;
00677       args = data + strlen("while");
00678       while ((*args < 33) && (*args != '(')) args++;
00679       if ((*args == '(') && (c = argument_end(args))) {
00680          int whileblock;
00681          int whilestart;
00682          int whileend;
00683          char *whilelabel;
00684          args++;
00685          *c = '\0';
00686          c++;
00687          c = ast_skip_blanks(c);
00688          if (aeldebug & DEBUG_TOKENS)
00689             ast_verbose("--WHILE on : '%s' : '%s'\n", args, c);
00690          mlen = strlen(exten) + 128 + strlen(args) + strlen(name);
00691          margs = alloca(mlen);
00692          /* Remember where to put the conditional, and keep its position */
00693          whilestart = (*pos);
00694          whilelabel = *label;
00695          *label = NULL;
00696          (*pos)++;
00697          /* Remember where the whileblock starts */
00698          whileblock = (*pos);
00699          snprintf(margs, mlen, "while-%s-%d", name, whilestart);
00700          build_step("while", margs, filename, lineno, con, exten, pos, c, &fillin, label);
00701          /* Close the loop */
00702          app = "Goto";
00703          snprintf(margs, mlen, "%d", whilestart);
00704          if (ast_add_extension2(con, 0, exten, (*pos)++, *label, NULL, app, strdup(margs), FREE, registrar))
00705             ast_log(LOG_WARNING, "Unable to add step at priority '%d' of %s '%s'\n", *pos, what, name);
00706          *label = NULL;
00707          whileend = (*pos);
00708          /* Place trailer */
00709          app = "NoOp";
00710          snprintf(margs, mlen, "Finish while-%s-%d", name, whilestart);
00711          if (ast_add_extension2(con, 0, exten, (*pos)++, *label, NULL, app, strdup(margs), FREE, registrar))
00712             ast_log(LOG_WARNING, "Unable to add step at priority '%d' of %s '%s'\n", *pos, what, name);
00713          *label = NULL;
00714          app = "GotoIf";
00715          snprintf(margs, mlen, "$[ %s ]?%d:%d", args, whileblock, whileend);
00716          if (ast_add_extension2(con, 0, exten, whilestart, whilelabel, NULL, app, strdup(margs), FREE, registrar))
00717             ast_log(LOG_WARNING, "Unable to add step at priority '%d' of %s '%s'\n", *pos, what, name);
00718          fillin_process(con, fillin, filename, lineno, exten, whileend, exten, whilestart);
00719          fillin_free(fillin);
00720       } else
00721          ast_log(LOG_WARNING, "Syntax error in while declaration in %s around line %d!\n", filename, lineno); 
00722    } else if (matches_keyword(data, "jump")) {
00723       char *p;
00724       /* Jump... */
00725       fillin = NULL;
00726       args = data + strlen("jump");
00727       args = ast_skip_blanks(args);
00728       if (aeldebug & DEBUG_TOKENS)
00729          ast_verbose("--JUMP to : '%s'\n", args);
00730       p = strchr(args, ',');
00731       if (p) {
00732          *p = '\0';
00733          p++;
00734       } else
00735          p = "1";
00736       c = strchr(args, '@');
00737       if (c) {
00738          *c = '\0';
00739          c++;
00740       }
00741       mlen = strlen(exten) + 128 + strlen(args) + strlen(name) + (c ? strlen(c) : 0);
00742       margs = alloca(mlen);
00743       if (c) 
00744          snprintf(margs, mlen, "%s|%s|%s", c,args, p);
00745       else
00746          snprintf(margs, mlen, "%s|%s", args, p);
00747       app = "Goto";
00748       if (ast_add_extension2(con, 0, exten, (*pos)++, *label, NULL, app, strdup(margs), FREE, registrar))
00749          ast_log(LOG_WARNING, "Unable to add step at priority '%d' of %s '%s'\n", *pos, what, name);
00750       *label = NULL;
00751    } else if (matches_keyword(data, "goto")) {
00752       /* Jump... */
00753       fillin = NULL;
00754       args = data + strlen("goto");
00755       args = ast_skip_blanks(args);
00756       if (aeldebug & DEBUG_TOKENS)
00757          ast_verbose("--GOTO to : '%s'\n", args);
00758       app = "Goto";
00759       if (args[0] == '(' && args[strlen(args) - 1] == ')') {
00760          args[0] = '\0';
00761          args++;
00762          args[strlen(args) - 1] = '\0';
00763       }
00764       if (ast_add_extension2(con, 0, exten, (*pos)++, *label, NULL, app, strdup(args), FREE, registrar))
00765          ast_log(LOG_WARNING, "Unable to add step at priority '%d' of %s '%s'\n", *pos, what, name);
00766       *label = NULL;
00767    } else if (matches_keyword(data, "for")) {
00768       /* While... */
00769       fillin = NULL;
00770       args = data + strlen("for");
00771       while ((*args < 33) && (*args != '(')) args++;
00772       if ((*args == '(') && (c = argument_end(args))) {
00773          int forblock;
00774          int forprep;
00775          int forstart;
00776          int forend;
00777          struct stringlink *fields;
00778          char *tmp;
00779          char *forlabel = NULL;
00780          args++;
00781          *c = '\0';
00782          c++;
00783          c = ast_skip_blanks(c);
00784          /* Parse arguments first */
00785          tmp = alloca(strlen(args) + 10);
00786          if (tmp) {
00787             snprintf(tmp, strlen(args) + 10, "{%s;}", args);
00788             fields = arg_parse(tmp, filename, lineno);
00789          } else
00790             fields = NULL;
00791          if (fields && fields->next && fields->next->next) {
00792             if (aeldebug & DEBUG_TOKENS)
00793                ast_verbose("--FOR ('%s' ; '%s' ; '%s') : '%s'\n", fields->data, fields->next->data, fields->next->next->data, c);
00794             mlen = strlen(exten) + 128 + strlen(args) + strlen(name);
00795             margs = alloca(mlen);
00796             forprep = *pos;
00797             snprintf(margs, mlen, "for-%s-%d", name, forprep);
00798             fillin = NULL;
00799             build_step("while", margs, filename, lineno, con, exten, pos, fields->data, &fillin, label);
00800             /* Remember where to put the conditional, and keep its position */
00801             forstart = (*pos);
00802             forlabel = *label;
00803             (*pos)++;
00804             *label = NULL;
00805             /* Remember where the whileblock starts */
00806             forblock = (*pos);
00807             build_step("for", margs, filename, lineno, con, exten, pos, c, &fillin, label);
00808             build_step("for", margs, filename, lineno, con, exten, pos, fields->next->next->data, &fillin, label);
00809             /* Close the loop */
00810             app = "Goto";
00811             snprintf(margs, mlen, "%d", forstart);
00812             if (ast_add_extension2(con, 0, exten, (*pos)++, *label, NULL, app, strdup(margs), FREE, registrar))
00813                ast_log(LOG_WARNING, "Unable to add step at priority '%d' of %s '%s'\n", *pos, what, name);
00814             *label = NULL;
00815             forend = (*pos);
00816             /* Place trailer */
00817             app = "NoOp";
00818             snprintf(margs, mlen, "Finish for-%s-%d", name, forprep);
00819             if (ast_add_extension2(con, 0, exten, (*pos)++, *label, NULL, app, strdup(margs), FREE, registrar))
00820                ast_log(LOG_WARNING, "Unable to add step at priority '%d' of %s '%s'\n", *pos, what, name);
00821             *label = NULL;
00822             app = "GotoIf";
00823             snprintf(margs, mlen, "$[ %s ]?%d:%d", fields->next->data, forblock, forend);
00824             if (ast_add_extension2(con, 0, exten, forstart, forlabel, NULL, app, strdup(margs), FREE, registrar))
00825                ast_log(LOG_WARNING, "Unable to add step at priority '%d' of %s '%s'\n", forstart, what, name);
00826             fillin_process(con, fillin, filename, lineno, exten, forend, exten, forstart);
00827             fillin_free(fillin);
00828          } else
00829             ast_log(LOG_NOTICE, "Improper for declaration in %s around line %d!\n", filename, lineno); 
00830          arg_free(fields);
00831       } else
00832          ast_log(LOG_WARNING, "Syntax error in for declaration in %s around line %d!\n", filename, lineno); 
00833          
00834    } else if (!strcasecmp(data, "break") || !strcasecmp(data, "continue")) {
00835       struct fillin *fi;
00836       fi = malloc(sizeof(struct fillin));
00837       if (fi) {
00838          memset(fi, 0, sizeof(struct fillin));
00839          if (!strcasecmp(data, "break"))
00840             fi->type = FILLIN_BREAK;
00841          else
00842             fi->type = FILLIN_CONTINUE;
00843          ast_copy_string(fi->exten, exten, sizeof(fi->exten));
00844          fi->priority = (*pos)++;
00845          fi->next = *fillout;
00846          *fillout = fi;
00847       }
00848    } else if (match_assignment(data, &rest)) {
00849       if (aeldebug & DEBUG_TOKENS)
00850          ast_verbose("ASSIGN  '%s' = '%s'\n", data, rest);
00851       mlen = strlen(rest) + strlen(data) + 20;
00852       margs = alloca(mlen);
00853       snprintf(margs, mlen, "%s=$[ %s ]", data, rest);
00854       app = "Set";
00855       if (ast_add_extension2(con, 0, exten, *pos, *label, NULL, app, strdup(margs), FREE, registrar))
00856          ast_log(LOG_WARNING, "Unable to add assignment at priority '%d' of %s '%s'\n", *pos, what, name);
00857       else {
00858          *label = NULL;
00859          (*pos)++;
00860       }
00861    } else {
00862       app = data;
00863       args = app;
00864       while (*args && (*args > 32) && (*args != '(')) args++;
00865          if (*args != '(') {
00866          while(*args && (*args != '(')) { *args = '\0'; args++; };
00867       }
00868       if (*args == '(') {
00869          *args = '\0';
00870          args++;
00871          /* Got arguments, trim trailing ')' */
00872          c = args + strlen(args) - 1;
00873          while((c >= args) && (*c < 33) && (*c != ')')) { *c = '\0'; c--; };
00874          if ((c >= args) && (*c == ')')) *c = '\0';
00875       } else
00876          args = "";
00877       ast_process_quotes_and_slashes(args, ',', '|');
00878       if (app[0] == '&') {
00879          app++;
00880          margs = alloca(strlen(args) + strlen(app) + 10);
00881          sprintf(margs, "%s|%s", app, args);
00882          args = margs;
00883          app = "Macro";
00884       }
00885       if (aeldebug & DEBUG_TOKENS)
00886          ast_verbose("-- APP: '%s', ARGS: '%s'\n", app, args);
00887       if (ast_add_extension2(con, 0, exten, *pos, *label, NULL, app, strdup(args), FREE, registrar))
00888          ast_log(LOG_WARNING, "Unable to add step at priority '%d' of %s '%s'\n", *pos, what, name);
00889       else {
00890          (*pos)++;
00891          *label = NULL;
00892       }
00893    }
00894    return 0;
00895 }
00896 
00897 static int build_step(const char *what, const char *name, const char *filename, int lineno, struct ast_context *con, char *exten, int *pos, char *data, struct fillin **fillout, char **label)
00898 {
00899    struct stringlink *args, *cur;
00900    int res=0;
00901    struct fillin *fillin=NULL;
00902    int dropfill = 0;
00903    char *labelin = NULL;
00904    if (!fillout) {
00905       fillout = &fillin;
00906       dropfill = 1;
00907    }
00908    if (!label) {
00909       label = &labelin;
00910    };
00911    args = arg_parse(data, filename, lineno);
00912    cur = args;
00913    while(cur) {
00914       res |= __build_step(what, name, filename, lineno, con, exten, pos, cur->data, fillout, label);
00915       cur = cur->next;
00916    }
00917    arg_free(args);
00918    if (dropfill) {
00919       fillin_process(con, fillin, filename, lineno, NULL, 0, NULL, 0);
00920       fillin_free(fillin);
00921    }
00922    return res;
00923 }
00924 
00925 static int parse_catch(char *data, char **catch, char **rest)
00926 {
00927    /* Skip the word 'catch' */
00928    data += 5;
00929    data = ast_skip_blanks(data);
00930    /* Here's the extension */
00931    *catch = data;
00932    if (!*data)
00933       return 0;
00934    while (*data && (*data > 32)) data++;
00935    if (!*data)
00936       return 0;
00937    /* Trim any trailing spaces */
00938    *data = '\0';
00939    data++;
00940    data = ast_skip_blanks(data);
00941    if (!*data)
00942       return 0;
00943    *rest = data;
00944    return 1;
00945 }
00946 
00947 static void handle_macro(struct ast_context **local_contexts, struct stringlink *vars, const char *filename, int lineno)
00948 {
00949    struct stringlink *argv;
00950    struct stringlink *paramv;
00951    struct stringlink *cur;
00952    struct ast_context *con;
00953    struct fillin *fillin;
00954    char *catch, *rest;
00955    char name[256];
00956    int pos;
00957    int cpos;
00958 
00959    if (aeldebug & DEBUG_MACROS)
00960       ast_verbose("Root macro def is '%s'\n", vars->data);
00961    argv = split_token(vars->data, filename, lineno);
00962    paramv = split_params(vars->data, filename, lineno);
00963    if (aeldebug & DEBUG_MACROS) 
00964       ast_verbose("Found macro '%s'\n", vars->data);
00965    snprintf(name, sizeof(name), "macro-%s", vars->data);
00966    con = ast_context_create(local_contexts, name, registrar);
00967    if (con) {
00968       pos = 1;
00969       cur = paramv;
00970       while(cur) {
00971          if (aeldebug & DEBUG_MACROS)
00972             ast_verbose("  PARAM => '%s'\n", cur->data);
00973          snprintf(name, sizeof(name), "%s=${ARG%d}", cur->data, pos);
00974          if (ast_add_extension2(con, 0, "s", pos, NULL, NULL, "Set", strdup(name), FREE, registrar))
00975             ast_log(LOG_WARNING, "Unable to add step at priority '%d' of macro '%s'\n", pos, vars->data);
00976          else
00977             pos++;
00978          cur = cur->next;
00979       }
00980       cur = argv;
00981       while(cur) {
00982          if (aeldebug & DEBUG_MACROS)
00983             ast_verbose("  STEP => '%s'\n", cur->data);
00984          if (matches_keyword(cur->data, "catch")) {
00985             if (aeldebug & DEBUG_MACROS)
00986                ast_verbose("--CATCH: '%s'\n", cur->data);
00987             if (parse_catch(cur->data, &catch, &rest)) {
00988                cpos = 1;
00989                build_step("catch", catch, filename, lineno, con, catch, &cpos, rest, NULL, NULL);
00990             } else
00991                ast_log(LOG_NOTICE, "Parse error for catch at about line %d of %s\n", lineno, filename);
00992          } else {
00993             fillin = NULL;
00994             build_step("macro", vars->data, filename, lineno, con, "s", &pos, cur->data, NULL, NULL);
00995          }
00996          cur = cur->next;
00997       }
00998    } else
00999       ast_log(LOG_WARNING, "Unable to create context '%s'\n", name);
01000    arg_free(paramv);
01001    arg_free(argv);
01002    if (vars->next)
01003       ast_log(LOG_NOTICE, "Ignoring excess tokens in macro definition around line %d of %s!\n", lineno, filename);
01004 }
01005 
01006 static int matches_extension(char *exten, char **extout)
01007 {
01008    char *c;
01009    *extout = NULL;
01010    c = exten;
01011    while(*c && (*c > 32)) c++;
01012    if (*c) {
01013       *c = '\0';
01014       c++;
01015       c = ast_skip_blanks(c);
01016       if (*c) {
01017          if (*c == '=') {
01018             *c = '\0';
01019             c++;
01020             if (*c == '>')
01021                c++;
01022             c = ast_skip_blanks(c);
01023             *extout = c;
01024             return 1;
01025          }
01026       }
01027    }
01028    return 0;
01029 }
01030 
01031 static void parse_keyword(char *s, char **o)
01032 {
01033    char *c;
01034    c = s;
01035    while((*c) && (*c > 32)) c++;
01036    if (*c) {
01037       *c = '\0';
01038       c++;
01039       c = ast_skip_blanks(c);
01040       *o = c;
01041    } else
01042       *o = NULL;
01043 }
01044 
01045 static void handle_context(struct ast_context **local_contexts, struct stringlink *vars, const char *filename, int lineno)
01046 {
01047    struct stringlink *argv;
01048    struct stringlink *cur2;
01049    struct stringlink *argv2;
01050    struct stringlink *cur;
01051    struct ast_context *con;
01052    char *rest;
01053    char *c;
01054    char name[256];
01055    int pos;
01056 
01057    if (aeldebug & DEBUG_CONTEXTS)
01058       ast_verbose("Root context def is '%s'\n", vars->data);
01059    argv = split_token(vars->data, filename, lineno);
01060    if (aeldebug & DEBUG_CONTEXTS) 
01061       ast_verbose("Found context '%s'\n", vars->data);
01062    snprintf(name, sizeof(name), "%s", vars->data);
01063    con = ast_context_create(local_contexts, name, registrar);
01064    if (con) {
01065       cur = argv;
01066       while(cur) {
01067          if (matches_keyword(cur->data, "includes")) {
01068             if (aeldebug & DEBUG_CONTEXTS)
01069                ast_verbose("--INCLUDES: '%s'\n", cur->data);
01070             parse_keyword(cur->data, &rest);
01071             if (rest) {
01072                argv2 = arg_parse(rest, filename, lineno);
01073                cur2 = argv2;
01074                while(cur2) {
01075                   ast_context_add_include2(con, cur2->data, registrar);
01076                   cur2 = cur2->next;
01077                }
01078                arg_free(argv2);
01079             }
01080          } else if (matches_keyword(cur->data, "ignorepat")) {
01081             if (aeldebug & DEBUG_CONTEXTS)
01082                ast_verbose("--IGNOREPAT: '%s'\n", cur->data);
01083             parse_keyword(cur->data, &rest);
01084             if (rest) {
01085                argv2 = arg_parse(rest, filename, lineno);
01086                cur2 = argv2;
01087                while(cur2) {
01088                   ast_context_add_ignorepat2(con, cur2->data, registrar);
01089                   cur2 = cur2->next;
01090                }
01091                arg_free(argv2);
01092             }
01093          } else if (matches_keyword(cur->data, "switches") || matches_keyword(cur->data, "eswitches")) {
01094             if (aeldebug & DEBUG_CONTEXTS)
01095                ast_verbose("--[E]SWITCH: '%s'\n", cur->data);
01096             parse_keyword(cur->data, &rest);
01097             if (rest) {
01098                argv2 = arg_parse(rest, filename, lineno);
01099                cur2 = argv2;
01100                while(cur2) {
01101                   c = strchr(cur2->data, '/');
01102                   if (c) {
01103                      *c = '\0';
01104                      c++;
01105                   } else
01106                      c = "";
01107                   ast_context_add_switch2(con, cur2->data, c, (cur->data[0] == 'e'), registrar);
01108                   cur2 = cur2->next;
01109                }
01110                arg_free(argv2);
01111             }
01112          } else if (matches_extension(cur->data, &rest)) {
01113             if (aeldebug & DEBUG_CONTEXTS)
01114                ast_verbose("Extension: '%s' => '%s'\n", cur->data, rest);
01115             pos = 1;
01116             build_step("extension", cur->data, filename, lineno, con, cur->data, &pos, rest, NULL, NULL);
01117          }
01118          cur = cur->next;
01119       }
01120    } else
01121          ast_log(LOG_WARNING, "Unable to create context '%s'\n", name);
01122    arg_free(argv);
01123    if (vars->next)
01124       ast_log(LOG_NOTICE, "Ignoring excess tokens in macro definition around line %d of %s!\n", lineno, filename);
01125 }
01126 
01127 static int handle_root_token(struct ast_context **local_contexts, char *token, int level, const char *filename, int lineno)
01128 {
01129    struct stringlink *argv, *cur;
01130    argv = split_token(token, filename, lineno);
01131    if (aeldebug & DEBUG_TOKENS) {
01132       ast_verbose("Found root token '%s' at level %d (%s:%d)!\n", token, level, filename, lineno);
01133       cur = argv;
01134       while(cur) {
01135          ast_verbose("   ARG => '%s'\n", cur->data);
01136          cur = cur->next;
01137       }
01138    }
01139    if (!strcasecmp(token, "globals")) {
01140       handle_globals(argv);
01141    } else if (!strcasecmp(token, "macro")) {
01142       handle_macro(local_contexts, argv, filename, lineno);
01143    } else if (!strcasecmp(token, "context")) {
01144       handle_context(local_contexts, argv, filename, lineno);
01145    } else {
01146       ast_log(LOG_NOTICE, "Unknown root token '%s'\n", token);
01147    }
01148    arg_free(argv);
01149    return 0;
01150 }
01151 
01152 
01153 static int ast_ael_compile(struct ast_context **local_contexts, const char *filename)
01154 {
01155    char *rfilename;
01156    char *buf, *tbuf;
01157    int bufsiz;
01158    FILE *f;
01159    char *c;
01160    char *token;
01161    int lineno=0;
01162 
01163    if (filename[0] == '/')
01164       rfilename = (char *)filename;
01165    else {
01166       rfilename = alloca(strlen(filename) + strlen(ast_config_AST_CONFIG_DIR) + 2);
01167       sprintf(rfilename, "%s/%s", ast_config_AST_CONFIG_DIR, filename);
01168    }
01169    
01170    f = fopen(rfilename, "r");
01171    if (!f) {
01172       ast_log(LOG_WARNING, "Unable to open '%s': %s\n", rfilename, strerror(errno));
01173       return -1;
01174    }
01175    buf = malloc(4096);
01176    if (!buf) {
01177       ast_log(LOG_WARNING, "Out of memory!\n");
01178       fclose(f);
01179       return -1;
01180    }
01181    buf[0] = 0;
01182    bufsiz = 4096;
01183    while(!feof(f)) {
01184       if (bufsiz - strlen(buf) < 2048) {
01185          bufsiz += 4096;
01186          tbuf = realloc(buf, bufsiz);
01187          if (tbuf) {
01188             buf = tbuf;
01189          } else {
01190             free(buf);
01191             ast_log(LOG_WARNING, "Out of memory!\n");
01192             fclose(f);
01193          }
01194       }
01195       if (fgets(buf + strlen(buf), bufsiz - strlen(buf), f)) {
01196          lineno++;
01197          while(*buf && buf[strlen(buf) - 1] < 33)
01198             buf[strlen(buf) - 1] = '\0';
01199          c = strstr(buf, "//");
01200          if (c)
01201             *c = '\0';
01202          if (*buf) {
01203             if (aeldebug & DEBUG_READ)
01204                ast_verbose("Newly composed line '%s'\n", buf);
01205             while((token = grab_token(buf, filename, lineno))) {
01206                handle_root_token(local_contexts, token, 0, filename, lineno);
01207                free(token);
01208             }
01209          }
01210       }
01211    };
01212    free(buf);
01213    fclose(f);
01214    return 0;
01215 }
01216 
01217 static int pbx_load_module(void)
01218 {
01219    struct ast_context *local_contexts=NULL, *con;
01220    ast_ael_compile(&local_contexts, config);
01221    ast_merge_contexts_and_delete(&local_contexts, registrar);
01222    for (con = ast_walk_contexts(NULL); con; con = ast_walk_contexts(con))
01223       ast_context_verify_includes(con);
01224 
01225    return 0;
01226 }
01227 
01228 /* CLI interface */
01229 static int ael_debug_read(int fd, int argc, char *argv[])
01230 {
01231    aeldebug |= DEBUG_READ;
01232    return 0;
01233 }
01234 
01235 static int ael_debug_tokens(int fd, int argc, char *argv[])
01236 {
01237    aeldebug |= DEBUG_TOKENS;
01238    return 0;
01239 }
01240 
01241 static int ael_debug_macros(int fd, int argc, char *argv[])
01242 {
01243    aeldebug |= DEBUG_MACROS;
01244    return 0;
01245 }
01246 
01247 static int ael_debug_contexts(int fd, int argc, char *argv[])
01248 {
01249    aeldebug |= DEBUG_CONTEXTS;
01250    return 0;
01251 }
01252 
01253 static int ael_no_debug(int fd, int argc, char *argv[])
01254 {
01255    aeldebug = 0;
01256    return 0;
01257 }
01258 
01259 static int ael_reload(int fd, int argc, char *argv[])
01260 {
01261    ast_context_destroy(NULL, registrar);
01262    return (pbx_load_module());
01263 }
01264 
01265 static struct ast_cli_entry  ael_cli[] = {
01266    { { "ael", "reload", NULL }, ael_reload, "Reload AEL configuration"},
01267    { { "ael", "debug", "read", NULL }, ael_debug_read, "Enable AEL read debug"},
01268    { { "ael", "debug", "tokens", NULL }, ael_debug_tokens, "Enable AEL tokens debug"},
01269    { { "ael", "debug", "macros", NULL }, ael_debug_macros, "Enable AEL macros debug"},
01270    { { "ael", "debug", "contexts", NULL }, ael_debug_contexts, "Enable AEL contexts debug"},
01271    { { "ael", "no", "debug", NULL }, ael_no_debug, "Disable AEL debug messages"},
01272 };
01273 
01274 /*
01275  * Standard module functions ...
01276  */
01277 int unload_module(void)
01278 {
01279    ast_context_destroy(NULL, registrar);
01280    ast_cli_unregister_multiple(ael_cli, sizeof(ael_cli)/ sizeof(ael_cli[0]));
01281    return 0;
01282 }
01283 
01284 
01285 int load_module(void)
01286 {
01287    ast_cli_register_multiple(ael_cli, sizeof(ael_cli)/ sizeof(ael_cli[0]));
01288    return (pbx_load_module());
01289 }
01290 
01291 int reload(void)
01292 {
01293    ast_context_destroy(NULL, registrar);
01294    return pbx_load_module();
01295 }
01296 
01297 int usecount(void)
01298 {
01299    return 0;
01300 }
01301 
01302 char *description(void)
01303 {
01304    return dtext;
01305 }
01306 
01307 char *key(void)
01308 {
01309    return ASTERISK_GPL_KEY;
01310 }

Generated on Wed Oct 28 15:47:55 2009 for Asterisk - the Open Source PBX by  doxygen 1.5.6