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
00030 #include "asterisk.h"
00031
00032 #if !defined(STANDALONE)
00033 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 328209 $")
00034 #endif
00035
00036 #include <ctype.h>
00037 #include <regex.h>
00038 #include <sys/stat.h>
00039
00040 #ifdef STANDALONE
00041 #ifdef HAVE_MTX_PROFILE
00042 static int mtx_prof = -1;
00043 #endif
00044 #endif
00045 #include "asterisk/pbx.h"
00046 #include "asterisk/config.h"
00047 #include "asterisk/module.h"
00048 #include "asterisk/logger.h"
00049 #include "asterisk/cli.h"
00050 #include "asterisk/app.h"
00051 #include "asterisk/callerid.h"
00052 #include "asterisk/hashtab.h"
00053 #include "asterisk/ael_structs.h"
00054 #include "asterisk/pval.h"
00055 #ifdef AAL_ARGCHECK
00056 #include "asterisk/argdesc.h"
00057 #endif
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081 #define DEBUG_READ (1 << 0)
00082 #define DEBUG_TOKENS (1 << 1)
00083 #define DEBUG_MACROS (1 << 2)
00084 #define DEBUG_CONTEXTS (1 << 3)
00085
00086 static char *config = "extensions.ael";
00087 static char *registrar = "pbx_ael";
00088 static int pbx_load_module(void);
00089
00090 #ifndef AAL_ARGCHECK
00091
00092
00093
00094
00095
00096 #endif
00097
00098 #ifdef AAL_ARGCHECK
00099 int option_matches_j( struct argdesc *should, pval *is, struct argapp *app);
00100 int option_matches( struct argdesc *should, pval *is, struct argapp *app);
00101 int ael_is_funcname(char *name);
00102 #endif
00103
00104 int check_app_args(pval *appcall, pval *arglist, struct argapp *app);
00105 void check_pval(pval *item, struct argapp *apps, int in_globals);
00106 void check_pval_item(pval *item, struct argapp *apps, int in_globals);
00107 void check_switch_expr(pval *item, struct argapp *apps);
00108 void ast_expr_register_extra_error_info(char *errmsg);
00109 void ast_expr_clear_extra_error_info(void);
00110 struct pval *find_macro(char *name);
00111 struct pval *find_context(char *name);
00112 struct pval *find_context(char *name);
00113 struct pval *find_macro(char *name);
00114 struct ael_priority *new_prio(void);
00115 struct ael_extension *new_exten(void);
00116 void destroy_extensions(struct ael_extension *exten);
00117 void set_priorities(struct ael_extension *exten);
00118 void add_extensions(struct ael_extension *exten);
00119 int ast_compile_ael2(struct ast_context **local_contexts, struct ast_hashtab *local_table, struct pval *root);
00120 void destroy_pval(pval *item);
00121 void destroy_pval_item(pval *item);
00122 int is_float(char *arg );
00123 int is_int(char *arg );
00124 int is_empty(char *arg);
00125
00126
00127
00128 static int aeldebug = 0;
00129
00130
00131
00132 #ifndef STANDALONE
00133 static char *aelsub = "AELSub";
00134
00135 static int aelsub_exec(struct ast_channel *chan, const char *vdata)
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 }
00151 #endif
00152
00153
00154
00155 static int pbx_load_module(void)
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);
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;
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);
00199 return AST_MODULE_LOAD_DECLINE;
00200 }
00201 destroy_pval(parse_tree);
00202
00203 return AST_MODULE_LOAD_SUCCESS;
00204 }
00205
00206
00207 static char *handle_cli_ael_set_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
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 }
00240
00241 static char *handle_cli_ael_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
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 }
00259
00260 static struct ast_cli_entry cli_ael[] = {
00261 AST_CLI_DEFINE(handle_cli_ael_reload, "Reload AEL configuration"),
00262 AST_CLI_DEFINE(handle_cli_ael_set_debug, "Enable AEL debugging flags")
00263 };
00264
00265 static int unload_module(void)
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 }
00274
00275 static int load_module(void)
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 }
00283
00284 static int reload(void)
00285 {
00286 return pbx_load_module();
00287 }
00288
00289 #ifdef STANDALONE
00290 #define AST_MODULE "ael"
00291 int ael_external_load_module(void);
00292 int ael_external_load_module(void)
00293 {
00294 pbx_load_module();
00295 return 1;
00296 }
00297 #endif
00298
00299 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Asterisk Extension Language Compiler",
00300 .load = load_module,
00301 .unload = unload_module,
00302 .reload = reload,
00303 );
00304
00305 #ifdef AAL_ARGCHECK
00306 static const char * const ael_funclist[] =
00307 {
00308 "AGENT",
00309 "ARRAY",
00310 "BASE64_DECODE",
00311 "BASE64_ENCODE",
00312 "CALLERID",
00313 "CDR",
00314 "CHANNEL",
00315 "CHECKSIPDOMAIN",
00316 "CHECK_MD5",
00317 "CURL",
00318 "CUT",
00319 "DB",
00320 "DB_EXISTS",
00321 "DUNDILOOKUP",
00322 "ENUMLOOKUP",
00323 "ENV",
00324 "EVAL",
00325 "EXISTS",
00326 "FIELDQTY",
00327 "FILTER",
00328 "GROUP",
00329 "GROUP_COUNT",
00330 "GROUP_LIST",
00331 "GROUP_MATCH_COUNT",
00332 "IAXPEER",
00333 "IF",
00334 "IFTIME",
00335 "ISNULL",
00336 "KEYPADHASH",
00337 "LANGUAGE",
00338 "LEN",
00339 "MATH",
00340 "MD5",
00341 "MUSICCLASS",
00342 "QUEUEAGENTCOUNT",
00343 "QUEUE_MEMBER_COUNT",
00344 "QUEUE_MEMBER_LIST",
00345 "QUOTE",
00346 "RAND",
00347 "REGEX",
00348 "SET",
00349 "SHA1",
00350 "SIPCHANINFO",
00351 "SIPPEER",
00352 "SIP_HEADER",
00353 "SORT",
00354 "STAT",
00355 "STRFTIME",
00356 "STRPTIME",
00357 "TIMEOUT",
00358 "TXTCIDNAME",
00359 "URIDECODE",
00360 "URIENCODE",
00361 "VMCOUNT"
00362 };
00363
00364
00365 int ael_is_funcname(char *name)
00366 {
00367 int s,t;
00368 t = sizeof(ael_funclist)/sizeof(char*);
00369 s = 0;
00370 while ((s < t) && strcasecmp(name, ael_funclist[s]))
00371 s++;
00372 if ( s < t )
00373 return 1;
00374 else
00375 return 0;
00376 }
00377 #endif