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>
31 ASTERISK_FILE_VERSION(__FILE__
, "$Revision$")
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"
48 #include "asterisk/argdesc.h"
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);
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
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
);
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;
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
;
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
);
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
;
154 static char *handle_cli_ael_debug_multiple_deprecated(struct ast_cli_entry
*e
, int cmd
, struct ast_cli_args
*a
)
158 e
->command
= "ael debug [read|tokens|macros|contexts|off]";
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";
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"))
183 return CLI_SHOWUSAGE
;
188 static char *handle_cli_ael_set_debug(struct ast_cli_entry
*e
, int cmd
, struct ast_cli_args
*a
)
192 e
->command
= "ael set debug {read|tokens|macros|contexts|off}";
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";
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"))
217 return CLI_SHOWUSAGE
;
222 static char *handle_cli_ael_reload(struct ast_cli_entry
*e
, int cmd
, struct ast_cli_args
*a
)
226 e
->command
= "ael reload";
228 "Usage: ael reload\n"
229 " Reloads AEL configuration.\n";
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
));
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)
275 AST_MODULE_INFO(ASTERISK_GPL_KEY
, AST_MODFLAG_DEFAULT
, "Asterisk Extension Language Compiler",
277 .unload
= unload_module
,
282 static char *ael_funclist
[] =
319 "QUEUE_MEMBER_COUNT",
341 int ael_is_funcname(char *name
)
344 t
= sizeof(ael_funclist
)/sizeof(char*);
346 while ((s
< t
) && strcasecmp(name
, ael_funclist
[s
]))