Wed Jan 8 2020 09:49:49

Asterisk developer's documentation


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 #if !defined(STANDALONE)
33 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 370642 $")
34 #endif
35 
36 #include <ctype.h>
37 #include <regex.h>
38 #include <sys/stat.h>
39 
40 #ifdef STANDALONE
41 #ifdef HAVE_MTX_PROFILE
42 static int mtx_prof = -1; /* helps the standalone compile with the mtx_prof flag on */
43 #endif
44 #endif
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"
55 #ifdef AAL_ARGCHECK
56 #include "asterisk/argdesc.h"
57 #endif
58 
59 /*** DOCUMENTATION
60  <application name="AELSub" language="en_US">
61  <synopsis>
62  Launch subroutine built with AEL
63  </synopsis>
64  <syntax>
65  <parameter name="routine" required="true">
66  <para>Named subroutine to execute.</para>
67  </parameter>
68  <parameter name="args" required="false" />
69  </syntax>
70  <description>
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>
75  </description>
76  </application>
77  ***/
78 
79 /* these functions are in ../ast_expr2.fl */
80 
81 #define DEBUG_READ (1 << 0)
82 #define DEBUG_TOKENS (1 << 1)
83 #define DEBUG_MACROS (1 << 2)
84 #define DEBUG_CONTEXTS (1 << 3)
85 
86 static char *config = "extensions.ael";
87 static char *registrar = "pbx_ael";
88 static int pbx_load_module(void);
89 
90 #ifndef AAL_ARGCHECK
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
94 */
95 
96 #endif
97 
98 #ifdef AAL_ARGCHECK
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);
102 #endif
103 
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);
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);
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);
125 
126 /* static void substitute_commas(char *str); */
127 
128 static int aeldebug = 0;
129 
130 /* interface stuff */
131 
132 #ifndef STANDALONE
133 static char *aelsub = "AELSub";
134 
135 static int aelsub_exec(struct ast_channel *chan, const char *vdata)
136 {
137  char buf[256], *data = ast_strdupa(vdata);
138  struct ast_app *gosub = pbx_findapp("Gosub");
140  AST_APP_ARG(name);
141  AST_APP_ARG(args);
142  );
143 
144  if (gosub) {
146  snprintf(buf, sizeof(buf), "%s,~~s~~,1(%s)", args.name, args.args);
147  return pbx_exec(chan, gosub, buf);
148  }
149  return -1;
150 }
151 #endif
152 
153 /* if all the below are static, who cares if they are present? */
154 
155 static int pbx_load_module(void)
156 {
157  int errs=0, sem_err=0, sem_warn=0, sem_note=0;
158  char *rfilename;
159  struct ast_context *local_contexts=NULL, *con;
160  struct ast_hashtab *local_table=NULL;
161 
162  struct pval *parse_tree;
163 
164  ast_log(LOG_NOTICE, "Starting AEL load process.\n");
165  if (config[0] == '/')
166  rfilename = (char *)config;
167  else {
168  rfilename = ast_alloca(strlen(config) + strlen(ast_config_AST_CONFIG_DIR) + 2);
169  sprintf(rfilename, "%s/%s", ast_config_AST_CONFIG_DIR, config);
170  }
171  if (access(rfilename,R_OK) != 0) {
172  ast_log(LOG_NOTICE, "File %s not found; AEL declining load\n", rfilename);
174  }
175 
176  parse_tree = ael2_parse(rfilename, &errs);
177  ast_log(LOG_NOTICE, "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_log(LOG_NOTICE, "AEL load process: checked config file name '%s'.\n", rfilename);
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 */
186  }
187  ast_log(LOG_NOTICE, "AEL load process: compiled config file name '%s'.\n", rfilename);
188 
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_log(LOG_NOTICE, "AEL load process: merged config file name '%s'.\n", rfilename);
193  for (con = ast_walk_contexts(NULL); con; con = ast_walk_contexts(con))
195  ast_log(LOG_NOTICE, "AEL load process: verified config file name '%s'.\n", rfilename);
196  } else {
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 */
200  }
201  destroy_pval(parse_tree); /* free up the memory */
202 
204 }
205 
206 /* CLI interface */
207 static char *handle_cli_ael_set_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
208 {
209  switch (cmd) {
210  case CLI_INIT:
211  e->command = "ael set debug {read|tokens|macros|contexts|off}";
212  e->usage =
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";
217  return NULL;
218  case CLI_GENERATE:
219  return NULL;
220  }
221 
222  if (a->argc != e->args)
223  return CLI_SHOWUSAGE;
224 
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"))
234  aeldebug = 0;
235  else
236  return CLI_SHOWUSAGE;
237 
238  return CLI_SUCCESS;
239 }
240 
241 static char *handle_cli_ael_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
242 {
243  switch (cmd) {
244  case CLI_INIT:
245  e->command = "ael reload";
246  e->usage =
247  "Usage: ael reload\n"
248  " Reloads AEL configuration.\n";
249  return NULL;
250  case CLI_GENERATE:
251  return NULL;
252  }
253 
254  if (a->argc != 2)
255  return CLI_SHOWUSAGE;
256 
257  return (pbx_load_module() ? CLI_FAILURE : CLI_SUCCESS);
258 }
259 
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")
263 };
264 
265 static int unload_module(void)
266 {
267  ast_context_destroy(NULL, registrar);
268  ast_cli_unregister_multiple(cli_ael, ARRAY_LEN(cli_ael));
269 #ifndef STANDALONE
271 #endif
272  return 0;
273 }
274 
275 static int load_module(void)
276 {
277  ast_cli_register_multiple(cli_ael, ARRAY_LEN(cli_ael));
278 #ifndef STANDALONE
280 #endif
281  return (pbx_load_module());
282 }
283 
284 static int reload(void)
285 {
286  return pbx_load_module();
287 }
288 
289 #ifdef STANDALONE
290 #define AST_MODULE "ael"
291 int ael_external_load_module(void);
292 int ael_external_load_module(void)
293 {
294  pbx_load_module();
295  return 1;
296 }
297 #endif
298 
299 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Asterisk Extension Language Compiler",
300  .load = load_module,
301  .unload = unload_module,
302  .reload = reload,
303  );
304 
305 #ifdef AAL_ARGCHECK
306 static const char * const ael_funclist[] =
307 {
308  "AGENT",
309  "ARRAY",
310  "BASE64_DECODE",
311  "BASE64_ENCODE",
312  "CALLERID",
313  "CDR",
314  "CHANNEL",
315  "CHECKSIPDOMAIN",
316  "CHECK_MD5",
317  "CURL",
318  "CUT",
319  "DB",
320  "DB_EXISTS",
321  "DUNDILOOKUP",
322  "ENUMLOOKUP",
323  "ENV",
324  "EVAL",
325  "EXISTS",
326  "FIELDQTY",
327  "FILTER",
328  "GROUP",
329  "GROUP_COUNT",
330  "GROUP_LIST",
331  "GROUP_MATCH_COUNT",
332  "IAXPEER",
333  "IF",
334  "IFTIME",
335  "ISNULL",
336  "KEYPADHASH",
337  "LANGUAGE",
338  "LEN",
339  "MATH",
340  "MD5",
341  "MUSICCLASS",
342  "QUEUEAGENTCOUNT",
343  "QUEUE_MEMBER_COUNT",
344  "QUEUE_MEMBER_LIST",
345  "QUOTE",
346  "RAND",
347  "REGEX",
348  "SET",
349  "SHA1",
350  "SIPCHANINFO",
351  "SIPPEER",
352  "SIP_HEADER",
353  "SORT",
354  "STAT",
355  "STRFTIME",
356  "STRPTIME",
357  "TIMEOUT",
358  "TXTCIDNAME",
359  "URIDECODE",
360  "URIENCODE",
361  "VMCOUNT"
362 };
363 
364 
365 int ael_is_funcname(char *name)
366 {
367  int s,t;
368  t = sizeof(ael_funclist)/sizeof(char*);
369  s = 0;
370  while ((s < t) && strcasecmp(name, ael_funclist[s]))
371  s++;
372  if ( s < t )
373  return 1;
374  else
375  return 0;
376 }
377 #endif
int ast_hashtab_compare_contexts(const void *ah_a, const void *ah_b)
hashtable functions for contexts
Definition: pbx.c:1136
void check_pval_item(pval *item, struct argapp *apps, int in_globals)
Definition: pval.c:2364
static char exten[AST_MAX_EXTENSION]
Definition: chan_alsa.c:109
Main Channel structure associated with a channel.
Definition: channel.h:742
void destroy_pval_item(pval *item)
Definition: pval.c:4711
#define AST_CLI_DEFINE(fn, txt,...)
Definition: cli.h:191
void check_switch_expr(pval *item, struct argapp *apps)
Definition: pval.c:2191
void check_pval(pval *item, struct argapp *apps, int in_globals)
Definition: pval.c:2872
struct ael_priority * new_prio(void)
Definition: pval.c:2931
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:131
#define ARRAY_LEN(a)
Definition: isdn_lib.c:42
static int errs
Definition: pval.c:67
struct ast_app * pbx_findapp(const char *app)
Look up an application.
Definition: pbx.c:1537
int pbx_exec(struct ast_channel *c, struct ast_app *app, const char *data)
Execute an application.
Definition: pbx.c:1497
CallerID (and other GR30) management and generation Includes code and algorithms from the Zapata libr...
#define ast_alloca(size)
call __builtin_alloca to ensure we get gcc builtin semantics
Definition: utils.h:653
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
Definition: cli.c:2177
Definition: pbx.c:1301
descriptor for a cli entry.
Definition: cli.h:165
const int argc
Definition: cli.h:154
Generic (perhaps overly so) hashtable implementation Hash Table support in Asterisk.
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application&#39;s arguments.
Definition: app.h:572
void add_extensions(struct ael_extension *exten)
Definition: pval.c:4251
Definition: cli.h:146
static int aeldebug
Definition: pbx_ael.c:128
Configuration File Parser.
#define AST_MODULE_INFO(keystr, flags_to_set, desc, fields...)
Definition: module.h:374
int is_float(char *arg)
Definition: pval.c:1970
int ast_unregister_application(const char *app)
Unregister an application.
Definition: pbx.c:7705
Definition: pval.h:110
#define DEBUG_MACROS
Definition: pbx_ael.c:83
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:88
int args
This gets set in ast_cli_register()
Definition: cli.h:179
struct ael_extension * new_exten(void)
Definition: pval.c:2937
static const char app[]
Definition: app_adsiprog.c:49
static char * handle_cli_ael_set_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: pbx_ael.c:207
static char * aelsub
Definition: pbx_ael.c:133
struct ast_hashtab * ast_hashtab_create(int initial_buckets, int(*compare)(const void *a, const void *b), int(*resize)(struct ast_hashtab *), int(*newsize)(struct ast_hashtab *tab), unsigned int(*hash)(const void *obj), int do_locking)
Create the hashtable list.
Definition: hashtab.c:226
Definition: pval.h:48
struct ast_context * ast_walk_contexts(struct ast_context *con)
Definition: pbx.c:11174
Core PBX routines and definitions.
void destroy_pval(pval *item)
Definition: pval.c:4979
const char *const * argv
Definition: cli.h:155
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: utils.h:663
void ast_expr_clear_extra_error_info(void)
Definition: ast_expr2f.c:2475
#define LOG_ERROR
Definition: logger.h:155
int ast_compile_ael2(struct ast_context **local_contexts, struct ast_hashtab *local_table, struct pval *root)
Definition: pval.c:4451
static struct @350 args
#define CLI_SHOWUSAGE
Definition: cli.h:44
const char * ast_config_AST_CONFIG_DIR
Definition: asterisk.c:256
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:7937
static char * config
Definition: pbx_ael.c:86
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207
#define DEBUG_CONTEXTS
Definition: pbx_ael.c:84
#define LOG_NOTICE
Definition: logger.h:133
static struct ast_hashtab * local_table
Definition: pbx_config.c:61
static char * registrar
Definition: pbx_ael.c:87
#define CLI_FAILURE
Definition: cli.h:45
static const char name[]
char * command
Definition: cli.h:180
unsigned int ast_hashtab_hash_contexts(const void *obj)
Definition: pbx.c:1188
Structures for AEL - the Asterisk extension language.
int is_int(char *arg)
Definition: pval.c:1979
static char * handle_cli_ael_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: pbx_ael.c:241
struct pval * find_context(char *name)
Definition: pval.c:1960
void ast_expr_register_extra_error_info(char *errmsg)
Definition: ast_expr2f.c:2469
Support for logging to various files, console and syslog Configuration in file logger.conf.
#define DEBUG_TOKENS
Definition: pbx_ael.c:82
void destroy_extensions(struct ael_extension *exten)
Definition: pval.c:2985
const char * usage
Definition: cli.h:171
#define CLI_SUCCESS
Definition: cli.h:43
void set_priorities(struct ael_extension *exten)
Definition: pval.c:4225
Standard Command Line Interface.
ast_app: A registered application
Definition: pbx.c:971
int check_app_args(pval *appcall, pval *arglist, struct argapp *app)
Definition: pval.c:2137
int ast_cli_register_multiple(struct ast_cli_entry *e, int len)
Register multiple commands.
Definition: cli.c:2167
static struct ast_context * local_contexts
Definition: pbx_config.c:60
int is_empty(char *arg)
Definition: pval.c:1988
Application convenience functions, designed to give consistent look and feel to Asterisk apps...
struct pval * find_macro(char *name)
Definition: pval.c:1950
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:9875
#define AST_STANDARD_RAW_ARGS(args, parse)
Definition: app.h:606
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:2892
#define AST_APP_ARG(name)
Define an application argument.
Definition: app.h:555
int ast_context_verify_includes(struct ast_context *con)
Verifies includes in an ast_contect structure.
Definition: pbx.c:11221
static int unload_module(void)
Definition: pbx_ael.c:265
static int reload(void)
Definition: pbx_ael.c:284
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:38
Asterisk module definitions.
static int aelsub_exec(struct ast_channel *chan, const char *vdata)
Definition: pbx_ael.c:135
static int load_module(void)
Definition: pbx_ael.c:275
ast_context: An extension context
Definition: pbx.c:955
static struct ast_cli_entry cli_ael[]
Definition: pbx_ael.c:260
#define ast_register_application_xml(app, execute)
Register an application using XML documentation.
Definition: module.h:437
#define DEBUG_READ
Definition: pbx_ael.c:81
#define ASTERISK_FILE_VERSION(file, version)
Register/unregister a source code file with the core.
Definition: asterisk.h:180
static int pbx_load_module(void)
Definition: pbx_ael.c:155