1999-10-13 04:15:49 +00:00
/*
2005-09-14 20:46:50 +00:00
* Asterisk - - An open source telephony toolkit .
1999-10-13 04:15:49 +00:00
*
2006-04-11 21:18:27 +00:00
* Copyright ( C ) 1999 - 2006 , Digium , Inc .
1999-10-13 04:15:49 +00:00
*
2004-10-02 20:43:16 +00:00
* Mark Spencer < markster @ digium . com >
1999-10-13 04:15:49 +00:00
*
2005-09-14 20:46:50 +00:00
* See http : //www.asterisk.org for more information about
* the Asterisk project . Please do not directly contact
* any of the maintainers of this project for assistance ;
* the project provides a web site , mailing lists and IRC
* channels for your use .
*
1999-10-13 04:15:49 +00:00
* This program is free software , distributed under the terms of
2005-09-14 20:46:50 +00:00
* the GNU General Public License Version 2. See the LICENSE file
* at the top of the source tree .
*/
2005-10-24 20:12:06 +00:00
/*! \file
2005-09-14 20:46:50 +00:00
*
2005-10-24 20:12:06 +00:00
* \ brief Populate and remember extensions from static config file
2005-11-14 19:00:38 +00:00
*
2005-09-14 20:46:50 +00:00
*
1999-10-13 04:15:49 +00:00
*/
2006-06-07 18:54:56 +00:00
# include "asterisk.h"
ASTERISK_FILE_VERSION ( __FILE__ , " $Revision$ " )
2005-06-06 22:12:19 +00:00
# include <ctype.h>
2007-11-20 23:16:15 +00:00
# include "asterisk/paths.h" /* ast_config_AST_CONFIG_DIR */
2005-04-21 06:02:45 +00:00
# include "asterisk/pbx.h"
# include "asterisk/config.h"
# include "asterisk/module.h"
# include "asterisk/logger.h"
# include "asterisk/cli.h"
2007-11-22 03:50:04 +00:00
# include "asterisk/channel.h" /* AST_MAX_EXTENSION */
2005-04-21 06:02:45 +00:00
# include "asterisk/callerid.h"
1999-10-13 04:15:49 +00:00
static char * config = " extensions.conf " ;
2001-04-17 16:49:37 +00:00
static char * registrar = " pbx_config " ;
2006-09-16 23:53:58 +00:00
static char userscontext [ AST_MAX_EXTENSION ] = " default " ;
1999-10-13 04:15:49 +00:00
static int static_config = 0 ;
2001-09-12 21:29:54 +00:00
static int write_protect_config = 1 ;
2007-02-16 18:04:34 +00:00
static int autofallthrough_config = 1 ;
2005-06-03 02:27:08 +00:00
static int clearglobalvars_config = 0 ;
closes issue #11363; where the pattern _20x. buried in an included context, didn't match 2012; There were a small set of problems to fix: 1. I needed NOT to score patterns unless you are at the end of the data string. 2. Capital N,X,Z and small n,x,z are OK in patterns. I canonicalize the patterns in the trie to caps. 3. When a pattern ends with dot or exclamation, CANMATCH/MATCHMORE should always report this pattern, no matter the length. With this commit, I also supplied the wish of Luigi, where the user can select which pattern matching algorithm to use, the old (legacy) pattern matcher, or the new, trie based matcher. The OLD matcher is the default. A new [general] section variable, extenpatternmatchnew, is added to the extensions.conf, and the example config has it set to false. If true, the new matcher is used. In all other respects, the context/exten structs are the same; the tries and hashtabs are formed, but in the new mode the tries are not used. A new CLI command 'dialplan set extenpatternmatch true/false' is provided to allow switching at run time. I beg users that are forced to return to the old matcher to please report the reason in the bug tracker. Measured the speed benefit of the new matcher against an impossibly large context with 10,000 extensions: the new matcher is 374 times faster.
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@89547 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-11-24 21:00:26 +00:00
static int extenpatternmatchnew_config = 0 ;
2008-03-10 21:48:20 +00:00
static char * overrideswitch_config = NULL ;
1999-10-13 04:15:49 +00:00
2004-06-09 01:45:08 +00:00
AST_MUTEX_DEFINE_STATIC ( save_dialplan_lock ) ;
2001-09-12 21:29:54 +00:00
2003-07-14 15:33:21 +00:00
static struct ast_context * local_contexts = NULL ;
(closes issue #6002)
Reported by: rizzo
Tested by: murf
Proposal of the changes to be made, and then an announcement of how they were accomplished:
http://lists.digium.com/pipermail/asterisk-dev/2008-February/032065.html
and:
http://lists.digium.com/pipermail/asterisk-dev/2008-March/032124.html
Here is a recap, file by file, of what I have done:
pbx/pbx_config.c
pbx/pbx_ael.c
All funcs that were passed a ptr to the context list, now will ALSO be passed a hashtab ptr to the same set.
Why? because (for the time being), the dialplan is stored in both, to facilitate a quick, low-cost move to
hash-tables to speed up dialplan processing. If it was deemed necessary to pass the context LIST, well, it
is just as necessary to have the TABLE available. This is because the list/table in question might not be
the global one, but temporary ones we would use to stage the dialplan on, and then swap into the global
position when things are ready.
We now have one external function for apps to use, "ast_context_find_or_create()" instead of the pre-existing
"find" and "create", as all existing usages used both in tandem anyway.
pbx_config, and pbx_ael, will stage the reloaded dialplan into local lists and tables, and
then call merge_contexts_and_delete, which will merge (now) existing contexts and
priorities from other registrars into this local set by copying them. Then, merge_contexts_and_delete will
lock down the contexts, swap the lists and tables, and unlock (real quick), and then
destroy the old dialplan.
chan_sip.c
chan_iax.c
chan_skinny.c
All the channel drivers that would add regcontexts now use the ast_context_find_or_create now.
chan_sip also includes a small fix to get rid of warnings about removing priorities that never got entered.
apps/app_meetme.c
apps/app_dial.c
apps/app_queue.c
All the apps that added a context/exten/priority were also modified to use ast_context_find_or_create instead.
include/asterisk/pbx.h
ast_context_create() is removed. Find_or_create_ is the new method.
ast_context_find_or_create() interface gets the hashtab added.
ast_merge_contexts_and_delete() gets the local hashtab arg added.
ast_wrlock_contexts_version() is added so you can detect if someone else got a writelock between your readlocking and writelocking.
ast_hashtab_compare_contexts was made public for use in pbx_config/pbx_ael
ast_hashtab_hash_contexts was in like fashion make public.
include/asterisk/pval.h
ast_compile_ael2() interface changed to include the local hashtab table ptr.
main/features.c
For the sake of the parking context, we use ast_context_find_or_create().
main/pbx.c
I changed all the "tree" names to "table" instead. That's because the original
implementation was based on binary trees. (had a free library). Then I moved
to hashtabs. Now, the names move forward too.
refcount field added to contexts, so you can keep track of how many modules
wanted this context to exist.
Some log messages that are warnings were inflated from LOG_NOTICE to LOG_WARNING.
Added some calls to ast_verb(3,...) for debug messages
Lots of little mods to ast_context_remove_extension2, which is now excersized in ways
it was not previously; one definite bug fixed.
find_or_create was upgraded to handle both local lists/tables as well as the globals.
context_merge() was added to do the per-context merging of the old/present contexts/extens/prios into the new/proposed local list/tables
ast_merge_contexts_and_delete() was heavily modified.
ast_add_extension2() was also upgraded to handle changes.
the context_destroy() code was re-engineered to handle the new way of doing things,
by exten/prio instead of by context.
res/ael/pval.c
res/ael/ael.tab.c
res/ael/ael.tab.h
res/ael/ael.y
res/ael/ael_lex.c
res/ael/ael.flex
utils/ael_main.c
utils/extconf.c
utils/conf2ael.c
utils/Makefile
Had to change the interface to ast_compile_ael2(), to include the hashtab ptr.
This ended up involving several external apps. The main gotcha was I had to
include lock.h and hashtab.h in several places.
As a side note, I tested this stuff pretty thoroughly, I replicated the problems
originally reported by Luigi, and made triply sure that reloads worked, and everything
worked thru "stop gracefully". I found a and fixed a few bugs as I was merging into
trunk, that did not appear in my tests of bug6002.
How's this for verbose commit messages?
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@106757 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2008-03-07 18:57:57 +00:00
static struct ast_hashtab * local_table = NULL ;
2001-09-12 21:29:54 +00:00
/*
2007-10-11 19:03:06 +00:00
* Prototypes for our completion functions
2001-09-12 21:29:54 +00:00
*/
2007-10-11 19:03:06 +00:00
static char * complete_dialplan_remove_include ( struct ast_cli_args * ) ;
static char * complete_dialplan_add_include ( struct ast_cli_args * ) ;
static char * complete_dialplan_remove_ignorepat ( struct ast_cli_args * ) ;
static char * complete_dialplan_add_ignorepat ( struct ast_cli_args * ) ;
static char * complete_dialplan_remove_extension ( struct ast_cli_args * ) ;
static char * complete_dialplan_add_extension ( struct ast_cli_args * ) ;
2003-07-14 15:33:21 +00:00
2001-09-12 21:29:54 +00:00
/*
* Implementation of functions provided by this module
*/
2005-11-14 19:00:38 +00:00
/*!
2001-09-12 21:29:54 +00:00
* REMOVE INCLUDE command stuff
*/
2007-10-11 19:03:06 +00:00
static char * handle_cli_dialplan_remove_include ( struct ast_cli_entry * e , int cmd , struct ast_cli_args * a )
2006-09-18 19:54:18 +00:00
{
2007-10-11 19:03:06 +00:00
switch ( cmd ) {
case CLI_INIT :
e - > command = " dialplan remove include " ;
e - > usage =
" Usage: dialplan remove include <context> from <context> \n "
" Remove an included context from another context. \n " ;
return NULL ;
case CLI_GENERATE :
return complete_dialplan_remove_include ( a ) ;
}
2006-09-18 19:54:18 +00:00
2007-10-11 19:03:06 +00:00
if ( strcmp ( a - > argv [ 4 ] , " from " ) )
return CLI_SHOWUSAGE ;
2006-09-18 19:54:18 +00:00
2007-10-11 19:03:06 +00:00
if ( ! ast_context_remove_include ( a - > argv [ 5 ] , a - > argv [ 3 ] , registrar ) ) {
ast_cli ( a - > fd , " We are not including '%s' into '%s' now \n " ,
a - > argv [ 3 ] , a - > argv [ 5 ] ) ;
return CLI_SUCCESS ;
2006-09-18 19:54:18 +00:00
}
2007-10-11 19:03:06 +00:00
ast_cli ( a - > fd , " Failed to remove '%s' include from '%s' context \n " ,
a - > argv [ 3 ] , a - > argv [ 5 ] ) ;
return CLI_FAILURE ;
2006-09-18 19:54:18 +00:00
}
2006-03-28 22:44:55 +00:00
/*! \brief return true if 'name' is included by context c */
static int lookup_ci ( struct ast_context * c , const char * name )
{
struct ast_include * i = NULL ;
2007-02-28 20:46:01 +00:00
if ( ast_rdlock_context ( c ) ) /* error, skip */
2006-03-28 22:44:55 +00:00
return 0 ;
while ( ( i = ast_walk_context_includes ( c , i ) ) )
if ( ! strcmp ( name , ast_get_include_name ( i ) ) )
break ;
ast_unlock_context ( c ) ;
return i ? - 1 /* success */ : 0 ;
}
/*! \brief return true if 'name' is in the ignorepats for context c */
static int lookup_c_ip ( struct ast_context * c , const char * name )
{
struct ast_ignorepat * ip = NULL ;
2007-02-28 20:46:01 +00:00
if ( ast_rdlock_context ( c ) ) /* error, skip */
2006-03-28 22:44:55 +00:00
return 0 ;
while ( ( ip = ast_walk_context_ignorepats ( c , ip ) ) )
if ( ! strcmp ( name , ast_get_ignorepat_name ( ip ) ) )
break ;
ast_unlock_context ( c ) ;
return ip ? - 1 /* success */ : 0 ;
}
/*! \brief moves to the n-th word in the string, or empty string if none */
static const char * skip_words ( const char * p , int n )
{
int in_blank = 0 ;
for ( ; n & & * p ; p + + ) {
if ( isblank ( * p ) /* XXX order is important */ & & ! in_blank ) {
n - - ; /* one word is gone */
in_blank = 1 ;
} else if ( /* !is_blank(*p), we know already, && */ in_blank ) {
in_blank = 0 ;
}
}
return p ;
}
/*! \brief match the first 'len' chars of word. len==0 always succeeds */
static int partial_match ( const char * s , const char * word , int len )
{
return ( len = = 0 | | ! strncmp ( s , word , len ) ) ;
}
2006-05-09 16:24:07 +00:00
/*! \brief split extension\@context in two parts, return -1 on error.
2006-03-28 22:44:55 +00:00
* The return string is malloc ' ed and pointed by * ext
*/
static int split_ec ( const char * src , char * * ext , char * * const ctx )
{
char * c , * e = ast_strdup ( src ) ; /* now src is not used anymore */
if ( e = = NULL )
return - 1 ; /* malloc error */
/* now, parse values from 'exten@context' */
* ext = e ;
c = strchr ( e , ' @ ' ) ;
if ( c = = NULL ) /* no context part */
* ctx = " " ; /* it is not overwritten, anyways */
else { /* found context, check for duplicity ... */
* c + + = ' \0 ' ;
* ctx = c ;
if ( strchr ( c , ' @ ' ) ) { /* two @, not allowed */
free ( e ) ;
return - 1 ;
}
}
return 0 ;
}
/* _X_ is the string we need to complete */
2007-10-11 19:03:06 +00:00
static char * complete_dialplan_remove_include ( struct ast_cli_args * a )
2006-09-18 19:54:18 +00:00
{
int which = 0 ;
char * res = NULL ;
2007-10-11 19:03:06 +00:00
int len = strlen ( a - > word ) ; /* how many bytes to match */
2006-09-18 19:54:18 +00:00
struct ast_context * c = NULL ;
2007-10-11 19:03:06 +00:00
if ( a - > pos = = 3 ) { /* "dialplan remove include _X_" */
2007-02-28 20:46:01 +00:00
if ( ast_wrlock_contexts ( ) ) {
2006-09-18 19:54:18 +00:00
ast_log ( LOG_ERROR , " Failed to lock context list \n " ) ;
return NULL ;
}
/* walk contexts and their includes, return the n-th match */
while ( ! res & & ( c = ast_walk_contexts ( c ) ) ) {
struct ast_include * i = NULL ;
2007-02-28 20:46:01 +00:00
if ( ast_rdlock_context ( c ) ) /* error ? skip this one */
2006-09-18 19:54:18 +00:00
continue ;
while ( ! res & & ( i = ast_walk_context_includes ( c , i ) ) ) {
const char * i_name = ast_get_include_name ( i ) ;
struct ast_context * nc = NULL ;
int already_served = 0 ;
2007-10-11 19:03:06 +00:00
if ( ! partial_match ( i_name , a - > word , len ) )
2006-09-18 19:54:18 +00:00
continue ; /* not matched */
/* check if this include is already served or not */
/* go through all contexts again till we reach actual
* context or already_served = 1
*/
while ( ( nc = ast_walk_contexts ( nc ) ) & & nc ! = c & & ! already_served )
already_served = lookup_ci ( nc , i_name ) ;
2007-10-11 19:03:06 +00:00
if ( ! already_served & & + + which > a - > n )
2006-09-18 19:54:18 +00:00
res = strdup ( i_name ) ;
}
ast_unlock_context ( c ) ;
}
ast_unlock_contexts ( ) ;
return res ;
2007-10-11 19:03:06 +00:00
} else if ( a - > pos = = 4 ) { /* "dialplan remove include CTX _X_" */
2006-09-18 19:54:18 +00:00
/*
* complete as ' from ' , but only if previous context is really
* included somewhere
*/
char * context , * dupline ;
2007-10-11 19:03:06 +00:00
const char * s = skip_words ( a - > line , 3 ) ; /* skip 'dialplan' 'remove' 'include' */
2006-09-18 19:54:18 +00:00
2007-10-11 19:03:06 +00:00
if ( a - > n > 0 )
2006-09-18 19:54:18 +00:00
return NULL ;
context = dupline = strdup ( s ) ;
if ( ! dupline ) {
ast_log ( LOG_ERROR , " Out of free memory \n " ) ;
return NULL ;
}
strsep ( & dupline , " " ) ;
2007-02-28 20:46:01 +00:00
if ( ast_rdlock_contexts ( ) ) {
2006-09-18 19:54:18 +00:00
ast_log ( LOG_ERROR , " Failed to lock contexts list \n " ) ;
free ( context ) ;
return NULL ;
}
/* go through all contexts and check if is included ... */
while ( ! res & & ( c = ast_walk_contexts ( c ) ) )
if ( lookup_ci ( c , context ) ) /* context is really included, complete "from" command */
res = strdup ( " from " ) ;
ast_unlock_contexts ( ) ;
if ( ! res )
ast_log ( LOG_WARNING , " %s not included anywhere \n " , context ) ;
free ( context ) ;
return res ;
2007-10-11 19:03:06 +00:00
} else if ( a - > pos = = 5 ) { /* "dialplan remove include CTX from _X_" */
2006-09-18 19:54:18 +00:00
/*
* Context from which we removing include . . .
*/
char * context , * dupline , * from ;
2007-10-11 19:03:06 +00:00
const char * s = skip_words ( a - > line , 3 ) ; /* skip 'dialplan' 'remove' 'include' */
2006-09-18 19:54:18 +00:00
context = dupline = strdup ( s ) ;
if ( ! dupline ) {
ast_log ( LOG_ERROR , " Out of free memory \n " ) ;
return NULL ;
}
strsep ( & dupline , " " ) ; /* skip context */
/* fourth word must be 'from' */
from = strsep ( & dupline , " " ) ;
if ( ! from | | strcmp ( from , " from " ) ) {
free ( context ) ;
return NULL ;
}
2007-02-28 20:46:01 +00:00
if ( ast_rdlock_contexts ( ) ) {
2006-09-18 19:54:18 +00:00
ast_log ( LOG_ERROR , " Failed to lock context list \n " ) ;
free ( context ) ;
return NULL ;
}
/* walk through all contexts ... */
c = NULL ;
while ( ! res & & ( c = ast_walk_contexts ( c ) ) ) {
const char * c_name = ast_get_context_name ( c ) ;
2007-10-11 19:03:06 +00:00
if ( ! partial_match ( c_name , a - > word , len ) ) /* not a good target */
2006-09-18 19:54:18 +00:00
continue ;
/* walk through all includes and check if it is our context */
2007-10-11 19:03:06 +00:00
if ( lookup_ci ( c , context ) & & + + which > a - > n )
2006-09-18 19:54:18 +00:00
res = strdup ( c_name ) ;
}
ast_unlock_contexts ( ) ;
free ( context ) ;
return res ;
}
return NULL ;
}
2005-11-14 19:00:38 +00:00
/*!
2001-09-12 21:29:54 +00:00
* REMOVE EXTENSION command stuff
*/
2007-10-11 19:03:06 +00:00
static char * handle_cli_dialplan_remove_extension ( struct ast_cli_entry * e , int cmd , struct ast_cli_args * a )
2006-09-18 19:54:18 +00:00
{
int removing_priority = 0 ;
char * exten , * context ;
2007-10-11 19:03:06 +00:00
char * ret = CLI_FAILURE ;
switch ( cmd ) {
case CLI_INIT :
e - > command = " dialplan remove extension " ;
e - > usage =
" Usage: dialplan remove extension exten@context [priority] \n "
" Remove an extension from a given context. If a priority \n "
" is given, only that specific priority from the given extension \n "
" will be removed. \n " ;
return NULL ;
case CLI_GENERATE :
return complete_dialplan_remove_extension ( a ) ;
}
2006-09-18 19:54:18 +00:00
2007-10-11 19:03:06 +00:00
if ( a - > argc ! = 5 & & a - > argc ! = 4 )
return CLI_SHOWUSAGE ;
2006-09-18 19:54:18 +00:00
/*
* Priority input checking . . .
*/
2007-10-11 19:03:06 +00:00
if ( a - > argc = = 5 ) {
char * c = a - > argv [ 4 ] ;
2006-09-18 19:54:18 +00:00
/* check for digits in whole parameter for right priority ...
* why ? because atoi ( strtol ) returns 0 if any characters in
* string and whole extension will be removed , it ' s not good
*/
if ( ! strcmp ( " hint " , c ) )
removing_priority = PRIORITY_HINT ;
else {
while ( * c & & isdigit ( * c ) )
c + + ;
if ( * c ) { /* non-digit in string */
2007-10-11 19:03:06 +00:00
ast_cli ( a - > fd , " Invalid priority '%s' \n " , a - > argv [ 4 ] ) ;
return CLI_FAILURE ;
2006-09-18 19:54:18 +00:00
}
2007-10-11 19:03:06 +00:00
removing_priority = atoi ( a - > argv [ 4 ] ) ;
2006-09-18 19:54:18 +00:00
}
if ( removing_priority = = 0 ) {
2007-10-11 19:03:06 +00:00
ast_cli ( a - > fd , " If you want to remove whole extension, please " \
2006-09-18 19:54:18 +00:00
" omit priority argument \n " ) ;
2007-10-11 19:03:06 +00:00
return CLI_FAILURE ;
2006-09-18 19:54:18 +00:00
}
}
/* XXX original overwrote argv[3] */
/*
* Format exten @ context checking . . .
*/
2007-10-11 19:03:06 +00:00
if ( split_ec ( a - > argv [ 3 ] , & exten , & context ) )
return CLI_FAILURE ; /* XXX malloc failure */
2006-09-18 19:54:18 +00:00
if ( ( ! strlen ( exten ) ) | | ( ! ( strlen ( context ) ) ) ) {
2007-10-11 19:03:06 +00:00
ast_cli ( a - > fd , " Missing extension or context name in third argument '%s' \n " ,
a - > argv [ 3 ] ) ;
2006-09-18 19:54:18 +00:00
free ( exten ) ;
2007-10-11 19:03:06 +00:00
return CLI_FAILURE ;
2006-09-18 19:54:18 +00:00
}
if ( ! ast_context_remove_extension ( context , exten , removing_priority , registrar ) ) {
if ( ! removing_priority )
2007-10-11 19:03:06 +00:00
ast_cli ( a - > fd , " Whole extension %s@%s removed \n " ,
2006-09-18 19:54:18 +00:00
exten , context ) ;
else
2007-10-11 19:03:06 +00:00
ast_cli ( a - > fd , " Extension %s@%s with priority %d removed \n " ,
2006-09-18 19:54:18 +00:00
exten , context , removing_priority ) ;
2007-10-11 19:03:06 +00:00
ret = CLI_SUCCESS ;
2006-09-18 19:54:18 +00:00
} else {
2007-10-11 19:03:06 +00:00
ast_cli ( a - > fd , " Failed to remove extension %s@%s \n " , exten , context ) ;
ret = CLI_FAILURE ;
2006-09-18 19:54:18 +00:00
}
free ( exten ) ;
return ret ;
}
2001-09-12 21:29:54 +00:00
# define BROKEN_READLINE 1
# ifdef BROKEN_READLINE
/*
* There is one funny thing , when you have word like 300 @ and you hit
* < tab > , you arguments will like as your word is ' 300 ' , so it ' @ '
* characters acts sometimes as word delimiter and sometimes as a part
* of word
*
* This fix function , allocates new word variable and store here every
* time xxx @ yyy always as one word and correct pos is set too
*
* It ' s ugly , I know , but I ' m waiting for Mark suggestion if upper is
* bug or feature . . .
*/
2006-01-18 22:17:31 +00:00
static int fix_complete_args ( const char * line , char * * word , int * pos )
2001-09-12 21:29:54 +00:00
{
char * _line , * _strsep_line , * _previous_word = NULL , * _word = NULL ;
int words = 0 ;
_line = strdup ( line ) ;
_strsep_line = _line ;
while ( _strsep_line ) {
_previous_word = _word ;
_word = strsep ( & _strsep_line , " " ) ;
if ( _word & & strlen ( _word ) ) words + + ;
}
if ( _word | | _previous_word ) {
if ( _word ) {
if ( ! strlen ( _word ) ) words + + ;
* word = strdup ( _word ) ;
} else
* word = strdup ( _previous_word ) ;
* pos = words - 1 ;
free ( _line ) ;
return 0 ;
}
free ( _line ) ;
return - 1 ;
}
# endif /* BROKEN_READLINE */
2007-10-11 19:03:06 +00:00
static char * complete_dialplan_remove_extension ( struct ast_cli_args * a )
2001-09-12 21:29:54 +00:00
{
2004-05-03 04:38:31 +00:00
char * ret = NULL ;
2001-09-12 21:29:54 +00:00
int which = 0 ;
# ifdef BROKEN_READLINE
2006-03-28 22:44:55 +00:00
char * word2 ;
2001-09-12 21:29:54 +00:00
/*
* Fix arguments , * word is a new allocated structure , REMEMBER to
* free * word when you want to return from this function . . .
*/
2007-10-11 19:03:06 +00:00
if ( fix_complete_args ( a - > line , & word2 , & a - > pos ) ) {
2001-09-12 21:29:54 +00:00
ast_log ( LOG_ERROR , " Out of free memory \n " ) ;
return NULL ;
}
2007-10-11 19:03:06 +00:00
a - > word = word2 ;
2001-09-12 21:29:54 +00:00
# endif
2007-10-11 19:03:06 +00:00
if ( a - > pos = = 3 ) { /* 'dialplan remove extension _X_' (exten@context ... */
2006-03-28 22:44:55 +00:00
struct ast_context * c = NULL ;
char * context = NULL , * exten = NULL ;
int le = 0 ; /* length of extension */
int lc = 0 ; /* length of context */
2001-09-12 21:29:54 +00:00
2007-10-11 19:03:06 +00:00
lc = split_ec ( a - > word , & exten , & context ) ;
2001-09-12 21:29:54 +00:00
# ifdef BROKEN_READLINE
2006-03-28 22:44:55 +00:00
free ( word2 ) ;
2001-09-12 21:29:54 +00:00
# endif
2006-03-28 22:44:55 +00:00
if ( lc ) /* error */
return NULL ;
le = strlen ( exten ) ;
lc = strlen ( context ) ;
2001-09-12 21:29:54 +00:00
2007-02-28 20:46:01 +00:00
if ( ast_rdlock_contexts ( ) ) {
2001-09-12 21:29:54 +00:00
ast_log ( LOG_ERROR , " Failed to lock context list \n " ) ;
2006-03-28 22:44:55 +00:00
goto error2 ;
2001-09-12 21:29:54 +00:00
}
/* find our context ... */
2006-03-28 22:44:55 +00:00
while ( ( c = ast_walk_contexts ( c ) ) ) { /* match our context if any */
struct ast_exten * e = NULL ;
/* XXX locking ? */
if ( ! partial_match ( ast_get_context_name ( c ) , context , lc ) )
continue ; /* context not matched */
while ( ( e = ast_walk_context_extensions ( c , e ) ) ) { /* try to complete extensions ... */
2007-10-11 19:03:06 +00:00
if ( partial_match ( ast_get_extension_name ( e ) , exten , le ) & & + + which > a - > n ) { /* n-th match */
2006-03-28 22:44:55 +00:00
/* If there is an extension then return exten@context. XXX otherwise ? */
if ( exten )
asprintf ( & ret , " %s@%s " , ast_get_extension_name ( e ) , ast_get_context_name ( c ) ) ;
break ;
2001-09-12 21:29:54 +00:00
}
}
2006-03-28 22:44:55 +00:00
if ( e ) /* got a match */
break ;
2001-09-12 21:29:54 +00:00
}
ast_unlock_contexts ( ) ;
2006-03-28 22:44:55 +00:00
error2 :
if ( exten )
free ( exten ) ;
2007-10-11 19:03:06 +00:00
} else if ( a - > pos = = 4 ) { /* 'dialplan remove extension EXT _X_' (priority) */
2006-03-28 22:44:55 +00:00
char * exten = NULL , * context , * p ;
2001-09-12 21:29:54 +00:00
struct ast_context * c ;
2006-03-28 22:44:55 +00:00
int le , lc , len ;
2007-10-11 19:03:06 +00:00
const char * s = skip_words ( a - > line , 3 ) ; /* skip 'dialplan' 'remove' 'extension' */
2006-03-28 22:44:55 +00:00
int i = split_ec ( s , & exten , & context ) ; /* parse ext@context */
if ( i ) /* error */
goto error3 ;
if ( ( p = strchr ( exten , ' ' ) ) ) /* remove space after extension */
* p = ' \0 ' ;
if ( ( p = strchr ( context , ' ' ) ) ) /* remove space after context */
* p = ' \0 ' ;
le = strlen ( exten ) ;
lc = strlen ( context ) ;
2007-10-11 19:03:06 +00:00
len = strlen ( a - > word ) ;
2006-03-28 22:44:55 +00:00
if ( le = = 0 | | lc = = 0 )
goto error3 ;
2001-09-12 21:29:54 +00:00
2007-02-28 20:46:01 +00:00
if ( ast_rdlock_contexts ( ) ) {
2001-09-12 21:29:54 +00:00
ast_log ( LOG_ERROR , " Failed to lock context list \n " ) ;
2006-03-28 22:44:55 +00:00
goto error3 ;
2001-09-12 21:29:54 +00:00
}
/* walk contexts */
2006-03-28 22:44:55 +00:00
c = NULL ;
while ( ( c = ast_walk_contexts ( c ) ) ) {
/* XXX locking on c ? */
struct ast_exten * e ;
if ( strcmp ( ast_get_context_name ( c ) , context ) ! = 0 )
continue ;
/* got it, we must match here */
e = NULL ;
while ( ( e = ast_walk_context_extensions ( c , e ) ) ) {
struct ast_exten * priority ;
char buffer [ 10 ] ;
2001-09-12 21:29:54 +00:00
2006-03-28 22:44:55 +00:00
if ( strcmp ( ast_get_extension_name ( e ) , exten ) ! = 0 )
continue ;
/* XXX lock e ? */
priority = NULL ;
while ( ! ret & & ( priority = ast_walk_extension_priorities ( e , priority ) ) ) {
snprintf ( buffer , sizeof ( buffer ) , " %u " , ast_get_extension_priority ( priority ) ) ;
2007-10-11 19:03:06 +00:00
if ( partial_match ( buffer , a - > word , len ) & & + + which > a - > n ) /* n-th match */
2006-03-28 22:44:55 +00:00
ret = strdup ( buffer ) ;
2001-09-12 21:29:54 +00:00
}
2006-03-28 22:44:55 +00:00
break ;
2001-09-12 21:29:54 +00:00
}
2006-03-28 22:44:55 +00:00
break ;
2001-09-12 21:29:54 +00:00
}
ast_unlock_contexts ( ) ;
2006-03-28 22:44:55 +00:00
error3 :
if ( exten )
free ( exten ) ;
2001-09-12 21:29:54 +00:00
# ifdef BROKEN_READLINE
2006-03-28 22:44:55 +00:00
free ( word2 ) ;
2001-09-12 21:29:54 +00:00
# endif
2006-03-28 22:44:55 +00:00
}
return ret ;
2001-09-12 21:29:54 +00:00
}
2006-09-21 21:59:12 +00:00
/*!
* Include context . . .
*/
2007-10-11 19:03:06 +00:00
static char * handle_cli_dialplan_add_include ( struct ast_cli_entry * e , int cmd , struct ast_cli_args * a )
2001-09-12 21:29:54 +00:00
{
2007-10-11 19:03:06 +00:00
switch ( cmd ) {
case CLI_INIT :
e - > command = " dialplan add include " ;
e - > usage =
" Usage: dialplan add include <context> into <context> \n "
" Include a context in another context. \n " ;
return NULL ;
case CLI_GENERATE :
return complete_dialplan_add_include ( a ) ;
}
if ( a - > argc ! = 6 ) /* dialplan add include CTX in CTX */
return CLI_SHOWUSAGE ;
2001-09-12 21:29:54 +00:00
2006-09-21 21:59:12 +00:00
/* fifth arg must be 'into' ... */
2007-10-11 19:03:06 +00:00
if ( strcmp ( a - > argv [ 4 ] , " into " ) )
return CLI_SHOWUSAGE ;
2001-09-12 21:29:54 +00:00
2007-10-11 19:03:06 +00:00
if ( ast_context_add_include ( a - > argv [ 5 ] , a - > argv [ 3 ] , registrar ) ) {
2006-09-21 21:59:12 +00:00
switch ( errno ) {
case ENOMEM :
2007-10-11 19:03:06 +00:00
ast_cli ( a - > fd , " Out of memory for context addition \n " ) ;
2006-09-21 21:59:12 +00:00
break ;
2006-03-28 22:44:55 +00:00
2006-09-21 21:59:12 +00:00
case EBUSY :
2007-10-11 19:03:06 +00:00
ast_cli ( a - > fd , " Failed to lock context(s) list, please try again later \n " ) ;
2006-09-21 21:59:12 +00:00
break ;
2006-03-28 22:44:55 +00:00
2006-09-21 21:59:12 +00:00
case EEXIST :
2007-10-11 19:03:06 +00:00
ast_cli ( a - > fd , " Context '%s' already included in '%s' context \n " ,
a - > argv [ 3 ] , a - > argv [ 5 ] ) ;
2006-09-21 21:59:12 +00:00
break ;
case ENOENT :
case EINVAL :
2007-10-11 19:03:06 +00:00
ast_cli ( a - > fd , " There is no existence of context '%s' \n " ,
errno = = ENOENT ? a - > argv [ 5 ] : a - > argv [ 3 ] ) ;
2006-09-21 21:59:12 +00:00
break ;
default :
2007-10-11 19:03:06 +00:00
ast_cli ( a - > fd , " Failed to include '%s' in '%s' context \n " ,
a - > argv [ 3 ] , a - > argv [ 5 ] ) ;
2006-09-21 21:59:12 +00:00
break ;
2006-09-18 19:54:18 +00:00
}
2007-10-11 19:03:06 +00:00
return CLI_FAILURE ;
2006-09-21 21:59:12 +00:00
}
2006-09-18 19:54:18 +00:00
/* show some info ... */
2007-10-11 19:03:06 +00:00
ast_cli ( a - > fd , " Context '%s' included in '%s' context \n " ,
a - > argv [ 3 ] , a - > argv [ 5 ] ) ;
2006-09-18 19:54:18 +00:00
2007-10-11 19:03:06 +00:00
return CLI_SUCCESS ;
2006-09-18 19:54:18 +00:00
}
2007-10-11 19:03:06 +00:00
static char * complete_dialplan_add_include ( struct ast_cli_args * a )
2006-09-18 19:54:18 +00:00
{
struct ast_context * c ;
int which = 0 ;
char * ret = NULL ;
2007-10-11 19:03:06 +00:00
int len = strlen ( a - > word ) ;
2006-09-18 19:54:18 +00:00
2007-10-11 19:03:06 +00:00
if ( a - > pos = = 3 ) { /* 'dialplan add include _X_' (context) ... */
2007-02-28 20:46:01 +00:00
if ( ast_rdlock_contexts ( ) ) {
2006-09-18 19:54:18 +00:00
ast_log ( LOG_ERROR , " Failed to lock context list \n " ) ;
return NULL ;
}
for ( c = NULL ; ! ret & & ( c = ast_walk_contexts ( c ) ) ; )
2007-10-11 19:03:06 +00:00
if ( partial_match ( ast_get_context_name ( c ) , a - > word , len ) & & + + which > a - > n )
2006-09-18 19:54:18 +00:00
ret = strdup ( ast_get_context_name ( c ) ) ;
ast_unlock_contexts ( ) ;
return ret ;
2007-10-11 19:03:06 +00:00
} else if ( a - > pos = = 4 ) { /* dialplan add include CTX _X_ */
2006-09-18 19:54:18 +00:00
/* complete as 'into' if context exists or we are unable to check */
char * context , * dupline ;
struct ast_context * c ;
2007-10-11 19:03:06 +00:00
const char * s = skip_words ( a - > line , 3 ) ; /* should not fail */
2006-09-18 19:54:18 +00:00
2007-10-11 19:03:06 +00:00
if ( a - > n ! = 0 ) /* only once */
2006-09-18 19:54:18 +00:00
return NULL ;
/* parse context from line ... */
context = dupline = strdup ( s ) ;
if ( ! context ) {
ast_log ( LOG_ERROR , " Out of free memory \n " ) ;
return strdup ( " into " ) ;
}
strsep ( & dupline , " " ) ;
/* check for context existence ... */
2007-02-28 20:46:01 +00:00
if ( ast_rdlock_contexts ( ) ) {
2006-09-18 19:54:18 +00:00
ast_log ( LOG_ERROR , " Failed to lock context list \n " ) ;
/* our fault, we can't check, so complete 'into' ... */
ret = strdup ( " into " ) ;
} else {
for ( c = NULL ; ! ret & & ( c = ast_walk_contexts ( c ) ) ; )
if ( ! strcmp ( context , ast_get_context_name ( c ) ) )
ret = strdup ( " into " ) ; /* found */
ast_unlock_contexts ( ) ;
}
free ( context ) ;
return ret ;
2007-10-11 19:03:06 +00:00
} else if ( a - > pos = = 5 ) { /* 'dialplan add include CTX into _X_' (dst context) */
2006-09-18 19:54:18 +00:00
char * context , * dupline , * into ;
2007-10-11 19:03:06 +00:00
const char * s = skip_words ( a - > line , 3 ) ; /* should not fail */
2006-09-18 19:54:18 +00:00
context = dupline = strdup ( s ) ;
if ( ! dupline ) {
ast_log ( LOG_ERROR , " Out of free memory \n " ) ;
return NULL ;
}
strsep ( & dupline , " " ) ; /* skip context */
into = strsep ( & dupline , " " ) ;
/* error if missing context or fifth word is not 'into' */
if ( ! strlen ( context ) | | strcmp ( into , " into " ) ) {
ast_log ( LOG_ERROR , " bad context %s or missing into %s \n " ,
context , into ) ;
goto error3 ;
}
2007-02-28 20:46:01 +00:00
if ( ast_rdlock_contexts ( ) ) {
2006-09-18 19:54:18 +00:00
ast_log ( LOG_ERROR , " Failed to lock context list \n " ) ;
goto error3 ;
}
for ( c = NULL ; ( c = ast_walk_contexts ( c ) ) ; )
if ( ! strcmp ( context , ast_get_context_name ( c ) ) )
break ;
if ( c ) { /* first context exists, go on... */
/* go through all contexts ... */
for ( c = NULL ; ! ret & & ( c = ast_walk_contexts ( c ) ) ; ) {
if ( ! strcmp ( context , ast_get_context_name ( c ) ) )
continue ; /* skip ourselves */
2007-10-11 19:03:06 +00:00
if ( partial_match ( ast_get_context_name ( c ) , a - > word , len ) & &
2006-09-18 19:54:18 +00:00
! lookup_ci ( c , context ) /* not included yet */ & &
2007-10-11 19:03:06 +00:00
+ + which > a - > n )
2006-09-18 19:54:18 +00:00
ret = strdup ( ast_get_context_name ( c ) ) ;
}
} else {
ast_log ( LOG_ERROR , " context %s not found \n " , context ) ;
}
ast_unlock_contexts ( ) ;
error3 :
free ( context ) ;
return ret ;
}
return NULL ;
}
2005-11-14 19:00:38 +00:00
/*!
* \ brief ' save dialplan ' CLI command implementation functions . . .
2001-09-12 21:29:54 +00:00
*/
2007-10-11 19:03:06 +00:00
static char * handle_cli_dialplan_save ( struct ast_cli_entry * e , int cmd , struct ast_cli_args * a )
2001-09-12 21:29:54 +00:00
{
2008-03-10 21:48:20 +00:00
char filename [ 256 ] , overrideswitch [ 256 ] = " " ;
2001-09-12 21:29:54 +00:00
struct ast_context * c ;
2004-01-28 01:29:47 +00:00
struct ast_config * cfg ;
struct ast_variable * v ;
2001-09-12 21:29:54 +00:00
int incomplete = 0 ; /* incomplete config write? */
FILE * output ;
2007-08-16 21:09:46 +00:00
struct ast_flags config_flags = { 0 } ;
2006-03-28 22:44:55 +00:00
const char * base , * slash , * file ;
2007-10-11 19:03:06 +00:00
switch ( cmd ) {
case CLI_INIT :
e - > command = " dialplan save " ;
e - > usage =
" Usage: dialplan save [/path/to/extension/file] \n "
" Save dialplan created by pbx_config module. \n "
" \n "
" Example: dialplan save (/etc/asterisk/extensions.conf) \n "
" dialplan save /home/markster (/home/markster/extensions.conf) \n " ;
return NULL ;
case CLI_GENERATE :
return NULL ;
}
2001-09-12 21:29:54 +00:00
if ( ! ( static_config & & ! write_protect_config ) ) {
2007-10-11 19:03:06 +00:00
ast_cli ( a - > fd ,
2001-09-12 21:29:54 +00:00
" I can't save dialplan now, see '%s' example file. \n " ,
config ) ;
2007-10-11 19:03:06 +00:00
return CLI_FAILURE ;
2001-09-12 21:29:54 +00:00
}
2007-10-11 19:03:06 +00:00
if ( a - > argc ! = 2 & & a - > argc ! = 3 )
return CLI_SHOWUSAGE ;
2001-09-12 21:29:54 +00:00
2003-08-13 15:25:16 +00:00
if ( ast_mutex_lock ( & save_dialplan_lock ) ) {
2007-10-11 19:03:06 +00:00
ast_cli ( a - > fd ,
2001-09-12 21:29:54 +00:00
" Failed to lock dialplan saving (another proccess saving?) \n " ) ;
2007-10-11 19:03:06 +00:00
return CLI_FAILURE ;
2001-09-12 21:29:54 +00:00
}
2006-03-28 22:44:55 +00:00
/* XXX the code here is quite loose, a pathname with .conf in it
* is assumed to be a complete pathname
*/
2007-10-11 19:03:06 +00:00
if ( a - > argc = = 3 ) { /* have config path. Look for *.conf */
base = a - > argv [ 2 ] ;
if ( ! strstr ( a - > argv [ 2 ] , " .conf " ) ) { /*no, this is assumed to be a pathname */
2006-03-28 22:44:55 +00:00
/* if filename ends with '/', do not add one */
2007-10-11 19:03:06 +00:00
slash = ( * ( a - > argv [ 2 ] + strlen ( a - > argv [ 2 ] ) - 1 ) = = ' / ' ) ? " / " : " " ;
2006-03-28 22:44:55 +00:00
file = config ; /* default: 'extensions.conf' */
} else { /* yes, complete file name */
slash = " " ;
file = " " ;
}
} else {
2001-09-12 21:29:54 +00:00
/* no config file, default one */
2006-03-28 22:44:55 +00:00
base = ast_config_AST_CONFIG_DIR ;
slash = " / " ;
file = config ;
}
snprintf ( filename , sizeof ( filename ) , " %s%s%s " , base , slash , config ) ;
2001-09-12 21:29:54 +00:00
2007-08-16 21:09:46 +00:00
cfg = ast_config_load ( " extensions.conf " , config_flags ) ;
2004-01-28 01:29:47 +00:00
2001-09-12 21:29:54 +00:00
/* try to lock contexts list */
2007-02-28 20:46:01 +00:00
if ( ast_rdlock_contexts ( ) ) {
2007-10-11 19:03:06 +00:00
ast_cli ( a - > fd , " Failed to lock contexts list \n " ) ;
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & save_dialplan_lock ) ;
2005-01-25 06:10:20 +00:00
ast_config_destroy ( cfg ) ;
2007-10-11 19:03:06 +00:00
return CLI_FAILURE ;
2001-09-12 21:29:54 +00:00
}
/* create new file ... */
if ( ! ( output = fopen ( filename , " wt " ) ) ) {
2007-10-11 19:03:06 +00:00
ast_cli ( a - > fd , " Failed to create file '%s' \n " ,
2001-09-12 21:29:54 +00:00
filename ) ;
ast_unlock_contexts ( ) ;
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & save_dialplan_lock ) ;
2005-01-25 06:10:20 +00:00
ast_config_destroy ( cfg ) ;
2007-10-11 19:03:06 +00:00
return CLI_FAILURE ;
2001-09-12 21:29:54 +00:00
}
/* fireout general info */
2008-03-10 21:48:20 +00:00
if ( overrideswitch_config ) {
snprintf ( overrideswitch , sizeof ( overrideswitch ) , " overrideswitch=%s \n " , overrideswitch_config ) ;
}
fprintf ( output , " [general] \n static=%s \n writeprotect=%s \n autofallthrough=%s \n clearglobalvars=%s \n %sextenpatternmatchnew=%s \n \n " ,
2001-09-12 21:29:54 +00:00
static_config ? " yes " : " no " ,
2006-08-29 12:24:01 +00:00
write_protect_config ? " yes " : " no " ,
autofallthrough_config ? " yes " : " no " ,
closes issue #11363; where the pattern _20x. buried in an included context, didn't match 2012; There were a small set of problems to fix: 1. I needed NOT to score patterns unless you are at the end of the data string. 2. Capital N,X,Z and small n,x,z are OK in patterns. I canonicalize the patterns in the trie to caps. 3. When a pattern ends with dot or exclamation, CANMATCH/MATCHMORE should always report this pattern, no matter the length. With this commit, I also supplied the wish of Luigi, where the user can select which pattern matching algorithm to use, the old (legacy) pattern matcher, or the new, trie based matcher. The OLD matcher is the default. A new [general] section variable, extenpatternmatchnew, is added to the extensions.conf, and the example config has it set to false. If true, the new matcher is used. In all other respects, the context/exten structs are the same; the tries and hashtabs are formed, but in the new mode the tries are not used. A new CLI command 'dialplan set extenpatternmatch true/false' is provided to allow switching at run time. I beg users that are forced to return to the old matcher to please report the reason in the bug tracker. Measured the speed benefit of the new matcher against an impossibly large context with 10,000 extensions: the new matcher is 374 times faster.
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@89547 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-11-24 21:00:26 +00:00
clearglobalvars_config ? " yes " : " no " ,
2008-03-10 21:48:20 +00:00
overrideswitch_config ? overrideswitch : " " ,
closes issue #11363; where the pattern _20x. buried in an included context, didn't match 2012; There were a small set of problems to fix: 1. I needed NOT to score patterns unless you are at the end of the data string. 2. Capital N,X,Z and small n,x,z are OK in patterns. I canonicalize the patterns in the trie to caps. 3. When a pattern ends with dot or exclamation, CANMATCH/MATCHMORE should always report this pattern, no matter the length. With this commit, I also supplied the wish of Luigi, where the user can select which pattern matching algorithm to use, the old (legacy) pattern matcher, or the new, trie based matcher. The OLD matcher is the default. A new [general] section variable, extenpatternmatchnew, is added to the extensions.conf, and the example config has it set to false. If true, the new matcher is used. In all other respects, the context/exten structs are the same; the tries and hashtabs are formed, but in the new mode the tries are not used. A new CLI command 'dialplan set extenpatternmatch true/false' is provided to allow switching at run time. I beg users that are forced to return to the old matcher to please report the reason in the bug tracker. Measured the speed benefit of the new matcher against an impossibly large context with 10,000 extensions: the new matcher is 374 times faster.
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@89547 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-11-24 21:00:26 +00:00
extenpatternmatchnew_config ? " yes " : " no " ) ;
2001-09-12 21:29:54 +00:00
2004-01-28 01:29:47 +00:00
if ( ( v = ast_variable_browse ( cfg , " globals " ) ) ) {
fprintf ( output , " [globals] \n " ) ;
while ( v ) {
fprintf ( output , " %s => %s \n " , v - > name , v - > value ) ;
v = v - > next ;
}
fprintf ( output , " \n " ) ;
}
2005-01-25 06:10:20 +00:00
ast_config_destroy ( cfg ) ;
2004-01-28 01:29:47 +00:00
2006-03-28 22:44:55 +00:00
# define PUT_CTX_HDR do { \
if ( ! context_header_written ) { \
fprintf ( output , " [%s] \n " , ast_get_context_name ( c ) ) ; \
context_header_written = 1 ; \
} \
} while ( 0 )
2001-09-12 21:29:54 +00:00
/* walk all contexts */
2006-03-28 22:44:55 +00:00
for ( c = NULL ; ( c = ast_walk_contexts ( c ) ) ; ) {
int context_header_written = 0 ;
struct ast_exten * e , * last_written_e = NULL ;
struct ast_include * i ;
struct ast_ignorepat * ip ;
struct ast_sw * sw ;
2001-09-12 21:29:54 +00:00
2006-03-28 22:44:55 +00:00
/* try to lock context and fireout all info */
2007-02-28 20:46:01 +00:00
if ( ast_rdlock_context ( c ) ) { /* lock failure */
2006-03-28 22:44:55 +00:00
incomplete = 1 ;
continue ;
}
/* registered by this module? */
/* XXX do we need this ? */
if ( ! strcmp ( ast_get_context_registrar ( c ) , registrar ) ) {
fprintf ( output , " [%s] \n " , ast_get_context_name ( c ) ) ;
context_header_written = 1 ;
}
2001-09-12 21:29:54 +00:00
2006-03-28 22:44:55 +00:00
/* walk extensions ... */
for ( e = NULL ; ( e = ast_walk_context_extensions ( c , e ) ) ; ) {
struct ast_exten * p = NULL ;
2001-09-12 21:29:54 +00:00
2006-03-28 22:44:55 +00:00
/* fireout priorities */
while ( ( p = ast_walk_extension_priorities ( e , p ) ) ) {
if ( strcmp ( ast_get_extension_registrar ( p ) , registrar ) ! = 0 ) /* not this source */
continue ;
/* make empty line between different extensions */
if ( last_written_e ! = NULL & &
strcmp ( ast_get_extension_name ( last_written_e ) ,
ast_get_extension_name ( p ) ) )
fprintf ( output , " \n " ) ;
last_written_e = p ;
2001-09-12 21:29:54 +00:00
2006-03-28 22:44:55 +00:00
PUT_CTX_HDR ;
2007-10-11 19:03:06 +00:00
if ( ast_get_extension_priority ( p ) = = PRIORITY_HINT ) { /* easy */
2006-03-28 22:44:55 +00:00
fprintf ( output , " exten => %s,hint,%s \n " ,
ast_get_extension_name ( p ) ,
ast_get_extension_app ( p ) ) ;
2007-07-27 16:20:55 +00:00
} else {
2006-03-28 22:44:55 +00:00
const char * sep , * cid ;
2006-08-29 12:24:01 +00:00
const char * el = ast_get_extension_label ( p ) ;
2007-06-11 04:28:08 +00:00
char label [ 128 ] = " " ;
2006-08-29 13:40:04 +00:00
2006-03-28 22:44:55 +00:00
if ( ast_get_extension_matchcid ( p ) ) {
sep = " / " ;
cid = ast_get_extension_cidmatch ( p ) ;
2006-08-29 13:40:04 +00:00
} else
2006-03-28 22:44:55 +00:00
sep = cid = " " ;
2006-08-29 13:40:04 +00:00
2007-06-11 04:28:08 +00:00
if ( el & & ( snprintf ( label , sizeof ( label ) , " (%s) " , el ) ! = ( strlen ( el ) + 2 ) ) )
2006-08-29 13:40:04 +00:00
incomplete = 1 ; /* error encountered or label > 125 chars */
2006-08-29 12:24:01 +00:00
fprintf ( output , " exten => %s%s%s,%d%s,%s(%s) \n " ,
2007-07-09 01:17:28 +00:00
ast_get_extension_name ( p ) , ( ast_strlen_zero ( sep ) ? " " : sep ) , ( ast_strlen_zero ( cid ) ? " " : cid ) ,
2006-08-29 13:40:04 +00:00
ast_get_extension_priority ( p ) , label ,
2007-07-27 16:20:55 +00:00
ast_get_extension_app ( p ) , ( ast_strlen_zero ( ast_get_extension_app_data ( p ) ) ? " " : ( const char * ) ast_get_extension_app_data ( p ) ) ) ;
2001-09-12 21:29:54 +00:00
}
}
2006-03-28 22:44:55 +00:00
}
2001-09-12 21:29:54 +00:00
2006-03-28 22:44:55 +00:00
/* written any extensions? ok, write space between exten & inc */
if ( last_written_e )
fprintf ( output , " \n " ) ;
2004-08-21 18:55:39 +00:00
2006-03-28 22:44:55 +00:00
/* walk through includes */
for ( i = NULL ; ( i = ast_walk_context_includes ( c , i ) ) ; ) {
if ( strcmp ( ast_get_include_registrar ( i ) , registrar ) ! = 0 )
continue ; /* not mine */
PUT_CTX_HDR ;
fprintf ( output , " include => %s \n " , ast_get_include_name ( i ) ) ;
}
if ( ast_walk_context_includes ( c , NULL ) )
fprintf ( output , " \n " ) ;
/* walk through switches */
for ( sw = NULL ; ( sw = ast_walk_context_switches ( c , sw ) ) ; ) {
if ( strcmp ( ast_get_switch_registrar ( sw ) , registrar ) ! = 0 )
continue ; /* not mine */
PUT_CTX_HDR ;
fprintf ( output , " switch => %s/%s \n " ,
ast_get_switch_name ( sw ) , ast_get_switch_data ( sw ) ) ;
}
2004-08-21 18:55:39 +00:00
2006-03-28 22:44:55 +00:00
if ( ast_walk_context_switches ( c , NULL ) )
fprintf ( output , " \n " ) ;
2001-09-12 21:29:54 +00:00
2006-03-28 22:44:55 +00:00
/* fireout ignorepats ... */
for ( ip = NULL ; ( ip = ast_walk_context_ignorepats ( c , ip ) ) ; ) {
if ( strcmp ( ast_get_ignorepat_registrar ( ip ) , registrar ) ! = 0 )
continue ; /* not mine */
PUT_CTX_HDR ;
fprintf ( output , " ignorepat => %s \n " ,
2001-09-12 21:29:54 +00:00
ast_get_ignorepat_name ( ip ) ) ;
2006-03-28 22:44:55 +00:00
}
2001-09-12 21:29:54 +00:00
2006-03-28 22:44:55 +00:00
ast_unlock_context ( c ) ;
2001-09-12 21:29:54 +00:00
}
ast_unlock_contexts ( ) ;
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & save_dialplan_lock ) ;
2001-09-12 21:29:54 +00:00
fclose ( output ) ;
if ( incomplete ) {
2007-10-11 19:03:06 +00:00
ast_cli ( a - > fd , " Saved dialplan is incomplete \n " ) ;
return CLI_FAILURE ;
2001-09-12 21:29:54 +00:00
}
2007-10-11 19:03:06 +00:00
ast_cli ( a - > fd , " Dialplan successfully saved into '%s' \n " ,
2001-09-12 21:29:54 +00:00
filename ) ;
2007-10-11 19:03:06 +00:00
return CLI_SUCCESS ;
2001-09-12 21:29:54 +00:00
}
2005-11-14 19:00:38 +00:00
/*!
* \ brief ADD EXTENSION command stuff
2001-09-12 21:29:54 +00:00
*/
2007-10-11 19:03:06 +00:00
static char * handle_cli_dialplan_add_extension ( struct ast_cli_entry * e , int cmd , struct ast_cli_args * a )
2001-09-12 21:29:54 +00:00
{
char * whole_exten ;
char * exten , * prior ;
2003-03-30 22:55:42 +00:00
int iprior = - 2 ;
2001-09-12 21:29:54 +00:00
char * cidmatch , * app , * app_data ;
2003-02-12 13:59:15 +00:00
char * start , * end ;
2001-09-12 21:29:54 +00:00
2007-10-11 19:03:06 +00:00
switch ( cmd ) {
case CLI_INIT :
e - > command = " dialplan add extension " ;
e - > usage =
" Usage: dialplan add extension <exten>,<priority>,<app>,<app-data> \n "
" into <context> [replace] \n \n "
" This command will add new extension into <context>. If there is an \n "
" existence of extension with the same priority and last 'replace' \n "
" arguments is given here we simply replace this extension. \n "
" \n "
" Example: dialplan add extension 6123,1,Dial,IAX/216.207.245.56/6123 into local \n "
" Now, you can dial 6123 and talk to Markster :) \n " ;
return NULL ;
case CLI_GENERATE :
return complete_dialplan_add_extension ( a ) ;
}
2001-09-12 21:29:54 +00:00
/* check for arguments at first */
2007-10-11 19:03:06 +00:00
if ( a - > argc ! = 6 & & a - > argc ! = 7 )
return CLI_SHOWUSAGE ;
if ( strcmp ( a - > argv [ 4 ] , " into " ) )
return CLI_SHOWUSAGE ;
if ( a - > argc = = 7 )
if ( strcmp ( a - > argv [ 6 ] , " replace " ) )
return CLI_SHOWUSAGE ;
2001-09-12 21:29:54 +00:00
2006-09-21 21:59:12 +00:00
/* XXX overwrite argv[3] */
2007-10-11 19:03:06 +00:00
whole_exten = a - > argv [ 3 ] ;
exten = strsep ( & whole_exten , " , " ) ;
2001-09-12 21:29:54 +00:00
if ( strchr ( exten , ' / ' ) ) {
cidmatch = exten ;
strsep ( & cidmatch , " / " ) ;
} else {
cidmatch = NULL ;
}
2006-09-21 21:59:12 +00:00
prior = strsep ( & whole_exten , " , " ) ;
2003-04-06 18:19:51 +00:00
if ( prior ) {
2006-03-28 22:44:55 +00:00
if ( ! strcmp ( prior , " hint " ) ) {
2003-04-06 18:19:51 +00:00
iprior = PRIORITY_HINT ;
} else {
2005-04-29 17:00:33 +00:00
if ( sscanf ( prior , " %d " , & iprior ) ! = 1 ) {
2007-10-11 19:03:06 +00:00
ast_cli ( a - > fd , " '%s' is not a valid priority \n " , prior ) ;
2003-11-23 22:40:37 +00:00
prior = NULL ;
}
2003-04-06 18:19:51 +00:00
}
2003-03-30 22:55:42 +00:00
}
2004-09-07 01:22:57 +00:00
app = whole_exten ;
2003-04-06 18:19:51 +00:00
if ( app & & ( start = strchr ( app , ' ( ' ) ) & & ( end = strrchr ( app , ' ) ' ) ) ) {
2003-02-12 13:59:15 +00:00
* start = * end = ' \0 ' ;
app_data = start + 1 ;
2004-09-07 01:22:57 +00:00
} else {
if ( app ) {
app_data = strchr ( app , ' , ' ) ;
if ( app_data ) {
* app_data = ' \0 ' ;
app_data + + ;
}
} else
app_data = NULL ;
}
2001-09-12 21:29:54 +00:00
2006-03-28 22:44:55 +00:00
if ( ! exten | | ! prior | | ! app | | ( ! app_data & & iprior ! = PRIORITY_HINT ) )
2007-10-11 19:03:06 +00:00
return CLI_SHOWUSAGE ;
2001-09-12 21:29:54 +00:00
2003-03-30 22:55:42 +00:00
if ( ! app_data )
2004-06-14 22:03:59 +00:00
app_data = " " ;
2007-10-11 19:03:06 +00:00
if ( ast_add_extension ( a - > argv [ 5 ] , a - > argc = = 7 ? 1 : 0 , exten , iprior , NULL , cidmatch , app ,
2007-11-27 22:14:55 +00:00
( void * ) strdup ( app_data ) , ast_free_ptr , registrar ) ) {
2001-09-12 21:29:54 +00:00
switch ( errno ) {
2006-03-28 22:44:55 +00:00
case ENOMEM :
2007-10-11 19:03:06 +00:00
ast_cli ( a - > fd , " Out of free memory \n " ) ;
2006-03-28 22:44:55 +00:00
break ;
case EBUSY :
2007-10-11 19:03:06 +00:00
ast_cli ( a - > fd , " Failed to lock context(s) list, please try again later \n " ) ;
2006-03-28 22:44:55 +00:00
break ;
case ENOENT :
2007-10-11 19:03:06 +00:00
ast_cli ( a - > fd , " No existence of '%s' context \n " , a - > argv [ 5 ] ) ;
2006-03-28 22:44:55 +00:00
break ;
case EEXIST :
2007-10-11 19:03:06 +00:00
ast_cli ( a - > fd , " Extension %s@%s with priority %s already exists \n " ,
exten , a - > argv [ 5 ] , prior ) ;
2006-03-28 22:44:55 +00:00
break ;
default :
2007-10-11 19:03:06 +00:00
ast_cli ( a - > fd , " Failed to add '%s,%s,%s,%s' extension into '%s' context \n " ,
exten , prior , app , app_data , a - > argv [ 5 ] ) ;
2006-03-28 22:44:55 +00:00
break ;
2001-09-12 21:29:54 +00:00
}
2007-10-11 19:03:06 +00:00
return CLI_FAILURE ;
2001-09-12 21:29:54 +00:00
}
2007-10-11 19:03:06 +00:00
if ( a - > argc = = 7 )
ast_cli ( a - > fd , " Extension %s@%s (%s) replace by '%s,%s,%s,%s' \n " ,
exten , a - > argv [ 5 ] , prior , exten , prior , app , app_data ) ;
2001-09-12 21:29:54 +00:00
else
2007-10-11 19:03:06 +00:00
ast_cli ( a - > fd , " Extension '%s,%s,%s,%s' added into '%s' context \n " ,
exten , prior , app , app_data , a - > argv [ 5 ] ) ;
2001-09-12 21:29:54 +00:00
2007-10-11 19:03:06 +00:00
return CLI_SUCCESS ;
2001-09-12 21:29:54 +00:00
}
2006-09-21 21:59:12 +00:00
/*! dialplan add extension 6123,1,Dial,IAX/212.71.138.13/6123 into local */
2007-10-11 19:03:06 +00:00
static char * complete_dialplan_add_extension ( struct ast_cli_args * a )
2001-09-12 21:29:54 +00:00
{
2006-09-21 21:59:12 +00:00
int which = 0 ;
2006-09-18 19:54:18 +00:00
2007-10-11 19:03:06 +00:00
if ( a - > pos = = 4 ) { /* complete 'into' word ... */
return ( a - > n = = 0 ) ? strdup ( " into " ) : NULL ;
} else if ( a - > pos = = 5 ) { /* complete context */
2006-09-18 19:54:18 +00:00
struct ast_context * c = NULL ;
2007-10-11 19:03:06 +00:00
int len = strlen ( a - > word ) ;
2006-09-18 19:54:18 +00:00
char * res = NULL ;
/* try to lock contexts list ... */
2007-02-28 20:46:01 +00:00
if ( ast_rdlock_contexts ( ) ) {
2006-09-18 19:54:18 +00:00
ast_log ( LOG_WARNING , " Failed to lock contexts list \n " ) ;
return NULL ;
}
/* walk through all contexts */
while ( ! res & & ( c = ast_walk_contexts ( c ) ) )
2007-10-11 19:03:06 +00:00
if ( partial_match ( ast_get_context_name ( c ) , a - > word , len ) & & + + which > a - > n )
2006-09-18 19:54:18 +00:00
res = strdup ( ast_get_context_name ( c ) ) ;
ast_unlock_contexts ( ) ;
return res ;
2007-10-11 19:03:06 +00:00
} else if ( a - > pos = = 6 ) {
return a - > n = = 0 ? strdup ( " replace " ) : NULL ;
2006-09-18 19:54:18 +00:00
}
return NULL ;
}
2005-11-14 19:00:38 +00:00
/*!
2001-09-12 21:29:54 +00:00
* IGNOREPAT CLI stuff
*/
2007-10-11 19:03:06 +00:00
static char * handle_cli_dialplan_add_ignorepat ( struct ast_cli_entry * e , int cmd , struct ast_cli_args * a )
2006-09-18 19:54:18 +00:00
{
2007-10-11 19:03:06 +00:00
switch ( cmd ) {
case CLI_INIT :
e - > command = " dialplan add ignorepat " ;
e - > usage =
" Usage: dialplan add ignorepat <pattern> into <context> \n "
" This command adds a new ignore pattern into context <context> \n "
" \n "
" Example: dialplan add ignorepat _3XX into local \n " ;
return NULL ;
case CLI_GENERATE :
return complete_dialplan_add_ignorepat ( a ) ;
}
if ( a - > argc ! = 6 )
return CLI_SHOWUSAGE ;
if ( strcmp ( a - > argv [ 4 ] , " into " ) )
return CLI_SHOWUSAGE ;
2006-09-18 19:54:18 +00:00
2007-10-11 19:03:06 +00:00
if ( ast_context_add_ignorepat ( a - > argv [ 5 ] , a - > argv [ 3 ] , registrar ) ) {
2006-09-18 19:54:18 +00:00
switch ( errno ) {
case ENOMEM :
2007-10-11 19:03:06 +00:00
ast_cli ( a - > fd , " Out of free memory \n " ) ;
2006-09-18 19:54:18 +00:00
break ;
case ENOENT :
2007-10-11 19:03:06 +00:00
ast_cli ( a - > fd , " There is no existence of '%s' context \n " , a - > argv [ 5 ] ) ;
2006-09-18 19:54:18 +00:00
break ;
case EEXIST :
2007-10-11 19:03:06 +00:00
ast_cli ( a - > fd , " Ignore pattern '%s' already included in '%s' context \n " ,
a - > argv [ 3 ] , a - > argv [ 5 ] ) ;
2006-09-18 19:54:18 +00:00
break ;
case EBUSY :
2007-10-11 19:03:06 +00:00
ast_cli ( a - > fd , " Failed to lock context(s) list, please, try again later \n " ) ;
2006-09-18 19:54:18 +00:00
break ;
default :
2007-10-11 19:03:06 +00:00
ast_cli ( a - > fd , " Failed to add ingore pattern '%s' into '%s' context \n " ,
a - > argv [ 3 ] , a - > argv [ 5 ] ) ;
2006-09-18 19:54:18 +00:00
break ;
}
2007-10-11 19:03:06 +00:00
return CLI_FAILURE ;
2006-09-18 19:54:18 +00:00
}
2007-10-11 19:03:06 +00:00
ast_cli ( a - > fd , " Ignore pattern '%s' added into '%s' context \n " ,
a - > argv [ 3 ] , a - > argv [ 5 ] ) ;
return CLI_SUCCESS ;
2006-09-18 19:54:18 +00:00
}
2007-10-11 19:03:06 +00:00
static char * complete_dialplan_add_ignorepat ( struct ast_cli_args * a )
2006-09-18 19:54:18 +00:00
{
2007-10-11 19:03:06 +00:00
if ( a - > pos = = 4 )
return a - > n = = 0 ? strdup ( " into " ) : NULL ;
else if ( a - > pos = = 5 ) {
2006-09-18 19:54:18 +00:00
struct ast_context * c ;
int which = 0 ;
char * dupline , * ignorepat = NULL ;
const char * s ;
char * ret = NULL ;
2007-10-11 19:03:06 +00:00
int len = strlen ( a - > word ) ;
2006-09-18 19:54:18 +00:00
/* XXX skip first three words 'dialplan' 'add' 'ignorepat' */
2007-10-11 19:03:06 +00:00
s = skip_words ( a - > line , 3 ) ;
2006-09-18 19:54:18 +00:00
if ( s = = NULL )
return NULL ;
dupline = strdup ( s ) ;
if ( ! dupline ) {
ast_log ( LOG_ERROR , " Malloc failure \n " ) ;
return NULL ;
}
ignorepat = strsep ( & dupline , " " ) ;
2007-02-28 20:46:01 +00:00
if ( ast_rdlock_contexts ( ) ) {
2006-09-18 19:54:18 +00:00
ast_log ( LOG_ERROR , " Failed to lock contexts list \n " ) ;
return NULL ;
}
for ( c = NULL ; ! ret & & ( c = ast_walk_contexts ( c ) ) ; ) {
int found = 0 ;
2007-10-11 19:03:06 +00:00
if ( ! partial_match ( ast_get_context_name ( c ) , a - > word , len ) )
2006-09-18 19:54:18 +00:00
continue ; /* not mine */
if ( ignorepat ) /* there must be one, right ? */
found = lookup_c_ip ( c , ignorepat ) ;
2007-10-11 19:03:06 +00:00
if ( ! found & & + + which > a - > n )
2006-09-18 19:54:18 +00:00
ret = strdup ( ast_get_context_name ( c ) ) ;
}
if ( ignorepat )
free ( ignorepat ) ;
ast_unlock_contexts ( ) ;
return ret ;
}
return NULL ;
}
2007-10-11 19:03:06 +00:00
static char * handle_cli_dialplan_remove_ignorepat ( struct ast_cli_entry * e , int cmd , struct ast_cli_args * a )
2003-07-14 15:33:21 +00:00
{
2007-10-11 19:03:06 +00:00
switch ( cmd ) {
case CLI_INIT :
e - > command = " dialplan remove ignorepat " ;
e - > usage =
" Usage: dialplan remove ignorepat <pattern> from <context> \n "
" This command removes an ignore pattern from context <context> \n "
" \n "
" Example: dialplan remove ignorepat _3XX from local \n " ;
return NULL ;
case CLI_GENERATE :
return complete_dialplan_remove_ignorepat ( a ) ;
}
if ( a - > argc ! = 6 )
return CLI_SHOWUSAGE ;
if ( strcmp ( a - > argv [ 4 ] , " from " ) )
return CLI_SHOWUSAGE ;
2006-09-18 19:54:18 +00:00
2007-10-11 19:03:06 +00:00
if ( ast_context_remove_ignorepat ( a - > argv [ 5 ] , a - > argv [ 3 ] , registrar ) ) {
2006-09-18 19:54:18 +00:00
switch ( errno ) {
case EBUSY :
2007-10-11 19:03:06 +00:00
ast_cli ( a - > fd , " Failed to lock context(s) list, please try again later \n " ) ;
2006-09-18 19:54:18 +00:00
break ;
case ENOENT :
2007-10-11 19:03:06 +00:00
ast_cli ( a - > fd , " There is no existence of '%s' context \n " , a - > argv [ 5 ] ) ;
2006-09-18 19:54:18 +00:00
break ;
case EINVAL :
2007-10-11 19:03:06 +00:00
ast_cli ( a - > fd , " There is no existence of '%s' ignore pattern in '%s' context \n " ,
a - > argv [ 3 ] , a - > argv [ 5 ] ) ;
2006-09-18 19:54:18 +00:00
break ;
default :
2007-10-11 19:03:06 +00:00
ast_cli ( a - > fd , " Failed to remove ignore pattern '%s' from '%s' context \n " ,
a - > argv [ 3 ] , a - > argv [ 5 ] ) ;
2006-09-18 19:54:18 +00:00
break ;
}
2007-10-11 19:03:06 +00:00
return CLI_FAILURE ;
2006-09-18 19:54:18 +00:00
}
2007-10-11 19:03:06 +00:00
ast_cli ( a - > fd , " Ignore pattern '%s' removed from '%s' context \n " ,
a - > argv [ 3 ] , a - > argv [ 5 ] ) ;
return CLI_SUCCESS ;
2003-07-14 15:33:21 +00:00
}
2007-10-11 19:03:06 +00:00
static char * complete_dialplan_remove_ignorepat ( struct ast_cli_args * a )
2006-09-18 19:54:18 +00:00
{
struct ast_context * c ;
int which = 0 ;
char * ret = NULL ;
2007-10-11 19:03:06 +00:00
if ( a - > pos = = 3 ) {
int len = strlen ( a - > word ) ;
2007-02-28 20:46:01 +00:00
if ( ast_rdlock_contexts ( ) ) {
2006-09-18 19:54:18 +00:00
ast_log ( LOG_WARNING , " Failed to lock contexts list \n " ) ;
return NULL ;
}
for ( c = NULL ; ! ret & & ( c = ast_walk_contexts ( c ) ) ; ) {
struct ast_ignorepat * ip ;
2007-02-28 20:46:01 +00:00
if ( ast_rdlock_context ( c ) ) /* error, skip it */
2006-09-18 19:54:18 +00:00
continue ;
for ( ip = NULL ; ! ret & & ( ip = ast_walk_context_ignorepats ( c , ip ) ) ; ) {
2007-10-11 19:03:06 +00:00
if ( partial_match ( ast_get_ignorepat_name ( ip ) , a - > word , len ) & & + + which > a - > n ) {
2006-09-18 19:54:18 +00:00
/* n-th match */
struct ast_context * cw = NULL ;
int found = 0 ;
while ( ( cw = ast_walk_contexts ( cw ) ) & & cw ! = c & & ! found ) {
/* XXX do i stop on c, or skip it ? */
found = lookup_c_ip ( cw , ast_get_ignorepat_name ( ip ) ) ;
}
if ( ! found )
ret = strdup ( ast_get_ignorepat_name ( ip ) ) ;
}
}
ast_unlock_context ( c ) ;
}
ast_unlock_contexts ( ) ;
return ret ;
2007-10-11 19:03:06 +00:00
} else if ( a - > pos = = 4 ) {
return a - > n = = 0 ? strdup ( " from " ) : NULL ;
} else if ( a - > pos = = 5 ) { /* XXX check this */
2006-09-18 19:54:18 +00:00
char * dupline , * duplinet , * ignorepat ;
2007-10-11 19:03:06 +00:00
int len = strlen ( a - > word ) ;
2006-09-18 19:54:18 +00:00
2007-10-11 19:03:06 +00:00
dupline = strdup ( a - > line ) ;
2006-09-18 19:54:18 +00:00
if ( ! dupline ) {
ast_log ( LOG_WARNING , " Out of free memory \n " ) ;
return NULL ;
}
duplinet = dupline ;
strsep ( & duplinet , " " ) ;
strsep ( & duplinet , " " ) ;
ignorepat = strsep ( & duplinet , " " ) ;
if ( ! ignorepat ) {
free ( dupline ) ;
return NULL ;
}
2007-02-28 20:46:01 +00:00
if ( ast_rdlock_contexts ( ) ) {
2006-09-18 19:54:18 +00:00
ast_log ( LOG_WARNING , " Failed to lock contexts list \n " ) ;
free ( dupline ) ;
return NULL ;
}
for ( c = NULL ; ! ret & & ( c = ast_walk_contexts ( c ) ) ; ) {
2007-02-28 20:46:01 +00:00
if ( ast_rdlock_context ( c ) ) /* fail, skip it */
2006-09-18 19:54:18 +00:00
continue ;
2007-10-11 19:03:06 +00:00
if ( ! partial_match ( ast_get_context_name ( c ) , a - > word , len ) )
2006-09-18 19:54:18 +00:00
continue ;
2007-10-11 19:03:06 +00:00
if ( lookup_c_ip ( c , ignorepat ) & & + + which > a - > n )
2006-09-18 19:54:18 +00:00
ret = strdup ( ast_get_context_name ( c ) ) ;
ast_unlock_context ( c ) ;
}
ast_unlock_contexts ( ) ;
free ( dupline ) ;
return NULL ;
}
return NULL ;
}
static int pbx_load_module ( void ) ;
2007-10-11 19:03:06 +00:00
static char * handle_cli_dialplan_reload ( struct ast_cli_entry * e , int cmd , struct ast_cli_args * a )
2006-09-18 19:54:18 +00:00
{
2007-10-11 19:03:06 +00:00
switch ( cmd ) {
case CLI_INIT :
e - > command = " dialplan reload " ;
e - > usage =
" Usage: dialplan reload \n "
" Reload extensions.conf without reloading any other \n "
" modules. This command does not delete global variables \n "
" unless clearglobalvars is set to yes in extensions.conf \n " ;
return NULL ;
case CLI_GENERATE :
return NULL ;
}
if ( a - > argc ! = 2 )
return CLI_SHOWUSAGE ;
2007-02-26 20:09:06 +00:00
if ( clearglobalvars_config )
pbx_builtin_clear_globals ( ) ;
2007-10-11 19:03:06 +00:00
2006-09-18 19:54:18 +00:00
pbx_load_module ( ) ;
2007-10-11 19:03:06 +00:00
return CLI_SUCCESS ;
2006-09-18 19:54:18 +00:00
}
2005-11-14 19:00:38 +00:00
/*!
2001-09-12 21:29:54 +00:00
* CLI entries for commands provided by this module
*/
2006-09-18 19:54:18 +00:00
static struct ast_cli_entry cli_pbx_config [ ] = {
2007-10-22 20:05:18 +00:00
AST_CLI_DEFINE ( handle_cli_dialplan_add_extension , " Add new extension into context " ) ,
AST_CLI_DEFINE ( handle_cli_dialplan_remove_extension , " Remove a specified extension " ) ,
AST_CLI_DEFINE ( handle_cli_dialplan_add_ignorepat , " Add new ignore pattern " ) ,
AST_CLI_DEFINE ( handle_cli_dialplan_remove_ignorepat , " Remove ignore pattern from context " ) ,
AST_CLI_DEFINE ( handle_cli_dialplan_add_include , " Include context in other context " ) ,
AST_CLI_DEFINE ( handle_cli_dialplan_remove_include , " Remove a specified include from context " ) ,
AST_CLI_DEFINE ( handle_cli_dialplan_reload , " Reload extensions and *only* extensions " )
2006-09-18 19:54:18 +00:00
} ;
2007-10-11 19:03:06 +00:00
static struct ast_cli_entry cli_dialplan_save =
2007-10-22 20:05:18 +00:00
AST_CLI_DEFINE ( handle_cli_dialplan_save , " Save dialplan " ) ;
2003-07-14 15:33:21 +00:00
2005-11-14 19:00:38 +00:00
/*!
2001-09-12 21:29:54 +00:00
* Standard module functions . . .
*/
2006-08-21 02:11:39 +00:00
static int unload_module ( void )
1999-10-13 04:15:49 +00:00
{
2001-09-12 21:29:54 +00:00
if ( static_config & & ! write_protect_config )
2006-09-18 19:54:18 +00:00
ast_cli_unregister ( & cli_dialplan_save ) ;
2008-03-10 21:48:20 +00:00
if ( overrideswitch_config ) {
ast_free ( overrideswitch_config ) ;
}
2006-09-18 19:54:18 +00:00
ast_cli_unregister_multiple ( cli_pbx_config , sizeof ( cli_pbx_config ) / sizeof ( struct ast_cli_entry ) ) ;
2001-04-17 16:49:37 +00:00
ast_context_destroy ( NULL , registrar ) ;
1999-10-13 04:15:49 +00:00
return 0 ;
}
2006-08-31 21:00:20 +00:00
static int pbx_load_config ( const char * config_file )
1999-10-13 04:15:49 +00:00
{
struct ast_config * cfg ;
2005-05-19 01:18:37 +00:00
char * end ;
2004-10-03 04:19:59 +00:00
char * label ;
2003-08-03 19:26:09 +00:00
char realvalue [ 256 ] ;
2004-10-02 20:43:16 +00:00
int lastpri = - 2 ;
2006-03-28 22:44:55 +00:00
struct ast_context * con ;
2006-04-06 14:40:47 +00:00
struct ast_variable * v ;
2006-09-20 20:40:39 +00:00
const char * cxt ;
2007-02-16 18:04:34 +00:00
const char * aft ;
2008-03-10 21:48:20 +00:00
const char * newpm , * ovsw ;
2007-08-16 21:09:46 +00:00
struct ast_flags config_flags = { 0 } ;
cfg = ast_config_load ( config_file , config_flags ) ;
2006-04-06 14:23:37 +00:00
if ( ! cfg )
2006-08-31 21:00:20 +00:00
return 0 ;
2006-03-28 22:44:55 +00:00
2006-04-06 14:40:47 +00:00
/* Use existing config to populate the PBX table */
static_config = ast_true ( ast_variable_retrieve ( cfg , " general " , " static " ) ) ;
write_protect_config = ast_true ( ast_variable_retrieve ( cfg , " general " , " writeprotect " ) ) ;
2007-02-16 18:04:34 +00:00
if ( ( aft = ast_variable_retrieve ( cfg , " general " , " autofallthrough " ) ) )
autofallthrough_config = ast_true ( aft ) ;
closes issue #11363; where the pattern _20x. buried in an included context, didn't match 2012; There were a small set of problems to fix: 1. I needed NOT to score patterns unless you are at the end of the data string. 2. Capital N,X,Z and small n,x,z are OK in patterns. I canonicalize the patterns in the trie to caps. 3. When a pattern ends with dot or exclamation, CANMATCH/MATCHMORE should always report this pattern, no matter the length. With this commit, I also supplied the wish of Luigi, where the user can select which pattern matching algorithm to use, the old (legacy) pattern matcher, or the new, trie based matcher. The OLD matcher is the default. A new [general] section variable, extenpatternmatchnew, is added to the extensions.conf, and the example config has it set to false. If true, the new matcher is used. In all other respects, the context/exten structs are the same; the tries and hashtabs are formed, but in the new mode the tries are not used. A new CLI command 'dialplan set extenpatternmatch true/false' is provided to allow switching at run time. I beg users that are forced to return to the old matcher to please report the reason in the bug tracker. Measured the speed benefit of the new matcher against an impossibly large context with 10,000 extensions: the new matcher is 374 times faster.
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@89547 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-11-24 21:00:26 +00:00
if ( ( newpm = ast_variable_retrieve ( cfg , " general " , " extenpatternmatchnew " ) ) )
extenpatternmatchnew_config = ast_true ( newpm ) ;
2006-04-06 14:40:47 +00:00
clearglobalvars_config = ast_true ( ast_variable_retrieve ( cfg , " general " , " clearglobalvars " ) ) ;
2008-03-10 21:48:20 +00:00
if ( ( ovsw = ast_variable_retrieve ( cfg , " general " , " overrideswitch " ) ) ) {
if ( overrideswitch_config ) {
ast_free ( overrideswitch_config ) ;
}
if ( ! ast_strlen_zero ( ovsw ) ) {
overrideswitch_config = ast_strdup ( ovsw ) ;
} else {
overrideswitch_config = NULL ;
}
}
2006-09-16 23:53:58 +00:00
if ( ( cxt = ast_variable_retrieve ( cfg , " general " , " userscontext " ) ) )
ast_copy_string ( userscontext , cxt , sizeof ( userscontext ) ) ;
else
ast_copy_string ( userscontext , " default " , sizeof ( userscontext ) ) ;
2006-04-06 14:40:47 +00:00
for ( v = ast_variable_browse ( cfg , " globals " ) ; v ; v = v - > next ) {
pbx_substitute_variables_helper ( NULL , v - > value , realvalue , sizeof ( realvalue ) - 1 ) ;
pbx_builtin_setvar_helper ( NULL , v - > name , realvalue ) ;
}
for ( cxt = NULL ; ( cxt = ast_category_browse ( cfg , cxt ) ) ; ) {
/* All categories but "general" or "globals" are considered contexts */
if ( ! strcasecmp ( cxt , " general " ) | | ! strcasecmp ( cxt , " globals " ) )
continue ;
(closes issue #6002)
Reported by: rizzo
Tested by: murf
Proposal of the changes to be made, and then an announcement of how they were accomplished:
http://lists.digium.com/pipermail/asterisk-dev/2008-February/032065.html
and:
http://lists.digium.com/pipermail/asterisk-dev/2008-March/032124.html
Here is a recap, file by file, of what I have done:
pbx/pbx_config.c
pbx/pbx_ael.c
All funcs that were passed a ptr to the context list, now will ALSO be passed a hashtab ptr to the same set.
Why? because (for the time being), the dialplan is stored in both, to facilitate a quick, low-cost move to
hash-tables to speed up dialplan processing. If it was deemed necessary to pass the context LIST, well, it
is just as necessary to have the TABLE available. This is because the list/table in question might not be
the global one, but temporary ones we would use to stage the dialplan on, and then swap into the global
position when things are ready.
We now have one external function for apps to use, "ast_context_find_or_create()" instead of the pre-existing
"find" and "create", as all existing usages used both in tandem anyway.
pbx_config, and pbx_ael, will stage the reloaded dialplan into local lists and tables, and
then call merge_contexts_and_delete, which will merge (now) existing contexts and
priorities from other registrars into this local set by copying them. Then, merge_contexts_and_delete will
lock down the contexts, swap the lists and tables, and unlock (real quick), and then
destroy the old dialplan.
chan_sip.c
chan_iax.c
chan_skinny.c
All the channel drivers that would add regcontexts now use the ast_context_find_or_create now.
chan_sip also includes a small fix to get rid of warnings about removing priorities that never got entered.
apps/app_meetme.c
apps/app_dial.c
apps/app_queue.c
All the apps that added a context/exten/priority were also modified to use ast_context_find_or_create instead.
include/asterisk/pbx.h
ast_context_create() is removed. Find_or_create_ is the new method.
ast_context_find_or_create() interface gets the hashtab added.
ast_merge_contexts_and_delete() gets the local hashtab arg added.
ast_wrlock_contexts_version() is added so you can detect if someone else got a writelock between your readlocking and writelocking.
ast_hashtab_compare_contexts was made public for use in pbx_config/pbx_ael
ast_hashtab_hash_contexts was in like fashion make public.
include/asterisk/pval.h
ast_compile_ael2() interface changed to include the local hashtab table ptr.
main/features.c
For the sake of the parking context, we use ast_context_find_or_create().
main/pbx.c
I changed all the "tree" names to "table" instead. That's because the original
implementation was based on binary trees. (had a free library). Then I moved
to hashtabs. Now, the names move forward too.
refcount field added to contexts, so you can keep track of how many modules
wanted this context to exist.
Some log messages that are warnings were inflated from LOG_NOTICE to LOG_WARNING.
Added some calls to ast_verb(3,...) for debug messages
Lots of little mods to ast_context_remove_extension2, which is now excersized in ways
it was not previously; one definite bug fixed.
find_or_create was upgraded to handle both local lists/tables as well as the globals.
context_merge() was added to do the per-context merging of the old/present contexts/extens/prios into the new/proposed local list/tables
ast_merge_contexts_and_delete() was heavily modified.
ast_add_extension2() was also upgraded to handle changes.
the context_destroy() code was re-engineered to handle the new way of doing things,
by exten/prio instead of by context.
res/ael/pval.c
res/ael/ael.tab.c
res/ael/ael.tab.h
res/ael/ael.y
res/ael/ael_lex.c
res/ael/ael.flex
utils/ael_main.c
utils/extconf.c
utils/conf2ael.c
utils/Makefile
Had to change the interface to ast_compile_ael2(), to include the hashtab ptr.
This ended up involving several external apps. The main gotcha was I had to
include lock.h and hashtab.h in several places.
As a side note, I tested this stuff pretty thoroughly, I replicated the problems
originally reported by Luigi, and made triply sure that reloads worked, and everything
worked thru "stop gracefully". I found a and fixed a few bugs as I was merging into
trunk, that did not appear in my tests of bug6002.
How's this for verbose commit messages?
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@106757 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2008-03-07 18:57:57 +00:00
con = ast_context_find_or_create ( & local_contexts , local_table , cxt , registrar ) ;
2006-04-06 14:40:47 +00:00
if ( con = = NULL )
continue ;
2006-03-28 22:44:55 +00:00
2006-04-06 14:40:47 +00:00
for ( v = ast_variable_browse ( cfg , cxt ) ; v ; v = v - > next ) {
if ( ! strcasecmp ( v - > name , " exten " ) ) {
2006-07-12 13:29:10 +00:00
char * tc = ast_strdup ( v - > value ) ;
if ( tc ) {
2006-03-29 20:08:14 +00:00
int ipri = - 2 ;
char realext [ 256 ] = " " ;
2007-07-23 19:51:41 +00:00
char * plus , * firstp ;
2006-04-06 14:40:47 +00:00
char * pri , * appl , * data , * cidmatch ;
char * stringp = tc ;
char * ext = strsep ( & stringp , " , " ) ;
if ( ! ext )
ext = " " ;
pbx_substitute_variables_helper ( NULL , ext , realext , sizeof ( realext ) - 1 ) ;
cidmatch = strchr ( realext , ' / ' ) ;
if ( cidmatch ) {
* cidmatch + + = ' \0 ' ;
ast_shrink_phone_number ( cidmatch ) ;
}
pri = strsep ( & stringp , " , " ) ;
if ( ! pri )
pri = " " ;
2007-06-27 21:09:24 +00:00
pri = ast_skip_blanks ( pri ) ;
pri = ast_trim_blanks ( pri ) ;
2006-04-06 14:40:47 +00:00
label = strchr ( pri , ' ( ' ) ;
if ( label ) {
* label + + = ' \0 ' ;
end = strchr ( label , ' ) ' ) ;
if ( end )
* end = ' \0 ' ;
else
ast_log ( LOG_WARNING , " Label missing trailing ')' at line %d \n " , v - > lineno ) ;
}
plus = strchr ( pri , ' + ' ) ;
if ( plus )
* plus + + = ' \0 ' ;
if ( ! strcmp ( pri , " hint " ) )
ipri = PRIORITY_HINT ;
else if ( ! strcmp ( pri , " next " ) | | ! strcmp ( pri , " n " ) ) {
if ( lastpri > - 2 )
ipri = lastpri + 1 ;
else
ast_log ( LOG_WARNING , " Can't use 'next' priority on the first entry! \n " ) ;
} else if ( ! strcmp ( pri , " same " ) | | ! strcmp ( pri , " s " ) ) {
if ( lastpri > - 2 )
ipri = lastpri ;
else
ast_log ( LOG_WARNING , " Can't use 'same' priority on the first entry! \n " ) ;
} else if ( sscanf ( pri , " %d " , & ipri ) ! = 1 & &
( ipri = ast_findlabel_extension2 ( NULL , con , realext , pri , cidmatch ) ) < 1 ) {
ast_log ( LOG_WARNING , " Invalid priority/label '%s' at line %d \n " , pri , v - > lineno ) ;
ipri = 0 ;
}
appl = S_OR ( stringp , " " ) ;
2007-07-23 19:51:41 +00:00
/* Find the first occurrence of '(' */
2006-04-06 14:40:47 +00:00
firstp = strchr ( appl , ' ( ' ) ;
2007-07-23 19:51:41 +00:00
if ( ! firstp ) {
/* No arguments */
2006-04-06 14:40:47 +00:00
data = " " ;
} else {
appl = strsep ( & stringp , " ( " ) ;
data = stringp ;
end = strrchr ( data , ' ) ' ) ;
if ( ( end = strrchr ( data , ' ) ' ) ) ) {
* end = ' \0 ' ;
2006-03-29 20:08:14 +00:00
} else {
2006-04-06 14:40:47 +00:00
ast_log ( LOG_WARNING , " No closing parenthesis found? '%s(%s' \n " , appl , data ) ;
2006-03-29 20:08:14 +00:00
}
2006-04-06 14:40:47 +00:00
}
2001-09-12 21:29:54 +00:00
2006-04-06 14:40:47 +00:00
if ( ! data )
2007-07-23 19:51:41 +00:00
data = " " ;
2006-04-06 14:40:47 +00:00
appl = ast_skip_blanks ( appl ) ;
if ( ipri ) {
if ( plus )
ipri + = atoi ( plus ) ;
lastpri = ipri ;
if ( ! ast_opt_dont_warn & & ! strcmp ( realext , " _. " ) )
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 ) ;
2007-09-17 18:57:56 +00:00
if ( ast_add_extension2 ( con , 0 , realext , ipri , label , cidmatch , appl , strdup ( data ) , ast_free_ptr , registrar ) ) {
2006-04-06 14:40:47 +00:00
ast_log ( LOG_WARNING , " Unable to register extension at line %d \n " , v - > lineno ) ;
2006-03-28 22:44:55 +00:00
}
1999-10-13 04:15:49 +00:00
}
2006-04-06 14:40:47 +00:00
free ( tc ) ;
1999-10-13 04:15:49 +00:00
}
2006-04-06 14:40:47 +00:00
} else if ( ! strcasecmp ( v - > name , " include " ) ) {
pbx_substitute_variables_helper ( NULL , v - > value , realvalue , sizeof ( realvalue ) - 1 ) ;
if ( ast_context_add_include2 ( con , realvalue , registrar ) )
ast_log ( LOG_WARNING , " Unable to include context '%s' in context '%s' \n " , v - > value , cxt ) ;
} else if ( ! strcasecmp ( v - > name , " ignorepat " ) ) {
pbx_substitute_variables_helper ( NULL , v - > value , realvalue , sizeof ( realvalue ) - 1 ) ;
if ( ast_context_add_ignorepat2 ( con , realvalue , registrar ) )
ast_log ( LOG_WARNING , " Unable to include ignorepat '%s' in context '%s' \n " , v - > value , cxt ) ;
} else if ( ! strcasecmp ( v - > name , " switch " ) | | ! strcasecmp ( v - > name , " lswitch " ) | | ! strcasecmp ( v - > name , " eswitch " ) ) {
2007-07-23 19:51:41 +00:00
char * stringp = realvalue ;
2006-04-06 14:40:47 +00:00
char * appl , * data ;
This commits the performance mods that give the priority processing engine in the pbx, a 25-30% speed boost. The two updates used, are, first, to merge the ast_exists_extension() and the ast_spawn_extension() where they are called sequentially in a loop in the code, into a slightly upgraded version of ast_spawn_extension(), with a few extra args; and, second, I modified the substitute_variables_helper_full, so it zeroes out the byte after the evaluated string instead of demanding you pre-zero the buffer; I also went thru the code and removed the code that zeroed this buffer before every call to the substitute_variables_helper_full. The first fix provides about a 9% speedup, and the second the rest. These figures come from the 'PIPS' benchmark I describe in blogs, conf. reports, etc.
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@88166 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-11-01 22:26:51 +00:00
2006-04-06 14:40:47 +00:00
if ( ! strcasecmp ( v - > name , " switch " ) )
pbx_substitute_variables_helper ( NULL , v - > value , realvalue , sizeof ( realvalue ) - 1 ) ;
else
ast_copy_string ( realvalue , v - > value , sizeof ( realvalue ) ) ;
appl = strsep ( & stringp , " / " ) ;
2007-07-23 19:51:41 +00:00
data = S_OR ( stringp , " " ) ;
2006-04-06 14:40:47 +00:00
if ( ast_context_add_switch2 ( con , appl , data , ! strcasecmp ( v - > name , " eswitch " ) , registrar ) )
ast_log ( LOG_WARNING , " Unable to include switch '%s' in context '%s' \n " , v - > value , cxt ) ;
2006-12-21 15:52:44 +00:00
} else {
ast_log ( LOG_WARNING , " ==!!== Unknown directive: %s at line %d -- IGNORING!!! \n " , v - > name , v - > lineno ) ;
2006-03-29 20:08:14 +00:00
}
1999-10-13 04:15:49 +00:00
}
}
2006-04-06 14:40:47 +00:00
ast_config_destroy ( cfg ) ;
2006-08-31 21:00:20 +00:00
return 1 ;
2006-04-06 14:23:37 +00:00
}
2006-09-16 23:53:58 +00:00
static void append_interface ( char * iface , int maxlen , char * add )
{
int len = strlen ( iface ) ;
if ( strlen ( add ) + len < maxlen - 2 ) {
if ( strlen ( iface ) ) {
iface [ len ] = ' & ' ;
strcpy ( iface + len + 1 , add ) ;
} else
strcpy ( iface , add ) ;
}
}
static void pbx_load_users ( void )
{
struct ast_config * cfg ;
char * cat , * chan ;
2006-09-20 20:40:39 +00:00
const char * zapchan ;
const char * hasexten ;
2006-09-16 23:53:58 +00:00
char tmp [ 256 ] ;
char iface [ 256 ] ;
char zapcopy [ 256 ] ;
char * c ;
int len ;
int hasvoicemail ;
int start , finish , x ;
2007-10-14 15:34:54 +00:00
struct ast_context * con = NULL ;
2007-08-16 21:09:46 +00:00
struct ast_flags config_flags = { 0 } ;
2006-09-16 23:53:58 +00:00
2007-08-16 21:09:46 +00:00
cfg = ast_config_load ( " users.conf " , config_flags ) ;
2006-09-16 23:53:58 +00:00
if ( ! cfg )
return ;
for ( cat = ast_category_browse ( cfg , NULL ) ; cat ; cat = ast_category_browse ( cfg , cat ) ) {
if ( ! strcasecmp ( cat , " general " ) )
continue ;
iface [ 0 ] = ' \0 ' ;
len = sizeof ( iface ) ;
if ( ast_true ( ast_config_option ( cfg , cat , " hassip " ) ) ) {
snprintf ( tmp , sizeof ( tmp ) , " SIP/%s " , cat ) ;
append_interface ( iface , sizeof ( iface ) , tmp ) ;
}
if ( ast_true ( ast_config_option ( cfg , cat , " hasiax " ) ) ) {
2006-12-30 18:32:31 +00:00
snprintf ( tmp , sizeof ( tmp ) , " IAX2/%s " , cat ) ;
2006-09-16 23:53:58 +00:00
append_interface ( iface , sizeof ( iface ) , tmp ) ;
}
2006-10-02 19:01:10 +00:00
if ( ast_true ( ast_config_option ( cfg , cat , " hash323 " ) ) ) {
snprintf ( tmp , sizeof ( tmp ) , " H323/%s " , cat ) ;
append_interface ( iface , sizeof ( iface ) , tmp ) ;
}
2006-09-16 23:53:58 +00:00
hasexten = ast_config_option ( cfg , cat , " hasexten " ) ;
if ( hasexten & & ! ast_true ( hasexten ) )
continue ;
hasvoicemail = ast_true ( ast_config_option ( cfg , cat , " hasvoicemail " ) ) ;
zapchan = ast_variable_retrieve ( cfg , cat , " zapchan " ) ;
if ( ! zapchan )
zapchan = ast_variable_retrieve ( cfg , " general " , " zapchan " ) ;
if ( ! ast_strlen_zero ( zapchan ) ) {
ast_copy_string ( zapcopy , zapchan , sizeof ( zapcopy ) ) ;
c = zapcopy ;
chan = strsep ( & c , " , " ) ;
while ( chan ) {
if ( sscanf ( chan , " %d-%d " , & start , & finish ) = = 2 ) {
/* Range */
} else if ( sscanf ( chan , " %d " , & start ) ) {
/* Just one */
finish = start ;
} else {
start = 0 ; finish = 0 ;
}
if ( finish < start ) {
x = finish ;
finish = start ;
start = x ;
}
for ( x = start ; x < = finish ; x + + ) {
snprintf ( tmp , sizeof ( tmp ) , " Zap/%d " , x ) ;
append_interface ( iface , sizeof ( iface ) , tmp ) ;
}
chan = strsep ( & c , " , " ) ;
}
}
if ( ! ast_strlen_zero ( iface ) ) {
2007-10-14 15:34:54 +00:00
/* Only create a context here when it is really needed. Otherwise default empty context
created by pbx_config may conflict with the one explicitly created by pbx_ael */
if ( ! con )
(closes issue #6002)
Reported by: rizzo
Tested by: murf
Proposal of the changes to be made, and then an announcement of how they were accomplished:
http://lists.digium.com/pipermail/asterisk-dev/2008-February/032065.html
and:
http://lists.digium.com/pipermail/asterisk-dev/2008-March/032124.html
Here is a recap, file by file, of what I have done:
pbx/pbx_config.c
pbx/pbx_ael.c
All funcs that were passed a ptr to the context list, now will ALSO be passed a hashtab ptr to the same set.
Why? because (for the time being), the dialplan is stored in both, to facilitate a quick, low-cost move to
hash-tables to speed up dialplan processing. If it was deemed necessary to pass the context LIST, well, it
is just as necessary to have the TABLE available. This is because the list/table in question might not be
the global one, but temporary ones we would use to stage the dialplan on, and then swap into the global
position when things are ready.
We now have one external function for apps to use, "ast_context_find_or_create()" instead of the pre-existing
"find" and "create", as all existing usages used both in tandem anyway.
pbx_config, and pbx_ael, will stage the reloaded dialplan into local lists and tables, and
then call merge_contexts_and_delete, which will merge (now) existing contexts and
priorities from other registrars into this local set by copying them. Then, merge_contexts_and_delete will
lock down the contexts, swap the lists and tables, and unlock (real quick), and then
destroy the old dialplan.
chan_sip.c
chan_iax.c
chan_skinny.c
All the channel drivers that would add regcontexts now use the ast_context_find_or_create now.
chan_sip also includes a small fix to get rid of warnings about removing priorities that never got entered.
apps/app_meetme.c
apps/app_dial.c
apps/app_queue.c
All the apps that added a context/exten/priority were also modified to use ast_context_find_or_create instead.
include/asterisk/pbx.h
ast_context_create() is removed. Find_or_create_ is the new method.
ast_context_find_or_create() interface gets the hashtab added.
ast_merge_contexts_and_delete() gets the local hashtab arg added.
ast_wrlock_contexts_version() is added so you can detect if someone else got a writelock between your readlocking and writelocking.
ast_hashtab_compare_contexts was made public for use in pbx_config/pbx_ael
ast_hashtab_hash_contexts was in like fashion make public.
include/asterisk/pval.h
ast_compile_ael2() interface changed to include the local hashtab table ptr.
main/features.c
For the sake of the parking context, we use ast_context_find_or_create().
main/pbx.c
I changed all the "tree" names to "table" instead. That's because the original
implementation was based on binary trees. (had a free library). Then I moved
to hashtabs. Now, the names move forward too.
refcount field added to contexts, so you can keep track of how many modules
wanted this context to exist.
Some log messages that are warnings were inflated from LOG_NOTICE to LOG_WARNING.
Added some calls to ast_verb(3,...) for debug messages
Lots of little mods to ast_context_remove_extension2, which is now excersized in ways
it was not previously; one definite bug fixed.
find_or_create was upgraded to handle both local lists/tables as well as the globals.
context_merge() was added to do the per-context merging of the old/present contexts/extens/prios into the new/proposed local list/tables
ast_merge_contexts_and_delete() was heavily modified.
ast_add_extension2() was also upgraded to handle changes.
the context_destroy() code was re-engineered to handle the new way of doing things,
by exten/prio instead of by context.
res/ael/pval.c
res/ael/ael.tab.c
res/ael/ael.tab.h
res/ael/ael.y
res/ael/ael_lex.c
res/ael/ael.flex
utils/ael_main.c
utils/extconf.c
utils/conf2ael.c
utils/Makefile
Had to change the interface to ast_compile_ael2(), to include the hashtab ptr.
This ended up involving several external apps. The main gotcha was I had to
include lock.h and hashtab.h in several places.
As a side note, I tested this stuff pretty thoroughly, I replicated the problems
originally reported by Luigi, and made triply sure that reloads worked, and everything
worked thru "stop gracefully". I found a and fixed a few bugs as I was merging into
trunk, that did not appear in my tests of bug6002.
How's this for verbose commit messages?
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@106757 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2008-03-07 18:57:57 +00:00
con = ast_context_find_or_create ( & local_contexts , local_table , userscontext , registrar ) ;
2007-10-14 15:34:54 +00:00
if ( ! con ) {
ast_log ( LOG_ERROR , " Can't find/create user context '%s' \n " , userscontext ) ;
return ;
}
2006-09-16 23:53:58 +00:00
/* Add hint */
2007-01-06 00:28:16 +00:00
ast_add_extension2 ( con , 0 , cat , - 1 , NULL , NULL , iface , NULL , NULL , registrar ) ;
2006-09-16 23:53:58 +00:00
/* If voicemail, use "stdexten" else use plain old dial */
if ( hasvoicemail ) {
2007-07-27 16:20:55 +00:00
snprintf ( tmp , sizeof ( tmp ) , " stdexten,%s,${HINT} " , cat ) ;
2007-09-17 18:57:56 +00:00
ast_add_extension2 ( con , 0 , cat , 1 , NULL , NULL , " Macro " , strdup ( tmp ) , ast_free_ptr , registrar ) ;
2006-09-16 23:53:58 +00:00
} else {
2007-09-17 18:57:56 +00:00
ast_add_extension2 ( con , 0 , cat , 1 , NULL , NULL , " Dial " , strdup ( " ${HINT} " ) , ast_free_ptr , registrar ) ;
2006-09-16 23:53:58 +00:00
}
}
}
ast_config_destroy ( cfg ) ;
}
2006-04-06 14:23:37 +00:00
static int pbx_load_module ( void )
{
struct ast_context * con ;
(closes issue #6002)
Reported by: rizzo
Tested by: murf
Proposal of the changes to be made, and then an announcement of how they were accomplished:
http://lists.digium.com/pipermail/asterisk-dev/2008-February/032065.html
and:
http://lists.digium.com/pipermail/asterisk-dev/2008-March/032124.html
Here is a recap, file by file, of what I have done:
pbx/pbx_config.c
pbx/pbx_ael.c
All funcs that were passed a ptr to the context list, now will ALSO be passed a hashtab ptr to the same set.
Why? because (for the time being), the dialplan is stored in both, to facilitate a quick, low-cost move to
hash-tables to speed up dialplan processing. If it was deemed necessary to pass the context LIST, well, it
is just as necessary to have the TABLE available. This is because the list/table in question might not be
the global one, but temporary ones we would use to stage the dialplan on, and then swap into the global
position when things are ready.
We now have one external function for apps to use, "ast_context_find_or_create()" instead of the pre-existing
"find" and "create", as all existing usages used both in tandem anyway.
pbx_config, and pbx_ael, will stage the reloaded dialplan into local lists and tables, and
then call merge_contexts_and_delete, which will merge (now) existing contexts and
priorities from other registrars into this local set by copying them. Then, merge_contexts_and_delete will
lock down the contexts, swap the lists and tables, and unlock (real quick), and then
destroy the old dialplan.
chan_sip.c
chan_iax.c
chan_skinny.c
All the channel drivers that would add regcontexts now use the ast_context_find_or_create now.
chan_sip also includes a small fix to get rid of warnings about removing priorities that never got entered.
apps/app_meetme.c
apps/app_dial.c
apps/app_queue.c
All the apps that added a context/exten/priority were also modified to use ast_context_find_or_create instead.
include/asterisk/pbx.h
ast_context_create() is removed. Find_or_create_ is the new method.
ast_context_find_or_create() interface gets the hashtab added.
ast_merge_contexts_and_delete() gets the local hashtab arg added.
ast_wrlock_contexts_version() is added so you can detect if someone else got a writelock between your readlocking and writelocking.
ast_hashtab_compare_contexts was made public for use in pbx_config/pbx_ael
ast_hashtab_hash_contexts was in like fashion make public.
include/asterisk/pval.h
ast_compile_ael2() interface changed to include the local hashtab table ptr.
main/features.c
For the sake of the parking context, we use ast_context_find_or_create().
main/pbx.c
I changed all the "tree" names to "table" instead. That's because the original
implementation was based on binary trees. (had a free library). Then I moved
to hashtabs. Now, the names move forward too.
refcount field added to contexts, so you can keep track of how many modules
wanted this context to exist.
Some log messages that are warnings were inflated from LOG_NOTICE to LOG_WARNING.
Added some calls to ast_verb(3,...) for debug messages
Lots of little mods to ast_context_remove_extension2, which is now excersized in ways
it was not previously; one definite bug fixed.
find_or_create was upgraded to handle both local lists/tables as well as the globals.
context_merge() was added to do the per-context merging of the old/present contexts/extens/prios into the new/proposed local list/tables
ast_merge_contexts_and_delete() was heavily modified.
ast_add_extension2() was also upgraded to handle changes.
the context_destroy() code was re-engineered to handle the new way of doing things,
by exten/prio instead of by context.
res/ael/pval.c
res/ael/ael.tab.c
res/ael/ael.tab.h
res/ael/ael.y
res/ael/ael_lex.c
res/ael/ael.flex
utils/ael_main.c
utils/extconf.c
utils/conf2ael.c
utils/Makefile
Had to change the interface to ast_compile_ael2(), to include the hashtab ptr.
This ended up involving several external apps. The main gotcha was I had to
include lock.h and hashtab.h in several places.
As a side note, I tested this stuff pretty thoroughly, I replicated the problems
originally reported by Luigi, and made triply sure that reloads worked, and everything
worked thru "stop gracefully". I found a and fixed a few bugs as I was merging into
trunk, that did not appear in my tests of bug6002.
How's this for verbose commit messages?
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@106757 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2008-03-07 18:57:57 +00:00
if ( ! local_table )
local_table = ast_hashtab_create ( 17 , ast_hashtab_compare_contexts , ast_hashtab_resize_java , ast_hashtab_newsize_java , ast_hashtab_hash_contexts , 0 ) ;
if ( ! pbx_load_config ( config ) )
2006-08-31 21:00:20 +00:00
return AST_MODULE_LOAD_DECLINE ;
2006-09-16 23:53:58 +00:00
pbx_load_users ( ) ;
(closes issue #6002)
Reported by: rizzo
Tested by: murf
Proposal of the changes to be made, and then an announcement of how they were accomplished:
http://lists.digium.com/pipermail/asterisk-dev/2008-February/032065.html
and:
http://lists.digium.com/pipermail/asterisk-dev/2008-March/032124.html
Here is a recap, file by file, of what I have done:
pbx/pbx_config.c
pbx/pbx_ael.c
All funcs that were passed a ptr to the context list, now will ALSO be passed a hashtab ptr to the same set.
Why? because (for the time being), the dialplan is stored in both, to facilitate a quick, low-cost move to
hash-tables to speed up dialplan processing. If it was deemed necessary to pass the context LIST, well, it
is just as necessary to have the TABLE available. This is because the list/table in question might not be
the global one, but temporary ones we would use to stage the dialplan on, and then swap into the global
position when things are ready.
We now have one external function for apps to use, "ast_context_find_or_create()" instead of the pre-existing
"find" and "create", as all existing usages used both in tandem anyway.
pbx_config, and pbx_ael, will stage the reloaded dialplan into local lists and tables, and
then call merge_contexts_and_delete, which will merge (now) existing contexts and
priorities from other registrars into this local set by copying them. Then, merge_contexts_and_delete will
lock down the contexts, swap the lists and tables, and unlock (real quick), and then
destroy the old dialplan.
chan_sip.c
chan_iax.c
chan_skinny.c
All the channel drivers that would add regcontexts now use the ast_context_find_or_create now.
chan_sip also includes a small fix to get rid of warnings about removing priorities that never got entered.
apps/app_meetme.c
apps/app_dial.c
apps/app_queue.c
All the apps that added a context/exten/priority were also modified to use ast_context_find_or_create instead.
include/asterisk/pbx.h
ast_context_create() is removed. Find_or_create_ is the new method.
ast_context_find_or_create() interface gets the hashtab added.
ast_merge_contexts_and_delete() gets the local hashtab arg added.
ast_wrlock_contexts_version() is added so you can detect if someone else got a writelock between your readlocking and writelocking.
ast_hashtab_compare_contexts was made public for use in pbx_config/pbx_ael
ast_hashtab_hash_contexts was in like fashion make public.
include/asterisk/pval.h
ast_compile_ael2() interface changed to include the local hashtab table ptr.
main/features.c
For the sake of the parking context, we use ast_context_find_or_create().
main/pbx.c
I changed all the "tree" names to "table" instead. That's because the original
implementation was based on binary trees. (had a free library). Then I moved
to hashtabs. Now, the names move forward too.
refcount field added to contexts, so you can keep track of how many modules
wanted this context to exist.
Some log messages that are warnings were inflated from LOG_NOTICE to LOG_WARNING.
Added some calls to ast_verb(3,...) for debug messages
Lots of little mods to ast_context_remove_extension2, which is now excersized in ways
it was not previously; one definite bug fixed.
find_or_create was upgraded to handle both local lists/tables as well as the globals.
context_merge() was added to do the per-context merging of the old/present contexts/extens/prios into the new/proposed local list/tables
ast_merge_contexts_and_delete() was heavily modified.
ast_add_extension2() was also upgraded to handle changes.
the context_destroy() code was re-engineered to handle the new way of doing things,
by exten/prio instead of by context.
res/ael/pval.c
res/ael/ael.tab.c
res/ael/ael.tab.h
res/ael/ael.y
res/ael/ael_lex.c
res/ael/ael.flex
utils/ael_main.c
utils/extconf.c
utils/conf2ael.c
utils/Makefile
Had to change the interface to ast_compile_ael2(), to include the hashtab ptr.
This ended up involving several external apps. The main gotcha was I had to
include lock.h and hashtab.h in several places.
As a side note, I tested this stuff pretty thoroughly, I replicated the problems
originally reported by Luigi, and made triply sure that reloads worked, and everything
worked thru "stop gracefully". I found a and fixed a few bugs as I was merging into
trunk, that did not appear in my tests of bug6002.
How's this for verbose commit messages?
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@106757 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2008-03-07 18:57:57 +00:00
ast_merge_contexts_and_delete ( & local_contexts , local_table , registrar ) ;
local_table = NULL ; /* the local table has been moved into the global one. */
local_contexts = NULL ;
2003-10-25 17:50:06 +00:00
2006-03-28 22:44:55 +00:00
for ( con = NULL ; ( con = ast_walk_contexts ( con ) ) ; )
2003-10-25 17:50:06 +00:00
ast_context_verify_includes ( con ) ;
2008-03-10 21:48:20 +00:00
pbx_set_overrideswitch ( overrideswitch_config ) ;
2004-10-16 19:46:02 +00:00
pbx_set_autofallthrough ( autofallthrough_config ) ;
closes issue #11363; where the pattern _20x. buried in an included context, didn't match 2012; There were a small set of problems to fix: 1. I needed NOT to score patterns unless you are at the end of the data string. 2. Capital N,X,Z and small n,x,z are OK in patterns. I canonicalize the patterns in the trie to caps. 3. When a pattern ends with dot or exclamation, CANMATCH/MATCHMORE should always report this pattern, no matter the length. With this commit, I also supplied the wish of Luigi, where the user can select which pattern matching algorithm to use, the old (legacy) pattern matcher, or the new, trie based matcher. The OLD matcher is the default. A new [general] section variable, extenpatternmatchnew, is added to the extensions.conf, and the example config has it set to false. If true, the new matcher is used. In all other respects, the context/exten structs are the same; the tries and hashtabs are formed, but in the new mode the tries are not used. A new CLI command 'dialplan set extenpatternmatch true/false' is provided to allow switching at run time. I beg users that are forced to return to the old matcher to please report the reason in the bug tracker. Measured the speed benefit of the new matcher against an impossibly large context with 10,000 extensions: the new matcher is 374 times faster.
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@89547 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-11-24 21:00:26 +00:00
pbx_set_extenpatternmatchnew ( extenpatternmatchnew_config ) ;
2004-10-16 19:46:02 +00:00
2007-12-26 20:02:27 +00:00
return AST_MODULE_LOAD_SUCCESS ;
1999-10-13 04:15:49 +00:00
}
2006-08-21 02:11:39 +00:00
static int load_module ( void )
2001-04-17 16:49:37 +00:00
{
2006-04-06 14:40:47 +00:00
if ( pbx_load_module ( ) )
2006-08-31 21:00:20 +00:00
return AST_MODULE_LOAD_DECLINE ;
2001-09-12 21:29:54 +00:00
if ( static_config & & ! write_protect_config )
2006-09-18 19:54:18 +00:00
ast_cli_register ( & cli_dialplan_save ) ;
ast_cli_register_multiple ( cli_pbx_config , sizeof ( cli_pbx_config ) / sizeof ( struct ast_cli_entry ) ) ;
2001-09-12 21:29:54 +00:00
2007-12-26 20:02:27 +00:00
return AST_MODULE_LOAD_SUCCESS ;
2001-04-17 16:49:37 +00:00
}
2006-08-21 02:11:39 +00:00
static int reload ( void )
2001-04-17 16:49:37 +00:00
{
2005-06-03 02:27:08 +00:00
if ( clearglobalvars_config )
pbx_builtin_clear_globals ( ) ;
2007-12-26 20:02:27 +00:00
return pbx_load_module ( ) ;
2001-04-17 16:49:37 +00:00
}
2006-08-21 02:11:39 +00:00
AST_MODULE_INFO ( ASTERISK_GPL_KEY , AST_MODFLAG_DEFAULT , " Text Extension Configuration " ,
. load = load_module ,
. unload = unload_module ,
. reload = reload ,
) ;