mer feb 12 14:56:57 CET 2003
[asterisk/asterisk.git] / pbx / pbx_config.c
1 /*
2  * Asterisk -- A telephony toolkit for Linux.
3  *
4  * Populate and remember extensions from static config file
5  * 
6  * Copyright (C) 1999, Mark Spencer
7  *
8  * Mark Spencer <markster@linux-support.net>
9  *
10  * This program is free software, distributed under the terms of
11  * the GNU General Public License
12  */
13
14 #include <asterisk/pbx.h>
15 #include <asterisk/config.h>
16 #include <asterisk/module.h>
17 #include <asterisk/logger.h>
18 #include <asterisk/cli.h>
19 #include <stdlib.h>
20 #include <stdio.h>
21 #include <string.h>
22 #include <ctype.h>
23 #include <errno.h>
24 /* For where to put dynamic tables */
25 #include "../asterisk.h"
26 #include "../astconf.h"
27
28 static char *dtext = "Text Extension Configuration";
29 static char *config = "extensions.conf";
30 static char *registrar = "pbx_config";
31
32 static int static_config = 0;
33 static int write_protect_config = 1;
34
35 static pthread_mutex_t save_dialplan_lock = AST_MUTEX_INITIALIZER;
36
37 /*
38  * Help for commands provided by this module ...
39  */
40 static char context_dont_include_help[] =
41 "Usage: dont include context in include\n"
42 "       Remove include from context.\n";
43
44 static char context_remove_extension_help[] =
45 "Usage: remove extension exten@context [priority]\n"
46 "       Remove whole extension from context. If priority is set, we are only\n"
47 "       removing extension with given priority.\n";
48
49 static char context_add_include_help[] =
50 "Usage: include context in context\n"
51 "       Include context in other context.\n";
52
53 static char save_dialplan_help[] =
54 "Usage: save dialplan [/path/to/extension/file]\n"
55 "       Save dialplan created by pbx_config module.\n"
56 "\n"
57 "Example: save dialplan                 (/etc/asterisk/extensions.conf)\n"
58 "         save dialplan /home/markster  (/home/markster/extensions.conf)\n";
59
60 static char context_add_extension_help[] =
61 "Usage: add extension <exten>,<priority>,<app>,<app-data> into <context>\n"
62 "       [replace]\n\n"
63 "       This command will add new extension into <context>. If there is an\n"
64 "       existence of extension with the same priority and last 'replace'\n"
65 "       arguments is given here we simply replace this extension.\n"
66 "\n"
67 "Example: add extension 6123,1,Dial,IAX/216.207.245.56/6123 into local\n"
68 "         Now, you can dial 6123 and talk to Markster :)\n";
69
70 static char context_add_ignorepat_help[] =
71 "Usage: add ignorepat <pattern> into <context>\n"
72 "       This command add new ignore pattern into context <context>\n"
73 "\n"
74 "Example: add ignorepat _3XX into local\n";
75
76 static char context_remove_ignorepat_help[] =
77 "Usage: remove ignorepat <pattern> from <context>\n"
78 "       This command remove ignore pattern from context <context>\n"
79 "\n"
80 "Example: remove ignorepat _3XX from local\n";
81
82 /*
83  * Implementation of functions provided by this module
84  */
85
86 /*
87  * REMOVE INCLUDE command stuff
88  */
89 static int handle_context_dont_include(int fd, int argc, char *argv[])
90 {
91         if (argc != 5) return RESULT_SHOWUSAGE;
92
93         if (strcmp(argv[3], "in")) return RESULT_SHOWUSAGE;
94
95         if (!ast_context_remove_include(argv[4], argv[2], registrar)) {
96                 ast_cli(fd, "We are not including '%s' in '%s' now\n",
97                         argv[2], argv[4]);
98                 return RESULT_SUCCESS;
99         }
100
101         ast_cli(fd, "Failed to remove '%s' include from '%s' context\n",
102                 argv[2], argv[4]);
103         return RESULT_FAILURE;
104 }
105
106 static char *complete_context_dont_include(char *line, char *word,
107         int pos, int state)
108 {
109         int which = 0;
110
111         /*
112          * Context completion ...
113          */
114         if (pos == 2) {
115                 struct ast_context *c;
116
117                 if (ast_lock_contexts()) {
118                         ast_log(LOG_ERROR, "Failed to lock context list\n");
119                         return NULL;
120                 }
121
122                 /* walk pbx_get_contexts ... */
123                 c = ast_walk_contexts(NULL); 
124                 while (c) {
125                         struct ast_include *i;
126
127                         if (ast_lock_context(c)) {
128                                 c = ast_walk_contexts(c);
129                                 continue;
130                         }
131
132                         i = ast_walk_context_includes(c, NULL);
133                         while (i) {
134                                 if (!strlen(word) ||
135                                         !strncmp(ast_get_include_name(i), word, strlen(word))) {
136                                         struct ast_context *nc;
137                                         int already_served = 0;
138
139                                         /* check if this include is already served or not */
140
141                                         /* go through all contexts again till we reach actuall
142                                          * context or already_served = 1
143                                          */
144                                         nc = ast_walk_contexts(NULL);
145                                         while (nc && nc != c && !already_served) {
146                                                 if (!ast_lock_context(nc)) {
147                                                         struct ast_include *ni;
148
149                                                         ni = ast_walk_context_includes(nc, NULL);
150                                                         while (ni && !already_served) {
151                                                                 if (!strcmp(ast_get_include_name(i),
152                                                                         ast_get_include_name(ni)))
153                                                                         already_served = 1;
154                                                                 ni = ast_walk_context_includes(nc, ni);
155                                                         }       
156                                                         
157                                                         ast_unlock_context(nc);
158                                                 }
159                                                 nc = ast_walk_contexts(nc);
160                                         }
161
162                                         if (!already_served) {
163                                                 if (++which > state) {
164                                                         char *res =
165                                                                 strdup(ast_get_include_name(i));
166                                                         ast_unlock_context(c);
167                                                         ast_unlock_contexts();
168                                                         return res;
169                                                 }
170                                         }
171                                 }
172                                 i = ast_walk_context_includes(c, i);
173                         }
174
175                         ast_unlock_context(c);
176                         c = ast_walk_contexts(c);
177                 }
178
179                 ast_unlock_contexts();
180                 return NULL;
181         }
182
183         /*
184          * 'in' completion ... (complete only if previous context is really
185          * included somewhere)
186          */
187         if (pos == 3) {
188                 struct ast_context *c;
189                 char *context, *dupline, *duplinet;
190
191                 if (state > 0) return NULL;
192
193                 /* take 'context' from line ... */
194                 if (!(dupline = strdup(line))) {
195                         ast_log(LOG_ERROR, "Out of free memory\n");
196                         return NULL;
197                 }
198
199                 duplinet = dupline;
200                 strsep(&duplinet, " "); /* skip 'dont' */
201                 strsep(&duplinet, " "); /* skip 'include' */
202                 context = strsep(&duplinet, " ");
203
204                 if (!context) {
205                         free(dupline);
206                         return NULL;
207                 }
208
209                 if (ast_lock_contexts()) {
210                         ast_log(LOG_WARNING, "Failed to lock contexts list\n");
211                         free(dupline);
212                         return NULL;
213                 }
214
215                 /* go through all contexts and check if is included ... */
216                 c = ast_walk_contexts(NULL);
217                 while (c) {
218                         struct ast_include *i;
219                         if (ast_lock_context(c)) {
220                                 free(dupline);
221                                 ast_unlock_contexts();
222                                 return NULL;
223                         }
224
225                         i = ast_walk_context_includes(c, NULL);
226                         while (i) {
227                                 /* is it our context? */
228                                 if (!strcmp(ast_get_include_name(i), context)) {
229                                         /* yes, it is, context is really included, so
230                                          * complete "in" command
231                                          */
232                                         free(dupline);
233                                         ast_unlock_context(c);
234                                         ast_unlock_contexts();
235                                         return strdup("in");
236                                 }
237                                 i = ast_walk_context_includes(c, i);
238                         }
239                         ast_unlock_context(c);
240                         c = ast_walk_contexts(c);
241                 }
242                 free(dupline);
243                 ast_unlock_contexts();
244                 return NULL;
245         }
246
247         /*
248          * Context from which we removing include ... 
249          */
250         if (pos == 4) {
251                 struct ast_context *c;
252                 char *context, *dupline, *duplinet, *in;
253
254                 if (!(dupline = strdup(line))) {
255                         ast_log(LOG_ERROR, "Out of free memory\n");
256                         return NULL;
257                 }
258
259                 duplinet = dupline;
260
261                 strsep(&duplinet, " "); /* skip 'dont' */
262                 strsep(&duplinet, " "); /* skip 'include' */
263
264                 if (!(context = strsep(&duplinet, " "))) {
265                         free(dupline);
266                         return NULL;
267                 }
268
269                 /* third word must be in */
270                 in = strsep(&duplinet, " ");
271                 if (!in ||
272                         strcmp(in, "in")) {
273                         free(dupline);
274                         return NULL;
275                 }
276
277                 if (ast_lock_contexts()) {
278                         ast_log(LOG_ERROR, "Failed to lock context list\n");
279                         free(dupline);
280                         return NULL;
281                 }
282
283                 /* walk through all contexts ... */
284                 c = ast_walk_contexts(NULL);
285                 while (c) {
286                         struct ast_include *i;
287                         if (ast_lock_context(c)) {
288                                 free(dupline);
289                                 return NULL;
290                         }
291         
292                         /* walk through all includes and check if it is our context */  
293                         i = ast_walk_context_includes(c, NULL);
294                         while (i) {
295                                 /* is in this context included another on which we want to
296                                  * remove?
297                                  */
298                                 if (!strcmp(context, ast_get_include_name(i))) {
299                                         /* yes, it's included, is matching our word too? */
300                                         if (!strncmp(ast_get_context_name(c),
301                                                         word, strlen(word))) {
302                                                 /* check state for completion */
303                                                 if (++which > state) {
304                                                         char *res = strdup(ast_get_context_name(c));
305                                                         free(dupline);
306                                                         ast_unlock_context(c);
307                                                         ast_unlock_contexts();
308                                                         return res;
309                                                 }
310                                         }
311                                         break;
312                                 }
313                                 i = ast_walk_context_includes(c, i);
314                         }       
315                         ast_unlock_context(c);
316                         c = ast_walk_contexts(c);
317                 }
318
319                 free(dupline);
320                 ast_unlock_contexts();
321                 return NULL;
322         }
323
324         return NULL;
325 }
326
327 /*
328  * REMOVE EXTENSION command stuff
329  */
330 static int handle_context_remove_extension(int fd, int argc, char *argv[])
331 {
332         int removing_priority = 0;
333         char *exten, *context;
334
335         if (argc != 4 && argc != 3) return RESULT_SHOWUSAGE;
336
337         /*
338          * Priority input checking ...
339          */
340         if (argc == 4) {
341                 char *c = argv[3];
342
343                 /* check for digits in whole parameter for right priority ...
344                  * why? because atoi (strtol) returns 0 if any characters in
345                  * string and whole extension will be removed, it's not good
346                  */
347                 while (*c != '\0') {
348                         if (!isdigit(*c++)) {
349                                 ast_cli(fd, "Invalid priority '%s'\n", argv[3]);
350                                 return RESULT_FAILURE;
351                         }
352                 }
353
354                 removing_priority = atoi(argv[3]);
355
356                 if (removing_priority == 0) {
357                         ast_cli(fd, "If you want to remove whole extension, please " \
358                                 "omit priority argument\n");
359                         return RESULT_FAILURE;
360                 }
361         }
362
363         /*
364          * Format exten@context checking ...
365          */
366         if (!(context = strchr(argv[2], (int)'@'))) {
367                 ast_cli(fd, "First argument must be in exten@context format\n");
368                 return RESULT_FAILURE;
369         }
370
371         *context++ = '\0';
372         exten = argv[2];
373         if ((!strlen(exten)) || (!(strlen(context)))) {
374                 ast_cli(fd, "Missing extension or context name in second argument '%s@%s'\n",
375                         exten == NULL ? "?" : exten, context == NULL ? "?" : context);
376                 return RESULT_FAILURE;
377         }
378
379         if (!ast_context_remove_extension(context, exten, removing_priority, registrar)) {
380                 if (!removing_priority)
381                         ast_cli(fd, "Whole extension %s@%s removed\n",
382                                 exten, context);
383                 else
384                         ast_cli(fd, "Extension %s@%s with priority %d removed\n",
385                                 exten, context, removing_priority);
386                         
387                 return RESULT_SUCCESS;
388         }
389
390         ast_cli(fd, "Failed to remove extension %s@%s\n", exten, context);
391
392         return RESULT_FAILURE;
393 }
394
395 #define BROKEN_READLINE 1
396
397 #ifdef BROKEN_READLINE
398 /*
399  * There is one funny thing, when you have word like 300@ and you hit
400  * <tab>, you arguments will like as your word is '300 ', so it '@'
401  * characters acts sometimes as word delimiter and sometimes as a part
402  * of word
403  *
404  * This fix function, allocates new word variable and store here every
405  * time xxx@yyy always as one word and correct pos is set too
406  *
407  * It's ugly, I know, but I'm waiting for Mark suggestion if upper is
408  * bug or feature ...
409  */
410 static int fix_complete_args(char *line, char **word, int *pos)
411 {
412         char *_line, *_strsep_line, *_previous_word = NULL, *_word = NULL;
413         int words = 0;
414
415         _line = strdup(line);
416
417         _strsep_line = _line;
418         while (_strsep_line) {
419                 _previous_word = _word;
420                 _word = strsep(&_strsep_line, " ");
421
422                 if (_word && strlen(_word)) words++;
423         }
424
425
426         if (_word || _previous_word) {
427                 if (_word) {
428                         if (!strlen(_word)) words++;
429                         *word = strdup(_word);
430                 } else
431                         *word = strdup(_previous_word);
432                 *pos = words - 1;
433                 free(_line);
434                 return 0;
435         }
436
437         free(_line);
438         return -1;
439 }
440 #endif /* BROKEN_READLINE */
441
442 static char *complete_context_remove_extension(char *line, char *word, int pos,
443         int state)
444 {
445         char *ret;
446         int which = 0;
447
448 #ifdef BROKEN_READLINE
449         /*
450          * Fix arguments, *word is a new allocated structure, REMEMBER to
451          * free *word when you want to return from this function ...
452          */
453         if (fix_complete_args(line, &word, &pos)) {
454                 ast_log(LOG_ERROR, "Out of free memory\n");
455                 return NULL;
456         }
457 #endif
458
459         /*
460          * exten@context completion ... 
461          */
462         if (pos == 2) {
463                 struct ast_context *c;
464                 struct ast_exten *e;
465                 char *context = NULL, *exten = NULL, *delim = NULL;
466
467                 /* now, parse values from word = exten@context */
468                 if ((delim = strchr(word, (int)'@'))) {
469                         /* check for duplicity ... */
470                         if (delim != strrchr(word, (int)'@')) {
471 #ifdef BROKEN_READLINE
472                                 free(word);
473 #endif
474                                 return NULL;
475                         }
476
477                         *delim = '\0';
478                         exten = strdup(word);
479                         context = strdup(delim + 1);
480                         *delim = '@';
481                 } else {
482                         exten = strdup(word);
483                 }
484 #ifdef BROKEN_READLINE
485                 free(word);
486 #endif
487
488                 if (ast_lock_contexts()) {
489                         ast_log(LOG_ERROR, "Failed to lock context list\n");
490                         free(context); free(exten);
491                         return NULL;
492                 }
493
494                 /* find our context ... */
495                 c = ast_walk_contexts(NULL); 
496                 while (c) {
497                         /* our context? */
498                         if ( (!context || !strlen(context)) ||                            /* if no input, all contexts ... */
499                                  (context && !strncmp(ast_get_context_name(c),
500                                               context, strlen(context))) ) {                  /* if input, compare ... */
501                                 /* try to complete extensions ... */
502                                 e = ast_walk_context_extensions(c, NULL);
503                                 while (e) {
504                                         /* our extension? */
505                                         if ( (!exten || !strlen(exten)) ||                           /* if not input, all extensions ... */
506                                                  (exten && !strncmp(ast_get_extension_name(e), exten,
507                                                                     strlen(exten))) ) { /* if input, compare ... */
508                                                 if (++which > state) {
509                                                         /* is there some context input? if not, throw back
510                                                          * exten@context, if yes throw back only context ...
511                                                          */
512                                                         if (!context) {
513                                                                 ret = malloc(strlen(ast_get_extension_name(e)) +
514                                                                         strlen(ast_get_context_name(c)) + 2);
515                                                                 if (ret)
516                                                                         sprintf(ret, "%s@%s", ast_get_extension_name(e),
517                                                                                 ast_get_context_name(c));
518                                                         } else {
519                                                                 ret = strdup(ast_get_context_name(c));
520                                                         }
521                                                         free(exten); free(context);
522
523                                                         ast_unlock_contexts();
524         
525                                                         return ret;
526                                                 }
527                                         }
528                                         e = ast_walk_context_extensions(c, e);
529                                 }
530                         }
531                         c = ast_walk_contexts(c);
532                 }
533
534                 ast_unlock_contexts();
535
536                 free(exten); free(context);
537
538                 return NULL;
539         }
540
541         /*
542          * Complete priority ...
543          */
544         if (pos == 3) {
545                 char *delim, *exten, *context, *dupline, *duplinet, *ec;
546                 struct ast_context *c;
547
548                 dupline = strdup(line);
549                 if (!dupline) {
550 #ifdef BROKEN_READLINE
551                         free(word);
552 #endif
553                         return NULL;
554                 }
555                 duplinet = dupline;
556
557                 strsep(&duplinet, " "); /* skip 'remove' */
558                 strsep(&duplinet, " "); /* skip 'extension */
559
560                 if (!(ec = strsep(&duplinet, " "))) {
561                         free(dupline);
562 #ifdef BROKEN_READLINE
563                         free(word);
564 #endif
565                         return NULL;
566                 }
567
568                 /* wrong exten@context format? */
569                 if (!(delim = strchr(ec, (int)'@')) ||
570                         (strchr(ec, (int)'@') != strrchr(ec, (int)'@'))) {
571 #ifdef BROKEN_READLINE
572                         free(word);
573 #endif
574                         free(dupline);
575                         return NULL;
576                 }
577
578                 /* check if there is exten and context too ... */
579                 *delim = '\0';
580                 if ((!strlen(ec)) || (!strlen(delim + 1))) {
581 #ifdef BROKEN_READLINE
582                         free(word);
583 #endif
584                         free(dupline);
585                         return NULL;
586                 }
587
588                 exten = strdup(ec);
589                 context = strdup(delim + 1);
590                 free(dupline);
591
592                 if (ast_lock_contexts()) {
593                         ast_log(LOG_ERROR, "Failed to lock context list\n");
594 #ifdef BROKEN_READLINE
595                         free(word);
596 #endif
597                         free(exten); free(context);
598                         return NULL;
599                 }
600
601                 /* walk contexts */
602                 c = ast_walk_contexts(NULL); 
603                 while (c) {
604                         if (!strcmp(ast_get_context_name(c), context)) {
605                                 struct ast_exten *e;
606
607                                 /* walk extensions */
608                                 free(context);
609                                 e = ast_walk_context_extensions(c, NULL); 
610                                 while (e) {
611                                         if (!strcmp(ast_get_extension_name(e), exten)) {
612                                                 struct ast_exten *priority;
613                                                 char buffer[10];
614                                         
615                                                 free(exten);
616                                                 priority = ast_walk_extension_priorities(e, NULL);
617                                                 /* serve priorities */
618                                                 do {
619                                                         snprintf(buffer, 10, "%u",
620                                                                 ast_get_extension_priority(priority));
621                                                         if (!strncmp(word, buffer, strlen(word))) {
622                                                                 if (++which > state) {
623 #ifdef BROKEN_READLINE
624                                                                         free(word);
625 #endif
626                                                                         ast_unlock_contexts();
627                                                                         return strdup(buffer);
628                                                                 }
629                                                         }
630                                                         priority = ast_walk_extension_priorities(e,
631                                                                 priority);
632                                                 } while (priority);
633
634 #ifdef BROKEN_READLINE
635                                                 free(word);
636 #endif
637                                                 ast_unlock_contexts();
638                                                 return NULL;                    
639                                         }
640                                         e = ast_walk_context_extensions(c, e);
641                                 }
642 #ifdef BROKEN_READLINE
643                                 free(word);
644 #endif
645                                 free(exten);
646                                 ast_unlock_contexts();
647                                 return NULL;
648                         }
649                         c = ast_walk_contexts(c);
650                 }
651
652 #ifdef BROKEN_READLINE
653                 free(word);
654 #endif
655                 free(exten); free(context);
656
657                 ast_unlock_contexts();
658                 return NULL;
659         }
660
661 #ifdef BROKEN_READLINE
662         free(word);
663 #endif
664         return NULL; 
665 }
666
667 /*
668  * Include context ...
669  */
670 static int handle_context_add_include(int fd, int argc, char *argv[])
671 {
672         if (argc != 4) return RESULT_SHOWUSAGE;
673
674         /* third arg must be 'in' ... */
675         if (strcmp(argv[2], "in")) return RESULT_SHOWUSAGE;
676
677         if (ast_context_add_include(argv[3], argv[1], registrar)) {
678                 switch (errno) {
679                         case ENOMEM:
680                                 ast_cli(fd, "Out of memory for context addition\n"); break;
681
682                         case EBUSY:
683                                 ast_cli(fd, "Failed to lock context(s) list, please try again later\n"); break;
684
685                         case EEXIST:
686                                 ast_cli(fd, "Context '%s' already included in '%s' context\n",
687                                         argv[1], argv[3]); break;
688
689                         case ENODATA:
690                         case EINVAL:
691                                 ast_cli(fd, "There is no existence of context '%s'\n",
692                                         errno == ENODATA ? argv[3] : argv[1]); break;
693
694                         default:
695                                 ast_cli(fd, "Failed to include '%s' in '%s' context\n",
696                                         argv[1], argv[3]); break;
697                 }
698                 return RESULT_FAILURE;
699         }
700
701         /* show some info ... */
702         ast_cli(fd, "Context '%s' included in '%s' context\n",
703                 argv[1], argv[3]);
704
705         return RESULT_SUCCESS;
706 }
707
708 static char *complete_context_add_include(char *line, char *word, int pos,
709     int state)
710 {
711         struct ast_context *c;
712         int which = 0;
713
714         /* server context for inclusion ... */
715         if (pos == 1)
716         {
717                 if (ast_lock_contexts()) {
718                         ast_log(LOG_ERROR, "Failed to lock context list\n");
719                         return NULL;
720                 }
721
722                 /* server all contexts */ 
723                 c = ast_walk_contexts(NULL); 
724                 while (c) {
725                         if ((!strlen(word) || 
726                                  !strncmp(ast_get_context_name(c), word, strlen(word))) &&
727                                 ++which > state)
728                         {
729                                 char *context = strdup(ast_get_context_name(c));
730                                 ast_unlock_contexts();
731                                 return context;
732                         }
733                         c = ast_walk_contexts(c);
734                 }
735
736                 ast_unlock_contexts();
737         }
738
739         /* complete 'in' only if context exist ... */
740         if (pos == 2)
741         {
742                 char *context, *dupline, *duplinet;
743
744                 if (state != 0) return NULL;
745
746                 /* parse context from line ... */
747                 if (!(dupline = strdup(line))) {
748                         ast_log(LOG_ERROR, "Out of free memory\n");
749                         if (state == 0) return strdup("in");
750                         return NULL;
751                 }
752
753                 duplinet = dupline;
754
755                 strsep(&duplinet, " ");
756                 context = strsep(&duplinet, " ");
757                 if (context) {
758                         struct ast_context *c;
759                         int context_existence = 0;
760
761                         /* check for context existence ... */
762                         if (ast_lock_contexts()) {
763                                 ast_log(LOG_ERROR, "Failed to lock context list\n");
764                                 free(dupline);
765                                 /* our fault, we can't check, so complete 'in' ... */
766                                 return strdup("in");
767                         }
768
769                         c = ast_walk_contexts(NULL);
770                         while (c && !context_existence) {
771                                 if (!strcmp(context, ast_get_context_name(c))) {
772                                         context_existence = 1;
773                                         continue;
774                                 }
775                                 c = ast_walk_contexts(c);
776                         }
777
778                         /* if context exists, return 'into' ... */
779                         if (context_existence) {
780                                 free(dupline);
781                                 ast_unlock_contexts();
782                                 return strdup("into");
783                         }
784
785                         ast_unlock_contexts();
786                 }       
787
788                 free(dupline);
789                 return NULL;
790         }
791
792         /* serve context into which we include another context */
793         if (pos == 3)
794         {
795                 char *context, *dupline, *duplinet, *in;
796                 int context_existence = 0;
797
798                 if (!(dupline = strdup(line))) {
799                         ast_log(LOG_ERROR, "Out of free memory\n");
800                         return NULL;
801                 }
802
803                 duplinet = dupline;
804
805                 strsep(&duplinet, " "); /* skip 'include' */
806                 context = strsep(&duplinet, " ");
807                 in = strsep(&duplinet, " ");
808
809                 /* given some context and third word is in? */
810                 if (!strlen(context) || strcmp(in, "in")) {
811                         free(dupline);
812                         return NULL;
813                 }
814
815                 if (ast_lock_contexts()) {
816                         ast_log(LOG_ERROR, "Failed to lock context list\n");
817                         free(dupline);
818                         return NULL;
819                 }
820
821                 /* check for context existence ... */
822                 c = ast_walk_contexts(NULL);
823                 while (c && !context_existence) {
824                         if (!strcmp(context, ast_get_context_name(c))) {
825                                 context_existence = 1;
826                                 continue;
827                         }
828                         c = ast_walk_contexts(c);
829                 }
830
831                 if (!context_existence) {
832                         free(dupline);
833                         ast_unlock_contexts();
834                         return NULL;
835                 }
836
837                 /* go through all contexts ... */
838                 c = ast_walk_contexts(NULL);
839                 while (c) {
840                         /* must be different contexts ... */
841                         if (strcmp(context, ast_get_context_name(c))) {
842                                 if (!ast_lock_context(c)) {
843                                         struct ast_include *i;
844                                         int included = 0;
845
846                                         /* check for duplicity inclusion ... */
847                                         i = ast_walk_context_includes(c, NULL);
848                                         while (i && !included) {
849                                                 if (!strcmp(ast_get_include_name(i), context))
850                                                         included = 1;
851                                                 i = ast_walk_context_includes(c, i);
852                                         }
853                                         ast_unlock_context(c);
854
855                                         /* not included yet, so show possibility ... */
856                                         if (!included &&
857                                                 !strncmp(ast_get_context_name(c), word, strlen(word))){
858                                                 
859                                                 if (++which > state) {
860                                                         char *res = strdup(ast_get_context_name(c));
861                                                         free(dupline);
862                                                         ast_unlock_contexts();
863                                                         return res;
864                                                 }
865                                         }       
866                                 }
867                         }
868                         c = ast_walk_contexts(c);
869                 }
870
871                 ast_unlock_contexts();
872                 free(dupline);
873                 return NULL;
874         }
875
876         return NULL;
877 }
878
879 /*
880  * 'save dialplan' CLI command implementation functions ...
881  */
882 static int handle_save_dialplan(int fd, int argc, char *argv[])
883 {
884         char filename[256];
885         struct ast_context *c;
886         int context_header_written;
887         int incomplete = 0; /* incomplete config write? */
888         FILE *output;
889
890         if (! (static_config && !write_protect_config)) {
891                 ast_cli(fd,
892                         "I can't save dialplan now, see '%s' example file.\n",
893                         config);
894                 return RESULT_FAILURE;
895         }
896
897         if (argc != 2 && argc != 3) return RESULT_SHOWUSAGE;
898
899         if (ast_pthread_mutex_lock(&save_dialplan_lock)) {
900                 ast_cli(fd,
901                         "Failed to lock dialplan saving (another proccess saving?)\n");
902                 return RESULT_FAILURE;
903         }
904
905         /* have config path? */
906         if (argc == 3) {
907                 /* is there extension.conf too? */
908                 if (!strstr(argv[2], ".conf")) {
909                         /* no, only directory path, check for last '/' occurence */
910                         if (*(argv[2] + strlen(argv[2]) -1) == '/')
911                                 snprintf(filename, sizeof(filename), "%s%s",
912                                         argv[2], config);
913                         else
914                                 /* without config extensions.conf, add it */
915                                 snprintf(filename, sizeof(filename), "%s/%s",
916                                         argv[2], config);
917                 } else
918                         /* there is an .conf */
919                         snprintf(filename, sizeof(filename), argv[2]);
920         } else
921                 /* no config file, default one */
922                 snprintf(filename, sizeof(filename), "%s/%s",
923                         (char *)ast_config_AST_CONFIG_DIR, config);
924
925         /* try to lock contexts list */
926         if (ast_lock_contexts()) {
927                 ast_cli(fd, "Failed to lock contexts list\n");
928                 ast_pthread_mutex_unlock(&save_dialplan_lock);
929                 return RESULT_FAILURE;
930         }
931
932         /* create new file ... */
933         if (!(output = fopen(filename, "wt"))) {
934                 ast_cli(fd, "Failed to create file '%s'\n",
935                         filename);
936                 ast_unlock_contexts();
937                 ast_pthread_mutex_unlock(&save_dialplan_lock);
938                 return RESULT_FAILURE;
939         }
940
941         /* fireout general info */
942         fprintf(output, "[general]\nstatic=%s\nwriteprotect=%s\n\n",
943                 static_config ? "yes" : "no",
944                 write_protect_config ? "yes" : "no");
945
946         /* walk all contexts */
947         c = ast_walk_contexts(NULL);
948         while (c) {
949                 context_header_written = 0;
950         
951                 /* try to lock context and fireout all info */  
952                 if (!ast_lock_context(c)) {
953                         struct ast_exten *e, *last_written_e = NULL;
954                         struct ast_include *i;
955                         struct ast_ignorepat *ip;
956
957                         /* registered by this module? */
958                         if (!strcmp(ast_get_context_registrar(c), registrar)) {
959                                 fprintf(output, "[%s]\n", ast_get_context_name(c));
960                                 context_header_written = 1;
961                         }
962
963                         /* walk extensions ... */
964                         e = ast_walk_context_extensions(c, NULL);
965                         while (e) {
966                                 struct ast_exten *p;
967
968                                 /* fireout priorities */
969                                 p = ast_walk_extension_priorities(e, NULL);
970                                 while (p) {
971                                         if (!strcmp(ast_get_extension_registrar(p),
972                                                 registrar)) {
973                         
974                                                 /* make empty line between different extensions */      
975                                                 if (last_written_e != NULL &&
976                                                         strcmp(ast_get_extension_name(last_written_e),
977                                                                 ast_get_extension_name(p)))
978                                                         fprintf(output, "\n");
979                                                 last_written_e = p;
980                                 
981                                                 if (!context_header_written) {
982                                                         fprintf(output, "[%s]\n", ast_get_context_name(c));
983                                                         context_header_written = 1;
984                                                 }
985
986                                                 fprintf(output, "exten => %s,%d,%s,%s\n",
987                                                         ast_get_extension_name(p),
988                                                         ast_get_extension_priority(p),
989                                                         ast_get_extension_app(p),
990                                                         (char *)ast_get_extension_app_data(p));
991                                         }
992                                         p = ast_walk_extension_priorities(e, p);
993                                 }
994
995                                 e = ast_walk_context_extensions(c, e);
996                         }
997
998                         /* written any extensions? ok, write space between exten & inc */
999                         if (last_written_e) fprintf(output, "\n");
1000
1001                         /* walk through includes */
1002                         i = ast_walk_context_includes(c, NULL);
1003                         while (i) {
1004                                 if (!strcmp(ast_get_include_registrar(i), registrar)) {
1005                                         if (!context_header_written) {
1006                                                 fprintf(output, "[%s]\n", ast_get_context_name(c));
1007                                                 context_header_written = 1;
1008                                         }
1009                                         fprintf(output, "include => %s\n",
1010                                                 ast_get_include_name(i));
1011                                 }
1012                                 i = ast_walk_context_includes(c, i);
1013                         }
1014
1015                         if (ast_walk_context_includes(c, NULL))
1016                                 fprintf(output, "\n");
1017
1018                         /* fireout ignorepats ... */
1019                         ip = ast_walk_context_ignorepats(c, NULL);
1020                         while (ip) {
1021                                 if (!strcmp(ast_get_ignorepat_registrar(ip), registrar)) {
1022                                         if (!context_header_written) {
1023                                                 fprintf(output, "[%s]\n", ast_get_context_name(c));
1024                                                 context_header_written = 1;
1025                                         }
1026
1027                                         fprintf(output, "ignorepat => %s\n",
1028                                                 ast_get_ignorepat_name(ip));
1029                                 }
1030                                 ip = ast_walk_context_ignorepats(c, ip);
1031                         }
1032
1033                         ast_unlock_context(c);
1034                 } else
1035                         incomplete = 1;
1036
1037                 c = ast_walk_contexts(c);
1038         }       
1039
1040         ast_unlock_contexts();
1041         ast_pthread_mutex_unlock(&save_dialplan_lock);
1042         fclose(output);
1043
1044         if (incomplete) {
1045                 ast_cli(fd, "Saved dialplan is incomplete\n");
1046                 return RESULT_FAILURE;
1047         }
1048
1049         ast_cli(fd, "Dialplane successfully saved into '%s'\n",
1050                 filename);
1051         return RESULT_SUCCESS;
1052 }
1053
1054 /*
1055  * ADD EXTENSION command stuff
1056  */
1057 static int handle_context_add_extension(int fd, int argc, char *argv[])
1058 {
1059         char *whole_exten;
1060         char *exten, *prior;
1061         char *cidmatch, *app, *app_data;
1062         char *start, *end;
1063
1064         /* check for arguments at first */
1065         if (argc != 5 && argc != 6) return RESULT_SHOWUSAGE;
1066         if (strcmp(argv[3], "into")) return RESULT_SHOWUSAGE;
1067         if (argc == 6) if (strcmp(argv[5], "replace")) return RESULT_SHOWUSAGE;
1068
1069         whole_exten = argv[2];
1070         exten           = strsep(&whole_exten,",");
1071         if (strchr(exten, '/')) {
1072                 cidmatch = exten;
1073                 strsep(&cidmatch,"/");
1074         } else {
1075                 cidmatch = NULL;
1076         }
1077         prior       = strsep(&whole_exten,",");
1078         app         = strsep(&whole_exten,",");
1079         if ((start = strchr(app, '(')) && (end = strrchr(app, ')'))) {
1080                 *start = *end = '\0';
1081                 app_data = start + 1;
1082                 for (start = app_data; *start; start++)
1083                         if (*start == ',')
1084                                 *start = '|';
1085         } else
1086                 app_data    = whole_exten;
1087
1088         if (!exten || !prior || !app || !app_data) return RESULT_SHOWUSAGE;
1089
1090         if (ast_add_extension(argv[4], argc == 6 ? 1 : 0, exten, atoi(prior), cidmatch, app,
1091                 (void *)strdup(app_data), free, registrar)) {
1092                 switch (errno) {
1093                         case ENOMEM:
1094                                 ast_cli(fd, "Out of free memory\n"); break;
1095
1096                         case EBUSY:
1097                                 ast_cli(fd, "Failed to lock context(s) list, please try again later\n"); break;
1098
1099                         case ENODATA:
1100                                 ast_cli(fd, "No existence of '%s' context\n", argv[4]); break;
1101
1102                         case EEXIST:
1103                                 ast_cli(fd, "Extension %s@%s with priority %s already exists\n",
1104                                         exten, argv[4], prior); break;
1105
1106                         default:
1107                                 ast_cli(fd, "Failed to add '%s,%s,%s,%s' extension into '%s' context\n",
1108                                         exten, prior, app, app_data, argv[4]); break;
1109                 }
1110                 return RESULT_FAILURE;
1111         }
1112
1113         if (argc == 6) 
1114                 ast_cli(fd, "Extension %s@%s (%s) replace by '%s,%s,%s,%s'\n",
1115                         exten, argv[4], prior, exten, prior, app, app_data);
1116         else
1117                 ast_cli(fd, "Extension '%s,%s,%s,%s' added into '%s' context\n",
1118                         exten, prior, app, app_data, argv[4]);
1119
1120         return RESULT_SUCCESS;
1121 }
1122
1123 /* add extension 6123,1,Dial,IAX/212.71.138.13/6123 into local */
1124 static char *complete_context_add_extension(char *line, char *word,
1125         int pos, int state)
1126 {
1127         int which = 0;
1128
1129         /* complete 'into' word ... */
1130         if (pos == 3) {
1131                 if (state == 0) return strdup("into");
1132                 return NULL;
1133         }
1134
1135         /* complete context */
1136         if (pos == 4) {
1137                 struct ast_context *c;
1138
1139                 /* try to lock contexts list ... */
1140                 if (ast_lock_contexts()) {
1141                         ast_log(LOG_WARNING, "Failed to lock contexts list\n");
1142                         return NULL;
1143                 }
1144
1145                 /* walk through all contexts */
1146                 c = ast_walk_contexts(NULL);
1147                 while (c) {
1148                         /* matching context? */
1149                         if (!strncmp(ast_get_context_name(c), word, strlen(word))) {
1150                                 if (++which > state) {
1151                                         char *res = strdup(ast_get_context_name(c));
1152                                         ast_unlock_contexts();
1153                                         return res;
1154                                 }
1155                         }
1156                         c = ast_walk_contexts(c);
1157                 }
1158
1159                 ast_unlock_contexts();
1160                 return NULL;
1161         }
1162
1163         if (pos == 5) return state == 0 ? strdup("replace") : NULL;
1164
1165         return NULL;
1166 }
1167
1168 /*
1169  * IGNOREPAT CLI stuff
1170  */
1171 static int handle_context_add_ignorepat(int fd, int argc, char *argv[])
1172 {
1173         if (argc != 5) return RESULT_SHOWUSAGE;
1174         if (strcmp(argv[3], "into")) return RESULT_SHOWUSAGE;
1175
1176         if (ast_context_add_ignorepat(argv[4], argv[2], registrar)) {
1177                 switch (errno) {
1178                         case ENOMEM:
1179                                 ast_cli(fd, "Out of free memory\n"); break;
1180
1181                         case ENODATA:
1182                                 ast_cli(fd, "There is no existence of '%s' context\n", argv[4]);
1183                                 break;
1184
1185                         case EEXIST:
1186                                 ast_cli(fd, "Ignore pattern '%s' already included in '%s' context\n",
1187                                         argv[2], argv[4]);
1188                                 break;
1189
1190                         case EBUSY:
1191                                 ast_cli(fd, "Failed to lock context(s) list, please, try again later\n");
1192                                 break;
1193
1194                         default:
1195                                 ast_cli(fd, "Failed to add ingore pattern '%s' into '%s' context\n",
1196                                         argv[2], argv[4]);
1197                                 break;
1198                 }
1199                 return RESULT_FAILURE;
1200         }
1201
1202         ast_cli(fd, "Ignore pattern '%s' added into '%s' context\n",
1203                 argv[2], argv[4]);
1204         return RESULT_SUCCESS;
1205 }
1206
1207 static char *complete_context_add_ignorepat(char *line, char *word,
1208         int pos, int state)
1209 {
1210         if (pos == 3) return state == 0 ? strdup("into") : NULL;
1211
1212         if (pos == 4) {
1213                 struct ast_context *c;
1214                 int which = 0;
1215                 char *dupline, *duplinet, *ignorepat = NULL;
1216
1217                 dupline = strdup(line);
1218                 duplinet = dupline;
1219
1220                 if (duplinet) {
1221                         strsep(&duplinet, " "); /* skip 'add' */
1222                         strsep(&duplinet, " "); /* skip 'ignorepat' */
1223                         ignorepat = strsep(&duplinet, " ");
1224                 }
1225
1226                 if (ast_lock_contexts()) {
1227                         ast_log(LOG_ERROR, "Failed to lock contexts list\n");
1228                         return NULL;
1229                 }
1230
1231                 c = ast_walk_contexts(NULL);
1232                 while (c) {
1233                         if (!strncmp(ast_get_context_name(c), word, strlen(word))) {
1234                                 int serve_context = 1;
1235                                 if (ignorepat) {
1236                                         if (!ast_lock_context(c)) {
1237                                                 struct ast_ignorepat *ip;
1238                                                 ip = ast_walk_context_ignorepats(c, NULL);
1239                                                 while (ip && serve_context) {
1240                                                         if (!strcmp(ast_get_ignorepat_name(ip), ignorepat))
1241                                                                 serve_context = 0;
1242                                                         ip = ast_walk_context_ignorepats(c, ip);
1243                                                 }
1244                                                 ast_unlock_context(c);
1245                                         }
1246                                 }
1247                                 if (serve_context) {
1248                                         if (++which > state) {
1249                                                 char *context = strdup(ast_get_context_name(c));
1250                                                 if (dupline) free(dupline);
1251                                                 ast_unlock_contexts();
1252                                                 return context;
1253                                         }
1254                                 }
1255                         }
1256                         c = ast_walk_contexts(c);
1257                 }
1258
1259                 if (dupline) free(dupline);
1260                 ast_unlock_contexts();
1261                 return NULL;
1262         }
1263
1264         return NULL;
1265 }
1266
1267 static int handle_context_remove_ignorepat(int fd, int argc, char *argv[])
1268 {
1269         if (argc != 5) return RESULT_SHOWUSAGE;
1270         if (strcmp(argv[3], "from")) return RESULT_SHOWUSAGE;
1271
1272         if (ast_context_remove_ignorepat(argv[4], argv[2], registrar)) {
1273                 switch (errno) {
1274                         case EBUSY:
1275                                 ast_cli(fd, "Failed to lock context(s) list, please try again later\n");
1276                                 break;
1277
1278                         case ENODATA:
1279                                 ast_cli(fd, "There is no existence of '%s' context\n", argv[4]);
1280                                 break;
1281
1282                         case EINVAL:
1283                                 ast_cli(fd, "There is no existence of '%s' ignore pattern in '%s' context\n",
1284                                         argv[2], argv[4]);
1285                                 break;
1286
1287                         default:
1288                                 ast_cli(fd, "Failed to remove ignore pattern '%s' from '%s' context\n");
1289                                 break;
1290                 }
1291                 return RESULT_FAILURE;
1292         }
1293
1294         ast_cli(fd, "Ignore pattern '%s' removed from '%s' context\n",
1295                 argv[2], argv[4]);
1296         return RESULT_SUCCESS;
1297 }
1298
1299 static char *complete_context_remove_ignorepat(char *line, char *word,
1300         int pos, int state)
1301 {
1302         struct ast_context *c;
1303         int which = 0;
1304
1305         if (pos == 2) {
1306                 if (ast_lock_contexts()) {
1307                         ast_log(LOG_WARNING, "Failed to lock contexts list\n");
1308                         return NULL;
1309                 }
1310
1311                 c = ast_walk_contexts(NULL);
1312                 while (c) {
1313                         if (!ast_lock_context(c)) {
1314                                 struct ast_ignorepat *ip;
1315                         
1316                                 ip = ast_walk_context_ignorepats(c, NULL);
1317                                 while (ip) {
1318                                         if (!strncmp(ast_get_ignorepat_name(ip), word, strlen(word))) {
1319                                                 if (which + 1 > state) {
1320                                                         struct ast_context *cw;
1321                                                         int already_served = 0;
1322                                                         cw = ast_walk_contexts(NULL);
1323                                                         while (cw && cw != c && !already_served) {
1324                                                                 if (!ast_lock_context(cw)) {
1325                                                                         struct ast_ignorepat *ipw;
1326                                                                         ipw = ast_walk_context_ignorepats(cw, NULL);
1327                                                                         while (ipw) {
1328                                                                                 if (!strcmp(ast_get_ignorepat_name(ipw),
1329                                                                                         ast_get_ignorepat_name(ip))) already_served = 1;
1330                                                                                 ipw = ast_walk_context_ignorepats(cw, ipw);
1331                                                                         }
1332                                                                         ast_unlock_context(cw);
1333                                                                 }
1334                                                                 cw = ast_walk_contexts(cw);
1335                                                         }
1336                                                         if (!already_served) {
1337                                                                 char *ret = strdup(ast_get_ignorepat_name(ip));
1338                                                                 ast_unlock_context(c);
1339                                                                 ast_unlock_contexts();
1340                                                                 return ret;
1341                                                         }
1342                                                 } else
1343                                                         which++;
1344                                         }
1345                                         ip = ast_walk_context_ignorepats(c, ip);
1346                                 }
1347
1348                                 ast_unlock_context(c);
1349                         }
1350                         c = ast_walk_contexts(c);
1351                 }
1352
1353                 ast_unlock_contexts();
1354                 return NULL;
1355         }
1356  
1357         if (pos == 3) return state == 0 ? strdup("from") : NULL;
1358
1359         if (pos == 4) {
1360                 char *dupline, *duplinet, *ignorepat;
1361
1362                 dupline = strdup(line);
1363                 if (!dupline) {
1364                         ast_log(LOG_WARNING, "Out of free memory\n");
1365                         return NULL;
1366                 }
1367
1368                 duplinet = dupline;
1369                 strsep(&duplinet, " ");
1370                 strsep(&duplinet, " ");
1371                 ignorepat = strsep(&duplinet, " ");
1372
1373                 if (!ignorepat) {
1374                         free(dupline);
1375                         return NULL;
1376                 }
1377
1378                 if (ast_lock_contexts()) {
1379                         ast_log(LOG_WARNING, "Failed to lock contexts list\n");
1380                         free(dupline);
1381                         return NULL;
1382                 }
1383
1384                 c = ast_walk_contexts(NULL);
1385                 while (c) {
1386                         if (!ast_lock_context(c)) {
1387                                 struct ast_ignorepat *ip;
1388                                 ip = ast_walk_context_ignorepats(c, NULL);
1389                                 while (ip) {
1390                                         if (!strcmp(ast_get_ignorepat_name(ip), ignorepat)) {
1391                                                 if (!strncmp(ast_get_context_name(c), word, strlen(word))) {
1392                                                         if (++which > state) {
1393                                                                 char *ret = strdup(ast_get_context_name(c));
1394                                                                 free(dupline);
1395                                                                 ast_unlock_context(c);
1396                                                                 ast_unlock_contexts();
1397                                                                 return ret;
1398                                                         }
1399                                                 }
1400                                         }
1401                                         ip = ast_walk_context_ignorepats(c, ip);
1402                                 }
1403
1404                                 ast_unlock_context(c);
1405                         }
1406                         c = ast_walk_contexts(c);
1407                 }
1408
1409                 free(dupline);
1410                 ast_unlock_contexts();
1411                 return NULL;
1412         }
1413
1414         return NULL;
1415 }
1416
1417 /*
1418  * CLI entries for commands provided by this module
1419  */
1420 static struct ast_cli_entry context_dont_include_cli =
1421         { { "dont", "include", NULL }, handle_context_dont_include,
1422                 "Remove a specified include from context", context_dont_include_help,
1423                 complete_context_dont_include };
1424
1425 static struct ast_cli_entry context_remove_extension_cli =
1426         { { "remove", "extension", NULL }, handle_context_remove_extension,
1427                 "Remove a specified extension", context_remove_extension_help,
1428                 complete_context_remove_extension };
1429
1430 static struct ast_cli_entry context_add_include_cli =
1431         { { "include", "context", NULL }, handle_context_add_include,
1432                 "Include context in other context", context_add_include_help,
1433                 complete_context_add_include };
1434
1435 static struct ast_cli_entry save_dialplan_cli =
1436         { { "save", "dialplan", NULL }, handle_save_dialplan,
1437                 "Save dialplan", save_dialplan_help };
1438
1439 static struct ast_cli_entry context_add_extension_cli =
1440         { { "add", "extension", NULL }, handle_context_add_extension,
1441                 "Add new extension into context", context_add_extension_help,
1442                 complete_context_add_extension };
1443
1444 static struct ast_cli_entry context_add_ignorepat_cli =
1445         { { "add", "ignorepat", NULL }, handle_context_add_ignorepat,
1446                 "Add new ignore pattern", context_add_ignorepat_help,
1447                 complete_context_add_ignorepat };
1448
1449 static struct ast_cli_entry context_remove_ignorepat_cli =
1450         { { "remove", "ignorepat", NULL }, handle_context_remove_ignorepat,
1451                 "Remove ignore pattern from context", context_remove_ignorepat_help,
1452                 complete_context_remove_ignorepat };
1453
1454 /*
1455  * Standard module functions ...
1456  */
1457 int unload_module(void)
1458 {
1459         ast_cli_unregister(&context_add_extension_cli);
1460         if (static_config && !write_protect_config)
1461                 ast_cli_unregister(&save_dialplan_cli);
1462         ast_cli_unregister(&context_add_include_cli);
1463         ast_cli_unregister(&context_dont_include_cli);
1464         ast_cli_unregister(&context_remove_extension_cli);
1465         ast_cli_unregister(&context_remove_ignorepat_cli);
1466         ast_cli_unregister(&context_add_ignorepat_cli);
1467         ast_context_destroy(NULL, registrar);
1468         return 0;
1469 }
1470
1471 static int pbx_load_module(void)
1472 {
1473         struct ast_config *cfg;
1474         struct ast_variable *v;
1475         char *cxt, *ext, *pri, *appl, *data, *tc, *cidmatch;
1476         struct ast_context *con;
1477         char *start, *end;
1478
1479         cfg = ast_load(config);
1480         if (cfg) {
1481                 /* Use existing config to populate the PBX table */
1482                 static_config = ast_true(ast_variable_retrieve(cfg, "general",
1483                         "static"));
1484                 write_protect_config = ast_true(ast_variable_retrieve(cfg, "general",
1485                         "writeprotect"));
1486                 v = ast_variable_browse(cfg, "globals");
1487                 while(v) {
1488                         pbx_builtin_setvar_helper(NULL, v->name, v->value);
1489                         v = v->next;
1490                 }
1491                 cxt = ast_category_browse(cfg, NULL);
1492                 while(cxt) {
1493                         /* All categories but "general" are considered contexts */
1494                         if (!strcasecmp(cxt, "general") || !strcasecmp(cxt, "globals")) {
1495                                 cxt = ast_category_browse(cfg, cxt);
1496                                 continue;
1497                         }
1498                         if ((con=ast_context_create(cxt, registrar))) {
1499                                 v = ast_variable_browse(cfg, cxt);
1500                                 while(v) {
1501                                         if (!strcasecmp(v->name, "exten")) {
1502                                                 char *stringp=NULL;
1503                                                 tc = strdup(v->value);
1504                                                 if(tc!=NULL){
1505                                                         stringp=tc;
1506                                                         ext = strsep(&stringp, ",");
1507                                                         if (!ext)
1508                                                                 ext="";
1509                                                         pri = strsep(&stringp, ",");
1510                                                         if (!pri)
1511                                                                 pri="";
1512                                                         appl = stringp;
1513                                                         if (!(start = strchr(appl, '(')))
1514                                                                 appl = strsep(&stringp, ",");
1515                                                         if (!appl)
1516                                                                 appl="";
1517                                                         if (start && (end = strrchr(appl, ')'))) {
1518                                                                 *start = *end = '\0';
1519                                                                 data = start + 1;
1520                                                                 for (start = data; *start; start++)
1521                                                                         if (*start == ',')
1522                                                                                 *start = '|';
1523                                                         } else if (stringp!=NULL && *stringp=='"') {
1524                                                                 stringp++;
1525                                                                 data = strsep(&stringp, "\"");
1526                                                                 stringp++;
1527                                                         } else {
1528                                                                 data = strsep(&stringp, ",");
1529                                                         }
1530                                                         cidmatch = strchr(ext, '/');
1531                                                         if (cidmatch) {
1532                                                                 *cidmatch = '\0';
1533                                                                 cidmatch++;
1534                                                         }
1535                                                         stringp=ext;
1536                                                         strsep(&stringp, "/");
1537
1538                                                         if (!data)
1539                                                                 data="";
1540                                                         if (ast_add_extension2(con, 0, ext, atoi(pri), cidmatch, appl, strdup(data), free, registrar)) {
1541                                                                 ast_log(LOG_WARNING, "Unable to register extension at line %d\n", v->lineno);
1542                                                         }
1543                                                         free(tc);
1544                                                 } else fprintf(stderr,"Error strdup returned NULL in %s\n",__PRETTY_FUNCTION__);
1545                                         } else if(!strcasecmp(v->name, "include")) {
1546                                                 if (ast_context_add_include2(con, v->value, registrar))
1547                                                         ast_log(LOG_WARNING, "Unable to include context '%s' in context '%s'\n", v->value, cxt);
1548                                         } else if(!strcasecmp(v->name, "ignorepat")) {
1549                                                 if (ast_context_add_ignorepat2(con, v->value, registrar))
1550                                                         ast_log(LOG_WARNING, "Unable to include ignorepat '%s' in context '%s'\n", v->value, cxt);
1551                                         } else if (!strcasecmp(v->name, "switch")) {
1552                                                 char *stringp=NULL;
1553                                                 tc = strdup(v->value);
1554                                                 stringp=tc;
1555                                                 appl = strsep(&stringp, "/");
1556                                                 data = strsep(&stringp, "");
1557                                                 if (!data)
1558                                                         data = "";
1559                                                 if (ast_context_add_switch2(con, appl, data, registrar))
1560                                                         ast_log(LOG_WARNING, "Unable to include switch '%s' in context '%s'\n", v->value, cxt);
1561                                         }
1562                                         v = v->next;
1563                                 }
1564                         }
1565                         cxt = ast_category_browse(cfg, cxt);
1566                 }
1567                 ast_destroy(cfg);
1568         }
1569         return 0;
1570 }
1571
1572 int load_module(void)
1573 {
1574         if (pbx_load_module()) return -1;
1575  
1576         ast_cli_register(&context_remove_extension_cli);
1577         ast_cli_register(&context_dont_include_cli);
1578         ast_cli_register(&context_add_include_cli);
1579         if (static_config && !write_protect_config)
1580                 ast_cli_register(&save_dialplan_cli);
1581         ast_cli_register(&context_add_extension_cli);
1582         ast_cli_register(&context_add_ignorepat_cli);
1583         ast_cli_register(&context_remove_ignorepat_cli);
1584
1585         return 0;
1586 }
1587
1588 int reload(void)
1589 {
1590         ast_context_destroy(NULL, registrar);
1591         pbx_builtin_clear_globals();
1592         pbx_load_module();
1593         return 0;
1594 }
1595
1596 int usecount(void)
1597 {
1598         return 0;
1599 }
1600
1601 char *description(void)
1602 {
1603         return dtext;
1604 }
1605
1606 char *key(void)
1607 {
1608         return ASTERISK_GPL_KEY;
1609 }