00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029 #include "asterisk.h"
00030
00031 #if !defined(STANDALONE)
00032 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 165792 $")
00033 #endif
00034
00035 #include <ctype.h>
00036 #include <regex.h>
00037 #include <sys/stat.h>
00038
00039 #ifdef STANDALONE
00040 #ifdef HAVE_MTX_PROFILE
00041 static int mtx_prof = -1;
00042 #endif
00043 #endif
00044 #include "asterisk/pbx.h"
00045 #include "asterisk/config.h"
00046 #include "asterisk/module.h"
00047 #include "asterisk/logger.h"
00048 #include "asterisk/cli.h"
00049 #include "asterisk/app.h"
00050 #include "asterisk/callerid.h"
00051 #include "asterisk/hashtab.h"
00052 #include "asterisk/ael_structs.h"
00053 #include "asterisk/pval.h"
00054 #ifdef AAL_ARGCHECK
00055 #include "asterisk/argdesc.h"
00056 #endif
00057
00058
00059
00060 #define DEBUG_READ (1 << 0)
00061 #define DEBUG_TOKENS (1 << 1)
00062 #define DEBUG_MACROS (1 << 2)
00063 #define DEBUG_CONTEXTS (1 << 3)
00064
00065 static char *config = "extensions.ael";
00066 static char *registrar = "pbx_ael";
00067 static int pbx_load_module(void);
00068
00069 #ifndef AAL_ARGCHECK
00070
00071
00072
00073
00074
00075 #endif
00076
00077 #ifdef AAL_ARGCHECK
00078 int option_matches_j( struct argdesc *should, pval *is, struct argapp *app);
00079 int option_matches( struct argdesc *should, pval *is, struct argapp *app);
00080 int ael_is_funcname(char *name);
00081 #endif
00082
00083 int check_app_args(pval *appcall, pval *arglist, struct argapp *app);
00084 void check_pval(pval *item, struct argapp *apps, int in_globals);
00085 void check_pval_item(pval *item, struct argapp *apps, int in_globals);
00086 void check_switch_expr(pval *item, struct argapp *apps);
00087 void ast_expr_register_extra_error_info(char *errmsg);
00088 void ast_expr_clear_extra_error_info(void);
00089 struct pval *find_macro(char *name);
00090 struct pval *find_context(char *name);
00091 struct pval *find_context(char *name);
00092 struct pval *find_macro(char *name);
00093 struct ael_priority *new_prio(void);
00094 struct ael_extension *new_exten(void);
00095 void destroy_extensions(struct ael_extension *exten);
00096 void set_priorities(struct ael_extension *exten);
00097 void add_extensions(struct ael_extension *exten);
00098 void ast_compile_ael2(struct ast_context **local_contexts, struct ast_hashtab *local_table, struct pval *root);
00099 void destroy_pval(pval *item);
00100 void destroy_pval_item(pval *item);
00101 int is_float(char *arg );
00102 int is_int(char *arg );
00103 int is_empty(char *arg);
00104
00105
00106
00107 static int aeldebug = 0;
00108
00109
00110
00111
00112
00113 static int pbx_load_module(void)
00114 {
00115 int errs=0, sem_err=0, sem_warn=0, sem_note=0;
00116 char *rfilename;
00117 struct ast_context *local_contexts=NULL, *con;
00118 struct ast_hashtab *local_table=NULL;
00119
00120 struct pval *parse_tree;
00121
00122 ast_log(LOG_NOTICE, "Starting AEL load process.\n");
00123 if (config[0] == '/')
00124 rfilename = (char *)config;
00125 else {
00126 rfilename = alloca(strlen(config) + strlen(ast_config_AST_CONFIG_DIR) + 2);
00127 sprintf(rfilename, "%s/%s", ast_config_AST_CONFIG_DIR, config);
00128 }
00129 if (access(rfilename,R_OK) != 0) {
00130 ast_log(LOG_NOTICE, "File %s not found; AEL declining load\n", rfilename);
00131 return AST_MODULE_LOAD_DECLINE;
00132 }
00133
00134 parse_tree = ael2_parse(rfilename, &errs);
00135 ast_log(LOG_NOTICE, "AEL load process: parsed config file name '%s'.\n", rfilename);
00136 ael2_semantic_check(parse_tree, &sem_err, &sem_warn, &sem_note);
00137 if (errs == 0 && sem_err == 0) {
00138 ast_log(LOG_NOTICE, "AEL load process: checked config file name '%s'.\n", rfilename);
00139 local_table = ast_hashtab_create(11, ast_hashtab_compare_contexts, ast_hashtab_resize_java, ast_hashtab_newsize_java, ast_hashtab_hash_contexts, 0);
00140 ast_compile_ael2(&local_contexts, local_table, parse_tree);
00141 ast_log(LOG_NOTICE, "AEL load process: compiled config file name '%s'.\n", rfilename);
00142
00143 ast_merge_contexts_and_delete(&local_contexts, local_table, registrar);
00144 local_table = NULL;
00145 local_contexts = NULL;
00146 ast_log(LOG_NOTICE, "AEL load process: merged config file name '%s'.\n", rfilename);
00147 for (con = ast_walk_contexts(NULL); con; con = ast_walk_contexts(con))
00148 ast_context_verify_includes(con);
00149 ast_log(LOG_NOTICE, "AEL load process: verified config file name '%s'.\n", rfilename);
00150 } else {
00151 ast_log(LOG_ERROR, "Sorry, but %d syntax errors and %d semantic errors were detected. It doesn't make sense to compile.\n", errs, sem_err);
00152 destroy_pval(parse_tree);
00153 return AST_MODULE_LOAD_DECLINE;
00154 }
00155 destroy_pval(parse_tree);
00156
00157 return AST_MODULE_LOAD_SUCCESS;
00158 }
00159
00160
00161 static char *handle_cli_ael_set_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00162 {
00163 switch (cmd) {
00164 case CLI_INIT:
00165 e->command = "ael set debug {read|tokens|macros|contexts|off}";
00166 e->usage =
00167 "Usage: ael set debug {read|tokens|macros|contexts|off}\n"
00168 " Enable AEL read, token, macro, or context debugging,\n"
00169 " or disable all AEL debugging messages. Note: this\n"
00170 " currently does nothing.\n";
00171 return NULL;
00172 case CLI_GENERATE:
00173 return NULL;
00174 }
00175
00176 if (a->argc != e->args)
00177 return CLI_SHOWUSAGE;
00178
00179 if (!strcasecmp(a->argv[3], "read"))
00180 aeldebug |= DEBUG_READ;
00181 else if (!strcasecmp(a->argv[3], "tokens"))
00182 aeldebug |= DEBUG_TOKENS;
00183 else if (!strcasecmp(a->argv[3], "macros"))
00184 aeldebug |= DEBUG_MACROS;
00185 else if (!strcasecmp(a->argv[3], "contexts"))
00186 aeldebug |= DEBUG_CONTEXTS;
00187 else if (!strcasecmp(a->argv[3], "off"))
00188 aeldebug = 0;
00189 else
00190 return CLI_SHOWUSAGE;
00191
00192 return CLI_SUCCESS;
00193 }
00194
00195 static char *handle_cli_ael_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00196 {
00197 switch (cmd) {
00198 case CLI_INIT:
00199 e->command = "ael reload";
00200 e->usage =
00201 "Usage: ael reload\n"
00202 " Reloads AEL configuration.\n";
00203 return NULL;
00204 case CLI_GENERATE:
00205 return NULL;
00206 }
00207
00208 if (a->argc != 2)
00209 return CLI_SHOWUSAGE;
00210
00211 return (pbx_load_module() ? CLI_FAILURE : CLI_SUCCESS);
00212 }
00213
00214 static struct ast_cli_entry cli_ael[] = {
00215 AST_CLI_DEFINE(handle_cli_ael_reload, "Reload AEL configuration"),
00216 AST_CLI_DEFINE(handle_cli_ael_set_debug, "Enable AEL debugging flags")
00217 };
00218
00219 static int unload_module(void)
00220 {
00221 ast_context_destroy(NULL, registrar);
00222 ast_cli_unregister_multiple(cli_ael, ARRAY_LEN(cli_ael));
00223 return 0;
00224 }
00225
00226 static int load_module(void)
00227 {
00228 ast_cli_register_multiple(cli_ael, ARRAY_LEN(cli_ael));
00229 return (pbx_load_module());
00230 }
00231
00232 static int reload(void)
00233 {
00234 return pbx_load_module();
00235 }
00236
00237 #ifdef STANDALONE
00238 #define AST_MODULE "ael"
00239 int ael_external_load_module(void);
00240 int ael_external_load_module(void)
00241 {
00242 pbx_load_module();
00243 return 1;
00244 }
00245 #endif
00246
00247 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Asterisk Extension Language Compiler",
00248 .load = load_module,
00249 .unload = unload_module,
00250 .reload = reload,
00251 );
00252
00253 #ifdef AAL_ARGCHECK
00254 static char *ael_funclist[] =
00255 {
00256 "AGENT",
00257 "ARRAY",
00258 "BASE64_DECODE",
00259 "BASE64_ENCODE",
00260 "CALLERID",
00261 "CDR",
00262 "CHANNEL",
00263 "CHECKSIPDOMAIN",
00264 "CHECK_MD5",
00265 "CURL",
00266 "CUT",
00267 "DB",
00268 "DB_EXISTS",
00269 "DUNDILOOKUP",
00270 "ENUMLOOKUP",
00271 "ENV",
00272 "EVAL",
00273 "EXISTS",
00274 "FIELDQTY",
00275 "FILTER",
00276 "GROUP",
00277 "GROUP_COUNT",
00278 "GROUP_LIST",
00279 "GROUP_MATCH_COUNT",
00280 "IAXPEER",
00281 "IF",
00282 "IFTIME",
00283 "ISNULL",
00284 "KEYPADHASH",
00285 "LANGUAGE",
00286 "LEN",
00287 "MATH",
00288 "MD5",
00289 "MUSICCLASS",
00290 "QUEUEAGENTCOUNT",
00291 "QUEUE_MEMBER_COUNT",
00292 "QUEUE_MEMBER_LIST",
00293 "QUOTE",
00294 "RAND",
00295 "REGEX",
00296 "SET",
00297 "SHA1",
00298 "SIPCHANINFO",
00299 "SIPPEER",
00300 "SIP_HEADER",
00301 "SORT",
00302 "STAT",
00303 "STRFTIME",
00304 "STRPTIME",
00305 "TIMEOUT",
00306 "TXTCIDNAME",
00307 "URIDECODE",
00308 "URIENCODE",
00309 "VMCOUNT"
00310 };
00311
00312
00313 int ael_is_funcname(char *name)
00314 {
00315 int s,t;
00316 t = sizeof(ael_funclist)/sizeof(char*);
00317 s = 0;
00318 while ((s < t) && strcasecmp(name, ael_funclist[s]))
00319 s++;
00320 if ( s < t )
00321 return 1;
00322 else
00323 return 0;
00324 }
00325 #endif