use matching char types for strings (issue #5106)
[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         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         int inpar = 0;
439         c = variable;
440         
441         while(*c && (*c > 32)) {
442           if(*c == ')' && (inpar > 0)) {
443             inpar--;
444           } else if(*c == '(' && (inpar >= 0)) {
445             inpar++;
446           } else if(*c == '=' && (inpar == 0)) {
447             break;
448           }
449           c++;
450         } 
451         ws = c;
452         while(*c && (*c < 33)) c++;
453         if (*c == '=') {
454                 *ws = '\0';
455                 *c = '\0';
456                 c++;
457                 while ((*c) && (*c < 33)) c++;
458                 *value = c;
459                 return 1;
460         }
461         return 0;
462 }
463
464 static int matches_label(char *data, char **rest)
465 {
466         char last = 0;
467         char *start = data;
468         while (*data > 32) {
469                 last = *data;
470                 data++;
471         }
472         if (last != ':') {
473                 while (*data && (*data < 33)) data++;
474                 last = *data;
475                 data++;
476         }
477         if (last == ':') {
478                 *rest = data;
479                 /* Go back and trim up the label */
480                 while(*start && ((*start > 32) && (*start != ':'))) start++;
481                 *start = '\0';
482                 return 1;
483         }
484         return 0;
485 }
486
487 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);
488 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)
489 {
490         char *app;
491         char *args;
492         char *c;
493         char *margs=NULL;
494         char *oargs;
495         char *rest;
496         const char *curcase, *newcase;
497         struct stringlink *swargs, *cur;
498         int cpos;
499         int mlen;
500         int pattern = 0;
501         struct fillin *fillin;
502         while (*data && (*data < 33)) data++;
503         if (matches_label(data, &c)) {
504                 *label = data;
505                 data = c;
506                 while (*data && (*data < 33)) data++;
507         }
508         if (!data || ast_strlen_zero(data))
509                 return 0;
510         if (matches_keyword(data, "switch")) {
511                 fillin = NULL;
512                 /* Switch */
513                 args = data + strlen("switch");
514                 while ((*args < 33) && (*args != '(')) args++;
515                 if ((*args == '(') && (c = strchr(args, ')'))) {
516                         args++;
517                         *c = '\0';
518                         c++;
519                         if (aeldebug & DEBUG_TOKENS)
520                                 ast_verbose("--SWITCH on : %s\n", args);
521                         mlen = strlen(exten) + 128 + strlen(args) + strlen(name);
522                         margs = alloca(mlen);
523                         app = "Goto";
524                         sprintf(margs, "sw-%s-%d-%s|1", name, *pos, args);
525                         process_quotes_and_slashes(margs, ',', '|');
526                         oargs = args;
527                         args = margs;
528                         if (ast_add_extension2(con, 0, exten, *pos, *label, NULL, app, strdup(args), FREE, registrar))
529                                 ast_log(LOG_WARNING, "Unable to add step at priority '%d' of %s '%s'\n", *pos, what, name);
530                         else {
531                                 *label = NULL;
532                                 (*pos)++;
533                         }
534                         app = "NoOp";
535                         sprintf(margs, "Finish switch-%s-%d", name, *pos - 1);
536                         if (ast_add_extension2(con, 0, exten, *pos, *label, NULL, app, strdup(args), FREE, registrar))
537                                 ast_log(LOG_WARNING, "Unable to add step at priority '%d' of %s '%s'\n", *pos, what, name);
538                         else {
539                                 *label = NULL;
540                                 (*pos)++;
541                         }
542                         while(*c && (*c < 33)) c++;
543                         if (aeldebug & DEBUG_TOKENS)
544                                 ast_verbose("ARG Parsing '%s'\n", c);
545                         swargs = arg_parse(c, filename, lineno);
546                         cur = swargs;
547                         curcase = NULL;
548                         while(cur) {
549                                 if ((newcase = get_case(cur->data, &rest, &pattern))) {
550                                         if (aeldebug & DEBUG_TOKENS)
551                                                 ast_verbose("--NEWCASE: '%s'!\n", newcase);
552                                         if (curcase) {
553                                                 /* Handle fall through */
554                                                 char tmp[strlen(newcase) + strlen(name) + 40];
555                                                 sprintf(tmp, "sw-%s-%d-%s|%d", name, *pos - 2, newcase, 1);
556                                                 ast_add_extension2(con, 0, margs, cpos, NULL, NULL, "Goto", strdup(tmp), FREE, registrar);
557                                         }
558                                         curcase = newcase;
559                                         cpos = 1;
560                                         if (pattern)
561                                                 snprintf(margs, mlen, "_sw-%s-%d-%s", name, *pos - 2, curcase);
562                                         else
563                                                 snprintf(margs, mlen, "sw-%s-%d-%s", name, *pos - 2, curcase);
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, exten, 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 if (curcase) {
573                                         if (aeldebug & DEBUG_TOKENS)
574                                                 ast_verbose("Building statement from '%s'\n", rest);
575                                         if (!strcasecmp(rest, "break")) {
576                                                 char tmp[strlen(exten) + 10];
577                                                 sprintf(tmp, "%s|%d", exten, *pos - 1);
578                                                 ast_add_extension2(con, 0, margs, cpos, *label, NULL, "Goto", strdup(tmp), FREE, registrar);
579                                                 curcase = NULL;
580                                                 *label = NULL;
581                                         } else
582                                                 build_step("switch", margs, filename, lineno, con, margs, &cpos, rest, &fillin, label);
583                                 } else 
584                                         ast_log(LOG_WARNING, "Unreachable code in switch at about line %d of %s\n", lineno, filename);
585                                 if (aeldebug & DEBUG_TOKENS)
586                                         ast_verbose("--SWARG: %s\n", cur->data);
587                                 cur = cur->next;
588                         }
589                         /* Can't do anything with these */
590                         fillin_process(con, fillin, filename, lineno, NULL, 0, NULL, 0);
591                         fillin_free(fillin);
592                         arg_free(swargs);
593                 } else
594                         ast_log(LOG_WARNING, "Syntax error in switch declaration in %s around line %d!\n", filename, lineno); 
595                         
596         } else if (matches_keyword(data, "if")) {
597                 /* If... */
598                 args = data + strlen("if");
599                 while ((*args < 33) && (*args != '(')) args++;
600                 if ((*args == '(') && (c = strchr(args, ')'))) {
601                         int ifblock;
602                         int ifstart;
603                         int elsestart;
604                         int ifend;
605                         int ifskip;
606                         char *elses;
607                         char *iflabel;
608                         args++;
609                         *c = '\0';
610                         c++;
611                         while(*c && (*c < 33)) c++;
612                         if (aeldebug & DEBUG_TOKENS)
613                                 ast_verbose("--IF on : '%s' : '%s'\n", args, c);
614                         mlen = strlen(exten) + 128 + strlen(args) + strlen(name);
615                         margs = alloca(mlen);
616                         /* Remember where the ifblock starts, and skip over */
617                         ifblock = (*pos)++;
618                         iflabel = *label;
619                         *label = NULL;
620                         /* Remember where the start of the ifblock is */
621                         ifstart = *pos;
622                         snprintf(margs, mlen, "if-%s-%d", name, ifblock);
623                         /* Now process the block of the if */
624                         if (aeldebug & DEBUG_TOKENS)
625                                 ast_verbose("Searching for elses in '%s'\n", c);
626                         elses = grab_else(c, filename, lineno);
627                         build_step("if", margs, filename, lineno, con, exten, pos, c, fillout, label);
628                         if (elses) {
629                                 /* Reserve a goto to exit the if */
630                                 ifskip = *pos;
631                                 (*pos)++;
632                                 elsestart = *pos;
633                                 build_step("else", margs, filename, lineno, con, exten, pos, elses, fillout, label);
634                         } else {
635                                 elsestart = *pos;
636                                 ifskip = 0;
637                         }
638                         ifend = *pos;
639                         (*pos)++;
640                         app = "NoOp";
641                         snprintf(margs, mlen, "Finish if-%s-%d", name, ifblock);
642                         if (ast_add_extension2(con, 0, exten, ifend, *label, NULL, app, strdup(margs), FREE, registrar))
643                                 ast_log(LOG_WARNING, "Unable to add step at priority '%d' of %s '%s'\n", *pos, what, name);
644                         *label = NULL;
645                         app = "GotoIf";
646                         snprintf(margs, mlen, "$[ %s ]?%d:%d", args, ifstart, elsestart);
647                         if (ast_add_extension2(con, 0, exten, ifblock, iflabel, NULL, app, strdup(margs), FREE, registrar))
648                                 ast_log(LOG_WARNING, "Unable to add step at priority '%d' of %s '%s'\n", *pos, what, name);
649                         if (ifskip) {
650                                 /* Skip as appropriate around else clause */
651                                 snprintf(margs, mlen, "%d", ifend);
652                                 if (ast_add_extension2(con, 0, exten, ifskip, NULL, NULL, app, strdup(margs), FREE, registrar))
653                                         ast_log(LOG_WARNING, "Unable to add step at priority '%d' of %s '%s'\n", *pos, what, name);
654                         }
655                 } else
656                         ast_log(LOG_WARNING, "Syntax error in if declaration in %s around line %d!\n", filename, lineno); 
657         } else if (matches_keyword(data, "while")) {
658                 /* While... */
659                 fillin = NULL;
660                 args = data + strlen("while");
661                 while ((*args < 33) && (*args != '(')) args++;
662                 if ((*args == '(') && (c = strchr(args, ')'))) {
663                         int whileblock;
664                         int whilestart;
665                         int whileend;
666                         char *whilelabel;
667                         args++;
668                         *c = '\0';
669                         c++;
670                         while(*c && (*c < 33)) c++;
671                         if (aeldebug & DEBUG_TOKENS)
672                                 ast_verbose("--WHILE on : '%s' : '%s'\n", args, c);
673                         mlen = strlen(exten) + 128 + strlen(args) + strlen(name);
674                         margs = alloca(mlen);
675                         /* Remember where to put the conditional, and keep its position */
676                         whilestart = (*pos);
677                         whilelabel = *label;
678                         *label = NULL;
679                         (*pos)++;
680                         /* Remember where the whileblock starts */
681                         whileblock = (*pos);
682                         snprintf(margs, mlen, "while-%s-%d", name, whilestart);
683                         build_step("while", margs, filename, lineno, con, exten, pos, c, &fillin, label);
684                         /* Close the loop */
685                         app = "Goto";
686                         snprintf(margs, mlen, "%d", whilestart);
687                         if (ast_add_extension2(con, 0, exten, (*pos)++, *label, NULL, app, strdup(margs), FREE, registrar))
688                                 ast_log(LOG_WARNING, "Unable to add step at priority '%d' of %s '%s'\n", *pos, what, name);
689                         *label = NULL;
690                         whileend = (*pos);
691                         /* Place trailer */
692                         app = "NoOp";
693                         snprintf(margs, mlen, "Finish while-%s-%d", name, whilestart);
694                         if (ast_add_extension2(con, 0, exten, (*pos)++, *label, NULL, app, strdup(margs), FREE, registrar))
695                                 ast_log(LOG_WARNING, "Unable to add step at priority '%d' of %s '%s'\n", *pos, what, name);
696                         *label = NULL;
697                         app = "GotoIf";
698                         snprintf(margs, mlen, "$[ %s ]?%d:%d", args, whileblock, whileend);
699                         if (ast_add_extension2(con, 0, exten, whilestart, whilelabel, NULL, app, strdup(margs), FREE, registrar))
700                                 ast_log(LOG_WARNING, "Unable to add step at priority '%d' of %s '%s'\n", *pos, what, name);
701                         fillin_process(con, fillin, filename, lineno, exten, whileend, exten, whilestart);
702                         fillin_free(fillin);
703                 } else
704                         ast_log(LOG_WARNING, "Syntax error in while declaration in %s around line %d!\n", filename, lineno); 
705         } else if (matches_keyword(data, "jump")) {
706                 char *p;
707                 /* Jump... */
708                 fillin = NULL;
709                 args = data + strlen("jump");
710                 while(*args && (*args < 33)) args++;
711                 if (aeldebug & DEBUG_TOKENS)
712                         ast_verbose("--JUMP to : '%s'\n", args);
713                 p = strchr(args, ',');
714                 if (p) {
715                         *p = '\0';
716                         p++;
717                 } else
718                         p = "1";
719                 c = strchr(args, '@');
720                 if (c) {
721                         *c = '\0';
722                         c++;
723                 }
724                 mlen = strlen(exten) + 128 + strlen(args) + strlen(name) + (c ? strlen(c) : 0);
725                 margs = alloca(mlen);
726                 if (c) 
727                         snprintf(margs, mlen, "%s|%s|%s", c,args, p);
728                 else
729                         snprintf(margs, mlen, "%s|%s", args, p);
730                 app = "Goto";
731                 if (ast_add_extension2(con, 0, exten, (*pos)++, *label, NULL, app, strdup(margs), 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, "goto")) {
735                 /* Jump... */
736                 fillin = NULL;
737                 args = data + strlen("goto");
738                 while(*args && (*args < 33)) args++;
739                 if (aeldebug & DEBUG_TOKENS)
740                         ast_verbose("--GOTO to : '%s'\n", args);
741                 app = "Goto";
742                 if (ast_add_extension2(con, 0, exten, (*pos)++, *label, NULL, app, strdup(args), FREE, registrar))
743                         ast_log(LOG_WARNING, "Unable to add step at priority '%d' of %s '%s'\n", *pos, what, name);
744                 *label = NULL;
745         } else if (matches_keyword(data, "for")) {
746                 /* While... */
747                 fillin = NULL;
748                 args = data + strlen("for");
749                 while ((*args < 33) && (*args != '(')) args++;
750                 if ((*args == '(') && (c = strchr(args, ')'))) {
751                         int forblock;
752                         int forprep;
753                         int forstart;
754                         int forend;
755                         struct stringlink *fields;
756                         char *tmp;
757                         char *forlabel = NULL;
758                         args++;
759                         *c = '\0';
760                         c++;
761                         while(*c && (*c < 33)) c++;
762                         /* Parse arguments first */
763                         tmp = alloca(strlen(args) + 10);
764                         if (tmp) {
765                                 snprintf(tmp, strlen(args) + 10, "{%s;}", args);
766                                 fields = arg_parse(tmp, filename, lineno);
767                         } else
768                                 fields = NULL;
769                         if (fields && fields->next && fields->next->next) {
770                                 if (aeldebug & DEBUG_TOKENS)
771                                         ast_verbose("--FOR ('%s' ; '%s' ; '%s') : '%s'\n", fields->data, fields->next->data, fields->next->next->data, c);
772                                 mlen = strlen(exten) + 128 + strlen(args) + strlen(name);
773                                 margs = alloca(mlen);
774                                 forprep = *pos;
775                                 snprintf(margs, mlen, "for-%s-%d", name, forprep);
776                                 fillin = NULL;
777                                 build_step("while", margs, filename, lineno, con, exten, pos, fields->data, &fillin, label);
778                                 /* Remember where to put the conditional, and keep its position */
779                                 forstart = (*pos);
780                                 forlabel = *label;
781                                 (*pos)++;
782                                 *label = NULL;
783                                 /* Remember where the whileblock starts */
784                                 forblock = (*pos);
785                                 build_step("for", margs, filename, lineno, con, exten, pos, fields->next->next->data, &fillin, label);
786                                 build_step("for", margs, filename, lineno, con, exten, pos, c, &fillin, label);
787                                 /* Close the loop */
788                                 app = "Goto";
789                                 snprintf(margs, mlen, "%d", forstart);
790                                 if (ast_add_extension2(con, 0, exten, (*pos)++, *label, NULL, app, strdup(margs), FREE, registrar))
791                                         ast_log(LOG_WARNING, "Unable to add step at priority '%d' of %s '%s'\n", *pos, what, name);
792                                 *label = NULL;
793                                 forend = (*pos);
794                                 /* Place trailer */
795                                 app = "NoOp";
796                                 snprintf(margs, mlen, "Finish for-%s-%d", name, forprep);
797                                 if (ast_add_extension2(con, 0, exten, (*pos)++, *label, NULL, app, strdup(margs), FREE, registrar))
798                                         ast_log(LOG_WARNING, "Unable to add step at priority '%d' of %s '%s'\n", *pos, what, name);
799                                 *label = NULL;
800                                 app = "GotoIf";
801                                 snprintf(margs, mlen, "$[ %s ]?%d:%d", fields->next->data, forblock, forend);
802                                 if (ast_add_extension2(con, 0, exten, forstart, forlabel, NULL, app, strdup(margs), FREE, registrar))
803                                         ast_log(LOG_WARNING, "Unable to add step at priority '%d' of %s '%s'\n", forstart, what, name);
804                                 fillin_process(con, fillin, filename, lineno, exten, forend, exten, forstart);
805                                 fillin_free(fillin);
806                         } else
807                                 ast_log(LOG_NOTICE, "Improper for declaration in %s around line %d!\n", filename, lineno); 
808                         arg_free(fields);
809                 } else
810                         ast_log(LOG_WARNING, "Syntax error in for declaration in %s around line %d!\n", filename, lineno); 
811                         
812         } else if (!strcasecmp(data, "break") || !strcasecmp(data, "continue")) {
813                 struct fillin *fi;
814                 fi = malloc(sizeof(struct fillin));
815                 if (fi) {
816                         memset(fi, 0, sizeof(struct fillin));
817                         if (!strcasecmp(data, "break"))
818                                 fi->type = FILLIN_BREAK;
819                         else
820                                 fi->type = FILLIN_CONTINUE;
821                         ast_copy_string(fi->exten, exten, sizeof(fi->exten));
822                         fi->priority = (*pos)++;
823                         fi->next = *fillout;
824                         *fillout = fi;
825                 }
826         } else if (match_assignment(data, &rest)) {
827                 if (aeldebug & DEBUG_TOKENS)
828                         ast_verbose("ASSIGN  '%s' = '%s'\n", data, rest);
829                 mlen = strlen(rest) + strlen(data) + 20;
830                 margs = alloca(mlen);
831                 snprintf(margs, mlen, "%s=$[ %s ]", data, rest);
832                 app = "Set";
833                 if (ast_add_extension2(con, 0, exten, *pos, *label, NULL, app, strdup(margs), FREE, registrar))
834                         ast_log(LOG_WARNING, "Unable to add assignment at priority '%d' of %s '%s'\n", *pos, what, name);
835                 else {
836                         *label = NULL;
837                         (*pos)++;
838                 }
839         } else {
840                 app = data;
841                 args = app;
842                 while (*args && (*args > 32) && (*args != '(')) args++;
843                         if (*args != '(') {
844                         while(*args && (*args != '(')) { *args = '\0'; args++; };
845                 }
846                 if (*args == '(') {
847                         *args = '\0';
848                         args++;
849                         /* Got arguments, trim trailing ')' */
850                         c = args + strlen(args) - 1;
851                         while((c >= args) && (*c < 33) && (*c != ')')) { *c = '\0'; c--; };
852                         if ((c >= args) && (*c == ')')) *c = '\0';
853                 } else
854                         args = "";
855                 process_quotes_and_slashes(args, ',', '|');
856                 if (app[0] == '&') {
857                         app++;
858                         margs = alloca(strlen(args) + strlen(app) + 10);
859                         sprintf(margs, "%s|%s", app, args);
860                         args = margs;
861                         app = "Macro";
862                 }
863                 if (aeldebug & DEBUG_TOKENS)
864                         ast_verbose("-- APP: '%s', ARGS: '%s'\n", app, args);
865                 if (ast_add_extension2(con, 0, exten, *pos, *label, NULL, app, strdup(args), FREE, registrar))
866                         ast_log(LOG_WARNING, "Unable to add step at priority '%d' of %s '%s'\n", *pos, what, name);
867                 else {
868                         (*pos)++;
869                         *label = NULL;
870                 }
871         }
872         return 0;
873 }
874
875 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)
876 {
877         struct stringlink *args, *cur;
878         int res=0;
879         struct fillin *fillin=NULL;
880         int dropfill = 0;
881         char *labelin = NULL;
882         if (!fillout) {
883                 fillout = &fillin;
884                 dropfill = 1;
885         }
886         if (!label) {
887                 label = &labelin;
888         };
889         args = arg_parse(data, filename, lineno);
890         cur = args;
891         while(cur) {
892                 res |= __build_step(what, name, filename, lineno, con, exten, pos, cur->data, fillout, label);
893                 cur = cur->next;
894         }
895         arg_free(args);
896         if (dropfill) {
897                 fillin_process(con, fillin, filename, lineno, NULL, 0, NULL, 0);
898                 fillin_free(fillin);
899         }
900         return res;
901 }
902
903 static int parse_catch(char *data, char **catch, char **rest)
904 {
905         /* Skip the word 'catch' */
906         data += 5;
907         while (*data && (*data < 33)) data++;
908         /* Here's the extension */
909         *catch = data;
910         if (!*data)
911                 return 0;
912         while (*data && (*data > 32)) data++;
913         if (!*data)
914                 return 0;
915         /* Trim any trailing spaces */
916         *data = '\0';
917         data++;
918         while(*data && (*data < 33)) data++;
919         if (!*data)
920                 return 0;
921         *rest = data;
922         return 1;
923 }
924
925 static void handle_macro(struct ast_context **local_contexts, struct stringlink *vars, const char *filename, int lineno)
926 {
927         struct stringlink *argv;
928         struct stringlink *paramv;
929         struct stringlink *cur;
930         struct ast_context *con;
931         struct fillin *fillin;
932         char *catch, *rest;
933         char name[256];
934         int pos;
935         int cpos;
936
937         if (aeldebug & DEBUG_MACROS)
938                 ast_verbose("Root macro def is '%s'\n", vars->data);
939         argv = split_token(vars->data, filename, lineno);
940         paramv = split_params(vars->data, filename, lineno);
941         if (aeldebug & DEBUG_MACROS) 
942                 ast_verbose("Found macro '%s'\n", vars->data);
943         snprintf(name, sizeof(name), "macro-%s", vars->data);
944         con = ast_context_create(local_contexts, name, registrar);
945         if (con) {
946                 pos = 1;
947                 cur = paramv;
948                 while(cur) {
949                         if (aeldebug & DEBUG_MACROS)
950                                 ast_verbose("  PARAM => '%s'\n", cur->data);
951                         snprintf(name, sizeof(name), "%s=${ARG%d}", cur->data, pos);
952                         if (ast_add_extension2(con, 0, "s", pos, NULL, NULL, "Set", strdup(name), FREE, registrar))
953                                 ast_log(LOG_WARNING, "Unable to add step at priority '%d' of macro '%s'\n", pos, vars->data);
954                         else
955                                 pos++;
956                         cur = cur->next;
957                 }
958                 cur = argv;
959                 while(cur) {
960                         if (aeldebug & DEBUG_MACROS)
961                                 ast_verbose("  STEP => '%s'\n", cur->data);
962                         if (matches_keyword(cur->data, "catch")) {
963                                 if (aeldebug & DEBUG_MACROS)
964                                         ast_verbose("--CATCH: '%s'\n", cur->data);
965                                 if (parse_catch(cur->data, &catch, &rest)) {
966                                         cpos = 1;
967                                         build_step("catch", catch, filename, lineno, con, catch, &cpos, rest, NULL, NULL);
968                                 } else
969                                         ast_log(LOG_NOTICE, "Parse error for catch at about line %d of %s\n", lineno, filename);
970                         } else {
971                                 fillin = NULL;
972                                 build_step("macro", vars->data, filename, lineno, con, "s", &pos, cur->data, NULL, NULL);
973                         }
974                         cur = cur->next;
975                 }
976         } else
977                 ast_log(LOG_WARNING, "Unable to create context '%s'\n", name);
978         arg_free(argv);
979         if (vars->next)
980                 ast_log(LOG_NOTICE, "Ignoring excess tokens in macro definition around line %d of %s!\n", lineno, filename);
981 }
982
983 static int matches_extension(char *exten, char **extout)
984 {
985         char *c;
986         *extout = NULL;
987         c = exten;
988         while(*c && (*c > 32)) c++;
989         if (*c) {
990                 *c = '\0';
991                 c++;
992                 while(*c && (*c < 33)) c++;
993                 if (*c) {
994                         if (*c == '=') {
995                                 *c = '\0';
996                                 c++;
997                                 if (*c == '>')
998                                         c++;
999                                 while (*c && (*c < 33)) c++;
1000                                 *extout = c;
1001                                 return 1;
1002                         }
1003                 }
1004         }
1005         return 0;
1006 }
1007
1008 static void parse_keyword(char *s, char **o)
1009 {
1010         char *c;
1011         c = s;
1012         while((*c) && (*c > 32)) c++;
1013         if (*c) {
1014                 *c = '\0';
1015                 c++;
1016                 while(*c && (*c < 33)) c++;
1017                 *o = c;
1018         } else
1019                 *o = NULL;
1020 }
1021
1022 static void handle_context(struct ast_context **local_contexts, struct stringlink *vars, const char *filename, int lineno)
1023 {
1024         struct stringlink *argv;
1025         struct stringlink *paramv;
1026         struct stringlink *cur2;
1027         struct stringlink *argv2;
1028         struct stringlink *cur;
1029         struct ast_context *con;
1030         char *rest;
1031         char *c;
1032         char name[256];
1033         int pos;
1034
1035         if (aeldebug & DEBUG_CONTEXTS)
1036                 ast_verbose("Root context def is '%s'\n", vars->data);
1037         argv = split_token(vars->data, filename, lineno);
1038         paramv = split_params(vars->data, filename, lineno);
1039         if (aeldebug & DEBUG_CONTEXTS) 
1040                 ast_verbose("Found context '%s'\n", vars->data);
1041         snprintf(name, sizeof(name), "%s", vars->data);
1042         con = ast_context_create(local_contexts, name, registrar);
1043         if (con) {
1044                 cur = argv;
1045                 while(cur) {
1046                         if (matches_keyword(cur->data, "includes")) {
1047                                 if (aeldebug & DEBUG_CONTEXTS)
1048                                         ast_verbose("--INCLUDES: '%s'\n", cur->data);
1049                                 parse_keyword(cur->data, &rest);
1050                                 if (rest) {
1051                                         argv2 = arg_parse(rest, filename, lineno);
1052                                         cur2 = argv2;
1053                                         while(cur2) {
1054                                                 ast_context_add_include2(con, cur2->data, registrar);
1055                                                 cur2 = cur2->next;
1056                                         }
1057                                         arg_free(argv2);
1058                                 }
1059                         } else if (matches_keyword(cur->data, "ignorepat")) {
1060                                 if (aeldebug & DEBUG_CONTEXTS)
1061                                         ast_verbose("--IGNOREPAT: '%s'\n", cur->data);
1062                                 parse_keyword(cur->data, &rest);
1063                                 if (rest) {
1064                                         argv2 = arg_parse(rest, filename, lineno);
1065                                         cur2 = argv2;
1066                                         while(cur2) {
1067                                                 ast_context_add_ignorepat2(con, cur2->data, registrar);
1068                                                 cur2 = cur2->next;
1069                                         }
1070                                         arg_free(argv2);
1071                                 }
1072                         } else if (matches_keyword(cur->data, "switches") || matches_keyword(cur->data, "eswitches")) {
1073                                 if (aeldebug & DEBUG_CONTEXTS)
1074                                         ast_verbose("--[E]SWITCH: '%s'\n", cur->data);
1075                                 parse_keyword(cur->data, &rest);
1076                                 if (rest) {
1077                                         argv2 = arg_parse(rest, filename, lineno);
1078                                         cur2 = argv2;
1079                                         while(cur2) {
1080                                                 c = strchr(cur2->data, '/');
1081                                                 if (c) {
1082                                                         *c = '\0';
1083                                                         c++;
1084                                                 } else
1085                                                         c = "";
1086                                                 ast_context_add_switch2(con, cur2->data, c, (cur->data[0] == 'e'), registrar);
1087                                                 cur2 = cur2->next;
1088                                         }
1089                                         arg_free(argv2);
1090                                 }
1091                         } else if (matches_extension(cur->data, &rest)) {
1092                                 if (aeldebug & DEBUG_CONTEXTS)
1093                                         ast_verbose("Extension: '%s' => '%s'\n", cur->data, rest);
1094                                 pos = 1;
1095                                 build_step("extension", cur->data, filename, lineno, con, cur->data, &pos, rest, NULL, NULL);
1096                         }
1097                         cur = cur->next;
1098                 }
1099         } else
1100                         ast_log(LOG_WARNING, "Unable to create context '%s'\n", name);
1101         arg_free(argv);
1102         if (vars->next)
1103                 ast_log(LOG_NOTICE, "Ignoring excess tokens in macro definition around line %d of %s!\n", lineno, filename);
1104 }
1105
1106 static int handle_root_token(struct ast_context **local_contexts, char *token, int level, const char *filename, int lineno)
1107 {
1108         struct stringlink *argv, *cur;
1109         argv = split_token(token, filename, lineno);
1110         if (aeldebug & DEBUG_TOKENS) {
1111                 ast_verbose("Found root token '%s' at level %d (%s:%d)!\n", token, level, filename, lineno);
1112                 cur = argv;
1113                 while(cur) {
1114                         ast_verbose("   ARG => '%s'\n", cur->data);
1115                         cur = cur->next;
1116                 }
1117         }
1118         if (!strcasecmp(token, "globals")) {
1119                 handle_globals(argv);
1120         } else if (!strcasecmp(token, "macro")) {
1121                 handle_macro(local_contexts, argv, filename, lineno);
1122         } else if (!strcasecmp(token, "context")) {
1123                 handle_context(local_contexts, argv, filename, lineno);
1124         } else {
1125                 ast_log(LOG_NOTICE, "Unknown root token '%s'\n", token);
1126         }
1127         arg_free(argv);
1128         return 0;
1129 }
1130
1131
1132 static int ast_ael_compile(struct ast_context **local_contexts, const char *filename)
1133 {
1134         char *rfilename;
1135         char *buf, *tbuf;
1136         int bufsiz;
1137         FILE *f;
1138         char *c;
1139         char *token;
1140         int lineno=0;
1141
1142         if (filename[0] == '/')
1143                 rfilename = (char *)filename;
1144         else {
1145                 rfilename = alloca(strlen(filename) + strlen(ast_config_AST_CONFIG_DIR) + 2);
1146                 sprintf(rfilename, "%s/%s", ast_config_AST_CONFIG_DIR, filename);
1147         }
1148         
1149         f = fopen(rfilename, "r");
1150         if (!f) {
1151                 ast_log(LOG_WARNING, "Unable to open '%s': %s\n", rfilename, strerror(errno));
1152                 return -1;
1153         }
1154         buf = malloc(4096);
1155         if (!buf) {
1156                 ast_log(LOG_WARNING, "Out of memory!\n");
1157                 fclose(f);
1158                 return -1;
1159         }
1160         buf[0] = 0;
1161         bufsiz = 4096;
1162         while(!feof(f)) {
1163                 if (bufsiz - strlen(buf) < 2048) {
1164                         bufsiz += 4096;
1165                         tbuf = realloc(buf, bufsiz);
1166                         if (tbuf) {
1167                                 buf = tbuf;
1168                         } else {
1169                                 free(buf);
1170                                 ast_log(LOG_WARNING, "Out of memory!\n");
1171                                 fclose(f);
1172                         }
1173                 }
1174                 if (fgets(buf + strlen(buf), bufsiz - strlen(buf), f)) {
1175                         lineno++;
1176                         while(*buf && buf[strlen(buf) - 1] < 33)
1177                                 buf[strlen(buf) - 1] = '\0';
1178                         c = strstr(buf, "//");
1179                         if (c)
1180                                 *c = '\0';
1181                         if (*buf) {
1182                                 if (aeldebug & DEBUG_READ)
1183                                         ast_verbose("Newly composed line '%s'\n", buf);
1184                                 while((token = grab_token(buf, filename, lineno))) {
1185                                         handle_root_token(local_contexts, token, 0, filename, lineno);
1186                                         free(token);
1187                                 }
1188                         }
1189                 }
1190         };
1191         free(buf);
1192         fclose(f);
1193         return 0;
1194 }
1195
1196 static int pbx_load_module(void)
1197 {
1198         struct ast_context *local_contexts=NULL, *con;
1199         ast_ael_compile(&local_contexts, config);
1200         ast_merge_contexts_and_delete(&local_contexts, registrar);
1201         for (con = ast_walk_contexts(NULL); con; con = ast_walk_contexts(con))
1202                 ast_context_verify_includes(con);
1203
1204 #if 0
1205                 v = ast_variable_browse(cfg, "globals");
1206                 while(v) {
1207                         memset(realvalue, 0, sizeof(realvalue));
1208                         pbx_substitute_variables_helper(NULL, v->value, realvalue, sizeof(realvalue) - 1);
1209                         pbx_builtin_setvar_helper(NULL, v->name, realvalue);
1210                         v = v->next;
1211                 }
1212                 cxt = ast_category_browse(cfg, NULL);
1213                 while(cxt) {
1214                         /* All categories but "general" or "globals" are considered contexts */
1215                         if (!strcasecmp(cxt, "general") || !strcasecmp(cxt, "globals")) {
1216                                 cxt = ast_category_browse(cfg, cxt);
1217                                 continue;
1218                         }
1219                         if ((con=ast_context_create(&local_contexts,cxt, registrar))) {
1220                                 v = ast_variable_browse(cfg, cxt);
1221                                 while(v) {
1222                                         if (!strcasecmp(v->name, "exten")) {
1223                                                 char *stringp=NULL;
1224                                                 int ipri = -2;
1225                                                 char realext[256]="";
1226                                                 char *plus;
1227                                                 tc = strdup(v->value);
1228                                                 if(tc!=NULL){
1229                                                         stringp=tc;
1230                                                         ext = strsep(&stringp, ",");
1231                                                         if (!ext)
1232                                                                 ext="";
1233                                                         cidmatch = strchr(ext, '/');
1234                                                         if (cidmatch) {
1235                                                                 *cidmatch = '\0';
1236                                                                 cidmatch++;
1237                                                                 ast_shrink_phone_number(cidmatch);
1238                                                         }
1239                                                         pri = strsep(&stringp, ",");
1240                                                         if (!pri)
1241                                                                 pri="";
1242                                                         label = strchr(pri, '(');
1243                                                         if (label) {
1244                                                                 *label = '\0';
1245                                                                 label++;
1246                                                                 end = strchr(label, ')');
1247                                                                 if (end)
1248                                                                         *end = '\0';
1249                                                                 else
1250                                                                         ast_log(LOG_WARNING, "Label missing trailing ')' at line %d\n", v->lineno);
1251                                                         }
1252                                                         plus = strchr(pri, '+');
1253                                                         if (plus) {
1254                                                                 *plus = '\0';
1255                                                                 plus++;
1256                                                         }
1257                                                         if (!strcmp(pri,"hint"))
1258                                                                 ipri=PRIORITY_HINT;
1259                                                         else if (!strcmp(pri, "next") || !strcmp(pri, "n")) {
1260                                                                 if (lastpri > -2)
1261                                                                         ipri = lastpri + 1;
1262                                                                 else
1263                                                                         ast_log(LOG_WARNING, "Can't use 'next' priority on the first entry!\n");
1264                                                         } else if (!strcmp(pri, "same") || !strcmp(pri, "s")) {
1265                                                                 if (lastpri > -2)
1266                                                                         ipri = lastpri;
1267                                                                 else
1268                                                                         ast_log(LOG_WARNING, "Can't use 'same' priority on the first entry!\n");
1269                                                         } else  {
1270                                                                 if (sscanf(pri, "%i", &ipri) != 1) {
1271                                                                         if ((ipri = ast_findlabel_extension2(NULL, con, ext, pri, cidmatch)) < 1) {
1272                                                                                 ast_log(LOG_WARNING, "Invalid priority/label '%s' at line %d\n", pri, v->lineno);
1273                                                                                 ipri = 0;
1274                                                                         }
1275                                                                 }
1276                                                         }
1277                                                         appl = stringp;
1278                                                         if (!appl)
1279                                                                 appl="";
1280                                                         if (!(start = strchr(appl, '('))) {
1281                                                                 if (stringp)
1282                                                                         appl = strsep(&stringp, ",");
1283                                                                 else
1284                                                                         appl = "";
1285                                                         }
1286                                                         if (start && (end = strrchr(appl, ')'))) {
1287                                                                 *start = *end = '\0';
1288                                                                 data = start + 1;
1289                                                                 process_quotes_and_slashes(data, ',', '|');
1290                                                         } else if (stringp!=NULL && *stringp=='"') {
1291                                                                 stringp++;
1292                                                                 data = strsep(&stringp, "\"");
1293                                                                 stringp++;
1294                                                         } else {
1295                                                                 if (stringp)
1296                                                                         data = strsep(&stringp, ",");
1297                                                                 else
1298                                                                         data = "";
1299                                                         }
1300
1301                                                         if (!data)
1302                                                                 data="";
1303                                                         while(*appl && (*appl < 33)) appl++;
1304                                                         pbx_substitute_variables_helper(NULL, ext, realext, sizeof(realext) - 1);
1305                                                         if (ipri) {
1306                                                                 if (plus)
1307                                                                         ipri += atoi(plus);
1308                                                                 lastpri = ipri;
1309                                                                 if (!strcmp(realext, "_."))
1310                                                                         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);
1311                                                                 if (ast_add_extension2(con, 0, realext, ipri, label, cidmatch, appl, strdup(data), FREE, registrar)) {
1312                                                                         ast_log(LOG_WARNING, "Unable to register extension at line %d\n", v->lineno);
1313                                                                 }
1314                                                         }
1315                                                         free(tc);
1316                                                 } else fprintf(stderr,"Error strdup returned NULL in %s\n",__PRETTY_FUNCTION__);
1317                                         } else if(!strcasecmp(v->name, "include")) {
1318                                                 memset(realvalue, 0, sizeof(realvalue));
1319                                                 pbx_substitute_variables_helper(NULL, v->value, realvalue, sizeof(realvalue) - 1);
1320                                                 if (ast_context_add_include2(con, realvalue, registrar))
1321                                                         ast_log(LOG_WARNING, "Unable to include context '%s' in context '%s'\n", v->value, cxt);
1322                                         } else if(!strcasecmp(v->name, "ignorepat")) {
1323                                                 memset(realvalue, 0, sizeof(realvalue));
1324                                                 pbx_substitute_variables_helper(NULL, v->value, realvalue, sizeof(realvalue) - 1);
1325                                                 if (ast_context_add_ignorepat2(con, realvalue, registrar))
1326                                                         ast_log(LOG_WARNING, "Unable to include ignorepat '%s' in context '%s'\n", v->value, cxt);
1327                                         } else if (!strcasecmp(v->name, "switch") || !strcasecmp(v->name, "lswitch") || !strcasecmp(v->name, "eswitch")) {
1328                                                 char *stringp=NULL;
1329                                                 memset(realvalue, 0, sizeof(realvalue));
1330                                                 if (!strcasecmp(v->name, "switch"))
1331                                                         pbx_substitute_variables_helper(NULL, v->value, realvalue, sizeof(realvalue) - 1);
1332                                                 else
1333                                                         strncpy(realvalue, v->value, sizeof(realvalue) - 1);
1334                                                 tc = realvalue;
1335                                                 stringp=tc;
1336                                                 appl = strsep(&stringp, "/");
1337                                                 data = strsep(&stringp, "");
1338                                                 if (!data)
1339                                                         data = "";
1340                                                 if (ast_context_add_switch2(con, appl, data, !strcasecmp(v->name, "eswitch"), registrar))
1341                                                         ast_log(LOG_WARNING, "Unable to include switch '%s' in context '%s'\n", v->value, cxt);
1342                                         }
1343                                         v = v->next;
1344                                 }
1345                         }
1346                         cxt = ast_category_browse(cfg, cxt);
1347                 }
1348                 ast_config_destroy(cfg);
1349         }
1350         ast_merge_contexts_and_delete(&local_contexts,registrar);
1351
1352         for (con = ast_walk_contexts(NULL); con; con = ast_walk_contexts(con))
1353                 ast_context_verify_includes(con);
1354
1355         pbx_set_autofallthrough(autofallthrough_config);
1356 #endif
1357
1358         return 0;
1359 }
1360
1361 int load_module(void)
1362 {
1363         if (pbx_load_module()) return -1;
1364  
1365         return 0;
1366 }
1367
1368 int reload(void)
1369 {
1370         ast_context_destroy(NULL, registrar);
1371         /* For martin's global variables, don't clear them on reload */
1372         pbx_load_module();
1373         return 0;
1374 }
1375
1376 int usecount(void)
1377 {
1378         return 0;
1379 }
1380
1381 char *description(void)
1382 {
1383         return dtext;
1384 }
1385
1386 char *key(void)
1387 {
1388         return ASTERISK_GPL_KEY;
1389 }