pbx_ael.c 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379
  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. /*! \file
  19. *
  20. * \brief Compile symbolic Asterisk Extension Logic into Asterisk extensions, version 2.
  21. *
  22. */
  23. /*** MODULEINFO
  24. <depend>res_ael_share</depend>
  25. <support_level>extended</support_level>
  26. ***/
  27. #include "asterisk.h"
  28. #if !defined(STANDALONE)
  29. ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
  30. #endif
  31. #include <ctype.h>
  32. #include <regex.h>
  33. #include <sys/stat.h>
  34. #ifdef STANDALONE
  35. #ifdef HAVE_MTX_PROFILE
  36. static int mtx_prof = -1; /* helps the standalone compile with the mtx_prof flag on */
  37. #endif
  38. #endif
  39. #include "asterisk/pbx.h"
  40. #include "asterisk/config.h"
  41. #include "asterisk/module.h"
  42. #include "asterisk/logger.h"
  43. #include "asterisk/cli.h"
  44. #include "asterisk/app.h"
  45. #include "asterisk/callerid.h"
  46. #include "asterisk/hashtab.h"
  47. #include "asterisk/ael_structs.h"
  48. #include "asterisk/pval.h"
  49. #ifdef AAL_ARGCHECK
  50. #include "asterisk/argdesc.h"
  51. #endif
  52. /*** DOCUMENTATION
  53. <application name="AELSub" language="en_US">
  54. <synopsis>
  55. Launch subroutine built with AEL
  56. </synopsis>
  57. <syntax>
  58. <parameter name="routine" required="true">
  59. <para>Named subroutine to execute.</para>
  60. </parameter>
  61. <parameter name="args" required="false" />
  62. </syntax>
  63. <description>
  64. <para>Execute the named subroutine, defined in AEL, from another dialplan
  65. language, such as extensions.conf, Realtime extensions, or Lua.</para>
  66. <para>The purpose of this application is to provide a sane entry point into
  67. AEL subroutines, the implementation of which may change from time to time.</para>
  68. </description>
  69. </application>
  70. ***/
  71. /* these functions are in ../ast_expr2.fl */
  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. static char *config = "extensions.ael";
  77. static char *registrar = "pbx_ael";
  78. static int pbx_load_module(void);
  79. #ifndef AAL_ARGCHECK
  80. /* for the time being, short circuit all the AAL related structures
  81. without permanently removing the code; after/during the AAL
  82. development, this code can be properly re-instated
  83. */
  84. #endif
  85. #ifdef AAL_ARGCHECK
  86. int option_matches_j( struct argdesc *should, pval *is, struct argapp *app);
  87. int option_matches( struct argdesc *should, pval *is, struct argapp *app);
  88. int ael_is_funcname(char *name);
  89. #endif
  90. int check_app_args(pval *appcall, pval *arglist, struct argapp *app);
  91. void check_pval(pval *item, struct argapp *apps, int in_globals);
  92. void check_pval_item(pval *item, struct argapp *apps, int in_globals);
  93. void check_switch_expr(pval *item, struct argapp *apps);
  94. void ast_expr_register_extra_error_info(char *errmsg);
  95. void ast_expr_clear_extra_error_info(void);
  96. struct pval *find_macro(char *name);
  97. struct pval *find_context(char *name);
  98. struct pval *find_context(char *name);
  99. struct pval *find_macro(char *name);
  100. struct ael_priority *new_prio(void);
  101. struct ael_extension *new_exten(void);
  102. void destroy_extensions(struct ael_extension *exten);
  103. void set_priorities(struct ael_extension *exten);
  104. void add_extensions(struct ael_extension *exten);
  105. int ast_compile_ael2(struct ast_context **local_contexts, struct ast_hashtab *local_table, struct pval *root);
  106. void destroy_pval(pval *item);
  107. void destroy_pval_item(pval *item);
  108. int is_float(char *arg );
  109. int is_int(char *arg );
  110. int is_empty(char *arg);
  111. /* static void substitute_commas(char *str); */
  112. static int aeldebug = 0;
  113. /* interface stuff */
  114. #ifndef STANDALONE
  115. static char *aelsub = "AELSub";
  116. static int aelsub_exec(struct ast_channel *chan, const char *vdata)
  117. {
  118. char buf[256], *data = ast_strdupa(vdata);
  119. struct ast_app *gosub = pbx_findapp("Gosub");
  120. AST_DECLARE_APP_ARGS(args,
  121. AST_APP_ARG(name);
  122. AST_APP_ARG(args);
  123. );
  124. if (gosub) {
  125. AST_STANDARD_RAW_ARGS(args, data);
  126. snprintf(buf, sizeof(buf), "%s,~~s~~,1(%s)", args.name, args.args);
  127. return pbx_exec(chan, gosub, buf);
  128. }
  129. return -1;
  130. }
  131. #endif
  132. /* if all the below are static, who cares if they are present? */
  133. static int pbx_load_module(void)
  134. {
  135. int errs=0, sem_err=0, sem_warn=0, sem_note=0;
  136. char *rfilename;
  137. struct ast_context *local_contexts=NULL, *con;
  138. struct ast_hashtab *local_table=NULL;
  139. struct pval *parse_tree;
  140. ast_debug(1, "Starting AEL load process.\n");
  141. if (config[0] == '/')
  142. rfilename = (char *)config;
  143. else {
  144. rfilename = ast_alloca(strlen(config) + strlen(ast_config_AST_CONFIG_DIR) + 2);
  145. sprintf(rfilename, "%s/%s", ast_config_AST_CONFIG_DIR, config);
  146. }
  147. if (access(rfilename,R_OK) != 0) {
  148. ast_log(LOG_NOTICE, "File %s not found; AEL declining load\n", rfilename);
  149. return AST_MODULE_LOAD_DECLINE;
  150. }
  151. parse_tree = ael2_parse(rfilename, &errs);
  152. ast_debug(1, "AEL load process: parsed config file name '%s'.\n", rfilename);
  153. ael2_semantic_check(parse_tree, &sem_err, &sem_warn, &sem_note);
  154. if (errs == 0 && sem_err == 0) {
  155. ast_debug(1, "AEL load process: checked config file name '%s'.\n", rfilename);
  156. local_table = ast_hashtab_create(11, ast_hashtab_compare_contexts, ast_hashtab_resize_java, ast_hashtab_newsize_java, ast_hashtab_hash_contexts, 0);
  157. if (ast_compile_ael2(&local_contexts, local_table, parse_tree)) {
  158. ast_log(LOG_ERROR, "AEL compile failed! Aborting.\n");
  159. destroy_pval(parse_tree); /* free up the memory */
  160. return AST_MODULE_LOAD_DECLINE;
  161. }
  162. ast_debug(1, "AEL load process: compiled config file name '%s'.\n", rfilename);
  163. ast_merge_contexts_and_delete(&local_contexts, local_table, registrar);
  164. local_table = NULL; /* it's the dialplan global now */
  165. local_contexts = NULL;
  166. ast_debug(1, "AEL load process: merged config file name '%s'.\n", rfilename);
  167. for (con = ast_walk_contexts(NULL); con; con = ast_walk_contexts(con))
  168. ast_context_verify_includes(con);
  169. ast_debug(1, "AEL load process: verified config file name '%s'.\n", rfilename);
  170. } else {
  171. 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);
  172. destroy_pval(parse_tree); /* free up the memory */
  173. return AST_MODULE_LOAD_DECLINE;
  174. }
  175. destroy_pval(parse_tree); /* free up the memory */
  176. return AST_MODULE_LOAD_SUCCESS;
  177. }
  178. /* CLI interface */
  179. static char *handle_cli_ael_set_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
  180. {
  181. switch (cmd) {
  182. case CLI_INIT:
  183. e->command = "ael set debug {read|tokens|macros|contexts|off}";
  184. e->usage =
  185. "Usage: ael set debug {read|tokens|macros|contexts|off}\n"
  186. " Enable AEL read, token, macro, or context debugging,\n"
  187. " or disable all AEL debugging messages. Note: this\n"
  188. " currently does nothing.\n";
  189. return NULL;
  190. case CLI_GENERATE:
  191. return NULL;
  192. }
  193. if (a->argc != e->args)
  194. return CLI_SHOWUSAGE;
  195. if (!strcasecmp(a->argv[3], "read"))
  196. aeldebug |= DEBUG_READ;
  197. else if (!strcasecmp(a->argv[3], "tokens"))
  198. aeldebug |= DEBUG_TOKENS;
  199. else if (!strcasecmp(a->argv[3], "macros"))
  200. aeldebug |= DEBUG_MACROS;
  201. else if (!strcasecmp(a->argv[3], "contexts"))
  202. aeldebug |= DEBUG_CONTEXTS;
  203. else if (!strcasecmp(a->argv[3], "off"))
  204. aeldebug = 0;
  205. else
  206. return CLI_SHOWUSAGE;
  207. return CLI_SUCCESS;
  208. }
  209. static char *handle_cli_ael_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
  210. {
  211. switch (cmd) {
  212. case CLI_INIT:
  213. e->command = "ael reload";
  214. e->usage =
  215. "Usage: ael reload\n"
  216. " Reloads AEL configuration.\n";
  217. return NULL;
  218. case CLI_GENERATE:
  219. return NULL;
  220. }
  221. if (a->argc != 2)
  222. return CLI_SHOWUSAGE;
  223. return (pbx_load_module() ? CLI_FAILURE : CLI_SUCCESS);
  224. }
  225. static struct ast_cli_entry cli_ael[] = {
  226. AST_CLI_DEFINE(handle_cli_ael_reload, "Reload AEL configuration"),
  227. AST_CLI_DEFINE(handle_cli_ael_set_debug, "Enable AEL debugging flags")
  228. };
  229. static int unload_module(void)
  230. {
  231. ast_context_destroy(NULL, registrar);
  232. ast_cli_unregister_multiple(cli_ael, ARRAY_LEN(cli_ael));
  233. #ifndef STANDALONE
  234. ast_unregister_application(aelsub);
  235. #endif
  236. return 0;
  237. }
  238. static int load_module(void)
  239. {
  240. ast_cli_register_multiple(cli_ael, ARRAY_LEN(cli_ael));
  241. #ifndef STANDALONE
  242. ast_register_application_xml(aelsub, aelsub_exec);
  243. #endif
  244. return (pbx_load_module());
  245. }
  246. static int reload(void)
  247. {
  248. return pbx_load_module();
  249. }
  250. #ifdef STANDALONE
  251. #define AST_MODULE "ael"
  252. int ael_external_load_module(void);
  253. int ael_external_load_module(void)
  254. {
  255. pbx_load_module();
  256. return 1;
  257. }
  258. #endif
  259. AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Asterisk Extension Language Compiler",
  260. .support_level = AST_MODULE_SUPPORT_EXTENDED,
  261. .load = load_module,
  262. .unload = unload_module,
  263. .reload = reload,
  264. );
  265. #ifdef AAL_ARGCHECK
  266. static const char * const ael_funclist[] =
  267. {
  268. "AGENT",
  269. "ARRAY",
  270. "BASE64_DECODE",
  271. "BASE64_ENCODE",
  272. "CALLERID",
  273. "CDR",
  274. "CHANNEL",
  275. "CHECKSIPDOMAIN",
  276. "CHECK_MD5",
  277. "CURL",
  278. "CUT",
  279. "DB",
  280. "DB_EXISTS",
  281. "DUNDILOOKUP",
  282. "ENUMLOOKUP",
  283. "ENV",
  284. "EVAL",
  285. "EXISTS",
  286. "FIELDQTY",
  287. "FILTER",
  288. "GROUP",
  289. "GROUP_COUNT",
  290. "GROUP_LIST",
  291. "GROUP_MATCH_COUNT",
  292. "IAXPEER",
  293. "IF",
  294. "IFTIME",
  295. "ISNULL",
  296. "KEYPADHASH",
  297. "LANGUAGE",
  298. "LEN",
  299. "MATH",
  300. "MD5",
  301. "MUSICCLASS",
  302. "QUEUEAGENTCOUNT",
  303. "QUEUE_MEMBER_COUNT",
  304. "QUEUE_MEMBER_LIST",
  305. "QUOTE",
  306. "RAND",
  307. "REGEX",
  308. "SET",
  309. "SHA1",
  310. "SIPCHANINFO",
  311. "SIPPEER",
  312. "SIP_HEADER",
  313. "SORT",
  314. "STAT",
  315. "STRFTIME",
  316. "STRPTIME",
  317. "TIMEOUT",
  318. "TXTCIDNAME",
  319. "URIDECODE",
  320. "URIENCODE",
  321. "VMCOUNT"
  322. };
  323. int ael_is_funcname(char *name)
  324. {
  325. int s,t;
  326. t = sizeof(ael_funclist)/sizeof(char*);
  327. s = 0;
  328. while ((s < t) && strcasecmp(name, ael_funclist[s]))
  329. s++;
  330. if ( s < t )
  331. return 1;
  332. else
  333. return 0;
  334. }
  335. #endif