2 * Asterisk -- An open source telephony toolkit.
4 * Copyright (C) 2006, 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
27 #include "asterisk/autoconfig.h"
30 #include <sys/types.h>
36 #if !defined(SOLARIS) && !defined(__CYGWIN__)
43 #include "asterisk/compat.h"
44 #include "asterisk/pbx.h"
45 #include "asterisk/ast_expr.h"
46 #include "asterisk/channel.h"
47 #include "asterisk/chanvars.h"
48 #include "asterisk/module.h"
49 #include "asterisk/app.h"
50 #include "asterisk/config.h"
51 #include "asterisk/options.h"
52 #include "asterisk/callerid.h"
53 #include "asterisk/ael_structs.h"
54 #include "asterisk/devicestate.h"
55 #include "asterisk/stringfields.h"
56 #include "asterisk/ael_structs.h"
57 #include "asterisk/pval.h"
58 #include "asterisk/extconf.h"
60 void get_start_stop(unsigned int *word, int bitsperword, int totalbits, int *start, int *end);
61 int all_bits_set(unsigned int *word, int bitsperword, int totalbits);
62 void ast_log(int level, const char *file, int line, const char *function, const char *fmt, ...)
67 printf("LOG: lev:%d file:%s line:%d func: %s ",
68 level, file, line, function);
75 extern char *months[];
76 char ast_config_AST_CONFIG_DIR[PATH_MAX];
78 char *config = "extensions.conf";
81 static char *registrar = "conf2ael";
82 static char userscontext[AST_MAX_EXTENSION] = "default";
83 static int static_config = 0;
84 static int write_protect_config = 1;
85 static int autofallthrough_config = 0;
86 static int clearglobalvars_config = 0;
87 char ast_config_AST_SYSTEM_NAME[20] = ""; */
89 /*! Go no deeper than this through includes (not counting loops) */
90 #define AST_PBX_MAX_STACK 128
91 /* static AST_RWLIST_HEAD_STATIC(acf_root, ast_custom_function); */
92 extern char ast_config_AST_CONFIG_DIR[PATH_MAX];
95 void ast_register_file_version(void);
96 void ast_unregister_file_version(void);
98 void ast_register_file_version(void)
101 printf("Executed ast_register_file_version();\n"); */
102 /* I'm erasing this, because I don't think anyone really ever needs to see it anyway */
105 void ast_unregister_file_version(void)
108 printf("Executed ast_unregister_file_version();\n"); */
109 /* I'm erasing this, because I don't think anyone really ever needs to see it anyway */
115 /* experiment 1: see if it's easier just to use existing config code
116 * to read in the extensions.conf file. In this scenario,
117 I have to rip/copy code from other modules, because they
118 are staticly declared as-is. A solution would be to move
119 the ripped code to another location and make them available
120 to other modules and standalones */
122 /* Our own version of ast_log, since the expr parser uses it. -- stolen from utils/check_expr.c */
123 void ast_log(int level, const char *file, int line, const char *function, const char *fmt, ...) __attribute__ ((format (printf,5,6)));
125 /* stolen from pbx.c */
129 #define EXT_DATA_SIZE 256
131 #define EXT_DATA_SIZE 8192
134 #define SWITCH_DATA_LENGTH 256
136 #define VAR_BUF_SIZE 4096
139 #define VAR_SOFTTRAN 2
140 #define VAR_HARDTRAN 3
142 #define BACKGROUND_SKIP (1 << 0)
143 #define BACKGROUND_NOANSWER (1 << 1)
144 #define BACKGROUND_MATCHEXTEN (1 << 2)
145 #define BACKGROUND_PLAYBACK (1 << 3)
148 \brief ast_exten: An extension
149 The dialplan is saved as a linked list with each context
150 having it's own linked list of extensions - one item per
154 char *exten; /*!< Extension name */
155 int matchcid; /*!< Match caller id ? */
156 const char *cidmatch; /*!< Caller id to match for this extension */
157 int priority; /*!< Priority */
158 const char *label; /*!< Label */
159 struct ast_context *parent; /*!< The context this extension belongs to */
160 const char *app; /*!< Application to execute */
161 struct ast_app *cached_app; /*!< Cached location of application */
162 void *data; /*!< Data to use (arguments) */
163 void (*datad)(void *); /*!< Data destructor */
164 struct ast_exten *peer; /*!< Next higher priority with our extension */
165 const char *registrar; /*!< Registrar */
166 struct ast_exten *next; /*!< Extension with a greater ID */
171 /*! \brief ast_include: include= support in extensions.conf */
174 const char *rname; /*!< Context to include */
175 const char *registrar; /*!< Registrar */
176 int hastime; /*!< If time construct exists */
177 struct ast_timing timing; /*!< time construct */
178 struct ast_include *next; /*!< Link them together */
182 /*! \brief ast_sw: Switch statement in extensions.conf */
185 const char *registrar; /*!< Registrar */
186 char *data; /*!< Data load */
188 AST_LIST_ENTRY(ast_sw) list;
193 /*! \brief ast_ignorepat: Ignore patterns in dial plan */
194 struct ast_ignorepat {
195 const char *registrar;
196 struct ast_ignorepat *next;
197 const char pattern[0];
200 /*! \brief ast_context: An extension context */
202 ast_rwlock_t lock; /*!< A lock to prevent multiple threads from clobbering the context */
203 struct ast_exten *root; /*!< The root of the list of extensions */
204 struct ast_context *next; /*!< Link them together */
205 struct ast_include *includes; /*!< Include other contexts */
206 struct ast_ignorepat *ignorepats; /*!< Patterns for which to continue playing dialtone */
207 const char *registrar; /*!< Registrar */
208 AST_LIST_HEAD_NOLOCK(, ast_sw) alts; /*!< Alternative switches */
209 ast_mutex_t macrolock; /*!< A lock to implement "exclusive" macros - held whilst a call is executing in the macro */
210 char name[0]; /*!< Name of the context */
214 /*! \brief ast_app: A registered application */
216 int (*execute)(struct ast_channel *chan, void *data);
217 const char *synopsis; /*!< Synopsis text for 'show applications' */
218 const char *description; /*!< Description (help text) for 'show application <name>' */
219 AST_RWLIST_ENTRY(ast_app) list; /*!< Next app in list */
220 struct module *module; /*!< Module this app belongs to */
221 char name[0]; /*!< Name of the application */
224 /*! \brief ast_state_cb: An extension state notify register item */
225 struct ast_state_cb {
228 ast_state_cb_type callback;
229 struct ast_state_cb *next;
232 /*! \brief Structure for dial plan hints
234 \note Hints are pointers from an extension in the dialplan to one or
235 more devices (tech/name)
236 - See \ref AstExtState
239 struct ast_exten *exten; /*!< Extension */
240 int laststate; /*!< Last known state */
241 struct ast_state_cb *callbacks; /*!< Callback list for this extension */
242 AST_RWLIST_ENTRY(ast_hint) list;/*!< Pointer to next hint in list */
248 struct ast_state_cb *callbacks;
250 AST_LIST_ENTRY(store_hint) list;
254 AST_LIST_HEAD(store_hints, store_hint);
256 static const struct cfextension_states {
258 const char * const text;
259 } extension_states[] = {
260 { AST_EXTENSION_NOT_INUSE, "Idle" },
261 { AST_EXTENSION_INUSE, "InUse" },
262 { AST_EXTENSION_BUSY, "Busy" },
263 { AST_EXTENSION_UNAVAILABLE, "Unavailable" },
264 { AST_EXTENSION_RINGING, "Ringing" },
265 { AST_EXTENSION_INUSE | AST_EXTENSION_RINGING, "InUse&Ringing" },
266 { AST_EXTENSION_ONHOLD, "Hold" },
267 { AST_EXTENSION_INUSE | AST_EXTENSION_ONHOLD, "InUse&Hold" }
269 #define STATUS_NO_CONTEXT 1
270 #define STATUS_NO_EXTENSION 2
271 #define STATUS_NO_PRIORITY 3
272 #define STATUS_NO_LABEL 4
273 #define STATUS_SUCCESS 5
275 extern struct ast_context *local_contexts;
276 extern struct ast_context *contexts;
279 struct ast_custom_function *ast_custom_function_find(const char *name);
282 struct ast_custom_function *ast_custom_function_find(const char *name)
284 return 0; /* in "standalone" mode, functions are just not avail */
288 struct profile_entry {
290 uint64_t scale; /* if non-zero, values are scaled by this */
296 struct profile_data {
299 struct profile_entry e[0];
302 static int bit_at(unsigned int *word, int bitsperword, int bitnum)
304 return word[bitnum/bitsperword] & (1 << (bitnum % bitsperword));
307 void get_start_stop(unsigned int *word, int bitsperword, int totalbits, int *start, int *end)
310 int thisbit, thatbit = bit_at(word, bitsperword, totalbits-1);
312 for (i=0; i<totalbits; i++) {
313 thisbit = bit_at(word, bitsperword, i);
315 if (thisbit != thatbit ) {
326 int all_bits_set(unsigned int *word, int bitsperword, int totalbits )
329 int i, total=totalbits/bitsperword,bitmask = 0;
331 for (i=0; i<bitsperword; i++)
336 for (i=0; i<total; i++)
338 if (word[i] != bitmask)
345 int main(int argc, char **argv)
347 struct ast_context *tmp;
348 struct ast_exten *e, *eroot;
349 pval *tree, *tmptree, *sws;
350 struct ast_include *tmpi;
351 struct ast_sw *sw = 0;
352 struct ast_ignorepat *ipi;
358 /* 3 simple steps: */
359 /* 1. read in the extensions.conf config file
360 * 2. traverse, and build an AEL tree
361 * 3. Output the AEL tree into a file
363 printf("WARNING: This is an EXTREMELY preliminary version of a program\n");
364 printf(" that will someday hopefully do a thoughful and intelligent\n");
365 printf(" job of transforming your extensions.conf file into an\n");
366 printf(" extensions.ael file.\n");
367 printf(" This version has absolutely no intelligence, and pretty\n");
368 printf(" much just does a direct conversion\n");
369 printf(" The result will most likely need careful attention to\n");
370 printf(" finish the job!!!!!\n");
373 strcpy(ast_config_AST_CONFIG_DIR,"/etc/asterisk");
375 printf("Loading %s/%s...\n", ast_config_AST_CONFIG_DIR, config);
377 localized_pbx_load_module();
379 printf("... Done!\n");
382 while ((tmp = localized_walk_contexts(tmp)) ) {
383 printf("Context: %s\n", tmp->name);
385 printf("=========\n");
386 printf("Sizeof(context)=%d\n", (int)sizeof(struct ast_context));
387 printf("Sizeof(exten)=%d\n", (int)sizeof(struct ast_exten));
388 printf("Sizeof(include)=%d\n", (int)sizeof(struct ast_include));
389 printf("Sizeof(ignorepat)=%d\n", (int)sizeof(struct ast_ignorepat));
390 printf("Sizeof(sw)=%d\n", (int)sizeof(struct ast_sw));
392 while ((tmp = localized_walk_contexts(tmp)) ) {
393 /* printf("Context: %s\n", tmp->name); */
394 tmptree = pvalCreateNode(PV_CONTEXT);
398 pvalTopLevAddObject(tree, tmptree);
400 pvalContextSetName(tmptree, ast_strdup(tmp->name));
403 incl = pvalCreateNode(PV_INCLUDES);
404 pvalContextAddStatement(tmptree, incl);
405 for (tmpi = tmp->includes; tmpi; ) { /* includes */
406 if (strchr(tmpi->name,'|')==0) {
413 int startbit=0, endbit=0;
415 if (all_bits_set(tmpi->timing.minmask, 30, 720))
416 strcpy(timerange, "*");
420 get_start_stop(tmpi->timing.minmask, 30, 720, &startbit, &endbit);
422 min = (startbit % 30) * 2;
423 sprintf(tbuf,"%02d:%02d", hr, min);
424 strcpy(timerange, tbuf);
426 min = (endbit % 30) * 2;
427 sprintf(tbuf,"%02d:%02d", hr, min);
428 strcat(timerange,"-");
429 strcat(timerange,tbuf);
432 if (all_bits_set(&tmpi->timing.dowmask, 7, 7))
433 strcpy(dowrange, "*");
435 get_start_stop(&tmpi->timing.dowmask, 7, 7, &startbit, &endbit);
436 strcpy(dowrange, days[startbit]);
437 strcat(dowrange,"-");
438 strcat(dowrange, days[endbit]);
441 if (all_bits_set(&tmpi->timing.monthmask, 12, 12))
442 strcpy(monrange, "*");
444 get_start_stop(&tmpi->timing.monthmask, 12, 12, &startbit, &endbit);
445 strcpy(monrange, months[startbit]);
446 strcat(monrange,"-");
447 strcat(monrange, months[endbit]);
450 if (all_bits_set(&tmpi->timing.daymask, 31, 31))
451 strcpy(domrange, "*");
454 get_start_stop(&tmpi->timing.daymask, 31, 31, &startbit, &endbit);
455 sprintf(tbuf,"%d", startbit);
456 strcpy(domrange, tbuf);
457 strcat(domrange,"-");
458 sprintf(tbuf,"%d", endbit);
459 strcat(domrange, tbuf);
461 /* now all 4 fields are set; what do we do? */
462 pvalIncludesAddIncludeWithTimeConstraints(incl, strdup(tmpi->name), strdup(timerange), strdup(domrange), strdup(dowrange), strdup(monrange));
465 pvalIncludesAddInclude(incl, strdup(tmpi->name));
467 } else { /* it appears the timing constraint info is tacked onto the name, carve it up and divvy it out */
469 char *all = strdup(tmpi->name);
470 char *hr = strchr(all,'|');
473 dow = strchr(hr,'|');
476 dom = strchr(dow,'|');
479 mon = strchr(dom,'|');
482 /* now all 4 fields are set; what do we do? */
483 pvalIncludesAddIncludeWithTimeConstraints(incl, all, hr, dow, dom, mon);
484 /* the original data is always best to keep (no 2-min rounding) */
486 ast_log(LOG_ERROR,"No month spec attached to include!\n");
489 ast_log(LOG_ERROR,"No day of month spec attached to include!\n");
492 ast_log(LOG_ERROR,"No day of week spec attached to include!\n");
499 for (ipi = tmp->ignorepats; ipi; ) { /* ignorepats */
500 incl = pvalCreateNode(PV_IGNOREPAT);
501 pvalIgnorePatSetPattern(incl,(char *)ipi->pattern);
502 pvalContextAddStatement(tmptree, incl);
506 while ( (eroot = localized_walk_context_extensions(tmp, eroot)) ) {
507 pval *exten = pvalCreateNode(PV_EXTENSION);
508 pvalContextAddStatement(tmptree, exten);
509 pvalExtenSetName(exten, ast_strdup(eroot->exten));
512 pval *block = pvalCreateNode(PV_STATEMENTBLOCK);
513 pvalExtenSetStatement(exten, block);
516 while ( (e = localized_walk_extension_priorities(eroot, e)) ) {
517 /* printf(" %s(%s)\n", e->app, (char*)e->data); */
519 pval *statemnt = pvalCreateNode(PV_APPLICATION_CALL);
520 pval *args = pvalCreateNode(PV_WORD);
522 pvalAppCallSetAppName(statemnt, ast_strdup(e->app));
523 pvalWordSetString(args, ast_strdup(e->data));
524 pvalAppCallAddArg(statemnt, args);
526 pvalStatementBlockAddStatement(block, statemnt);
529 pval *statemnt = pvalCreateNode(PV_APPLICATION_CALL);
530 pval *args = pvalCreateNode(PV_WORD);
532 /* printf(" %s (%s)\n", eroot->app, (char *)eroot->data); */
534 pvalAppCallSetAppName(statemnt, ast_strdup(eroot->app));
535 pvalWordSetString(args, ast_strdup(eroot->data));
538 pvalAppCallAddArg(statemnt, args);
539 pvalExtenSetStatement(exten, statemnt);
542 /* printf(" extension: %s\n", eroot->exten); */
544 if (AST_LIST_FIRST(&tmp->alts)) {
545 sws = pvalCreateNode(PV_SWITCHES);
546 pvalContextAddStatement(tmptree,sws);
549 while ((sw = localized_walk_context_switches(tmp,sw)) ) {
550 pvalSwitchesAddSwitch(sws, ast_strdup(sw->name));
554 printf("Generating aelout.ael file...\n");
556 ael2_print("aelout.ael", tree);
558 printf("...Done!\n");
563 /* ==================================== for linking internal stuff to external stuff */
565 int pbx_builtin_setvar(struct ast_channel *chan, void *data)
567 return localized_pbx_builtin_setvar(chan, data);
570 void pbx_substitute_variables_helper(struct ast_channel *c,const char *cp1,char *cp2,int count);
571 void pbx_substitute_variables_helper(struct ast_channel *c,const char *cp1,char *cp2,int count)
574 strncpy(cp2,cp1,AST_MAX_EXTENSION); /* Right now, this routine is ONLY being called for
575 a possible var substitution on extension names,
581 int ast_add_extension2(struct ast_context *con,
582 int replace, const char *extension, int priority, const char *label, const char *callerid,
583 const char *application, void *data, void (*datad)(void *),
584 const char *registrar)
586 return localized_add_extension2(con, replace, extension, priority, label, callerid, application, data, datad, registrar);
589 int ast_context_add_ignorepat2(struct ast_context *con, const char *value, const char *registrar)
592 return localized_context_add_ignorepat2(con, value, registrar);
595 int ast_context_add_switch2(struct ast_context *con, const char *value,
596 const char *data, int eval, const char *registrar)
599 return localized_context_add_switch2(con, value, data, eval, registrar);
602 int ast_context_add_include2(struct ast_context *con, const char *value,
603 const char *registrar)
606 return localized_context_add_include2(con, value,registrar);
609 struct ast_context *ast_context_create(struct ast_context **extcontexts, const char *name, const char *registrar)
611 printf("Creating context %s, registrar=%s\n", name, registrar);
613 return localized_context_create(extcontexts, name, registrar);
616 void ast_cli_register_multiple(void);
618 void ast_cli_register_multiple(void)
622 void ast_module_register(const struct ast_module_info *x)
626 void ast_module_unregister(const struct ast_module_info *x)
630 void ast_cli_unregister_multiple(void);
632 void ast_cli_unregister_multiple(void)
636 struct ast_context *ast_walk_contexts(struct ast_context *con);
637 struct ast_context *ast_walk_contexts(struct ast_context *con)
639 return localized_walk_contexts(con);
642 void ast_context_destroy(struct ast_context *con, const char *registrar);
644 void ast_context_destroy(struct ast_context *con, const char *registrar)
646 return localized_context_destroy(con, registrar);
649 int ast_context_verify_includes(struct ast_context *con);
651 int ast_context_verify_includes(struct ast_context *con)
653 return localized_context_verify_includes(con);
656 void ast_merge_contexts_and_delete(struct ast_context **extcontexts, const char *registrar);
658 void ast_merge_contexts_and_delete(struct ast_context **extcontexts, const char *registrar)
660 localized_merge_contexts_and_delete(extcontexts, registrar);
663 struct ast_exten *pbx_find_extension(struct ast_channel *chan,
664 struct ast_context *bypass,
665 struct pbx_find_info *q,
670 const char *callerid,
671 enum ext_match_t action);
673 struct ast_exten *pbx_find_extension(struct ast_channel *chan,
674 struct ast_context *bypass,
675 struct pbx_find_info *q,
680 const char *callerid,
681 enum ext_match_t action)
683 return localized_find_extension(bypass, q, context, exten, priority, label, callerid, action);