2 * Asterisk -- An open source telephony toolkit.
4 * Copyright (C) 1999 - 2006, Digium, Inc.
6 * Mark Spencer <markster@digium.com>
8 * See http://www.asterisk.org for more information about
9 * the Asterisk project. Please do not directly contact
10 * any of the maintainers of this project for assistance;
11 * the project provides a web site, mailing lists and IRC
12 * channels for your use.
14 * This program is free software, distributed under the terms of
15 * the GNU General Public License Version 2. See the LICENSE file
16 * at the top of the source tree.
21 * \brief Populate and remember extensions from static config file
28 ASTERISK_FILE_VERSION(__FILE__
, "$Revision$")
30 #include <sys/types.h>
37 #include "asterisk/pbx.h"
38 #include "asterisk/config.h"
39 #include "asterisk/options.h"
40 #include "asterisk/module.h"
41 #include "asterisk/logger.h"
42 #include "asterisk/cli.h"
43 #include "asterisk/callerid.h"
45 static char *config
= "extensions.conf";
46 static char *registrar
= "pbx_config";
47 static char userscontext
[AST_MAX_EXTENSION
] = "default";
49 static int static_config
= 0;
50 static int write_protect_config
= 1;
51 static int autofallthrough_config
= 1;
52 static int clearglobalvars_config
= 0;
54 AST_MUTEX_DEFINE_STATIC(save_dialplan_lock
);
56 static struct ast_context
*local_contexts
= NULL
;
59 * Help for commands provided by this module ...
61 static char context_add_extension_help
[] =
62 "Usage: dialplan add extension <exten>,<priority>,<app>,<app-data>\n"
63 " into <context> [replace]\n\n"
64 " This command will add new extension into <context>. If there is an\n"
65 " existence of extension with the same priority and last 'replace'\n"
66 " arguments is given here we simply replace this extension.\n"
68 "Example: dialplan add extension 6123,1,Dial,IAX/216.207.245.56/6123 into local\n"
69 " Now, you can dial 6123 and talk to Markster :)\n";
71 static char context_remove_extension_help
[] =
72 "Usage: dialplan remove extension exten[/cid]@context [priority]\n"
73 " Remove an extension from a given context. If a priority\n"
74 " is given, only that specific priority from the given extension\n"
75 " will be removed.\n";
77 static char context_add_ignorepat_help
[] =
78 "Usage: dialplan add ignorepat <pattern> into <context>\n"
79 " This command adds a new ignore pattern into context <context>\n"
81 "Example: dialplan add ignorepat _3XX into local\n";
83 static char context_remove_ignorepat_help
[] =
84 "Usage: dialplan remove ignorepat <pattern> from <context>\n"
85 " This command removes an ignore pattern from context <context>\n"
87 "Example: dialplan remove ignorepat _3XX from local\n";
89 static char context_add_include_help
[] =
90 "Usage: dialplan add include <context> into <context>\n"
91 " Include a context in another context.\n";
93 static char context_remove_include_help
[] =
94 "Usage: dialplan remove include <context> from <context>\n"
95 " Remove an included context from another context.\n";
97 static char save_dialplan_help
[] =
98 "Usage: dialplan save [/path/to/extension/file]\n"
99 " Save dialplan created by pbx_config module.\n"
101 "Example: dialplan save (/etc/asterisk/extensions.conf)\n"
102 " dialplan save /home/markster (/home/markster/extensions.conf)\n";
104 static char reload_extensions_help
[] =
105 "Usage: dialplan reload\n"
106 " reload extensions.conf without reloading any other modules\n"
107 " This command does not delete global variables unless\n"
108 " clearglobalvars is set to yes in extensions.conf\n";
111 * Implementation of functions provided by this module
115 * REMOVE INCLUDE command stuff
117 static int handle_context_dont_include_deprecated(int fd
, int argc
, char *argv
[])
120 return RESULT_SHOWUSAGE
;
122 if (strcmp(argv
[3], "into"))
123 return RESULT_SHOWUSAGE
;
125 if (!ast_context_remove_include(argv
[4], argv
[2], registrar
)) {
126 ast_cli(fd
, "We are not including '%s' into '%s' now\n",
128 return RESULT_SUCCESS
;
131 ast_cli(fd
, "Failed to remove '%s' include from '%s' context\n",
133 return RESULT_FAILURE
;
136 static int handle_context_remove_include(int fd
, int argc
, char *argv
[])
139 return RESULT_SHOWUSAGE
;
142 if (strcmp(argv
[4], "from")) {
143 return RESULT_SHOWUSAGE
;
146 if (!ast_context_remove_include(argv
[5], argv
[3], registrar
)) {
147 ast_cli(fd
, "The dialplan no longer includes '%s' into '%s'\n",
149 return RESULT_SUCCESS
;
152 ast_cli(fd
, "Failed to remove '%s' include from '%s' context\n",
155 return RESULT_FAILURE
;
158 /*! \brief return true if 'name' is included by context c */
159 static int lookup_ci(struct ast_context
*c
, const char *name
)
161 struct ast_include
*i
= NULL
;
163 if (ast_lock_context(c
)) /* error, skip */
165 while ( (i
= ast_walk_context_includes(c
, i
)) )
166 if (!strcmp(name
, ast_get_include_name(i
)))
168 ast_unlock_context(c
);
169 return i
? -1 /* success */ : 0;
172 /*! \brief return true if 'name' is in the ignorepats for context c */
173 static int lookup_c_ip(struct ast_context
*c
, const char *name
)
175 struct ast_ignorepat
*ip
= NULL
;
177 if (ast_lock_context(c
)) /* error, skip */
179 while ( (ip
= ast_walk_context_ignorepats(c
, ip
)) )
180 if (!strcmp(name
, ast_get_ignorepat_name(ip
)))
182 ast_unlock_context(c
);
183 return ip
? -1 /* success */ : 0;
186 /*! \brief moves to the n-th word in the string, or empty string if none */
187 static const char *skip_words(const char *p
, int n
)
190 for (;n
&& *p
; p
++) {
191 if (isblank(*p
) /* XXX order is important */ && !in_blank
) {
192 n
--; /* one word is gone */
194 } else if (/* !is_blank(*p), we know already, && */ in_blank
) {
201 /*! \brief match the first 'len' chars of word. len==0 always succeeds */
202 static int partial_match(const char *s
, const char *word
, int len
)
204 return (len
== 0 || !strncmp(s
, word
, len
));
207 /*! \brief split extension\@context in two parts, return -1 on error.
208 * The return string is malloc'ed and pointed by *ext
210 static int split_ec(const char *src
, char **ext
, char ** const ctx
, char ** const cid
)
212 char *i
, *c
, *e
= ast_strdup(src
); /* now src is not used anymore */
215 return -1; /* malloc error */
216 /* now, parse values from 'exten@context' */
219 if (c
== NULL
) /* no context part */
220 *ctx
= ""; /* it is not overwritten, anyways */
221 else { /* found context, check for duplicity ... */
224 if (strchr(c
, '@')) { /* two @, not allowed */
229 if (cid
&& (i
= strchr(e
, '/'))) {
233 /* Signal none detected */
239 /* _X_ is the string we need to complete */
240 static char *complete_context_dont_include_deprecated(const char *line
, const char *word
,
245 int len
= strlen(word
); /* how many bytes to match */
246 struct ast_context
*c
= NULL
;
248 if (pos
== 2) { /* "dont include _X_" */
249 if (ast_wrlock_contexts()) {
250 ast_log(LOG_ERROR
, "Failed to lock context list\n");
253 /* walk contexts and their includes, return the n-th match */
254 while (!res
&& (c
= ast_walk_contexts(c
))) {
255 struct ast_include
*i
= NULL
;
257 if (ast_lock_context(c
)) /* error ? skip this one */
260 while ( !res
&& (i
= ast_walk_context_includes(c
, i
)) ) {
261 const char *i_name
= ast_get_include_name(i
);
262 struct ast_context
*nc
= NULL
;
263 int already_served
= 0;
265 if (!partial_match(i_name
, word
, len
))
266 continue; /* not matched */
268 /* check if this include is already served or not */
270 /* go through all contexts again till we reach actual
271 * context or already_served = 1
273 while ( (nc
= ast_walk_contexts(nc
)) && nc
!= c
&& !already_served
)
274 already_served
= lookup_ci(nc
, i_name
);
276 if (!already_served
&& ++which
> state
)
277 res
= strdup(i_name
);
279 ast_unlock_context(c
);
282 ast_unlock_contexts();
284 } else if (pos
== 3) { /* "dont include CTX _X_" */
286 * complete as 'in', but only if previous context is really
289 char *context
, *dupline
;
290 const char *s
= skip_words(line
, 2); /* skip 'dont' 'include' */
294 context
= dupline
= strdup(s
);
296 ast_log(LOG_ERROR
, "Out of free memory\n");
299 strsep(&dupline
, " ");
301 if (ast_rdlock_contexts()) {
302 ast_log(LOG_ERROR
, "Failed to lock contexts list\n");
307 /* go through all contexts and check if is included ... */
308 while (!res
&& (c
= ast_walk_contexts(c
)))
309 if (lookup_ci(c
, context
)) /* context is really included, complete "in" command */
311 ast_unlock_contexts();
313 ast_log(LOG_WARNING
, "%s not included anywhere\n", context
);
316 } else if (pos
== 4) { /* "dont include CTX in _X_" */
318 * Context from which we removing include ...
320 char *context
, *dupline
, *in
;
321 const char *s
= skip_words(line
, 2); /* skip 'dont' 'include' */
322 context
= dupline
= strdup(s
);
324 ast_log(LOG_ERROR
, "Out of free memory\n");
328 strsep(&dupline
, " "); /* skip context */
330 /* third word must be 'in' */
331 in
= strsep(&dupline
, " ");
332 if (!in
|| strcmp(in
, "in")) {
337 if (ast_rdlock_contexts()) {
338 ast_log(LOG_ERROR
, "Failed to lock context list\n");
343 /* walk through all contexts ... */
345 while ( !res
&& (c
= ast_walk_contexts(c
))) {
346 const char *c_name
= ast_get_context_name(c
);
347 if (!partial_match(c_name
, word
, len
)) /* not a good target */
349 /* walk through all includes and check if it is our context */
350 if (lookup_ci(c
, context
) && ++which
> state
)
351 res
= strdup(c_name
);
353 ast_unlock_contexts();
361 static char *complete_context_remove_include(const char *line
, const char *word
,
366 int len
= strlen(word
); /* how many bytes to match */
367 struct ast_context
*c
= NULL
;
369 if (pos
== 3) { /* "dialplan remove include _X_" */
370 if (ast_rdlock_contexts()) {
371 ast_log(LOG_ERROR
, "Failed to lock context list\n");
374 /* walk contexts and their includes, return the n-th match */
375 while (!res
&& (c
= ast_walk_contexts(c
))) {
376 struct ast_include
*i
= NULL
;
378 if (ast_lock_context(c
)) /* error ? skip this one */
381 while ( !res
&& (i
= ast_walk_context_includes(c
, i
)) ) {
382 const char *i_name
= ast_get_include_name(i
);
383 struct ast_context
*nc
= NULL
;
384 int already_served
= 0;
386 if (!partial_match(i_name
, word
, len
))
387 continue; /* not matched */
389 /* check if this include is already served or not */
391 /* go through all contexts again till we reach actual
392 * context or already_served = 1
394 while ( (nc
= ast_walk_contexts(nc
)) && nc
!= c
&& !already_served
)
395 already_served
= lookup_ci(nc
, i_name
);
397 if (!already_served
&& ++which
> state
)
398 res
= strdup(i_name
);
400 ast_unlock_context(c
);
403 ast_unlock_contexts();
405 } else if (pos
== 4) { /* "dialplan remove include CTX _X_" */
407 * complete as 'from', but only if previous context is really
410 char *context
, *dupline
;
411 const char *s
= skip_words(line
, 3); /* skip 'dialplan' 'remove' 'include' */
415 context
= dupline
= strdup(s
);
417 ast_log(LOG_ERROR
, "Out of free memory\n");
420 strsep(&dupline
, " ");
422 if (ast_rdlock_contexts()) {
423 ast_log(LOG_ERROR
, "Failed to lock contexts list\n");
428 /* go through all contexts and check if is included ... */
429 while (!res
&& (c
= ast_walk_contexts(c
)))
430 if (lookup_ci(c
, context
)) /* context is really included, complete "from" command */
431 res
= strdup("from");
432 ast_unlock_contexts();
434 ast_log(LOG_WARNING
, "%s not included anywhere\n", context
);
437 } else if (pos
== 5) { /* "dialplan remove include CTX from _X_" */
439 * Context from which we removing include ...
441 char *context
, *dupline
, *from
;
442 const char *s
= skip_words(line
, 3); /* skip 'dialplan' 'remove' 'include' */
443 context
= dupline
= strdup(s
);
445 ast_log(LOG_ERROR
, "Out of free memory\n");
449 strsep(&dupline
, " "); /* skip context */
451 /* fourth word must be 'from' */
452 from
= strsep(&dupline
, " ");
453 if (!from
|| strcmp(from
, "from")) {
458 if (ast_rdlock_contexts()) {
459 ast_log(LOG_ERROR
, "Failed to lock context list\n");
464 /* walk through all contexts ... */
466 while ( !res
&& (c
= ast_walk_contexts(c
))) {
467 const char *c_name
= ast_get_context_name(c
);
468 if (!partial_match(c_name
, word
, len
)) /* not a good target */
470 /* walk through all includes and check if it is our context */
471 if (lookup_ci(c
, context
) && ++which
> state
)
472 res
= strdup(c_name
);
474 ast_unlock_contexts();
483 * REMOVE EXTENSION command stuff
485 static int handle_context_remove_extension_deprecated(int fd
, int argc
, char *argv
[])
487 int removing_priority
= 0;
488 char *exten
, *context
, *cid
;
489 int ret
= RESULT_FAILURE
;
491 if (argc
!= 4 && argc
!= 3) return RESULT_SHOWUSAGE
;
494 * Priority input checking ...
499 /* check for digits in whole parameter for right priority ...
500 * why? because atoi (strtol) returns 0 if any characters in
501 * string and whole extension will be removed, it's not good
503 if (!strcmp("hint", c
))
504 removing_priority
= PRIORITY_HINT
;
506 while (*c
&& isdigit(*c
))
508 if (*c
) { /* non-digit in string */
509 ast_cli(fd
, "Invalid priority '%s'\n", argv
[3]);
510 return RESULT_FAILURE
;
512 removing_priority
= atoi(argv
[3]);
515 if (removing_priority
== 0) {
516 ast_cli(fd
, "If you want to remove whole extension, please " \
517 "omit priority argument\n");
518 return RESULT_FAILURE
;
522 /* XXX original overwrote argv[2] */
524 * Format exten@context checking ...
526 if (split_ec(argv
[2], &exten
, &context
, &cid
))
527 return RESULT_FAILURE
; /* XXX malloc failure */
528 if ((!strlen(exten
)) || (!(strlen(context
)))) {
529 ast_cli(fd
, "Missing extension or context name in second argument '%s'\n",
532 return RESULT_FAILURE
;
535 if (!ast_context_remove_extension_callerid(context
, exten
, removing_priority
,
536 /* Do NOT substitute S_OR; it is NOT the same thing */
537 cid
? cid
: (removing_priority
? "" : NULL
), cid
? 1 : 0, registrar
)) {
538 if (!removing_priority
)
539 ast_cli(fd
, "Whole extension %s@%s removed\n",
542 ast_cli(fd
, "Extension %s@%s with priority %d removed\n",
543 exten
, context
, removing_priority
);
545 ret
= RESULT_SUCCESS
;
547 ast_cli(fd
, "Failed to remove extension %s@%s\n", exten
, context
);
548 ret
= RESULT_FAILURE
;
554 static int handle_context_remove_extension(int fd
, int argc
, char *argv
[])
556 int removing_priority
= 0;
557 char *exten
, *context
, *cid
;
558 int ret
= RESULT_FAILURE
;
560 if (argc
!= 5 && argc
!= 4) return RESULT_SHOWUSAGE
;
563 * Priority input checking ...
568 /* check for digits in whole parameter for right priority ...
569 * why? because atoi (strtol) returns 0 if any characters in
570 * string and whole extension will be removed, it's not good
572 if (!strcmp("hint", c
))
573 removing_priority
= PRIORITY_HINT
;
575 while (*c
&& isdigit(*c
))
577 if (*c
) { /* non-digit in string */
578 ast_cli(fd
, "Invalid priority '%s'\n", argv
[4]);
579 return RESULT_FAILURE
;
581 removing_priority
= atoi(argv
[4]);
584 if (removing_priority
== 0) {
585 ast_cli(fd
, "If you want to remove whole extension, please " \
586 "omit priority argument\n");
587 return RESULT_FAILURE
;
591 /* XXX original overwrote argv[3] */
593 * Format exten@context checking ...
595 if (split_ec(argv
[3], &exten
, &context
, &cid
))
596 return RESULT_FAILURE
; /* XXX malloc failure */
597 if ((!strlen(exten
)) || (!(strlen(context
)))) {
598 ast_cli(fd
, "Missing extension or context name in third argument '%s'\n",
601 return RESULT_FAILURE
;
604 if (!ast_context_remove_extension_callerid(context
, exten
, removing_priority
,
605 /* Do NOT substitute S_OR; it is NOT the same thing */
606 cid
? cid
: (removing_priority
? "" : NULL
), cid
? 1 : 0, registrar
)) {
607 if (!removing_priority
)
608 ast_cli(fd
, "Whole extension %s@%s removed\n",
611 ast_cli(fd
, "Extension %s@%s with priority %d removed\n",
612 exten
, context
, removing_priority
);
614 ret
= RESULT_SUCCESS
;
616 ast_cli(fd
, "Failed to remove extension %s@%s\n", exten
, context
);
617 ret
= RESULT_FAILURE
;
623 #define BROKEN_READLINE 1
625 #ifdef BROKEN_READLINE
627 * There is one funny thing, when you have word like 300@ and you hit
628 * <tab>, you arguments will like as your word is '300 ', so it '@'
629 * characters acts sometimes as word delimiter and sometimes as a part
632 * This fix function, allocates new word variable and store here every
633 * time xxx@yyy always as one word and correct pos is set too
635 * It's ugly, I know, but I'm waiting for Mark suggestion if upper is
638 static int fix_complete_args(const char *line
, char **word
, int *pos
)
640 char *_line
, *_strsep_line
, *_previous_word
= NULL
, *_word
= NULL
;
643 _line
= strdup(line
);
645 _strsep_line
= _line
;
646 while (_strsep_line
) {
647 _previous_word
= _word
;
648 _word
= strsep(&_strsep_line
, " ");
650 if (_word
&& strlen(_word
)) words
++;
654 if (_word
|| _previous_word
) {
656 if (!strlen(_word
)) words
++;
657 *word
= strdup(_word
);
659 *word
= strdup(_previous_word
);
668 #endif /* BROKEN_READLINE */
670 static char *complete_context_remove_extension_deprecated(const char *line
, const char *word
, int pos
,
676 #ifdef BROKEN_READLINE
679 * Fix arguments, *word is a new allocated structure, REMEMBER to
680 * free *word when you want to return from this function ...
682 if (fix_complete_args(line
, &word2
, &pos
)) {
683 ast_log(LOG_ERROR
, "Out of free memory\n");
689 if (pos
== 2) { /* 'remove extension _X_' (exten/cid@context ... */
690 struct ast_context
*c
= NULL
;
691 char *context
= NULL
, *exten
= NULL
, *cid
= NULL
;
692 int le
= 0; /* length of extension */
693 int lc
= 0; /* length of context */
694 int lcid
= 0; /* length of cid */
696 lc
= split_ec(word
, &exten
, &context
, &cid
);
697 #ifdef BROKEN_READLINE
703 lc
= strlen(context
);
704 lcid
= cid
? strlen(cid
) : -1;
706 if (ast_rdlock_contexts()) {
707 ast_log(LOG_ERROR
, "Failed to lock context list\n");
711 /* find our context ... */
712 while ( (c
= ast_walk_contexts(c
)) ) { /* match our context if any */
713 struct ast_exten
*e
= NULL
;
715 if (!partial_match(ast_get_context_name(c
), context
, lc
))
716 continue; /* context not matched */
717 while ( (e
= ast_walk_context_extensions(c
, e
)) ) { /* try to complete extensions ... */
718 if ( !strchr(word
, '/') ||
719 (!strchr(word
, '@') && partial_match(ast_get_extension_cidmatch(e
), cid
, lcid
)) ||
720 (strchr(word
, '@') && !strcmp(ast_get_extension_cidmatch(e
), cid
))) {
721 if ( ((strchr(word
, '/') || strchr(word
, '@')) && !strcmp(ast_get_extension_name(e
), exten
)) ||
722 (!strchr(word
, '/') && !strchr(word
, '@') && partial_match(ast_get_extension_name(e
), exten
, le
))) { /* n-th match */
723 if (++which
> state
) {
724 /* If there is an extension then return exten@context. */
725 if (ast_get_extension_matchcid(e
) && (!strchr(word
, '@') || strchr(word
, '/'))) {
726 asprintf(&ret
, "%s/%s@%s", ast_get_extension_name(e
), ast_get_extension_cidmatch(e
), ast_get_context_name(c
));
728 } else if (!ast_get_extension_matchcid(e
) && !strchr(word
, '/')) {
729 asprintf(&ret
, "%s@%s", ast_get_extension_name(e
), ast_get_context_name(c
));
736 if (e
) /* got a match */
740 ast_unlock_contexts();
744 } else if (pos
== 3) { /* 'remove extension EXT _X_' (priority) */
745 char *exten
= NULL
, *context
, *cid
, *p
;
746 struct ast_context
*c
;
747 int le
, lc
, lcid
, len
;
748 const char *s
= skip_words(line
, 2); /* skip 'remove' 'extension' */
749 int i
= split_ec(s
, &exten
, &context
, &cid
); /* parse ext@context */
753 if ( (p
= strchr(exten
, ' ')) ) /* remove space after extension */
755 if ( (p
= strchr(context
, ' ')) ) /* remove space after context */
758 lc
= strlen(context
);
761 if (le
== 0 || lc
== 0)
764 if (ast_rdlock_contexts()) {
765 ast_log(LOG_ERROR
, "Failed to lock context list\n");
771 while ( (c
= ast_walk_contexts(c
)) ) {
772 /* XXX locking on c ? */
774 if (strcmp(ast_get_context_name(c
), context
) != 0)
776 /* got it, we must match here */
778 while ( (e
= ast_walk_context_extensions(c
, e
)) ) {
779 struct ast_exten
*priority
;
782 if (cid
&& strcmp(ast_get_extension_cidmatch(e
), cid
) != 0) {
785 if (strcmp(ast_get_extension_name(e
), exten
) != 0)
789 while ( !ret
&& (priority
= ast_walk_extension_priorities(e
, priority
)) ) {
790 snprintf(buffer
, sizeof(buffer
), "%u", ast_get_extension_priority(priority
));
791 if (partial_match(buffer
, word
, len
) && ++which
> state
) /* n-th match */
792 ret
= strdup(buffer
);
798 ast_unlock_contexts();
803 #ifdef BROKEN_READLINE
809 static char *complete_context_remove_extension(const char *line
, const char *word
, int pos
,
815 #ifdef BROKEN_READLINE
818 * Fix arguments, *word is a new allocated structure, REMEMBER to
819 * free *word when you want to return from this function ...
821 if (fix_complete_args(line
, &word2
, &pos
)) {
822 ast_log(LOG_ERROR
, "Out of free memory\n");
828 if (pos
== 3) { /* 'dialplan remove extension _X_' (exten@context ... */
829 struct ast_context
*c
= NULL
;
830 char *context
= NULL
, *exten
= NULL
, *cid
= NULL
;
831 int le
= 0; /* length of extension */
832 int lc
= 0; /* length of context */
833 int lcid
= 0; /* length of cid */
835 lc
= split_ec(word
, &exten
, &context
, &cid
);
836 if (lc
) { /* error */
837 #ifdef BROKEN_READLINE
843 lc
= strlen(context
);
844 lcid
= cid
? strlen(cid
) : -1;
846 if (ast_rdlock_contexts()) {
847 ast_log(LOG_ERROR
, "Failed to lock context list\n");
851 /* find our context ... */
852 while ( (c
= ast_walk_contexts(c
)) ) { /* match our context if any */
853 struct ast_exten
*e
= NULL
;
855 if (!partial_match(ast_get_context_name(c
), context
, lc
))
856 continue; /* context not matched */
857 while ( (e
= ast_walk_context_extensions(c
, e
)) ) { /* try to complete extensions ... */
858 if ( !strchr(word
, '/') ||
859 (!strchr(word
, '@') && partial_match(ast_get_extension_cidmatch(e
), cid
, lcid
)) ||
860 (strchr(word
, '@') && !strcmp(ast_get_extension_cidmatch(e
), cid
))) {
861 if ( ((strchr(word
, '/') || strchr(word
, '@')) && !strcmp(ast_get_extension_name(e
), exten
)) ||
862 (!strchr(word
, '/') && !strchr(word
, '@') && partial_match(ast_get_extension_name(e
), exten
, le
))) { /* n-th match */
863 if (++which
> state
) {
864 /* If there is an extension then return exten@context. */
865 if (ast_get_extension_matchcid(e
) && (!strchr(word
, '@') || strchr(word
, '/'))) {
866 asprintf(&ret
, "%s/%s@%s", ast_get_extension_name(e
), ast_get_extension_cidmatch(e
), ast_get_context_name(c
));
868 } else if (!ast_get_extension_matchcid(e
) && !strchr(word
, '/')) {
869 asprintf(&ret
, "%s@%s", ast_get_extension_name(e
), ast_get_context_name(c
));
876 if (e
) /* got a match */
879 #ifdef BROKEN_READLINE
883 ast_unlock_contexts();
887 } else if (pos
== 4) { /* 'dialplan remove extension EXT _X_' (priority) */
888 char *exten
= NULL
, *context
, *cid
, *p
;
889 struct ast_context
*c
;
890 int le
, lc
, lcid
, len
;
891 const char *s
= skip_words(line
, 3); /* skip 'dialplan' 'remove' 'extension' */
892 int i
= split_ec(s
, &exten
, &context
, &cid
); /* parse ext@context */
896 if ( (p
= strchr(exten
, ' ')) ) /* remove space after extension */
898 if ( (p
= strchr(context
, ' ')) ) /* remove space after context */
901 lc
= strlen(context
);
902 lcid
= cid
? strlen(cid
) : -1;
904 if (le
== 0 || lc
== 0)
907 if (ast_rdlock_contexts()) {
908 ast_log(LOG_ERROR
, "Failed to lock context list\n");
914 while ( (c
= ast_walk_contexts(c
)) ) {
915 /* XXX locking on c ? */
917 if (strcmp(ast_get_context_name(c
), context
) != 0)
919 /* got it, we must match here */
921 while ( (e
= ast_walk_context_extensions(c
, e
)) ) {
922 struct ast_exten
*priority
;
925 if (cid
&& strcmp(ast_get_extension_cidmatch(e
), cid
) != 0) {
928 if (strcmp(ast_get_extension_name(e
), exten
) != 0)
932 while ( !ret
&& (priority
= ast_walk_extension_priorities(e
, priority
)) ) {
933 snprintf(buffer
, sizeof(buffer
), "%u", ast_get_extension_priority(priority
));
934 if (partial_match(buffer
, word
, len
) && ++which
> state
) /* n-th match */
935 ret
= strdup(buffer
);
941 ast_unlock_contexts();
945 #ifdef BROKEN_READLINE
953 * Include context ...
955 static int handle_context_add_include_deprecated(int fd
, int argc
, char *argv
[])
957 if (argc
!= 5) /* include context CTX in CTX */
958 return RESULT_SHOWUSAGE
;
960 /* third arg must be 'in' ... */
961 if (strcmp(argv
[3], "in") && strcmp(argv
[3], "into")) /* XXX why both ? */
962 return RESULT_SHOWUSAGE
;
964 if (ast_context_add_include(argv
[4], argv
[2], registrar
)) {
967 ast_cli(fd
, "Out of memory for context addition\n");
971 ast_cli(fd
, "Failed to lock context(s) list, please try again later\n");
975 ast_cli(fd
, "Context '%s' already included in '%s' context\n",
981 ast_cli(fd
, "There is no existence of context '%s'\n",
982 errno
== ENOENT
? argv
[4] : argv
[2]);
986 ast_cli(fd
, "Failed to include '%s' in '%s' context\n",
990 return RESULT_FAILURE
;
993 /* show some info ... */
994 ast_cli(fd
, "Context '%s' included in '%s' context\n",
997 return RESULT_SUCCESS
;
1000 static int handle_context_add_include(int fd
, int argc
, char *argv
[])
1002 if (argc
!= 6) /* dialplan add include CTX in CTX */
1003 return RESULT_SHOWUSAGE
;
1005 /* fifth arg must be 'into' ... */
1006 if (strcmp(argv
[4], "into"))
1007 return RESULT_SHOWUSAGE
;
1009 if (ast_context_add_include(argv
[5], argv
[3], registrar
)) {
1012 ast_cli(fd
, "Out of memory for context addition\n");
1016 ast_cli(fd
, "Failed to lock context(s) list, please try again later\n");
1020 ast_cli(fd
, "Context '%s' already included in '%s' context\n",
1026 ast_cli(fd
, "There is no existence of context '%s'\n",
1027 errno
== ENOENT
? argv
[5] : argv
[3]);
1031 ast_cli(fd
, "Failed to include '%s' in '%s' context\n",
1035 return RESULT_FAILURE
;
1038 /* show some info ... */
1039 ast_cli(fd
, "Context '%s' included in '%s' context\n",
1042 return RESULT_SUCCESS
;
1045 static char *complete_context_add_include_deprecated(const char *line
, const char *word
, int pos
,
1048 struct ast_context
*c
;
1051 int len
= strlen(word
);
1053 if (pos
== 2) { /* 'include context _X_' (context) ... */
1054 if (ast_rdlock_contexts()) {
1055 ast_log(LOG_ERROR
, "Failed to lock context list\n");
1058 for (c
= NULL
; !ret
&& (c
= ast_walk_contexts(c
)); )
1059 if (partial_match(ast_get_context_name(c
), word
, len
) && ++which
> state
)
1060 ret
= strdup(ast_get_context_name(c
));
1061 ast_unlock_contexts();
1063 } else if (pos
== 3) { /* include context CTX _X_ */
1064 /* complete as 'in' if context exists or we are unable to check */
1065 char *context
, *dupline
;
1066 struct ast_context
*c
;
1067 const char *s
= skip_words(line
, 2); /* should not fail */
1069 if (state
!= 0) /* only once */
1072 /* parse context from line ... */
1073 context
= dupline
= strdup(s
);
1075 ast_log(LOG_ERROR
, "Out of free memory\n");
1076 return strdup("in");
1078 strsep(&dupline
, " ");
1080 /* check for context existence ... */
1081 if (ast_rdlock_contexts()) {
1082 ast_log(LOG_ERROR
, "Failed to lock context list\n");
1083 /* our fault, we can't check, so complete 'in' ... */
1086 for (c
= NULL
; !ret
&& (c
= ast_walk_contexts(c
)); )
1087 if (!strcmp(context
, ast_get_context_name(c
)))
1088 ret
= strdup("in"); /* found */
1089 ast_unlock_contexts();
1093 } else if (pos
== 4) { /* 'include context CTX in _X_' (dst context) */
1094 char *context
, *dupline
, *in
;
1095 const char *s
= skip_words(line
, 2); /* should not fail */
1096 context
= dupline
= strdup(s
);
1098 ast_log(LOG_ERROR
, "Out of free memory\n");
1101 strsep(&dupline
, " "); /* skip context */
1102 in
= strsep(&dupline
, " ");
1103 /* error if missing context or third word is not 'in' */
1104 if (!strlen(context
) || strcmp(in
, "in")) {
1105 ast_log(LOG_ERROR
, "bad context %s or missing in %s\n",
1110 if (ast_rdlock_contexts()) {
1111 ast_log(LOG_ERROR
, "Failed to lock context list\n");
1115 for (c
= NULL
; (c
= ast_walk_contexts(c
)); )
1116 if (!strcmp(context
, ast_get_context_name(c
)))
1118 if (c
) { /* first context exists, go on... */
1119 /* go through all contexts ... */
1120 for (c
= NULL
; !ret
&& (c
= ast_walk_contexts(c
)); ) {
1121 if (!strcmp(context
, ast_get_context_name(c
)))
1122 continue; /* skip ourselves */
1123 if (partial_match(ast_get_context_name(c
), word
, len
) &&
1124 !lookup_ci(c
, context
) /* not included yet */ &&
1126 ret
= strdup(ast_get_context_name(c
));
1129 ast_log(LOG_ERROR
, "context %s not found\n", context
);
1131 ast_unlock_contexts();
1140 static char *complete_context_add_include(const char *line
, const char *word
, int pos
,
1143 struct ast_context
*c
;
1146 int len
= strlen(word
);
1148 if (pos
== 3) { /* 'dialplan add include _X_' (context) ... */
1149 if (ast_rdlock_contexts()) {
1150 ast_log(LOG_ERROR
, "Failed to lock context list\n");
1153 for (c
= NULL
; !ret
&& (c
= ast_walk_contexts(c
)); )
1154 if (partial_match(ast_get_context_name(c
), word
, len
) && ++which
> state
)
1155 ret
= strdup(ast_get_context_name(c
));
1156 ast_unlock_contexts();
1158 } else if (pos
== 4) { /* dialplan add include CTX _X_ */
1159 /* complete as 'into' if context exists or we are unable to check */
1160 char *context
, *dupline
;
1161 struct ast_context
*c
;
1162 const char *s
= skip_words(line
, 3); /* should not fail */
1164 if (state
!= 0) /* only once */
1167 /* parse context from line ... */
1168 context
= dupline
= strdup(s
);
1170 ast_log(LOG_ERROR
, "Out of free memory\n");
1171 return strdup("into");
1173 strsep(&dupline
, " ");
1175 /* check for context existence ... */
1176 if (ast_rdlock_contexts()) {
1177 ast_log(LOG_ERROR
, "Failed to lock context list\n");
1178 /* our fault, we can't check, so complete 'into' ... */
1179 ret
= strdup("into");
1181 for (c
= NULL
; !ret
&& (c
= ast_walk_contexts(c
)); )
1182 if (!strcmp(context
, ast_get_context_name(c
)))
1183 ret
= strdup("into"); /* found */
1184 ast_unlock_contexts();
1188 } else if (pos
== 5) { /* 'dialplan add include CTX into _X_' (dst context) */
1189 char *context
, *dupline
, *into
;
1190 const char *s
= skip_words(line
, 3); /* should not fail */
1191 context
= dupline
= strdup(s
);
1193 ast_log(LOG_ERROR
, "Out of free memory\n");
1196 strsep(&dupline
, " "); /* skip context */
1197 into
= strsep(&dupline
, " ");
1198 /* error if missing context or fifth word is not 'into' */
1199 if (!strlen(context
) || strcmp(into
, "into")) {
1200 ast_log(LOG_ERROR
, "bad context %s or missing into %s\n",
1205 if (ast_rdlock_contexts()) {
1206 ast_log(LOG_ERROR
, "Failed to lock context list\n");
1210 for (c
= NULL
; (c
= ast_walk_contexts(c
)); )
1211 if (!strcmp(context
, ast_get_context_name(c
)))
1213 if (c
) { /* first context exists, go on... */
1214 /* go through all contexts ... */
1215 for (c
= NULL
; !ret
&& (c
= ast_walk_contexts(c
)); ) {
1216 if (!strcmp(context
, ast_get_context_name(c
)))
1217 continue; /* skip ourselves */
1218 if (partial_match(ast_get_context_name(c
), word
, len
) &&
1219 !lookup_ci(c
, context
) /* not included yet */ &&
1221 ret
= strdup(ast_get_context_name(c
));
1224 ast_log(LOG_ERROR
, "context %s not found\n", context
);
1226 ast_unlock_contexts();
1236 * \brief 'save dialplan' CLI command implementation functions ...
1238 static int handle_save_dialplan(int fd
, int argc
, char *argv
[])
1241 struct ast_context
*c
;
1242 struct ast_config
*cfg
;
1243 struct ast_variable
*v
;
1244 int incomplete
= 0; /* incomplete config write? */
1247 const char *base
, *slash
, *file
;
1249 if (! (static_config
&& !write_protect_config
)) {
1251 "I can't save dialplan now, see '%s' example file.\n",
1253 return RESULT_FAILURE
;
1256 if (argc
!= 2 && argc
!= 3)
1257 return RESULT_SHOWUSAGE
;
1259 if (ast_mutex_lock(&save_dialplan_lock
)) {
1261 "Failed to lock dialplan saving (another proccess saving?)\n");
1262 return RESULT_FAILURE
;
1264 /* XXX the code here is quite loose, a pathname with .conf in it
1265 * is assumed to be a complete pathname
1267 if (argc
== 3) { /* have config path. Look for *.conf */
1269 if (!strstr(argv
[2], ".conf")) { /*no, this is assumed to be a pathname */
1270 /* if filename ends with '/', do not add one */
1271 slash
= (*(argv
[2] + strlen(argv
[2]) -1) == '/') ? "/" : "";
1272 file
= config
; /* default: 'extensions.conf' */
1273 } else { /* yes, complete file name */
1278 /* no config file, default one */
1279 base
= ast_config_AST_CONFIG_DIR
;
1283 snprintf(filename
, sizeof(filename
), "%s%s%s", base
, slash
, config
);
1285 cfg
= ast_config_load("extensions.conf");
1287 /* try to lock contexts list */
1288 if (ast_rdlock_contexts()) {
1289 ast_cli(fd
, "Failed to lock contexts list\n");
1290 ast_mutex_unlock(&save_dialplan_lock
);
1291 ast_config_destroy(cfg
);
1292 return RESULT_FAILURE
;
1295 /* create new file ... */
1296 if (!(output
= fopen(filename
, "wt"))) {
1297 ast_cli(fd
, "Failed to create file '%s'\n",
1299 ast_unlock_contexts();
1300 ast_mutex_unlock(&save_dialplan_lock
);
1301 ast_config_destroy(cfg
);
1302 return RESULT_FAILURE
;
1305 /* fireout general info */
1306 fprintf(output
, "[general]\nstatic=%s\nwriteprotect=%s\nautofallthrough=%s\nclearglobalvars=%s\npriorityjumping=%s\n\n",
1307 static_config
? "yes" : "no",
1308 write_protect_config
? "yes" : "no",
1309 autofallthrough_config
? "yes" : "no",
1310 clearglobalvars_config
? "yes" : "no",
1311 ast_true(ast_variable_retrieve(cfg
, "general", "priorityjumping")) ? "yes" : "no");
1313 if ((v
= ast_variable_browse(cfg
, "globals"))) {
1314 fprintf(output
, "[globals]\n");
1316 fprintf(output
, "%s => %s\n", v
->name
, v
->value
);
1319 fprintf(output
, "\n");
1322 ast_config_destroy(cfg
);
1324 #define PUT_CTX_HDR do { \
1325 if (!context_header_written) { \
1326 fprintf(output, "[%s]\n", ast_get_context_name(c)); \
1327 context_header_written = 1; \
1331 /* walk all contexts */
1332 for (c
= NULL
; (c
= ast_walk_contexts(c
)); ) {
1333 int context_header_written
= 0;
1334 struct ast_exten
*e
, *last_written_e
= NULL
;
1335 struct ast_include
*i
;
1336 struct ast_ignorepat
*ip
;
1339 /* try to lock context and fireout all info */
1340 if (ast_lock_context(c
)) { /* lock failure */
1344 /* registered by this module? */
1345 /* XXX do we need this ? */
1346 if (!strcmp(ast_get_context_registrar(c
), registrar
)) {
1347 fprintf(output
, "[%s]\n", ast_get_context_name(c
));
1348 context_header_written
= 1;
1351 /* walk extensions ... */
1352 for (e
= NULL
; (e
= ast_walk_context_extensions(c
, e
)); ) {
1353 struct ast_exten
*p
= NULL
;
1355 /* fireout priorities */
1356 while ( (p
= ast_walk_extension_priorities(e
, p
)) ) {
1357 if (strcmp(ast_get_extension_registrar(p
), registrar
) != 0) /* not this source */
1360 /* make empty line between different extensions */
1361 if (last_written_e
!= NULL
&&
1362 strcmp(ast_get_extension_name(last_written_e
),
1363 ast_get_extension_name(p
)))
1364 fprintf(output
, "\n");
1369 if (ast_get_extension_priority(p
)==PRIORITY_HINT
) { /* easy */
1370 fprintf(output
, "exten => %s,hint,%s\n",
1371 ast_get_extension_name(p
),
1372 ast_get_extension_app(p
));
1373 } else { /* copy and replace '|' with ',' */
1374 const char *sep
, *cid
;
1375 char *tempdata
= "";
1377 const char *el
= ast_get_extension_label(p
);
1378 char label
[128] = "";
1380 s
= ast_get_extension_app_data(p
);
1383 tempdata
= alloca(strlen(tempdata
) * 2 + 1);
1385 for (t
= tempdata
; *s
; s
++, t
++) {
1389 if (*s
== ',' || *s
== ';')
1394 /* Terminating NULL */
1398 if (ast_get_extension_matchcid(p
)) {
1400 cid
= ast_get_extension_cidmatch(p
);
1404 if (el
&& (snprintf(label
, sizeof(label
), "(%s)", el
) != (strlen(el
) + 2)))
1405 incomplete
= 1; /* error encountered or label > 125 chars */
1407 fprintf(output
, "exten => %s%s%s,%d%s,%s(%s)\n",
1408 ast_get_extension_name(p
), (ast_strlen_zero(sep
) ? "" : sep
), (ast_strlen_zero(cid
) ? "" : cid
),
1409 ast_get_extension_priority(p
), label
,
1410 ast_get_extension_app(p
), (ast_strlen_zero(tempdata
) ? "" : tempdata
));
1415 /* written any extensions? ok, write space between exten & inc */
1417 fprintf(output
, "\n");
1419 /* walk through includes */
1420 for (i
= NULL
; (i
= ast_walk_context_includes(c
, i
)) ; ) {
1421 if (strcmp(ast_get_include_registrar(i
), registrar
) != 0)
1422 continue; /* not mine */
1424 fprintf(output
, "include => %s\n", ast_get_include_name(i
));
1426 if (ast_walk_context_includes(c
, NULL
))
1427 fprintf(output
, "\n");
1429 /* walk through switches */
1430 for (sw
= NULL
; (sw
= ast_walk_context_switches(c
, sw
)) ; ) {
1431 if (strcmp(ast_get_switch_registrar(sw
), registrar
) != 0)
1432 continue; /* not mine */
1434 fprintf(output
, "switch => %s/%s\n",
1435 ast_get_switch_name(sw
), ast_get_switch_data(sw
));
1438 if (ast_walk_context_switches(c
, NULL
))
1439 fprintf(output
, "\n");
1441 /* fireout ignorepats ... */
1442 for (ip
= NULL
; (ip
= ast_walk_context_ignorepats(c
, ip
)); ) {
1443 if (strcmp(ast_get_ignorepat_registrar(ip
), registrar
) != 0)
1444 continue; /* not mine */
1446 fprintf(output
, "ignorepat => %s\n",
1447 ast_get_ignorepat_name(ip
));
1450 ast_unlock_context(c
);
1453 ast_unlock_contexts();
1454 ast_mutex_unlock(&save_dialplan_lock
);
1458 ast_cli(fd
, "Saved dialplan is incomplete\n");
1459 return RESULT_FAILURE
;
1462 ast_cli(fd
, "Dialplan successfully saved into '%s'\n",
1464 return RESULT_SUCCESS
;
1468 * \brief ADD EXTENSION command stuff
1470 static int handle_context_add_extension_deprecated(int fd
, int argc
, char *argv
[])
1473 char *exten
, *prior
;
1475 char *cidmatch
, *app
, *app_data
;
1478 /* check for arguments at first */
1479 if (argc
!= 5 && argc
!= 6)
1480 return RESULT_SHOWUSAGE
;
1481 if (strcmp(argv
[3], "into"))
1482 return RESULT_SHOWUSAGE
;
1483 if (argc
== 6) if (strcmp(argv
[5], "replace")) return RESULT_SHOWUSAGE
;
1485 /* XXX overwrite argv[2] */
1486 whole_exten
= argv
[2];
1487 exten
= strsep(&whole_exten
,",");
1488 if (strchr(exten
, '/')) {
1490 strsep(&cidmatch
,"/");
1494 prior
= strsep(&whole_exten
,",");
1496 if (!strcmp(prior
, "hint")) {
1497 iprior
= PRIORITY_HINT
;
1499 if (sscanf(prior
, "%d", &iprior
) != 1) {
1500 ast_cli(fd
, "'%s' is not a valid priority\n", prior
);
1506 if (app
&& (start
= strchr(app
, '(')) && (end
= strrchr(app
, ')'))) {
1507 *start
= *end
= '\0';
1508 app_data
= start
+ 1;
1509 ast_process_quotes_and_slashes(app_data
, ',', '|');
1512 app_data
= strchr(app
, ',');
1521 if (!exten
|| !prior
|| !app
|| (!app_data
&& iprior
!= PRIORITY_HINT
))
1522 return RESULT_SHOWUSAGE
;
1526 if (ast_add_extension(argv
[4], argc
== 6 ? 1 : 0, exten
, iprior
, NULL
, cidmatch
, app
,
1527 (void *)strdup(app_data
), ast_free
, registrar
)) {
1530 ast_cli(fd
, "Out of free memory\n");
1534 ast_cli(fd
, "Failed to lock context(s) list, please try again later\n");
1538 ast_cli(fd
, "No existence of '%s' context\n", argv
[4]);
1542 ast_cli(fd
, "Extension %s@%s with priority %s already exists\n",
1543 exten
, argv
[4], prior
);
1547 ast_cli(fd
, "Failed to add '%s,%s,%s,%s' extension into '%s' context\n",
1548 exten
, prior
, app
, app_data
, argv
[4]);
1551 return RESULT_FAILURE
;
1555 ast_cli(fd
, "Extension %s@%s (%s) replace by '%s,%s,%s,%s'\n",
1556 exten
, argv
[4], prior
, exten
, prior
, app
, app_data
);
1558 ast_cli(fd
, "Extension '%s,%s,%s,%s' added into '%s' context\n",
1559 exten
, prior
, app
, app_data
, argv
[4]);
1561 return RESULT_SUCCESS
;
1563 static int handle_context_add_extension(int fd
, int argc
, char *argv
[])
1566 char *exten
, *prior
;
1568 char *cidmatch
, *app
, *app_data
;
1571 /* check for arguments at first */
1572 if (argc
!= 6 && argc
!= 7)
1573 return RESULT_SHOWUSAGE
;
1574 if (strcmp(argv
[4], "into"))
1575 return RESULT_SHOWUSAGE
;
1576 if (argc
== 7) if (strcmp(argv
[6], "replace")) return RESULT_SHOWUSAGE
;
1578 /* XXX overwrite argv[3] */
1579 whole_exten
= argv
[3];
1580 exten
= strsep(&whole_exten
,",");
1581 if (strchr(exten
, '/')) {
1583 strsep(&cidmatch
,"/");
1587 prior
= strsep(&whole_exten
,",");
1589 if (!strcmp(prior
, "hint")) {
1590 iprior
= PRIORITY_HINT
;
1592 if (sscanf(prior
, "%d", &iprior
) != 1) {
1593 ast_cli(fd
, "'%s' is not a valid priority\n", prior
);
1599 if (app
&& (start
= strchr(app
, '(')) && (end
= strrchr(app
, ')'))) {
1600 *start
= *end
= '\0';
1601 app_data
= start
+ 1;
1602 ast_process_quotes_and_slashes(app_data
, ',', '|');
1605 app_data
= strchr(app
, ',');
1614 if (!exten
|| !prior
|| !app
|| (!app_data
&& iprior
!= PRIORITY_HINT
))
1615 return RESULT_SHOWUSAGE
;
1619 if (ast_add_extension(argv
[5], argc
== 7 ? 1 : 0, exten
, iprior
, NULL
, cidmatch
, app
,
1620 (void *)strdup(app_data
), ast_free
, registrar
)) {
1623 ast_cli(fd
, "Out of free memory\n");
1627 ast_cli(fd
, "Failed to lock context(s) list, please try again later\n");
1631 ast_cli(fd
, "No existence of '%s' context\n", argv
[5]);
1635 ast_cli(fd
, "Extension %s@%s with priority %s already exists\n",
1636 exten
, argv
[5], prior
);
1640 ast_cli(fd
, "Failed to add '%s,%s,%s,%s' extension into '%s' context\n",
1641 exten
, prior
, app
, app_data
, argv
[5]);
1644 return RESULT_FAILURE
;
1648 ast_cli(fd
, "Extension %s@%s (%s) replace by '%s,%s,%s,%s'\n",
1649 exten
, argv
[5], prior
, exten
, prior
, app
, app_data
);
1651 ast_cli(fd
, "Extension '%s,%s,%s,%s' added into '%s' context\n",
1652 exten
, prior
, app
, app_data
, argv
[5]);
1654 return RESULT_SUCCESS
;
1657 /*! dialplan add extension 6123,1,Dial,IAX/212.71.138.13/6123 into local */
1658 static char *complete_context_add_extension_deprecated(const char *line
, const char *word
, int pos
, int state
)
1662 if (pos
== 3) { /* complete 'into' word ... */
1663 return (state
== 0) ? strdup("into") : NULL
;
1664 } else if (pos
== 4) { /* complete context */
1665 struct ast_context
*c
= NULL
;
1666 int len
= strlen(word
);
1669 /* try to lock contexts list ... */
1670 if (ast_rdlock_contexts()) {
1671 ast_log(LOG_WARNING
, "Failed to lock contexts list\n");
1675 /* walk through all contexts */
1676 while ( !res
&& (c
= ast_walk_contexts(c
)) )
1677 if (partial_match(ast_get_context_name(c
), word
, len
) && ++which
> state
)
1678 res
= strdup(ast_get_context_name(c
));
1679 ast_unlock_contexts();
1681 } else if (pos
== 5) {
1682 return state
== 0 ? strdup("replace") : NULL
;
1687 static char *complete_context_add_extension(const char *line
, const char *word
, int pos
, int state
)
1691 if (pos
== 4) { /* complete 'into' word ... */
1692 return (state
== 0) ? strdup("into") : NULL
;
1693 } else if (pos
== 5) { /* complete context */
1694 struct ast_context
*c
= NULL
;
1695 int len
= strlen(word
);
1698 /* try to lock contexts list ... */
1699 if (ast_rdlock_contexts()) {
1700 ast_log(LOG_WARNING
, "Failed to lock contexts list\n");
1704 /* walk through all contexts */
1705 while ( !res
&& (c
= ast_walk_contexts(c
)) )
1706 if (partial_match(ast_get_context_name(c
), word
, len
) && ++which
> state
)
1707 res
= strdup(ast_get_context_name(c
));
1708 ast_unlock_contexts();
1710 } else if (pos
== 6) {
1711 return state
== 0 ? strdup("replace") : NULL
;
1717 * IGNOREPAT CLI stuff
1719 static int handle_context_add_ignorepat_deprecated(int fd
, int argc
, char *argv
[])
1722 return RESULT_SHOWUSAGE
;
1723 if (strcmp(argv
[3], "into"))
1724 return RESULT_SHOWUSAGE
;
1726 if (ast_context_add_ignorepat(argv
[4], argv
[2], registrar
)) {
1729 ast_cli(fd
, "Out of free memory\n");
1733 ast_cli(fd
, "There is no existence of '%s' context\n", argv
[4]);
1737 ast_cli(fd
, "Ignore pattern '%s' already included in '%s' context\n",
1742 ast_cli(fd
, "Failed to lock context(s) list, please, try again later\n");
1746 ast_cli(fd
, "Failed to add ingore pattern '%s' into '%s' context\n",
1750 return RESULT_FAILURE
;
1753 ast_cli(fd
, "Ignore pattern '%s' added into '%s' context\n",
1755 return RESULT_SUCCESS
;
1758 static int handle_context_add_ignorepat(int fd
, int argc
, char *argv
[])
1761 return RESULT_SHOWUSAGE
;
1762 if (strcmp(argv
[4], "into"))
1763 return RESULT_SHOWUSAGE
;
1765 if (ast_context_add_ignorepat(argv
[5], argv
[3], registrar
)) {
1768 ast_cli(fd
, "Out of free memory\n");
1772 ast_cli(fd
, "There is no existence of '%s' context\n", argv
[5]);
1776 ast_cli(fd
, "Ignore pattern '%s' already included in '%s' context\n",
1781 ast_cli(fd
, "Failed to lock context(s) list, please, try again later\n");
1785 ast_cli(fd
, "Failed to add ingore pattern '%s' into '%s' context\n",
1789 return RESULT_FAILURE
;
1792 ast_cli(fd
, "Ignore pattern '%s' added into '%s' context\n",
1794 return RESULT_SUCCESS
;
1797 static char *complete_context_add_ignorepat_deprecated(const char *line
, const char *word
,
1801 return state
== 0 ? strdup("into") : NULL
;
1802 else if (pos
== 4) {
1803 struct ast_context
*c
;
1805 char *dupline
, *ignorepat
= NULL
;
1808 int len
= strlen(word
);
1810 /* XXX skip first two words 'add' 'ignorepat' */
1811 s
= skip_words(line
, 2);
1814 dupline
= strdup(s
);
1816 ast_log(LOG_ERROR
, "Malloc failure\n");
1819 ignorepat
= strsep(&dupline
, " ");
1821 if (ast_rdlock_contexts()) {
1822 ast_log(LOG_ERROR
, "Failed to lock contexts list\n");
1826 for (c
= NULL
; !ret
&& (c
= ast_walk_contexts(c
));) {
1829 if (!partial_match(ast_get_context_name(c
), word
, len
))
1830 continue; /* not mine */
1831 if (ignorepat
) /* there must be one, right ? */
1832 found
= lookup_c_ip(c
, ignorepat
);
1833 if (!found
&& ++which
> state
)
1834 ret
= strdup(ast_get_context_name(c
));
1839 ast_unlock_contexts();
1846 static char *complete_context_add_ignorepat(const char *line
, const char *word
,
1850 return state
== 0 ? strdup("into") : NULL
;
1851 else if (pos
== 5) {
1852 struct ast_context
*c
;
1854 char *dupline
, *ignorepat
= NULL
;
1857 int len
= strlen(word
);
1859 /* XXX skip first three words 'dialplan' 'add' 'ignorepat' */
1860 s
= skip_words(line
, 3);
1863 dupline
= strdup(s
);
1865 ast_log(LOG_ERROR
, "Malloc failure\n");
1868 ignorepat
= strsep(&dupline
, " ");
1870 if (ast_rdlock_contexts()) {
1871 ast_log(LOG_ERROR
, "Failed to lock contexts list\n");
1875 for (c
= NULL
; !ret
&& (c
= ast_walk_contexts(c
));) {
1878 if (!partial_match(ast_get_context_name(c
), word
, len
))
1879 continue; /* not mine */
1880 if (ignorepat
) /* there must be one, right ? */
1881 found
= lookup_c_ip(c
, ignorepat
);
1882 if (!found
&& ++which
> state
)
1883 ret
= strdup(ast_get_context_name(c
));
1888 ast_unlock_contexts();
1895 static int handle_context_remove_ignorepat_deprecated(int fd
, int argc
, char *argv
[])
1898 return RESULT_SHOWUSAGE
;
1899 if (strcmp(argv
[3], "from"))
1900 return RESULT_SHOWUSAGE
;
1902 if (ast_context_remove_ignorepat(argv
[4], argv
[2], registrar
)) {
1905 ast_cli(fd
, "Failed to lock context(s) list, please try again later\n");
1909 ast_cli(fd
, "There is no existence of '%s' context\n", argv
[4]);
1913 ast_cli(fd
, "There is no existence of '%s' ignore pattern in '%s' context\n",
1918 ast_cli(fd
, "Failed to remove ignore pattern '%s' from '%s' context\n", argv
[2], argv
[4]);
1921 return RESULT_FAILURE
;
1924 ast_cli(fd
, "Ignore pattern '%s' removed from '%s' context\n",
1926 return RESULT_SUCCESS
;
1929 static int handle_context_remove_ignorepat(int fd
, int argc
, char *argv
[])
1932 return RESULT_SHOWUSAGE
;
1933 if (strcmp(argv
[4], "from"))
1934 return RESULT_SHOWUSAGE
;
1936 if (ast_context_remove_ignorepat(argv
[5], argv
[3], registrar
)) {
1939 ast_cli(fd
, "Failed to lock context(s) list, please try again later\n");
1943 ast_cli(fd
, "There is no existence of '%s' context\n", argv
[5]);
1947 ast_cli(fd
, "There is no existence of '%s' ignore pattern in '%s' context\n",
1952 ast_cli(fd
, "Failed to remove ignore pattern '%s' from '%s' context\n", argv
[3], argv
[5]);
1955 return RESULT_FAILURE
;
1958 ast_cli(fd
, "Ignore pattern '%s' removed from '%s' context\n",
1960 return RESULT_SUCCESS
;
1963 static char *complete_context_remove_ignorepat_deprecated(const char *line
, const char *word
,
1966 struct ast_context
*c
;
1971 int len
= strlen(word
);
1972 if (ast_rdlock_contexts()) {
1973 ast_log(LOG_WARNING
, "Failed to lock contexts list\n");
1977 for (c
= NULL
; !ret
&& (c
= ast_walk_contexts(c
));) {
1978 struct ast_ignorepat
*ip
;
1980 if (ast_lock_context(c
)) /* error, skip it */
1983 for (ip
= NULL
; !ret
&& (ip
= ast_walk_context_ignorepats(c
, ip
));) {
1984 if (partial_match(ast_get_ignorepat_name(ip
), word
, len
) && ++which
> state
) {
1986 struct ast_context
*cw
= NULL
;
1988 while ( (cw
= ast_walk_contexts(cw
)) && cw
!= c
&& !found
) {
1989 /* XXX do i stop on c, or skip it ? */
1990 found
= lookup_c_ip(cw
, ast_get_ignorepat_name(ip
));
1993 ret
= strdup(ast_get_ignorepat_name(ip
));
1996 ast_unlock_context(c
);
1998 ast_unlock_contexts();
2000 } else if (pos
== 3) {
2001 return state
== 0 ? strdup("from") : NULL
;
2002 } else if (pos
== 4) { /* XXX check this */
2003 char *dupline
, *duplinet
, *ignorepat
;
2004 int len
= strlen(word
);
2006 dupline
= strdup(line
);
2008 ast_log(LOG_WARNING
, "Out of free memory\n");
2013 strsep(&duplinet
, " ");
2014 strsep(&duplinet
, " ");
2015 ignorepat
= strsep(&duplinet
, " ");
2022 if (ast_rdlock_contexts()) {
2023 ast_log(LOG_WARNING
, "Failed to lock contexts list\n");
2028 for (c
= NULL
; !ret
&& (c
= ast_walk_contexts(c
)); ) {
2029 if (ast_lock_context(c
)) /* fail, skip it */
2031 if (!partial_match(ast_get_context_name(c
), word
, len
))
2033 if (lookup_c_ip(c
, ignorepat
) && ++which
> state
)
2034 ret
= strdup(ast_get_context_name(c
));
2035 ast_unlock_context(c
);
2037 ast_unlock_contexts();
2045 static char *complete_context_remove_ignorepat(const char *line
, const char *word
,
2048 struct ast_context
*c
;
2053 int len
= strlen(word
);
2054 if (ast_rdlock_contexts()) {
2055 ast_log(LOG_WARNING
, "Failed to lock contexts list\n");
2059 for (c
= NULL
; !ret
&& (c
= ast_walk_contexts(c
));) {
2060 struct ast_ignorepat
*ip
;
2062 if (ast_lock_context(c
)) /* error, skip it */
2065 for (ip
= NULL
; !ret
&& (ip
= ast_walk_context_ignorepats(c
, ip
));) {
2066 if (partial_match(ast_get_ignorepat_name(ip
), word
, len
) && ++which
> state
) {
2068 struct ast_context
*cw
= NULL
;
2070 while ( (cw
= ast_walk_contexts(cw
)) && cw
!= c
&& !found
) {
2071 /* XXX do i stop on c, or skip it ? */
2072 found
= lookup_c_ip(cw
, ast_get_ignorepat_name(ip
));
2075 ret
= strdup(ast_get_ignorepat_name(ip
));
2078 ast_unlock_context(c
);
2080 ast_unlock_contexts();
2082 } else if (pos
== 4) {
2083 return state
== 0 ? strdup("from") : NULL
;
2084 } else if (pos
== 5) { /* XXX check this */
2085 char *dupline
, *duplinet
, *ignorepat
;
2086 int len
= strlen(word
);
2088 dupline
= strdup(line
);
2090 ast_log(LOG_WARNING
, "Out of free memory\n");
2095 strsep(&duplinet
, " ");
2096 strsep(&duplinet
, " ");
2097 ignorepat
= strsep(&duplinet
, " ");
2104 if (ast_rdlock_contexts()) {
2105 ast_log(LOG_WARNING
, "Failed to lock contexts list\n");
2110 for (c
= NULL
; !ret
&& (c
= ast_walk_contexts(c
)); ) {
2111 if (ast_lock_context(c
)) /* fail, skip it */
2113 if (!partial_match(ast_get_context_name(c
), word
, len
))
2115 if (lookup_c_ip(c
, ignorepat
) && ++which
> state
)
2116 ret
= strdup(ast_get_context_name(c
));
2117 ast_unlock_context(c
);
2119 ast_unlock_contexts();
2127 static int pbx_load_module(void);
2129 static int handle_reload_extensions(int fd
, int argc
, char *argv
[])
2132 return RESULT_SHOWUSAGE
;
2133 if (clearglobalvars_config
)
2134 pbx_builtin_clear_globals();
2136 ast_cli(fd
, "Dialplan reloaded.\n");
2137 return RESULT_SUCCESS
;
2141 * CLI entries for commands provided by this module
2143 static struct ast_cli_entry cli_dont_include_deprecated
= {
2144 { "dont", "include", NULL
},
2145 handle_context_dont_include_deprecated
, NULL
,
2146 NULL
, complete_context_dont_include_deprecated
};
2148 static struct ast_cli_entry cli_remove_extension_deprecated
= {
2149 { "remove", "extension", NULL
},
2150 handle_context_remove_extension_deprecated
, NULL
,
2151 NULL
, complete_context_remove_extension_deprecated
};
2153 static struct ast_cli_entry cli_include_context_deprecated
= {
2154 { "include", "context", NULL
},
2155 handle_context_add_include_deprecated
, NULL
,
2156 NULL
, complete_context_add_include_deprecated
};
2158 static struct ast_cli_entry cli_add_extension_deprecated
= {
2159 { "add", "extension", NULL
},
2160 handle_context_add_extension_deprecated
, NULL
,
2161 NULL
, complete_context_add_extension_deprecated
};
2163 static struct ast_cli_entry cli_add_ignorepat_deprecated
= {
2164 { "add", "ignorepat", NULL
},
2165 handle_context_add_ignorepat_deprecated
, NULL
,
2166 NULL
, complete_context_add_ignorepat_deprecated
};
2168 static struct ast_cli_entry cli_remove_ignorepat_deprecated
= {
2169 { "remove", "ignorepat", NULL
},
2170 handle_context_remove_ignorepat_deprecated
, NULL
,
2171 NULL
, complete_context_remove_ignorepat_deprecated
};
2173 static struct ast_cli_entry cli_extensions_reload_deprecated
= {
2174 { "extensions", "reload", NULL
},
2175 handle_reload_extensions
, NULL
,
2178 static struct ast_cli_entry cli_save_dialplan_deprecated
= {
2179 { "save", "dialplan", NULL
},
2180 handle_save_dialplan
, NULL
,
2183 static struct ast_cli_entry cli_pbx_config
[] = {
2184 { { "dialplan", "add", "extension", NULL
},
2185 handle_context_add_extension
, "Add new extension into context",
2186 context_add_extension_help
, complete_context_add_extension
, &cli_add_extension_deprecated
},
2188 { { "dialplan", "remove", "extension", NULL
},
2189 handle_context_remove_extension
, "Remove a specified extension",
2190 context_remove_extension_help
, complete_context_remove_extension
, &cli_remove_extension_deprecated
},
2192 { { "dialplan", "add", "ignorepat", NULL
},
2193 handle_context_add_ignorepat
, "Add new ignore pattern",
2194 context_add_ignorepat_help
, complete_context_add_ignorepat
, &cli_add_ignorepat_deprecated
},
2196 { { "dialplan", "remove", "ignorepat", NULL
},
2197 handle_context_remove_ignorepat
, "Remove ignore pattern from context",
2198 context_remove_ignorepat_help
, complete_context_remove_ignorepat
, &cli_remove_ignorepat_deprecated
},
2200 { { "dialplan", "add", "include", NULL
},
2201 handle_context_add_include
, "Include context in other context",
2202 context_add_include_help
, complete_context_add_include
, &cli_include_context_deprecated
},
2204 { { "dialplan", "remove", "include", NULL
},
2205 handle_context_remove_include
, "Remove a specified include from context",
2206 context_remove_include_help
, complete_context_remove_include
, &cli_dont_include_deprecated
},
2208 { { "dialplan", "reload", NULL
},
2209 handle_reload_extensions
, "Reload extensions and *only* extensions",
2210 reload_extensions_help
, NULL
, &cli_extensions_reload_deprecated
},
2214 static struct ast_cli_entry cli_dialplan_save
= {
2215 { "dialplan", "save", NULL
},
2216 handle_save_dialplan
, "Save dialplan",
2217 save_dialplan_help
, NULL
, &cli_save_dialplan_deprecated
};
2220 * Standard module functions ...
2222 static int unload_module(void)
2224 if (static_config
&& !write_protect_config
)
2225 ast_cli_unregister(&cli_dialplan_save
);
2226 ast_cli_unregister_multiple(cli_pbx_config
, sizeof(cli_pbx_config
) / sizeof(struct ast_cli_entry
));
2227 ast_context_destroy(NULL
, registrar
);
2231 static int pbx_load_config(const char *config_file
)
2233 struct ast_config
*cfg
;
2236 char realvalue
[256];
2238 struct ast_context
*con
;
2239 struct ast_variable
*v
;
2243 cfg
= ast_config_load(config_file
);
2247 /* Use existing config to populate the PBX table */
2248 static_config
= ast_true(ast_variable_retrieve(cfg
, "general", "static"));
2249 write_protect_config
= ast_true(ast_variable_retrieve(cfg
, "general", "writeprotect"));
2250 if ((aft
= ast_variable_retrieve(cfg
, "general", "autofallthrough")))
2251 autofallthrough_config
= ast_true(aft
);
2252 clearglobalvars_config
= ast_true(ast_variable_retrieve(cfg
, "general", "clearglobalvars"));
2253 ast_set2_flag(&ast_options
, ast_true(ast_variable_retrieve(cfg
, "general", "priorityjumping")), AST_OPT_FLAG_PRIORITY_JUMPING
);
2255 if ((cxt
= ast_variable_retrieve(cfg
, "general", "userscontext")))
2256 ast_copy_string(userscontext
, cxt
, sizeof(userscontext
));
2258 ast_copy_string(userscontext
, "default", sizeof(userscontext
));
2260 for (v
= ast_variable_browse(cfg
, "globals"); v
; v
= v
->next
) {
2261 memset(realvalue
, 0, sizeof(realvalue
));
2262 pbx_substitute_variables_helper(NULL
, v
->value
, realvalue
, sizeof(realvalue
) - 1);
2263 pbx_builtin_setvar_helper(NULL
, v
->name
, realvalue
);
2265 for (cxt
= NULL
; (cxt
= ast_category_browse(cfg
, cxt
)); ) {
2266 /* All categories but "general" or "globals" are considered contexts */
2267 if (!strcasecmp(cxt
, "general") || !strcasecmp(cxt
, "globals"))
2269 con
=ast_context_find_or_create(&local_contexts
,cxt
, registrar
);
2273 for (v
= ast_variable_browse(cfg
, cxt
); v
; v
= v
->next
) {
2274 if (!strcasecmp(v
->name
, "exten")) {
2275 char *tc
= ast_strdup(v
->value
);
2278 char realext
[256]="";
2279 char *plus
, *firstp
, *firstc
;
2280 char *pri
, *appl
, *data
, *cidmatch
;
2282 char *ext
= strsep(&stringp
, ",");
2285 pbx_substitute_variables_helper(NULL
, ext
, realext
, sizeof(realext
) - 1);
2286 cidmatch
= strchr(realext
, '/');
2289 ast_shrink_phone_number(cidmatch
);
2291 pri
= strsep(&stringp
, ",");
2294 pri
= ast_skip_blanks(pri
);
2295 pri
= ast_trim_blanks(pri
);
2296 label
= strchr(pri
, '(');
2299 end
= strchr(label
, ')');
2303 ast_log(LOG_WARNING
, "Label missing trailing ')' at line %d\n", v
->lineno
);
2305 plus
= strchr(pri
, '+');
2308 if (!strcmp(pri
,"hint"))
2310 else if (!strcmp(pri
, "next") || !strcmp(pri
, "n")) {
2314 ast_log(LOG_WARNING
, "Can't use 'next' priority on the first entry!\n");
2315 } else if (!strcmp(pri
, "same") || !strcmp(pri
, "s")) {
2319 ast_log(LOG_WARNING
, "Can't use 'same' priority on the first entry!\n");
2320 } else if (sscanf(pri
, "%d", &ipri
) != 1 &&
2321 (ipri
= ast_findlabel_extension2(NULL
, con
, realext
, pri
, cidmatch
)) < 1) {
2322 ast_log(LOG_WARNING
, "Invalid priority/label '%s' at line %d\n", pri
, v
->lineno
);
2325 appl
= S_OR(stringp
, "");
2326 /* Find the first occurrence of either '(' or ',' */
2327 firstc
= strchr(appl
, ',');
2328 firstp
= strchr(appl
, '(');
2329 if (firstc
&& (!firstp
|| firstc
< firstp
)) {
2330 /* comma found, no parenthesis */
2331 /* or both found, but comma found first */
2332 appl
= strsep(&stringp
, ",");
2334 } else if (!firstc
&& !firstp
) {
2338 /* Final remaining case is parenthesis found first */
2339 appl
= strsep(&stringp
, "(");
2341 end
= strrchr(data
, ')');
2342 if ((end
= strrchr(data
, ')'))) {
2345 ast_log(LOG_WARNING
, "No closing parenthesis found? '%s(%s'\n", appl
, data
);
2347 ast_process_quotes_and_slashes(data
, ',', '|');
2352 appl
= ast_skip_blanks(appl
);
2357 if (!ast_opt_dont_warn
&& !strcmp(realext
, "_."))
2358 ast_log(LOG_WARNING
, "The use of '_.' for an extension is strongly discouraged and can have unexpected behavior. Please use '_X.' instead at line %d\n", v
->lineno
);
2359 if (ast_add_extension2(con
, 0, realext
, ipri
, label
, cidmatch
, appl
, strdup(data
), ast_free
, registrar
)) {
2360 ast_log(LOG_WARNING
, "Unable to register extension at line %d\n", v
->lineno
);
2365 } else if (!strcasecmp(v
->name
, "include")) {
2366 memset(realvalue
, 0, sizeof(realvalue
));
2367 pbx_substitute_variables_helper(NULL
, v
->value
, realvalue
, sizeof(realvalue
) - 1);
2368 if (ast_context_add_include2(con
, realvalue
, registrar
))
2369 ast_log(LOG_WARNING
, "Unable to include context '%s' in context '%s'\n", v
->value
, cxt
);
2370 } else if (!strcasecmp(v
->name
, "ignorepat")) {
2371 memset(realvalue
, 0, sizeof(realvalue
));
2372 pbx_substitute_variables_helper(NULL
, v
->value
, realvalue
, sizeof(realvalue
) - 1);
2373 if (ast_context_add_ignorepat2(con
, realvalue
, registrar
))
2374 ast_log(LOG_WARNING
, "Unable to include ignorepat '%s' in context '%s'\n", v
->value
, cxt
);
2375 } else if (!strcasecmp(v
->name
, "switch") || !strcasecmp(v
->name
, "lswitch") || !strcasecmp(v
->name
, "eswitch")) {
2376 char *stringp
= realvalue
;
2379 memset(realvalue
, 0, sizeof(realvalue
));
2380 if (!strcasecmp(v
->name
, "switch"))
2381 pbx_substitute_variables_helper(NULL
, v
->value
, realvalue
, sizeof(realvalue
) - 1);
2383 ast_copy_string(realvalue
, v
->value
, sizeof(realvalue
));
2384 appl
= strsep(&stringp
, "/");
2385 data
= strsep(&stringp
, ""); /* XXX what for ? */
2388 if (ast_context_add_switch2(con
, appl
, data
, !strcasecmp(v
->name
, "eswitch"), registrar
))
2389 ast_log(LOG_WARNING
, "Unable to include switch '%s' in context '%s'\n", v
->value
, cxt
);
2393 ast_config_destroy(cfg
);
2397 static void append_interface(char *iface
, int maxlen
, char *add
)
2399 int len
= strlen(iface
);
2400 if (strlen(add
) + len
< maxlen
- 2) {
2401 if (strlen(iface
)) {
2403 strcpy(iface
+ len
+ 1, add
);
2409 static void pbx_load_users(void)
2411 struct ast_config
*cfg
;
2413 const char *dahdichan
;
2414 const char *hasexten
;
2421 int start
, finish
, x
;
2422 struct ast_context
*con
= NULL
;
2424 cfg
= ast_config_load("users.conf");
2428 for (cat
= ast_category_browse(cfg
, NULL
); cat
; cat
= ast_category_browse(cfg
, cat
)) {
2429 if (!strcasecmp(cat
, "general"))
2432 len
= sizeof(iface
);
2433 if (ast_true(ast_config_option(cfg
, cat
, "hassip"))) {
2434 snprintf(tmp
, sizeof(tmp
), "SIP/%s", cat
);
2435 append_interface(iface
, sizeof(iface
), tmp
);
2437 if (ast_true(ast_config_option(cfg
, cat
, "hasiax"))) {
2438 snprintf(tmp
, sizeof(tmp
), "IAX2/%s", cat
);
2439 append_interface(iface
, sizeof(iface
), tmp
);
2441 if (ast_true(ast_config_option(cfg
, cat
, "hash323"))) {
2442 snprintf(tmp
, sizeof(tmp
), "H323/%s", cat
);
2443 append_interface(iface
, sizeof(iface
), tmp
);
2445 hasexten
= ast_config_option(cfg
, cat
, "hasexten");
2446 if (hasexten
&& !ast_true(hasexten
))
2448 hasvoicemail
= ast_true(ast_config_option(cfg
, cat
, "hasvoicemail"));
2449 dahdichan
= ast_variable_retrieve(cfg
, cat
, "dahdichan");
2451 dahdichan
= ast_variable_retrieve(cfg
, "general", "dahdichan");
2453 /* no dahdichan, but look for zapchan too */
2454 dahdichan
= ast_variable_retrieve(cfg
, cat
, "zapchan");
2456 dahdichan
= ast_variable_retrieve(cfg
, "general", "zapchan");
2458 if (!ast_strlen_zero(dahdichan
)) {
2459 ast_log(LOG_WARNING
, "Use of zapchan in users.conf is deprecated. Please update configuration to use dahdichan instead.\n");
2462 if (!ast_strlen_zero(dahdichan
)) {
2463 ast_copy_string(zapcopy
, dahdichan
, sizeof(zapcopy
));
2465 chan
= strsep(&c
, ",");
2467 if (sscanf(chan
, "%d-%d", &start
, &finish
) == 2) {
2469 } else if (sscanf(chan
, "%d", &start
)) {
2473 start
= 0; finish
= 0;
2475 if (finish
< start
) {
2480 for (x
= start
; x
<= finish
; x
++) {
2481 snprintf(tmp
, sizeof(tmp
), "Zap/%d", x
);
2482 append_interface(iface
, sizeof(iface
), tmp
);
2484 chan
= strsep(&c
, ",");
2487 if (!ast_strlen_zero(iface
)) {
2488 /* Only create a context here when it is really needed. Otherwise default empty context
2489 created by pbx_config may conflict with the one explicitly created by pbx_ael */
2491 con
= ast_context_find_or_create(&local_contexts
, userscontext
, registrar
);
2494 ast_log(LOG_ERROR
, "Can't find/create user context '%s'\n", userscontext
);
2499 ast_add_extension2(con
, 0, cat
, -1, NULL
, NULL
, iface
, NULL
, NULL
, registrar
);
2500 /* If voicemail, use "stdexten" else use plain old dial */
2502 snprintf(tmp
, sizeof(tmp
), "stdexten|%s|${HINT}", cat
);
2503 ast_add_extension2(con
, 0, cat
, 1, NULL
, NULL
, "Macro", strdup(tmp
), ast_free
, registrar
);
2505 ast_add_extension2(con
, 0, cat
, 1, NULL
, NULL
, "Dial", strdup("${HINT}"), ast_free
, registrar
);
2509 ast_config_destroy(cfg
);
2512 static int pbx_load_module(void)
2514 struct ast_context
*con
;
2516 if(!pbx_load_config(config
))
2517 return AST_MODULE_LOAD_DECLINE
;
2521 ast_merge_contexts_and_delete(&local_contexts
, registrar
);
2523 for (con
= NULL
; (con
= ast_walk_contexts(con
));)
2524 ast_context_verify_includes(con
);
2526 pbx_set_autofallthrough(autofallthrough_config
);
2531 static int load_module(void)
2533 if (pbx_load_module())
2534 return AST_MODULE_LOAD_DECLINE
;
2536 if (static_config
&& !write_protect_config
)
2537 ast_cli_register(&cli_dialplan_save
);
2538 ast_cli_register_multiple(cli_pbx_config
, sizeof(cli_pbx_config
) / sizeof(struct ast_cli_entry
));
2543 static int reload(void)
2545 if (clearglobalvars_config
)
2546 pbx_builtin_clear_globals();
2551 AST_MODULE_INFO(ASTERISK_GPL_KEY
, AST_MODFLAG_DEFAULT
, "Text Extension Configuration",
2552 .load
= load_module
,
2553 .unload
= unload_module
,