Asterisk - The Open Source Telephony Project GIT-master-754dea3
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros Modules Pages
pbx_ael.c
Go to the documentation of this file.
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 <support_level>extended</support_level>
28 ***/
29
30#include "asterisk.h"
31
32#include <ctype.h>
33#include <regex.h>
34#include <sys/stat.h>
35
36#include "asterisk/pbx.h"
37#include "asterisk/config.h"
38#include "asterisk/module.h"
39#include "asterisk/logger.h"
40#include "asterisk/cli.h"
41#include "asterisk/app.h"
42#include "asterisk/callerid.h"
43#include "asterisk/hashtab.h"
45#include "asterisk/pval.h"
46#ifdef AAL_ARGCHECK
47#include "asterisk/argdesc.h"
48#endif
49
50/*** DOCUMENTATION
51 <application name="AELSub" language="en_US">
52 <since>
53 <version>10.0.0</version>
54 </since>
55 <synopsis>
56 Launch subroutine built with AEL
57 </synopsis>
58 <syntax>
59 <parameter name="routine" required="true">
60 <para>Named subroutine to execute.</para>
61 </parameter>
62 <parameter name="args" required="false" />
63 </syntax>
64 <description>
65 <para>Execute the named subroutine, defined in AEL, from another dialplan
66 language, such as extensions.conf, Realtime extensions, or Lua.</para>
67 <para>The purpose of this application is to provide a sane entry point into
68 AEL subroutines, the implementation of which may change from time to time.</para>
69 </description>
70 </application>
71 ***/
72
73/* these functions are in ../ast_expr2.fl */
74
75#define DEBUG_READ (1 << 0)
76#define DEBUG_TOKENS (1 << 1)
77#define DEBUG_MACROS (1 << 2)
78#define DEBUG_CONTEXTS (1 << 3)
79
80static char *config = "extensions.ael";
81static char *registrar = "pbx_ael";
82static int pbx_load_module(void);
83
84#ifndef AAL_ARGCHECK
85/* for the time being, short circuit all the AAL related structures
86 without permanently removing the code; after/during the AAL
87 development, this code can be properly re-instated
88*/
89
90#endif
91
92#ifdef AAL_ARGCHECK
93int option_matches_j( struct argdesc *should, pval *is, struct argapp *app);
94int option_matches( struct argdesc *should, pval *is, struct argapp *app);
95int ael_is_funcname(char *name);
96#endif
97
98int check_app_args(pval *appcall, pval *arglist, struct argapp *app);
99void check_pval(pval *item, struct argapp *apps, int in_globals);
100void check_pval_item(pval *item, struct argapp *apps, int in_globals);
101void check_switch_expr(pval *item, struct argapp *apps);
102void ast_expr_register_extra_error_info(char *errmsg);
104struct pval *find_context(char *name);
105struct pval *find_context(char *name);
106struct ael_priority *new_prio(void);
107struct ael_extension *new_exten(void);
108void destroy_extensions(struct ael_extension *exten);
109void set_priorities(struct ael_extension *exten);
110void add_extensions(struct ael_extension *exten);
111int ast_compile_ael2(struct ast_context **local_contexts, struct ast_hashtab *local_table, struct pval *root);
112void destroy_pval(pval *item);
114int is_float(char *arg );
115int is_int(char *arg );
116int is_empty(char *arg);
117
118/* static void substitute_commas(char *str); */
119
120static int aeldebug = 0;
121
122/* interface stuff */
123
124#ifndef STANDALONE
125static char *aelsub = "AELSub";
126
127static int aelsub_exec(struct ast_channel *chan, const char *vdata)
128{
129 char buf[256], *data = ast_strdupa(vdata);
130 struct ast_app *gosub = pbx_findapp("Gosub");
134 );
135
136 if (gosub) {
138 snprintf(buf, sizeof(buf), "%s,~~s~~,1(%s)", args.name, args.args);
139 return pbx_exec(chan, gosub, buf);
140 }
141 return -1;
142}
143#endif
144
145/* if all the below are static, who cares if they are present? */
146
147static int pbx_load_module(void)
148{
149 int errs=0, sem_err=0, sem_warn=0, sem_note=0;
150 char *rfilename;
151 struct ast_context *local_contexts=NULL, *con;
153
154 struct pval *parse_tree;
155
156 ast_debug(1, "Starting AEL load process.\n");
157 if (config[0] == '/')
158 rfilename = (char *)config;
159 else {
160 rfilename = ast_alloca(strlen(config) + strlen(ast_config_AST_CONFIG_DIR) + 2);
161 sprintf(rfilename, "%s/%s", ast_config_AST_CONFIG_DIR, config);
162 }
163 if (access(rfilename,R_OK) != 0) {
164 ast_log(LOG_NOTICE, "File %s not found; AEL declining load\n", rfilename);
166 }
167
168 parse_tree = ael2_parse(rfilename, &errs);
169 ast_debug(1, "AEL load process: parsed config file name '%s'.\n", rfilename);
170 ael2_semantic_check(parse_tree, &sem_err, &sem_warn, &sem_note);
171 if (errs == 0 && sem_err == 0) {
172 ast_debug(1, "AEL load process: checked config file name '%s'.\n", rfilename);
174 if (ast_compile_ael2(&local_contexts, local_table, parse_tree)) {
175 ast_log(LOG_ERROR, "AEL compile failed! Aborting.\n");
176 destroy_pval(parse_tree); /* free up the memory */
178 }
179 ast_debug(1, "AEL load process: compiled config file name '%s'.\n", rfilename);
180
182 local_table = NULL; /* it's the dialplan global now */
184 ast_debug(1, "AEL load process: merged config file name '%s'.\n", rfilename);
185 for (con = ast_walk_contexts(NULL); con; con = ast_walk_contexts(con))
187 ast_debug(1, "AEL load process: verified config file name '%s'.\n", rfilename);
188 } else {
189 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);
190 destroy_pval(parse_tree); /* free up the memory */
192 }
193 destroy_pval(parse_tree); /* free up the memory */
194
196}
197
198/* CLI interface */
199static char *handle_cli_ael_set_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
200{
201 switch (cmd) {
202 case CLI_INIT:
203 e->command = "ael set debug {read|tokens|contexts|off}";
204 e->usage =
205 "Usage: ael set debug {read|tokens|contexts|off}\n"
206 " Enable AEL read, token, or context debugging,\n"
207 " or disable all AEL debugging messages. Note: this\n"
208 " currently does nothing.\n";
209 return NULL;
210 case CLI_GENERATE:
211 return NULL;
212 }
213
214 if (a->argc != e->args)
215 return CLI_SHOWUSAGE;
216
217 if (!strcasecmp(a->argv[3], "read"))
219 else if (!strcasecmp(a->argv[3], "tokens"))
221 else if (!strcasecmp(a->argv[3], "contexts"))
223 else if (!strcasecmp(a->argv[3], "off"))
224 aeldebug = 0;
225 else
226 return CLI_SHOWUSAGE;
227
228 return CLI_SUCCESS;
229}
230
231static char *handle_cli_ael_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
232{
233 switch (cmd) {
234 case CLI_INIT:
235 e->command = "ael reload";
236 e->usage =
237 "Usage: ael reload\n"
238 " Reloads AEL configuration.\n";
239 return NULL;
240 case CLI_GENERATE:
241 return NULL;
242 }
243
244 if (a->argc != 2)
245 return CLI_SHOWUSAGE;
246
247#ifndef STANDALONE
248 /* Lock-Protected reload. It is VERY BAD to have simultaneous ael load_module() executing at the same time */
250#else
251 /* Lock-Protected reload not needed (and not available) when running standalone (Example: via aelparse cli tool). No reload contention is possible */
253#endif
254}
255
256static struct ast_cli_entry cli_ael[] = {
257 AST_CLI_DEFINE(handle_cli_ael_reload, "Reload AEL configuration"),
258 AST_CLI_DEFINE(handle_cli_ael_set_debug, "Enable AEL debugging flags")
259};
260
261static int unload_module(void)
262{
265#ifndef STANDALONE
267#endif
268 return 0;
269}
270
271static int load_module(void)
272{
273 int pbx_load_res = AST_MODULE_LOAD_SUCCESS;
274
276#ifndef STANDALONE
278#endif
279 pbx_load_res = pbx_load_module();
280 if (AST_MODULE_LOAD_SUCCESS != pbx_load_res) {
281#ifndef STANDALONE
283#endif
285 }
286
287 return pbx_load_res;
288}
289
290static int reload(void)
291{
292 /* Lock-Protected reload not needed because we're already being called from ast_module_reload() */
293 return pbx_load_module();
294}
295
296#ifdef STANDALONE
297#define AST_MODULE "ael"
300{
302 return 1;
303}
304#endif
305
306AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Asterisk Extension Language Compiler",
307 .support_level = AST_MODULE_SUPPORT_EXTENDED,
308 .load = load_module,
309 .unload = unload_module,
310 .reload = reload,
311 .requires = "res_ael_share",
313
314#ifdef AAL_ARGCHECK
315static const char * const ael_funclist[] =
316{
317 "AGENT",
318 "ARRAY",
319 "BASE64_DECODE",
320 "BASE64_ENCODE",
321 "CALLERID",
322 "CDR",
323 "CHANNEL",
324 "CHECKSIPDOMAIN",
325 "CHECK_MD5",
326 "CURL",
327 "CUT",
328 "DB",
329 "DB_EXISTS",
330 "DUNDILOOKUP",
331 "ENUMLOOKUP",
332 "ENV",
333 "EVAL",
334 "EXISTS",
335 "FIELDQTY",
336 "FILTER",
337 "GROUP",
338 "GROUP_COUNT",
339 "GROUP_LIST",
340 "GROUP_MATCH_COUNT",
341 "IAXPEER",
342 "IF",
343 "IFTIME",
344 "ISNULL",
345 "KEYPADHASH",
346 "LANGUAGE",
347 "LEN",
348 "MATH",
349 "MD5",
350 "MUSICCLASS",
351 "QUEUEAGENTCOUNT",
352 "QUEUE_MEMBER_COUNT",
353 "QUEUE_MEMBER_LIST",
354 "QUOTE",
355 "RAND",
356 "REGEX",
357 "SET",
358 "SHA1",
359 "SIPCHANINFO",
360 "SIPPEER",
361 "SIP_HEADER",
362 "SORT",
363 "STAT",
364 "STRFTIME",
365 "STRPTIME",
366 "TIMEOUT",
367 "TXTCIDNAME",
368 "URIDECODE",
369 "URIENCODE",
370 "VMCOUNT"
371};
372
373
374int ael_is_funcname(char *name)
375{
376 int s,t;
377 t = sizeof(ael_funclist)/sizeof(char*);
378 s = 0;
379 while ((s < t) && strcasecmp(name, ael_funclist[s]))
380 s++;
381 if ( s < t )
382 return 1;
383 else
384 return 0;
385}
386#endif
int ael_external_load_module(void)
Structures for AEL - the Asterisk extension language.
struct pval * ael2_parse(char *fname, int *errs)
Definition: ael_lex.c:3344
void ael2_semantic_check(pval *item, int *errs, int *warns, int *notes)
Definition: pval.c:2885
static const char app[]
Definition: app_adsiprog.c:56
Asterisk main include file. File version handling, generic pbx functions.
#define ast_alloca(size)
call __builtin_alloca to ensure we get gcc builtin semantics
Definition: astmm.h:288
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:298
#define ast_log
Definition: astobj2.c:42
CallerID (and other GR30) management and generation Includes code and algorithms from the Zapata libr...
Standard Command Line Interface.
#define CLI_SHOWUSAGE
Definition: cli.h:45
#define CLI_SUCCESS
Definition: cli.h:44
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
Definition: clicompat.c:30
#define AST_CLI_DEFINE(fn, txt,...)
Definition: cli.h:197
@ CLI_INIT
Definition: cli.h:152
@ CLI_GENERATE
Definition: cli.h:153
#define CLI_FAILURE
Definition: cli.h:46
#define ast_cli_register_multiple(e, len)
Register multiple commands.
Definition: cli.h:265
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
static const char name[]
Definition: format_mp3.c:68
Generic (perhaps overly so) hashtable implementation Hash Table support in Asterisk.
int ast_hashtab_newsize_java(struct ast_hashtab *tab)
Create a prime number roughly 2x the current table size.
Definition: hashtab.c:127
#define ast_hashtab_create(initial_buckets, compare, resize, newsize, hash, do_locking)
Create the hashtable list.
Definition: hashtab.h:254
int ast_hashtab_resize_java(struct ast_hashtab *tab)
Determines if a table resize should occur using the Java algorithm (if the table load factor is 75% o...
Definition: hashtab.c:84
Application convenience functions, designed to give consistent look and feel to Asterisk apps.
#define AST_APP_ARG(name)
Define an application argument.
#define AST_STANDARD_RAW_ARGS(args, parse)
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application's arguments.
Configuration File Parser.
Support for logging to various files, console and syslog Configuration in file logger....
#define ast_debug(level,...)
Log a DEBUG message.
#define LOG_ERROR
#define LOG_NOTICE
Asterisk module definitions.
@ AST_MODFLAG_DEFAULT
Definition: module.h:329
#define AST_MODULE_INFO(keystr, flags_to_set, desc, fields...)
Definition: module.h:557
@ AST_MODULE_SUPPORT_EXTENDED
Definition: module.h:122
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:46
@ AST_MODULE_RELOAD_SUCCESS
Definition: module.h:110
int ast_unregister_application(const char *app)
Unregister an application.
Definition: pbx_app.c:392
@ AST_MODULE_LOAD_SUCCESS
Definition: module.h:70
@ AST_MODULE_LOAD_DECLINE
Module has failed to load, may be in an inconsistent state.
Definition: module.h:78
enum ast_module_reload_result ast_module_reload(const char *name)
Reload asterisk modules.
Definition: loader.c:1730
#define ast_register_application_xml(app, execute)
Register an application using XML documentation.
Definition: module.h:640
const char * ast_config_AST_CONFIG_DIR
Definition: options.c:151
Core PBX routines and definitions.
struct ast_context * ast_walk_contexts(struct ast_context *con)
Definition: extconf.c:4024
int ast_hashtab_compare_contexts(const void *ah_a, const void *ah_b)
hashtable functions for contexts
Definition: ael_main.c:589
unsigned int ast_hashtab_hash_contexts(const void *obj)
Definition: ael_main.c:596
int pbx_exec(struct ast_channel *c, struct ast_app *app, const char *data)
Execute an application.
Definition: pbx_app.c:471
void ast_merge_contexts_and_delete(struct ast_context **extcontexts, struct ast_hashtab *exttable, const char *registrar)
Merge the temporary contexts into a global contexts list and delete from the global list the ones tha...
Definition: pbx.c:6441
void ast_context_destroy(struct ast_context *con, const char *registrar)
Destroy a context (matches the specified context or ANY context if NULL)
Definition: pbx.c:8236
int ast_context_verify_includes(struct ast_context *con)
Verifies includes in an ast_contect structure.
Definition: pbx.c:8747
struct ast_app * pbx_findapp(const char *app)
Look up an application.
Definition: ael_main.c:165
int ast_compile_ael2(struct ast_context **local_contexts, struct ast_hashtab *local_table, struct pval *root)
Definition: pval.c:4413
void check_switch_expr(pval *item, struct argapp *apps)
Definition: pval.c:2184
struct ael_priority * new_prio(void)
Definition: pval.c:2924
void destroy_pval_item(pval *item)
Definition: pval.c:4672
int is_empty(char *arg)
Definition: pval.c:1981
void check_pval_item(pval *item, struct argapp *apps, int in_globals)
Definition: pval.c:2357
#define DEBUG_CONTEXTS
Definition: pbx_ael.c:78
static char * aelsub
Definition: pbx_ael.c:125
#define DEBUG_TOKENS
Definition: pbx_ael.c:76
int check_app_args(pval *appcall, pval *arglist, struct argapp *app)
Definition: pval.c:2130
static int pbx_load_module(void)
Definition: pbx_ael.c:147
int is_float(char *arg)
Definition: pval.c:1963
static struct ast_cli_entry cli_ael[]
Definition: pbx_ael.c:256
void set_priorities(struct ael_extension *exten)
Definition: pval.c:4187
static char * config
Definition: pbx_ael.c:80
void ast_expr_clear_extra_error_info(void)
Definition: ast_expr2f.c:2469
static int aelsub_exec(struct ast_channel *chan, const char *vdata)
Definition: pbx_ael.c:127
void check_pval(pval *item, struct argapp *apps, int in_globals)
Definition: pval.c:2865
struct ael_extension * new_exten(void)
Definition: pval.c:2930
struct pval * find_context(char *name)
Definition: pval.c:1953
void destroy_pval(pval *item)
Definition: pval.c:4940
void destroy_extensions(struct ael_extension *exten)
Definition: pval.c:2978
static char * handle_cli_ael_set_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: pbx_ael.c:199
#define DEBUG_READ
Definition: pbx_ael.c:75
static int aeldebug
Definition: pbx_ael.c:120
static char * registrar
Definition: pbx_ael.c:81
static int load_module(void)
Definition: pbx_ael.c:271
void add_extensions(struct ael_extension *exten)
Definition: pval.c:4213
static int unload_module(void)
Definition: pbx_ael.c:261
static int reload(void)
Definition: pbx_ael.c:290
static char * handle_cli_ael_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: pbx_ael.c:231
int is_int(char *arg)
Definition: pval.c:1972
void ast_expr_register_extra_error_info(char *errmsg)
Definition: ast_expr2f.c:2463
static struct ast_context * local_contexts
Definition: pbx_config.c:119
static struct ast_hashtab * local_table
Definition: pbx_config.c:120
static int errs
Definition: pval.c:65
#define NULL
Definition: resample.c:96
Registered applications container.
Definition: pbx_app.c:68
Definition: pval.h:111
ast_app: A registered application
Definition: pbx_app.c:45
Main Channel structure associated with a channel.
descriptor for a cli entry.
Definition: cli.h:171
int args
This gets set in ast_cli_register()
Definition: cli.h:185
char * command
Definition: cli.h:186
const char * usage
Definition: cli.h:177
ast_context: An extension context
Definition: pbx.c:299
Definition: pval.h:49
static struct aco_type item
Definition: test_config.c:1463
const char * args
static struct test_val a
#define ARRAY_LEN(a)
Definition: utils.h:666