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