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