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$ " )
2003-04-23 19:09:13 +00:00
# include <sys/types.h>
2005-06-06 22:12:19 +00:00
# include <stdlib.h>
# include <stdio.h>
# include <string.h>
# include <ctype.h>
# include <errno.h>
2005-04-21 06:02:45 +00:00
# include "asterisk/pbx.h"
# include "asterisk/config.h"
2005-05-19 01:57:19 +00:00
# include "asterisk/options.h"
2005-04-21 06:02:45 +00:00
# include "asterisk/module.h"
# include "asterisk/logger.h"
# include "asterisk/cli.h"
# 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 ;
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 ;
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
{
2006-02-24 10:50:43 +00:00
char filename [ 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 */
2007-06-12 15:58:28 +00:00
fprintf ( output , " [general] \n static=%s \n writeprotect=%s \n autofallthrough=%s \n clearglobalvars=%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 " ,
2007-06-12 15:58:28 +00:00
clearglobalvars_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 ,
2001-09-12 21:29:54 +00:00
( void * ) strdup ( app_data ) , free , registrar ) ) {
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 ) ;
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 ;
2007-08-16 21:09:46 +00:00
struct ast_flags config_flags = { 0 } ;
1999-10-13 04:15:49 +00:00
2007-08-16 21:09:46 +00:00
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 ) ;
2006-04-06 14:40:47 +00:00
clearglobalvars_config = ast_true ( ast_variable_retrieve ( cfg , " general " , " clearglobalvars " ) ) ;
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 ;
2006-09-16 23:53:58 +00:00
con = ast_context_find_or_create ( & local_contexts , 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 )
con = ast_context_find_or_create ( & local_contexts , userscontext , registrar ) ;
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 ;
2006-08-31 21:00:20 +00:00
if ( ! pbx_load_config ( config ) )
return AST_MODULE_LOAD_DECLINE ;
2006-09-16 23:53:58 +00:00
pbx_load_users ( ) ;
2006-04-06 14:23:37 +00:00
ast_merge_contexts_and_delete ( & local_contexts , registrar ) ;
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 ) ;
2004-10-16 19:46:02 +00:00
pbx_set_autofallthrough ( autofallthrough_config ) ;
1999-10-13 04:15:49 +00:00
return 0 ;
}
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
return 0 ;
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 ( ) ;
2001-09-12 21:29:54 +00:00
pbx_load_module ( ) ;
2001-04-17 16:49:37 +00:00
return 0 ;
}
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 ,
) ;