Automatically create new buddy upon reception of a presence stanza of
[asterisk/asterisk.git] / pbx / pbx_ael.c
1 /* 
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2006, Digium, Inc.
5  *
6  * Steve Murphy <murf@parsetree.com>
7  *
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.
13  *
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.
17  */
18
19 /*! \file
20  *
21  * \brief Compile symbolic Asterisk Extension Logic into Asterisk extensions, version 2.
22  * 
23  */
24
25 /*** MODULEINFO
26         <depend>res_ael_share</depend>
27  ***/
28
29 #include "asterisk.h"
30
31 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
32
33 #include <ctype.h>
34 #include <regex.h>
35 #include <sys/stat.h>
36
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/ael_structs.h"
45 #include "asterisk/pval.h"
46 #ifdef AAL_ARGCHECK
47 #include "asterisk/argdesc.h"
48 #endif
49
50 /* these functions are in ../ast_expr2.fl */
51
52 #define DEBUG_READ   (1 << 0)
53 #define DEBUG_TOKENS (1 << 1)
54 #define DEBUG_MACROS (1 << 2)
55 #define DEBUG_CONTEXTS (1 << 3)
56
57 static char *config = "extensions.ael";
58 static char *registrar = "pbx_ael";
59 static int pbx_load_module(void);
60
61 #ifndef AAL_ARGCHECK
62 /* for the time being, short circuit all the AAL related structures
63    without permanently removing the code; after/during the AAL 
64    development, this code can be properly re-instated 
65 */
66
67 #endif
68
69 #ifdef AAL_ARGCHECK
70 int option_matches_j( struct argdesc *should, pval *is, struct argapp *app);
71 int option_matches( struct argdesc *should, pval *is, struct argapp *app);
72 int ael_is_funcname(char *name);
73 #endif
74
75 int check_app_args(pval *appcall, pval *arglist, struct argapp *app);
76 void check_pval(pval *item, struct argapp *apps, int in_globals);
77 void check_pval_item(pval *item, struct argapp *apps, int in_globals);
78 void check_switch_expr(pval *item, struct argapp *apps);
79 void ast_expr_register_extra_error_info(char *errmsg);
80 void ast_expr_clear_extra_error_info(void);
81 struct pval *find_macro(char *name);
82 struct pval *find_context(char *name);
83 struct pval *find_context(char *name);
84 struct pval *find_macro(char *name);
85 struct ael_priority *new_prio(void);
86 struct ael_extension *new_exten(void);
87 void linkprio(struct ael_extension *exten, struct ael_priority *prio);
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 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);
97
98 /* static void substitute_commas(char *str); */
99
100 static int aeldebug = 0;
101
102 /* interface stuff */
103
104 /* if all the below are static, who cares if they are present? */
105
106 static int pbx_load_module(void)
107 {
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 pval *parse_tree;
112
113         ast_log(LOG_NOTICE, "Starting AEL load process.\n");
114         if (config[0] == '/')
115                 rfilename = (char *)config;
116         else {
117                 rfilename = alloca(strlen(config) + strlen(ast_config_AST_CONFIG_DIR) + 2);
118                 sprintf(rfilename, "%s/%s", ast_config_AST_CONFIG_DIR, config);
119         }
120         if (access(rfilename,R_OK) != 0) {
121                 ast_log(LOG_NOTICE, "File %s not found; AEL declining load\n", rfilename);
122                 return AST_MODULE_LOAD_DECLINE;
123         }
124         
125         parse_tree = ael2_parse(rfilename, &errs);
126         ast_log(LOG_NOTICE, "AEL load process: parsed config file name '%s'.\n", rfilename);
127         ael2_semantic_check(parse_tree, &sem_err, &sem_warn, &sem_note);
128         if (errs == 0 && sem_err == 0) {
129                 ast_log(LOG_NOTICE, "AEL load process: checked config file name '%s'.\n", rfilename);
130                 ast_compile_ael2(&local_contexts, parse_tree);
131                 ast_log(LOG_NOTICE, "AEL load process: compiled config file name '%s'.\n", rfilename);
132                 
133                 ast_merge_contexts_and_delete(&local_contexts, registrar);
134                 ast_log(LOG_NOTICE, "AEL load process: merged config file name '%s'.\n", rfilename);
135                 for (con = ast_walk_contexts(NULL); con; con = ast_walk_contexts(con))
136                         ast_context_verify_includes(con);
137                 ast_log(LOG_NOTICE, "AEL load process: verified config file name '%s'.\n", rfilename);
138         } else {
139                 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);
140                 destroy_pval(parse_tree); /* free up the memory */
141                 return AST_MODULE_LOAD_DECLINE;
142         }
143         destroy_pval(parse_tree); /* free up the memory */
144         
145         return AST_MODULE_LOAD_SUCCESS;
146 }
147
148 /* CLI interface */
149 static char *handle_cli_ael_debug_multiple_deprecated(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
150 {
151         switch (cmd) {
152         case CLI_INIT:
153                 e->command = "ael debug [read|tokens|macros|contexts|off]";
154                 e->usage =
155                         "Usage: ael debug [read|tokens|macros|contexts|off]\n"
156                         "       Enable AEL read, token, macro, or context debugging,\n"
157                         "       or disable all AEL debugging messages.  Note: this\n"
158                         "       currently does nothing.\n";
159                 return NULL;
160         case CLI_GENERATE:
161                 return NULL;
162         }
163
164         if (a->argc != 3)
165                 return CLI_SHOWUSAGE;
166
167         if (!strcasecmp(a->argv[2], "read"))
168                 aeldebug |= DEBUG_READ;
169         else if (!strcasecmp(a->argv[2], "tokens"))
170                 aeldebug |= DEBUG_TOKENS;
171         else if (!strcasecmp(a->argv[2], "macros"))
172                 aeldebug |= DEBUG_MACROS;
173         else if (!strcasecmp(a->argv[2], "contexts"))
174                 aeldebug |= DEBUG_CONTEXTS;
175         else if (!strcasecmp(a->argv[2], "off"))
176                 aeldebug = 0;
177         else
178                 return CLI_SHOWUSAGE;
179
180         return CLI_SUCCESS;
181 }
182
183 static char *handle_cli_ael_set_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
184 {
185         switch (cmd) {
186         case CLI_INIT:
187                 e->command = "ael set debug {read|tokens|macros|contexts|off}";
188                 e->usage =
189                         "Usage: ael debug {read|tokens|macros|contexts|off}\n"
190                         "       Enable AEL read, token, macro, or context debugging,\n"
191                         "       or disable all AEL debugging messages.  Note: this\n"
192                         "       currently does nothing.\n";
193                 return NULL;
194         case CLI_GENERATE:
195                 return NULL;
196         }
197
198         if (a->argc != e->args)
199                 return CLI_SHOWUSAGE;
200
201         if (!strcasecmp(a->argv[3], "read"))
202                 aeldebug |= DEBUG_READ;
203         else if (!strcasecmp(a->argv[3], "tokens"))
204                 aeldebug |= DEBUG_TOKENS;
205         else if (!strcasecmp(a->argv[3], "macros"))
206                 aeldebug |= DEBUG_MACROS;
207         else if (!strcasecmp(a->argv[3], "contexts"))
208                 aeldebug |= DEBUG_CONTEXTS;
209         else if (!strcasecmp(a->argv[3], "off"))
210                 aeldebug = 0;
211         else
212                 return CLI_SHOWUSAGE;
213
214         return CLI_SUCCESS;
215 }
216
217 static char *handle_cli_ael_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
218 {
219         switch (cmd) {
220         case CLI_INIT:
221                 e->command = "ael reload";
222                 e->usage =
223                         "Usage: ael reload\n"
224                         "       Reloads AEL configuration.\n";
225                 return NULL;
226         case CLI_GENERATE:
227                 return NULL;
228         }
229
230         if (a->argc != 2)
231                 return CLI_SHOWUSAGE;
232
233         return (pbx_load_module() ? CLI_FAILURE : CLI_SUCCESS);
234 }
235
236 static struct ast_cli_entry cli_ael_debug_multiple_deprecated = AST_CLI_DEFINE(handle_cli_ael_debug_multiple_deprecated, "Enable AEL debugging flags");
237 static struct ast_cli_entry cli_ael[] = {
238         AST_CLI_DEFINE(handle_cli_ael_reload,    "Reload AEL configuration"),
239         AST_CLI_DEFINE(handle_cli_ael_set_debug, "Enable AEL debugging flags", .deprecate_cmd = &cli_ael_debug_multiple_deprecated)
240 };
241
242 static int unload_module(void)
243 {
244         ast_context_destroy(NULL, registrar);
245         ast_cli_unregister_multiple(cli_ael, sizeof(cli_ael) / sizeof(struct ast_cli_entry));
246         return 0;
247 }
248
249 static int load_module(void)
250 {
251         ast_cli_register_multiple(cli_ael, sizeof(cli_ael) / sizeof(struct ast_cli_entry));
252         return (pbx_load_module());
253 }
254
255 static int reload(void)
256 {
257         return pbx_load_module();
258 }
259
260 #ifdef STANDALONE_AEL
261 #define AST_MODULE "ael"
262 int ael_external_load_module(void);
263 int ael_external_load_module(void)
264 {
265         pbx_load_module();
266         return 1;
267 }
268 #endif
269
270 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Asterisk Extension Language Compiler",
271                 .load = load_module,
272                 .unload = unload_module,
273                 .reload = reload,
274                );
275
276 #ifdef AAL_ARGCHECK
277 static char *ael_funclist[] =
278 {
279         "AGENT",
280         "ARRAY",
281         "BASE64_DECODE",
282         "BASE64_ENCODE",
283         "CALLERID",
284         "CDR",
285         "CHANNEL",
286         "CHECKSIPDOMAIN",
287         "CHECK_MD5",
288         "CURL",
289         "CUT",
290         "DB",
291         "DB_EXISTS",
292         "DUNDILOOKUP",
293         "ENUMLOOKUP",
294         "ENV",
295         "EVAL",
296         "EXISTS",
297         "FIELDQTY",
298         "FILTER",
299         "GROUP",
300         "GROUP_COUNT",
301         "GROUP_LIST",
302         "GROUP_MATCH_COUNT",
303         "IAXPEER",
304         "IF",
305         "IFTIME",
306         "ISNULL",
307         "KEYPADHASH",
308         "LANGUAGE",
309         "LEN",
310         "MATH",
311         "MD5",
312         "MUSICCLASS",
313         "QUEUEAGENTCOUNT",
314         "QUEUE_MEMBER_COUNT",
315         "QUEUE_MEMBER_LIST",
316         "QUOTE",
317         "RAND",
318         "REGEX",
319         "SET",
320         "SHA1",
321         "SIPCHANINFO",
322         "SIPPEER",
323         "SIP_HEADER",
324         "SORT",
325         "STAT",
326         "STRFTIME",
327         "STRPTIME",
328         "TIMEOUT",
329         "TXTCIDNAME",
330         "URIDECODE",
331         "URIENCODE",
332         "VMCOUNT"
333 };
334
335
336 int ael_is_funcname(char *name)
337 {
338         int s,t;
339         t = sizeof(ael_funclist)/sizeof(char*);
340         s = 0;
341         while ((s < t) && strcasecmp(name, ael_funclist[s])) 
342                 s++;
343         if ( s < t )
344                 return 1;
345         else
346                 return 0;
347 }
348 #endif