Merged revisions 140817 via svnmerge from
[asterisk-bristuff.git] / pbx / pbx_ael.c
blob22ec24105df1f88ce9bd65401eea8f4df5caa3ce
1 /*
2 * Asterisk -- An open source telephony toolkit.
4 * Copyright (C) 2006, Digium, Inc.
6 * Steve Murphy <murf@parsetree.com>
8 * See http://www.asterisk.org for more information about
9 * the Asterisk project. Please do not directly contact
10 * any of the maintainers of this project for assistance;
11 * the project provides a web site, mailing lists and IRC
12 * channels for your use.
14 * This program is free software, distributed under the terms of
15 * the GNU General Public License Version 2. See the LICENSE file
16 * at the top of the source tree.
19 /*! \file
21 * \brief Compile symbolic Asterisk Extension Logic into Asterisk extensions, version 2.
25 /*** MODULEINFO
26 <depend>res_ael_share</depend>
27 ***/
29 #include "asterisk.h"
31 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
33 #include <ctype.h>
34 #include <regex.h>
35 #include <sys/stat.h>
37 #include "asterisk/pbx.h"
38 #include "asterisk/config.h"
39 #include "asterisk/module.h"
40 #include "asterisk/logger.h"
41 #include "asterisk/cli.h"
42 #include "asterisk/app.h"
43 #include "asterisk/callerid.h"
44 #include "asterisk/hashtab.h"
45 #include "asterisk/ael_structs.h"
46 #include "asterisk/pval.h"
47 #ifdef AAL_ARGCHECK
48 #include "asterisk/argdesc.h"
49 #endif
51 /* these functions are in ../ast_expr2.fl */
53 #define DEBUG_READ (1 << 0)
54 #define DEBUG_TOKENS (1 << 1)
55 #define DEBUG_MACROS (1 << 2)
56 #define DEBUG_CONTEXTS (1 << 3)
58 static char *config = "extensions.ael";
59 static char *registrar = "pbx_ael";
60 static int pbx_load_module(void);
62 #ifndef AAL_ARGCHECK
63 /* for the time being, short circuit all the AAL related structures
64 without permanently removing the code; after/during the AAL
65 development, this code can be properly re-instated
68 #endif
70 #ifdef AAL_ARGCHECK
71 int option_matches_j( struct argdesc *should, pval *is, struct argapp *app);
72 int option_matches( struct argdesc *should, pval *is, struct argapp *app);
73 int ael_is_funcname(char *name);
74 #endif
76 int check_app_args(pval *appcall, pval *arglist, struct argapp *app);
77 void check_pval(pval *item, struct argapp *apps, int in_globals);
78 void check_pval_item(pval *item, struct argapp *apps, int in_globals);
79 void check_switch_expr(pval *item, struct argapp *apps);
80 void ast_expr_register_extra_error_info(char *errmsg);
81 void ast_expr_clear_extra_error_info(void);
82 struct pval *find_macro(char *name);
83 struct pval *find_context(char *name);
84 struct pval *find_context(char *name);
85 struct pval *find_macro(char *name);
86 struct ael_priority *new_prio(void);
87 struct ael_extension *new_exten(void);
88 void destroy_extensions(struct ael_extension *exten);
89 void set_priorities(struct ael_extension *exten);
90 void add_extensions(struct ael_extension *exten);
91 void ast_compile_ael2(struct ast_context **local_contexts, struct ast_hashtab *local_table, struct pval *root);
92 void destroy_pval(pval *item);
93 void destroy_pval_item(pval *item);
94 int is_float(char *arg );
95 int is_int(char *arg );
96 int is_empty(char *arg);
98 /* static void substitute_commas(char *str); */
100 static int aeldebug = 0;
102 /* interface stuff */
104 /* if all the below are static, who cares if they are present? */
106 static int pbx_load_module(void)
108 int errs=0, sem_err=0, sem_warn=0, sem_note=0;
109 char *rfilename;
110 struct ast_context *local_contexts=NULL, *con;
111 struct ast_hashtab *local_table=NULL;
113 struct pval *parse_tree;
115 ast_log(LOG_NOTICE, "Starting AEL load process.\n");
116 if (config[0] == '/')
117 rfilename = (char *)config;
118 else {
119 rfilename = alloca(strlen(config) + strlen(ast_config_AST_CONFIG_DIR) + 2);
120 sprintf(rfilename, "%s/%s", ast_config_AST_CONFIG_DIR, config);
122 if (access(rfilename,R_OK) != 0) {
123 ast_log(LOG_NOTICE, "File %s not found; AEL declining load\n", rfilename);
124 return AST_MODULE_LOAD_DECLINE;
127 parse_tree = ael2_parse(rfilename, &errs);
128 ast_log(LOG_NOTICE, "AEL load process: parsed config file name '%s'.\n", rfilename);
129 ael2_semantic_check(parse_tree, &sem_err, &sem_warn, &sem_note);
130 if (errs == 0 && sem_err == 0) {
131 ast_log(LOG_NOTICE, "AEL load process: checked config file name '%s'.\n", rfilename);
132 local_table = ast_hashtab_create(11, ast_hashtab_compare_contexts, ast_hashtab_resize_java, ast_hashtab_newsize_java, ast_hashtab_hash_contexts, 0);
133 ast_compile_ael2(&local_contexts, local_table, parse_tree);
134 ast_log(LOG_NOTICE, "AEL load process: compiled config file name '%s'.\n", rfilename);
136 ast_merge_contexts_and_delete(&local_contexts, local_table, registrar);
137 local_table = NULL; /* it's the dialplan global now */
138 local_contexts = NULL;
139 ast_log(LOG_NOTICE, "AEL load process: merged config file name '%s'.\n", rfilename);
140 for (con = ast_walk_contexts(NULL); con; con = ast_walk_contexts(con))
141 ast_context_verify_includes(con);
142 ast_log(LOG_NOTICE, "AEL load process: verified config file name '%s'.\n", rfilename);
143 } else {
144 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);
145 destroy_pval(parse_tree); /* free up the memory */
146 return AST_MODULE_LOAD_DECLINE;
148 destroy_pval(parse_tree); /* free up the memory */
150 return AST_MODULE_LOAD_SUCCESS;
153 /* CLI interface */
154 static char *handle_cli_ael_debug_multiple_deprecated(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
156 switch (cmd) {
157 case CLI_INIT:
158 e->command = "ael debug [read|tokens|macros|contexts|off]";
159 e->usage =
160 "Usage: ael debug [read|tokens|macros|contexts|off]\n"
161 " Enable AEL read, token, macro, or context debugging,\n"
162 " or disable all AEL debugging messages. Note: this\n"
163 " currently does nothing.\n";
164 return NULL;
165 case CLI_GENERATE:
166 return NULL;
169 if (a->argc != 3)
170 return CLI_SHOWUSAGE;
172 if (!strcasecmp(a->argv[2], "read"))
173 aeldebug |= DEBUG_READ;
174 else if (!strcasecmp(a->argv[2], "tokens"))
175 aeldebug |= DEBUG_TOKENS;
176 else if (!strcasecmp(a->argv[2], "macros"))
177 aeldebug |= DEBUG_MACROS;
178 else if (!strcasecmp(a->argv[2], "contexts"))
179 aeldebug |= DEBUG_CONTEXTS;
180 else if (!strcasecmp(a->argv[2], "off"))
181 aeldebug = 0;
182 else
183 return CLI_SHOWUSAGE;
185 return CLI_SUCCESS;
188 static char *handle_cli_ael_set_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
190 switch (cmd) {
191 case CLI_INIT:
192 e->command = "ael set debug {read|tokens|macros|contexts|off}";
193 e->usage =
194 "Usage: ael debug {read|tokens|macros|contexts|off}\n"
195 " Enable AEL read, token, macro, or context debugging,\n"
196 " or disable all AEL debugging messages. Note: this\n"
197 " currently does nothing.\n";
198 return NULL;
199 case CLI_GENERATE:
200 return NULL;
203 if (a->argc != e->args)
204 return CLI_SHOWUSAGE;
206 if (!strcasecmp(a->argv[3], "read"))
207 aeldebug |= DEBUG_READ;
208 else if (!strcasecmp(a->argv[3], "tokens"))
209 aeldebug |= DEBUG_TOKENS;
210 else if (!strcasecmp(a->argv[3], "macros"))
211 aeldebug |= DEBUG_MACROS;
212 else if (!strcasecmp(a->argv[3], "contexts"))
213 aeldebug |= DEBUG_CONTEXTS;
214 else if (!strcasecmp(a->argv[3], "off"))
215 aeldebug = 0;
216 else
217 return CLI_SHOWUSAGE;
219 return CLI_SUCCESS;
222 static char *handle_cli_ael_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
224 switch (cmd) {
225 case CLI_INIT:
226 e->command = "ael reload";
227 e->usage =
228 "Usage: ael reload\n"
229 " Reloads AEL configuration.\n";
230 return NULL;
231 case CLI_GENERATE:
232 return NULL;
235 if (a->argc != 2)
236 return CLI_SHOWUSAGE;
238 return (pbx_load_module() ? CLI_FAILURE : CLI_SUCCESS);
241 static struct ast_cli_entry cli_ael_debug_multiple_deprecated = AST_CLI_DEFINE(handle_cli_ael_debug_multiple_deprecated, "Enable AEL debugging flags");
242 static struct ast_cli_entry cli_ael[] = {
243 AST_CLI_DEFINE(handle_cli_ael_reload, "Reload AEL configuration"),
244 AST_CLI_DEFINE(handle_cli_ael_set_debug, "Enable AEL debugging flags", .deprecate_cmd = &cli_ael_debug_multiple_deprecated)
247 static int unload_module(void)
249 ast_context_destroy(NULL, registrar);
250 ast_cli_unregister_multiple(cli_ael, sizeof(cli_ael) / sizeof(struct ast_cli_entry));
251 return 0;
254 static int load_module(void)
256 ast_cli_register_multiple(cli_ael, sizeof(cli_ael) / sizeof(struct ast_cli_entry));
257 return (pbx_load_module());
260 static int reload(void)
262 return pbx_load_module();
265 #ifdef STANDALONE_AEL
266 #define AST_MODULE "ael"
267 int ael_external_load_module(void);
268 int ael_external_load_module(void)
270 pbx_load_module();
271 return 1;
273 #endif
275 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Asterisk Extension Language Compiler",
276 .load = load_module,
277 .unload = unload_module,
278 .reload = reload,
281 #ifdef AAL_ARGCHECK
282 static char *ael_funclist[] =
284 "AGENT",
285 "ARRAY",
286 "BASE64_DECODE",
287 "BASE64_ENCODE",
288 "CALLERID",
289 "CDR",
290 "CHANNEL",
291 "CHECKSIPDOMAIN",
292 "CHECK_MD5",
293 "CURL",
294 "CUT",
295 "DB",
296 "DB_EXISTS",
297 "DUNDILOOKUP",
298 "ENUMLOOKUP",
299 "ENV",
300 "EVAL",
301 "EXISTS",
302 "FIELDQTY",
303 "FILTER",
304 "GROUP",
305 "GROUP_COUNT",
306 "GROUP_LIST",
307 "GROUP_MATCH_COUNT",
308 "IAXPEER",
309 "IF",
310 "IFTIME",
311 "ISNULL",
312 "KEYPADHASH",
313 "LANGUAGE",
314 "LEN",
315 "MATH",
316 "MD5",
317 "MUSICCLASS",
318 "QUEUEAGENTCOUNT",
319 "QUEUE_MEMBER_COUNT",
320 "QUEUE_MEMBER_LIST",
321 "QUOTE",
322 "RAND",
323 "REGEX",
324 "SET",
325 "SHA1",
326 "SIPCHANINFO",
327 "SIPPEER",
328 "SIP_HEADER",
329 "SORT",
330 "STAT",
331 "STRFTIME",
332 "STRPTIME",
333 "TIMEOUT",
334 "TXTCIDNAME",
335 "URIDECODE",
336 "URIENCODE",
337 "VMCOUNT"
341 int ael_is_funcname(char *name)
343 int s,t;
344 t = sizeof(ael_funclist)/sizeof(char*);
345 s = 0;
346 while ((s < t) && strcasecmp(name, ael_funclist[s]))
347 s++;
348 if ( s < t )
349 return 1;
350 else
351 return 0;
353 #endif