2 * Asterisk -- A telephony toolkit for Linux.
4 * Populate and remember extensions from static config file
6 * Copyright (C) 1999, Mark Spencer
8 * Mark Spencer <markster@linux-support.net>
10 * This program is free software, distributed under the terms of
11 * the GNU General Public License
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>
25 /* For where to put dynamic tables */
26 #include "../asterisk.h"
27 #include "../astconf.h"
29 #ifdef __AST_DEBUG_MALLOC
30 static void FREE(void *ptr)
38 static char *dtext = "Text Extension Configuration";
39 static char *config = "extensions.conf";
40 static char *registrar = "pbx_config";
42 static int static_config = 0;
43 static int write_protect_config = 1;
45 static pthread_mutex_t save_dialplan_lock = AST_MUTEX_INITIALIZER;
48 * Help for commands provided by this module ...
50 static char context_dont_include_help[] =
51 "Usage: dont include context in include\n"
52 " Remove include from context.\n";
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";
59 static char context_add_include_help[] =
60 "Usage: include context in context\n"
61 " Include context in other context.\n";
63 static char save_dialplan_help[] =
64 "Usage: save dialplan [/path/to/extension/file]\n"
65 " Save dialplan created by pbx_config module.\n"
67 "Example: save dialplan (/etc/asterisk/extensions.conf)\n"
68 " save dialplan /home/markster (/home/markster/extensions.conf)\n";
70 static char context_add_extension_help[] =
71 "Usage: add extension <exten>,<priority>,<app>,<app-data> into <context>\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"
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";
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"
84 "Example: add ignorepat _3XX into local\n";
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"
90 "Example: remove ignorepat _3XX from local\n";
93 * Implementation of functions provided by this module
97 * REMOVE INCLUDE command stuff
99 static int handle_context_dont_include(int fd, int argc, char *argv[])
101 if (argc != 5) return RESULT_SHOWUSAGE;
103 if (strcmp(argv[3], "in")) return RESULT_SHOWUSAGE;
105 if (!ast_context_remove_include(argv[4], argv[2], registrar)) {
106 ast_cli(fd, "We are not including '%s' in '%s' now\n",
108 return RESULT_SUCCESS;
111 ast_cli(fd, "Failed to remove '%s' include from '%s' context\n",
113 return RESULT_FAILURE;
116 static char *complete_context_dont_include(char *line, char *word,
122 * Context completion ...
125 struct ast_context *c;
127 if (ast_lock_contexts()) {
128 ast_log(LOG_ERROR, "Failed to lock context list\n");
132 /* walk pbx_get_contexts ... */
133 c = ast_walk_contexts(NULL);
135 struct ast_include *i;
137 if (ast_lock_context(c)) {
138 c = ast_walk_contexts(c);
142 i = ast_walk_context_includes(c, NULL);
145 !strncmp(ast_get_include_name(i), word, strlen(word))) {
146 struct ast_context *nc;
147 int already_served = 0;
149 /* check if this include is already served or not */
151 /* go through all contexts again till we reach actuall
152 * context or already_served = 1
154 nc = ast_walk_contexts(NULL);
155 while (nc && nc != c && !already_served) {
156 if (!ast_lock_context(nc)) {
157 struct ast_include *ni;
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)))
164 ni = ast_walk_context_includes(nc, ni);
167 ast_unlock_context(nc);
169 nc = ast_walk_contexts(nc);
172 if (!already_served) {
173 if (++which > state) {
175 strdup(ast_get_include_name(i));
176 ast_unlock_context(c);
177 ast_unlock_contexts();
182 i = ast_walk_context_includes(c, i);
185 ast_unlock_context(c);
186 c = ast_walk_contexts(c);
189 ast_unlock_contexts();
194 * 'in' completion ... (complete only if previous context is really
195 * included somewhere)
198 struct ast_context *c;
199 char *context, *dupline, *duplinet;
201 if (state > 0) return NULL;
203 /* take 'context' from line ... */
204 if (!(dupline = strdup(line))) {
205 ast_log(LOG_ERROR, "Out of free memory\n");
210 strsep(&duplinet, " "); /* skip 'dont' */
211 strsep(&duplinet, " "); /* skip 'include' */
212 context = strsep(&duplinet, " ");
219 if (ast_lock_contexts()) {
220 ast_log(LOG_WARNING, "Failed to lock contexts list\n");
225 /* go through all contexts and check if is included ... */
226 c = ast_walk_contexts(NULL);
228 struct ast_include *i;
229 if (ast_lock_context(c)) {
231 ast_unlock_contexts();
235 i = ast_walk_context_includes(c, NULL);
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
243 ast_unlock_context(c);
244 ast_unlock_contexts();
247 i = ast_walk_context_includes(c, i);
249 ast_unlock_context(c);
250 c = ast_walk_contexts(c);
253 ast_unlock_contexts();
258 * Context from which we removing include ...
261 struct ast_context *c;
262 char *context, *dupline, *duplinet, *in;
264 if (!(dupline = strdup(line))) {
265 ast_log(LOG_ERROR, "Out of free memory\n");
271 strsep(&duplinet, " "); /* skip 'dont' */
272 strsep(&duplinet, " "); /* skip 'include' */
274 if (!(context = strsep(&duplinet, " "))) {
279 /* third word must be in */
280 in = strsep(&duplinet, " ");
287 if (ast_lock_contexts()) {
288 ast_log(LOG_ERROR, "Failed to lock context list\n");
293 /* walk through all contexts ... */
294 c = ast_walk_contexts(NULL);
296 struct ast_include *i;
297 if (ast_lock_context(c)) {
302 /* walk through all includes and check if it is our context */
303 i = ast_walk_context_includes(c, NULL);
305 /* is in this context included another on which we want to
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));
316 ast_unlock_context(c);
317 ast_unlock_contexts();
323 i = ast_walk_context_includes(c, i);
325 ast_unlock_context(c);
326 c = ast_walk_contexts(c);
330 ast_unlock_contexts();
338 * REMOVE EXTENSION command stuff
340 static int handle_context_remove_extension(int fd, int argc, char *argv[])
342 int removing_priority = 0;
343 char *exten, *context;
345 if (argc != 4 && argc != 3) return RESULT_SHOWUSAGE;
348 * Priority input checking ...
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
357 if (strcmp("hint", c)) {
359 if (!isdigit(*c++)) {
360 ast_cli(fd, "Invalid priority '%s'\n", argv[3]);
361 return RESULT_FAILURE;
364 removing_priority = atoi(argv[3]);
366 removing_priority = PRIORITY_HINT;
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;
376 * Format exten@context checking ...
378 if (!(context = strchr(argv[2], (int)'@'))) {
379 ast_cli(fd, "First argument must be in exten@context format\n");
380 return RESULT_FAILURE;
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;
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",
396 ast_cli(fd, "Extension %s@%s with priority %d removed\n",
397 exten, context, removing_priority);
399 return RESULT_SUCCESS;
402 ast_cli(fd, "Failed to remove extension %s@%s\n", exten, context);
404 return RESULT_FAILURE;
407 #define BROKEN_READLINE 1
409 #ifdef BROKEN_READLINE
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
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
419 * It's ugly, I know, but I'm waiting for Mark suggestion if upper is
422 static int fix_complete_args(char *line, char **word, int *pos)
424 char *_line, *_strsep_line, *_previous_word = NULL, *_word = NULL;
427 _line = strdup(line);
429 _strsep_line = _line;
430 while (_strsep_line) {
431 _previous_word = _word;
432 _word = strsep(&_strsep_line, " ");
434 if (_word && strlen(_word)) words++;
438 if (_word || _previous_word) {
440 if (!strlen(_word)) words++;
441 *word = strdup(_word);
443 *word = strdup(_previous_word);
452 #endif /* BROKEN_READLINE */
454 static char *complete_context_remove_extension(char *line, char *word, int pos,
460 #ifdef BROKEN_READLINE
462 * Fix arguments, *word is a new allocated structure, REMEMBER to
463 * free *word when you want to return from this function ...
465 if (fix_complete_args(line, &word, &pos)) {
466 ast_log(LOG_ERROR, "Out of free memory\n");
472 * exten@context completion ...
475 struct ast_context *c;
477 char *context = NULL, *exten = NULL, *delim = NULL;
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
490 exten = strdup(word);
491 context = strdup(delim + 1);
494 exten = strdup(word);
496 #ifdef BROKEN_READLINE
500 if (ast_lock_contexts()) {
501 ast_log(LOG_ERROR, "Failed to lock context list\n");
502 free(context); free(exten);
506 /* find our context ... */
507 c = ast_walk_contexts(NULL);
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);
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 ...
525 ret = malloc(strlen(ast_get_extension_name(e)) +
526 strlen(ast_get_context_name(c)) + 2);
528 sprintf(ret, "%s@%s", ast_get_extension_name(e),
529 ast_get_context_name(c));
531 ret = strdup(ast_get_context_name(c));
533 free(exten); free(context);
535 ast_unlock_contexts();
540 e = ast_walk_context_extensions(c, e);
543 c = ast_walk_contexts(c);
546 ast_unlock_contexts();
548 free(exten); free(context);
554 * Complete priority ...
557 char *delim, *exten, *context, *dupline, *duplinet, *ec;
558 struct ast_context *c;
560 dupline = strdup(line);
562 #ifdef BROKEN_READLINE
569 strsep(&duplinet, " "); /* skip 'remove' */
570 strsep(&duplinet, " "); /* skip 'extension */
572 if (!(ec = strsep(&duplinet, " "))) {
574 #ifdef BROKEN_READLINE
580 /* wrong exten@context format? */
581 if (!(delim = strchr(ec, (int)'@')) ||
582 (strchr(ec, (int)'@') != strrchr(ec, (int)'@'))) {
583 #ifdef BROKEN_READLINE
590 /* check if there is exten and context too ... */
592 if ((!strlen(ec)) || (!strlen(delim + 1))) {
593 #ifdef BROKEN_READLINE
601 context = strdup(delim + 1);
604 if (ast_lock_contexts()) {
605 ast_log(LOG_ERROR, "Failed to lock context list\n");
606 #ifdef BROKEN_READLINE
609 free(exten); free(context);
614 c = ast_walk_contexts(NULL);
616 if (!strcmp(ast_get_context_name(c), context)) {
619 /* walk extensions */
621 e = ast_walk_context_extensions(c, NULL);
623 if (!strcmp(ast_get_extension_name(e), exten)) {
624 struct ast_exten *priority;
628 priority = ast_walk_extension_priorities(e, NULL);
629 /* serve priorities */
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
638 ast_unlock_contexts();
639 return strdup(buffer);
642 priority = ast_walk_extension_priorities(e,
646 #ifdef BROKEN_READLINE
649 ast_unlock_contexts();
652 e = ast_walk_context_extensions(c, e);
654 #ifdef BROKEN_READLINE
658 ast_unlock_contexts();
661 c = ast_walk_contexts(c);
664 #ifdef BROKEN_READLINE
667 free(exten); free(context);
669 ast_unlock_contexts();
673 #ifdef BROKEN_READLINE
680 * Include context ...
682 static int handle_context_add_include(int fd, int argc, char *argv[])
684 if (argc != 4) return RESULT_SHOWUSAGE;
686 /* third arg must be 'in' ... */
687 if (strcmp(argv[2], "in")) return RESULT_SHOWUSAGE;
689 if (ast_context_add_include(argv[3], argv[1], registrar)) {
692 ast_cli(fd, "Out of memory for context addition\n"); break;
695 ast_cli(fd, "Failed to lock context(s) list, please try again later\n"); break;
698 ast_cli(fd, "Context '%s' already included in '%s' context\n",
699 argv[1], argv[3]); break;
703 ast_cli(fd, "There is no existence of context '%s'\n",
704 errno == ENOENT ? argv[3] : argv[1]); break;
707 ast_cli(fd, "Failed to include '%s' in '%s' context\n",
708 argv[1], argv[3]); break;
710 return RESULT_FAILURE;
713 /* show some info ... */
714 ast_cli(fd, "Context '%s' included in '%s' context\n",
717 return RESULT_SUCCESS;
720 static char *complete_context_add_include(char *line, char *word, int pos,
723 struct ast_context *c;
726 /* server context for inclusion ... */
729 if (ast_lock_contexts()) {
730 ast_log(LOG_ERROR, "Failed to lock context list\n");
734 /* server all contexts */
735 c = ast_walk_contexts(NULL);
737 if ((!strlen(word) ||
738 !strncmp(ast_get_context_name(c), word, strlen(word))) &&
741 char *context = strdup(ast_get_context_name(c));
742 ast_unlock_contexts();
745 c = ast_walk_contexts(c);
748 ast_unlock_contexts();
751 /* complete 'in' only if context exist ... */
754 char *context, *dupline, *duplinet;
756 if (state != 0) return NULL;
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");
767 strsep(&duplinet, " ");
768 context = strsep(&duplinet, " ");
770 struct ast_context *c;
771 int context_existence = 0;
773 /* check for context existence ... */
774 if (ast_lock_contexts()) {
775 ast_log(LOG_ERROR, "Failed to lock context list\n");
777 /* our fault, we can't check, so complete 'in' ... */
781 c = ast_walk_contexts(NULL);
782 while (c && !context_existence) {
783 if (!strcmp(context, ast_get_context_name(c))) {
784 context_existence = 1;
787 c = ast_walk_contexts(c);
790 /* if context exists, return 'into' ... */
791 if (context_existence) {
793 ast_unlock_contexts();
794 return strdup("into");
797 ast_unlock_contexts();
804 /* serve context into which we include another context */
807 char *context, *dupline, *duplinet, *in;
808 int context_existence = 0;
810 if (!(dupline = strdup(line))) {
811 ast_log(LOG_ERROR, "Out of free memory\n");
817 strsep(&duplinet, " "); /* skip 'include' */
818 context = strsep(&duplinet, " ");
819 in = strsep(&duplinet, " ");
821 /* given some context and third word is in? */
822 if (!strlen(context) || strcmp(in, "in")) {
827 if (ast_lock_contexts()) {
828 ast_log(LOG_ERROR, "Failed to lock context list\n");
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;
840 c = ast_walk_contexts(c);
843 if (!context_existence) {
845 ast_unlock_contexts();
849 /* go through all contexts ... */
850 c = ast_walk_contexts(NULL);
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;
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))
863 i = ast_walk_context_includes(c, i);
865 ast_unlock_context(c);
867 /* not included yet, so show possibility ... */
869 !strncmp(ast_get_context_name(c), word, strlen(word))){
871 if (++which > state) {
872 char *res = strdup(ast_get_context_name(c));
874 ast_unlock_contexts();
880 c = ast_walk_contexts(c);
883 ast_unlock_contexts();
892 * 'save dialplan' CLI command implementation functions ...
894 static int handle_save_dialplan(int fd, int argc, char *argv[])
897 struct ast_context *c;
898 int context_header_written;
899 int incomplete = 0; /* incomplete config write? */
902 if (! (static_config && !write_protect_config)) {
904 "I can't save dialplan now, see '%s' example file.\n",
906 return RESULT_FAILURE;
909 if (argc != 2 && argc != 3) return RESULT_SHOWUSAGE;
911 if (ast_pthread_mutex_lock(&save_dialplan_lock)) {
913 "Failed to lock dialplan saving (another proccess saving?)\n");
914 return RESULT_FAILURE;
917 /* have config path? */
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",
926 /* without config extensions.conf, add it */
927 snprintf(filename, sizeof(filename), "%s/%s",
930 /* there is an .conf */
931 snprintf(filename, sizeof(filename), argv[2]);
933 /* no config file, default one */
934 snprintf(filename, sizeof(filename), "%s/%s",
935 (char *)ast_config_AST_CONFIG_DIR, config);
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;
944 /* create new file ... */
945 if (!(output = fopen(filename, "wt"))) {
946 ast_cli(fd, "Failed to create file '%s'\n",
948 ast_unlock_contexts();
949 ast_pthread_mutex_unlock(&save_dialplan_lock);
950 return RESULT_FAILURE;
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");
958 /* walk all contexts */
959 c = ast_walk_contexts(NULL);
961 context_header_written = 0;
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;
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;
975 /* walk extensions ... */
976 e = ast_walk_context_extensions(c, NULL);
980 /* fireout priorities */
981 p = ast_walk_extension_priorities(e, NULL);
983 if (!strcmp(ast_get_extension_registrar(p),
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");
993 if (!context_header_written) {
994 fprintf(output, "[%s]\n", ast_get_context_name(c));
995 context_header_written = 1;
998 if (ast_get_extension_priority(p)!=PRIORITY_HINT) {
999 char *tempdata = NULL, *startdata;
1000 tempdata = strdup((char *)ast_get_extension_app_data(p));
1002 startdata = tempdata;
1004 if (*tempdata == '|')
1008 tempdata = startdata;
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),
1018 fprintf(output, "exten => %s,hint,%s\n",
1019 ast_get_extension_name(p),
1020 ast_get_extension_app(p));
1023 p = ast_walk_extension_priorities(e, p);
1026 e = ast_walk_context_extensions(c, e);
1029 /* written any extensions? ok, write space between exten & inc */
1030 if (last_written_e) fprintf(output, "\n");
1032 /* walk through includes */
1033 i = ast_walk_context_includes(c, NULL);
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;
1040 fprintf(output, "include => %s\n",
1041 ast_get_include_name(i));
1043 i = ast_walk_context_includes(c, i);
1046 if (ast_walk_context_includes(c, NULL))
1047 fprintf(output, "\n");
1049 /* fireout ignorepats ... */
1050 ip = ast_walk_context_ignorepats(c, NULL);
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;
1058 fprintf(output, "ignorepat => %s\n",
1059 ast_get_ignorepat_name(ip));
1061 ip = ast_walk_context_ignorepats(c, ip);
1064 ast_unlock_context(c);
1068 c = ast_walk_contexts(c);
1071 ast_unlock_contexts();
1072 ast_pthread_mutex_unlock(&save_dialplan_lock);
1076 ast_cli(fd, "Saved dialplan is incomplete\n");
1077 return RESULT_FAILURE;
1080 ast_cli(fd, "Dialplane successfully saved into '%s'\n",
1082 return RESULT_SUCCESS;
1086 * ADD EXTENSION command stuff
1088 static int handle_context_add_extension(int fd, int argc, char *argv[])
1091 char *exten, *prior;
1093 char *cidmatch, *app, *app_data;
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;
1101 whole_exten = argv[2];
1102 exten = strsep(&whole_exten,",");
1103 if (strchr(exten, '/')) {
1105 strsep(&cidmatch,"/");
1109 prior = strsep(&whole_exten,",");
1111 if (!strcmp(prior, "hint")) {
1112 iprior = PRIORITY_HINT;
1114 iprior = atoi(prior);
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++)
1125 app_data = whole_exten;
1127 if (!exten || !prior || !app || (!app_data && iprior != PRIORITY_HINT)) return RESULT_SHOWUSAGE;
1131 if (ast_add_extension(argv[4], argc == 6 ? 1 : 0, exten, iprior, cidmatch, app,
1132 (void *)strdup(app_data), free, registrar)) {
1135 ast_cli(fd, "Out of free memory\n"); break;
1138 ast_cli(fd, "Failed to lock context(s) list, please try again later\n"); break;
1141 ast_cli(fd, "No existence of '%s' context\n", argv[4]); break;
1144 ast_cli(fd, "Extension %s@%s with priority %s already exists\n",
1145 exten, argv[4], prior); break;
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;
1151 return RESULT_FAILURE;
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);
1158 ast_cli(fd, "Extension '%s,%s,%s,%s' added into '%s' context\n",
1159 exten, prior, app, app_data, argv[4]);
1161 return RESULT_SUCCESS;
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,
1170 /* complete 'into' word ... */
1172 if (state == 0) return strdup("into");
1176 /* complete context */
1178 struct ast_context *c;
1180 /* try to lock contexts list ... */
1181 if (ast_lock_contexts()) {
1182 ast_log(LOG_WARNING, "Failed to lock contexts list\n");
1186 /* walk through all contexts */
1187 c = ast_walk_contexts(NULL);
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();
1197 c = ast_walk_contexts(c);
1200 ast_unlock_contexts();
1204 if (pos == 5) return state == 0 ? strdup("replace") : NULL;
1210 * IGNOREPAT CLI stuff
1212 static int handle_context_add_ignorepat(int fd, int argc, char *argv[])
1214 if (argc != 5) return RESULT_SHOWUSAGE;
1215 if (strcmp(argv[3], "into")) return RESULT_SHOWUSAGE;
1217 if (ast_context_add_ignorepat(argv[4], argv[2], registrar)) {
1220 ast_cli(fd, "Out of free memory\n"); break;
1223 ast_cli(fd, "There is no existence of '%s' context\n", argv[4]);
1227 ast_cli(fd, "Ignore pattern '%s' already included in '%s' context\n",
1232 ast_cli(fd, "Failed to lock context(s) list, please, try again later\n");
1236 ast_cli(fd, "Failed to add ingore pattern '%s' into '%s' context\n",
1240 return RESULT_FAILURE;
1243 ast_cli(fd, "Ignore pattern '%s' added into '%s' context\n",
1245 return RESULT_SUCCESS;
1248 static char *complete_context_add_ignorepat(char *line, char *word,
1251 if (pos == 3) return state == 0 ? strdup("into") : NULL;
1254 struct ast_context *c;
1256 char *dupline, *duplinet, *ignorepat = NULL;
1258 dupline = strdup(line);
1262 strsep(&duplinet, " "); /* skip 'add' */
1263 strsep(&duplinet, " "); /* skip 'ignorepat' */
1264 ignorepat = strsep(&duplinet, " ");
1267 if (ast_lock_contexts()) {
1268 ast_log(LOG_ERROR, "Failed to lock contexts list\n");
1272 c = ast_walk_contexts(NULL);
1274 if (!strncmp(ast_get_context_name(c), word, strlen(word))) {
1275 int serve_context = 1;
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))
1283 ip = ast_walk_context_ignorepats(c, ip);
1285 ast_unlock_context(c);
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();
1297 c = ast_walk_contexts(c);
1300 if (dupline) free(dupline);
1301 ast_unlock_contexts();
1308 static int handle_context_remove_ignorepat(int fd, int argc, char *argv[])
1310 if (argc != 5) return RESULT_SHOWUSAGE;
1311 if (strcmp(argv[3], "from")) return RESULT_SHOWUSAGE;
1313 if (ast_context_remove_ignorepat(argv[4], argv[2], registrar)) {
1316 ast_cli(fd, "Failed to lock context(s) list, please try again later\n");
1320 ast_cli(fd, "There is no existence of '%s' context\n", argv[4]);
1324 ast_cli(fd, "There is no existence of '%s' ignore pattern in '%s' context\n",
1329 ast_cli(fd, "Failed to remove ignore pattern '%s' from '%s' context\n");
1332 return RESULT_FAILURE;
1335 ast_cli(fd, "Ignore pattern '%s' removed from '%s' context\n",
1337 return RESULT_SUCCESS;
1340 static char *complete_context_remove_ignorepat(char *line, char *word,
1343 struct ast_context *c;
1347 if (ast_lock_contexts()) {
1348 ast_log(LOG_WARNING, "Failed to lock contexts list\n");
1352 c = ast_walk_contexts(NULL);
1354 if (!ast_lock_context(c)) {
1355 struct ast_ignorepat *ip;
1357 ip = ast_walk_context_ignorepats(c, NULL);
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);
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);
1373 ast_unlock_context(cw);
1375 cw = ast_walk_contexts(cw);
1377 if (!already_served) {
1378 char *ret = strdup(ast_get_ignorepat_name(ip));
1379 ast_unlock_context(c);
1380 ast_unlock_contexts();
1386 ip = ast_walk_context_ignorepats(c, ip);
1389 ast_unlock_context(c);
1391 c = ast_walk_contexts(c);
1394 ast_unlock_contexts();
1398 if (pos == 3) return state == 0 ? strdup("from") : NULL;
1401 char *dupline, *duplinet, *ignorepat;
1403 dupline = strdup(line);
1405 ast_log(LOG_WARNING, "Out of free memory\n");
1410 strsep(&duplinet, " ");
1411 strsep(&duplinet, " ");
1412 ignorepat = strsep(&duplinet, " ");
1419 if (ast_lock_contexts()) {
1420 ast_log(LOG_WARNING, "Failed to lock contexts list\n");
1425 c = ast_walk_contexts(NULL);
1427 if (!ast_lock_context(c)) {
1428 struct ast_ignorepat *ip;
1429 ip = ast_walk_context_ignorepats(c, NULL);
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));
1436 ast_unlock_context(c);
1437 ast_unlock_contexts();
1442 ip = ast_walk_context_ignorepats(c, ip);
1445 ast_unlock_context(c);
1447 c = ast_walk_contexts(c);
1451 ast_unlock_contexts();
1459 * CLI entries for commands provided by this module
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 };
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 };
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 };
1476 static struct ast_cli_entry save_dialplan_cli =
1477 { { "save", "dialplan", NULL }, handle_save_dialplan,
1478 "Save dialplan", save_dialplan_help };
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 };
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 };
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 };
1496 * Standard module functions ...
1498 int unload_module(void)
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);
1512 static int pbx_load_module(void)
1514 struct ast_config *cfg;
1515 struct ast_variable *v;
1516 char *cxt, *ext, *pri, *appl, *data, *tc, *cidmatch;
1517 struct ast_context *con;
1520 cfg = ast_load(config);
1522 /* Use existing config to populate the PBX table */
1523 static_config = ast_true(ast_variable_retrieve(cfg, "general",
1525 write_protect_config = ast_true(ast_variable_retrieve(cfg, "general",
1527 v = ast_variable_browse(cfg, "globals");
1529 pbx_builtin_setvar_helper(NULL, v->name, v->value);
1532 cxt = ast_category_browse(cfg, NULL);
1534 /* All categories but "general" are considered contexts */
1535 if (!strcasecmp(cxt, "general") || !strcasecmp(cxt, "globals")) {
1536 cxt = ast_category_browse(cfg, cxt);
1539 if ((con=ast_context_create(cxt, registrar))) {
1540 v = ast_variable_browse(cfg, cxt);
1542 if (!strcasecmp(v->name, "exten")) {
1545 tc = strdup(v->value);
1548 ext = strsep(&stringp, ",");
1551 pri = strsep(&stringp, ",");
1554 if (!strcmp(pri,"hint"))
1561 if (!(start = strchr(appl, '('))) {
1563 appl = strsep(&stringp, ",");
1567 if (start && (end = strrchr(appl, ')'))) {
1568 *start = *end = '\0';
1570 for (start = data; *start; start++)
1573 } else if (stringp!=NULL && *stringp=='"') {
1575 data = strsep(&stringp, "\"");
1579 data = strsep(&stringp, ",");
1583 cidmatch = strchr(ext, '/');
1589 strsep(&stringp, "/");
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);
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")) {
1606 tc = strdup(v->value);
1608 appl = strsep(&stringp, "/");
1609 data = strsep(&stringp, "");
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);
1618 cxt = ast_category_browse(cfg, cxt);
1625 int load_module(void)
1627 if (pbx_load_module()) return -1;
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);
1643 ast_context_destroy(NULL, registrar);
1644 /* For martin's global variables, don't clear them on reload */
1646 pbx_builtin_clear_globals();
1657 char *description(void)
1664 return ASTERISK_GPL_KEY;