Make conf2ael build on 64-bit systems.
[asterisk/asterisk.git] / utils / conf2ael.c
1 /*  
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2006, 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
26
27 #include "asterisk/autoconfig.h"
28
29 #include <stdio.h>
30 #include <sys/types.h>
31 #include <stdlib.h>
32 #include <stdarg.h>
33 #include <string.h>
34 #include <locale.h>
35 #include <ctype.h>
36 #if !defined(SOLARIS) && !defined(__CYGWIN__)
37 #include <err.h>
38 #endif
39 #include <errno.h>
40 #include <regex.h>
41 #include <limits.h>
42
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"
59
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, ...)
63 {
64                 va_list vars;
65                         va_start(vars,fmt);
66                         
67                                 printf("LOG: lev:%d file:%s  line:%d func: %s  ",
68                                                                    level, file, line, function);
69                                         vprintf(fmt, vars);
70                                                 fflush(stdout);
71                                                         va_end(vars);
72 }
73
74 extern char *days[];
75 extern char *months[];
76 char ast_config_AST_CONFIG_DIR[PATH_MAX];
77
78 char *config = "extensions.conf";
79
80 /* 
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] = ""; */
88
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];
93
94 /* modulation */
95 void ast_register_file_version(void);
96 void ast_unregister_file_version(void);
97
98 void ast_register_file_version(void)
99 {
100         /* if(!no_comp)
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 */
103 }
104
105 void ast_unregister_file_version(void)
106 {
107         /* if(!no_comp)
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 */
110
111 }
112
113
114
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 */
121
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)));
124
125 /* stolen from pbx.c */
126 struct ast_context;
127 struct ast_app;
128 #ifdef LOW_MEMORY
129 #define EXT_DATA_SIZE 256
130 #else
131 #define EXT_DATA_SIZE 8192
132 #endif
133
134 #define SWITCH_DATA_LENGTH 256
135
136 #define VAR_BUF_SIZE 4096
137
138 #define VAR_NORMAL              1
139 #define VAR_SOFTTRAN    2
140 #define VAR_HARDTRAN    3
141
142 #define BACKGROUND_SKIP         (1 << 0)
143 #define BACKGROUND_NOANSWER     (1 << 1)
144 #define BACKGROUND_MATCHEXTEN   (1 << 2)
145 #define BACKGROUND_PLAYBACK     (1 << 3)
146
147 /*!
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
151         priority.
152 */
153 struct ast_exten {
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 */
167         char stuff[0];
168 };
169
170
171 /*! \brief ast_include: include= support in extensions.conf */
172 struct ast_include {
173         const char *name;
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 */
179         char stuff[0];
180 };
181
182 /*! \brief ast_sw: Switch statement in extensions.conf */
183 struct ast_sw {
184         char *name;
185         const char *registrar;                  /*!< Registrar */
186         char *data;                             /*!< Data load */
187         int eval;
188         AST_LIST_ENTRY(ast_sw) list;
189         char *tmpdata;
190         char stuff[0];
191 };
192
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];
198 };
199
200 /*! \brief ast_context: An extension context */
201 struct ast_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 */
211 };
212
213
214 /*! \brief ast_app: A registered application */
215 struct ast_app {
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 &lt;name&gt;' */
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 */
222 };
223
224 /*! \brief ast_state_cb: An extension state notify register item */
225 struct ast_state_cb {
226         int id;
227         void *data;
228         ast_state_cb_type callback;
229         struct ast_state_cb *next;
230 };
231
232 /*! \brief Structure for dial plan hints
233
234   \note Hints are pointers from an extension in the dialplan to one or
235   more devices (tech/name) 
236         - See \ref AstExtState
237 */
238 struct ast_hint {
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 */
243 };
244
245 struct store_hint {
246         char *context;
247         char *exten;
248         struct ast_state_cb *callbacks;
249         int laststate;
250         AST_LIST_ENTRY(store_hint) list;
251         char data[1];
252 };
253
254 AST_LIST_HEAD(store_hints, store_hint);
255
256 static const struct cfextension_states {
257         int extension_state;
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" }
268 };
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
274
275 extern struct ast_context *local_contexts;
276 extern struct ast_context *contexts;
277
278
279 struct ast_custom_function *ast_custom_function_find(const char *name);
280
281
282 struct ast_custom_function *ast_custom_function_find(const char *name)
283 {
284         return 0; /* in "standalone" mode, functions are just not avail */
285 }
286
287
288 struct profile_entry {
289         const char *name;
290         uint64_t        scale;  /* if non-zero, values are scaled by this */
291         int64_t mark;
292         int64_t value;
293         int64_t events;
294 };
295
296 struct profile_data {
297         int entries;
298         int max_size;
299         struct profile_entry e[0];
300 };
301
302 static int bit_at(unsigned int *word, int bitsperword, int bitnum)
303 {
304         return word[bitnum/bitsperword] & (1 << (bitnum % bitsperword));
305 }
306
307 void get_start_stop(unsigned int *word, int bitsperword, int totalbits, int *start, int *end)
308 {
309         int i;
310         int thisbit, thatbit = bit_at(word, bitsperword, totalbits-1);
311         
312         for (i=0; i<totalbits; i++) {
313                 thisbit = bit_at(word, bitsperword, i);
314                 
315                 if (thisbit != thatbit ) {
316                         if (thisbit) {
317                                 *start = i;
318                         } else {
319                                 *end = i;
320                         }
321                 }
322                 thatbit = thisbit;
323         }
324 }
325
326 int all_bits_set(unsigned int *word, int bitsperword, int totalbits )
327 {
328         
329         int i, total=totalbits/bitsperword,bitmask = 0;
330         
331         for (i=0; i<bitsperword; i++)
332         {
333                 bitmask |= (1 << i);
334         }
335         
336         for (i=0; i<total; i++)
337         {
338                 if (word[i] != bitmask)
339                         return 0;
340         }
341         return 1;
342 }
343
344
345 int main(int argc, char **argv)
346 {
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;
353         pval *incl=0;
354
355         tree = 0;
356         tmptree = 0;
357         
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
362          */
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");
371
372
373         strcpy(ast_config_AST_CONFIG_DIR,"/etc/asterisk");
374         
375         printf("Loading %s/%s...\n", ast_config_AST_CONFIG_DIR, config);
376         
377         localized_pbx_load_module();
378         
379         printf("... Done!\n");
380         
381         tmp = 0;
382         while ((tmp = localized_walk_contexts(tmp)) ) {
383                 printf("Context: %s\n", tmp->name);
384         }
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));
391         tmp = 0;
392         while ((tmp = localized_walk_contexts(tmp)) ) {
393                 /* printf("Context: %s\n", tmp->name); */
394                 tmptree = pvalCreateNode(PV_CONTEXT);
395                 if (!tree)
396                         tree = tmptree;
397                 else
398                         pvalTopLevAddObject(tree, tmptree);
399                 
400                 pvalContextSetName(tmptree, ast_strdup(tmp->name));
401                 
402                 if (tmp->includes) {
403                         incl = pvalCreateNode(PV_INCLUDES);
404                         pvalContextAddStatement(tmptree, incl);
405                         for (tmpi = tmp->includes; tmpi; ) { /* includes */
406                                 if (strchr(tmpi->name,'|')==0) {
407                                         if (tmpi->hastime)
408                                         {
409                                                 char timerange[15];
410                                                 char dowrange[10];
411                                                 char domrange[10];
412                                                 char monrange[10];
413                                                 int startbit=0, endbit=0;
414                                                 
415                                                 if (all_bits_set(tmpi->timing.minmask, 30, 720))
416                                                         strcpy(timerange, "*");
417                                                 else {
418                                                         int hr, min;
419                                                         char tbuf[20];
420                                                         get_start_stop(tmpi->timing.minmask, 30, 720, &startbit, &endbit);
421                                                         hr = startbit/30;
422                                                         min = (startbit % 30) * 2;
423                                                         sprintf(tbuf,"%02d:%02d", hr, min);
424                                                         strcpy(timerange, tbuf);
425                                                         hr = endbit/30;
426                                                         min = (endbit % 30) * 2;
427                                                         sprintf(tbuf,"%02d:%02d", hr, min);
428                                                         strcat(timerange,"-");
429                                                         strcat(timerange,tbuf);
430                                                 }
431                                                 
432                                                 if (all_bits_set(&tmpi->timing.dowmask, 7, 7))
433                                                         strcpy(dowrange, "*");
434                                                 else {
435                                                         get_start_stop(&tmpi->timing.dowmask, 7, 7, &startbit, &endbit);
436                                                         strcpy(dowrange, days[startbit]);
437                                                         strcat(dowrange,"-");
438                                                         strcat(dowrange, days[endbit]);
439                                                 }
440                                                 
441                                                 if (all_bits_set(&tmpi->timing.monthmask, 12, 12))
442                                                         strcpy(monrange, "*");
443                                                 else {
444                                                         get_start_stop(&tmpi->timing.monthmask, 12, 12, &startbit, &endbit);
445                                                         strcpy(monrange, months[startbit]);
446                                                         strcat(monrange,"-");
447                                                         strcat(monrange, months[endbit]);
448                                                 }
449                                                 
450                                                 if (all_bits_set(&tmpi->timing.daymask, 31, 31))
451                                                         strcpy(domrange, "*");
452                                                 else {
453                                                         char tbuf[20];
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);
460                                                 }
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));
463                                                 
464                                         } else {
465                                                 pvalIncludesAddInclude(incl, strdup(tmpi->name));
466                                         }
467                                 } else { /* it appears the timing constraint info is tacked onto the name, carve it up and divvy it out */
468                                         char *dow,*dom,*mon;
469                                         char *all = strdup(tmpi->name);
470                                         char *hr = strchr(all,'|');
471                                         if (hr) {
472                                                 *hr++ = 0;
473                                                 dow = strchr(hr,'|');
474                                                 if (dow) {
475                                                         *dow++ = 0;
476                                                         dom = strchr(dow,'|');
477                                                         if (dom) {
478                                                                 *dom++ = 0;
479                                                                 mon = strchr(dom,'|');
480                                                                 if (mon) {
481                                                                         *mon++ = 0;
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) */
485                                                                 } else {
486                                                                         ast_log(LOG_ERROR,"No month spec attached to include!\n");
487                                                                 }
488                                                         } else {
489                                                                 ast_log(LOG_ERROR,"No day of month spec attached to include!\n");
490                                                         }
491                                                 } else {
492                                                         ast_log(LOG_ERROR,"No day of week spec attached to include!\n");
493                                                 }
494                                         }
495                                 }
496                                 tmpi = tmpi->next;
497                         }
498                 }
499                 for (ipi = tmp->ignorepats; ipi; ) { /* ignorepats */
500                         incl = pvalCreateNode(PV_IGNOREPAT);
501                         pvalIgnorePatSetPattern(incl,(char *)ipi->pattern);
502                         pvalContextAddStatement(tmptree, incl);
503                         ipi = ipi->next;
504                 }
505                 eroot=0;
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));
510                         
511                         if (eroot->peer) {
512                                 pval *block = pvalCreateNode(PV_STATEMENTBLOCK);
513                                 pvalExtenSetStatement(exten, block);
514                                 
515                                 e = 0;
516                                 while ( (e = localized_walk_extension_priorities(eroot, e)) ) {
517                                         /* printf("           %s(%s)\n", e->app, (char*)e->data); */
518                                         
519                                         pval *statemnt = pvalCreateNode(PV_APPLICATION_CALL);
520                                         pval *args = pvalCreateNode(PV_WORD);
521                                         
522                                         pvalAppCallSetAppName(statemnt, ast_strdup(e->app));
523                                         pvalWordSetString(args, ast_strdup(e->data));
524                                         pvalAppCallAddArg(statemnt, args);
525                                         
526                                         pvalStatementBlockAddStatement(block, statemnt);
527                                 }
528                         } else {
529                                 pval *statemnt = pvalCreateNode(PV_APPLICATION_CALL);
530                                 pval *args = pvalCreateNode(PV_WORD);
531
532                                 /* printf("           %s (%s)\n", eroot->app, (char *)eroot->data); */
533                                 
534                                 pvalAppCallSetAppName(statemnt, ast_strdup(eroot->app));
535                                 pvalWordSetString(args, ast_strdup(eroot->data));
536
537                                 
538                                 pvalAppCallAddArg(statemnt, args);
539                                 pvalExtenSetStatement(exten, statemnt);
540                         }
541
542                         /* printf("   extension: %s\n", eroot->exten); */
543                 }
544                 if (AST_LIST_FIRST(&tmp->alts)) {
545                         sws = pvalCreateNode(PV_SWITCHES);
546                         pvalContextAddStatement(tmptree,sws);
547                         
548                         sw = 0;
549                         while ((sw = localized_walk_context_switches(tmp,sw)) ) {
550                                 pvalSwitchesAddSwitch(sws, ast_strdup(sw->name));
551                         }
552                 }
553         }
554         printf("Generating aelout.ael file...\n");
555         
556         ael2_print("aelout.ael", tree);
557         
558         printf("...Done!\n");
559         return 0;
560 }
561
562
563 /* ==================================== for linking internal stuff to external stuff */
564
565 int pbx_builtin_setvar(struct ast_channel *chan, void *data)
566 {
567         return localized_pbx_builtin_setvar(chan, data);
568 }
569
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)
572 {
573         if (cp1 && *cp1)
574                 strncpy(cp2,cp1,AST_MAX_EXTENSION); /* Right now, this routine is ONLY being called for 
575                                                                                            a possible var substitution on extension names,
576                                                                                            so....! */
577         else
578                 *cp2 = 0;
579 }
580
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)
585 {
586         return localized_add_extension2(con, replace, extension, priority, label, callerid, application, data, datad, registrar);
587 }
588
589 int ast_context_add_ignorepat2(struct ast_context *con, const char *value, const char *registrar)
590 {
591         
592         return localized_context_add_ignorepat2(con, value, registrar);
593 }
594
595 int ast_context_add_switch2(struct ast_context *con, const char *value,
596                                                                  const char *data, int eval, const char *registrar)
597 {
598         
599         return localized_context_add_switch2(con, value, data, eval, registrar);
600 }
601
602 int ast_context_add_include2(struct ast_context *con, const char *value,
603                                                                   const char *registrar)
604 {
605         
606         return localized_context_add_include2(con, value,registrar);
607 }
608
609 struct ast_context *ast_context_create(struct ast_context **extcontexts, const char *name, const char *registrar)
610 {
611         printf("Creating context %s, registrar=%s\n", name, registrar);
612         
613         return localized_context_create(extcontexts, name, registrar);
614 }
615
616 void ast_cli_register_multiple(void);
617
618 void ast_cli_register_multiple(void)
619 {
620 }
621
622 void ast_module_register(const struct ast_module_info *x)
623 {
624 }
625
626 void ast_module_unregister(const struct ast_module_info *x)
627 {
628 }
629
630 void ast_cli_unregister_multiple(void);
631
632 void ast_cli_unregister_multiple(void)
633 {
634 }
635
636 struct ast_context *ast_walk_contexts(struct ast_context *con);
637 struct ast_context *ast_walk_contexts(struct ast_context *con)
638 {
639         return localized_walk_contexts(con);
640 }
641
642 void ast_context_destroy(struct ast_context *con, const char *registrar);
643
644 void ast_context_destroy(struct ast_context *con, const char *registrar)
645 {
646         return localized_context_destroy(con, registrar);
647 }
648
649 int ast_context_verify_includes(struct ast_context *con);
650
651 int ast_context_verify_includes(struct ast_context *con)
652 {
653         return  localized_context_verify_includes(con);
654 }
655
656 void ast_merge_contexts_and_delete(struct ast_context **extcontexts, const char *registrar);
657
658 void ast_merge_contexts_and_delete(struct ast_context **extcontexts, const char *registrar)
659 {
660         localized_merge_contexts_and_delete(extcontexts, registrar);
661 }
662
663 struct ast_exten *pbx_find_extension(struct ast_channel *chan,
664                                                                          struct ast_context *bypass,
665                                                                          struct pbx_find_info *q,
666                                                                          const char *context, 
667                                                                          const char *exten, 
668                                                                          int priority,
669                                                                          const char *label, 
670                                                                          const char *callerid, 
671                                                                          enum ext_match_t action);
672
673 struct ast_exten *pbx_find_extension(struct ast_channel *chan,
674                                                                          struct ast_context *bypass,
675                                                                          struct pbx_find_info *q,
676                                                                          const char *context, 
677                                                                          const char *exten, 
678                                                                          int priority,
679                                                                          const char *label, 
680                                                                          const char *callerid, 
681                                                                          enum ext_match_t action)
682 {
683         return localized_find_extension(bypass, q, context, exten, priority, label, callerid, action);
684 }
685