Oops
[asterisk/asterisk.git] / pbx / pbx_ael.c
1 /*
2  * Asterisk -- A telephony toolkit for Linux.
3  *
4  * Compile symbolic Asterisk Extension Logic into Asterisk extensions
5  * 
6  * Copyright (C) 2005, Digium, Inc.
7  *
8  * Mark Spencer <markster@digium.com>
9  *
10  * This program is free software, distributed under the terms of
11  * the GNU General Public License
12  */
13
14 #include <sys/types.h>
15 #include <stdlib.h>
16 #include <stdio.h>
17 #include <string.h>
18 #include <ctype.h>
19 #include <errno.h>
20
21 #include "asterisk.h"
22
23 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
24
25 #include "asterisk/pbx.h"
26 #include "asterisk/config.h"
27 #include "asterisk/module.h"
28 #include "asterisk/logger.h"
29 #include "asterisk/cli.h"
30 #include "asterisk/callerid.h"
31
32 struct stringlink {
33         struct stringlink *next;
34         unsigned char data[0];
35 };
36
37 #define FILLIN_BREAK            1
38 #define FILLIN_CONTINUE         2
39
40 struct fillin {
41         struct fillin *next;
42         char exten[AST_MAX_EXTENSION];
43         int priority;
44         int type;
45 };
46
47 #ifdef __AST_DEBUG_MALLOC
48 static void FREE(void *ptr)
49 {
50         free(ptr);
51 }
52 #else
53 #define FREE free
54 #endif
55
56 #define DEBUG_READ   (1 << 0)
57 #define DEBUG_TOKENS (1 << 1)
58 #define DEBUG_MACROS (1 << 2)
59 #define DEBUG_CONTEXTS (1 << 3)
60
61 static int aeldebug = 0;
62
63 static char *dtext = "Asterisk Extension Language Compiler";
64 static char *config = "extensions.ael";
65 static char *registrar = "pbx_ael";
66
67 /*
68  * Static code
69  */
70 static char *process_quotes_and_slashes(char *start, char find, char replace_with)
71 {
72         char *dataPut = start;
73         int inEscape = 0;
74         int inQuotes = 0;
75
76         for (; *start; start++) {
77                 if (inEscape) {
78                         *dataPut++ = *start;       /* Always goes verbatim */
79                         inEscape = 0;
80                 } else {
81                         if (*start == '\\') {
82                                 inEscape = 1;      /* Do not copy \ into the data */
83                         } else if (*start == '\'') {
84                                 inQuotes = 1-inQuotes;   /* Do not copy ' into the data */
85                         } else {
86                                 /* Replace , with |, unless in quotes */
87                                 *dataPut++ = inQuotes ? *start : ((*start==find) ? replace_with : *start);
88                         }
89                 }
90         }
91         if (start != dataPut)
92                 *dataPut = 0;
93         return dataPut;
94 }
95
96 /*
97  * Standard module functions ...
98  */
99 int unload_module(void)
100 {
101         ast_context_destroy(NULL, registrar);
102         return 0;
103 }
104
105 static char *__grab_token(char *src, const char *filename, int lineno, int link)
106 {
107         char *c;
108         char *b;
109         char *a;
110         int level = 0;
111         char *ret;
112 #if 0
113         if (aeldebug || DEBUG_TOKENS) 
114                 ast_verbose("Searching for token in '%s'!\n", src);
115 #endif
116         c = src;
117         while(*c) {
118                 if ((*c == '\\')) {
119                         c++;
120                         if (!*c)
121                                 c--;
122                 } else {
123                         if ((*c == '{') || (*c == '(')) {
124                                 level++;
125                         } else if ((*c == '}') || (*c == ')')) {
126                                 if (level)
127                                         level--;
128                                 else
129                                         ast_log(LOG_WARNING, "Syntax error at line %d of '%s', too many closing braces!\n", lineno, filename);
130                         } else if ((*c == ';') && !level) {
131                                 /* Got a token! */
132                                 *c = '\0';
133                                 b = c;
134                                 b--;
135                                 c++;
136                                 while((b > src) && (*b < 33)) { 
137                                         *b = '\0'; 
138                                         b--; 
139                                 }
140                                 a = src;
141                                 while(*a && (*a < 33))
142                                         a++;
143                                 if (link) {
144                                         ret = malloc(strlen(a) + sizeof(struct stringlink) + 1);
145                                         if (ret)
146                                                 strcpy(ret + sizeof(struct stringlink), a);
147                                 } else
148                                         ret = strdup(a);
149                                 /* Save remainder */
150                                 memmove(src, c, strlen(c) + 1);
151                                 return ret;
152                         }
153                 }
154                 c++;
155         }
156         return NULL;            
157 }
158
159 static char *grab_token(char *src, const char *filename, int lineno)
160 {
161         return __grab_token(src, filename, lineno, 0);
162 }
163
164 static struct stringlink *arg_parse(char *args, const char *filename, int lineno)
165 {
166         struct stringlink *cur, *prev=NULL, *root=NULL;
167         if (args) {
168                 if (aeldebug & DEBUG_TOKENS) 
169                         ast_verbose("Parsing args '%s'!\n", args);
170                 if (args[0] == '{') {
171                         /* Strip mandatory '}' from end */
172                         args[strlen(args) - 1] = '\0';
173                         while ((cur = (struct stringlink *)__grab_token(args + 1, filename, lineno, 1))) {
174                                 cur->next = NULL;
175                                 if (prev)
176                                         prev->next = cur;
177                                 else
178                                         root = cur;
179                                 prev = cur;
180                         }
181                 } else if (*args) {
182                         root = malloc(sizeof(struct stringlink) + strlen(args) + 1);
183                         if (root) {
184                                 strcpy(root->data, args);
185                                 root->next = NULL;
186                         }
187                 }
188         }
189         return root;
190 }
191
192 static char *grab_else(char *args, const char *filename, int lineno)
193 {
194         char *ret = NULL;
195         int level=0;
196         char *c;
197         if (args) {
198                 if (args[0] == '{') {
199                         c = args;
200                         while(*c) {
201                                 if (*c == '{')
202                                         level++;
203                                 else if (*c == '}') {
204                                         level--;
205                                         if (!level) {
206                                                 c++;
207                                                 while(*c && (*c < 33)) { *c = '\0'; c++; };
208                                                 if (!strncasecmp(c, "else", 4) && 
209                                                         ((c[4] == '{') || (c[4] < 33))) {
210                                                                 /* Ladies and gentlemen, we have an else clause */
211                                                         *c = '\0';
212                                                         c += 4;
213                                                         while(*c && (*c < 33)) c++;
214                                                         ret = c;
215                                                         if (aeldebug & DEBUG_TOKENS)
216                                                                 ast_verbose("Returning else clause '%s'\n", c);
217                                                 }
218                                         }
219                                         break;
220                                 }
221                                 c++;
222                         }
223                 }
224         }
225         return ret;
226 }
227
228 static struct stringlink *param_parse(char *parms, const char *macro, const char *filename, int lineno)
229 {
230         char *s, *e;
231         struct stringlink *root = NULL, *prev=NULL, *cur;
232         if (!parms || !*parms)
233                 return NULL;
234         if (*parms != '(') {
235                 ast_log(LOG_NOTICE, "Syntax error in parameter list for macro '%s' at about line %d of %s: Expecting '(' but got '%c'\n", macro, lineno, filename, *parms);
236                 return NULL;
237         }
238         s = parms + 1;
239         while(*s) {
240                 while(*s && (*s < 33)) s++;
241                 e = s;
242                 while(*e &&  (*e != ')') && (*e != ',')) {
243                         if (*e < 33)
244                                 *e = '\0';
245                         e++;
246                 }
247                 if (*e) {
248                         /* Strip token */
249                         *e = '\0';
250                         e++;
251                         /* Skip over whitespace */
252                         while(*e && (*e < 33)) e++;
253                         /* Link */
254                         cur = malloc(strlen(s) + sizeof(struct stringlink) + 1);
255                         if (cur) {
256                                 cur->next = NULL;
257                                 strcpy(cur->data, s);
258                                 if (prev)
259                                         prev->next = cur;
260                                 else
261                                         root = cur;
262                                 prev = cur;
263                         }
264                         s = e;
265                 }
266         }
267         return root;
268 }
269
270 static void arg_free(struct stringlink *cur)
271 {
272         struct stringlink *last;
273         while(cur) {
274                 last = cur;
275                 cur = cur->next;
276                 free(last);
277         }
278 }
279
280 static void handle_globals(struct stringlink *vars)
281 {
282         while(vars) {
283                 pbx_builtin_setvar(NULL, vars->data);
284                 vars = vars->next;
285         }
286 }
287
288 static struct stringlink *split_token(char *token, const char *filename, int lineno)
289 {
290         char *args, *p;
291         struct stringlink *argv;
292         args = token;
293         while (*args && (*args > 32) && (*args != '{') && (*args != '(')) args++;
294         if (*args) {
295                 p = args;
296                 while (*args && (*args < 33))
297                         args++;
298                 if (*args != '(') {
299                         *p = '\0';
300                 } else {
301                         while (*args && (*args != ')')) args++;
302                         if (*args == ')') {
303                                 args++;
304                                 while (*args && (*args < 33)) args++;
305                         }
306                 }
307                 if (!*args)
308                         args = NULL;
309         } else args = NULL;
310         argv = arg_parse(args, filename, lineno);
311         if (args)
312                 *args = '\0';
313         return argv;
314 }
315
316 static int matches_keyword(const char *data, const char *keyword)
317 {
318         char c;
319         if (!strncasecmp(data, keyword, strlen(keyword))) {
320                 c = data[strlen(keyword)];
321                 if ((c < 33) || (c == '(') || (c == '{'))
322                         return 1;
323         }
324         return 0;
325 }
326
327 static struct stringlink *split_params(char *token, const char *filename, int lineno)
328 {
329         char *params;
330         struct stringlink *paramv;
331         params = token;
332         while(*params && (*params > 32) && (*params != '(')) params++;
333         if (*params) {
334                 if (*params != '(') {
335                         *params = '\0';
336                         params++;
337                         while(*params && (*params < 33))
338                                 params++;
339                 }
340                 if (!*params)
341                         params = NULL;
342         } else params = NULL;
343         paramv = param_parse(params, token, filename, lineno);
344         if (params)
345                 *params = '\0';
346         return paramv;
347 }
348
349 static const char *get_case(char *s, char **restout, int *pattern)
350 {
351         char *newcase=NULL;
352         char *rest=NULL;
353         if (!strncasecmp(s, "case", 4) && s[4] && ((s[4] < 33) || (s[4] == ':'))) {
354                 newcase = s + 4;
355                 while (*newcase && (*newcase < 33)) newcase++;
356                 rest = newcase;
357                 *pattern = 0;
358         } else if (!strncasecmp(s, "pattern", 7) && s[7] && ((s[7] < 33) || (s[7] == ':'))) {
359                 newcase = s + 8;
360                 while (*newcase && (*newcase < 33)) newcase++;
361                 rest = newcase;
362                 *pattern = 1;
363         } else if (!strncasecmp(s, "default", 7) && ((s[7] < 33) || (s[7] == ':'))) {
364                 newcase = ".";
365                 rest = s + 7;
366                 while (*rest && (*rest < 33)) rest++;
367                 *pattern = 1;
368         }
369
370         if (rest) {
371                 while (*rest && (*rest > 32) && (*rest != ':')) rest++;
372                 if (*rest) {
373                         *rest = 0;
374                         rest++;
375                         while (*rest && ((*rest == ':') || (*rest < 33))) rest++;
376                         *restout = rest;
377                 } else {
378                         *restout = "";
379                 }
380         } else
381                 *restout = s;
382         if (aeldebug & DEBUG_TOKENS)
383                 ast_verbose("GETCASE: newcase is '%s', rest = '%s'\n", newcase, *restout);
384         return newcase;
385 }
386
387 static void fillin_free(struct fillin *fillin)
388 {
389         struct fillin *cur, *next;
390         cur =  fillin;
391         while(cur) {
392                 next = cur->next;
393                 free(cur);
394                 cur = next;
395         }
396 }
397
398 static void fillin_process(struct ast_context *con, struct fillin *fillin, const char *filename, int lineno, const char *breakexten, int breakprio, const char *contexten, int contprio)
399 {
400         struct fillin *cur;
401         char *app;
402         char mdata[AST_MAX_EXTENSION + 20];
403         cur = fillin;
404         while(cur) {
405                 if (cur->type == FILLIN_BREAK) {
406                         if (breakexten && breakprio) {
407                                 app = "Goto";
408                                 snprintf(mdata, sizeof(mdata), "%s|%d", breakexten, breakprio);
409                         } else {
410                                 app = "NoOp";
411                                 snprintf(mdata, sizeof(mdata), "Invalid break");
412                                 ast_log(LOG_NOTICE, "Ignoring inappropriate break around line %d of %s\n", lineno, filename);
413                         }
414                         if (ast_add_extension2(con, 0, cur->exten, cur->priority, NULL, NULL, app, strdup(mdata), FREE, registrar))
415                                 ast_log(LOG_WARNING, "Unable to add step at priority '%d' of break '%s'\n", cur->priority, cur->exten);
416                 } else if (cur->type == FILLIN_CONTINUE) {
417                         if (contexten && contprio) {
418                                 app = "Goto";
419                                 snprintf(mdata, sizeof(mdata), "%s|%d", contexten, contprio);
420                         } else {
421                                 app = "NoOp";
422                                 snprintf(mdata, sizeof(mdata), "Invalid continue");
423                                 ast_log(LOG_NOTICE, "Ignoring inappropriate continue around line %d of %s\n", lineno, filename);
424                         }
425                         if (ast_add_extension2(con, 0, cur->exten, cur->priority, NULL, NULL, app, strdup(mdata), FREE, registrar))
426                                 ast_log(LOG_WARNING, "Unable to add step at priority '%d' of continue '%s'\n", cur->priority, cur->exten);
427                 } else {
428                         ast_log(LOG_WARNING, "Whoa, unknown fillin type '%d'\n", cur->type);
429                 }
430                 cur = cur->next;
431         }
432 }
433
434 static int match_assignment(char *variable, char **value)
435 {
436         char *c;
437         char *ws;
438         c = variable;
439         while(*c && (*c > 32) && (*c != '=')) c++;
440         ws = c;
441         while(*c && (*c < 33)) c++;
442         if (*c == '=') {
443                 *ws = '\0';
444                 *c = '\0';
445                 c++;
446                 while ((*c) && (*c < 33)) c++;
447                 *value = c;
448                 return 1;
449         }
450         return 0;
451 }
452
453 static int matches_label(char *data, char **rest)
454 {
455         char last = 0;
456         char *start = data;
457         while (*data > 32) {
458                 last = *data;
459                 data++;
460         }
461         if (last != ':') {
462                 while (*data && (*data < 33)) data++;
463                 last = *data;
464                 data++;
465         }
466         if (last == ':') {
467                 *rest = data;
468                 /* Go back and trim up the label */
469                 while(*start && ((*start > 32) && (*start != ':'))) start++;
470                 *start = '\0';
471                 return 1;
472         }
473         return 0;
474 }
475
476 static int build_step(const char *what, const char *name, const char *filename, int lineno, struct ast_context *con, char *exten, int *pos, char *data, struct fillin **fillout, char **label);
477 static int __build_step(const char *what, const char *name, const char *filename, int lineno, struct ast_context *con, char *exten, int *pos, char *data, struct fillin **fillout, char **label)
478 {
479         char *app;
480         char *args;
481         char *c;
482         char *margs=NULL;
483         char *oargs;
484         char *rest;
485         const char *curcase, *newcase;
486         struct stringlink *swargs, *cur;
487         int cpos;
488         int mlen;
489         int pattern;
490         struct fillin *fillin;
491         while (*data && (*data < 33)) data++;
492         if (matches_label(data, &c)) {
493                 *label = data;
494                 data = c;
495                 while (*data && (*data < 33)) data++;
496         }
497         if (!data || ast_strlen_zero(data))
498                 return 0;
499         if (matches_keyword(data, "switch")) {
500                 fillin = NULL;
501                 /* Switch */
502                 args = data + strlen("switch");
503                 while ((*args < 33) && (*args != '(')) args++;
504                 if ((*args == '(') && (c = strchr(args, ')'))) {
505                         args++;
506                         *c = '\0';
507                         c++;
508                         if (aeldebug & DEBUG_TOKENS)
509                                 ast_verbose("--SWITCH on : %s\n", args);
510                         mlen = strlen(exten) + 128 + strlen(args) + strlen(name);
511                         margs = alloca(mlen);
512                         app = "Goto";
513                         sprintf(margs, "sw-%s-%d-%s|1", name, *pos, args);
514                         process_quotes_and_slashes(margs, ',', '|');
515                         oargs = args;
516                         args = margs;
517                         if (ast_add_extension2(con, 0, exten, *pos, *label, NULL, app, strdup(args), FREE, registrar))
518                                 ast_log(LOG_WARNING, "Unable to add step at priority '%d' of %s '%s'\n", *pos, what, name);
519                         else {
520                                 *label = NULL;
521                                 (*pos)++;
522                         }
523                         app = "NoOp";
524                         sprintf(margs, "Finish switch-%s-%d", name, *pos - 1);
525                         if (ast_add_extension2(con, 0, exten, *pos, *label, NULL, app, strdup(args), FREE, registrar))
526                                 ast_log(LOG_WARNING, "Unable to add step at priority '%d' of %s '%s'\n", *pos, what, name);
527                         else {
528                                 *label = NULL;
529                                 (*pos)++;
530                         }
531                         while(*c && (*c < 33)) c++;
532                         if (aeldebug & DEBUG_TOKENS)
533                                 ast_verbose("ARG Parsing '%s'\n", c);
534                         swargs = arg_parse(c, filename, lineno);
535                         cur = swargs;
536                         curcase = NULL;
537                         while(cur) {
538                                 if ((newcase = get_case(cur->data, &rest, &pattern))) {
539                                         if (aeldebug & DEBUG_TOKENS)
540                                                 ast_verbose("--NEWCASE: '%s'!\n", newcase);
541                                         if (curcase) {
542                                                 /* Handle fall through */
543                                                 char tmp[strlen(newcase) + strlen(name) + 40];
544                                                 sprintf(tmp, "sw-%s-%d-%s|%d", name, *pos - 2, newcase, 1);
545                                                 ast_add_extension2(con, 0, margs, cpos, NULL, NULL, "Goto", strdup(tmp), FREE, registrar);
546                                         }
547                                         curcase = newcase;
548                                         cpos = 1;
549                                         if (pattern)
550                                                 snprintf(margs, mlen, "_sw-%s-%d-%s", name, *pos - 2, curcase);
551                                         else
552                                                 snprintf(margs, mlen, "sw-%s-%d-%s", name, *pos - 2, curcase);
553                                         if (!strcasecmp(rest, "break")) {
554                                                 char tmp[strlen(exten) + 10];
555                                                 sprintf(tmp, "%s|%d", exten, *pos - 1);
556                                                 ast_add_extension2(con, 0, exten, cpos, *label, NULL, "Goto", strdup(tmp), FREE, registrar);
557                                                 curcase = NULL;
558                                                 *label = NULL;
559                                         } else
560                                                 build_step("switch", margs, filename, lineno, con, margs, &cpos, rest, &fillin, label);
561                                 } else if (curcase) {
562                                         if (aeldebug & DEBUG_TOKENS)
563                                                 ast_verbose("Building statement from '%s'\n", rest);
564                                         if (!strcasecmp(rest, "break")) {
565                                                 char tmp[strlen(exten) + 10];
566                                                 sprintf(tmp, "%s|%d", exten, *pos - 1);
567                                                 ast_add_extension2(con, 0, margs, cpos, *label, NULL, "Goto", strdup(tmp), FREE, registrar);
568                                                 curcase = NULL;
569                                                 *label = NULL;
570                                         } else
571                                                 build_step("switch", margs, filename, lineno, con, margs, &cpos, rest, &fillin, label);
572                                 } else 
573                                         ast_log(LOG_WARNING, "Unreachable code in switch at about line %d of %s\n", lineno, filename);
574                                 if (aeldebug & DEBUG_TOKENS)
575                                         ast_verbose("--SWARG: %s\n", cur->data);
576                                 cur = cur->next;
577                         }
578                         /* Can't do anything with these */
579                         fillin_process(con, fillin, filename, lineno, NULL, 0, NULL, 0);
580                         fillin_free(fillin);
581                         arg_free(swargs);
582                 } else
583                         ast_log(LOG_WARNING, "Syntax error in switch declaration in %s around line %d!\n", filename, lineno); 
584                         
585         } else if (matches_keyword(data, "if")) {
586                 /* If... */
587                 args = data + strlen("if");
588                 while ((*args < 33) && (*args != '(')) args++;
589                 if ((*args == '(') && (c = strchr(args, ')'))) {
590                         int ifblock;
591                         int ifstart;
592                         int elsestart;
593                         int ifend;
594                         int ifskip;
595                         char *elses;
596                         char *iflabel;
597                         args++;
598                         *c = '\0';
599                         c++;
600                         while(*c && (*c < 33)) c++;
601                         if (aeldebug & DEBUG_TOKENS)
602                                 ast_verbose("--IF on : '%s' : '%s'\n", args, c);
603                         mlen = strlen(exten) + 128 + strlen(args) + strlen(name);
604                         margs = alloca(mlen);
605                         /* Remember where the ifblock starts, and skip over */
606                         ifblock = (*pos)++;
607                         iflabel = *label;
608                         *label = NULL;
609                         /* Remember where the start of the ifblock is */
610                         ifstart = *pos;
611                         snprintf(margs, mlen, "if-%s-%d", name, ifblock);
612                         /* Now process the block of the if */
613                         if (aeldebug & DEBUG_TOKENS)
614                                 ast_verbose("Searching for elses in '%s'\n", c);
615                         elses = grab_else(c, filename, lineno);
616                         build_step("if", margs, filename, lineno, con, exten, pos, c, fillout, label);
617                         if (elses) {
618                                 /* Reserve a goto to exit the if */
619                                 ifskip = *pos;
620                                 (*pos)++;
621                                 elsestart = *pos;
622                                 build_step("else", margs, filename, lineno, con, exten, pos, elses, fillout, label);
623                         } else {
624                                 elsestart = *pos;
625                                 ifskip = 0;
626                         }
627                         ifend = *pos;
628                         (*pos)++;
629                         app = "NoOp";
630                         snprintf(margs, mlen, "Finish if-%s-%d", name, ifblock);
631                         if (ast_add_extension2(con, 0, exten, ifend, *label, NULL, app, strdup(margs), FREE, registrar))
632                                 ast_log(LOG_WARNING, "Unable to add step at priority '%d' of %s '%s'\n", *pos, what, name);
633                         *label = NULL;
634                         app = "Goto";
635                         snprintf(margs, mlen, "${IF($[ %s ]?%d:%d)}", args, ifstart, elsestart);
636                         if (ast_add_extension2(con, 0, exten, ifblock, iflabel, NULL, app, strdup(margs), FREE, registrar))
637                                 ast_log(LOG_WARNING, "Unable to add step at priority '%d' of %s '%s'\n", *pos, what, name);
638                         if (ifskip) {
639                                 /* Skip as appropriate around else clause */
640                                 snprintf(margs, mlen, "%d", ifend);
641                                 if (ast_add_extension2(con, 0, exten, ifskip, NULL, NULL, app, strdup(margs), FREE, registrar))
642                                         ast_log(LOG_WARNING, "Unable to add step at priority '%d' of %s '%s'\n", *pos, what, name);
643                         }
644                 } else
645                         ast_log(LOG_WARNING, "Syntax error in if declaration in %s around line %d!\n", filename, lineno); 
646         } else if (matches_keyword(data, "while")) {
647                 /* While... */
648                 fillin = NULL;
649                 args = data + strlen("while");
650                 while ((*args < 33) && (*args != '(')) args++;
651                 if ((*args == '(') && (c = strchr(args, ')'))) {
652                         int whileblock;
653                         int whilestart;
654                         int whileend;
655                         char *whilelabel;
656                         args++;
657                         *c = '\0';
658                         c++;
659                         while(*c && (*c < 33)) c++;
660                         if (aeldebug & DEBUG_TOKENS)
661                                 ast_verbose("--WHILE on : '%s' : '%s'\n", args, c);
662                         mlen = strlen(exten) + 128 + strlen(args) + strlen(name);
663                         margs = alloca(mlen);
664                         /* Remember where to put the conditional, and keep its position */
665                         whilestart = (*pos);
666                         whilelabel = *label;
667                         *label = NULL;
668                         (*pos)++;
669                         /* Remember where the whileblock starts */
670                         whileblock = (*pos);
671                         snprintf(margs, mlen, "while-%s-%d", name, whilestart);
672                         build_step("while", margs, filename, lineno, con, exten, pos, c, &fillin, label);
673                         /* Close the loop */
674                         app = "Goto";
675                         snprintf(margs, mlen, "%d", whilestart);
676                         if (ast_add_extension2(con, 0, exten, (*pos)++, *label, NULL, app, strdup(margs), FREE, registrar))
677                                 ast_log(LOG_WARNING, "Unable to add step at priority '%d' of %s '%s'\n", *pos, what, name);
678                         *label = NULL;
679                         whileend = (*pos);
680                         /* Place trailer */
681                         app = "NoOp";
682                         snprintf(margs, mlen, "Finish while-%s-%d", name, whilestart);
683                         if (ast_add_extension2(con, 0, exten, (*pos)++, *label, NULL, app, strdup(margs), FREE, registrar))
684                                 ast_log(LOG_WARNING, "Unable to add step at priority '%d' of %s '%s'\n", *pos, what, name);
685                         *label = NULL;
686                         app = "Goto";
687                         snprintf(margs, mlen, "${IF($[ %s ]?%d:%d)}", args, whileblock, whileend);
688                         if (ast_add_extension2(con, 0, exten, whilestart, whilelabel, NULL, app, strdup(margs), FREE, registrar))
689                                 ast_log(LOG_WARNING, "Unable to add step at priority '%d' of %s '%s'\n", *pos, what, name);
690                         fillin_process(con, fillin, filename, lineno, exten, whileend, exten, whilestart);
691                         fillin_free(fillin);
692                 } else
693                         ast_log(LOG_WARNING, "Syntax error in while declaration in %s around line %d!\n", filename, lineno); 
694         } else if (matches_keyword(data, "jump")) {
695                 char *p;
696                 /* Jump... */
697                 fillin = NULL;
698                 args = data + strlen("jump");
699                 while(*args && (*args < 33)) args++;
700                 if (aeldebug & DEBUG_TOKENS)
701                         ast_verbose("--JUMP to : '%s'\n", args);
702                 p = strchr(args, ',');
703                 if (p) {
704                         *p = '\0';
705                         p++;
706                 } else
707                         p = "1";
708                 c = strchr(args, '@');
709                 if (c) {
710                         *c = '\0';
711                         c++;
712                 }
713                 mlen = strlen(exten) + 128 + strlen(args) + strlen(name) + (c ? strlen(c) : 0);
714                 margs = alloca(mlen);
715                 if (c) 
716                         snprintf(margs, mlen, "%s|%s|%s", c,args, p);
717                 else
718                         snprintf(margs, mlen, "%s|%s", args, p);
719                 app = "Goto";
720                 if (ast_add_extension2(con, 0, exten, (*pos)++, *label, NULL, app, strdup(margs), FREE, registrar))
721                         ast_log(LOG_WARNING, "Unable to add step at priority '%d' of %s '%s'\n", *pos, what, name);
722                 *label = NULL;
723         } else if (matches_keyword(data, "goto")) {
724                 /* Jump... */
725                 fillin = NULL;
726                 args = data + strlen("goto");
727                 while(*args && (*args < 33)) args++;
728                 if (aeldebug & DEBUG_TOKENS)
729                         ast_verbose("--GOTO to : '%s'\n", args);
730                 app = "Goto";
731                 if (ast_add_extension2(con, 0, exten, (*pos)++, *label, NULL, app, strdup(args), FREE, registrar))
732                         ast_log(LOG_WARNING, "Unable to add step at priority '%d' of %s '%s'\n", *pos, what, name);
733                 *label = NULL;
734         } else if (matches_keyword(data, "for")) {
735                 /* While... */
736                 fillin = NULL;
737                 args = data + strlen("for");
738                 while ((*args < 33) && (*args != '(')) args++;
739                 if ((*args == '(') && (c = strchr(args, ')'))) {
740                         int forblock;
741                         int forprep;
742                         int forstart;
743                         int forend;
744                         struct stringlink *fields;
745                         char *tmp;
746                         char *forlabel = NULL;
747                         args++;
748                         *c = '\0';
749                         c++;
750                         while(*c && (*c < 33)) c++;
751                         /* Parse arguments first */
752                         tmp = alloca(strlen(args) + 10);
753                         if (tmp) {
754                                 snprintf(tmp, strlen(args) + 10, "{%s;}", args);
755                                 fields = arg_parse(tmp, filename, lineno);
756                         } else
757                                 fields = NULL;
758                         if (fields && fields->next && fields->next->next) {
759                                 if (aeldebug & DEBUG_TOKENS)
760                                         ast_verbose("--FOR ('%s' ; '%s' ; '%s') : '%s'\n", fields->data, fields->next->data, fields->next->next->data, c);
761                                 mlen = strlen(exten) + 128 + strlen(args) + strlen(name);
762                                 margs = alloca(mlen);
763                                 forprep = *pos;
764                                 snprintf(margs, mlen, "for-%s-%d", name, forprep);
765                                 fillin = NULL;
766                                 build_step("while", margs, filename, lineno, con, exten, pos, fields->data, &fillin, label);
767                                 /* Remember where to put the conditional, and keep its position */
768                                 forstart = (*pos);
769                                 forlabel = *label;
770                                 (*pos)++;
771                                 *label = NULL;
772                                 /* Remember where the whileblock starts */
773                                 forblock = (*pos);
774                                 build_step("for", margs, filename, lineno, con, exten, pos, fields->next->next->data, &fillin, label);
775                                 build_step("for", margs, filename, lineno, con, exten, pos, c, &fillin, label);
776                                 /* Close the loop */
777                                 app = "Goto";
778                                 snprintf(margs, mlen, "%d", forstart);
779                                 if (ast_add_extension2(con, 0, exten, (*pos)++, *label, NULL, app, strdup(margs), FREE, registrar))
780                                         ast_log(LOG_WARNING, "Unable to add step at priority '%d' of %s '%s'\n", *pos, what, name);
781                                 *label = NULL;
782                                 forend = (*pos);
783                                 /* Place trailer */
784                                 app = "NoOp";
785                                 snprintf(margs, mlen, "Finish for-%s-%d", name, forprep);
786                                 if (ast_add_extension2(con, 0, exten, (*pos)++, *label, NULL, app, strdup(margs), FREE, registrar))
787                                         ast_log(LOG_WARNING, "Unable to add step at priority '%d' of %s '%s'\n", *pos, what, name);
788                                 *label = NULL;
789                                 app = "Goto";
790                                 snprintf(margs, mlen, "${IF($[ %s ]?%d:%d)}", fields->next->data, forblock, forend);
791                                 if (ast_add_extension2(con, 0, exten, forstart, forlabel, NULL, app, strdup(margs), FREE, registrar))
792                                         ast_log(LOG_WARNING, "Unable to add step at priority '%d' of %s '%s'\n", forstart, what, name);
793                                 fillin_process(con, fillin, filename, lineno, exten, forend, exten, forstart);
794                                 fillin_free(fillin);
795                         } else
796                                 ast_log(LOG_NOTICE, "Improper for declaration in %s around line %d!\n", filename, lineno); 
797                         arg_free(fields);
798                 } else
799                         ast_log(LOG_WARNING, "Syntax error in for declaration in %s around line %d!\n", filename, lineno); 
800                         
801         } else if (!strcasecmp(data, "break") || !strcasecmp(data, "continue")) {
802                 struct fillin *fi;
803                 fi = malloc(sizeof(struct fillin));
804                 if (fi) {
805                         memset(fi, 0, sizeof(struct fillin));
806                         if (!strcasecmp(data, "break"))
807                                 fi->type = FILLIN_BREAK;
808                         else
809                                 fi->type = FILLIN_CONTINUE;
810                         ast_copy_string(fi->exten, exten, sizeof(fi->exten));
811                         fi->priority = (*pos)++;
812                         fi->next = *fillout;
813                         *fillout = fi;
814                 }
815         } else if (match_assignment(data, &rest)) {
816                 if (aeldebug & DEBUG_TOKENS)
817                         ast_verbose("ASSIGN  '%s' = '%s'\n", data, rest);
818                 mlen = strlen(rest) + strlen(data) + 20;
819                 margs = alloca(mlen);
820                 snprintf(margs, mlen, "%s=$[ %s ]", data, rest);
821                 app = "Set";
822                 if (ast_add_extension2(con, 0, exten, *pos, *label, NULL, app, strdup(margs), FREE, registrar))
823                         ast_log(LOG_WARNING, "Unable to add assignment at priority '%d' of %s '%s'\n", *pos, what, name);
824                 else {
825                         *label = NULL;
826                         (*pos)++;
827                 }
828         } else {
829                 app = data;
830                 args = app;
831                 while (*args && (*args > 32) && (*args != '(')) args++;
832                         if (*args != '(') {
833                         while(*args && (*args != '(')) { *args = '\0'; args++; };
834                 }
835                 if (*args == '(') {
836                         *args = '\0';
837                         args++;
838                         /* Got arguments, trim trailing ')' */
839                         c = args + strlen(args) - 1;
840                         while((c >= args) && (*c < 33) && (*c != ')')) { *c = '\0'; c--; };
841                         if ((c >= args) && (*c == ')')) *c = '\0';
842                 } else
843                         args = "";
844                 process_quotes_and_slashes(args, ',', '|');
845                 if (app[0] == '&') {
846                         app++;
847                         margs = alloca(strlen(args) + strlen(app) + 10);
848                         sprintf(margs, "%s|%s", app, args);
849                         args = margs;
850                         app = "Macro";
851                 }
852                 if (aeldebug & DEBUG_TOKENS)
853                         ast_verbose("-- APP: '%s', ARGS: '%s'\n", app, args);
854                 if (ast_add_extension2(con, 0, exten, *pos, *label, NULL, app, strdup(args), FREE, registrar))
855                         ast_log(LOG_WARNING, "Unable to add step at priority '%d' of %s '%s'\n", *pos, what, name);
856                 else {
857                         (*pos)++;
858                         *label = NULL;
859                 }
860         }
861         return 0;
862 }
863
864 static int build_step(const char *what, const char *name, const char *filename, int lineno, struct ast_context *con, char *exten, int *pos, char *data, struct fillin **fillout, char **label)
865 {
866         struct stringlink *args, *cur;
867         int res=0;
868         struct fillin *fillin=NULL;
869         int dropfill = 0;
870         char *labelin = NULL;
871         if (!fillout) {
872                 fillout = &fillin;
873                 dropfill = 1;
874         }
875         if (!label) {
876                 label = &labelin;
877         };
878         args = arg_parse(data, filename, lineno);
879         cur = args;
880         while(cur) {
881                 res |= __build_step(what, name, filename, lineno, con, exten, pos, cur->data, fillout, label);
882                 cur = cur->next;
883         }
884         arg_free(args);
885         if (dropfill) {
886                 fillin_process(con, fillin, filename, lineno, NULL, 0, NULL, 0);
887                 fillin_free(fillin);
888         }
889         return res;
890 }
891
892 static int parse_catch(char *data, char **catch, char **rest)
893 {
894         /* Skip the word 'catch' */
895         data += 5;
896         while (*data && (*data < 33)) data++;
897         /* Here's the extension */
898         *catch = data;
899         if (!*data)
900                 return 0;
901         while (*data && (*data > 32)) data++;
902         if (!*data)
903                 return 0;
904         /* Trim any trailing spaces */
905         *data = '\0';
906         data++;
907         while(*data && (*data < 33)) data++;
908         if (!*data)
909                 return 0;
910         *rest = data;
911         return 1;
912 }
913
914 static void handle_macro(struct ast_context **local_contexts, struct stringlink *vars, const char *filename, int lineno)
915 {
916         struct stringlink *argv;
917         struct stringlink *paramv;
918         struct stringlink *cur;
919         struct ast_context *con;
920         struct fillin *fillin;
921         char *catch, *rest;
922         char name[256];
923         int pos;
924         int cpos;
925
926         if (aeldebug & DEBUG_MACROS)
927                 ast_verbose("Root macro def is '%s'\n", vars->data);
928         argv = split_token(vars->data, filename, lineno);
929         paramv = split_params(vars->data, filename, lineno);
930         if (aeldebug & DEBUG_MACROS) 
931                 ast_verbose("Found macro '%s'\n", vars->data);
932         snprintf(name, sizeof(name), "macro-%s", vars->data);
933         con = ast_context_create(local_contexts, name, registrar);
934         if (con) {
935                 pos = 1;
936                 cur = paramv;
937                 while(cur) {
938                         if (aeldebug & DEBUG_MACROS)
939                                 ast_verbose("  PARAM => '%s'\n", cur->data);
940                         snprintf(name, sizeof(name), "%s=${ARG%d}", cur->data, pos);
941                         if (ast_add_extension2(con, 0, "s", pos, NULL, NULL, "Set", strdup(name), FREE, registrar))
942                                 ast_log(LOG_WARNING, "Unable to add step at priority '%d' of macro '%s'\n", pos, vars->data);
943                         else
944                                 pos++;
945                         cur = cur->next;
946                 }
947                 cur = argv;
948                 while(cur) {
949                         if (aeldebug & DEBUG_MACROS)
950                                 ast_verbose("  STEP => '%s'\n", cur->data);
951                         if (matches_keyword(cur->data, "catch")) {
952                                 if (aeldebug & DEBUG_MACROS)
953                                         ast_verbose("--CATCH: '%s'\n", cur->data);
954                                 if (parse_catch(cur->data, &catch, &rest)) {
955                                         cpos = 1;
956                                         build_step("catch", catch, filename, lineno, con, catch, &cpos, rest, NULL, NULL);
957                                 } else
958                                         ast_log(LOG_NOTICE, "Parse error for catch at about line %d of %s\n", lineno, filename);
959                         } else {
960                                 fillin = NULL;
961                                 build_step("macro", vars->data, filename, lineno, con, "s", &pos, cur->data, NULL, NULL);
962                         }
963                         cur = cur->next;
964                 }
965         } else
966                 ast_log(LOG_WARNING, "Unable to create context '%s'\n", name);
967         arg_free(argv);
968         if (vars->next)
969                 ast_log(LOG_NOTICE, "Ignoring excess tokens in macro definition around line %d of %s!\n", lineno, filename);
970 }
971
972 static int matches_extension(char *exten, char **extout)
973 {
974         char *c;
975         *extout = NULL;
976         c = exten;
977         while(*c && (*c > 32)) c++;
978         if (*c) {
979                 *c = '\0';
980                 c++;
981                 while(*c && (*c < 33)) c++;
982                 if (*c) {
983                         if (*c == '=') {
984                                 *c = '\0';
985                                 c++;
986                                 if (*c == '>')
987                                         c++;
988                                 while (*c && (*c < 33)) c++;
989                                 *extout = c;
990                                 return 1;
991                         }
992                 }
993         }
994         return 0;
995 }
996
997 static void parse_keyword(char *s, char **o)
998 {
999         char *c;
1000         c = s;
1001         while((*c) && (*c > 32)) c++;
1002         if (*c) {
1003                 *c = '\0';
1004                 c++;
1005                 while(*c && (*c < 33)) c++;
1006                 *o = c;
1007         } else
1008                 *o = NULL;
1009 }
1010
1011 static void handle_context(struct ast_context **local_contexts, struct stringlink *vars, const char *filename, int lineno)
1012 {
1013         struct stringlink *argv;
1014         struct stringlink *paramv;
1015         struct stringlink *cur2;
1016         struct stringlink *argv2;
1017         struct stringlink *cur;
1018         struct ast_context *con;
1019         char *rest;
1020         char *c;
1021         char name[256];
1022         int pos;
1023
1024         if (aeldebug & DEBUG_CONTEXTS)
1025                 ast_verbose("Root context def is '%s'\n", vars->data);
1026         argv = split_token(vars->data, filename, lineno);
1027         paramv = split_params(vars->data, filename, lineno);
1028         if (aeldebug & DEBUG_CONTEXTS) 
1029                 ast_verbose("Found context '%s'\n", vars->data);
1030         snprintf(name, sizeof(name), "%s", vars->data);
1031         con = ast_context_create(local_contexts, name, registrar);
1032         if (con) {
1033                 cur = argv;
1034                 while(cur) {
1035                         if (matches_keyword(cur->data, "includes")) {
1036                                 if (aeldebug & DEBUG_CONTEXTS)
1037                                         ast_verbose("--INCLUDES: '%s'\n", cur->data);
1038                                 parse_keyword(cur->data, &rest);
1039                                 if (rest) {
1040                                         argv2 = arg_parse(rest, filename, lineno);
1041                                         cur2 = argv2;
1042                                         while(cur2) {
1043                                                 ast_context_add_include2(con, cur2->data, registrar);
1044                                                 cur2 = cur2->next;
1045                                         }
1046                                         arg_free(argv2);
1047                                 }
1048                         } else if (matches_keyword(cur->data, "ignorepat")) {
1049                                 if (aeldebug & DEBUG_CONTEXTS)
1050                                         ast_verbose("--IGNOREPAT: '%s'\n", cur->data);
1051                                 parse_keyword(cur->data, &rest);
1052                                 if (rest) {
1053                                         argv2 = arg_parse(rest, filename, lineno);
1054                                         cur2 = argv2;
1055                                         while(cur2) {
1056                                                 ast_context_add_ignorepat2(con, cur2->data, registrar);
1057                                                 cur2 = cur2->next;
1058                                         }
1059                                         arg_free(argv2);
1060                                 }
1061                         } else if (matches_keyword(cur->data, "switches") || matches_keyword(cur->data, "eswitches")) {
1062                                 if (aeldebug & DEBUG_CONTEXTS)
1063                                         ast_verbose("--[E]SWITCH: '%s'\n", cur->data);
1064                                 parse_keyword(cur->data, &rest);
1065                                 if (rest) {
1066                                         argv2 = arg_parse(rest, filename, lineno);
1067                                         cur2 = argv2;
1068                                         while(cur2) {
1069                                                 c = strchr(cur2->data, '/');
1070                                                 if (c) {
1071                                                         *c = '\0';
1072                                                         c++;
1073                                                 } else
1074                                                         c = "";
1075                                                 ast_context_add_switch2(con, cur2->data, c, (cur->data[0] == 'e'), registrar);
1076                                                 cur2 = cur2->next;
1077                                         }
1078                                         arg_free(argv2);
1079                                 }
1080                         } else if (matches_extension(cur->data, &rest)) {
1081                                 if (aeldebug & DEBUG_CONTEXTS)
1082                                         ast_verbose("Extension: '%s' => '%s'\n", cur->data, rest);
1083                                 pos = 1;
1084                                 build_step("extension", cur->data, filename, lineno, con, cur->data, &pos, rest, NULL, NULL);
1085                         }
1086                         cur = cur->next;
1087                 }
1088         } else
1089                         ast_log(LOG_WARNING, "Unable to create context '%s'\n", name);
1090         arg_free(argv);
1091         if (vars->next)
1092                 ast_log(LOG_NOTICE, "Ignoring excess tokens in macro definition around line %d of %s!\n", lineno, filename);
1093 }
1094
1095 static int handle_root_token(struct ast_context **local_contexts, char *token, int level, const char *filename, int lineno)
1096 {
1097         struct stringlink *argv, *cur;
1098         argv = split_token(token, filename, lineno);
1099         if (aeldebug & DEBUG_TOKENS) {
1100                 ast_verbose("Found root token '%s' at level %d (%s:%d)!\n", token, level, filename, lineno);
1101                 cur = argv;
1102                 while(cur) {
1103                         ast_verbose("   ARG => '%s'\n", cur->data);
1104                         cur = cur->next;
1105                 }
1106         }
1107         if (!strcasecmp(token, "globals")) {
1108                 handle_globals(argv);
1109         } else if (!strcasecmp(token, "macro")) {
1110                 handle_macro(local_contexts, argv, filename, lineno);
1111         } else if (!strcasecmp(token, "context")) {
1112                 handle_context(local_contexts, argv, filename, lineno);
1113         } else {
1114                 ast_log(LOG_NOTICE, "Unknown root token '%s'\n", token);
1115         }
1116         arg_free(argv);
1117         return 0;
1118 }
1119
1120
1121 static int ast_ael_compile(struct ast_context **local_contexts, const char *filename)
1122 {
1123         char *rfilename;
1124         char *buf, *tbuf;
1125         int bufsiz;
1126         FILE *f;
1127         char *c;
1128         char *token;
1129         int lineno=0;
1130
1131         if (filename[0] == '/')
1132                 rfilename = (char *)filename;
1133         else {
1134                 rfilename = alloca(strlen(filename) + strlen(ast_config_AST_CONFIG_DIR) + 2);
1135                 sprintf(rfilename, "%s/%s", ast_config_AST_CONFIG_DIR, filename);
1136         }
1137         
1138         f = fopen(rfilename, "r");
1139         if (!f) {
1140                 ast_log(LOG_WARNING, "Unable to open '%s': %s\n", rfilename, strerror(errno));
1141                 return -1;
1142         }
1143         buf = malloc(4096);
1144         if (!buf) {
1145                 ast_log(LOG_WARNING, "Out of memory!\n");
1146                 fclose(f);
1147                 return -1;
1148         }
1149         buf[0] = 0;
1150         bufsiz = 4096;
1151         while(!feof(f)) {
1152                 if (strlen(buf) - bufsiz < 2048) {
1153                         bufsiz += 4096;
1154                         tbuf = realloc(buf, bufsiz);
1155                         if (tbuf) {
1156                                 buf = tbuf;
1157                         } else {
1158                                 free(buf);
1159                                 ast_log(LOG_WARNING, "Out of memory!\n");
1160                                 fclose(f);
1161                         }
1162                 }
1163                 if (fgets(buf + strlen(buf), bufsiz - strlen(buf), f)) {
1164                         lineno++;
1165                         while(*buf && buf[strlen(buf) - 1] < 33)
1166                                 buf[strlen(buf) - 1] = '\0';
1167                         c = strstr(buf, "//");
1168                         if (c)
1169                                 *c = '\0';
1170                         if (*buf) {
1171                                 if (aeldebug & DEBUG_READ)
1172                                         ast_verbose("Newly composed line '%s'\n", buf);
1173                                 while((token = grab_token(buf, filename, lineno))) {
1174                                         handle_root_token(local_contexts, token, 0, filename, lineno);
1175                                         free(token);
1176                                 }
1177                         }
1178                 }
1179         };
1180         free(buf);
1181         fclose(f);
1182         return 0;
1183 }
1184
1185 static int pbx_load_module(void)
1186 {
1187         struct ast_context *local_contexts=NULL, *con;
1188         ast_ael_compile(&local_contexts, config);
1189         ast_merge_contexts_and_delete(&local_contexts, registrar);
1190         for (con = ast_walk_contexts(NULL); con; con = ast_walk_contexts(con))
1191                 ast_context_verify_includes(con);
1192         pbx_set_autofallthrough(1);
1193
1194 #if 0
1195                 v = ast_variable_browse(cfg, "globals");
1196                 while(v) {
1197                         memset(realvalue, 0, sizeof(realvalue));
1198                         pbx_substitute_variables_helper(NULL, v->value, realvalue, sizeof(realvalue) - 1);
1199                         pbx_builtin_setvar_helper(NULL, v->name, realvalue);
1200                         v = v->next;
1201                 }
1202                 cxt = ast_category_browse(cfg, NULL);
1203                 while(cxt) {
1204                         /* All categories but "general" or "globals" are considered contexts */
1205                         if (!strcasecmp(cxt, "general") || !strcasecmp(cxt, "globals")) {
1206                                 cxt = ast_category_browse(cfg, cxt);
1207                                 continue;
1208                         }
1209                         if ((con=ast_context_create(&local_contexts,cxt, registrar))) {
1210                                 v = ast_variable_browse(cfg, cxt);
1211                                 while(v) {
1212                                         if (!strcasecmp(v->name, "exten")) {
1213                                                 char *stringp=NULL;
1214                                                 int ipri = -2;
1215                                                 char realext[256]="";
1216                                                 char *plus;
1217                                                 tc = strdup(v->value);
1218                                                 if(tc!=NULL){
1219                                                         stringp=tc;
1220                                                         ext = strsep(&stringp, ",");
1221                                                         if (!ext)
1222                                                                 ext="";
1223                                                         cidmatch = strchr(ext, '/');
1224                                                         if (cidmatch) {
1225                                                                 *cidmatch = '\0';
1226                                                                 cidmatch++;
1227                                                                 ast_shrink_phone_number(cidmatch);
1228                                                         }
1229                                                         pri = strsep(&stringp, ",");
1230                                                         if (!pri)
1231                                                                 pri="";
1232                                                         label = strchr(pri, '(');
1233                                                         if (label) {
1234                                                                 *label = '\0';
1235                                                                 label++;
1236                                                                 end = strchr(label, ')');
1237                                                                 if (end)
1238                                                                         *end = '\0';
1239                                                                 else
1240                                                                         ast_log(LOG_WARNING, "Label missing trailing ')' at line %d\n", v->lineno);
1241                                                         }
1242                                                         plus = strchr(pri, '+');
1243                                                         if (plus) {
1244                                                                 *plus = '\0';
1245                                                                 plus++;
1246                                                         }
1247                                                         if (!strcmp(pri,"hint"))
1248                                                                 ipri=PRIORITY_HINT;
1249                                                         else if (!strcmp(pri, "next") || !strcmp(pri, "n")) {
1250                                                                 if (lastpri > -2)
1251                                                                         ipri = lastpri + 1;
1252                                                                 else
1253                                                                         ast_log(LOG_WARNING, "Can't use 'next' priority on the first entry!\n");
1254                                                         } else if (!strcmp(pri, "same") || !strcmp(pri, "s")) {
1255                                                                 if (lastpri > -2)
1256                                                                         ipri = lastpri;
1257                                                                 else
1258                                                                         ast_log(LOG_WARNING, "Can't use 'same' priority on the first entry!\n");
1259                                                         } else  {
1260                                                                 if (sscanf(pri, "%i", &ipri) != 1) {
1261                                                                         if ((ipri = ast_findlabel_extension2(NULL, con, ext, pri, cidmatch)) < 1) {
1262                                                                                 ast_log(LOG_WARNING, "Invalid priority/label '%s' at line %d\n", pri, v->lineno);
1263                                                                                 ipri = 0;
1264                                                                         }
1265                                                                 }
1266                                                         }
1267                                                         appl = stringp;
1268                                                         if (!appl)
1269                                                                 appl="";
1270                                                         if (!(start = strchr(appl, '('))) {
1271                                                                 if (stringp)
1272                                                                         appl = strsep(&stringp, ",");
1273                                                                 else
1274                                                                         appl = "";
1275                                                         }
1276                                                         if (start && (end = strrchr(appl, ')'))) {
1277                                                                 *start = *end = '\0';
1278                                                                 data = start + 1;
1279                                                                 process_quotes_and_slashes(data, ',', '|');
1280                                                         } else if (stringp!=NULL && *stringp=='"') {
1281                                                                 stringp++;
1282                                                                 data = strsep(&stringp, "\"");
1283                                                                 stringp++;
1284                                                         } else {
1285                                                                 if (stringp)
1286                                                                         data = strsep(&stringp, ",");
1287                                                                 else
1288                                                                         data = "";
1289                                                         }
1290
1291                                                         if (!data)
1292                                                                 data="";
1293                                                         while(*appl && (*appl < 33)) appl++;
1294                                                         pbx_substitute_variables_helper(NULL, ext, realext, sizeof(realext) - 1);
1295                                                         if (ipri) {
1296                                                                 if (plus)
1297                                                                         ipri += atoi(plus);
1298                                                                 lastpri = ipri;
1299                                                                 if (!strcmp(realext, "_."))
1300                                                                         ast_log(LOG_WARNING, "The use of '_.' for an extension is strongly discouraged and can have unexpected behavior.  Please use '_X.' instead at line %d\n", v->lineno);
1301                                                                 if (ast_add_extension2(con, 0, realext, ipri, label, cidmatch, appl, strdup(data), FREE, registrar)) {
1302                                                                         ast_log(LOG_WARNING, "Unable to register extension at line %d\n", v->lineno);
1303                                                                 }
1304                                                         }
1305                                                         free(tc);
1306                                                 } else fprintf(stderr,"Error strdup returned NULL in %s\n",__PRETTY_FUNCTION__);
1307                                         } else if(!strcasecmp(v->name, "include")) {
1308                                                 memset(realvalue, 0, sizeof(realvalue));
1309                                                 pbx_substitute_variables_helper(NULL, v->value, realvalue, sizeof(realvalue) - 1);
1310                                                 if (ast_context_add_include2(con, realvalue, registrar))
1311                                                         ast_log(LOG_WARNING, "Unable to include context '%s' in context '%s'\n", v->value, cxt);
1312                                         } else if(!strcasecmp(v->name, "ignorepat")) {
1313                                                 memset(realvalue, 0, sizeof(realvalue));
1314                                                 pbx_substitute_variables_helper(NULL, v->value, realvalue, sizeof(realvalue) - 1);
1315                                                 if (ast_context_add_ignorepat2(con, realvalue, registrar))
1316                                                         ast_log(LOG_WARNING, "Unable to include ignorepat '%s' in context '%s'\n", v->value, cxt);
1317                                         } else if (!strcasecmp(v->name, "switch") || !strcasecmp(v->name, "lswitch") || !strcasecmp(v->name, "eswitch")) {
1318                                                 char *stringp=NULL;
1319                                                 memset(realvalue, 0, sizeof(realvalue));
1320                                                 if (!strcasecmp(v->name, "switch"))
1321                                                         pbx_substitute_variables_helper(NULL, v->value, realvalue, sizeof(realvalue) - 1);
1322                                                 else
1323                                                         strncpy(realvalue, v->value, sizeof(realvalue) - 1);
1324                                                 tc = realvalue;
1325                                                 stringp=tc;
1326                                                 appl = strsep(&stringp, "/");
1327                                                 data = strsep(&stringp, "");
1328                                                 if (!data)
1329                                                         data = "";
1330                                                 if (ast_context_add_switch2(con, appl, data, !strcasecmp(v->name, "eswitch"), registrar))
1331                                                         ast_log(LOG_WARNING, "Unable to include switch '%s' in context '%s'\n", v->value, cxt);
1332                                         }
1333                                         v = v->next;
1334                                 }
1335                         }
1336                         cxt = ast_category_browse(cfg, cxt);
1337                 }
1338                 ast_config_destroy(cfg);
1339         }
1340         ast_merge_contexts_and_delete(&local_contexts,registrar);
1341
1342         for (con = ast_walk_contexts(NULL); con; con = ast_walk_contexts(con))
1343                 ast_context_verify_includes(con);
1344
1345         pbx_set_autofallthrough(autofallthrough_config);
1346 #endif
1347
1348         return 0;
1349 }
1350
1351 int load_module(void)
1352 {
1353         if (pbx_load_module()) return -1;
1354  
1355         return 0;
1356 }
1357
1358 int reload(void)
1359 {
1360         ast_context_destroy(NULL, registrar);
1361         /* For martin's global variables, don't clear them on reload */
1362         pbx_load_module();
1363         return 0;
1364 }
1365
1366 int usecount(void)
1367 {
1368         return 0;
1369 }
1370
1371 char *description(void)
1372 {
1373         return dtext;
1374 }
1375
1376 char *key(void)
1377 {
1378         return ASTERISK_GPL_KEY;
1379 }