2 * Asterisk -- An open source telephony toolkit.
4 * Copyright (C) 2007, Digium, Inc.
6 * Steve Murphy <murf@digium.com>
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.
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.
21 * Reverse compile extensions.conf code into prototype AEL code
26 <depend>res_ael_share</depend>
27 <support_level>extended</support_level>
31 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
33 #include "asterisk/paths.h" /* CONFIG_DIR */
36 #if !defined(SOLARIS) && !defined(__CYGWIN__)
42 #include "asterisk/pbx.h"
43 #include "asterisk/ast_expr.h"
44 #include "asterisk/channel.h"
45 #include "asterisk/chanvars.h"
46 #include "asterisk/module.h"
47 #include "asterisk/app.h"
48 #include "asterisk/config.h"
49 #include "asterisk/options.h"
50 #include "asterisk/callerid.h"
51 #include "asterisk/lock.h"
52 #include "asterisk/hashtab.h"
53 #include "asterisk/ael_structs.h"
54 #include "asterisk/devicestate.h"
55 #include "asterisk/stringfields.h"
56 #include "asterisk/pval.h"
57 #include "asterisk/extconf.h"
59 struct ast_flags ast_compat = { 7 };
60 const char *ast_config_AST_CONFIG_DIR = "/etc/asterisk"; /* placeholder */
62 void get_start_stop(unsigned int *word, int bitsperword, int totalbits, int *start, int *end);
63 int all_bits_set(unsigned int *word, int bitsperword, int totalbits);
65 extern char *months[];
67 char *config = "extensions.conf";
70 static char *registrar = "conf2ael";
71 static char userscontext[AST_MAX_EXTENSION] = "default";
72 static int static_config = 0;
73 static int write_protect_config = 1;
74 static int autofallthrough_config = 0;
75 static int clearglobalvars_config = 0;
76 char ast_config_AST_SYSTEM_NAME[20] = ""; */
78 /*! Go no deeper than this through includes (not counting loops) */
79 #define AST_PBX_MAX_STACK 128
80 /* static AST_RWLIST_HEAD_STATIC(acf_root, ast_custom_function); */
81 //extern char ast_config_AST_CONFIG_DIR[PATH_MAX];
83 int option_verbose = 0;
85 void ast_register_file_version(const char *file, const char *version);
86 void ast_register_file_version(const char *file, const char *version)
90 void ast_unregister_file_version(const char *file);
91 void ast_unregister_file_version(const char *file)
94 #if !defined(LOW_MEMORY)
95 int ast_add_profile(const char *x, uint64_t scale) { return 0;}
97 /* Our own version of ast_log, since the expr parser uses it. -- stolen from utils/check_expr.c */
98 void ast_log(int level, const char *file, int line, const char *function, const char *fmt, ...) __attribute__((format(printf,5,6)));
100 void ast_log(int level, const char *file, int line, const char *function, const char *fmt, ...)
105 printf("LOG: lev:%d file:%s line:%d func: %s ",
106 level, file, line, function);
112 /* stolen from pbx.c */
116 #define EXT_DATA_SIZE 256
118 #define EXT_DATA_SIZE 8192
121 #define SWITCH_DATA_LENGTH 256
123 #define VAR_BUF_SIZE 4096
126 #define VAR_SOFTTRAN 2
127 #define VAR_HARDTRAN 3
129 #define BACKGROUND_SKIP (1 << 0)
130 #define BACKGROUND_NOANSWER (1 << 1)
131 #define BACKGROUND_MATCHEXTEN (1 << 2)
132 #define BACKGROUND_PLAYBACK (1 << 3)
135 \brief ast_exten: An extension
136 The dialplan is saved as a linked list with each context
137 having it's own linked list of extensions - one item per
141 char *exten; /*!< Extension name */
142 int matchcid; /*!< Match caller id ? */
143 const char *cidmatch; /*!< Caller id to match for this extension */
144 int priority; /*!< Priority */
145 const char *label; /*!< Label */
146 struct ast_context *parent; /*!< The context this extension belongs to */
147 const char *app; /*!< Application to execute */
148 struct ast_app *cached_app; /*!< Cached location of application */
149 void *data; /*!< Data to use (arguments) */
150 void (*datad)(void *); /*!< Data destructor */
151 struct ast_exten *peer; /*!< Next higher priority with our extension */
152 const char *registrar; /*!< Registrar */
153 struct ast_exten *next; /*!< Extension with a greater ID */
158 /*! \brief ast_include: include= support in extensions.conf */
161 const char *rname; /*!< Context to include */
162 const char *registrar; /*!< Registrar */
163 int hastime; /*!< If time construct exists */
164 struct ast_timing timing; /*!< time construct */
165 struct ast_include *next; /*!< Link them together */
169 /*! \brief ast_sw: Switch statement in extensions.conf */
172 const char *registrar; /*!< Registrar */
173 char *data; /*!< Data load */
175 AST_LIST_ENTRY(ast_sw) list;
180 /*! \brief ast_ignorepat: Ignore patterns in dial plan */
181 struct ast_ignorepat {
182 const char *registrar;
183 struct ast_ignorepat *next;
184 const char pattern[0];
187 /*! \brief ast_context: An extension context */
189 ast_rwlock_t lock; /*!< A lock to prevent multiple threads from clobbering the context */
190 struct ast_exten *root; /*!< The root of the list of extensions */
191 struct ast_context *next; /*!< Link them together */
192 struct ast_include *includes; /*!< Include other contexts */
193 struct ast_ignorepat *ignorepats; /*!< Patterns for which to continue playing dialtone */
194 const char *registrar; /*!< Registrar */
195 AST_LIST_HEAD_NOLOCK(, ast_sw) alts; /*!< Alternative switches */
196 ast_mutex_t macrolock; /*!< A lock to implement "exclusive" macros - held whilst a call is executing in the macro */
197 char name[0]; /*!< Name of the context */
201 /*! \brief ast_app: A registered application */
203 int (*execute)(struct ast_channel *chan, void *data);
204 const char *synopsis; /*!< Synopsis text for 'show applications' */
205 const char *description; /*!< Description (help text) for 'show application <name>' */
206 AST_RWLIST_ENTRY(ast_app) list; /*!< Next app in list */
207 struct module *module; /*!< Module this app belongs to */
208 char name[0]; /*!< Name of the application */
211 /*! \brief ast_state_cb: An extension state notify register item */
212 struct ast_state_cb {
215 ast_state_cb_type callback;
216 struct ast_state_cb *next;
219 /*! \brief Structure for dial plan hints
221 \note Hints are pointers from an extension in the dialplan to one or
222 more devices (tech/name)
223 - See \ref AstExtState
226 struct ast_exten *exten; /*!< Extension */
227 int laststate; /*!< Last known state */
228 struct ast_state_cb *callbacks; /*!< Callback list for this extension */
229 AST_RWLIST_ENTRY(ast_hint) list;/*!< Pointer to next hint in list */
235 struct ast_state_cb *callbacks;
237 AST_LIST_ENTRY(store_hint) list;
241 AST_LIST_HEAD(store_hints, store_hint);
243 static const struct cfextension_states {
245 const char * const text;
246 } extension_states[] = {
247 { AST_EXTENSION_NOT_INUSE, "Idle" },
248 { AST_EXTENSION_INUSE, "InUse" },
249 { AST_EXTENSION_BUSY, "Busy" },
250 { AST_EXTENSION_UNAVAILABLE, "Unavailable" },
251 { AST_EXTENSION_RINGING, "Ringing" },
252 { AST_EXTENSION_INUSE | AST_EXTENSION_RINGING, "InUse&Ringing" },
253 { AST_EXTENSION_ONHOLD, "Hold" },
254 { AST_EXTENSION_INUSE | AST_EXTENSION_ONHOLD, "InUse&Hold" }
256 #define STATUS_NO_CONTEXT 1
257 #define STATUS_NO_EXTENSION 2
258 #define STATUS_NO_PRIORITY 3
259 #define STATUS_NO_LABEL 4
260 #define STATUS_SUCCESS 5
262 extern struct ast_context *local_contexts;
263 extern struct ast_context *contexts;
266 struct ast_custom_function *ast_custom_function_find(const char *name);
269 struct ast_custom_function *ast_custom_function_find(const char *name)
271 return 0; /* in "standalone" mode, functions are just not avail */
275 struct profile_entry {
277 uint64_t scale; /* if non-zero, values are scaled by this */
283 struct profile_data {
286 struct profile_entry e[0];
289 static int bit_at(unsigned int *word, int bitsperword, int bitnum)
291 return word[bitnum/bitsperword] & (1 << (bitnum % bitsperword));
294 void get_start_stop(unsigned int *word, int bitsperword, int totalbits, int *start, int *end)
297 int thisbit, thatbit = bit_at(word, bitsperword, totalbits-1);
299 for (i=0; i<totalbits; i++) {
300 thisbit = bit_at(word, bitsperword, i);
302 if (thisbit != thatbit ) {
313 int all_bits_set(unsigned int *word, int bitsperword, int totalbits )
316 int i, total=totalbits/bitsperword,bitmask = 0;
318 for (i=0; i<bitsperword; i++)
323 for (i=0; i<total; i++)
325 if (word[i] != bitmask)
332 int main(int argc, char **argv)
334 struct ast_context *tmp;
335 struct ast_exten *e, *eroot;
336 pval *tree, *tmptree, *sws;
337 struct ast_include *tmpi;
338 struct ast_sw *sw = 0;
339 struct ast_ignorepat *ipi;
346 /* process the command line args */
347 for (i=1; i<argc; i++)
349 if (strcmp(argv[i],"-d")==0)
353 /* 3 simple steps: */
354 /* 1. read in the extensions.conf config file
355 * 2. traverse, and build an AEL tree
356 * 3. Output the AEL tree into a file
358 printf("WARNING: This is an EXTREMELY preliminary version of a program\n");
359 printf(" that will someday hopefully do a thoughful and intelligent\n");
360 printf(" job of transforming your extensions.conf file into an\n");
361 printf(" extensions.ael file.\n");
362 printf(" This version has absolutely no intelligence, and pretty\n");
363 printf(" much just does a direct conversion\n");
364 printf(" The result will most likely need careful attention to\n");
365 printf(" finish the job!!!!!\n");
368 printf(" (You could use -d the use the extensions.conf in the current directory!)\n");
370 printf("Loading %s/%s...\n", ast_config_AST_CONFIG_DIR, config);
373 localized_use_conf_dir();
374 localized_pbx_load_module();
376 printf("... Done!\n");
379 while ((tmp = localized_walk_contexts(tmp)) ) {
380 printf("Context: %s\n", tmp->name);
382 printf("=========\n");
384 while ((tmp = localized_walk_contexts(tmp)) ) {
385 /* printf("Context: %s\n", tmp->name); */
386 tmptree = pvalCreateNode(PV_CONTEXT);
390 pvalTopLevAddObject(tree, tmptree);
392 pvalContextSetName(tmptree, ast_strdup(tmp->name));
395 incl = pvalCreateNode(PV_INCLUDES);
396 pvalContextAddStatement(tmptree, incl);
397 for (tmpi = tmp->includes; tmpi; ) { /* includes */
398 if (strchr(tmpi->name,'|')==0) {
405 int startbit=0, endbit=0;
407 if (all_bits_set(tmpi->timing.minmask, 30, 720))
408 strcpy(timerange, "*");
412 get_start_stop(tmpi->timing.minmask, 30, 720, &startbit, &endbit);
414 min = (startbit % 30) * 2;
415 sprintf(tbuf,"%02d:%02d", hr, min);
416 strcpy(timerange, tbuf);
418 min = (endbit % 30) * 2;
419 sprintf(tbuf,"%02d:%02d", hr, min);
420 strcat(timerange,"-");
421 strcat(timerange,tbuf);
424 if (all_bits_set(&tmpi->timing.dowmask, 7, 7))
425 strcpy(dowrange, "*");
427 get_start_stop(&tmpi->timing.dowmask, 7, 7, &startbit, &endbit);
428 strcpy(dowrange, days[startbit]);
429 strcat(dowrange,"-");
430 strcat(dowrange, days[endbit]);
433 if (all_bits_set(&tmpi->timing.monthmask, 12, 12))
434 strcpy(monrange, "*");
436 get_start_stop(&tmpi->timing.monthmask, 12, 12, &startbit, &endbit);
437 strcpy(monrange, months[startbit]);
438 strcat(monrange,"-");
439 strcat(monrange, months[endbit]);
442 if (all_bits_set(&tmpi->timing.daymask, 31, 31))
443 strcpy(domrange, "*");
446 get_start_stop(&tmpi->timing.daymask, 31, 31, &startbit, &endbit);
447 sprintf(tbuf,"%d", startbit);
448 strcpy(domrange, tbuf);
449 strcat(domrange,"-");
450 sprintf(tbuf,"%d", endbit);
451 strcat(domrange, tbuf);
453 /* now all 4 fields are set; what do we do? */
454 pvalIncludesAddIncludeWithTimeConstraints(incl, strdup(tmpi->name), strdup(timerange), strdup(domrange), strdup(dowrange), strdup(monrange));
457 pvalIncludesAddInclude(incl, strdup(tmpi->name));
459 } else { /* it appears the timing constraint info is tacked onto the name, carve it up and divvy it out */
461 char *all = strdup(tmpi->name);
462 char *hr = strchr(all,'|');
465 dow = strchr(hr,'|');
468 dom = strchr(dow,'|');
471 mon = strchr(dom,'|');
474 /* now all 4 fields are set; what do we do? */
475 pvalIncludesAddIncludeWithTimeConstraints(incl, strdup(all), strdup(hr), strdup(dow), strdup(dom), strdup(mon));
476 /* the original data is always best to keep (no 2-min rounding) */
478 ast_log(LOG_ERROR,"No month spec attached to include!\n");
481 ast_log(LOG_ERROR,"No day of month spec attached to include!\n");
484 ast_log(LOG_ERROR,"No day of week spec attached to include!\n");
492 for (ipi = tmp->ignorepats; ipi; ) { /* ignorepats */
493 incl = pvalCreateNode(PV_IGNOREPAT);
494 pvalIgnorePatSetPattern(incl,(char *)ipi->pattern);
495 pvalContextAddStatement(tmptree, incl);
499 while ( (eroot = localized_walk_context_extensions(tmp, eroot)) ) {
500 pval *exten = pvalCreateNode(PV_EXTENSION);
501 pvalContextAddStatement(tmptree, exten);
502 pvalExtenSetName(exten, ast_strdup(eroot->exten));
505 pval *block = pvalCreateNode(PV_STATEMENTBLOCK);
506 pvalExtenSetStatement(exten, block);
509 while ( (e = localized_walk_extension_priorities(eroot, e)) ) {
511 pval *statemnt = pvalCreateNode(PV_APPLICATION_CALL);
512 pval *args = pvalCreateNode(PV_WORD);
514 /* printf(" %s(%s)\n", e->app, (char*)e->data); */
516 pvalAppCallSetAppName(statemnt, ast_strdup(e->app));
517 pvalWordSetString(args, ast_strdup(e->data));
518 pvalAppCallAddArg(statemnt, args);
520 pvalStatementBlockAddStatement(block, statemnt);
522 } else if (eroot->priority == -1) {
524 pval *statemnt = pvalCreateNode(PV_APPLICATION_CALL);
525 pval *args = pvalCreateNode(PV_WORD);
527 /* printf("Mike, we have a hint on exten %s with data %s\n", eroot->exten, eroot->app); */
529 pvalAppCallSetAppName(statemnt, "NoOp");
530 pvalWordSetString(args, ast_strdup(eroot->app));
533 pvalExtenSetStatement(exten, statemnt);
534 pvalExtenSetHints(exten, ast_strdup(eroot->app));
537 pval *statemnt = pvalCreateNode(PV_APPLICATION_CALL);
538 pval *args = pvalCreateNode(PV_WORD);
540 /* printf(" %s (%s)\n", eroot->app, (char *)eroot->data); */
542 pvalAppCallSetAppName(statemnt, ast_strdup(eroot->app));
543 pvalWordSetString(args, ast_strdup(eroot->data));
546 pvalAppCallAddArg(statemnt, args);
547 pvalExtenSetStatement(exten, statemnt);
550 /* printf(" extension: %s\n", eroot->exten); */
552 if (AST_LIST_FIRST(&tmp->alts)) {
553 sws = pvalCreateNode(PV_SWITCHES);
554 pvalContextAddStatement(tmptree,sws);
557 while ((sw = localized_walk_context_switches(tmp,sw)) ) {
558 pvalSwitchesAddSwitch(sws, ast_strdup(sw->name));
562 printf("Generating aelout.ael file...\n");
564 ael2_print("aelout.ael", tree);
566 printf("...Done!\n");
571 /* ==================================== for linking internal stuff to external stuff */
573 int pbx_builtin_setvar(struct ast_channel *chan, const char *data)
575 return localized_pbx_builtin_setvar(chan, data);
578 void pbx_substitute_variables_helper(struct ast_channel *c,const char *cp1,char *cp2,int count);
579 void pbx_substitute_variables_helper(struct ast_channel *c,const char *cp1,char *cp2,int count)
582 strncpy(cp2,cp1,AST_MAX_EXTENSION); /* Right now, this routine is ONLY being called for
583 a possible var substitution on extension names,
589 int ast_add_extension2(struct ast_context *con,
590 int replace, const char *extension, int priority, const char *label, const char *callerid,
591 const char *application, void *data, void (*datad)(void *),
592 const char *registrar)
594 return localized_add_extension2(con, replace, extension, priority, label, callerid, application, data, datad, registrar);
597 int ast_context_add_ignorepat2(struct ast_context *con, const char *value, const char *registrar)
600 return localized_context_add_ignorepat2(con, value, registrar);
603 int ast_context_add_switch2(struct ast_context *con, const char *value,
604 const char *data, int eval, const char *registrar)
607 return localized_context_add_switch2(con, value, data, eval, registrar);
610 int ast_context_add_include2(struct ast_context *con, const char *value,
611 const char *registrar)
614 return localized_context_add_include2(con, value,registrar);
617 struct ast_context *ast_context_find_or_create(struct ast_context **extcontexts, struct ast_hashtab *exttable, const char *name, const char *registrar)
619 printf("find/Creating context %s, registrar=%s\n", name, registrar);
621 return localized_context_find_or_create(extcontexts, exttable, name, registrar);
624 void ast_cli_register_multiple(void);
626 void ast_cli_register_multiple(void)
630 void ast_module_register(const struct ast_module_info *x)
634 void ast_module_unregister(const struct ast_module_info *x)
638 void ast_cli_unregister_multiple(void);
640 void ast_cli_unregister_multiple(void)
644 struct ast_context *ast_walk_contexts(struct ast_context *con);
645 struct ast_context *ast_walk_contexts(struct ast_context *con)
647 return localized_walk_contexts(con);
650 void ast_context_destroy(struct ast_context *con, const char *registrar);
652 void ast_context_destroy(struct ast_context *con, const char *registrar)
654 return localized_context_destroy(con, registrar);
657 int ast_context_verify_includes(struct ast_context *con);
659 int ast_context_verify_includes(struct ast_context *con)
661 return localized_context_verify_includes(con);
664 void ast_merge_contexts_and_delete(struct ast_context **extcontexts, struct ast_hashtab *exttable, const char *registrar);
666 void ast_merge_contexts_and_delete(struct ast_context **extcontexts, struct ast_hashtab *exttable, const char *registrar)
668 localized_merge_contexts_and_delete(extcontexts, exttable, registrar);
671 const char *ast_get_context_name(struct ast_context *con);
672 const char *ast_get_context_name(struct ast_context *con)
674 return con ? con->name : NULL;
677 struct ast_exten *ast_walk_context_extensions(struct ast_context *con, struct ast_exten *exten);
678 struct ast_exten *ast_walk_context_extensions(struct ast_context *con, struct ast_exten *exten)
683 struct ast_include *ast_walk_context_includes(struct ast_context *con, struct ast_include *inc);
684 struct ast_include *ast_walk_context_includes(struct ast_context *con, struct ast_include *inc)
689 struct ast_ignorepat *ast_walk_context_ignorepats(struct ast_context *con, struct ast_ignorepat *ip);
690 struct ast_ignorepat *ast_walk_context_ignorepats(struct ast_context *con, struct ast_ignorepat *ip)
695 struct ast_sw *ast_walk_context_switches(struct ast_context *con, struct ast_sw *sw);
696 struct ast_sw *ast_walk_context_switches(struct ast_context *con, struct ast_sw *sw)
701 struct ast_exten *pbx_find_extension(struct ast_channel *chan,
702 struct ast_context *bypass,
703 struct pbx_find_info *q,
708 const char *callerid,
709 enum ext_match_t action);
711 struct ast_exten *pbx_find_extension(struct ast_channel *chan,
712 struct ast_context *bypass,
713 struct pbx_find_info *q,
718 const char *callerid,
719 enum ext_match_t action)
721 return localized_find_extension(bypass, q, context, exten, priority, label, callerid, action);
724 int ast_hashtab_compare_contexts(const void *ah_a, const void *ah_b);
726 int ast_hashtab_compare_contexts(const void *ah_a, const void *ah_b)
731 unsigned int ast_hashtab_hash_contexts(const void *obj);
733 unsigned int ast_hashtab_hash_contexts(const void *obj)
739 #if !defined(LOW_MEMORY)
740 void ast_mark_lock_acquired(void *lock_addr)
744 void ast_remove_lock_info(void *lock_addr, struct ast_bt *bt)
748 void ast_store_lock_info(enum ast_lock_type type, const char *filename,
749 int line_num, const char *func, const char *lock_name, void *lock_addr, struct ast_bt *bt)
753 int ast_bt_get_addresses(struct ast_bt *bt)
758 char **ast_bt_get_symbols(void **addresses, size_t num_frames)
760 char **foo = calloc(num_frames, sizeof(char *) + 1);
763 for (i = 0; i < num_frames; i++) {
764 foo[i] = (char *) foo + sizeof(char *) * num_frames;
771 void ast_remove_lock_info(void *lock_addr)
775 void ast_store_lock_info(enum ast_lock_type type, const char *filename,
776 int line_num, const char *func, const char *lock_name, void *lock_addr)
779 #endif /* HAVE_BKTR */
780 #endif /* !defined(LOW_MEMORY) */
781 #endif /* DEBUG_THREADS */