/* * Asterisk -- An open source telephony toolkit. * * Copyright (C) 2007, Digium, Inc. * * Steve Murphy * * See http://www.asterisk.org for more information about * the Asterisk project. Please do not directly contact * any of the maintainers of this project for assistance; * the project provides a web site, mailing lists and IRC * channels for your use. * * This program is free software, distributed under the terms of * the GNU General Public License Version 2. See the LICENSE file * at the top of the source tree. */ /* * * Reverse compile extensions.conf code into prototype AEL code * */ /*** MODULEINFO res_ael_share ***/ #include "asterisk.h" ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/paths.h" /* CONFIG_DIR */ #include #include #if !defined(SOLARIS) && !defined(__CYGWIN__) #include #endif #include #include "asterisk.h" #include "asterisk/pbx.h" #include "asterisk/ast_expr.h" #include "asterisk/channel.h" #include "asterisk/chanvars.h" #include "asterisk/module.h" #include "asterisk/app.h" #include "asterisk/config.h" #include "asterisk/options.h" #include "asterisk/callerid.h" #include "asterisk/lock.h" #include "asterisk/hashtab.h" #include "asterisk/ael_structs.h" #include "asterisk/devicestate.h" #include "asterisk/stringfields.h" #include "asterisk/pval.h" #include "asterisk/extconf.h" struct ast_flags ast_compat = { 7 }; const char *ast_config_AST_CONFIG_DIR = "/etc/asterisk"; /* placeholder */ void get_start_stop(unsigned int *word, int bitsperword, int totalbits, int *start, int *end); int all_bits_set(unsigned int *word, int bitsperword, int totalbits); extern char *days[]; extern char *months[]; char *config = "extensions.conf"; /* static char *registrar = "conf2ael"; static char userscontext[AST_MAX_EXTENSION] = "default"; static int static_config = 0; static int write_protect_config = 1; static int autofallthrough_config = 0; static int clearglobalvars_config = 0; char ast_config_AST_SYSTEM_NAME[20] = ""; */ /*! Go no deeper than this through includes (not counting loops) */ #define AST_PBX_MAX_STACK 128 /* static AST_RWLIST_HEAD_STATIC(acf_root, ast_custom_function); */ //extern char ast_config_AST_CONFIG_DIR[PATH_MAX]; int option_debug = 0; int option_verbose = 0; void ast_register_file_version(const char *file, const char *version); void ast_register_file_version(const char *file, const char *version) { } void ast_unregister_file_version(const char *file); void ast_unregister_file_version(const char *file) { } #if !defined(LOW_MEMORY) int ast_add_profile(const char *x, uint64_t scale) { return 0;} #endif /* Our own version of ast_log, since the expr parser uses it. -- stolen from utils/check_expr.c */ void ast_log(int level, const char *file, int line, const char *function, const char *fmt, ...) __attribute__((format(printf,5,6))); void ast_log(int level, const char *file, int line, const char *function, const char *fmt, ...) { va_list vars; va_start(vars,fmt); printf("LOG: lev:%d file:%s line:%d func: %s ", level, file, line, function); vprintf(fmt, vars); fflush(stdout); va_end(vars); } /* stolen from pbx.c */ struct ast_context; struct ast_app; #ifdef LOW_MEMORY #define EXT_DATA_SIZE 256 #else #define EXT_DATA_SIZE 8192 #endif #define SWITCH_DATA_LENGTH 256 #define VAR_BUF_SIZE 4096 #define VAR_NORMAL 1 #define VAR_SOFTTRAN 2 #define VAR_HARDTRAN 3 #define BACKGROUND_SKIP (1 << 0) #define BACKGROUND_NOANSWER (1 << 1) #define BACKGROUND_MATCHEXTEN (1 << 2) #define BACKGROUND_PLAYBACK (1 << 3) /*! \brief ast_exten: An extension The dialplan is saved as a linked list with each context having it's own linked list of extensions - one item per priority. */ struct ast_exten { char *exten; /*!< Extension name */ int matchcid; /*!< Match caller id ? */ const char *cidmatch; /*!< Caller id to match for this extension */ int priority; /*!< Priority */ const char *label; /*!< Label */ struct ast_context *parent; /*!< The context this extension belongs to */ const char *app; /*!< Application to execute */ struct ast_app *cached_app; /*!< Cached location of application */ void *data; /*!< Data to use (arguments) */ void (*datad)(void *); /*!< Data destructor */ struct ast_exten *peer; /*!< Next higher priority with our extension */ const char *registrar; /*!< Registrar */ struct ast_exten *next; /*!< Extension with a greater ID */ char stuff[0]; }; /*! \brief ast_include: include= support in extensions.conf */ struct ast_include { const char *name; const char *rname; /*!< Context to include */ const char *registrar; /*!< Registrar */ int hastime; /*!< If time construct exists */ struct ast_timing timing; /*!< time construct */ struct ast_include *next; /*!< Link them together */ char stuff[0]; }; /*! \brief ast_sw: Switch statement in extensions.conf */ struct ast_sw { char *name; const char *registrar; /*!< Registrar */ char *data; /*!< Data load */ int eval; AST_LIST_ENTRY(ast_sw) list; char *tmpdata; char stuff[0]; }; /*! \brief ast_ignorepat: Ignore patterns in dial plan */ struct ast_ignorepat { const char *registrar; struct ast_ignorepat *next; const char pattern[0]; }; /*! \brief ast_context: An extension context */ struct ast_context { ast_rwlock_t lock; /*!< A lock to prevent multiple threads from clobbering the context */ struct ast_exten *root; /*!< The root of the list of extensions */ struct ast_context *next; /*!< Link them together */ struct ast_include *includes; /*!< Include other contexts */ struct ast_ignorepat *ignorepats; /*!< Patterns for which to continue playing dialtone */ const char *registrar; /*!< Registrar */ AST_LIST_HEAD_NOLOCK(, ast_sw) alts; /*!< Alternative switches */ ast_mutex_t macrolock; /*!< A lock to implement "exclusive" macros - held whilst a call is executing in the macro */ char name[0]; /*!< Name of the context */ }; /*! \brief ast_app: A registered application */ struct ast_app { int (*execute)(struct ast_channel *chan, void *data); const char *synopsis; /*!< Synopsis text for 'show applications' */ const char *description; /*!< Description (help text) for 'show application <name>' */ AST_RWLIST_ENTRY(ast_app) list; /*!< Next app in list */ struct module *module; /*!< Module this app belongs to */ char name[0]; /*!< Name of the application */ }; /*! \brief ast_state_cb: An extension state notify register item */ struct ast_state_cb { int id; void *data; ast_state_cb_type callback; struct ast_state_cb *next; }; /*! \brief Structure for dial plan hints \note Hints are pointers from an extension in the dialplan to one or more devices (tech/name) - See \ref AstExtState */ struct ast_hint { struct ast_exten *exten; /*!< Extension */ int laststate; /*!< Last known state */ struct ast_state_cb *callbacks; /*!< Callback list for this extension */ AST_RWLIST_ENTRY(ast_hint) list;/*!< Pointer to next hint in list */ }; struct store_hint { char *context; char *exten; struct ast_state_cb *callbacks; int laststate; AST_LIST_ENTRY(store_hint) list; char data[1]; }; AST_LIST_HEAD(store_hints, store_hint); static const struct cfextension_states { int extension_state; const char * const text; } extension_states[] = { { AST_EXTENSION_NOT_INUSE, "Idle" }, { AST_EXTENSION_INUSE, "InUse" }, { AST_EXTENSION_BUSY, "Busy" }, { AST_EXTENSION_UNAVAILABLE, "Unavailable" }, { AST_EXTENSION_RINGING, "Ringing" }, { AST_EXTENSION_INUSE | AST_EXTENSION_RINGING, "InUse&Ringing" }, { AST_EXTENSION_ONHOLD, "Hold" }, { AST_EXTENSION_INUSE | AST_EXTENSION_ONHOLD, "InUse&Hold" } }; #define STATUS_NO_CONTEXT 1 #define STATUS_NO_EXTENSION 2 #define STATUS_NO_PRIORITY 3 #define STATUS_NO_LABEL 4 #define STATUS_SUCCESS 5 extern struct ast_context *local_contexts; extern struct ast_context *contexts; struct ast_custom_function *ast_custom_function_find(const char *name); struct ast_custom_function *ast_custom_function_find(const char *name) { return 0; /* in "standalone" mode, functions are just not avail */ } struct profile_entry { const char *name; uint64_t scale; /* if non-zero, values are scaled by this */ int64_t mark; int64_t value; int64_t events; }; struct profile_data { int entries; int max_size; struct profile_entry e[0]; }; static int bit_at(unsigned int *word, int bitsperword, int bitnum) { return word[bitnum/bitsperword] & (1 << (bitnum % bitsperword)); } void get_start_stop(unsigned int *word, int bitsperword, int totalbits, int *start, int *end) { int i; int thisbit, thatbit = bit_at(word, bitsperword, totalbits-1); for (i=0; iname); } printf("=========\n"); tmp = 0; while ((tmp = localized_walk_contexts(tmp)) ) { /* printf("Context: %s\n", tmp->name); */ tmptree = pvalCreateNode(PV_CONTEXT); if (!tree) tree = tmptree; else pvalTopLevAddObject(tree, tmptree); pvalContextSetName(tmptree, ast_strdup(tmp->name)); if (tmp->includes) { incl = pvalCreateNode(PV_INCLUDES); pvalContextAddStatement(tmptree, incl); for (tmpi = tmp->includes; tmpi; ) { /* includes */ if (strchr(tmpi->name,'|')==0) { if (tmpi->hastime) { char timerange[15]; char dowrange[10]; char domrange[10]; char monrange[10]; int startbit=0, endbit=0; if (all_bits_set(tmpi->timing.minmask, 30, 720)) strcpy(timerange, "*"); else { int hr, min; char tbuf[20]; get_start_stop(tmpi->timing.minmask, 30, 720, &startbit, &endbit); hr = startbit/30; min = (startbit % 30) * 2; sprintf(tbuf,"%02d:%02d", hr, min); strcpy(timerange, tbuf); hr = endbit/30; min = (endbit % 30) * 2; sprintf(tbuf,"%02d:%02d", hr, min); strcat(timerange,"-"); strcat(timerange,tbuf); } if (all_bits_set(&tmpi->timing.dowmask, 7, 7)) strcpy(dowrange, "*"); else { get_start_stop(&tmpi->timing.dowmask, 7, 7, &startbit, &endbit); strcpy(dowrange, days[startbit]); strcat(dowrange,"-"); strcat(dowrange, days[endbit]); } if (all_bits_set(&tmpi->timing.monthmask, 12, 12)) strcpy(monrange, "*"); else { get_start_stop(&tmpi->timing.monthmask, 12, 12, &startbit, &endbit); strcpy(monrange, months[startbit]); strcat(monrange,"-"); strcat(monrange, months[endbit]); } if (all_bits_set(&tmpi->timing.daymask, 31, 31)) strcpy(domrange, "*"); else { char tbuf[20]; get_start_stop(&tmpi->timing.daymask, 31, 31, &startbit, &endbit); sprintf(tbuf,"%d", startbit); strcpy(domrange, tbuf); strcat(domrange,"-"); sprintf(tbuf,"%d", endbit); strcat(domrange, tbuf); } /* now all 4 fields are set; what do we do? */ pvalIncludesAddIncludeWithTimeConstraints(incl, strdup(tmpi->name), strdup(timerange), strdup(domrange), strdup(dowrange), strdup(monrange)); } else { pvalIncludesAddInclude(incl, strdup(tmpi->name)); } } else { /* it appears the timing constraint info is tacked onto the name, carve it up and divvy it out */ char *dow,*dom,*mon; char *all = strdup(tmpi->name); char *hr = strchr(all,'|'); if (hr) { *hr++ = 0; dow = strchr(hr,'|'); if (dow) { *dow++ = 0; dom = strchr(dow,'|'); if (dom) { *dom++ = 0; mon = strchr(dom,'|'); if (mon) { *mon++ = 0; /* now all 4 fields are set; what do we do? */ pvalIncludesAddIncludeWithTimeConstraints(incl, strdup(all), strdup(hr), strdup(dow), strdup(dom), strdup(mon)); /* the original data is always best to keep (no 2-min rounding) */ } else { ast_log(LOG_ERROR,"No month spec attached to include!\n"); } } else { ast_log(LOG_ERROR,"No day of month spec attached to include!\n"); } } else { ast_log(LOG_ERROR,"No day of week spec attached to include!\n"); } } free(all); } tmpi = tmpi->next; } } for (ipi = tmp->ignorepats; ipi; ) { /* ignorepats */ incl = pvalCreateNode(PV_IGNOREPAT); pvalIgnorePatSetPattern(incl,(char *)ipi->pattern); pvalContextAddStatement(tmptree, incl); ipi = ipi->next; } eroot=0; while ( (eroot = localized_walk_context_extensions(tmp, eroot)) ) { pval *exten = pvalCreateNode(PV_EXTENSION); pvalContextAddStatement(tmptree, exten); pvalExtenSetName(exten, ast_strdup(eroot->exten)); if (eroot->peer) { pval *block = pvalCreateNode(PV_STATEMENTBLOCK); pvalExtenSetStatement(exten, block); e = 0; while ( (e = localized_walk_extension_priorities(eroot, e)) ) { pval *statemnt = pvalCreateNode(PV_APPLICATION_CALL); pval *args = pvalCreateNode(PV_WORD); /* printf(" %s(%s)\n", e->app, (char*)e->data); */ pvalAppCallSetAppName(statemnt, ast_strdup(e->app)); pvalWordSetString(args, ast_strdup(e->data)); pvalAppCallAddArg(statemnt, args); pvalStatementBlockAddStatement(block, statemnt); } } else if (eroot->priority == -1) { pval *statemnt = pvalCreateNode(PV_APPLICATION_CALL); pval *args = pvalCreateNode(PV_WORD); /* printf("Mike, we have a hint on exten %s with data %s\n", eroot->exten, eroot->app); */ pvalAppCallSetAppName(statemnt, "NoOp"); pvalWordSetString(args, ast_strdup(eroot->app)); pvalExtenSetStatement(exten, statemnt); pvalExtenSetHints(exten, ast_strdup(eroot->app)); } else { pval *statemnt = pvalCreateNode(PV_APPLICATION_CALL); pval *args = pvalCreateNode(PV_WORD); /* printf(" %s (%s)\n", eroot->app, (char *)eroot->data); */ pvalAppCallSetAppName(statemnt, ast_strdup(eroot->app)); pvalWordSetString(args, ast_strdup(eroot->data)); pvalAppCallAddArg(statemnt, args); pvalExtenSetStatement(exten, statemnt); } /* printf(" extension: %s\n", eroot->exten); */ } if (AST_LIST_FIRST(&tmp->alts)) { sws = pvalCreateNode(PV_SWITCHES); pvalContextAddStatement(tmptree,sws); sw = 0; while ((sw = localized_walk_context_switches(tmp,sw)) ) { pvalSwitchesAddSwitch(sws, ast_strdup(sw->name)); } } } printf("Generating aelout.ael file...\n"); ael2_print("aelout.ael", tree); printf("...Done!\n"); return 0; } /* ==================================== for linking internal stuff to external stuff */ int pbx_builtin_setvar(struct ast_channel *chan, void *data) { return localized_pbx_builtin_setvar(chan, data); } void pbx_substitute_variables_helper(struct ast_channel *c,const char *cp1,char *cp2,int count); void pbx_substitute_variables_helper(struct ast_channel *c,const char *cp1,char *cp2,int count) { if (cp1 && *cp1) strncpy(cp2,cp1,AST_MAX_EXTENSION); /* Right now, this routine is ONLY being called for a possible var substitution on extension names, so....! */ else *cp2 = 0; } int ast_add_extension2(struct ast_context *con, int replace, const char *extension, int priority, const char *label, const char *callerid, const char *application, void *data, void (*datad)(void *), const char *registrar) { return localized_add_extension2(con, replace, extension, priority, label, callerid, application, data, datad, registrar); } int ast_context_add_ignorepat2(struct ast_context *con, const char *value, const char *registrar) { return localized_context_add_ignorepat2(con, value, registrar); } int ast_context_add_switch2(struct ast_context *con, const char *value, const char *data, int eval, const char *registrar) { return localized_context_add_switch2(con, value, data, eval, registrar); } int ast_context_add_include2(struct ast_context *con, const char *value, const char *registrar) { return localized_context_add_include2(con, value,registrar); } struct ast_context *ast_context_find_or_create(struct ast_context **extcontexts, struct ast_hashtab *exttable, const char *name, const char *registrar) { printf("find/Creating context %s, registrar=%s\n", name, registrar); return localized_context_find_or_create(extcontexts, exttable, name, registrar); } void ast_cli_register_multiple(void); void ast_cli_register_multiple(void) { } void ast_module_register(const struct ast_module_info *x) { } void ast_module_unregister(const struct ast_module_info *x) { } void ast_cli_unregister_multiple(void); void ast_cli_unregister_multiple(void) { } struct ast_context *ast_walk_contexts(struct ast_context *con); struct ast_context *ast_walk_contexts(struct ast_context *con) { return localized_walk_contexts(con); } void ast_context_destroy(struct ast_context *con, const char *registrar); void ast_context_destroy(struct ast_context *con, const char *registrar) { return localized_context_destroy(con, registrar); } int ast_context_verify_includes(struct ast_context *con); int ast_context_verify_includes(struct ast_context *con) { return localized_context_verify_includes(con); } void ast_merge_contexts_and_delete(struct ast_context **extcontexts, struct ast_hashtab *exttable, const char *registrar); void ast_merge_contexts_and_delete(struct ast_context **extcontexts, struct ast_hashtab *exttable, const char *registrar) { localized_merge_contexts_and_delete(extcontexts, exttable, registrar); } struct ast_exten *pbx_find_extension(struct ast_channel *chan, struct ast_context *bypass, struct pbx_find_info *q, const char *context, const char *exten, int priority, const char *label, const char *callerid, enum ext_match_t action); struct ast_exten *pbx_find_extension(struct ast_channel *chan, struct ast_context *bypass, struct pbx_find_info *q, const char *context, const char *exten, int priority, const char *label, const char *callerid, enum ext_match_t action) { return localized_find_extension(bypass, q, context, exten, priority, label, callerid, action); } int ast_hashtab_compare_contexts(const void *ah_a, const void *ah_b); int ast_hashtab_compare_contexts(const void *ah_a, const void *ah_b) { return 0; } unsigned int ast_hashtab_hash_contexts(const void *obj); unsigned int ast_hashtab_hash_contexts(const void *obj) { return 0; } #ifdef DEBUG_THREADS #if !defined(LOW_MEMORY) void ast_mark_lock_acquired(void *lock_addr) { } #ifdef HAVE_BKTR void ast_remove_lock_info(void *lock_addr, struct ast_bt *bt) { } void ast_store_lock_info(enum ast_lock_type type, const char *filename, int line_num, const char *func, const char *lock_name, void *lock_addr, struct ast_bt *bt) { } int ast_bt_get_addresses(struct ast_bt *bt) { return 0; } #else void ast_remove_lock_info(void *lock_addr) { } void ast_store_lock_info(enum ast_lock_type type, const char *filename, int line_num, const char *func, const char *lock_name, void *lock_addr) { } #endif /* HAVE_BKTR */ #endif /* !defined(LOW_MEMORY) */ #endif /* DEBUG_THREADS */