Fix a typo
[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;
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                                                         /* is there some context input? if not, throw back
530                                                          * exten@context, if yes throw back only context ...
531                                                          */
532                                                         if (!context) {
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                                                         } else {
539                                                                 ret = strdup(ast_get_context_name(c));
540                                                         }
541                                                         free(exten); free(context);
542
543                                                         ast_unlock_contexts();
544         
545                                                         return ret;
546                                                 }
547                                         }
548                                         e = ast_walk_context_extensions(c, e);
549                                 }
550                         }
551                         c = ast_walk_contexts(c);
552                 }
553
554                 ast_unlock_contexts();
555
556                 free(exten); free(context);
557
558                 return NULL;
559         }
560
561         /*
562          * Complete priority ...
563          */
564         if (pos == 3) {
565                 char *delim, *exten, *context, *dupline, *duplinet, *ec;
566                 struct ast_context *c;
567
568                 dupline = strdup(line);
569                 if (!dupline) {
570 #ifdef BROKEN_READLINE
571                         free(word);
572 #endif
573                         return NULL;
574                 }
575                 duplinet = dupline;
576
577                 strsep(&duplinet, " "); /* skip 'remove' */
578                 strsep(&duplinet, " "); /* skip 'extension */
579
580                 if (!(ec = strsep(&duplinet, " "))) {
581                         free(dupline);
582 #ifdef BROKEN_READLINE
583                         free(word);
584 #endif
585                         return NULL;
586                 }
587
588                 /* wrong exten@context format? */
589                 if (!(delim = strchr(ec, (int)'@')) ||
590                         (strchr(ec, (int)'@') != strrchr(ec, (int)'@'))) {
591 #ifdef BROKEN_READLINE
592                         free(word);
593 #endif
594                         free(dupline);
595                         return NULL;
596                 }
597
598                 /* check if there is exten and context too ... */
599                 *delim = '\0';
600                 if ((!strlen(ec)) || (!strlen(delim + 1))) {
601 #ifdef BROKEN_READLINE
602                         free(word);
603 #endif
604                         free(dupline);
605                         return NULL;
606                 }
607
608                 exten = strdup(ec);
609                 context = strdup(delim + 1);
610                 free(dupline);
611
612                 if (ast_lock_contexts()) {
613                         ast_log(LOG_ERROR, "Failed to lock context list\n");
614 #ifdef BROKEN_READLINE
615                         free(word);
616 #endif
617                         free(exten); free(context);
618                         return NULL;
619                 }
620
621                 /* walk contexts */
622                 c = ast_walk_contexts(NULL); 
623                 while (c) {
624                         if (!strcmp(ast_get_context_name(c), context)) {
625                                 struct ast_exten *e;
626
627                                 /* walk extensions */
628                                 free(context);
629                                 e = ast_walk_context_extensions(c, NULL); 
630                                 while (e) {
631                                         if (!strcmp(ast_get_extension_name(e), exten)) {
632                                                 struct ast_exten *priority;
633                                                 char buffer[10];
634                                         
635                                                 free(exten);
636                                                 priority = ast_walk_extension_priorities(e, NULL);
637                                                 /* serve priorities */
638                                                 do {
639                                                         snprintf(buffer, 10, "%u",
640                                                                 ast_get_extension_priority(priority));
641                                                         if (!strncmp(word, buffer, strlen(word))) {
642                                                                 if (++which > state) {
643 #ifdef BROKEN_READLINE
644                                                                         free(word);
645 #endif
646                                                                         ast_unlock_contexts();
647                                                                         return strdup(buffer);
648                                                                 }
649                                                         }
650                                                         priority = ast_walk_extension_priorities(e,
651                                                                 priority);
652                                                 } while (priority);
653
654 #ifdef BROKEN_READLINE
655                                                 free(word);
656 #endif
657                                                 ast_unlock_contexts();
658                                                 return NULL;                    
659                                         }
660                                         e = ast_walk_context_extensions(c, e);
661                                 }
662 #ifdef BROKEN_READLINE
663                                 free(word);
664 #endif
665                                 free(exten);
666                                 ast_unlock_contexts();
667                                 return NULL;
668                         }
669                         c = ast_walk_contexts(c);
670                 }
671
672 #ifdef BROKEN_READLINE
673                 free(word);
674 #endif
675                 free(exten); free(context);
676
677                 ast_unlock_contexts();
678                 return NULL;
679         }
680
681 #ifdef BROKEN_READLINE
682         free(word);
683 #endif
684         return NULL; 
685 }
686
687 /*
688  * Include context ...
689  */
690 static int handle_context_add_include(int fd, int argc, char *argv[])
691 {
692         if (argc != 4) return RESULT_SHOWUSAGE;
693
694         /* third arg must be 'in' ... */
695         if (strcmp(argv[2], "in")) return RESULT_SHOWUSAGE;
696
697         if (ast_context_add_include(argv[3], argv[1], registrar)) {
698                 switch (errno) {
699                         case ENOMEM:
700                                 ast_cli(fd, "Out of memory for context addition\n"); break;
701
702                         case EBUSY:
703                                 ast_cli(fd, "Failed to lock context(s) list, please try again later\n"); break;
704
705                         case EEXIST:
706                                 ast_cli(fd, "Context '%s' already included in '%s' context\n",
707                                         argv[1], argv[3]); break;
708
709                         case ENOENT:
710                         case EINVAL:
711                                 ast_cli(fd, "There is no existence of context '%s'\n",
712                                         errno == ENOENT ? argv[3] : argv[1]); break;
713
714                         default:
715                                 ast_cli(fd, "Failed to include '%s' in '%s' context\n",
716                                         argv[1], argv[3]); break;
717                 }
718                 return RESULT_FAILURE;
719         }
720
721         /* show some info ... */
722         ast_cli(fd, "Context '%s' included in '%s' context\n",
723                 argv[1], argv[3]);
724
725         return RESULT_SUCCESS;
726 }
727
728 static char *complete_context_add_include(char *line, char *word, int pos,
729     int state)
730 {
731         struct ast_context *c;
732         int which = 0;
733
734         /* server context for inclusion ... */
735         if (pos == 1)
736         {
737                 if (ast_lock_contexts()) {
738                         ast_log(LOG_ERROR, "Failed to lock context list\n");
739                         return NULL;
740                 }
741
742                 /* server all contexts */ 
743                 c = ast_walk_contexts(NULL); 
744                 while (c) {
745                         if ((!strlen(word) || 
746                                  !strncmp(ast_get_context_name(c), word, strlen(word))) &&
747                                 ++which > state)
748                         {
749                                 char *context = strdup(ast_get_context_name(c));
750                                 ast_unlock_contexts();
751                                 return context;
752                         }
753                         c = ast_walk_contexts(c);
754                 }
755
756                 ast_unlock_contexts();
757         }
758
759         /* complete 'in' only if context exist ... */
760         if (pos == 2)
761         {
762                 char *context, *dupline, *duplinet;
763
764                 if (state != 0) return NULL;
765
766                 /* parse context from line ... */
767                 if (!(dupline = strdup(line))) {
768                         ast_log(LOG_ERROR, "Out of free memory\n");
769                         if (state == 0) return strdup("in");
770                         return NULL;
771                 }
772
773                 duplinet = dupline;
774
775                 strsep(&duplinet, " ");
776                 context = strsep(&duplinet, " ");
777                 if (context) {
778                         struct ast_context *c;
779                         int context_existence = 0;
780
781                         /* check for context existence ... */
782                         if (ast_lock_contexts()) {
783                                 ast_log(LOG_ERROR, "Failed to lock context list\n");
784                                 free(dupline);
785                                 /* our fault, we can't check, so complete 'in' ... */
786                                 return strdup("in");
787                         }
788
789                         c = ast_walk_contexts(NULL);
790                         while (c && !context_existence) {
791                                 if (!strcmp(context, ast_get_context_name(c))) {
792                                         context_existence = 1;
793                                         continue;
794                                 }
795                                 c = ast_walk_contexts(c);
796                         }
797
798                         /* if context exists, return 'into' ... */
799                         if (context_existence) {
800                                 free(dupline);
801                                 ast_unlock_contexts();
802                                 return strdup("into");
803                         }
804
805                         ast_unlock_contexts();
806                 }       
807
808                 free(dupline);
809                 return NULL;
810         }
811
812         /* serve context into which we include another context */
813         if (pos == 3)
814         {
815                 char *context, *dupline, *duplinet, *in;
816                 int context_existence = 0;
817
818                 if (!(dupline = strdup(line))) {
819                         ast_log(LOG_ERROR, "Out of free memory\n");
820                         return NULL;
821                 }
822
823                 duplinet = dupline;
824
825                 strsep(&duplinet, " "); /* skip 'include' */
826                 context = strsep(&duplinet, " ");
827                 in = strsep(&duplinet, " ");
828
829                 /* given some context and third word is in? */
830                 if (!strlen(context) || strcmp(in, "in")) {
831                         free(dupline);
832                         return NULL;
833                 }
834
835                 if (ast_lock_contexts()) {
836                         ast_log(LOG_ERROR, "Failed to lock context list\n");
837                         free(dupline);
838                         return NULL;
839                 }
840
841                 /* check for context existence ... */
842                 c = ast_walk_contexts(NULL);
843                 while (c && !context_existence) {
844                         if (!strcmp(context, ast_get_context_name(c))) {
845                                 context_existence = 1;
846                                 continue;
847                         }
848                         c = ast_walk_contexts(c);
849                 }
850
851                 if (!context_existence) {
852                         free(dupline);
853                         ast_unlock_contexts();
854                         return NULL;
855                 }
856
857                 /* go through all contexts ... */
858                 c = ast_walk_contexts(NULL);
859                 while (c) {
860                         /* must be different contexts ... */
861                         if (strcmp(context, ast_get_context_name(c))) {
862                                 if (!ast_lock_context(c)) {
863                                         struct ast_include *i;
864                                         int included = 0;
865
866                                         /* check for duplicity inclusion ... */
867                                         i = ast_walk_context_includes(c, NULL);
868                                         while (i && !included) {
869                                                 if (!strcmp(ast_get_include_name(i), context))
870                                                         included = 1;
871                                                 i = ast_walk_context_includes(c, i);
872                                         }
873                                         ast_unlock_context(c);
874
875                                         /* not included yet, so show possibility ... */
876                                         if (!included &&
877                                                 !strncmp(ast_get_context_name(c), word, strlen(word))){
878                                                 
879                                                 if (++which > state) {
880                                                         char *res = strdup(ast_get_context_name(c));
881                                                         free(dupline);
882                                                         ast_unlock_contexts();
883                                                         return res;
884                                                 }
885                                         }       
886                                 }
887                         }
888                         c = ast_walk_contexts(c);
889                 }
890
891                 ast_unlock_contexts();
892                 free(dupline);
893                 return NULL;
894         }
895
896         return NULL;
897 }
898
899 /*
900  * 'save dialplan' CLI command implementation functions ...
901  */
902 static int handle_save_dialplan(int fd, int argc, char *argv[])
903 {
904         char filename[256];
905         struct ast_context *c;
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         /* try to lock contexts list */
946         if (ast_lock_contexts()) {
947                 ast_cli(fd, "Failed to lock contexts list\n");
948                 ast_mutex_unlock(&save_dialplan_lock);
949                 return RESULT_FAILURE;
950         }
951
952         /* create new file ... */
953         if (!(output = fopen(filename, "wt"))) {
954                 ast_cli(fd, "Failed to create file '%s'\n",
955                         filename);
956                 ast_unlock_contexts();
957                 ast_mutex_unlock(&save_dialplan_lock);
958                 return RESULT_FAILURE;
959         }
960
961         /* fireout general info */
962         fprintf(output, "[general]\nstatic=%s\nwriteprotect=%s\n\n",
963                 static_config ? "yes" : "no",
964                 write_protect_config ? "yes" : "no");
965
966         /* walk all contexts */
967         c = ast_walk_contexts(NULL);
968         while (c) {
969                 context_header_written = 0;
970         
971                 /* try to lock context and fireout all info */  
972                 if (!ast_lock_context(c)) {
973                         struct ast_exten *e, *last_written_e = NULL;
974                         struct ast_include *i;
975                         struct ast_ignorepat *ip;
976
977                         /* registered by this module? */
978                         if (!strcmp(ast_get_context_registrar(c), registrar)) {
979                                 fprintf(output, "[%s]\n", ast_get_context_name(c));
980                                 context_header_written = 1;
981                         }
982
983                         /* walk extensions ... */
984                         e = ast_walk_context_extensions(c, NULL);
985                         while (e) {
986                                 struct ast_exten *p;
987
988                                 /* fireout priorities */
989                                 p = ast_walk_extension_priorities(e, NULL);
990                                 while (p) {
991                                         if (!strcmp(ast_get_extension_registrar(p),
992                                                 registrar)) {
993                         
994                                                 /* make empty line between different extensions */      
995                                                 if (last_written_e != NULL &&
996                                                         strcmp(ast_get_extension_name(last_written_e),
997                                                                 ast_get_extension_name(p)))
998                                                         fprintf(output, "\n");
999                                                 last_written_e = p;
1000                                 
1001                                                 if (!context_header_written) {
1002                                                         fprintf(output, "[%s]\n", ast_get_context_name(c));
1003                                                         context_header_written = 1;
1004                                                 }
1005
1006                                                 if (ast_get_extension_priority(p)!=PRIORITY_HINT) {
1007                                                         char *tempdata = NULL, *startdata;
1008                                                         tempdata = strdup((char *)ast_get_extension_app_data(p));
1009                                                         if (tempdata) {
1010                                                                 startdata = tempdata;
1011                                                                 while (*tempdata) {
1012                                                                         if (*tempdata == '|')
1013                                                                                 *tempdata = ',';
1014                                                                         tempdata++;
1015                                                                 }
1016                                                                 tempdata = startdata;
1017                                                         }
1018                                                         fprintf(output, "exten => %s,%d,%s(%s)\n",
1019                                                             ast_get_extension_name(p),
1020                                                             ast_get_extension_priority(p),
1021                                                             ast_get_extension_app(p),
1022                                                             tempdata);
1023                                                         if (tempdata)
1024                                                                 free(tempdata);
1025                                                 } else
1026                                                         fprintf(output, "exten => %s,hint,%s\n",
1027                                                             ast_get_extension_name(p),
1028                                                             ast_get_extension_app(p));
1029                                                 
1030                                         }
1031                                         p = ast_walk_extension_priorities(e, p);
1032                                 }
1033
1034                                 e = ast_walk_context_extensions(c, e);
1035                         }
1036
1037                         /* written any extensions? ok, write space between exten & inc */
1038                         if (last_written_e) fprintf(output, "\n");
1039
1040                         /* walk through includes */
1041                         i = ast_walk_context_includes(c, NULL);
1042                         while (i) {
1043                                 if (!strcmp(ast_get_include_registrar(i), registrar)) {
1044                                         if (!context_header_written) {
1045                                                 fprintf(output, "[%s]\n", ast_get_context_name(c));
1046                                                 context_header_written = 1;
1047                                         }
1048                                         fprintf(output, "include => %s\n",
1049                                                 ast_get_include_name(i));
1050                                 }
1051                                 i = ast_walk_context_includes(c, i);
1052                         }
1053
1054                         if (ast_walk_context_includes(c, NULL))
1055                                 fprintf(output, "\n");
1056
1057                         /* fireout ignorepats ... */
1058                         ip = ast_walk_context_ignorepats(c, NULL);
1059                         while (ip) {
1060                                 if (!strcmp(ast_get_ignorepat_registrar(ip), registrar)) {
1061                                         if (!context_header_written) {
1062                                                 fprintf(output, "[%s]\n", ast_get_context_name(c));
1063                                                 context_header_written = 1;
1064                                         }
1065
1066                                         fprintf(output, "ignorepat => %s\n",
1067                                                 ast_get_ignorepat_name(ip));
1068                                 }
1069                                 ip = ast_walk_context_ignorepats(c, ip);
1070                         }
1071
1072                         ast_unlock_context(c);
1073                 } else
1074                         incomplete = 1;
1075
1076                 c = ast_walk_contexts(c);
1077         }       
1078
1079         ast_unlock_contexts();
1080         ast_mutex_unlock(&save_dialplan_lock);
1081         fclose(output);
1082
1083         if (incomplete) {
1084                 ast_cli(fd, "Saved dialplan is incomplete\n");
1085                 return RESULT_FAILURE;
1086         }
1087
1088         ast_cli(fd, "Dialplane successfully saved into '%s'\n",
1089                 filename);
1090         return RESULT_SUCCESS;
1091 }
1092
1093 /*
1094  * ADD EXTENSION command stuff
1095  */
1096 static int handle_context_add_extension(int fd, int argc, char *argv[])
1097 {
1098         char *whole_exten;
1099         char *exten, *prior;
1100         int iprior = -2;
1101         char *cidmatch, *app, *app_data;
1102         char *start, *end;
1103
1104         /* check for arguments at first */
1105         if (argc != 5 && argc != 6) return RESULT_SHOWUSAGE;
1106         if (strcmp(argv[3], "into")) return RESULT_SHOWUSAGE;
1107         if (argc == 6) if (strcmp(argv[5], "replace")) return RESULT_SHOWUSAGE;
1108
1109         whole_exten = argv[2];
1110         exten           = strsep(&whole_exten,",");
1111         if (strchr(exten, '/')) {
1112                 cidmatch = exten;
1113                 strsep(&cidmatch,"/");
1114         } else {
1115                 cidmatch = NULL;
1116         }
1117         prior       = strsep(&whole_exten,",");
1118         if (prior) {
1119                 if (!strcmp(prior, "hint")) {
1120                         iprior = PRIORITY_HINT;
1121                 } else {
1122                         iprior = atoi(prior);
1123                 }
1124         }
1125         app         = strsep(&whole_exten,",");
1126         if (app && (start = strchr(app, '(')) && (end = strrchr(app, ')'))) {
1127                 *start = *end = '\0';
1128                 app_data = start + 1;
1129                 for (start = app_data; *start; start++)
1130                         if (*start == ',')
1131                                 *start = '|';
1132         } else
1133                 app_data    = whole_exten;
1134
1135         if (!exten || !prior || !app || (!app_data && iprior != PRIORITY_HINT)) return RESULT_SHOWUSAGE;
1136
1137         if (!app_data)
1138             app_data="";
1139         if (ast_add_extension(argv[4], argc == 6 ? 1 : 0, exten, iprior, cidmatch, app,
1140                 (void *)strdup(app_data), free, registrar)) {
1141                 switch (errno) {
1142                         case ENOMEM:
1143                                 ast_cli(fd, "Out of free memory\n"); break;
1144
1145                         case EBUSY:
1146                                 ast_cli(fd, "Failed to lock context(s) list, please try again later\n"); break;
1147
1148                         case ENOENT:
1149                                 ast_cli(fd, "No existence of '%s' context\n", argv[4]); break;
1150
1151                         case EEXIST:
1152                                 ast_cli(fd, "Extension %s@%s with priority %s already exists\n",
1153                                         exten, argv[4], prior); break;
1154
1155                         default:
1156                                 ast_cli(fd, "Failed to add '%s,%s,%s,%s' extension into '%s' context\n",
1157                                         exten, prior, app, app_data, argv[4]); break;
1158                 }
1159                 return RESULT_FAILURE;
1160         }
1161
1162         if (argc == 6) 
1163                 ast_cli(fd, "Extension %s@%s (%s) replace by '%s,%s,%s,%s'\n",
1164                         exten, argv[4], prior, exten, prior, app, app_data);
1165         else
1166                 ast_cli(fd, "Extension '%s,%s,%s,%s' added into '%s' context\n",
1167                         exten, prior, app, app_data, argv[4]);
1168
1169         return RESULT_SUCCESS;
1170 }
1171
1172 /* add extension 6123,1,Dial,IAX/212.71.138.13/6123 into local */
1173 static char *complete_context_add_extension(char *line, char *word,
1174         int pos, int state)
1175 {
1176         int which = 0;
1177
1178         /* complete 'into' word ... */
1179         if (pos == 3) {
1180                 if (state == 0) return strdup("into");
1181                 return NULL;
1182         }
1183
1184         /* complete context */
1185         if (pos == 4) {
1186                 struct ast_context *c;
1187
1188                 /* try to lock contexts list ... */
1189                 if (ast_lock_contexts()) {
1190                         ast_log(LOG_WARNING, "Failed to lock contexts list\n");
1191                         return NULL;
1192                 }
1193
1194                 /* walk through all contexts */
1195                 c = ast_walk_contexts(NULL);
1196                 while (c) {
1197                         /* matching context? */
1198                         if (!strncmp(ast_get_context_name(c), word, strlen(word))) {
1199                                 if (++which > state) {
1200                                         char *res = strdup(ast_get_context_name(c));
1201                                         ast_unlock_contexts();
1202                                         return res;
1203                                 }
1204                         }
1205                         c = ast_walk_contexts(c);
1206                 }
1207
1208                 ast_unlock_contexts();
1209                 return NULL;
1210         }
1211
1212         if (pos == 5) return state == 0 ? strdup("replace") : NULL;
1213
1214         return NULL;
1215 }
1216
1217 /*
1218  * IGNOREPAT CLI stuff
1219  */
1220 static int handle_context_add_ignorepat(int fd, int argc, char *argv[])
1221 {
1222         if (argc != 5) return RESULT_SHOWUSAGE;
1223         if (strcmp(argv[3], "into")) return RESULT_SHOWUSAGE;
1224
1225         if (ast_context_add_ignorepat(argv[4], argv[2], registrar)) {
1226                 switch (errno) {
1227                         case ENOMEM:
1228                                 ast_cli(fd, "Out of free memory\n"); break;
1229
1230                         case ENOENT:
1231                                 ast_cli(fd, "There is no existence of '%s' context\n", argv[4]);
1232                                 break;
1233
1234                         case EEXIST:
1235                                 ast_cli(fd, "Ignore pattern '%s' already included in '%s' context\n",
1236                                         argv[2], argv[4]);
1237                                 break;
1238
1239                         case EBUSY:
1240                                 ast_cli(fd, "Failed to lock context(s) list, please, try again later\n");
1241                                 break;
1242
1243                         default:
1244                                 ast_cli(fd, "Failed to add ingore pattern '%s' into '%s' context\n",
1245                                         argv[2], argv[4]);
1246                                 break;
1247                 }
1248                 return RESULT_FAILURE;
1249         }
1250
1251         ast_cli(fd, "Ignore pattern '%s' added into '%s' context\n",
1252                 argv[2], argv[4]);
1253         return RESULT_SUCCESS;
1254 }
1255
1256 static char *complete_context_add_ignorepat(char *line, char *word,
1257         int pos, int state)
1258 {
1259         if (pos == 3) return state == 0 ? strdup("into") : NULL;
1260
1261         if (pos == 4) {
1262                 struct ast_context *c;
1263                 int which = 0;
1264                 char *dupline, *duplinet, *ignorepat = NULL;
1265
1266                 dupline = strdup(line);
1267                 duplinet = dupline;
1268
1269                 if (duplinet) {
1270                         strsep(&duplinet, " "); /* skip 'add' */
1271                         strsep(&duplinet, " "); /* skip 'ignorepat' */
1272                         ignorepat = strsep(&duplinet, " ");
1273                 }
1274
1275                 if (ast_lock_contexts()) {
1276                         ast_log(LOG_ERROR, "Failed to lock contexts list\n");
1277                         return NULL;
1278                 }
1279
1280                 c = ast_walk_contexts(NULL);
1281                 while (c) {
1282                         if (!strncmp(ast_get_context_name(c), word, strlen(word))) {
1283                                 int serve_context = 1;
1284                                 if (ignorepat) {
1285                                         if (!ast_lock_context(c)) {
1286                                                 struct ast_ignorepat *ip;
1287                                                 ip = ast_walk_context_ignorepats(c, NULL);
1288                                                 while (ip && serve_context) {
1289                                                         if (!strcmp(ast_get_ignorepat_name(ip), ignorepat))
1290                                                                 serve_context = 0;
1291                                                         ip = ast_walk_context_ignorepats(c, ip);
1292                                                 }
1293                                                 ast_unlock_context(c);
1294                                         }
1295                                 }
1296                                 if (serve_context) {
1297                                         if (++which > state) {
1298                                                 char *context = strdup(ast_get_context_name(c));
1299                                                 if (dupline) free(dupline);
1300                                                 ast_unlock_contexts();
1301                                                 return context;
1302                                         }
1303                                 }
1304                         }
1305                         c = ast_walk_contexts(c);
1306                 }
1307
1308                 if (dupline) free(dupline);
1309                 ast_unlock_contexts();
1310                 return NULL;
1311         }
1312
1313         return NULL;
1314 }
1315
1316 static int handle_context_remove_ignorepat(int fd, int argc, char *argv[])
1317 {
1318         if (argc != 5) return RESULT_SHOWUSAGE;
1319         if (strcmp(argv[3], "from")) return RESULT_SHOWUSAGE;
1320
1321         if (ast_context_remove_ignorepat(argv[4], argv[2], registrar)) {
1322                 switch (errno) {
1323                         case EBUSY:
1324                                 ast_cli(fd, "Failed to lock context(s) list, please try again later\n");
1325                                 break;
1326
1327                         case ENOENT:
1328                                 ast_cli(fd, "There is no existence of '%s' context\n", argv[4]);
1329                                 break;
1330
1331                         case EINVAL:
1332                                 ast_cli(fd, "There is no existence of '%s' ignore pattern in '%s' context\n",
1333                                         argv[2], argv[4]);
1334                                 break;
1335
1336                         default:
1337                                 ast_cli(fd, "Failed to remove ignore pattern '%s' from '%s' context\n", argv[2], argv[4]);
1338                                 break;
1339                 }
1340                 return RESULT_FAILURE;
1341         }
1342
1343         ast_cli(fd, "Ignore pattern '%s' removed from '%s' context\n",
1344                 argv[2], argv[4]);
1345         return RESULT_SUCCESS;
1346 }
1347
1348 static int pbx_load_module(void);
1349
1350 static int handle_reload_extensions(int fd, int argc, char *argv[])
1351 {
1352         if (argc!=2) return RESULT_SHOWUSAGE;
1353         pbx_load_module();
1354         return RESULT_SUCCESS;
1355 }
1356
1357 static char *complete_context_remove_ignorepat(char *line, char *word,
1358         int pos, int state)
1359 {
1360         struct ast_context *c;
1361         int which = 0;
1362
1363         if (pos == 2) {
1364                 if (ast_lock_contexts()) {
1365                         ast_log(LOG_WARNING, "Failed to lock contexts list\n");
1366                         return NULL;
1367                 }
1368
1369                 c = ast_walk_contexts(NULL);
1370                 while (c) {
1371                         if (!ast_lock_context(c)) {
1372                                 struct ast_ignorepat *ip;
1373                         
1374                                 ip = ast_walk_context_ignorepats(c, NULL);
1375                                 while (ip) {
1376                                         if (!strncmp(ast_get_ignorepat_name(ip), word, strlen(word))) {
1377                                                 if (which + 1 > state) {
1378                                                         struct ast_context *cw;
1379                                                         int already_served = 0;
1380                                                         cw = ast_walk_contexts(NULL);
1381                                                         while (cw && cw != c && !already_served) {
1382                                                                 if (!ast_lock_context(cw)) {
1383                                                                         struct ast_ignorepat *ipw;
1384                                                                         ipw = ast_walk_context_ignorepats(cw, NULL);
1385                                                                         while (ipw) {
1386                                                                                 if (!strcmp(ast_get_ignorepat_name(ipw),
1387                                                                                         ast_get_ignorepat_name(ip))) already_served = 1;
1388                                                                                 ipw = ast_walk_context_ignorepats(cw, ipw);
1389                                                                         }
1390                                                                         ast_unlock_context(cw);
1391                                                                 }
1392                                                                 cw = ast_walk_contexts(cw);
1393                                                         }
1394                                                         if (!already_served) {
1395                                                                 char *ret = strdup(ast_get_ignorepat_name(ip));
1396                                                                 ast_unlock_context(c);
1397                                                                 ast_unlock_contexts();
1398                                                                 return ret;
1399                                                         }
1400                                                 } else
1401                                                         which++;
1402                                         }
1403                                         ip = ast_walk_context_ignorepats(c, ip);
1404                                 }
1405
1406                                 ast_unlock_context(c);
1407                         }
1408                         c = ast_walk_contexts(c);
1409                 }
1410
1411                 ast_unlock_contexts();
1412                 return NULL;
1413         }
1414  
1415         if (pos == 3) return state == 0 ? strdup("from") : NULL;
1416
1417         if (pos == 4) {
1418                 char *dupline, *duplinet, *ignorepat;
1419
1420                 dupline = strdup(line);
1421                 if (!dupline) {
1422                         ast_log(LOG_WARNING, "Out of free memory\n");
1423                         return NULL;
1424                 }
1425
1426                 duplinet = dupline;
1427                 strsep(&duplinet, " ");
1428                 strsep(&duplinet, " ");
1429                 ignorepat = strsep(&duplinet, " ");
1430
1431                 if (!ignorepat) {
1432                         free(dupline);
1433                         return NULL;
1434                 }
1435
1436                 if (ast_lock_contexts()) {
1437                         ast_log(LOG_WARNING, "Failed to lock contexts list\n");
1438                         free(dupline);
1439                         return NULL;
1440                 }
1441
1442                 c = ast_walk_contexts(NULL);
1443                 while (c) {
1444                         if (!ast_lock_context(c)) {
1445                                 struct ast_ignorepat *ip;
1446                                 ip = ast_walk_context_ignorepats(c, NULL);
1447                                 while (ip) {
1448                                         if (!strcmp(ast_get_ignorepat_name(ip), ignorepat)) {
1449                                                 if (!strncmp(ast_get_context_name(c), word, strlen(word))) {
1450                                                         if (++which > state) {
1451                                                                 char *ret = strdup(ast_get_context_name(c));
1452                                                                 free(dupline);
1453                                                                 ast_unlock_context(c);
1454                                                                 ast_unlock_contexts();
1455                                                                 return ret;
1456                                                         }
1457                                                 }
1458                                         }
1459                                         ip = ast_walk_context_ignorepats(c, ip);
1460                                 }
1461
1462                                 ast_unlock_context(c);
1463                         }
1464                         c = ast_walk_contexts(c);
1465                 }
1466
1467                 free(dupline);
1468                 ast_unlock_contexts();
1469                 return NULL;
1470         }
1471
1472         return NULL;
1473 }
1474
1475 /*
1476  * CLI entries for commands provided by this module
1477  */
1478 static struct ast_cli_entry context_dont_include_cli =
1479         { { "dont", "include", NULL }, handle_context_dont_include,
1480                 "Remove a specified include from context", context_dont_include_help,
1481                 complete_context_dont_include };
1482
1483 static struct ast_cli_entry context_remove_extension_cli =
1484         { { "remove", "extension", NULL }, handle_context_remove_extension,
1485                 "Remove a specified extension", context_remove_extension_help,
1486                 complete_context_remove_extension };
1487
1488 static struct ast_cli_entry context_add_include_cli =
1489         { { "include", "context", NULL }, handle_context_add_include,
1490                 "Include context in other context", context_add_include_help,
1491                 complete_context_add_include };
1492
1493 static struct ast_cli_entry save_dialplan_cli =
1494         { { "save", "dialplan", NULL }, handle_save_dialplan,
1495                 "Save dialplan", save_dialplan_help };
1496
1497 static struct ast_cli_entry context_add_extension_cli =
1498         { { "add", "extension", NULL }, handle_context_add_extension,
1499                 "Add new extension into context", context_add_extension_help,
1500                 complete_context_add_extension };
1501
1502 static struct ast_cli_entry context_add_ignorepat_cli =
1503         { { "add", "ignorepat", NULL }, handle_context_add_ignorepat,
1504                 "Add new ignore pattern", context_add_ignorepat_help,
1505                 complete_context_add_ignorepat };
1506
1507 static struct ast_cli_entry context_remove_ignorepat_cli =
1508         { { "remove", "ignorepat", NULL }, handle_context_remove_ignorepat,
1509                 "Remove ignore pattern from context", context_remove_ignorepat_help,
1510                 complete_context_remove_ignorepat };
1511
1512 static struct ast_cli_entry reload_extensions_cli = 
1513         { { "extensions", "reload", NULL}, handle_reload_extensions,
1514                 "Reload extensions and *only* extensions", reload_extensions_help };
1515
1516 /*
1517  * Standard module functions ...
1518  */
1519 int unload_module(void)
1520 {
1521         ast_cli_unregister(&context_add_extension_cli);
1522         if (static_config && !write_protect_config)
1523                 ast_cli_unregister(&save_dialplan_cli);
1524         ast_cli_unregister(&context_add_include_cli);
1525         ast_cli_unregister(&context_dont_include_cli);
1526         ast_cli_unregister(&context_remove_extension_cli);
1527         ast_cli_unregister(&context_remove_ignorepat_cli);
1528         ast_cli_unregister(&context_add_ignorepat_cli);
1529         ast_cli_unregister(&reload_extensions_cli);
1530         ast_context_destroy(NULL, registrar);
1531         return 0;
1532 }
1533
1534 static int pbx_load_module(void)
1535 {
1536         struct ast_config *cfg;
1537         struct ast_variable *v;
1538         char *cxt, *ext, *pri, *appl, *data, *tc, *cidmatch;
1539         struct ast_context *con;
1540         char *start, *end;
1541         char realvalue[256];
1542
1543         cfg = ast_load(config);
1544         if (cfg) {
1545                 /* Use existing config to populate the PBX table */
1546                 static_config = ast_true(ast_variable_retrieve(cfg, "general",
1547                         "static"));
1548                 write_protect_config = ast_true(ast_variable_retrieve(cfg, "general",
1549                         "writeprotect"));
1550                 v = ast_variable_browse(cfg, "globals");
1551                 while(v) {
1552                         memset(realvalue, 0, sizeof(realvalue));
1553                         pbx_substitute_variables_helper(NULL, v->value, realvalue, sizeof(realvalue) - 1);
1554                         pbx_builtin_setvar_helper(NULL, v->name, realvalue);
1555                         v = v->next;
1556                 }
1557                 cxt = ast_category_browse(cfg, NULL);
1558                 while(cxt) {
1559                         /* All categories but "general" are considered contexts */
1560                         if (!strcasecmp(cxt, "general") || !strcasecmp(cxt, "globals")) {
1561                                 cxt = ast_category_browse(cfg, cxt);
1562                                 continue;
1563                         }
1564                         if ((con=ast_context_create(&local_contexts,cxt, registrar))) {
1565                                 v = ast_variable_browse(cfg, cxt);
1566                                 while(v) {
1567                                         if (!strcasecmp(v->name, "exten")) {
1568                                                 char *stringp=NULL;
1569                                                 int ipri = -2;
1570                                                 char realext[256]="";
1571                                                 tc = strdup(v->value);
1572                                                 if(tc!=NULL){
1573                                                         stringp=tc;
1574                                                         ext = strsep(&stringp, ",");
1575                                                         if (!ext)
1576                                                                 ext="";
1577                                                         pri = strsep(&stringp, ",");
1578                                                         if (!pri)
1579                                                                 pri="";
1580                                                         if (!strcmp(pri,"hint"))
1581                                                                 ipri=PRIORITY_HINT;
1582                                                         else
1583                                                                 ipri=atoi(pri);
1584                                                         appl = stringp;
1585                                                         if (!appl)
1586                                                                 appl="";
1587                                                         if (!(start = strchr(appl, '('))) {
1588                                                                 if (stringp)
1589                                                                         appl = strsep(&stringp, ",");
1590                                                                 else
1591                                                                         appl = "";
1592                                                         }
1593                                                         if (start && (end = strrchr(appl, ')'))) {
1594                                                                 *start = *end = '\0';
1595                                                                 data = start + 1;
1596                                                                 for (start = data; *start; start++)
1597                                                                         if (*start == ',')
1598                                                                                 *start = '|';
1599                                                         } else if (stringp!=NULL && *stringp=='"') {
1600                                                                 stringp++;
1601                                                                 data = strsep(&stringp, "\"");
1602                                                                 stringp++;
1603                                                         } else {
1604                                                                 if (stringp)
1605                                                                         data = strsep(&stringp, ",");
1606                                                                 else
1607                                                                         data = "";
1608                                                         }
1609                                                         cidmatch = strchr(ext, '/');
1610                                                         if (cidmatch) {
1611                                                                 *cidmatch = '\0';
1612                                                                 cidmatch++;
1613                                                         }
1614                                                         stringp=ext;
1615                                                         strsep(&stringp, "/");
1616
1617                                                         if (!data)
1618                                                                 data="";
1619                                                         pbx_substitute_variables_helper(NULL, ext, realext, sizeof(realext) - 1);
1620                                                         if (ast_add_extension2(con, 0, realext, ipri, cidmatch, appl, strdup(data), FREE, registrar)) {
1621                                                                 ast_log(LOG_WARNING, "Unable to register extension at line %d\n", v->lineno);
1622                                                         }
1623                                                         free(tc);
1624                                                 } else fprintf(stderr,"Error strdup returned NULL in %s\n",__PRETTY_FUNCTION__);
1625                                         } else if(!strcasecmp(v->name, "include")) {
1626                                                 memset(realvalue, 0, sizeof(realvalue));
1627                                                 pbx_substitute_variables_helper(NULL, v->value, realvalue, sizeof(realvalue) - 1);
1628                                                 if (ast_context_add_include2(con, realvalue, registrar))
1629                                                         ast_log(LOG_WARNING, "Unable to include context '%s' in context '%s'\n", v->value, cxt);
1630                                         } else if(!strcasecmp(v->name, "ignorepat")) {
1631                                                 memset(realvalue, 0, sizeof(realvalue));
1632                                                 pbx_substitute_variables_helper(NULL, v->value, realvalue, sizeof(realvalue) - 1);
1633                                                 if (ast_context_add_ignorepat2(con, realvalue, registrar))
1634                                                         ast_log(LOG_WARNING, "Unable to include ignorepat '%s' in context '%s'\n", v->value, cxt);
1635                                         } else if (!strcasecmp(v->name, "switch")) {
1636                                                 char *stringp=NULL;
1637                                                 memset(realvalue, 0, sizeof(realvalue));
1638                                                 pbx_substitute_variables_helper(NULL, v->value, realvalue, sizeof(realvalue) - 1);
1639                                                 tc = realvalue;
1640                                                 stringp=tc;
1641                                                 appl = strsep(&stringp, "/");
1642                                                 data = strsep(&stringp, "");
1643                                                 if (!data)
1644                                                         data = "";
1645                                                 if (ast_context_add_switch2(con, appl, data, registrar))
1646                                                         ast_log(LOG_WARNING, "Unable to include switch '%s' in context '%s'\n", v->value, cxt);
1647                                         }
1648                                         v = v->next;
1649                                 }
1650                         }
1651                         cxt = ast_category_browse(cfg, cxt);
1652                 }
1653                 ast_destroy(cfg);
1654         }
1655         ast_merge_contexts_and_delete(&local_contexts,registrar);
1656
1657         for (con = ast_walk_contexts(NULL); con; con = ast_walk_contexts(con))
1658                 ast_context_verify_includes(con);
1659
1660         return 0;
1661 }
1662
1663 int load_module(void)
1664 {
1665         if (pbx_load_module()) return -1;
1666  
1667         ast_cli_register(&context_remove_extension_cli);
1668         ast_cli_register(&context_dont_include_cli);
1669         ast_cli_register(&context_add_include_cli);
1670         if (static_config && !write_protect_config)
1671                 ast_cli_register(&save_dialplan_cli);
1672         ast_cli_register(&context_add_extension_cli);
1673         ast_cli_register(&context_add_ignorepat_cli);
1674         ast_cli_register(&context_remove_ignorepat_cli);
1675         ast_cli_register(&reload_extensions_cli);
1676
1677         return 0;
1678 }
1679
1680 int reload(void)
1681 {
1682         ast_context_destroy(NULL, registrar);
1683         /* For martin's global variables, don't clear them on reload */
1684 #if 0
1685         pbx_builtin_clear_globals();
1686 #endif  
1687         pbx_load_module();
1688         return 0;
1689 }
1690
1691 int usecount(void)
1692 {
1693         return 0;
1694 }
1695
1696 char *description(void)
1697 {
1698         return dtext;
1699 }
1700
1701 char *key(void)
1702 {
1703         return ASTERISK_GPL_KEY;
1704 }