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