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