Fri Jul 15 2011 11:58:26

Asterisk developer's documentation


pbx_ael.c
Go to the documentation of this file.
00001 /* 
00002  * Asterisk -- An open source telephony toolkit.
00003  *
00004  * Copyright (C) 2006, Digium, Inc.
00005  *
00006  * Steve Murphy <murf@parsetree.com>
00007  *
00008  * See http://www.asterisk.org for more information about
00009  * the Asterisk project. Please do not directly contact
00010  * any of the maintainers of this project for assistance;
00011  * the project provides a web site, mailing lists and IRC
00012  * channels for your use.
00013  *
00014  * This program is free software, distributed under the terms of
00015  * the GNU General Public License Version 2. See the LICENSE file
00016  * at the top of the source tree.
00017  */
00018 
00019 /*! \file
00020  *
00021  * \brief Compile symbolic Asterisk Extension Logic into Asterisk extensions, version 2.
00022  * 
00023  */
00024 
00025 /*** MODULEINFO
00026    <depend>res_ael_share</depend>
00027  ***/
00028 
00029 #include "asterisk.h"
00030 
00031 #if !defined(STANDALONE)
00032 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 310448 $")
00033 #endif
00034 
00035 #include <ctype.h>
00036 #include <regex.h>
00037 #include <sys/stat.h>
00038 
00039 #ifdef STANDALONE
00040 #ifdef HAVE_MTX_PROFILE
00041 static int mtx_prof = -1; /* helps the standalone compile with the mtx_prof flag on */
00042 #endif
00043 #endif
00044 #include "asterisk/pbx.h"
00045 #include "asterisk/config.h"
00046 #include "asterisk/module.h"
00047 #include "asterisk/logger.h"
00048 #include "asterisk/cli.h"
00049 #include "asterisk/app.h"
00050 #include "asterisk/callerid.h"
00051 #include "asterisk/hashtab.h"
00052 #include "asterisk/ael_structs.h"
00053 #include "asterisk/pval.h"
00054 #ifdef AAL_ARGCHECK
00055 #include "asterisk/argdesc.h"
00056 #endif
00057 
00058 /*** DOCUMENTATION
00059    <application name="AELSub" language="en_US">
00060       <synopsis>
00061          Launch subroutine built with AEL
00062       </synopsis>
00063       <syntax>
00064          <parameter name="routine" required="true">
00065             <para>Named subroutine to execute.</para>
00066          </parameter>
00067          <parameter name="args" required="false" />
00068       </syntax>
00069       <description>
00070          <para>Execute the named subroutine, defined in AEL, from another dialplan
00071          language, such as extensions.conf, Realtime extensions, or Lua.</para>
00072          <para>The purpose of this application is to provide a sane entry point into
00073          AEL subroutines, the implementation of which may change from time to time.</para>
00074       </description>
00075    </application>
00076  ***/
00077 
00078 /* these functions are in ../ast_expr2.fl */
00079 
00080 #define DEBUG_READ   (1 << 0)
00081 #define DEBUG_TOKENS (1 << 1)
00082 #define DEBUG_MACROS (1 << 2)
00083 #define DEBUG_CONTEXTS (1 << 3)
00084 
00085 static char *config = "extensions.ael";
00086 static char *registrar = "pbx_ael";
00087 static int pbx_load_module(void);
00088 
00089 #ifndef AAL_ARGCHECK
00090 /* for the time being, short circuit all the AAL related structures
00091    without permanently removing the code; after/during the AAL 
00092    development, this code can be properly re-instated 
00093 */
00094 
00095 #endif
00096 
00097 #ifdef AAL_ARGCHECK
00098 int option_matches_j( struct argdesc *should, pval *is, struct argapp *app);
00099 int option_matches( struct argdesc *should, pval *is, struct argapp *app);
00100 int ael_is_funcname(char *name);
00101 #endif
00102 
00103 int check_app_args(pval *appcall, pval *arglist, struct argapp *app);
00104 void check_pval(pval *item, struct argapp *apps, int in_globals);
00105 void check_pval_item(pval *item, struct argapp *apps, int in_globals);
00106 void check_switch_expr(pval *item, struct argapp *apps);
00107 void ast_expr_register_extra_error_info(char *errmsg);
00108 void ast_expr_clear_extra_error_info(void);
00109 struct pval *find_macro(char *name);
00110 struct pval *find_context(char *name);
00111 struct pval *find_context(char *name);
00112 struct pval *find_macro(char *name);
00113 struct ael_priority *new_prio(void);
00114 struct ael_extension *new_exten(void);
00115 void destroy_extensions(struct ael_extension *exten);
00116 void set_priorities(struct ael_extension *exten);
00117 void add_extensions(struct ael_extension *exten);
00118 int ast_compile_ael2(struct ast_context **local_contexts, struct ast_hashtab *local_table, struct pval *root);
00119 void destroy_pval(pval *item);
00120 void destroy_pval_item(pval *item);
00121 int is_float(char *arg );
00122 int is_int(char *arg );
00123 int is_empty(char *arg);
00124 
00125 /* static void substitute_commas(char *str); */
00126 
00127 static int aeldebug = 0;
00128 
00129 /* interface stuff */
00130 
00131 #ifndef STANDALONE
00132 static char *aelsub = "AELSub";
00133 
00134 static int aelsub_exec(struct ast_channel *chan, void *vdata)
00135 {
00136    char buf[256], *data = ast_strdupa(vdata);
00137    struct ast_app *gosub = pbx_findapp("Gosub");
00138    AST_DECLARE_APP_ARGS(args,
00139       AST_APP_ARG(name);
00140       AST_APP_ARG(args);
00141    );
00142 
00143    if (gosub) {
00144       AST_STANDARD_RAW_ARGS(args, data);
00145       snprintf(buf, sizeof(buf), "%s,~~s~~,1(%s)", args.name, args.args);
00146       return pbx_exec(chan, gosub, buf);
00147    }
00148    return -1;
00149 }
00150 #endif
00151 
00152 /* if all the below are static, who cares if they are present? */
00153 
00154 static int pbx_load_module(void)
00155 {
00156    int errs=0, sem_err=0, sem_warn=0, sem_note=0;
00157    char *rfilename;
00158    struct ast_context *local_contexts=NULL, *con;
00159    struct ast_hashtab *local_table=NULL;
00160    
00161    struct pval *parse_tree;
00162 
00163    ast_log(LOG_NOTICE, "Starting AEL load process.\n");
00164    if (config[0] == '/')
00165       rfilename = (char *)config;
00166    else {
00167       rfilename = alloca(strlen(config) + strlen(ast_config_AST_CONFIG_DIR) + 2);
00168       sprintf(rfilename, "%s/%s", ast_config_AST_CONFIG_DIR, config);
00169    }
00170    if (access(rfilename,R_OK) != 0) {
00171       ast_log(LOG_NOTICE, "File %s not found; AEL declining load\n", rfilename);
00172       return AST_MODULE_LOAD_DECLINE;
00173    }
00174    
00175    parse_tree = ael2_parse(rfilename, &errs);
00176    ast_log(LOG_NOTICE, "AEL load process: parsed config file name '%s'.\n", rfilename);
00177    ael2_semantic_check(parse_tree, &sem_err, &sem_warn, &sem_note);
00178    if (errs == 0 && sem_err == 0) {
00179       ast_log(LOG_NOTICE, "AEL load process: checked config file name '%s'.\n", rfilename);
00180       local_table = ast_hashtab_create(11, ast_hashtab_compare_contexts, ast_hashtab_resize_java, ast_hashtab_newsize_java, ast_hashtab_hash_contexts, 0);
00181       if (ast_compile_ael2(&local_contexts, local_table, parse_tree)) {
00182          ast_log(LOG_ERROR, "AEL compile failed! Aborting.\n");
00183          destroy_pval(parse_tree); /* free up the memory */
00184          return AST_MODULE_LOAD_DECLINE;
00185       }
00186       ast_log(LOG_NOTICE, "AEL load process: compiled config file name '%s'.\n", rfilename);
00187       
00188       ast_merge_contexts_and_delete(&local_contexts, local_table, registrar);
00189       local_table = NULL; /* it's the dialplan global now */
00190       local_contexts = NULL;
00191       ast_log(LOG_NOTICE, "AEL load process: merged config file name '%s'.\n", rfilename);
00192       for (con = ast_walk_contexts(NULL); con; con = ast_walk_contexts(con))
00193          ast_context_verify_includes(con);
00194       ast_log(LOG_NOTICE, "AEL load process: verified config file name '%s'.\n", rfilename);
00195    } else {
00196       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);
00197       destroy_pval(parse_tree); /* free up the memory */
00198       return AST_MODULE_LOAD_DECLINE;
00199    }
00200    destroy_pval(parse_tree); /* free up the memory */
00201    
00202    return AST_MODULE_LOAD_SUCCESS;
00203 }
00204 
00205 /* CLI interface */
00206 static char *handle_cli_ael_set_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00207 {
00208    switch (cmd) {
00209    case CLI_INIT:
00210       e->command = "ael set debug {read|tokens|macros|contexts|off}";
00211       e->usage =
00212          "Usage: ael set debug {read|tokens|macros|contexts|off}\n"
00213          "       Enable AEL read, token, macro, or context debugging,\n"
00214          "       or disable all AEL debugging messages.  Note: this\n"
00215          "       currently does nothing.\n";
00216       return NULL;
00217    case CLI_GENERATE:
00218       return NULL;
00219    }
00220 
00221    if (a->argc != e->args)
00222       return CLI_SHOWUSAGE;
00223 
00224    if (!strcasecmp(a->argv[3], "read"))
00225       aeldebug |= DEBUG_READ;
00226    else if (!strcasecmp(a->argv[3], "tokens"))
00227       aeldebug |= DEBUG_TOKENS;
00228    else if (!strcasecmp(a->argv[3], "macros"))
00229       aeldebug |= DEBUG_MACROS;
00230    else if (!strcasecmp(a->argv[3], "contexts"))
00231       aeldebug |= DEBUG_CONTEXTS;
00232    else if (!strcasecmp(a->argv[3], "off"))
00233       aeldebug = 0;
00234    else
00235       return CLI_SHOWUSAGE;
00236 
00237    return CLI_SUCCESS;
00238 }
00239 
00240 static char *handle_cli_ael_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00241 {
00242    switch (cmd) {
00243    case CLI_INIT:
00244       e->command = "ael reload";
00245       e->usage =
00246          "Usage: ael reload\n"
00247          "       Reloads AEL configuration.\n";
00248       return NULL;
00249    case CLI_GENERATE:
00250       return NULL;
00251    }
00252 
00253    if (a->argc != 2)
00254       return CLI_SHOWUSAGE;
00255 
00256    return (pbx_load_module() ? CLI_FAILURE : CLI_SUCCESS);
00257 }
00258 
00259 static struct ast_cli_entry cli_ael[] = {
00260    AST_CLI_DEFINE(handle_cli_ael_reload,    "Reload AEL configuration"),
00261    AST_CLI_DEFINE(handle_cli_ael_set_debug, "Enable AEL debugging flags")
00262 };
00263 
00264 static int unload_module(void)
00265 {
00266    ast_context_destroy(NULL, registrar);
00267    ast_cli_unregister_multiple(cli_ael, ARRAY_LEN(cli_ael));
00268 #ifndef STANDALONE
00269    ast_unregister_application(aelsub);
00270 #endif
00271    return 0;
00272 }
00273 
00274 static int load_module(void)
00275 {
00276    ast_cli_register_multiple(cli_ael, ARRAY_LEN(cli_ael));
00277 #ifndef STANDALONE
00278    ast_register_application_xml(aelsub, aelsub_exec);
00279 #endif
00280    return (pbx_load_module());
00281 }
00282 
00283 static int reload(void)
00284 {
00285    return pbx_load_module();
00286 }
00287 
00288 #ifdef STANDALONE
00289 #define AST_MODULE "ael"
00290 int ael_external_load_module(void);
00291 int ael_external_load_module(void)
00292 {
00293         pbx_load_module();
00294         return 1;
00295 }
00296 #endif
00297 
00298 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Asterisk Extension Language Compiler",
00299       .load = load_module,
00300       .unload = unload_module,
00301       .reload = reload,
00302           );
00303 
00304 #ifdef AAL_ARGCHECK
00305 static char *ael_funclist[] =
00306 {
00307    "AGENT",
00308    "ARRAY",
00309    "BASE64_DECODE",
00310    "BASE64_ENCODE",
00311    "CALLERID",
00312    "CDR",
00313    "CHANNEL",
00314    "CHECKSIPDOMAIN",
00315    "CHECK_MD5",
00316    "CURL",
00317    "CUT",
00318    "DB",
00319    "DB_EXISTS",
00320    "DUNDILOOKUP",
00321    "ENUMLOOKUP",
00322    "ENV",
00323    "EVAL",
00324    "EXISTS",
00325    "FIELDQTY",
00326    "FILTER",
00327    "GROUP",
00328    "GROUP_COUNT",
00329    "GROUP_LIST",
00330    "GROUP_MATCH_COUNT",
00331    "IAXPEER",
00332    "IF",
00333    "IFTIME",
00334    "ISNULL",
00335    "KEYPADHASH",
00336    "LANGUAGE",
00337    "LEN",
00338    "MATH",
00339    "MD5",
00340    "MUSICCLASS",
00341    "QUEUEAGENTCOUNT",
00342    "QUEUE_MEMBER_COUNT",
00343    "QUEUE_MEMBER_LIST",
00344    "QUOTE",
00345    "RAND",
00346    "REGEX",
00347    "SET",
00348    "SHA1",
00349    "SIPCHANINFO",
00350    "SIPPEER",
00351    "SIP_HEADER",
00352    "SORT",
00353    "STAT",
00354    "STRFTIME",
00355    "STRPTIME",
00356    "TIMEOUT",
00357    "TXTCIDNAME",
00358    "URIDECODE",
00359    "URIENCODE",
00360    "VMCOUNT"
00361 };
00362 
00363 
00364 int ael_is_funcname(char *name)
00365 {
00366    int s,t;
00367    t = sizeof(ael_funclist)/sizeof(char*);
00368    s = 0;
00369    while ((s < t) && strcasecmp(name, ael_funclist[s])) 
00370       s++;
00371    if ( s < t )
00372       return 1;
00373    else
00374       return 0;
00375 }
00376 #endif