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 <asterisk/pbx.h>
15 #include <asterisk/config.h>
16 #include <asterisk/module.h>
17 #include <asterisk/logger.h>
18 #include <asterisk/cli.h>
24 /* For where to put dynamic tables */
25 #include "../asterisk.h"
26 #include "../astconf.h"
28 static char *dtext = "Text Extension Configuration";
29 static char *config = "extensions.conf";
30 static char *registrar = "pbx_config";
32 static int static_config = 0;
33 static int write_protect_config = 1;
35 static pthread_mutex_t save_dialplan_lock = AST_MUTEX_INITIALIZER;
38 * Help for commands provided by this module ...
40 static char context_dont_include_help[] =
41 "Usage: dont include context in include\n"
42 " Remove include from context.\n";
44 static char context_remove_extension_help[] =
45 "Usage: remove extension exten@context [priority]\n"
46 " Remove whole extension from context. If priority is set, we are only\n"
47 " removing extension with given priority.\n";
49 static char context_add_include_help[] =
50 "Usage: include context in context\n"
51 " Include context in other context.\n";
53 static char save_dialplan_help[] =
54 "Usage: save dialplan [/path/to/extension/file]\n"
55 " Save dialplan created by pbx_config module.\n"
57 "Example: save dialplan (/etc/asterisk/extensions.conf)\n"
58 " save dialplan /home/markster (/home/markster/extensions.conf)\n";
60 static char context_add_extension_help[] =
61 "Usage: add extension <exten>,<priority>,<app>,<app-data> into <context>\n"
63 " This command will add new extension into <context>. If there is an\n"
64 " existence of extension with the same priority and last 'replace'\n"
65 " arguments is given here we simply replace this extension.\n"
67 "Example: add extension 6123,1,Dial,IAX/216.207.245.56/6123 into local\n"
68 " Now, you can dial 6123 and talk to Markster :)\n";
70 static char context_add_ignorepat_help[] =
71 "Usage: add ignorepat <pattern> into <context>\n"
72 " This command add new ignore pattern into context <context>\n"
74 "Example: add ignorepat _3XX into local\n";
76 static char context_remove_ignorepat_help[] =
77 "Usage: remove ignorepat <pattern> from <context>\n"
78 " This command remove ignore pattern from context <context>\n"
80 "Example: remove ignorepat _3XX from local\n";
83 * Implementation of functions provided by this module
87 * REMOVE INCLUDE command stuff
89 static int handle_context_dont_include(int fd, int argc, char *argv[])
91 if (argc != 5) return RESULT_SHOWUSAGE;
93 if (strcmp(argv[3], "in")) return RESULT_SHOWUSAGE;
95 if (!ast_context_remove_include(argv[4], argv[2], registrar)) {
96 ast_cli(fd, "We are not including '%s' in '%s' now\n",
98 return RESULT_SUCCESS;
101 ast_cli(fd, "Failed to remove '%s' include from '%s' context\n",
103 return RESULT_FAILURE;
106 static char *complete_context_dont_include(char *line, char *word,
112 * Context completion ...
115 struct ast_context *c;
117 if (ast_lock_contexts()) {
118 ast_log(LOG_ERROR, "Failed to lock context list\n");
122 /* walk pbx_get_contexts ... */
123 c = ast_walk_contexts(NULL);
125 struct ast_include *i;
127 if (ast_lock_context(c)) {
128 c = ast_walk_contexts(c);
132 i = ast_walk_context_includes(c, NULL);
135 !strncmp(ast_get_include_name(i), word, strlen(word))) {
136 struct ast_context *nc;
137 int already_served = 0;
139 /* check if this include is already served or not */
141 /* go through all contexts again till we reach actuall
142 * context or already_served = 1
144 nc = ast_walk_contexts(NULL);
145 while (nc && nc != c && !already_served) {
146 if (!ast_lock_context(nc)) {
147 struct ast_include *ni;
149 ni = ast_walk_context_includes(nc, NULL);
150 while (ni && !already_served) {
151 if (!strcmp(ast_get_include_name(i),
152 ast_get_include_name(ni)))
154 ni = ast_walk_context_includes(nc, ni);
157 ast_unlock_context(nc);
159 nc = ast_walk_contexts(nc);
162 if (!already_served) {
163 if (++which > state) {
165 strdup(ast_get_include_name(i));
166 ast_unlock_context(c);
167 ast_unlock_contexts();
172 i = ast_walk_context_includes(c, i);
175 ast_unlock_context(c);
176 c = ast_walk_contexts(c);
179 ast_unlock_contexts();
184 * 'in' completion ... (complete only if previous context is really
185 * included somewhere)
188 struct ast_context *c;
189 char *context, *dupline, *duplinet;
191 if (state > 0) return NULL;
193 /* take 'context' from line ... */
194 if (!(dupline = strdup(line))) {
195 ast_log(LOG_ERROR, "Out of free memory\n");
200 strsep(&duplinet, " "); /* skip 'dont' */
201 strsep(&duplinet, " "); /* skip 'include' */
202 context = strsep(&duplinet, " ");
209 if (ast_lock_contexts()) {
210 ast_log(LOG_WARNING, "Failed to lock contexts list\n");
215 /* go through all contexts and check if is included ... */
216 c = ast_walk_contexts(NULL);
218 struct ast_include *i;
219 if (ast_lock_context(c)) {
221 ast_unlock_contexts();
225 i = ast_walk_context_includes(c, NULL);
227 /* is it our context? */
228 if (!strcmp(ast_get_include_name(i), context)) {
229 /* yes, it is, context is really included, so
230 * complete "in" command
233 ast_unlock_context(c);
234 ast_unlock_contexts();
237 i = ast_walk_context_includes(c, i);
239 ast_unlock_context(c);
240 c = ast_walk_contexts(c);
243 ast_unlock_contexts();
248 * Context from which we removing include ...
251 struct ast_context *c;
252 char *context, *dupline, *duplinet, *in;
254 if (!(dupline = strdup(line))) {
255 ast_log(LOG_ERROR, "Out of free memory\n");
261 strsep(&duplinet, " "); /* skip 'dont' */
262 strsep(&duplinet, " "); /* skip 'include' */
264 if (!(context = strsep(&duplinet, " "))) {
269 /* third word must be in */
270 in = strsep(&duplinet, " ");
277 if (ast_lock_contexts()) {
278 ast_log(LOG_ERROR, "Failed to lock context list\n");
283 /* walk through all contexts ... */
284 c = ast_walk_contexts(NULL);
286 struct ast_include *i;
287 if (ast_lock_context(c)) {
292 /* walk through all includes and check if it is our context */
293 i = ast_walk_context_includes(c, NULL);
295 /* is in this context included another on which we want to
298 if (!strcmp(context, ast_get_include_name(i))) {
299 /* yes, it's included, is matching our word too? */
300 if (!strncmp(ast_get_context_name(c),
301 word, strlen(word))) {
302 /* check state for completion */
303 if (++which > state) {
304 char *res = strdup(ast_get_context_name(c));
306 ast_unlock_context(c);
307 ast_unlock_contexts();
313 i = ast_walk_context_includes(c, i);
315 ast_unlock_context(c);
316 c = ast_walk_contexts(c);
320 ast_unlock_contexts();
328 * REMOVE EXTENSION command stuff
330 static int handle_context_remove_extension(int fd, int argc, char *argv[])
332 int removing_priority = 0;
333 char *exten, *context;
335 if (argc != 4 && argc != 3) return RESULT_SHOWUSAGE;
338 * Priority input checking ...
343 /* check for digits in whole parameter for right priority ...
344 * why? because atoi (strtol) returns 0 if any characters in
345 * string and whole extension will be removed, it's not good
347 if (strcmp("hint", c)) {
349 if (!isdigit(*c++)) {
350 ast_cli(fd, "Invalid priority '%s'\n", argv[3]);
351 return RESULT_FAILURE;
354 removing_priority = atoi(argv[3]);
356 removing_priority = PRIORITY_HINT;
358 if (removing_priority == 0) {
359 ast_cli(fd, "If you want to remove whole extension, please " \
360 "omit priority argument\n");
361 return RESULT_FAILURE;
366 * Format exten@context checking ...
368 if (!(context = strchr(argv[2], (int)'@'))) {
369 ast_cli(fd, "First argument must be in exten@context format\n");
370 return RESULT_FAILURE;
375 if ((!strlen(exten)) || (!(strlen(context)))) {
376 ast_cli(fd, "Missing extension or context name in second argument '%s@%s'\n",
377 exten == NULL ? "?" : exten, context == NULL ? "?" : context);
378 return RESULT_FAILURE;
381 if (!ast_context_remove_extension(context, exten, removing_priority, registrar)) {
382 if (!removing_priority)
383 ast_cli(fd, "Whole extension %s@%s removed\n",
386 ast_cli(fd, "Extension %s@%s with priority %d removed\n",
387 exten, context, removing_priority);
389 return RESULT_SUCCESS;
392 ast_cli(fd, "Failed to remove extension %s@%s\n", exten, context);
394 return RESULT_FAILURE;
397 #define BROKEN_READLINE 1
399 #ifdef BROKEN_READLINE
401 * There is one funny thing, when you have word like 300@ and you hit
402 * <tab>, you arguments will like as your word is '300 ', so it '@'
403 * characters acts sometimes as word delimiter and sometimes as a part
406 * This fix function, allocates new word variable and store here every
407 * time xxx@yyy always as one word and correct pos is set too
409 * It's ugly, I know, but I'm waiting for Mark suggestion if upper is
412 static int fix_complete_args(char *line, char **word, int *pos)
414 char *_line, *_strsep_line, *_previous_word = NULL, *_word = NULL;
417 _line = strdup(line);
419 _strsep_line = _line;
420 while (_strsep_line) {
421 _previous_word = _word;
422 _word = strsep(&_strsep_line, " ");
424 if (_word && strlen(_word)) words++;
428 if (_word || _previous_word) {
430 if (!strlen(_word)) words++;
431 *word = strdup(_word);
433 *word = strdup(_previous_word);
442 #endif /* BROKEN_READLINE */
444 static char *complete_context_remove_extension(char *line, char *word, int pos,
450 #ifdef BROKEN_READLINE
452 * Fix arguments, *word is a new allocated structure, REMEMBER to
453 * free *word when you want to return from this function ...
455 if (fix_complete_args(line, &word, &pos)) {
456 ast_log(LOG_ERROR, "Out of free memory\n");
462 * exten@context completion ...
465 struct ast_context *c;
467 char *context = NULL, *exten = NULL, *delim = NULL;
469 /* now, parse values from word = exten@context */
470 if ((delim = strchr(word, (int)'@'))) {
471 /* check for duplicity ... */
472 if (delim != strrchr(word, (int)'@')) {
473 #ifdef BROKEN_READLINE
480 exten = strdup(word);
481 context = strdup(delim + 1);
484 exten = strdup(word);
486 #ifdef BROKEN_READLINE
490 if (ast_lock_contexts()) {
491 ast_log(LOG_ERROR, "Failed to lock context list\n");
492 free(context); free(exten);
496 /* find our context ... */
497 c = ast_walk_contexts(NULL);
500 if ( (!context || !strlen(context)) || /* if no input, all contexts ... */
501 (context && !strncmp(ast_get_context_name(c),
502 context, strlen(context))) ) { /* if input, compare ... */
503 /* try to complete extensions ... */
504 e = ast_walk_context_extensions(c, NULL);
507 if ( (!exten || !strlen(exten)) || /* if not input, all extensions ... */
508 (exten && !strncmp(ast_get_extension_name(e), exten,
509 strlen(exten))) ) { /* if input, compare ... */
510 if (++which > state) {
511 /* is there some context input? if not, throw back
512 * exten@context, if yes throw back only context ...
515 ret = malloc(strlen(ast_get_extension_name(e)) +
516 strlen(ast_get_context_name(c)) + 2);
518 sprintf(ret, "%s@%s", ast_get_extension_name(e),
519 ast_get_context_name(c));
521 ret = strdup(ast_get_context_name(c));
523 free(exten); free(context);
525 ast_unlock_contexts();
530 e = ast_walk_context_extensions(c, e);
533 c = ast_walk_contexts(c);
536 ast_unlock_contexts();
538 free(exten); free(context);
544 * Complete priority ...
547 char *delim, *exten, *context, *dupline, *duplinet, *ec;
548 struct ast_context *c;
550 dupline = strdup(line);
552 #ifdef BROKEN_READLINE
559 strsep(&duplinet, " "); /* skip 'remove' */
560 strsep(&duplinet, " "); /* skip 'extension */
562 if (!(ec = strsep(&duplinet, " "))) {
564 #ifdef BROKEN_READLINE
570 /* wrong exten@context format? */
571 if (!(delim = strchr(ec, (int)'@')) ||
572 (strchr(ec, (int)'@') != strrchr(ec, (int)'@'))) {
573 #ifdef BROKEN_READLINE
580 /* check if there is exten and context too ... */
582 if ((!strlen(ec)) || (!strlen(delim + 1))) {
583 #ifdef BROKEN_READLINE
591 context = strdup(delim + 1);
594 if (ast_lock_contexts()) {
595 ast_log(LOG_ERROR, "Failed to lock context list\n");
596 #ifdef BROKEN_READLINE
599 free(exten); free(context);
604 c = ast_walk_contexts(NULL);
606 if (!strcmp(ast_get_context_name(c), context)) {
609 /* walk extensions */
611 e = ast_walk_context_extensions(c, NULL);
613 if (!strcmp(ast_get_extension_name(e), exten)) {
614 struct ast_exten *priority;
618 priority = ast_walk_extension_priorities(e, NULL);
619 /* serve priorities */
621 snprintf(buffer, 10, "%u",
622 ast_get_extension_priority(priority));
623 if (!strncmp(word, buffer, strlen(word))) {
624 if (++which > state) {
625 #ifdef BROKEN_READLINE
628 ast_unlock_contexts();
629 return strdup(buffer);
632 priority = ast_walk_extension_priorities(e,
636 #ifdef BROKEN_READLINE
639 ast_unlock_contexts();
642 e = ast_walk_context_extensions(c, e);
644 #ifdef BROKEN_READLINE
648 ast_unlock_contexts();
651 c = ast_walk_contexts(c);
654 #ifdef BROKEN_READLINE
657 free(exten); free(context);
659 ast_unlock_contexts();
663 #ifdef BROKEN_READLINE
670 * Include context ...
672 static int handle_context_add_include(int fd, int argc, char *argv[])
674 if (argc != 4) return RESULT_SHOWUSAGE;
676 /* third arg must be 'in' ... */
677 if (strcmp(argv[2], "in")) return RESULT_SHOWUSAGE;
679 if (ast_context_add_include(argv[3], argv[1], registrar)) {
682 ast_cli(fd, "Out of memory for context addition\n"); break;
685 ast_cli(fd, "Failed to lock context(s) list, please try again later\n"); break;
688 ast_cli(fd, "Context '%s' already included in '%s' context\n",
689 argv[1], argv[3]); break;
693 ast_cli(fd, "There is no existence of context '%s'\n",
694 errno == ENODATA ? argv[3] : argv[1]); break;
697 ast_cli(fd, "Failed to include '%s' in '%s' context\n",
698 argv[1], argv[3]); break;
700 return RESULT_FAILURE;
703 /* show some info ... */
704 ast_cli(fd, "Context '%s' included in '%s' context\n",
707 return RESULT_SUCCESS;
710 static char *complete_context_add_include(char *line, char *word, int pos,
713 struct ast_context *c;
716 /* server context for inclusion ... */
719 if (ast_lock_contexts()) {
720 ast_log(LOG_ERROR, "Failed to lock context list\n");
724 /* server all contexts */
725 c = ast_walk_contexts(NULL);
727 if ((!strlen(word) ||
728 !strncmp(ast_get_context_name(c), word, strlen(word))) &&
731 char *context = strdup(ast_get_context_name(c));
732 ast_unlock_contexts();
735 c = ast_walk_contexts(c);
738 ast_unlock_contexts();
741 /* complete 'in' only if context exist ... */
744 char *context, *dupline, *duplinet;
746 if (state != 0) return NULL;
748 /* parse context from line ... */
749 if (!(dupline = strdup(line))) {
750 ast_log(LOG_ERROR, "Out of free memory\n");
751 if (state == 0) return strdup("in");
757 strsep(&duplinet, " ");
758 context = strsep(&duplinet, " ");
760 struct ast_context *c;
761 int context_existence = 0;
763 /* check for context existence ... */
764 if (ast_lock_contexts()) {
765 ast_log(LOG_ERROR, "Failed to lock context list\n");
767 /* our fault, we can't check, so complete 'in' ... */
771 c = ast_walk_contexts(NULL);
772 while (c && !context_existence) {
773 if (!strcmp(context, ast_get_context_name(c))) {
774 context_existence = 1;
777 c = ast_walk_contexts(c);
780 /* if context exists, return 'into' ... */
781 if (context_existence) {
783 ast_unlock_contexts();
784 return strdup("into");
787 ast_unlock_contexts();
794 /* serve context into which we include another context */
797 char *context, *dupline, *duplinet, *in;
798 int context_existence = 0;
800 if (!(dupline = strdup(line))) {
801 ast_log(LOG_ERROR, "Out of free memory\n");
807 strsep(&duplinet, " "); /* skip 'include' */
808 context = strsep(&duplinet, " ");
809 in = strsep(&duplinet, " ");
811 /* given some context and third word is in? */
812 if (!strlen(context) || strcmp(in, "in")) {
817 if (ast_lock_contexts()) {
818 ast_log(LOG_ERROR, "Failed to lock context list\n");
823 /* check for context existence ... */
824 c = ast_walk_contexts(NULL);
825 while (c && !context_existence) {
826 if (!strcmp(context, ast_get_context_name(c))) {
827 context_existence = 1;
830 c = ast_walk_contexts(c);
833 if (!context_existence) {
835 ast_unlock_contexts();
839 /* go through all contexts ... */
840 c = ast_walk_contexts(NULL);
842 /* must be different contexts ... */
843 if (strcmp(context, ast_get_context_name(c))) {
844 if (!ast_lock_context(c)) {
845 struct ast_include *i;
848 /* check for duplicity inclusion ... */
849 i = ast_walk_context_includes(c, NULL);
850 while (i && !included) {
851 if (!strcmp(ast_get_include_name(i), context))
853 i = ast_walk_context_includes(c, i);
855 ast_unlock_context(c);
857 /* not included yet, so show possibility ... */
859 !strncmp(ast_get_context_name(c), word, strlen(word))){
861 if (++which > state) {
862 char *res = strdup(ast_get_context_name(c));
864 ast_unlock_contexts();
870 c = ast_walk_contexts(c);
873 ast_unlock_contexts();
882 * 'save dialplan' CLI command implementation functions ...
884 static int handle_save_dialplan(int fd, int argc, char *argv[])
887 struct ast_context *c;
888 int context_header_written;
889 int incomplete = 0; /* incomplete config write? */
892 if (! (static_config && !write_protect_config)) {
894 "I can't save dialplan now, see '%s' example file.\n",
896 return RESULT_FAILURE;
899 if (argc != 2 && argc != 3) return RESULT_SHOWUSAGE;
901 if (ast_pthread_mutex_lock(&save_dialplan_lock)) {
903 "Failed to lock dialplan saving (another proccess saving?)\n");
904 return RESULT_FAILURE;
907 /* have config path? */
909 /* is there extension.conf too? */
910 if (!strstr(argv[2], ".conf")) {
911 /* no, only directory path, check for last '/' occurence */
912 if (*(argv[2] + strlen(argv[2]) -1) == '/')
913 snprintf(filename, sizeof(filename), "%s%s",
916 /* without config extensions.conf, add it */
917 snprintf(filename, sizeof(filename), "%s/%s",
920 /* there is an .conf */
921 snprintf(filename, sizeof(filename), argv[2]);
923 /* no config file, default one */
924 snprintf(filename, sizeof(filename), "%s/%s",
925 (char *)ast_config_AST_CONFIG_DIR, config);
927 /* try to lock contexts list */
928 if (ast_lock_contexts()) {
929 ast_cli(fd, "Failed to lock contexts list\n");
930 ast_pthread_mutex_unlock(&save_dialplan_lock);
931 return RESULT_FAILURE;
934 /* create new file ... */
935 if (!(output = fopen(filename, "wt"))) {
936 ast_cli(fd, "Failed to create file '%s'\n",
938 ast_unlock_contexts();
939 ast_pthread_mutex_unlock(&save_dialplan_lock);
940 return RESULT_FAILURE;
943 /* fireout general info */
944 fprintf(output, "[general]\nstatic=%s\nwriteprotect=%s\n\n",
945 static_config ? "yes" : "no",
946 write_protect_config ? "yes" : "no");
948 /* walk all contexts */
949 c = ast_walk_contexts(NULL);
951 context_header_written = 0;
953 /* try to lock context and fireout all info */
954 if (!ast_lock_context(c)) {
955 struct ast_exten *e, *last_written_e = NULL;
956 struct ast_include *i;
957 struct ast_ignorepat *ip;
959 /* registered by this module? */
960 if (!strcmp(ast_get_context_registrar(c), registrar)) {
961 fprintf(output, "[%s]\n", ast_get_context_name(c));
962 context_header_written = 1;
965 /* walk extensions ... */
966 e = ast_walk_context_extensions(c, NULL);
970 /* fireout priorities */
971 p = ast_walk_extension_priorities(e, NULL);
973 if (!strcmp(ast_get_extension_registrar(p),
976 /* make empty line between different extensions */
977 if (last_written_e != NULL &&
978 strcmp(ast_get_extension_name(last_written_e),
979 ast_get_extension_name(p)))
980 fprintf(output, "\n");
983 if (!context_header_written) {
984 fprintf(output, "[%s]\n", ast_get_context_name(c));
985 context_header_written = 1;
988 if (!ast_get_extension_priority(p)==PRIORITY_HINT)
989 fprintf(output, "exten => %s,%d,%s,%s\n",
990 ast_get_extension_name(p),
991 ast_get_extension_priority(p),
992 ast_get_extension_app(p),
993 (char *)ast_get_extension_app_data(p));
995 fprintf(output, "exten => %s,hint,%s\n",
996 ast_get_extension_name(p),
997 ast_get_extension_app(p));
1000 p = ast_walk_extension_priorities(e, p);
1003 e = ast_walk_context_extensions(c, e);
1006 /* written any extensions? ok, write space between exten & inc */
1007 if (last_written_e) fprintf(output, "\n");
1009 /* walk through includes */
1010 i = ast_walk_context_includes(c, NULL);
1012 if (!strcmp(ast_get_include_registrar(i), registrar)) {
1013 if (!context_header_written) {
1014 fprintf(output, "[%s]\n", ast_get_context_name(c));
1015 context_header_written = 1;
1017 fprintf(output, "include => %s\n",
1018 ast_get_include_name(i));
1020 i = ast_walk_context_includes(c, i);
1023 if (ast_walk_context_includes(c, NULL))
1024 fprintf(output, "\n");
1026 /* fireout ignorepats ... */
1027 ip = ast_walk_context_ignorepats(c, NULL);
1029 if (!strcmp(ast_get_ignorepat_registrar(ip), registrar)) {
1030 if (!context_header_written) {
1031 fprintf(output, "[%s]\n", ast_get_context_name(c));
1032 context_header_written = 1;
1035 fprintf(output, "ignorepat => %s\n",
1036 ast_get_ignorepat_name(ip));
1038 ip = ast_walk_context_ignorepats(c, ip);
1041 ast_unlock_context(c);
1045 c = ast_walk_contexts(c);
1048 ast_unlock_contexts();
1049 ast_pthread_mutex_unlock(&save_dialplan_lock);
1053 ast_cli(fd, "Saved dialplan is incomplete\n");
1054 return RESULT_FAILURE;
1057 ast_cli(fd, "Dialplane successfully saved into '%s'\n",
1059 return RESULT_SUCCESS;
1063 * ADD EXTENSION command stuff
1065 static int handle_context_add_extension(int fd, int argc, char *argv[])
1068 char *exten, *prior;
1070 char *cidmatch, *app, *app_data;
1073 /* check for arguments at first */
1074 if (argc != 5 && argc != 6) return RESULT_SHOWUSAGE;
1075 if (strcmp(argv[3], "into")) return RESULT_SHOWUSAGE;
1076 if (argc == 6) if (strcmp(argv[5], "replace")) return RESULT_SHOWUSAGE;
1078 whole_exten = argv[2];
1079 exten = strsep(&whole_exten,",");
1080 if (strchr(exten, '/')) {
1082 strsep(&cidmatch,"/");
1086 prior = strsep(&whole_exten,",");
1087 if (!strcmp(prior, "hint")) {
1088 iprior = PRIORITY_HINT;
1090 iprior = atoi(prior);
1092 app = strsep(&whole_exten,",");
1093 if ((start = strchr(app, '(')) && (end = strrchr(app, ')'))) {
1094 *start = *end = '\0';
1095 app_data = start + 1;
1096 for (start = app_data; *start; start++)
1100 app_data = whole_exten;
1102 if (!exten || !prior || !app || (!app_data && iprior != PRIORITY_HINT)) return RESULT_SHOWUSAGE;
1106 if (ast_add_extension(argv[4], argc == 6 ? 1 : 0, exten, iprior, cidmatch, app,
1107 (void *)strdup(app_data), free, registrar)) {
1110 ast_cli(fd, "Out of free memory\n"); break;
1113 ast_cli(fd, "Failed to lock context(s) list, please try again later\n"); break;
1116 ast_cli(fd, "No existence of '%s' context\n", argv[4]); break;
1119 ast_cli(fd, "Extension %s@%s with priority %s already exists\n",
1120 exten, argv[4], prior); break;
1123 ast_cli(fd, "Failed to add '%s,%s,%s,%s' extension into '%s' context\n",
1124 exten, prior, app, app_data, argv[4]); break;
1126 return RESULT_FAILURE;
1130 ast_cli(fd, "Extension %s@%s (%s) replace by '%s,%s,%s,%s'\n",
1131 exten, argv[4], prior, exten, prior, app, app_data);
1133 ast_cli(fd, "Extension '%s,%s,%s,%s' added into '%s' context\n",
1134 exten, prior, app, app_data, argv[4]);
1136 return RESULT_SUCCESS;
1139 /* add extension 6123,1,Dial,IAX/212.71.138.13/6123 into local */
1140 static char *complete_context_add_extension(char *line, char *word,
1145 /* complete 'into' word ... */
1147 if (state == 0) return strdup("into");
1151 /* complete context */
1153 struct ast_context *c;
1155 /* try to lock contexts list ... */
1156 if (ast_lock_contexts()) {
1157 ast_log(LOG_WARNING, "Failed to lock contexts list\n");
1161 /* walk through all contexts */
1162 c = ast_walk_contexts(NULL);
1164 /* matching context? */
1165 if (!strncmp(ast_get_context_name(c), word, strlen(word))) {
1166 if (++which > state) {
1167 char *res = strdup(ast_get_context_name(c));
1168 ast_unlock_contexts();
1172 c = ast_walk_contexts(c);
1175 ast_unlock_contexts();
1179 if (pos == 5) return state == 0 ? strdup("replace") : NULL;
1185 * IGNOREPAT CLI stuff
1187 static int handle_context_add_ignorepat(int fd, int argc, char *argv[])
1189 if (argc != 5) return RESULT_SHOWUSAGE;
1190 if (strcmp(argv[3], "into")) return RESULT_SHOWUSAGE;
1192 if (ast_context_add_ignorepat(argv[4], argv[2], registrar)) {
1195 ast_cli(fd, "Out of free memory\n"); break;
1198 ast_cli(fd, "There is no existence of '%s' context\n", argv[4]);
1202 ast_cli(fd, "Ignore pattern '%s' already included in '%s' context\n",
1207 ast_cli(fd, "Failed to lock context(s) list, please, try again later\n");
1211 ast_cli(fd, "Failed to add ingore pattern '%s' into '%s' context\n",
1215 return RESULT_FAILURE;
1218 ast_cli(fd, "Ignore pattern '%s' added into '%s' context\n",
1220 return RESULT_SUCCESS;
1223 static char *complete_context_add_ignorepat(char *line, char *word,
1226 if (pos == 3) return state == 0 ? strdup("into") : NULL;
1229 struct ast_context *c;
1231 char *dupline, *duplinet, *ignorepat = NULL;
1233 dupline = strdup(line);
1237 strsep(&duplinet, " "); /* skip 'add' */
1238 strsep(&duplinet, " "); /* skip 'ignorepat' */
1239 ignorepat = strsep(&duplinet, " ");
1242 if (ast_lock_contexts()) {
1243 ast_log(LOG_ERROR, "Failed to lock contexts list\n");
1247 c = ast_walk_contexts(NULL);
1249 if (!strncmp(ast_get_context_name(c), word, strlen(word))) {
1250 int serve_context = 1;
1252 if (!ast_lock_context(c)) {
1253 struct ast_ignorepat *ip;
1254 ip = ast_walk_context_ignorepats(c, NULL);
1255 while (ip && serve_context) {
1256 if (!strcmp(ast_get_ignorepat_name(ip), ignorepat))
1258 ip = ast_walk_context_ignorepats(c, ip);
1260 ast_unlock_context(c);
1263 if (serve_context) {
1264 if (++which > state) {
1265 char *context = strdup(ast_get_context_name(c));
1266 if (dupline) free(dupline);
1267 ast_unlock_contexts();
1272 c = ast_walk_contexts(c);
1275 if (dupline) free(dupline);
1276 ast_unlock_contexts();
1283 static int handle_context_remove_ignorepat(int fd, int argc, char *argv[])
1285 if (argc != 5) return RESULT_SHOWUSAGE;
1286 if (strcmp(argv[3], "from")) return RESULT_SHOWUSAGE;
1288 if (ast_context_remove_ignorepat(argv[4], argv[2], registrar)) {
1291 ast_cli(fd, "Failed to lock context(s) list, please try again later\n");
1295 ast_cli(fd, "There is no existence of '%s' context\n", argv[4]);
1299 ast_cli(fd, "There is no existence of '%s' ignore pattern in '%s' context\n",
1304 ast_cli(fd, "Failed to remove ignore pattern '%s' from '%s' context\n");
1307 return RESULT_FAILURE;
1310 ast_cli(fd, "Ignore pattern '%s' removed from '%s' context\n",
1312 return RESULT_SUCCESS;
1315 static char *complete_context_remove_ignorepat(char *line, char *word,
1318 struct ast_context *c;
1322 if (ast_lock_contexts()) {
1323 ast_log(LOG_WARNING, "Failed to lock contexts list\n");
1327 c = ast_walk_contexts(NULL);
1329 if (!ast_lock_context(c)) {
1330 struct ast_ignorepat *ip;
1332 ip = ast_walk_context_ignorepats(c, NULL);
1334 if (!strncmp(ast_get_ignorepat_name(ip), word, strlen(word))) {
1335 if (which + 1 > state) {
1336 struct ast_context *cw;
1337 int already_served = 0;
1338 cw = ast_walk_contexts(NULL);
1339 while (cw && cw != c && !already_served) {
1340 if (!ast_lock_context(cw)) {
1341 struct ast_ignorepat *ipw;
1342 ipw = ast_walk_context_ignorepats(cw, NULL);
1344 if (!strcmp(ast_get_ignorepat_name(ipw),
1345 ast_get_ignorepat_name(ip))) already_served = 1;
1346 ipw = ast_walk_context_ignorepats(cw, ipw);
1348 ast_unlock_context(cw);
1350 cw = ast_walk_contexts(cw);
1352 if (!already_served) {
1353 char *ret = strdup(ast_get_ignorepat_name(ip));
1354 ast_unlock_context(c);
1355 ast_unlock_contexts();
1361 ip = ast_walk_context_ignorepats(c, ip);
1364 ast_unlock_context(c);
1366 c = ast_walk_contexts(c);
1369 ast_unlock_contexts();
1373 if (pos == 3) return state == 0 ? strdup("from") : NULL;
1376 char *dupline, *duplinet, *ignorepat;
1378 dupline = strdup(line);
1380 ast_log(LOG_WARNING, "Out of free memory\n");
1385 strsep(&duplinet, " ");
1386 strsep(&duplinet, " ");
1387 ignorepat = strsep(&duplinet, " ");
1394 if (ast_lock_contexts()) {
1395 ast_log(LOG_WARNING, "Failed to lock contexts list\n");
1400 c = ast_walk_contexts(NULL);
1402 if (!ast_lock_context(c)) {
1403 struct ast_ignorepat *ip;
1404 ip = ast_walk_context_ignorepats(c, NULL);
1406 if (!strcmp(ast_get_ignorepat_name(ip), ignorepat)) {
1407 if (!strncmp(ast_get_context_name(c), word, strlen(word))) {
1408 if (++which > state) {
1409 char *ret = strdup(ast_get_context_name(c));
1411 ast_unlock_context(c);
1412 ast_unlock_contexts();
1417 ip = ast_walk_context_ignorepats(c, ip);
1420 ast_unlock_context(c);
1422 c = ast_walk_contexts(c);
1426 ast_unlock_contexts();
1434 * CLI entries for commands provided by this module
1436 static struct ast_cli_entry context_dont_include_cli =
1437 { { "dont", "include", NULL }, handle_context_dont_include,
1438 "Remove a specified include from context", context_dont_include_help,
1439 complete_context_dont_include };
1441 static struct ast_cli_entry context_remove_extension_cli =
1442 { { "remove", "extension", NULL }, handle_context_remove_extension,
1443 "Remove a specified extension", context_remove_extension_help,
1444 complete_context_remove_extension };
1446 static struct ast_cli_entry context_add_include_cli =
1447 { { "include", "context", NULL }, handle_context_add_include,
1448 "Include context in other context", context_add_include_help,
1449 complete_context_add_include };
1451 static struct ast_cli_entry save_dialplan_cli =
1452 { { "save", "dialplan", NULL }, handle_save_dialplan,
1453 "Save dialplan", save_dialplan_help };
1455 static struct ast_cli_entry context_add_extension_cli =
1456 { { "add", "extension", NULL }, handle_context_add_extension,
1457 "Add new extension into context", context_add_extension_help,
1458 complete_context_add_extension };
1460 static struct ast_cli_entry context_add_ignorepat_cli =
1461 { { "add", "ignorepat", NULL }, handle_context_add_ignorepat,
1462 "Add new ignore pattern", context_add_ignorepat_help,
1463 complete_context_add_ignorepat };
1465 static struct ast_cli_entry context_remove_ignorepat_cli =
1466 { { "remove", "ignorepat", NULL }, handle_context_remove_ignorepat,
1467 "Remove ignore pattern from context", context_remove_ignorepat_help,
1468 complete_context_remove_ignorepat };
1471 * Standard module functions ...
1473 int unload_module(void)
1475 ast_cli_unregister(&context_add_extension_cli);
1476 if (static_config && !write_protect_config)
1477 ast_cli_unregister(&save_dialplan_cli);
1478 ast_cli_unregister(&context_add_include_cli);
1479 ast_cli_unregister(&context_dont_include_cli);
1480 ast_cli_unregister(&context_remove_extension_cli);
1481 ast_cli_unregister(&context_remove_ignorepat_cli);
1482 ast_cli_unregister(&context_add_ignorepat_cli);
1483 ast_context_destroy(NULL, registrar);
1487 static int pbx_load_module(void)
1489 struct ast_config *cfg;
1490 struct ast_variable *v;
1491 char *cxt, *ext, *pri, *appl, *data, *tc, *cidmatch;
1492 struct ast_context *con;
1495 cfg = ast_load(config);
1497 /* Use existing config to populate the PBX table */
1498 static_config = ast_true(ast_variable_retrieve(cfg, "general",
1500 write_protect_config = ast_true(ast_variable_retrieve(cfg, "general",
1502 v = ast_variable_browse(cfg, "globals");
1504 pbx_builtin_setvar_helper(NULL, v->name, v->value);
1507 cxt = ast_category_browse(cfg, NULL);
1509 /* All categories but "general" are considered contexts */
1510 if (!strcasecmp(cxt, "general") || !strcasecmp(cxt, "globals")) {
1511 cxt = ast_category_browse(cfg, cxt);
1514 if ((con=ast_context_create(cxt, registrar))) {
1515 v = ast_variable_browse(cfg, cxt);
1517 if (!strcasecmp(v->name, "exten")) {
1520 tc = strdup(v->value);
1523 ext = strsep(&stringp, ",");
1526 pri = strsep(&stringp, ",");
1529 if (!strcmp(pri,"hint"))
1536 if (!(start = strchr(appl, '('))) {
1538 appl = strsep(&stringp, ",");
1542 if (start && (end = strrchr(appl, ')'))) {
1543 *start = *end = '\0';
1545 for (start = data; *start; start++)
1548 } else if (stringp!=NULL && *stringp=='"') {
1550 data = strsep(&stringp, "\"");
1554 data = strsep(&stringp, ",");
1558 cidmatch = strchr(ext, '/');
1564 strsep(&stringp, "/");
1568 if (ast_add_extension2(con, 0, ext, ipri, cidmatch, appl, strdup(data), free, registrar)) {
1569 ast_log(LOG_WARNING, "Unable to register extension at line %d\n", v->lineno);
1572 } else fprintf(stderr,"Error strdup returned NULL in %s\n",__PRETTY_FUNCTION__);
1573 } else if(!strcasecmp(v->name, "include")) {
1574 if (ast_context_add_include2(con, v->value, registrar))
1575 ast_log(LOG_WARNING, "Unable to include context '%s' in context '%s'\n", v->value, cxt);
1576 } else if(!strcasecmp(v->name, "ignorepat")) {
1577 if (ast_context_add_ignorepat2(con, v->value, registrar))
1578 ast_log(LOG_WARNING, "Unable to include ignorepat '%s' in context '%s'\n", v->value, cxt);
1579 } else if (!strcasecmp(v->name, "switch")) {
1581 tc = strdup(v->value);
1583 appl = strsep(&stringp, "/");
1584 data = strsep(&stringp, "");
1587 if (ast_context_add_switch2(con, appl, data, registrar))
1588 ast_log(LOG_WARNING, "Unable to include switch '%s' in context '%s'\n", v->value, cxt);
1593 cxt = ast_category_browse(cfg, cxt);
1600 int load_module(void)
1602 if (pbx_load_module()) return -1;
1604 ast_cli_register(&context_remove_extension_cli);
1605 ast_cli_register(&context_dont_include_cli);
1606 ast_cli_register(&context_add_include_cli);
1607 if (static_config && !write_protect_config)
1608 ast_cli_register(&save_dialplan_cli);
1609 ast_cli_register(&context_add_extension_cli);
1610 ast_cli_register(&context_add_ignorepat_cli);
1611 ast_cli_register(&context_remove_ignorepat_cli);
1618 ast_context_destroy(NULL, registrar);
1619 /* For martin's global variables, don't clear them on reload */
1621 pbx_builtin_clear_globals();
1632 char *description(void)
1639 return ASTERISK_GPL_KEY;