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