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.
21 * \brief Compile symbolic Asterisk Extension Logic into Asterisk extensions, version 2.
26 <depend>res_ael_share</depend>
27 <support_level>extended</support_level>
32 #if !defined(STANDALONE)
33 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
41 #ifdef HAVE_MTX_PROFILE
42 static int mtx_prof = -1; /* helps the standalone compile with the mtx_prof flag on */
45 #include "asterisk/pbx.h"
46 #include "asterisk/config.h"
47 #include "asterisk/module.h"
48 #include "asterisk/logger.h"
49 #include "asterisk/cli.h"
50 #include "asterisk/app.h"
51 #include "asterisk/callerid.h"
52 #include "asterisk/hashtab.h"
53 #include "asterisk/ael_structs.h"
54 #include "asterisk/pval.h"
56 #include "asterisk/argdesc.h"
60 <application name="AELSub" language="en_US">
62 Launch subroutine built with AEL
65 <parameter name="routine" required="true">
66 <para>Named subroutine to execute.</para>
68 <parameter name="args" required="false" />
71 <para>Execute the named subroutine, defined in AEL, from another dialplan
72 language, such as extensions.conf, Realtime extensions, or Lua.</para>
73 <para>The purpose of this application is to provide a sane entry point into
74 AEL subroutines, the implementation of which may change from time to time.</para>
79 /* these functions are in ../ast_expr2.fl */
81 #define DEBUG_READ (1 << 0)
82 #define DEBUG_TOKENS (1 << 1)
83 #define DEBUG_MACROS (1 << 2)
84 #define DEBUG_CONTEXTS (1 << 3)
86 static char *config = "extensions.ael";
87 static char *registrar = "pbx_ael";
88 static int pbx_load_module(void);
91 /* for the time being, short circuit all the AAL related structures
92 without permanently removing the code; after/during the AAL
93 development, this code can be properly re-instated
99 int option_matches_j( struct argdesc *should, pval *is, struct argapp *app);
100 int option_matches( struct argdesc *should, pval *is, struct argapp *app);
101 int ael_is_funcname(char *name);
104 int check_app_args(pval *appcall, pval *arglist, struct argapp *app);
105 void check_pval(pval *item, struct argapp *apps, int in_globals);
106 void check_pval_item(pval *item, struct argapp *apps, int in_globals);
107 void check_switch_expr(pval *item, struct argapp *apps);
108 void ast_expr_register_extra_error_info(char *errmsg);
109 void ast_expr_clear_extra_error_info(void);
110 struct pval *find_macro(char *name);
111 struct pval *find_context(char *name);
112 struct pval *find_context(char *name);
113 struct pval *find_macro(char *name);
114 struct ael_priority *new_prio(void);
115 struct ael_extension *new_exten(void);
116 void destroy_extensions(struct ael_extension *exten);
117 void set_priorities(struct ael_extension *exten);
118 void add_extensions(struct ael_extension *exten);
119 int ast_compile_ael2(struct ast_context **local_contexts, struct ast_hashtab *local_table, struct pval *root);
120 void destroy_pval(pval *item);
121 void destroy_pval_item(pval *item);
122 int is_float(char *arg );
123 int is_int(char *arg );
124 int is_empty(char *arg);
126 /* static void substitute_commas(char *str); */
128 static int aeldebug = 0;
130 /* interface stuff */
133 static char *aelsub = "AELSub";
135 static int aelsub_exec(struct ast_channel *chan, const char *vdata)
137 char buf[256], *data = ast_strdupa(vdata);
138 struct ast_app *gosub = pbx_findapp("Gosub");
139 AST_DECLARE_APP_ARGS(args,
145 AST_STANDARD_RAW_ARGS(args, data);
146 snprintf(buf, sizeof(buf), "%s,~~s~~,1(%s)", args.name, args.args);
147 return pbx_exec(chan, gosub, buf);
153 /* if all the below are static, who cares if they are present? */
155 static int pbx_load_module(void)
157 int errs=0, sem_err=0, sem_warn=0, sem_note=0;
159 struct ast_context *local_contexts=NULL, *con;
160 struct ast_hashtab *local_table=NULL;
162 struct pval *parse_tree;
164 ast_debug(1, "Starting AEL load process.\n");
165 if (config[0] == '/')
166 rfilename = (char *)config;
168 rfilename = ast_alloca(strlen(config) + strlen(ast_config_AST_CONFIG_DIR) + 2);
169 sprintf(rfilename, "%s/%s", ast_config_AST_CONFIG_DIR, config);
171 if (access(rfilename,R_OK) != 0) {
172 ast_log(LOG_NOTICE, "File %s not found; AEL declining load\n", rfilename);
173 return AST_MODULE_LOAD_DECLINE;
176 parse_tree = ael2_parse(rfilename, &errs);
177 ast_debug(1, "AEL load process: parsed config file name '%s'.\n", rfilename);
178 ael2_semantic_check(parse_tree, &sem_err, &sem_warn, &sem_note);
179 if (errs == 0 && sem_err == 0) {
180 ast_debug(1, "AEL load process: checked config file name '%s'.\n", rfilename);
181 local_table = ast_hashtab_create(11, ast_hashtab_compare_contexts, ast_hashtab_resize_java, ast_hashtab_newsize_java, ast_hashtab_hash_contexts, 0);
182 if (ast_compile_ael2(&local_contexts, local_table, parse_tree)) {
183 ast_log(LOG_ERROR, "AEL compile failed! Aborting.\n");
184 destroy_pval(parse_tree); /* free up the memory */
185 return AST_MODULE_LOAD_DECLINE;
187 ast_debug(1, "AEL load process: compiled config file name '%s'.\n", rfilename);
189 ast_merge_contexts_and_delete(&local_contexts, local_table, registrar);
190 local_table = NULL; /* it's the dialplan global now */
191 local_contexts = NULL;
192 ast_debug(1, "AEL load process: merged config file name '%s'.\n", rfilename);
193 for (con = ast_walk_contexts(NULL); con; con = ast_walk_contexts(con))
194 ast_context_verify_includes(con);
195 ast_debug(1, "AEL load process: verified config file name '%s'.\n", rfilename);
197 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);
198 destroy_pval(parse_tree); /* free up the memory */
199 return AST_MODULE_LOAD_DECLINE;
201 destroy_pval(parse_tree); /* free up the memory */
203 return AST_MODULE_LOAD_SUCCESS;
207 static char *handle_cli_ael_set_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
211 e->command = "ael set debug {read|tokens|macros|contexts|off}";
213 "Usage: ael set debug {read|tokens|macros|contexts|off}\n"
214 " Enable AEL read, token, macro, or context debugging,\n"
215 " or disable all AEL debugging messages. Note: this\n"
216 " currently does nothing.\n";
222 if (a->argc != e->args)
223 return CLI_SHOWUSAGE;
225 if (!strcasecmp(a->argv[3], "read"))
226 aeldebug |= DEBUG_READ;
227 else if (!strcasecmp(a->argv[3], "tokens"))
228 aeldebug |= DEBUG_TOKENS;
229 else if (!strcasecmp(a->argv[3], "macros"))
230 aeldebug |= DEBUG_MACROS;
231 else if (!strcasecmp(a->argv[3], "contexts"))
232 aeldebug |= DEBUG_CONTEXTS;
233 else if (!strcasecmp(a->argv[3], "off"))
236 return CLI_SHOWUSAGE;
241 static char *handle_cli_ael_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
245 e->command = "ael reload";
247 "Usage: ael reload\n"
248 " Reloads AEL configuration.\n";
255 return CLI_SHOWUSAGE;
257 return (pbx_load_module() ? CLI_FAILURE : CLI_SUCCESS);
260 static struct ast_cli_entry cli_ael[] = {
261 AST_CLI_DEFINE(handle_cli_ael_reload, "Reload AEL configuration"),
262 AST_CLI_DEFINE(handle_cli_ael_set_debug, "Enable AEL debugging flags")
265 static int unload_module(void)
267 ast_context_destroy(NULL, registrar);
268 ast_cli_unregister_multiple(cli_ael, ARRAY_LEN(cli_ael));
270 ast_unregister_application(aelsub);
275 static int load_module(void)
277 ast_cli_register_multiple(cli_ael, ARRAY_LEN(cli_ael));
279 ast_register_application_xml(aelsub, aelsub_exec);
281 return (pbx_load_module());
284 static int reload(void)
286 return pbx_load_module();
290 #define AST_MODULE "ael"
291 int ael_external_load_module(void);
292 int ael_external_load_module(void)
299 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Asterisk Extension Language Compiler",
301 .unload = unload_module,
306 static const char * const ael_funclist[] =
343 "QUEUE_MEMBER_COUNT",
365 int ael_is_funcname(char *name)
368 t = sizeof(ael_funclist)/sizeof(char*);
370 while ((s < t) && strcasecmp(name, ael_funclist[s]))