e017be79c13bf329a9dec6d4ae6c2d864339f2c0
[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 != 5) return RESULT_SHOWUSAGE;
693
694         /* third arg must be 'in' ... */
695         if (strcmp(argv[3], "in")) return RESULT_SHOWUSAGE;
696
697         if (ast_context_add_include(argv[4], argv[2], 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[4] : argv[2]); 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[2], 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         struct ast_config *cfg;
907         struct ast_variable *v;
908         int context_header_written;
909         int incomplete = 0; /* incomplete config write? */
910         FILE *output;
911
912         if (! (static_config && !write_protect_config)) {
913                 ast_cli(fd,
914                         "I can't save dialplan now, see '%s' example file.\n",
915                         config);
916                 return RESULT_FAILURE;
917         }
918
919         if (argc != 2 && argc != 3) return RESULT_SHOWUSAGE;
920
921         if (ast_mutex_lock(&save_dialplan_lock)) {
922                 ast_cli(fd,
923                         "Failed to lock dialplan saving (another proccess saving?)\n");
924                 return RESULT_FAILURE;
925         }
926
927         /* have config path? */
928         if (argc == 3) {
929                 /* is there extension.conf too? */
930                 if (!strstr(argv[2], ".conf")) {
931                         /* no, only directory path, check for last '/' occurence */
932                         if (*(argv[2] + strlen(argv[2]) -1) == '/')
933                                 snprintf(filename, sizeof(filename), "%s%s",
934                                         argv[2], config);
935                         else
936                                 /* without config extensions.conf, add it */
937                                 snprintf(filename, sizeof(filename), "%s/%s",
938                                         argv[2], config);
939                 } else
940                         /* there is an .conf */
941                         snprintf(filename, sizeof(filename), argv[2]);
942         } else
943                 /* no config file, default one */
944                 snprintf(filename, sizeof(filename), "%s/%s",
945                         (char *)ast_config_AST_CONFIG_DIR, config);
946
947         cfg = ast_load("extensions.conf");
948
949         /* try to lock contexts list */
950         if (ast_lock_contexts()) {
951                 ast_cli(fd, "Failed to lock contexts list\n");
952                 ast_mutex_unlock(&save_dialplan_lock);
953                 ast_destroy(cfg);
954                 return RESULT_FAILURE;
955         }
956
957         /* create new file ... */
958         if (!(output = fopen(filename, "wt"))) {
959                 ast_cli(fd, "Failed to create file '%s'\n",
960                         filename);
961                 ast_unlock_contexts();
962                 ast_mutex_unlock(&save_dialplan_lock);
963                 ast_destroy(cfg);
964                 return RESULT_FAILURE;
965         }
966
967         /* fireout general info */
968         fprintf(output, "[general]\nstatic=%s\nwriteprotect=%s\n\n",
969                 static_config ? "yes" : "no",
970                 write_protect_config ? "yes" : "no");
971
972         if ((v = ast_variable_browse(cfg, "globals"))) {
973                 fprintf(output, "[globals]\n");
974                 while(v) {
975                         fprintf(output, "%s => %s\n", v->name, v->value);
976                         v = v->next;
977                 }
978                 fprintf(output, "\n");
979         }
980
981         ast_destroy(cfg);
982         
983         /* walk all contexts */
984         c = ast_walk_contexts(NULL);
985         while (c) {
986                 context_header_written = 0;
987         
988                 /* try to lock context and fireout all info */  
989                 if (!ast_lock_context(c)) {
990                         struct ast_exten *e, *last_written_e = NULL;
991                         struct ast_include *i;
992                         struct ast_ignorepat *ip;
993
994                         /* registered by this module? */
995                         if (!strcmp(ast_get_context_registrar(c), registrar)) {
996                                 fprintf(output, "[%s]\n", ast_get_context_name(c));
997                                 context_header_written = 1;
998                         }
999
1000                         /* walk extensions ... */
1001                         e = ast_walk_context_extensions(c, NULL);
1002                         while (e) {
1003                                 struct ast_exten *p;
1004
1005                                 /* fireout priorities */
1006                                 p = ast_walk_extension_priorities(e, NULL);
1007                                 while (p) {
1008                                         if (!strcmp(ast_get_extension_registrar(p),
1009                                                 registrar)) {
1010                         
1011                                                 /* make empty line between different extensions */      
1012                                                 if (last_written_e != NULL &&
1013                                                         strcmp(ast_get_extension_name(last_written_e),
1014                                                                 ast_get_extension_name(p)))
1015                                                         fprintf(output, "\n");
1016                                                 last_written_e = p;
1017                                 
1018                                                 if (!context_header_written) {
1019                                                         fprintf(output, "[%s]\n", ast_get_context_name(c));
1020                                                         context_header_written = 1;
1021                                                 }
1022
1023                                                 if (ast_get_extension_priority(p)!=PRIORITY_HINT) {
1024                                                         char *tempdata = NULL, *startdata;
1025                                                         tempdata = strdup((char *)ast_get_extension_app_data(p));
1026                                                         if (tempdata) {
1027                                                                 startdata = tempdata;
1028                                                                 while (*tempdata) {
1029                                                                         if (*tempdata == '|')
1030                                                                                 *tempdata = ',';
1031                                                                         tempdata++;
1032                                                                 }
1033                                                                 tempdata = startdata;
1034                                                         }
1035                                                         fprintf(output, "exten => %s,%d,%s(%s)\n",
1036                                                             ast_get_extension_name(p),
1037                                                             ast_get_extension_priority(p),
1038                                                             ast_get_extension_app(p),
1039                                                             tempdata);
1040                                                         if (tempdata)
1041                                                                 free(tempdata);
1042                                                 } else
1043                                                         fprintf(output, "exten => %s,hint,%s\n",
1044                                                             ast_get_extension_name(p),
1045                                                             ast_get_extension_app(p));
1046                                                 
1047                                         }
1048                                         p = ast_walk_extension_priorities(e, p);
1049                                 }
1050
1051                                 e = ast_walk_context_extensions(c, e);
1052                         }
1053
1054                         /* written any extensions? ok, write space between exten & inc */
1055                         if (last_written_e) fprintf(output, "\n");
1056
1057                         /* walk through includes */
1058                         i = ast_walk_context_includes(c, NULL);
1059                         while (i) {
1060                                 if (!strcmp(ast_get_include_registrar(i), registrar)) {
1061                                         if (!context_header_written) {
1062                                                 fprintf(output, "[%s]\n", ast_get_context_name(c));
1063                                                 context_header_written = 1;
1064                                         }
1065                                         fprintf(output, "include => %s\n",
1066                                                 ast_get_include_name(i));
1067                                 }
1068                                 i = ast_walk_context_includes(c, i);
1069                         }
1070
1071                         if (ast_walk_context_includes(c, NULL))
1072                                 fprintf(output, "\n");
1073
1074                         /* fireout ignorepats ... */
1075                         ip = ast_walk_context_ignorepats(c, NULL);
1076                         while (ip) {
1077                                 if (!strcmp(ast_get_ignorepat_registrar(ip), registrar)) {
1078                                         if (!context_header_written) {
1079                                                 fprintf(output, "[%s]\n", ast_get_context_name(c));
1080                                                 context_header_written = 1;
1081                                         }
1082
1083                                         fprintf(output, "ignorepat => %s\n",
1084                                                 ast_get_ignorepat_name(ip));
1085                                 }
1086                                 ip = ast_walk_context_ignorepats(c, ip);
1087                         }
1088
1089                         ast_unlock_context(c);
1090                 } else
1091                         incomplete = 1;
1092
1093                 c = ast_walk_contexts(c);
1094         }       
1095
1096         ast_unlock_contexts();
1097         ast_mutex_unlock(&save_dialplan_lock);
1098         fclose(output);
1099
1100         if (incomplete) {
1101                 ast_cli(fd, "Saved dialplan is incomplete\n");
1102                 return RESULT_FAILURE;
1103         }
1104
1105         ast_cli(fd, "Dialplane successfully saved into '%s'\n",
1106                 filename);
1107         return RESULT_SUCCESS;
1108 }
1109
1110 /*
1111  * ADD EXTENSION command stuff
1112  */
1113 static int handle_context_add_extension(int fd, int argc, char *argv[])
1114 {
1115         char *whole_exten;
1116         char *exten, *prior;
1117         int iprior = -2;
1118         char *cidmatch, *app, *app_data;
1119         char *start, *end;
1120
1121         /* check for arguments at first */
1122         if (argc != 5 && argc != 6) return RESULT_SHOWUSAGE;
1123         if (strcmp(argv[3], "into")) return RESULT_SHOWUSAGE;
1124         if (argc == 6) if (strcmp(argv[5], "replace")) return RESULT_SHOWUSAGE;
1125
1126         whole_exten = argv[2];
1127         exten           = strsep(&whole_exten,",");
1128         if (strchr(exten, '/')) {
1129                 cidmatch = exten;
1130                 strsep(&cidmatch,"/");
1131         } else {
1132                 cidmatch = NULL;
1133         }
1134         prior       = strsep(&whole_exten,",");
1135         if (prior) {
1136         if (!strcmp(prior, "hint")) {
1137                         iprior = PRIORITY_HINT;
1138                 } else {
1139                         if (sscanf(prior, "%i", &iprior) != 1) {
1140                                 ast_cli(fd, "'%s' is not a valid priority\n", prior);
1141                                 prior = NULL;
1142                         }
1143                 }
1144         }
1145         app         = strsep(&whole_exten,",");
1146         if (app && (start = strchr(app, '(')) && (end = strrchr(app, ')'))) {
1147                 *start = *end = '\0';
1148                 app_data = start + 1;
1149                 for (start = app_data; *start; start++)
1150                         if (*start == ',')
1151                                 *start = '|';
1152         } else
1153                 app_data    = whole_exten;
1154
1155         if (!exten || !prior || !app || (!app_data && iprior != PRIORITY_HINT)) return RESULT_SHOWUSAGE;
1156
1157         if (!app_data)
1158             app_data="";
1159         if (ast_add_extension(argv[4], argc == 6 ? 1 : 0, exten, iprior, cidmatch, app,
1160                 (void *)strdup(app_data), free, registrar)) {
1161                 switch (errno) {
1162                         case ENOMEM:
1163                                 ast_cli(fd, "Out of free memory\n"); break;
1164
1165                         case EBUSY:
1166                                 ast_cli(fd, "Failed to lock context(s) list, please try again later\n"); break;
1167
1168                         case ENOENT:
1169                                 ast_cli(fd, "No existence of '%s' context\n", argv[4]); break;
1170
1171                         case EEXIST:
1172                                 ast_cli(fd, "Extension %s@%s with priority %s already exists\n",
1173                                         exten, argv[4], prior); break;
1174
1175                         default:
1176                                 ast_cli(fd, "Failed to add '%s,%s,%s,%s' extension into '%s' context\n",
1177                                         exten, prior, app, app_data, argv[4]); break;
1178                 }
1179                 return RESULT_FAILURE;
1180         }
1181
1182         if (argc == 6) 
1183                 ast_cli(fd, "Extension %s@%s (%s) replace by '%s,%s,%s,%s'\n",
1184                         exten, argv[4], prior, exten, prior, app, app_data);
1185         else
1186                 ast_cli(fd, "Extension '%s,%s,%s,%s' added into '%s' context\n",
1187                         exten, prior, app, app_data, argv[4]);
1188
1189         return RESULT_SUCCESS;
1190 }
1191
1192 /* add extension 6123,1,Dial,IAX/212.71.138.13/6123 into local */
1193 static char *complete_context_add_extension(char *line, char *word,
1194         int pos, int state)
1195 {
1196         int which = 0;
1197
1198         /* complete 'into' word ... */
1199         if (pos == 3) {
1200                 if (state == 0) return strdup("into");
1201                 return NULL;
1202         }
1203
1204         /* complete context */
1205         if (pos == 4) {
1206                 struct ast_context *c;
1207
1208                 /* try to lock contexts list ... */
1209                 if (ast_lock_contexts()) {
1210                         ast_log(LOG_WARNING, "Failed to lock contexts list\n");
1211                         return NULL;
1212                 }
1213
1214                 /* walk through all contexts */
1215                 c = ast_walk_contexts(NULL);
1216                 while (c) {
1217                         /* matching context? */
1218                         if (!strncmp(ast_get_context_name(c), word, strlen(word))) {
1219                                 if (++which > state) {
1220                                         char *res = strdup(ast_get_context_name(c));
1221                                         ast_unlock_contexts();
1222                                         return res;
1223                                 }
1224                         }
1225                         c = ast_walk_contexts(c);
1226                 }
1227
1228                 ast_unlock_contexts();
1229                 return NULL;
1230         }
1231
1232         if (pos == 5) return state == 0 ? strdup("replace") : NULL;
1233
1234         return NULL;
1235 }
1236
1237 /*
1238  * IGNOREPAT CLI stuff
1239  */
1240 static int handle_context_add_ignorepat(int fd, int argc, char *argv[])
1241 {
1242         if (argc != 5) return RESULT_SHOWUSAGE;
1243         if (strcmp(argv[3], "into")) return RESULT_SHOWUSAGE;
1244
1245         if (ast_context_add_ignorepat(argv[4], argv[2], registrar)) {
1246                 switch (errno) {
1247                         case ENOMEM:
1248                                 ast_cli(fd, "Out of free memory\n"); break;
1249
1250                         case ENOENT:
1251                                 ast_cli(fd, "There is no existence of '%s' context\n", argv[4]);
1252                                 break;
1253
1254                         case EEXIST:
1255                                 ast_cli(fd, "Ignore pattern '%s' already included in '%s' context\n",
1256                                         argv[2], argv[4]);
1257                                 break;
1258
1259                         case EBUSY:
1260                                 ast_cli(fd, "Failed to lock context(s) list, please, try again later\n");
1261                                 break;
1262
1263                         default:
1264                                 ast_cli(fd, "Failed to add ingore pattern '%s' into '%s' context\n",
1265                                         argv[2], argv[4]);
1266                                 break;
1267                 }
1268                 return RESULT_FAILURE;
1269         }
1270
1271         ast_cli(fd, "Ignore pattern '%s' added into '%s' context\n",
1272                 argv[2], argv[4]);
1273         return RESULT_SUCCESS;
1274 }
1275
1276 static char *complete_context_add_ignorepat(char *line, char *word,
1277         int pos, int state)
1278 {
1279         if (pos == 3) return state == 0 ? strdup("into") : NULL;
1280
1281         if (pos == 4) {
1282                 struct ast_context *c;
1283                 int which = 0;
1284                 char *dupline, *duplinet, *ignorepat = NULL;
1285
1286                 dupline = strdup(line);
1287                 duplinet = dupline;
1288
1289                 if (duplinet) {
1290                         strsep(&duplinet, " "); /* skip 'add' */
1291                         strsep(&duplinet, " "); /* skip 'ignorepat' */
1292                         ignorepat = strsep(&duplinet, " ");
1293                 }
1294
1295                 if (ast_lock_contexts()) {
1296                         ast_log(LOG_ERROR, "Failed to lock contexts list\n");
1297                         return NULL;
1298                 }
1299
1300                 c = ast_walk_contexts(NULL);
1301                 while (c) {
1302                         if (!strncmp(ast_get_context_name(c), word, strlen(word))) {
1303                                 int serve_context = 1;
1304                                 if (ignorepat) {
1305                                         if (!ast_lock_context(c)) {
1306                                                 struct ast_ignorepat *ip;
1307                                                 ip = ast_walk_context_ignorepats(c, NULL);
1308                                                 while (ip && serve_context) {
1309                                                         if (!strcmp(ast_get_ignorepat_name(ip), ignorepat))
1310                                                                 serve_context = 0;
1311                                                         ip = ast_walk_context_ignorepats(c, ip);
1312                                                 }
1313                                                 ast_unlock_context(c);
1314                                         }
1315                                 }
1316                                 if (serve_context) {
1317                                         if (++which > state) {
1318                                                 char *context = strdup(ast_get_context_name(c));
1319                                                 if (dupline) free(dupline);
1320                                                 ast_unlock_contexts();
1321                                                 return context;
1322                                         }
1323                                 }
1324                         }
1325                         c = ast_walk_contexts(c);
1326                 }
1327
1328                 if (dupline) free(dupline);
1329                 ast_unlock_contexts();
1330                 return NULL;
1331         }
1332
1333         return NULL;
1334 }
1335
1336 static int handle_context_remove_ignorepat(int fd, int argc, char *argv[])
1337 {
1338         if (argc != 5) return RESULT_SHOWUSAGE;
1339         if (strcmp(argv[3], "from")) return RESULT_SHOWUSAGE;
1340
1341         if (ast_context_remove_ignorepat(argv[4], argv[2], registrar)) {
1342                 switch (errno) {
1343                         case EBUSY:
1344                                 ast_cli(fd, "Failed to lock context(s) list, please try again later\n");
1345                                 break;
1346
1347                         case ENOENT:
1348                                 ast_cli(fd, "There is no existence of '%s' context\n", argv[4]);
1349                                 break;
1350
1351                         case EINVAL:
1352                                 ast_cli(fd, "There is no existence of '%s' ignore pattern in '%s' context\n",
1353                                         argv[2], argv[4]);
1354                                 break;
1355
1356                         default:
1357                                 ast_cli(fd, "Failed to remove ignore pattern '%s' from '%s' context\n", argv[2], argv[4]);
1358                                 break;
1359                 }
1360                 return RESULT_FAILURE;
1361         }
1362
1363         ast_cli(fd, "Ignore pattern '%s' removed from '%s' context\n",
1364                 argv[2], argv[4]);
1365         return RESULT_SUCCESS;
1366 }
1367
1368 static int pbx_load_module(void);
1369
1370 static int handle_reload_extensions(int fd, int argc, char *argv[])
1371 {
1372         if (argc!=2) return RESULT_SHOWUSAGE;
1373         pbx_load_module();
1374         return RESULT_SUCCESS;
1375 }
1376
1377 static char *complete_context_remove_ignorepat(char *line, char *word,
1378         int pos, int state)
1379 {
1380         struct ast_context *c;
1381         int which = 0;
1382
1383         if (pos == 2) {
1384                 if (ast_lock_contexts()) {
1385                         ast_log(LOG_WARNING, "Failed to lock contexts list\n");
1386                         return NULL;
1387                 }
1388
1389                 c = ast_walk_contexts(NULL);
1390                 while (c) {
1391                         if (!ast_lock_context(c)) {
1392                                 struct ast_ignorepat *ip;
1393                         
1394                                 ip = ast_walk_context_ignorepats(c, NULL);
1395                                 while (ip) {
1396                                         if (!strncmp(ast_get_ignorepat_name(ip), word, strlen(word))) {
1397                                                 if (which + 1 > state) {
1398                                                         struct ast_context *cw;
1399                                                         int already_served = 0;
1400                                                         cw = ast_walk_contexts(NULL);
1401                                                         while (cw && cw != c && !already_served) {
1402                                                                 if (!ast_lock_context(cw)) {
1403                                                                         struct ast_ignorepat *ipw;
1404                                                                         ipw = ast_walk_context_ignorepats(cw, NULL);
1405                                                                         while (ipw) {
1406                                                                                 if (!strcmp(ast_get_ignorepat_name(ipw),
1407                                                                                         ast_get_ignorepat_name(ip))) already_served = 1;
1408                                                                                 ipw = ast_walk_context_ignorepats(cw, ipw);
1409                                                                         }
1410                                                                         ast_unlock_context(cw);
1411                                                                 }
1412                                                                 cw = ast_walk_contexts(cw);
1413                                                         }
1414                                                         if (!already_served) {
1415                                                                 char *ret = strdup(ast_get_ignorepat_name(ip));
1416                                                                 ast_unlock_context(c);
1417                                                                 ast_unlock_contexts();
1418                                                                 return ret;
1419                                                         }
1420                                                 } else
1421                                                         which++;
1422                                         }
1423                                         ip = ast_walk_context_ignorepats(c, ip);
1424                                 }
1425
1426                                 ast_unlock_context(c);
1427                         }
1428                         c = ast_walk_contexts(c);
1429                 }
1430
1431                 ast_unlock_contexts();
1432                 return NULL;
1433         }
1434  
1435         if (pos == 3) return state == 0 ? strdup("from") : NULL;
1436
1437         if (pos == 4) {
1438                 char *dupline, *duplinet, *ignorepat;
1439
1440                 dupline = strdup(line);
1441                 if (!dupline) {
1442                         ast_log(LOG_WARNING, "Out of free memory\n");
1443                         return NULL;
1444                 }
1445
1446                 duplinet = dupline;
1447                 strsep(&duplinet, " ");
1448                 strsep(&duplinet, " ");
1449                 ignorepat = strsep(&duplinet, " ");
1450
1451                 if (!ignorepat) {
1452                         free(dupline);
1453                         return NULL;
1454                 }
1455
1456                 if (ast_lock_contexts()) {
1457                         ast_log(LOG_WARNING, "Failed to lock contexts list\n");
1458                         free(dupline);
1459                         return NULL;
1460                 }
1461
1462                 c = ast_walk_contexts(NULL);
1463                 while (c) {
1464                         if (!ast_lock_context(c)) {
1465                                 struct ast_ignorepat *ip;
1466                                 ip = ast_walk_context_ignorepats(c, NULL);
1467                                 while (ip) {
1468                                         if (!strcmp(ast_get_ignorepat_name(ip), ignorepat)) {
1469                                                 if (!strncmp(ast_get_context_name(c), word, strlen(word))) {
1470                                                         if (++which > state) {
1471                                                                 char *ret = strdup(ast_get_context_name(c));
1472                                                                 free(dupline);
1473                                                                 ast_unlock_context(c);
1474                                                                 ast_unlock_contexts();
1475                                                                 return ret;
1476                                                         }
1477                                                 }
1478                                         }
1479                                         ip = ast_walk_context_ignorepats(c, ip);
1480                                 }
1481
1482                                 ast_unlock_context(c);
1483                         }
1484                         c = ast_walk_contexts(c);
1485                 }
1486
1487                 free(dupline);
1488                 ast_unlock_contexts();
1489                 return NULL;
1490         }
1491
1492         return NULL;
1493 }
1494
1495 /*
1496  * CLI entries for commands provided by this module
1497  */
1498 static struct ast_cli_entry context_dont_include_cli =
1499         { { "dont", "include", NULL }, handle_context_dont_include,
1500                 "Remove a specified include from context", context_dont_include_help,
1501                 complete_context_dont_include };
1502
1503 static struct ast_cli_entry context_remove_extension_cli =
1504         { { "remove", "extension", NULL }, handle_context_remove_extension,
1505                 "Remove a specified extension", context_remove_extension_help,
1506                 complete_context_remove_extension };
1507
1508 static struct ast_cli_entry context_add_include_cli =
1509         { { "include", "context", NULL }, handle_context_add_include,
1510                 "Include context in other context", context_add_include_help,
1511                 complete_context_add_include };
1512
1513 static struct ast_cli_entry save_dialplan_cli =
1514         { { "save", "dialplan", NULL }, handle_save_dialplan,
1515                 "Save dialplan", save_dialplan_help };
1516
1517 static struct ast_cli_entry context_add_extension_cli =
1518         { { "add", "extension", NULL }, handle_context_add_extension,
1519                 "Add new extension into context", context_add_extension_help,
1520                 complete_context_add_extension };
1521
1522 static struct ast_cli_entry context_add_ignorepat_cli =
1523         { { "add", "ignorepat", NULL }, handle_context_add_ignorepat,
1524                 "Add new ignore pattern", context_add_ignorepat_help,
1525                 complete_context_add_ignorepat };
1526
1527 static struct ast_cli_entry context_remove_ignorepat_cli =
1528         { { "remove", "ignorepat", NULL }, handle_context_remove_ignorepat,
1529                 "Remove ignore pattern from context", context_remove_ignorepat_help,
1530                 complete_context_remove_ignorepat };
1531
1532 static struct ast_cli_entry reload_extensions_cli = 
1533         { { "extensions", "reload", NULL}, handle_reload_extensions,
1534                 "Reload extensions and *only* extensions", reload_extensions_help };
1535
1536 /*
1537  * Standard module functions ...
1538  */
1539 int unload_module(void)
1540 {
1541         ast_cli_unregister(&context_add_extension_cli);
1542         if (static_config && !write_protect_config)
1543                 ast_cli_unregister(&save_dialplan_cli);
1544         ast_cli_unregister(&context_add_include_cli);
1545         ast_cli_unregister(&context_dont_include_cli);
1546         ast_cli_unregister(&context_remove_extension_cli);
1547         ast_cli_unregister(&context_remove_ignorepat_cli);
1548         ast_cli_unregister(&context_add_ignorepat_cli);
1549         ast_cli_unregister(&reload_extensions_cli);
1550         ast_context_destroy(NULL, registrar);
1551         return 0;
1552 }
1553
1554 static int pbx_load_module(void)
1555 {
1556         struct ast_config *cfg;
1557         struct ast_variable *v;
1558         char *cxt, *ext, *pri, *appl, *data, *tc, *cidmatch;
1559         struct ast_context *con;
1560         char *start, *end;
1561         char realvalue[256];
1562
1563         cfg = ast_load(config);
1564         if (cfg) {
1565                 /* Use existing config to populate the PBX table */
1566                 static_config = ast_true(ast_variable_retrieve(cfg, "general",
1567                         "static"));
1568                 write_protect_config = ast_true(ast_variable_retrieve(cfg, "general",
1569                         "writeprotect"));
1570                 v = ast_variable_browse(cfg, "globals");
1571                 while(v) {
1572                         memset(realvalue, 0, sizeof(realvalue));
1573                         pbx_substitute_variables_helper(NULL, v->value, realvalue, sizeof(realvalue) - 1);
1574                         pbx_builtin_setvar_helper(NULL, v->name, realvalue);
1575                         v = v->next;
1576                 }
1577                 cxt = ast_category_browse(cfg, NULL);
1578                 while(cxt) {
1579                         /* All categories but "general" are considered contexts */
1580                         if (!strcasecmp(cxt, "general") || !strcasecmp(cxt, "globals")) {
1581                                 cxt = ast_category_browse(cfg, cxt);
1582                                 continue;
1583                         }
1584                         if ((con=ast_context_create(&local_contexts,cxt, registrar))) {
1585                                 v = ast_variable_browse(cfg, cxt);
1586                                 while(v) {
1587                                         if (!strcasecmp(v->name, "exten")) {
1588                                                 char *stringp=NULL;
1589                                                 int ipri = -2;
1590                                                 char realext[256]="";
1591                                                 tc = strdup(v->value);
1592                                                 if(tc!=NULL){
1593                                                         stringp=tc;
1594                                                         ext = strsep(&stringp, ",");
1595                                                         if (!ext)
1596                                                                 ext="";
1597                                                         pri = strsep(&stringp, ",");
1598                                                         if (!pri)
1599                                                                 pri="";
1600                                                         if (!strcmp(pri,"hint"))
1601                                                                 ipri=PRIORITY_HINT;
1602                                                         else {
1603                                                                 if (sscanf(pri, "%i", &ipri) != 1) {
1604                                                                         ast_log(LOG_WARNING, "Invalid priority '%s' at line %d\n", pri, v->lineno);
1605                                                                         ipri = 0;
1606                                                                 }
1607                                                         }
1608                                                         appl = stringp;
1609                                                         if (!appl)
1610                                                                 appl="";
1611                                                         if (!(start = strchr(appl, '('))) {
1612                                                                 if (stringp)
1613                                                                         appl = strsep(&stringp, ",");
1614                                                                 else
1615                                                                         appl = "";
1616                                                         }
1617                                                         if (start && (end = strrchr(appl, ')'))) {
1618                                                                 *start = *end = '\0';
1619                                                                 data = start + 1;
1620                                                                 for (start = data; *start; start++)
1621                                                                         if (*start == ',')
1622                                                                                 *start = '|';
1623                                                         } else if (stringp!=NULL && *stringp=='"') {
1624                                                                 stringp++;
1625                                                                 data = strsep(&stringp, "\"");
1626                                                                 stringp++;
1627                                                         } else {
1628                                                                 if (stringp)
1629                                                                         data = strsep(&stringp, ",");
1630                                                                 else
1631                                                                         data = "";
1632                                                         }
1633                                                         cidmatch = strchr(ext, '/');
1634                                                         if (cidmatch) {
1635                                                                 *cidmatch = '\0';
1636                                                                 cidmatch++;
1637                                                         }
1638                                                         stringp=ext;
1639                                                         strsep(&stringp, "/");
1640
1641                                                         if (!data)
1642                                                                 data="";
1643                                                         while(*appl && (*appl < 33)) appl++;
1644                                                         pbx_substitute_variables_helper(NULL, ext, realext, sizeof(realext) - 1);
1645                                                         if (ipri) {
1646                                                                 if (ast_add_extension2(con, 0, realext, ipri, cidmatch, appl, strdup(data), FREE, registrar)) {
1647                                                                         ast_log(LOG_WARNING, "Unable to register extension at line %d\n", v->lineno);
1648                                                                 }
1649                                                         }
1650                                                         free(tc);
1651                                                 } else fprintf(stderr,"Error strdup returned NULL in %s\n",__PRETTY_FUNCTION__);
1652                                         } else if(!strcasecmp(v->name, "include")) {
1653                                                 memset(realvalue, 0, sizeof(realvalue));
1654                                                 pbx_substitute_variables_helper(NULL, v->value, realvalue, sizeof(realvalue) - 1);
1655                                                 if (ast_context_add_include2(con, realvalue, registrar))
1656                                                         ast_log(LOG_WARNING, "Unable to include context '%s' in context '%s'\n", v->value, cxt);
1657                                         } else if(!strcasecmp(v->name, "ignorepat")) {
1658                                                 memset(realvalue, 0, sizeof(realvalue));
1659                                                 pbx_substitute_variables_helper(NULL, v->value, realvalue, sizeof(realvalue) - 1);
1660                                                 if (ast_context_add_ignorepat2(con, realvalue, registrar))
1661                                                         ast_log(LOG_WARNING, "Unable to include ignorepat '%s' in context '%s'\n", v->value, cxt);
1662                                         } else if (!strcasecmp(v->name, "switch")) {
1663                                                 char *stringp=NULL;
1664                                                 memset(realvalue, 0, sizeof(realvalue));
1665                                                 pbx_substitute_variables_helper(NULL, v->value, realvalue, sizeof(realvalue) - 1);
1666                                                 tc = realvalue;
1667                                                 stringp=tc;
1668                                                 appl = strsep(&stringp, "/");
1669                                                 data = strsep(&stringp, "");
1670                                                 if (!data)
1671                                                         data = "";
1672                                                 if (ast_context_add_switch2(con, appl, data, registrar))
1673                                                         ast_log(LOG_WARNING, "Unable to include switch '%s' in context '%s'\n", v->value, cxt);
1674                                         }
1675                                         v = v->next;
1676                                 }
1677                         }
1678                         cxt = ast_category_browse(cfg, cxt);
1679                 }
1680                 ast_destroy(cfg);
1681         }
1682         ast_merge_contexts_and_delete(&local_contexts,registrar);
1683
1684         for (con = ast_walk_contexts(NULL); con; con = ast_walk_contexts(con))
1685                 ast_context_verify_includes(con);
1686
1687         return 0;
1688 }
1689
1690 int load_module(void)
1691 {
1692         if (pbx_load_module()) return -1;
1693  
1694         ast_cli_register(&context_remove_extension_cli);
1695         ast_cli_register(&context_dont_include_cli);
1696         ast_cli_register(&context_add_include_cli);
1697         if (static_config && !write_protect_config)
1698                 ast_cli_register(&save_dialplan_cli);
1699         ast_cli_register(&context_add_extension_cli);
1700         ast_cli_register(&context_add_ignorepat_cli);
1701         ast_cli_register(&context_remove_ignorepat_cli);
1702         ast_cli_register(&reload_extensions_cli);
1703
1704         return 0;
1705 }
1706
1707 int reload(void)
1708 {
1709         ast_context_destroy(NULL, registrar);
1710         /* For martin's global variables, don't clear them on reload */
1711 #if 0
1712         pbx_builtin_clear_globals();
1713 #endif  
1714         pbx_load_module();
1715         return 0;
1716 }
1717
1718 int usecount(void)
1719 {
1720         return 0;
1721 }
1722
1723 char *description(void)
1724 {
1725         return dtext;
1726 }
1727
1728 char *key(void)
1729 {
1730         return ASTERISK_GPL_KEY;
1731 }