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