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: 310448 $")
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
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080 #define DEBUG_READ (1 << 0)
00081 #define DEBUG_TOKENS (1 << 1)
00082 #define DEBUG_MACROS (1 << 2)
00083 #define DEBUG_CONTEXTS (1 << 3)
00084
00085 static char *config = "extensions.ael";
00086 static char *registrar = "pbx_ael";
00087 static int pbx_load_module(void);
00088
00089 #ifndef AAL_ARGCHECK
00090
00091
00092
00093
00094
00095 #endif
00096
00097 #ifdef AAL_ARGCHECK
00098 int option_matches_j( struct argdesc *should, pval *is, struct argapp *app);
00099 int option_matches( struct argdesc *should, pval *is, struct argapp *app);
00100 int ael_is_funcname(char *name);
00101 #endif
00102
00103 int check_app_args(pval *appcall, pval *arglist, struct argapp *app);
00104 void check_pval(pval *item, struct argapp *apps, int in_globals);
00105 void check_pval_item(pval *item, struct argapp *apps, int in_globals);
00106 void check_switch_expr(pval *item, struct argapp *apps);
00107 void ast_expr_register_extra_error_info(char *errmsg);
00108 void ast_expr_clear_extra_error_info(void);
00109 struct pval *find_macro(char *name);
00110 struct pval *find_context(char *name);
00111 struct pval *find_context(char *name);
00112 struct pval *find_macro(char *name);
00113 struct ael_priority *new_prio(void);
00114 struct ael_extension *new_exten(void);
00115 void destroy_extensions(struct ael_extension *exten);
00116 void set_priorities(struct ael_extension *exten);
00117 void add_extensions(struct ael_extension *exten);
00118 int ast_compile_ael2(struct ast_context **local_contexts, struct ast_hashtab *local_table, struct pval *root);
00119 void destroy_pval(pval *item);
00120 void destroy_pval_item(pval *item);
00121 int is_float(char *arg );
00122 int is_int(char *arg );
00123 int is_empty(char *arg);
00124
00125
00126
00127 static int aeldebug = 0;
00128
00129
00130
00131 #ifndef STANDALONE
00132 static char *aelsub = "AELSub";
00133
00134 static int aelsub_exec(struct ast_channel *chan, void *vdata)
00135 {
00136 char buf[256], *data = ast_strdupa(vdata);
00137 struct ast_app *gosub = pbx_findapp("Gosub");
00138 AST_DECLARE_APP_ARGS(args,
00139 AST_APP_ARG(name);
00140 AST_APP_ARG(args);
00141 );
00142
00143 if (gosub) {
00144 AST_STANDARD_RAW_ARGS(args, data);
00145 snprintf(buf, sizeof(buf), "%s,~~s~~,1(%s)", args.name, args.args);
00146 return pbx_exec(chan, gosub, buf);
00147 }
00148 return -1;
00149 }
00150 #endif
00151
00152
00153
00154 static int pbx_load_module(void)
00155 {
00156 int errs=0, sem_err=0, sem_warn=0, sem_note=0;
00157 char *rfilename;
00158 struct ast_context *local_contexts=NULL, *con;
00159 struct ast_hashtab *local_table=NULL;
00160
00161 struct pval *parse_tree;
00162
00163 ast_log(LOG_NOTICE, "Starting AEL load process.\n");
00164 if (config[0] == '/')
00165 rfilename = (char *)config;
00166 else {
00167 rfilename = alloca(strlen(config) + strlen(ast_config_AST_CONFIG_DIR) + 2);
00168 sprintf(rfilename, "%s/%s", ast_config_AST_CONFIG_DIR, config);
00169 }
00170 if (access(rfilename,R_OK) != 0) {
00171 ast_log(LOG_NOTICE, "File %s not found; AEL declining load\n", rfilename);
00172 return AST_MODULE_LOAD_DECLINE;
00173 }
00174
00175 parse_tree = ael2_parse(rfilename, &errs);
00176 ast_log(LOG_NOTICE, "AEL load process: parsed config file name '%s'.\n", rfilename);
00177 ael2_semantic_check(parse_tree, &sem_err, &sem_warn, &sem_note);
00178 if (errs == 0 && sem_err == 0) {
00179 ast_log(LOG_NOTICE, "AEL load process: checked config file name '%s'.\n", rfilename);
00180 local_table = ast_hashtab_create(11, ast_hashtab_compare_contexts, ast_hashtab_resize_java, ast_hashtab_newsize_java, ast_hashtab_hash_contexts, 0);
00181 if (ast_compile_ael2(&local_contexts, local_table, parse_tree)) {
00182 ast_log(LOG_ERROR, "AEL compile failed! Aborting.\n");
00183 destroy_pval(parse_tree);
00184 return AST_MODULE_LOAD_DECLINE;
00185 }
00186 ast_log(LOG_NOTICE, "AEL load process: compiled config file name '%s'.\n", rfilename);
00187
00188 ast_merge_contexts_and_delete(&local_contexts, local_table, registrar);
00189 local_table = NULL;
00190 local_contexts = NULL;
00191 ast_log(LOG_NOTICE, "AEL load process: merged config file name '%s'.\n", rfilename);
00192 for (con = ast_walk_contexts(NULL); con; con = ast_walk_contexts(con))
00193 ast_context_verify_includes(con);
00194 ast_log(LOG_NOTICE, "AEL load process: verified config file name '%s'.\n", rfilename);
00195 } else {
00196 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);
00197 destroy_pval(parse_tree);
00198 return AST_MODULE_LOAD_DECLINE;
00199 }
00200 destroy_pval(parse_tree);
00201
00202 return AST_MODULE_LOAD_SUCCESS;
00203 }
00204
00205
00206 static char *handle_cli_ael_set_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00207 {
00208 switch (cmd) {
00209 case CLI_INIT:
00210 e->command = "ael set debug {read|tokens|macros|contexts|off}";
00211 e->usage =
00212 "Usage: ael set debug {read|tokens|macros|contexts|off}\n"
00213 " Enable AEL read, token, macro, or context debugging,\n"
00214 " or disable all AEL debugging messages. Note: this\n"
00215 " currently does nothing.\n";
00216 return NULL;
00217 case CLI_GENERATE:
00218 return NULL;
00219 }
00220
00221 if (a->argc != e->args)
00222 return CLI_SHOWUSAGE;
00223
00224 if (!strcasecmp(a->argv[3], "read"))
00225 aeldebug |= DEBUG_READ;
00226 else if (!strcasecmp(a->argv[3], "tokens"))
00227 aeldebug |= DEBUG_TOKENS;
00228 else if (!strcasecmp(a->argv[3], "macros"))
00229 aeldebug |= DEBUG_MACROS;
00230 else if (!strcasecmp(a->argv[3], "contexts"))
00231 aeldebug |= DEBUG_CONTEXTS;
00232 else if (!strcasecmp(a->argv[3], "off"))
00233 aeldebug = 0;
00234 else
00235 return CLI_SHOWUSAGE;
00236
00237 return CLI_SUCCESS;
00238 }
00239
00240 static char *handle_cli_ael_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00241 {
00242 switch (cmd) {
00243 case CLI_INIT:
00244 e->command = "ael reload";
00245 e->usage =
00246 "Usage: ael reload\n"
00247 " Reloads AEL configuration.\n";
00248 return NULL;
00249 case CLI_GENERATE:
00250 return NULL;
00251 }
00252
00253 if (a->argc != 2)
00254 return CLI_SHOWUSAGE;
00255
00256 return (pbx_load_module() ? CLI_FAILURE : CLI_SUCCESS);
00257 }
00258
00259 static struct ast_cli_entry cli_ael[] = {
00260 AST_CLI_DEFINE(handle_cli_ael_reload, "Reload AEL configuration"),
00261 AST_CLI_DEFINE(handle_cli_ael_set_debug, "Enable AEL debugging flags")
00262 };
00263
00264 static int unload_module(void)
00265 {
00266 ast_context_destroy(NULL, registrar);
00267 ast_cli_unregister_multiple(cli_ael, ARRAY_LEN(cli_ael));
00268 #ifndef STANDALONE
00269 ast_unregister_application(aelsub);
00270 #endif
00271 return 0;
00272 }
00273
00274 static int load_module(void)
00275 {
00276 ast_cli_register_multiple(cli_ael, ARRAY_LEN(cli_ael));
00277 #ifndef STANDALONE
00278 ast_register_application_xml(aelsub, aelsub_exec);
00279 #endif
00280 return (pbx_load_module());
00281 }
00282
00283 static int reload(void)
00284 {
00285 return pbx_load_module();
00286 }
00287
00288 #ifdef STANDALONE
00289 #define AST_MODULE "ael"
00290 int ael_external_load_module(void);
00291 int ael_external_load_module(void)
00292 {
00293 pbx_load_module();
00294 return 1;
00295 }
00296 #endif
00297
00298 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Asterisk Extension Language Compiler",
00299 .load = load_module,
00300 .unload = unload_module,
00301 .reload = reload,
00302 );
00303
00304 #ifdef AAL_ARGCHECK
00305 static char *ael_funclist[] =
00306 {
00307 "AGENT",
00308 "ARRAY",
00309 "BASE64_DECODE",
00310 "BASE64_ENCODE",
00311 "CALLERID",
00312 "CDR",
00313 "CHANNEL",
00314 "CHECKSIPDOMAIN",
00315 "CHECK_MD5",
00316 "CURL",
00317 "CUT",
00318 "DB",
00319 "DB_EXISTS",
00320 "DUNDILOOKUP",
00321 "ENUMLOOKUP",
00322 "ENV",
00323 "EVAL",
00324 "EXISTS",
00325 "FIELDQTY",
00326 "FILTER",
00327 "GROUP",
00328 "GROUP_COUNT",
00329 "GROUP_LIST",
00330 "GROUP_MATCH_COUNT",
00331 "IAXPEER",
00332 "IF",
00333 "IFTIME",
00334 "ISNULL",
00335 "KEYPADHASH",
00336 "LANGUAGE",
00337 "LEN",
00338 "MATH",
00339 "MD5",
00340 "MUSICCLASS",
00341 "QUEUEAGENTCOUNT",
00342 "QUEUE_MEMBER_COUNT",
00343 "QUEUE_MEMBER_LIST",
00344 "QUOTE",
00345 "RAND",
00346 "REGEX",
00347 "SET",
00348 "SHA1",
00349 "SIPCHANINFO",
00350 "SIPPEER",
00351 "SIP_HEADER",
00352 "SORT",
00353 "STAT",
00354 "STRFTIME",
00355 "STRPTIME",
00356 "TIMEOUT",
00357 "TXTCIDNAME",
00358 "URIDECODE",
00359 "URIENCODE",
00360 "VMCOUNT"
00361 };
00362
00363
00364 int ael_is_funcname(char *name)
00365 {
00366 int s,t;
00367 t = sizeof(ael_funclist)/sizeof(char*);
00368 s = 0;
00369 while ((s < t) && strcasecmp(name, ael_funclist[s]))
00370 s++;
00371 if ( s < t )
00372 return 1;
00373 else
00374 return 0;
00375 }
00376 #endif