Remove extraneous copy
[asterisk/asterisk.git] / utils / conf2ael.c
1 /*  
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2007, Digium, Inc.
5  *
6  * Steve Murphy <murf@digium.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
19 /*
20  *
21  * Reverse compile extensions.conf code into prototype AEL code
22  *
23  */
24
25 /*** MODULEINFO
26         <depend>res_ael_share</depend>
27  ***/
28
29 #include "asterisk.h"
30 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
31
32 #include "asterisk/paths.h"     /* CONFIG_DIR */
33 #include <locale.h>
34 #include <ctype.h>
35 #if !defined(SOLARIS) && !defined(__CYGWIN__)
36 #include <err.h>
37 #endif
38 #include <regex.h>
39
40 #include "asterisk.h"
41 #include "asterisk/pbx.h"
42 #include "asterisk/ast_expr.h"
43 #include "asterisk/channel.h"
44 #include "asterisk/chanvars.h"
45 #include "asterisk/module.h"
46 #include "asterisk/app.h"
47 #include "asterisk/config.h"
48 #include "asterisk/options.h"
49 #include "asterisk/callerid.h"
50 #include "asterisk/ael_structs.h"
51 #include "asterisk/devicestate.h"
52 #include "asterisk/stringfields.h"
53 #include "asterisk/pval.h"
54 #include "asterisk/extconf.h"
55
56 const char *ast_config_AST_CONFIG_DIR = "/etc/asterisk";        /* placeholder */
57
58 void get_start_stop(unsigned int *word, int bitsperword, int totalbits, int *start, int *end);
59 int all_bits_set(unsigned int *word, int bitsperword, int totalbits);
60 extern char *days[];
61 extern char *months[];
62
63 char *config = "extensions.conf";
64
65 /* 
66 static char *registrar = "conf2ael";
67 static char userscontext[AST_MAX_EXTENSION] = "default";
68 static int static_config = 0;
69 static int write_protect_config = 1;
70 static int autofallthrough_config = 0;
71 static int clearglobalvars_config = 0;
72 char ast_config_AST_SYSTEM_NAME[20] = ""; */
73
74 /*! Go no deeper than this through includes (not counting loops) */
75 #define AST_PBX_MAX_STACK       128
76 /* static AST_RWLIST_HEAD_STATIC(acf_root, ast_custom_function); */
77 //extern char ast_config_AST_CONFIG_DIR[PATH_MAX];
78
79 void ast_register_file_version(const char *file, const char *version)
80 {
81 }
82
83 void ast_unregister_file_version(const char *file)
84 {
85 }
86 int ast_add_profile(const char *x, uint64_t scale) { return 0;}
87
88 /* Our own version of ast_log, since the expr parser uses it. -- stolen from utils/check_expr.c */
89 void ast_log(int level, const char *file, int line, const char *function, const char *fmt, ...) __attribute__ ((format (printf,5,6)));
90
91 void ast_log(int level, const char *file, int line, const char *function, const char *fmt, ...)
92 {
93         va_list vars;
94         va_start(vars,fmt);
95         
96         printf("LOG: lev:%d file:%s  line:%d func: %s  ",
97                    level, file, line, function);
98         vprintf(fmt, vars);
99         fflush(stdout);
100         va_end(vars);
101 }
102
103 /* stolen from pbx.c */
104 struct ast_context;
105 struct ast_app;
106 #ifdef LOW_MEMORY
107 #define EXT_DATA_SIZE 256
108 #else
109 #define EXT_DATA_SIZE 8192
110 #endif
111
112 #define SWITCH_DATA_LENGTH 256
113
114 #define VAR_BUF_SIZE 4096
115
116 #define VAR_NORMAL              1
117 #define VAR_SOFTTRAN    2
118 #define VAR_HARDTRAN    3
119
120 #define BACKGROUND_SKIP         (1 << 0)
121 #define BACKGROUND_NOANSWER     (1 << 1)
122 #define BACKGROUND_MATCHEXTEN   (1 << 2)
123 #define BACKGROUND_PLAYBACK     (1 << 3)
124
125 /*!
126    \brief ast_exten: An extension
127         The dialplan is saved as a linked list with each context
128         having it's own linked list of extensions - one item per
129         priority.
130 */
131 struct ast_exten {
132         char *exten;                    /*!< Extension name */
133         int matchcid;                   /*!< Match caller id ? */
134         const char *cidmatch;           /*!< Caller id to match for this extension */
135         int priority;                   /*!< Priority */
136         const char *label;              /*!< Label */
137         struct ast_context *parent;     /*!< The context this extension belongs to  */
138         const char *app;                /*!< Application to execute */
139         struct ast_app *cached_app;     /*!< Cached location of application */
140         void *data;                     /*!< Data to use (arguments) */
141         void (*datad)(void *);          /*!< Data destructor */
142         struct ast_exten *peer;         /*!< Next higher priority with our extension */
143         const char *registrar;          /*!< Registrar */
144         struct ast_exten *next;         /*!< Extension with a greater ID */
145         char stuff[0];
146 };
147
148
149 /*! \brief ast_include: include= support in extensions.conf */
150 struct ast_include {
151         const char *name;
152         const char *rname;                      /*!< Context to include */
153         const char *registrar;                  /*!< Registrar */
154         int hastime;                            /*!< If time construct exists */
155         struct ast_timing timing;               /*!< time construct */
156         struct ast_include *next;               /*!< Link them together */
157         char stuff[0];
158 };
159
160 /*! \brief ast_sw: Switch statement in extensions.conf */
161 struct ast_sw {
162         char *name;
163         const char *registrar;                  /*!< Registrar */
164         char *data;                             /*!< Data load */
165         int eval;
166         AST_LIST_ENTRY(ast_sw) list;
167         char *tmpdata;
168         char stuff[0];
169 };
170
171 /*! \brief ast_ignorepat: Ignore patterns in dial plan */
172 struct ast_ignorepat {
173         const char *registrar;
174         struct ast_ignorepat *next;
175         const char pattern[0];
176 };
177
178 /*! \brief ast_context: An extension context */
179 struct ast_context {
180         ast_rwlock_t lock;                      /*!< A lock to prevent multiple threads from clobbering the context */
181         struct ast_exten *root;                 /*!< The root of the list of extensions */
182         struct ast_context *next;               /*!< Link them together */
183         struct ast_include *includes;           /*!< Include other contexts */
184         struct ast_ignorepat *ignorepats;       /*!< Patterns for which to continue playing dialtone */
185         const char *registrar;                  /*!< Registrar */
186         AST_LIST_HEAD_NOLOCK(, ast_sw) alts;    /*!< Alternative switches */
187         ast_mutex_t macrolock;                  /*!< A lock to implement "exclusive" macros - held whilst a call is executing in the macro */
188         char name[0];                           /*!< Name of the context */
189 };
190
191
192 /*! \brief ast_app: A registered application */
193 struct ast_app {
194         int (*execute)(struct ast_channel *chan, void *data);
195         const char *synopsis;                   /*!< Synopsis text for 'show applications' */
196         const char *description;                /*!< Description (help text) for 'show application &lt;name&gt;' */
197         AST_RWLIST_ENTRY(ast_app) list;         /*!< Next app in list */
198         struct module *module;                  /*!< Module this app belongs to */
199         char name[0];                           /*!< Name of the application */
200 };
201
202 /*! \brief ast_state_cb: An extension state notify register item */
203 struct ast_state_cb {
204         int id;
205         void *data;
206         ast_state_cb_type callback;
207         struct ast_state_cb *next;
208 };
209
210 /*! \brief Structure for dial plan hints
211
212   \note Hints are pointers from an extension in the dialplan to one or
213   more devices (tech/name) 
214         - See \ref AstExtState
215 */
216 struct ast_hint {
217         struct ast_exten *exten;        /*!< Extension */
218         int laststate;                  /*!< Last known state */
219         struct ast_state_cb *callbacks; /*!< Callback list for this extension */
220         AST_RWLIST_ENTRY(ast_hint) list;/*!< Pointer to next hint in list */
221 };
222
223 struct store_hint {
224         char *context;
225         char *exten;
226         struct ast_state_cb *callbacks;
227         int laststate;
228         AST_LIST_ENTRY(store_hint) list;
229         char data[1];
230 };
231
232 AST_LIST_HEAD(store_hints, store_hint);
233
234 static const struct cfextension_states {
235         int extension_state;
236         const char * const text;
237 } extension_states[] = {
238         { AST_EXTENSION_NOT_INUSE,                     "Idle" },
239         { AST_EXTENSION_INUSE,                         "InUse" },
240         { AST_EXTENSION_BUSY,                          "Busy" },
241         { AST_EXTENSION_UNAVAILABLE,                   "Unavailable" },
242         { AST_EXTENSION_RINGING,                       "Ringing" },
243         { AST_EXTENSION_INUSE | AST_EXTENSION_RINGING, "InUse&Ringing" },
244         { AST_EXTENSION_ONHOLD,                        "Hold" },
245         { AST_EXTENSION_INUSE | AST_EXTENSION_ONHOLD,  "InUse&Hold" }
246 };
247 #define STATUS_NO_CONTEXT       1
248 #define STATUS_NO_EXTENSION     2
249 #define STATUS_NO_PRIORITY      3
250 #define STATUS_NO_LABEL         4
251 #define STATUS_SUCCESS          5
252
253 extern struct ast_context *local_contexts;
254 extern struct ast_context *contexts;
255
256
257 struct ast_custom_function *ast_custom_function_find(const char *name);
258
259
260 struct ast_custom_function *ast_custom_function_find(const char *name)
261 {
262         return 0; /* in "standalone" mode, functions are just not avail */
263 }
264
265
266 struct profile_entry {
267         const char *name;
268         uint64_t        scale;  /* if non-zero, values are scaled by this */
269         int64_t mark;
270         int64_t value;
271         int64_t events;
272 };
273
274 struct profile_data {
275         int entries;
276         int max_size;
277         struct profile_entry e[0];
278 };
279
280 static int bit_at(unsigned int *word, int bitsperword, int bitnum)
281 {
282         return word[bitnum/bitsperword] & (1 << (bitnum % bitsperword));
283 }
284
285 void get_start_stop(unsigned int *word, int bitsperword, int totalbits, int *start, int *end)
286 {
287         int i;
288         int thisbit, thatbit = bit_at(word, bitsperword, totalbits-1);
289         
290         for (i=0; i<totalbits; i++) {
291                 thisbit = bit_at(word, bitsperword, i);
292                 
293                 if (thisbit != thatbit ) {
294                         if (thisbit) {
295                                 *start = i;
296                         } else {
297                                 *end = i;
298                         }
299                 }
300                 thatbit = thisbit;
301         }
302 }
303
304 int all_bits_set(unsigned int *word, int bitsperword, int totalbits )
305 {
306         
307         int i, total=totalbits/bitsperword,bitmask = 0;
308         
309         for (i=0; i<bitsperword; i++)
310         {
311                 bitmask |= (1 << i);
312         }
313         
314         for (i=0; i<total; i++)
315         {
316                 if (word[i] != bitmask)
317                         return 0;
318         }
319         return 1;
320 }
321
322
323 int main(int argc, char **argv)
324 {
325         struct ast_context *tmp;
326         struct ast_exten *e, *eroot;
327         pval *tree, *tmptree, *sws;
328         struct ast_include *tmpi;
329         struct ast_sw *sw = 0;
330         struct ast_ignorepat *ipi;
331         pval *incl=0;
332         int localdir = 0, i;
333
334         tree = 0;
335         tmptree = 0;
336
337         /* process the command line args */
338         for (i=1; i<argc; i++)
339         {
340                 if (strcmp(argv[i],"-d")==0)
341                         localdir =1;
342         }
343         
344         /* 3 simple steps: */
345         /*   1. read in the extensions.conf config file 
346          *   2. traverse, and build an AEL tree
347          *   3. Output the AEL tree into a file
348          */
349         printf("WARNING: This is an EXTREMELY preliminary version of a program\n");
350         printf("         that will someday hopefully do a thoughful and intelligent\n");
351         printf("         job of transforming your extensions.conf file into an\n");
352         printf("         extensions.ael file.\n");
353         printf("         This version has absolutely no intelligence, and pretty\n");
354         printf("         much just does a direct conversion\n");
355         printf("         The result will most likely need careful attention to\n");
356         printf("         finish the job!!!!!\n");
357
358         if (!localdir)
359                 printf(" (You could use -d the use the extensions.conf in the current directory!)\n");
360
361         printf("Loading %s/%s...\n", ast_config_AST_CONFIG_DIR, config);
362
363         if (!localdir)
364                 localized_use_conf_dir();
365         localized_pbx_load_module();
366         
367         printf("... Done!\n");
368         
369         tmp = 0;
370         while ((tmp = localized_walk_contexts(tmp)) ) {
371                 printf("Context: %s\n", tmp->name);
372         }
373         printf("=========\n");
374         tmp = 0;
375         while ((tmp = localized_walk_contexts(tmp)) ) {
376                 /* printf("Context: %s\n", tmp->name); */
377                 tmptree = pvalCreateNode(PV_CONTEXT);
378                 if (!tree)
379                         tree = tmptree;
380                 else
381                         pvalTopLevAddObject(tree, tmptree);
382                 
383                 pvalContextSetName(tmptree, ast_strdup(tmp->name));
384                 
385                 if (tmp->includes) {
386                         incl = pvalCreateNode(PV_INCLUDES);
387                         pvalContextAddStatement(tmptree, incl);
388                         for (tmpi = tmp->includes; tmpi; ) { /* includes */
389                                 if (strchr(tmpi->name,'|')==0) {
390                                         if (tmpi->hastime)
391                                         {
392                                                 char timerange[15];
393                                                 char dowrange[10];
394                                                 char domrange[10];
395                                                 char monrange[10];
396                                                 int startbit=0, endbit=0;
397                                                 
398                                                 if (all_bits_set(tmpi->timing.minmask, 30, 720))
399                                                         strcpy(timerange, "*");
400                                                 else {
401                                                         int hr, min;
402                                                         char tbuf[20];
403                                                         get_start_stop(tmpi->timing.minmask, 30, 720, &startbit, &endbit);
404                                                         hr = startbit/30;
405                                                         min = (startbit % 30) * 2;
406                                                         sprintf(tbuf,"%02d:%02d", hr, min);
407                                                         strcpy(timerange, tbuf);
408                                                         hr = endbit/30;
409                                                         min = (endbit % 30) * 2;
410                                                         sprintf(tbuf,"%02d:%02d", hr, min);
411                                                         strcat(timerange,"-");
412                                                         strcat(timerange,tbuf);
413                                                 }
414                                                 
415                                                 if (all_bits_set(&tmpi->timing.dowmask, 7, 7))
416                                                         strcpy(dowrange, "*");
417                                                 else {
418                                                         get_start_stop(&tmpi->timing.dowmask, 7, 7, &startbit, &endbit);
419                                                         strcpy(dowrange, days[startbit]);
420                                                         strcat(dowrange,"-");
421                                                         strcat(dowrange, days[endbit]);
422                                                 }
423                                                 
424                                                 if (all_bits_set(&tmpi->timing.monthmask, 12, 12))
425                                                         strcpy(monrange, "*");
426                                                 else {
427                                                         get_start_stop(&tmpi->timing.monthmask, 12, 12, &startbit, &endbit);
428                                                         strcpy(monrange, months[startbit]);
429                                                         strcat(monrange,"-");
430                                                         strcat(monrange, months[endbit]);
431                                                 }
432                                                 
433                                                 if (all_bits_set(&tmpi->timing.daymask, 31, 31))
434                                                         strcpy(domrange, "*");
435                                                 else {
436                                                         char tbuf[20];
437                                                         get_start_stop(&tmpi->timing.daymask, 31, 31, &startbit, &endbit);
438                                                         sprintf(tbuf,"%d", startbit);
439                                                         strcpy(domrange, tbuf);
440                                                         strcat(domrange,"-");
441                                                         sprintf(tbuf,"%d", endbit);
442                                                         strcat(domrange, tbuf);
443                                                 }
444                                                 /* now all 4 fields are set; what do we do? */
445                                                 pvalIncludesAddIncludeWithTimeConstraints(incl, strdup(tmpi->name), strdup(timerange), strdup(domrange), strdup(dowrange), strdup(monrange));
446                                                 
447                                         } else {
448                                                 pvalIncludesAddInclude(incl, strdup(tmpi->name));
449                                         }
450                                 } else { /* it appears the timing constraint info is tacked onto the name, carve it up and divvy it out */
451                                         char *dow,*dom,*mon;
452                                         char *all = strdup(tmpi->name);
453                                         char *hr = strchr(all,'|');
454                                         if (hr) {
455                                                 *hr++ = 0;
456                                                 dow = strchr(hr,'|');
457                                                 if (dow) {
458                                                         *dow++ = 0;
459                                                         dom = strchr(dow,'|');
460                                                         if (dom) {
461                                                                 *dom++ = 0;
462                                                                 mon = strchr(dom,'|');
463                                                                 if (mon) {
464                                                                         *mon++ = 0;
465                                                                         /* now all 4 fields are set; what do we do? */
466                                                                         pvalIncludesAddIncludeWithTimeConstraints(incl, all, hr, dow, dom, mon);
467                                                                         /* the original data is always best to keep (no 2-min rounding) */
468                                                                 } else {
469                                                                         ast_log(LOG_ERROR,"No month spec attached to include!\n");
470                                                                 }
471                                                         } else {
472                                                                 ast_log(LOG_ERROR,"No day of month spec attached to include!\n");
473                                                         }
474                                                 } else {
475                                                         ast_log(LOG_ERROR,"No day of week spec attached to include!\n");
476                                                 }
477                                         }
478                                 }
479                                 tmpi = tmpi->next;
480                         }
481                 }
482                 for (ipi = tmp->ignorepats; ipi; ) { /* ignorepats */
483                         incl = pvalCreateNode(PV_IGNOREPAT);
484                         pvalIgnorePatSetPattern(incl,(char *)ipi->pattern);
485                         pvalContextAddStatement(tmptree, incl);
486                         ipi = ipi->next;
487                 }
488                 eroot=0;
489                 while ( (eroot = localized_walk_context_extensions(tmp, eroot)) ) {
490                         pval *exten = pvalCreateNode(PV_EXTENSION);
491                         pvalContextAddStatement(tmptree, exten);
492                         pvalExtenSetName(exten, ast_strdup(eroot->exten));
493                 
494                         if (eroot->peer) {
495                                 pval *block = pvalCreateNode(PV_STATEMENTBLOCK);
496                                 pvalExtenSetStatement(exten, block);
497                                 
498                                 e = 0;
499                                 while ( (e = localized_walk_extension_priorities(eroot, e)) ) {
500                                         
501                                         pval *statemnt = pvalCreateNode(PV_APPLICATION_CALL);
502                                         pval *args = pvalCreateNode(PV_WORD);
503                                         
504                                         /* printf("           %s(%s)\n", e->app, (char*)e->data); */
505
506                                         pvalAppCallSetAppName(statemnt, ast_strdup(e->app));
507                                         pvalWordSetString(args, ast_strdup(e->data));
508                                         pvalAppCallAddArg(statemnt, args);
509                                         
510                                         pvalStatementBlockAddStatement(block, statemnt);
511                                 }
512                         } else if (eroot->priority == -1) {
513
514                                 pval *statemnt = pvalCreateNode(PV_APPLICATION_CALL);
515                                 pval *args = pvalCreateNode(PV_WORD);
516
517                                 /* printf("Mike, we have a hint on exten %s with data %s\n", eroot->exten, eroot->app); */
518
519                                 pvalAppCallSetAppName(statemnt, "NoOp");
520                                 pvalWordSetString(args, ast_strdup(eroot->app));
521
522
523                                 pvalExtenSetStatement(exten, statemnt);
524                                 pvalExtenSetHints(exten, ast_strdup(eroot->app));
525                         } else {
526
527                                 pval *statemnt = pvalCreateNode(PV_APPLICATION_CALL);
528                                 pval *args = pvalCreateNode(PV_WORD);
529         
530                                 /* printf("           %s (%s)\n", eroot->app, (char *)eroot->data); */
531                                 
532                                 pvalAppCallSetAppName(statemnt, ast_strdup(eroot->app));
533                                 pvalWordSetString(args, ast_strdup(eroot->data));
534
535                                 
536                                 pvalAppCallAddArg(statemnt, args);
537                                 pvalExtenSetStatement(exten, statemnt);
538                         }
539
540                         /* printf("   extension: %s\n", eroot->exten); */
541                 }
542                 if (AST_LIST_FIRST(&tmp->alts)) {
543                         sws = pvalCreateNode(PV_SWITCHES);
544                         pvalContextAddStatement(tmptree,sws);
545                         
546                         sw = 0;
547                         while ((sw = localized_walk_context_switches(tmp,sw)) ) {
548                                 pvalSwitchesAddSwitch(sws, ast_strdup(sw->name));
549                         }
550                 }
551         }
552         printf("Generating aelout.ael file...\n");
553         
554         ael2_print("aelout.ael", tree);
555         
556         printf("...Done!\n");
557         return 0;
558 }
559
560
561 /* ==================================== for linking internal stuff to external stuff */
562
563 int pbx_builtin_setvar(struct ast_channel *chan, void *data)
564 {
565         return localized_pbx_builtin_setvar(chan, data);
566 }
567
568 void pbx_substitute_variables_helper(struct ast_channel *c,const char *cp1,char *cp2,int count);
569 void pbx_substitute_variables_helper(struct ast_channel *c,const char *cp1,char *cp2,int count)
570 {
571         if (cp1 && *cp1)
572                 strncpy(cp2,cp1,AST_MAX_EXTENSION); /* Right now, this routine is ONLY being called for 
573                                                                                            a possible var substitution on extension names,
574                                                                                            so....! */
575         else
576                 *cp2 = 0;
577 }
578
579 int ast_add_extension2(struct ast_context *con,
580                                            int replace, const char *extension, int priority, const char *label, const char *callerid,
581                                            const char *application, void *data, void (*datad)(void *),
582                                            const char *registrar)
583 {
584         return localized_add_extension2(con, replace, extension, priority, label, callerid, application, data, datad, registrar);
585 }
586
587 int ast_context_add_ignorepat2(struct ast_context *con, const char *value, const char *registrar)
588 {
589         
590         return localized_context_add_ignorepat2(con, value, registrar);
591 }
592
593 int ast_context_add_switch2(struct ast_context *con, const char *value,
594                                                                  const char *data, int eval, const char *registrar)
595 {
596         
597         return localized_context_add_switch2(con, value, data, eval, registrar);
598 }
599
600 int ast_context_add_include2(struct ast_context *con, const char *value,
601                                                                   const char *registrar)
602 {
603         
604         return localized_context_add_include2(con, value,registrar);
605 }
606
607 struct ast_context *ast_context_create(struct ast_context **extcontexts, const char *name, const char *registrar)
608 {
609         printf("Creating context %s, registrar=%s\n", name, registrar);
610         
611         return localized_context_create(extcontexts, name, registrar);
612 }
613
614 struct ast_context *ast_context_find_or_create(struct ast_context **extcontexts, const char *name, const char *registrar)
615 {
616         printf("find/Creating context %s, registrar=%s\n", name, registrar);
617         
618         return localized_context_create(extcontexts, name, registrar);
619 }
620
621 void ast_cli_register_multiple(void);
622
623 void ast_cli_register_multiple(void)
624 {
625 }
626
627 void ast_module_register(const struct ast_module_info *x)
628 {
629 }
630
631 void ast_module_unregister(const struct ast_module_info *x)
632 {
633 }
634
635 void ast_cli_unregister_multiple(void);
636
637 void ast_cli_unregister_multiple(void)
638 {
639 }
640
641 struct ast_context *ast_walk_contexts(struct ast_context *con);
642 struct ast_context *ast_walk_contexts(struct ast_context *con)
643 {
644         return localized_walk_contexts(con);
645 }
646
647 void ast_context_destroy(struct ast_context *con, const char *registrar);
648
649 void ast_context_destroy(struct ast_context *con, const char *registrar)
650 {
651         return localized_context_destroy(con, registrar);
652 }
653
654 int ast_context_verify_includes(struct ast_context *con);
655
656 int ast_context_verify_includes(struct ast_context *con)
657 {
658         return  localized_context_verify_includes(con);
659 }
660
661 void ast_merge_contexts_and_delete(struct ast_context **extcontexts, const char *registrar);
662
663 void ast_merge_contexts_and_delete(struct ast_context **extcontexts, const char *registrar)
664 {
665         localized_merge_contexts_and_delete(extcontexts, registrar);
666 }
667
668 struct ast_exten *pbx_find_extension(struct ast_channel *chan,
669                                                                          struct ast_context *bypass,
670                                                                          struct pbx_find_info *q,
671                                                                          const char *context, 
672                                                                          const char *exten, 
673                                                                          int priority,
674                                                                          const char *label, 
675                                                                          const char *callerid, 
676                                                                          enum ext_match_t action);
677
678 struct ast_exten *pbx_find_extension(struct ast_channel *chan,
679                                                                          struct ast_context *bypass,
680                                                                          struct pbx_find_info *q,
681                                                                          const char *context, 
682                                                                          const char *exten, 
683                                                                          int priority,
684                                                                          const char *label, 
685                                                                          const char *callerid, 
686                                                                          enum ext_match_t action)
687 {
688         return localized_find_extension(bypass, q, context, exten, priority, label, callerid, action);
689 }
690