1999-10-13 04:15:49 +00:00
/*
* Asterisk - - A telephony toolkit for Linux .
*
* Populate and remember extensions from static config file
*
2005-01-21 07:06:25 +00:00
* Copyright ( C ) 1999 - 2005 , 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
*
* This program is free software , distributed under the terms of
* the GNU General Public License
*/
2003-04-23 19:09:13 +00:00
# include <sys/types.h>
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"
# include "asterisk/callerid.h"
1999-10-13 04:15:49 +00:00
# include <stdlib.h>
# include <stdio.h>
# include <string.h>
2001-09-12 21:29:54 +00:00
# include <ctype.h>
# include <errno.h>
1999-10-13 04:15:49 +00:00
/* For where to put dynamic tables */
2005-04-21 06:02:45 +00:00
# include "asterisk.h"
# include "astconf.h"
1999-10-13 04:15:49 +00:00
2003-04-29 17:38:46 +00:00
# ifdef __AST_DEBUG_MALLOC
static void FREE ( void * ptr )
{
free ( ptr ) ;
}
# else
# define FREE free
# endif
1999-10-13 04:15:49 +00:00
static char * dtext = " Text Extension Configuration " ;
static char * config = " extensions.conf " ;
2001-04-17 16:49:37 +00:00
static char * registrar = " pbx_config " ;
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 ;
2004-10-16 19:46:02 +00:00
static int autofallthrough_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
/*
* Help for commands provided by this module . . .
*/
static char context_dont_include_help [ ] =
" Usage: dont include context in include \n "
" Remove include from context. \n " ;
static char context_remove_extension_help [ ] =
" Usage: remove extension exten@context [priority] \n "
" Remove whole extension from context. If priority is set, we are only \n "
" removing extension with given priority. \n " ;
static char context_add_include_help [ ] =
" Usage: include context in context \n "
" Include context in other context. \n " ;
static char save_dialplan_help [ ] =
" Usage: save dialplan [/path/to/extension/file] \n "
" Save dialplan created by pbx_config module. \n "
" \n "
" Example: save dialplan (/etc/asterisk/extensions.conf) \n "
" save dialplan /home/markster (/home/markster/extensions.conf) \n " ;
static char context_add_extension_help [ ] =
" Usage: add extension <exten>,<priority>,<app>,<app-data> into <context> \n "
" [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: add extension 6123,1,Dial,IAX/216.207.245.56/6123 into local \n "
" Now, you can dial 6123 and talk to Markster :) \n " ;
static char context_add_ignorepat_help [ ] =
" Usage: add ignorepat <pattern> into <context> \n "
" This command add new ignore pattern into context <context> \n "
" \n "
" Example: add ignorepat _3XX into local \n " ;
static char context_remove_ignorepat_help [ ] =
" Usage: remove ignorepat <pattern> from <context> \n "
" This command remove ignore pattern from context <context> \n "
" \n "
" Example: remove ignorepat _3XX from local \n " ;
2003-07-14 15:33:21 +00:00
static char reload_extensions_help [ ] =
" Usage: reload extensions.conf without reloading any other modules \n "
" This command does not delete global variables \n "
" \n "
2003-11-17 23:53:22 +00:00
" Example: extensions reload \n " ;
2003-07-14 15:33:21 +00:00
2004-06-14 21:43:16 +00:00
/*
* Static code
*/
2004-06-14 22:15:21 +00:00
static char * process_quotes_and_slashes ( char * start , char find , char replace_with )
2004-06-14 21:43:16 +00:00
{
2004-06-14 22:03:59 +00:00
char * dataPut = start ;
int inEscape = 0 ;
int inQuotes = 0 ;
for ( ; * start ; start + + ) {
if ( inEscape ) {
2004-06-14 21:43:16 +00:00
* dataPut + + = * start ; /* Always goes verbatim */
inEscape = 0 ;
2004-06-14 22:03:59 +00:00
} else {
if ( * start = = ' \\ ' ) {
2004-06-14 21:43:16 +00:00
inEscape = 1 ; /* Do not copy \ into the data */
2004-06-21 14:20:03 +00:00
} else if ( * start = = ' \' ' ) {
inQuotes = 1 - inQuotes ; /* Do not copy ' into the data */
2004-06-14 22:03:59 +00:00
} else {
2004-06-14 21:43:16 +00:00
/* Replace , with |, unless in quotes */
* dataPut + + = inQuotes ? * start : ( ( * start = = find ) ? replace_with : * start ) ;
}
}
}
* dataPut = 0 ;
return dataPut ;
}
2001-09-12 21:29:54 +00:00
/*
* Implementation of functions provided by this module
*/
/*
* REMOVE INCLUDE command stuff
*/
static int handle_context_dont_include ( int fd , int argc , char * argv [ ] )
{
if ( argc ! = 5 ) return RESULT_SHOWUSAGE ;
if ( strcmp ( argv [ 3 ] , " in " ) ) return RESULT_SHOWUSAGE ;
if ( ! ast_context_remove_include ( argv [ 4 ] , argv [ 2 ] , registrar ) ) {
ast_cli ( fd , " We are not including '%s' in '%s' now \n " ,
argv [ 2 ] , argv [ 4 ] ) ;
return RESULT_SUCCESS ;
}
ast_cli ( fd , " Failed to remove '%s' include from '%s' context \n " ,
argv [ 2 ] , argv [ 4 ] ) ;
return RESULT_FAILURE ;
}
static char * complete_context_dont_include ( char * line , char * word ,
int pos , int state )
{
int which = 0 ;
/*
* Context completion . . .
*/
if ( pos = = 2 ) {
struct ast_context * c ;
if ( ast_lock_contexts ( ) ) {
ast_log ( LOG_ERROR , " Failed to lock context list \n " ) ;
return NULL ;
}
/* walk pbx_get_contexts ... */
c = ast_walk_contexts ( NULL ) ;
while ( c ) {
struct ast_include * i ;
if ( ast_lock_context ( c ) ) {
c = ast_walk_contexts ( c ) ;
continue ;
}
i = ast_walk_context_includes ( c , NULL ) ;
while ( i ) {
if ( ! strlen ( word ) | |
! strncmp ( ast_get_include_name ( i ) , word , strlen ( word ) ) ) {
struct ast_context * nc ;
int already_served = 0 ;
/* check if this include is already served or not */
/* go through all contexts again till we reach actuall
* context or already_served = 1
*/
nc = ast_walk_contexts ( NULL ) ;
while ( nc & & nc ! = c & & ! already_served ) {
if ( ! ast_lock_context ( nc ) ) {
struct ast_include * ni ;
ni = ast_walk_context_includes ( nc , NULL ) ;
while ( ni & & ! already_served ) {
if ( ! strcmp ( ast_get_include_name ( i ) ,
ast_get_include_name ( ni ) ) )
already_served = 1 ;
ni = ast_walk_context_includes ( nc , ni ) ;
}
ast_unlock_context ( nc ) ;
}
nc = ast_walk_contexts ( nc ) ;
}
if ( ! already_served ) {
if ( + + which > state ) {
char * res =
strdup ( ast_get_include_name ( i ) ) ;
ast_unlock_context ( c ) ;
ast_unlock_contexts ( ) ;
return res ;
}
}
}
i = ast_walk_context_includes ( c , i ) ;
}
ast_unlock_context ( c ) ;
c = ast_walk_contexts ( c ) ;
}
ast_unlock_contexts ( ) ;
return NULL ;
}
/*
* ' in ' completion . . . ( complete only if previous context is really
* included somewhere )
*/
if ( pos = = 3 ) {
struct ast_context * c ;
char * context , * dupline , * duplinet ;
if ( state > 0 ) return NULL ;
/* take 'context' from line ... */
if ( ! ( dupline = strdup ( line ) ) ) {
ast_log ( LOG_ERROR , " Out of free memory \n " ) ;
return NULL ;
}
duplinet = dupline ;
strsep ( & duplinet , " " ) ; /* skip 'dont' */
strsep ( & duplinet , " " ) ; /* skip 'include' */
context = strsep ( & duplinet , " " ) ;
if ( ! context ) {
free ( dupline ) ;
return NULL ;
}
if ( ast_lock_contexts ( ) ) {
ast_log ( LOG_WARNING , " Failed to lock contexts list \n " ) ;
free ( dupline ) ;
return NULL ;
}
/* go through all contexts and check if is included ... */
c = ast_walk_contexts ( NULL ) ;
while ( c ) {
struct ast_include * i ;
if ( ast_lock_context ( c ) ) {
free ( dupline ) ;
ast_unlock_contexts ( ) ;
return NULL ;
}
i = ast_walk_context_includes ( c , NULL ) ;
while ( i ) {
/* is it our context? */
if ( ! strcmp ( ast_get_include_name ( i ) , context ) ) {
/* yes, it is, context is really included, so
* complete " in " command
*/
free ( dupline ) ;
ast_unlock_context ( c ) ;
ast_unlock_contexts ( ) ;
return strdup ( " in " ) ;
}
i = ast_walk_context_includes ( c , i ) ;
}
ast_unlock_context ( c ) ;
c = ast_walk_contexts ( c ) ;
}
free ( dupline ) ;
ast_unlock_contexts ( ) ;
return NULL ;
}
/*
* Context from which we removing include . . .
*/
if ( pos = = 4 ) {
struct ast_context * c ;
char * context , * dupline , * duplinet , * in ;
if ( ! ( dupline = strdup ( line ) ) ) {
ast_log ( LOG_ERROR , " Out of free memory \n " ) ;
return NULL ;
}
duplinet = dupline ;
strsep ( & duplinet , " " ) ; /* skip 'dont' */
strsep ( & duplinet , " " ) ; /* skip 'include' */
if ( ! ( context = strsep ( & duplinet , " " ) ) ) {
free ( dupline ) ;
return NULL ;
}
/* third word must be in */
in = strsep ( & duplinet , " " ) ;
if ( ! in | |
strcmp ( in , " in " ) ) {
free ( dupline ) ;
return NULL ;
}
if ( ast_lock_contexts ( ) ) {
ast_log ( LOG_ERROR , " Failed to lock context list \n " ) ;
free ( dupline ) ;
return NULL ;
}
/* walk through all contexts ... */
c = ast_walk_contexts ( NULL ) ;
while ( c ) {
struct ast_include * i ;
if ( ast_lock_context ( c ) ) {
free ( dupline ) ;
return NULL ;
}
/* walk through all includes and check if it is our context */
i = ast_walk_context_includes ( c , NULL ) ;
while ( i ) {
/* is in this context included another on which we want to
* remove ?
*/
if ( ! strcmp ( context , ast_get_include_name ( i ) ) ) {
/* yes, it's included, is matching our word too? */
if ( ! strncmp ( ast_get_context_name ( c ) ,
word , strlen ( word ) ) ) {
/* check state for completion */
if ( + + which > state ) {
char * res = strdup ( ast_get_context_name ( c ) ) ;
free ( dupline ) ;
ast_unlock_context ( c ) ;
ast_unlock_contexts ( ) ;
return res ;
}
}
break ;
}
i = ast_walk_context_includes ( c , i ) ;
}
ast_unlock_context ( c ) ;
c = ast_walk_contexts ( c ) ;
}
free ( dupline ) ;
ast_unlock_contexts ( ) ;
return NULL ;
}
return NULL ;
}
/*
* REMOVE EXTENSION command stuff
*/
static int handle_context_remove_extension ( int fd , int argc , char * argv [ ] )
{
int removing_priority = 0 ;
char * exten , * context ;
if ( argc ! = 4 & & argc ! = 3 ) return RESULT_SHOWUSAGE ;
/*
* Priority input checking . . .
*/
if ( argc = = 4 ) {
char * c = argv [ 3 ] ;
/* 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
*/
2003-03-30 22:55:42 +00:00
if ( strcmp ( " hint " , c ) ) {
while ( * c ! = ' \0 ' ) {
2001-09-12 21:29:54 +00:00
if ( ! isdigit ( * c + + ) ) {
ast_cli ( fd , " Invalid priority '%s' \n " , argv [ 3 ] ) ;
return RESULT_FAILURE ;
}
2003-03-30 22:55:42 +00:00
}
removing_priority = atoi ( argv [ 3 ] ) ;
} else
removing_priority = PRIORITY_HINT ;
2001-09-12 21:29:54 +00:00
if ( removing_priority = = 0 ) {
ast_cli ( fd , " If you want to remove whole extension, please " \
" omit priority argument \n " ) ;
return RESULT_FAILURE ;
}
}
/*
* Format exten @ context checking . . .
*/
if ( ! ( context = strchr ( argv [ 2 ] , ( int ) ' @ ' ) ) ) {
ast_cli ( fd , " First argument must be in exten@context format \n " ) ;
return RESULT_FAILURE ;
}
* context + + = ' \0 ' ;
exten = argv [ 2 ] ;
if ( ( ! strlen ( exten ) ) | | ( ! ( strlen ( context ) ) ) ) {
ast_cli ( fd , " Missing extension or context name in second argument '%s@%s' \n " ,
exten = = NULL ? " ? " : exten , context = = NULL ? " ? " : context ) ;
return RESULT_FAILURE ;
}
if ( ! ast_context_remove_extension ( context , exten , removing_priority , registrar ) ) {
if ( ! removing_priority )
ast_cli ( fd , " Whole extension %s@%s removed \n " ,
exten , context ) ;
else
ast_cli ( fd , " Extension %s@%s with priority %d removed \n " ,
exten , context , removing_priority ) ;
return RESULT_SUCCESS ;
}
ast_cli ( fd , " Failed to remove extension %s@%s \n " , exten , context ) ;
return RESULT_FAILURE ;
}
# 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 . . .
*/
static int fix_complete_args ( char * line , char * * word , int * pos )
{
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 */
static char * complete_context_remove_extension ( char * line , char * word , int pos ,
int state )
{
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
/*
* Fix arguments , * word is a new allocated structure , REMEMBER to
* free * word when you want to return from this function . . .
*/
if ( fix_complete_args ( line , & word , & pos ) ) {
ast_log ( LOG_ERROR , " Out of free memory \n " ) ;
return NULL ;
}
# endif
/*
* exten @ context completion . . .
*/
if ( pos = = 2 ) {
struct ast_context * c ;
struct ast_exten * e ;
char * context = NULL , * exten = NULL , * delim = NULL ;
/* now, parse values from word = exten@context */
if ( ( delim = strchr ( word , ( int ) ' @ ' ) ) ) {
/* check for duplicity ... */
if ( delim ! = strrchr ( word , ( int ) ' @ ' ) ) {
# ifdef BROKEN_READLINE
free ( word ) ;
# endif
return NULL ;
}
* delim = ' \0 ' ;
exten = strdup ( word ) ;
context = strdup ( delim + 1 ) ;
* delim = ' @ ' ;
} else {
exten = strdup ( word ) ;
}
# ifdef BROKEN_READLINE
free ( word ) ;
# endif
if ( ast_lock_contexts ( ) ) {
ast_log ( LOG_ERROR , " Failed to lock context list \n " ) ;
free ( context ) ; free ( exten ) ;
return NULL ;
}
/* find our context ... */
c = ast_walk_contexts ( NULL ) ;
while ( c ) {
/* our context? */
if ( ( ! context | | ! strlen ( context ) ) | | /* if no input, all contexts ... */
( context & & ! strncmp ( ast_get_context_name ( c ) ,
context , strlen ( context ) ) ) ) { /* if input, compare ... */
/* try to complete extensions ... */
e = ast_walk_context_extensions ( c , NULL ) ;
while ( e ) {
/* our extension? */
if ( ( ! exten | | ! strlen ( exten ) ) | | /* if not input, all extensions ... */
( exten & & ! strncmp ( ast_get_extension_name ( e ) , exten ,
strlen ( exten ) ) ) ) { /* if input, compare ... */
if ( + + which > state ) {
2004-05-01 05:50:51 +00:00
/* If there is an extension then return
* exten @ context .
2001-09-12 21:29:54 +00:00
*/
2004-05-01 05:50:51 +00:00
if ( exten ) {
2001-09-12 21:29:54 +00:00
ret = malloc ( strlen ( ast_get_extension_name ( e ) ) +
strlen ( ast_get_context_name ( c ) ) + 2 ) ;
if ( ret )
sprintf ( ret , " %s@%s " , ast_get_extension_name ( e ) ,
ast_get_context_name ( c ) ) ;
}
free ( exten ) ; free ( context ) ;
ast_unlock_contexts ( ) ;
return ret ;
}
}
e = ast_walk_context_extensions ( c , e ) ;
}
}
c = ast_walk_contexts ( c ) ;
}
ast_unlock_contexts ( ) ;
free ( exten ) ; free ( context ) ;
return NULL ;
}
/*
* Complete priority . . .
*/
if ( pos = = 3 ) {
char * delim , * exten , * context , * dupline , * duplinet , * ec ;
struct ast_context * c ;
dupline = strdup ( line ) ;
if ( ! dupline ) {
# ifdef BROKEN_READLINE
free ( word ) ;
# endif
return NULL ;
}
duplinet = dupline ;
strsep ( & duplinet , " " ) ; /* skip 'remove' */
strsep ( & duplinet , " " ) ; /* skip 'extension */
if ( ! ( ec = strsep ( & duplinet , " " ) ) ) {
free ( dupline ) ;
# ifdef BROKEN_READLINE
free ( word ) ;
# endif
return NULL ;
}
/* wrong exten@context format? */
if ( ! ( delim = strchr ( ec , ( int ) ' @ ' ) ) | |
( strchr ( ec , ( int ) ' @ ' ) ! = strrchr ( ec , ( int ) ' @ ' ) ) ) {
# ifdef BROKEN_READLINE
free ( word ) ;
# endif
free ( dupline ) ;
return NULL ;
}
/* check if there is exten and context too ... */
* delim = ' \0 ' ;
if ( ( ! strlen ( ec ) ) | | ( ! strlen ( delim + 1 ) ) ) {
# ifdef BROKEN_READLINE
free ( word ) ;
# endif
free ( dupline ) ;
return NULL ;
}
exten = strdup ( ec ) ;
context = strdup ( delim + 1 ) ;
free ( dupline ) ;
if ( ast_lock_contexts ( ) ) {
ast_log ( LOG_ERROR , " Failed to lock context list \n " ) ;
# ifdef BROKEN_READLINE
free ( word ) ;
# endif
free ( exten ) ; free ( context ) ;
return NULL ;
}
/* walk contexts */
c = ast_walk_contexts ( NULL ) ;
while ( c ) {
if ( ! strcmp ( ast_get_context_name ( c ) , context ) ) {
struct ast_exten * e ;
/* walk extensions */
free ( context ) ;
e = ast_walk_context_extensions ( c , NULL ) ;
while ( e ) {
if ( ! strcmp ( ast_get_extension_name ( e ) , exten ) ) {
struct ast_exten * priority ;
char buffer [ 10 ] ;
free ( exten ) ;
priority = ast_walk_extension_priorities ( e , NULL ) ;
/* serve priorities */
do {
snprintf ( buffer , 10 , " %u " ,
ast_get_extension_priority ( priority ) ) ;
if ( ! strncmp ( word , buffer , strlen ( word ) ) ) {
if ( + + which > state ) {
# ifdef BROKEN_READLINE
free ( word ) ;
# endif
ast_unlock_contexts ( ) ;
return strdup ( buffer ) ;
}
}
priority = ast_walk_extension_priorities ( e ,
priority ) ;
} while ( priority ) ;
# ifdef BROKEN_READLINE
free ( word ) ;
# endif
ast_unlock_contexts ( ) ;
return NULL ;
}
e = ast_walk_context_extensions ( c , e ) ;
}
# ifdef BROKEN_READLINE
free ( word ) ;
# endif
free ( exten ) ;
ast_unlock_contexts ( ) ;
return NULL ;
}
c = ast_walk_contexts ( c ) ;
}
# ifdef BROKEN_READLINE
free ( word ) ;
# endif
free ( exten ) ; free ( context ) ;
ast_unlock_contexts ( ) ;
return NULL ;
}
# ifdef BROKEN_READLINE
free ( word ) ;
# endif
return NULL ;
}
/*
* Include context . . .
*/
static int handle_context_add_include ( int fd , int argc , char * argv [ ] )
{
2004-01-31 20:22:25 +00:00
if ( argc ! = 5 ) return RESULT_SHOWUSAGE ;
2001-09-12 21:29:54 +00:00
/* third arg must be 'in' ... */
2004-01-31 20:22:25 +00:00
if ( strcmp ( argv [ 3 ] , " in " ) ) return RESULT_SHOWUSAGE ;
2001-09-12 21:29:54 +00:00
2004-01-31 20:22:25 +00:00
if ( ast_context_add_include ( argv [ 4 ] , argv [ 2 ] , registrar ) ) {
2001-09-12 21:29:54 +00:00
switch ( errno ) {
case ENOMEM :
ast_cli ( fd , " Out of memory for context addition \n " ) ; break ;
case EBUSY :
ast_cli ( fd , " Failed to lock context(s) list, please try again later \n " ) ; break ;
case EEXIST :
ast_cli ( fd , " Context '%s' already included in '%s' context \n " ,
argv [ 1 ] , argv [ 3 ] ) ; break ;
2003-04-23 19:13:35 +00:00
case ENOENT :
2001-09-12 21:29:54 +00:00
case EINVAL :
ast_cli ( fd , " There is no existence of context '%s' \n " ,
2004-01-31 20:22:25 +00:00
errno = = ENOENT ? argv [ 4 ] : argv [ 2 ] ) ; break ;
2001-09-12 21:29:54 +00:00
default :
ast_cli ( fd , " Failed to include '%s' in '%s' context \n " ,
argv [ 1 ] , argv [ 3 ] ) ; break ;
}
return RESULT_FAILURE ;
}
/* show some info ... */
ast_cli ( fd , " Context '%s' included in '%s' context \n " ,
2004-01-31 20:22:25 +00:00
argv [ 2 ] , argv [ 3 ] ) ;
2001-09-12 21:29:54 +00:00
return RESULT_SUCCESS ;
}
static char * complete_context_add_include ( char * line , char * word , int pos ,
int state )
{
struct ast_context * c ;
int which = 0 ;
/* server context for inclusion ... */
if ( pos = = 1 )
{
if ( ast_lock_contexts ( ) ) {
ast_log ( LOG_ERROR , " Failed to lock context list \n " ) ;
return NULL ;
}
/* server all contexts */
c = ast_walk_contexts ( NULL ) ;
while ( c ) {
if ( ( ! strlen ( word ) | |
! strncmp ( ast_get_context_name ( c ) , word , strlen ( word ) ) ) & &
+ + which > state )
{
char * context = strdup ( ast_get_context_name ( c ) ) ;
ast_unlock_contexts ( ) ;
return context ;
}
c = ast_walk_contexts ( c ) ;
}
ast_unlock_contexts ( ) ;
}
/* complete 'in' only if context exist ... */
if ( pos = = 2 )
{
char * context , * dupline , * duplinet ;
if ( state ! = 0 ) return NULL ;
/* parse context from line ... */
if ( ! ( dupline = strdup ( line ) ) ) {
ast_log ( LOG_ERROR , " Out of free memory \n " ) ;
if ( state = = 0 ) return strdup ( " in " ) ;
return NULL ;
}
duplinet = dupline ;
strsep ( & duplinet , " " ) ;
context = strsep ( & duplinet , " " ) ;
if ( context ) {
struct ast_context * c ;
int context_existence = 0 ;
/* check for context existence ... */
if ( ast_lock_contexts ( ) ) {
ast_log ( LOG_ERROR , " Failed to lock context list \n " ) ;
free ( dupline ) ;
/* our fault, we can't check, so complete 'in' ... */
return strdup ( " in " ) ;
}
c = ast_walk_contexts ( NULL ) ;
while ( c & & ! context_existence ) {
if ( ! strcmp ( context , ast_get_context_name ( c ) ) ) {
context_existence = 1 ;
continue ;
}
c = ast_walk_contexts ( c ) ;
}
/* if context exists, return 'into' ... */
if ( context_existence ) {
free ( dupline ) ;
ast_unlock_contexts ( ) ;
return strdup ( " into " ) ;
}
ast_unlock_contexts ( ) ;
}
free ( dupline ) ;
return NULL ;
}
/* serve context into which we include another context */
if ( pos = = 3 )
{
char * context , * dupline , * duplinet , * in ;
int context_existence = 0 ;
if ( ! ( dupline = strdup ( line ) ) ) {
ast_log ( LOG_ERROR , " Out of free memory \n " ) ;
return NULL ;
}
duplinet = dupline ;
strsep ( & duplinet , " " ) ; /* skip 'include' */
context = strsep ( & duplinet , " " ) ;
in = strsep ( & duplinet , " " ) ;
/* given some context and third word is in? */
if ( ! strlen ( context ) | | strcmp ( in , " in " ) ) {
free ( dupline ) ;
return NULL ;
}
if ( ast_lock_contexts ( ) ) {
ast_log ( LOG_ERROR , " Failed to lock context list \n " ) ;
free ( dupline ) ;
return NULL ;
}
/* check for context existence ... */
c = ast_walk_contexts ( NULL ) ;
while ( c & & ! context_existence ) {
if ( ! strcmp ( context , ast_get_context_name ( c ) ) ) {
context_existence = 1 ;
continue ;
}
c = ast_walk_contexts ( c ) ;
}
if ( ! context_existence ) {
free ( dupline ) ;
ast_unlock_contexts ( ) ;
return NULL ;
}
/* go through all contexts ... */
c = ast_walk_contexts ( NULL ) ;
while ( c ) {
/* must be different contexts ... */
if ( strcmp ( context , ast_get_context_name ( c ) ) ) {
if ( ! ast_lock_context ( c ) ) {
struct ast_include * i ;
int included = 0 ;
/* check for duplicity inclusion ... */
i = ast_walk_context_includes ( c , NULL ) ;
while ( i & & ! included ) {
if ( ! strcmp ( ast_get_include_name ( i ) , context ) )
included = 1 ;
i = ast_walk_context_includes ( c , i ) ;
}
ast_unlock_context ( c ) ;
/* not included yet, so show possibility ... */
if ( ! included & &
! strncmp ( ast_get_context_name ( c ) , word , strlen ( word ) ) ) {
if ( + + which > state ) {
char * res = strdup ( ast_get_context_name ( c ) ) ;
free ( dupline ) ;
ast_unlock_contexts ( ) ;
return res ;
}
}
}
}
c = ast_walk_contexts ( c ) ;
}
ast_unlock_contexts ( ) ;
free ( dupline ) ;
return NULL ;
}
return NULL ;
}
/*
* ' save dialplan ' CLI command implementation functions . . .
*/
static int handle_save_dialplan ( int fd , int argc , char * argv [ ] )
{
char filename [ 256 ] ;
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 context_header_written ;
int incomplete = 0 ; /* incomplete config write? */
FILE * output ;
if ( ! ( static_config & & ! write_protect_config ) ) {
ast_cli ( fd ,
" I can't save dialplan now, see '%s' example file. \n " ,
config ) ;
return RESULT_FAILURE ;
}
if ( argc ! = 2 & & argc ! = 3 ) return RESULT_SHOWUSAGE ;
2003-08-13 15:25:16 +00:00
if ( ast_mutex_lock ( & save_dialplan_lock ) ) {
2001-09-12 21:29:54 +00:00
ast_cli ( fd ,
" Failed to lock dialplan saving (another proccess saving?) \n " ) ;
return RESULT_FAILURE ;
}
/* have config path? */
if ( argc = = 3 ) {
/* is there extension.conf too? */
if ( ! strstr ( argv [ 2 ] , " .conf " ) ) {
/* no, only directory path, check for last '/' occurence */
if ( * ( argv [ 2 ] + strlen ( argv [ 2 ] ) - 1 ) = = ' / ' )
snprintf ( filename , sizeof ( filename ) , " %s%s " ,
argv [ 2 ] , config ) ;
else
/* without config extensions.conf, add it */
snprintf ( filename , sizeof ( filename ) , " %s/%s " ,
argv [ 2 ] , config ) ;
} else
/* there is an .conf */
snprintf ( filename , sizeof ( filename ) , argv [ 2 ] ) ;
} else
/* no config file, default one */
snprintf ( filename , sizeof ( filename ) , " %s/%s " ,
2003-01-30 15:03:20 +00:00
( char * ) ast_config_AST_CONFIG_DIR , config ) ;
2001-09-12 21:29:54 +00:00
2005-01-25 06:10:20 +00:00
cfg = ast_config_load ( " extensions.conf " ) ;
2004-01-28 01:29:47 +00:00
2001-09-12 21:29:54 +00:00
/* try to lock contexts list */
if ( ast_lock_contexts ( ) ) {
ast_cli ( 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 ) ;
2001-09-12 21:29:54 +00:00
return RESULT_FAILURE ;
}
/* create new file ... */
if ( ! ( output = fopen ( filename , " wt " ) ) ) {
ast_cli ( fd , " Failed to create file '%s' \n " ,
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 ) ;
2001-09-12 21:29:54 +00:00
return RESULT_FAILURE ;
}
/* fireout general info */
fprintf ( output , " [general] \n static=%s \n writeprotect=%s \n \n " ,
static_config ? " yes " : " no " ,
write_protect_config ? " yes " : " no " ) ;
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
2001-09-12 21:29:54 +00:00
/* walk all contexts */
c = ast_walk_contexts ( NULL ) ;
while ( c ) {
context_header_written = 0 ;
/* try to lock context and fireout all info */
if ( ! ast_lock_context ( c ) ) {
struct ast_exten * e , * last_written_e = NULL ;
struct ast_include * i ;
struct ast_ignorepat * ip ;
2004-08-21 18:55:39 +00:00
struct ast_sw * sw ;
2001-09-12 21:29:54 +00:00
/* registered by this module? */
if ( ! strcmp ( ast_get_context_registrar ( c ) , registrar ) ) {
fprintf ( output , " [%s] \n " , ast_get_context_name ( c ) ) ;
context_header_written = 1 ;
}
/* walk extensions ... */
e = ast_walk_context_extensions ( c , NULL ) ;
while ( e ) {
struct ast_exten * p ;
/* fireout priorities */
p = ast_walk_extension_priorities ( e , NULL ) ;
while ( p ) {
if ( ! strcmp ( ast_get_extension_registrar ( p ) ,
registrar ) ) {
/* 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 ;
if ( ! context_header_written ) {
fprintf ( output , " [%s] \n " , ast_get_context_name ( c ) ) ;
context_header_written = 1 ;
}
2003-05-30 14:32:18 +00:00
if ( ast_get_extension_priority ( p ) ! = PRIORITY_HINT ) {
char * tempdata = NULL , * startdata ;
tempdata = strdup ( ( char * ) ast_get_extension_app_data ( p ) ) ;
if ( tempdata ) {
startdata = tempdata ;
while ( * tempdata ) {
if ( * tempdata = = ' | ' )
* tempdata = ' , ' ;
tempdata + + ;
}
tempdata = startdata ;
}
2004-08-21 18:55:39 +00:00
if ( ast_get_extension_matchcid ( p ) )
fprintf ( output , " exten => %s/%s,%d,%s(%s) \n " ,
ast_get_extension_name ( p ) ,
ast_get_extension_cidmatch ( p ) ,
ast_get_extension_priority ( p ) ,
ast_get_extension_app ( p ) ,
tempdata ) ;
else
fprintf ( output , " exten => %s,%d,%s(%s) \n " ,
ast_get_extension_name ( p ) ,
ast_get_extension_priority ( p ) ,
ast_get_extension_app ( p ) ,
tempdata ) ;
2003-05-30 14:32:18 +00:00
if ( tempdata )
free ( tempdata ) ;
} else
2003-03-30 22:55:42 +00:00
fprintf ( output , " exten => %s,hint,%s \n " ,
ast_get_extension_name ( p ) ,
ast_get_extension_app ( p ) ) ;
2001-09-12 21:29:54 +00:00
}
p = ast_walk_extension_priorities ( e , p ) ;
}
e = ast_walk_context_extensions ( c , e ) ;
}
/* written any extensions? ok, write space between exten & inc */
if ( last_written_e ) fprintf ( output , " \n " ) ;
/* walk through includes */
i = ast_walk_context_includes ( c , NULL ) ;
while ( i ) {
if ( ! strcmp ( ast_get_include_registrar ( i ) , registrar ) ) {
if ( ! context_header_written ) {
fprintf ( output , " [%s] \n " , ast_get_context_name ( c ) ) ;
context_header_written = 1 ;
}
fprintf ( output , " include => %s \n " ,
ast_get_include_name ( i ) ) ;
}
i = ast_walk_context_includes ( c , i ) ;
}
if ( ast_walk_context_includes ( c , NULL ) )
fprintf ( output , " \n " ) ;
2004-08-21 18:55:39 +00:00
/* walk through switches */
sw = ast_walk_context_switches ( c , NULL ) ;
while ( sw ) {
if ( ! strcmp ( ast_get_switch_registrar ( sw ) , registrar ) ) {
if ( ! context_header_written ) {
fprintf ( output , " [%s] \n " , ast_get_context_name ( c ) ) ;
context_header_written = 1 ;
}
fprintf ( output , " switch => %s/%s \n " ,
ast_get_switch_name ( sw ) ,
ast_get_switch_data ( sw ) ) ;
}
sw = ast_walk_context_switches ( c , sw ) ;
}
if ( ast_walk_context_switches ( c , NULL ) )
fprintf ( output , " \n " ) ;
2001-09-12 21:29:54 +00:00
/* fireout ignorepats ... */
ip = ast_walk_context_ignorepats ( c , NULL ) ;
while ( ip ) {
if ( ! strcmp ( ast_get_ignorepat_registrar ( ip ) , registrar ) ) {
if ( ! context_header_written ) {
fprintf ( output , " [%s] \n " , ast_get_context_name ( c ) ) ;
context_header_written = 1 ;
}
fprintf ( output , " ignorepat => %s \n " ,
ast_get_ignorepat_name ( ip ) ) ;
}
ip = ast_walk_context_ignorepats ( c , ip ) ;
}
ast_unlock_context ( c ) ;
} else
incomplete = 1 ;
c = ast_walk_contexts ( c ) ;
}
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 ) {
ast_cli ( fd , " Saved dialplan is incomplete \n " ) ;
return RESULT_FAILURE ;
}
2005-03-23 21:45:05 +00:00
ast_cli ( fd , " Dialplan successfully saved into '%s' \n " ,
2001-09-12 21:29:54 +00:00
filename ) ;
return RESULT_SUCCESS ;
}
/*
* ADD EXTENSION command stuff
*/
static int handle_context_add_extension ( int fd , int argc , char * argv [ ] )
{
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
/* check for arguments at first */
if ( argc ! = 5 & & argc ! = 6 ) return RESULT_SHOWUSAGE ;
if ( strcmp ( argv [ 3 ] , " into " ) ) return RESULT_SHOWUSAGE ;
if ( argc = = 6 ) if ( strcmp ( argv [ 5 ] , " replace " ) ) return RESULT_SHOWUSAGE ;
whole_exten = argv [ 2 ] ;
exten = strsep ( & whole_exten , " , " ) ;
if ( strchr ( exten , ' / ' ) ) {
cidmatch = exten ;
strsep ( & cidmatch , " / " ) ;
} else {
cidmatch = NULL ;
}
prior = strsep ( & whole_exten , " , " ) ;
2003-04-06 18:19:51 +00:00
if ( prior ) {
2003-11-23 22:40:37 +00:00
if ( ! strcmp ( prior , " hint " ) ) {
2003-04-06 18:19:51 +00:00
iprior = PRIORITY_HINT ;
} else {
2003-12-03 02:45:24 +00:00
if ( sscanf ( prior , " %i " , & iprior ) ! = 1 ) {
2003-11-23 22:40:37 +00:00
ast_cli ( fd , " '%s' is not a valid priority \n " , prior ) ;
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-06-14 22:03:59 +00:00
process_quotes_and_slashes ( app_data , ' , ' , ' | ' ) ;
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
2003-03-30 22:55:42 +00:00
if ( ! exten | | ! prior | | ! app | | ( ! app_data & & iprior ! = PRIORITY_HINT ) ) return RESULT_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 = " " ;
2004-10-03 04:19:59 +00:00
if ( ast_add_extension ( argv [ 4 ] , argc = = 6 ? 1 : 0 , exten , iprior , NULL , cidmatch , app ,
2001-09-12 21:29:54 +00:00
( void * ) strdup ( app_data ) , free , registrar ) ) {
switch ( errno ) {
case ENOMEM :
ast_cli ( fd , " Out of free memory \n " ) ; break ;
case EBUSY :
ast_cli ( fd , " Failed to lock context(s) list, please try again later \n " ) ; break ;
2003-04-23 19:13:35 +00:00
case ENOENT :
2001-09-12 21:29:54 +00:00
ast_cli ( fd , " No existence of '%s' context \n " , argv [ 4 ] ) ; break ;
case EEXIST :
ast_cli ( fd , " Extension %s@%s with priority %s already exists \n " ,
exten , argv [ 4 ] , prior ) ; break ;
default :
ast_cli ( fd , " Failed to add '%s,%s,%s,%s' extension into '%s' context \n " ,
exten , prior , app , app_data , argv [ 4 ] ) ; break ;
}
return RESULT_FAILURE ;
}
if ( argc = = 6 )
ast_cli ( fd , " Extension %s@%s (%s) replace by '%s,%s,%s,%s' \n " ,
exten , argv [ 4 ] , prior , exten , prior , app , app_data ) ;
else
ast_cli ( fd , " Extension '%s,%s,%s,%s' added into '%s' context \n " ,
exten , prior , app , app_data , argv [ 4 ] ) ;
return RESULT_SUCCESS ;
}
/* add extension 6123,1,Dial,IAX/212.71.138.13/6123 into local */
static char * complete_context_add_extension ( char * line , char * word ,
int pos , int state )
{
int which = 0 ;
/* complete 'into' word ... */
if ( pos = = 3 ) {
if ( state = = 0 ) return strdup ( " into " ) ;
return NULL ;
}
/* complete context */
if ( pos = = 4 ) {
struct ast_context * c ;
/* try to lock contexts list ... */
if ( ast_lock_contexts ( ) ) {
ast_log ( LOG_WARNING , " Failed to lock contexts list \n " ) ;
return NULL ;
}
/* walk through all contexts */
c = ast_walk_contexts ( NULL ) ;
while ( c ) {
/* matching context? */
if ( ! strncmp ( ast_get_context_name ( c ) , word , strlen ( word ) ) ) {
if ( + + which > state ) {
char * res = strdup ( ast_get_context_name ( c ) ) ;
ast_unlock_contexts ( ) ;
return res ;
}
}
c = ast_walk_contexts ( c ) ;
}
ast_unlock_contexts ( ) ;
return NULL ;
}
if ( pos = = 5 ) return state = = 0 ? strdup ( " replace " ) : NULL ;
return NULL ;
}
/*
* IGNOREPAT CLI stuff
*/
static int handle_context_add_ignorepat ( int fd , int argc , char * argv [ ] )
{
if ( argc ! = 5 ) return RESULT_SHOWUSAGE ;
if ( strcmp ( argv [ 3 ] , " into " ) ) return RESULT_SHOWUSAGE ;
if ( ast_context_add_ignorepat ( argv [ 4 ] , argv [ 2 ] , registrar ) ) {
switch ( errno ) {
case ENOMEM :
ast_cli ( fd , " Out of free memory \n " ) ; break ;
2003-04-23 19:13:35 +00:00
case ENOENT :
2001-09-12 21:29:54 +00:00
ast_cli ( fd , " There is no existence of '%s' context \n " , argv [ 4 ] ) ;
break ;
case EEXIST :
ast_cli ( fd , " Ignore pattern '%s' already included in '%s' context \n " ,
argv [ 2 ] , argv [ 4 ] ) ;
break ;
case EBUSY :
ast_cli ( fd , " Failed to lock context(s) list, please, try again later \n " ) ;
break ;
default :
ast_cli ( fd , " Failed to add ingore pattern '%s' into '%s' context \n " ,
argv [ 2 ] , argv [ 4 ] ) ;
break ;
}
return RESULT_FAILURE ;
}
ast_cli ( fd , " Ignore pattern '%s' added into '%s' context \n " ,
argv [ 2 ] , argv [ 4 ] ) ;
return RESULT_SUCCESS ;
}
static char * complete_context_add_ignorepat ( char * line , char * word ,
int pos , int state )
{
if ( pos = = 3 ) return state = = 0 ? strdup ( " into " ) : NULL ;
if ( pos = = 4 ) {
struct ast_context * c ;
int which = 0 ;
char * dupline , * duplinet , * ignorepat = NULL ;
dupline = strdup ( line ) ;
duplinet = dupline ;
if ( duplinet ) {
strsep ( & duplinet , " " ) ; /* skip 'add' */
strsep ( & duplinet , " " ) ; /* skip 'ignorepat' */
ignorepat = strsep ( & duplinet , " " ) ;
}
if ( ast_lock_contexts ( ) ) {
ast_log ( LOG_ERROR , " Failed to lock contexts list \n " ) ;
return NULL ;
}
c = ast_walk_contexts ( NULL ) ;
while ( c ) {
if ( ! strncmp ( ast_get_context_name ( c ) , word , strlen ( word ) ) ) {
int serve_context = 1 ;
if ( ignorepat ) {
if ( ! ast_lock_context ( c ) ) {
struct ast_ignorepat * ip ;
ip = ast_walk_context_ignorepats ( c , NULL ) ;
while ( ip & & serve_context ) {
if ( ! strcmp ( ast_get_ignorepat_name ( ip ) , ignorepat ) )
serve_context = 0 ;
ip = ast_walk_context_ignorepats ( c , ip ) ;
}
ast_unlock_context ( c ) ;
}
}
if ( serve_context ) {
if ( + + which > state ) {
char * context = strdup ( ast_get_context_name ( c ) ) ;
if ( dupline ) free ( dupline ) ;
ast_unlock_contexts ( ) ;
return context ;
}
}
}
c = ast_walk_contexts ( c ) ;
}
if ( dupline ) free ( dupline ) ;
ast_unlock_contexts ( ) ;
return NULL ;
}
return NULL ;
}
static int handle_context_remove_ignorepat ( int fd , int argc , char * argv [ ] )
{
if ( argc ! = 5 ) return RESULT_SHOWUSAGE ;
if ( strcmp ( argv [ 3 ] , " from " ) ) return RESULT_SHOWUSAGE ;
if ( ast_context_remove_ignorepat ( argv [ 4 ] , argv [ 2 ] , registrar ) ) {
switch ( errno ) {
case EBUSY :
ast_cli ( fd , " Failed to lock context(s) list, please try again later \n " ) ;
break ;
2003-04-23 19:13:35 +00:00
case ENOENT :
2001-09-12 21:29:54 +00:00
ast_cli ( fd , " There is no existence of '%s' context \n " , argv [ 4 ] ) ;
break ;
case EINVAL :
ast_cli ( fd , " There is no existence of '%s' ignore pattern in '%s' context \n " ,
argv [ 2 ] , argv [ 4 ] ) ;
break ;
default :
2003-09-10 05:24:49 +00:00
ast_cli ( fd , " Failed to remove ignore pattern '%s' from '%s' context \n " , argv [ 2 ] , argv [ 4 ] ) ;
2001-09-12 21:29:54 +00:00
break ;
}
return RESULT_FAILURE ;
}
ast_cli ( fd , " Ignore pattern '%s' removed from '%s' context \n " ,
argv [ 2 ] , argv [ 4 ] ) ;
return RESULT_SUCCESS ;
}
2003-07-14 15:33:21 +00:00
static int pbx_load_module ( void ) ;
static int handle_reload_extensions ( int fd , int argc , char * argv [ ] )
{
if ( argc ! = 2 ) return RESULT_SHOWUSAGE ;
pbx_load_module ( ) ;
return RESULT_SUCCESS ;
}
2001-09-12 21:29:54 +00:00
static char * complete_context_remove_ignorepat ( char * line , char * word ,
int pos , int state )
{
struct ast_context * c ;
int which = 0 ;
if ( pos = = 2 ) {
if ( ast_lock_contexts ( ) ) {
ast_log ( LOG_WARNING , " Failed to lock contexts list \n " ) ;
return NULL ;
}
c = ast_walk_contexts ( NULL ) ;
while ( c ) {
if ( ! ast_lock_context ( c ) ) {
struct ast_ignorepat * ip ;
ip = ast_walk_context_ignorepats ( c , NULL ) ;
while ( ip ) {
if ( ! strncmp ( ast_get_ignorepat_name ( ip ) , word , strlen ( word ) ) ) {
if ( which + 1 > state ) {
struct ast_context * cw ;
int already_served = 0 ;
cw = ast_walk_contexts ( NULL ) ;
while ( cw & & cw ! = c & & ! already_served ) {
if ( ! ast_lock_context ( cw ) ) {
struct ast_ignorepat * ipw ;
ipw = ast_walk_context_ignorepats ( cw , NULL ) ;
while ( ipw ) {
if ( ! strcmp ( ast_get_ignorepat_name ( ipw ) ,
ast_get_ignorepat_name ( ip ) ) ) already_served = 1 ;
ipw = ast_walk_context_ignorepats ( cw , ipw ) ;
}
ast_unlock_context ( cw ) ;
}
cw = ast_walk_contexts ( cw ) ;
}
if ( ! already_served ) {
char * ret = strdup ( ast_get_ignorepat_name ( ip ) ) ;
ast_unlock_context ( c ) ;
ast_unlock_contexts ( ) ;
return ret ;
}
} else
which + + ;
}
ip = ast_walk_context_ignorepats ( c , ip ) ;
}
ast_unlock_context ( c ) ;
}
c = ast_walk_contexts ( c ) ;
}
ast_unlock_contexts ( ) ;
return NULL ;
}
if ( pos = = 3 ) return state = = 0 ? strdup ( " from " ) : NULL ;
if ( pos = = 4 ) {
char * dupline , * duplinet , * ignorepat ;
dupline = strdup ( line ) ;
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 ;
}
if ( ast_lock_contexts ( ) ) {
ast_log ( LOG_WARNING , " Failed to lock contexts list \n " ) ;
free ( dupline ) ;
return NULL ;
}
c = ast_walk_contexts ( NULL ) ;
while ( c ) {
if ( ! ast_lock_context ( c ) ) {
struct ast_ignorepat * ip ;
ip = ast_walk_context_ignorepats ( c , NULL ) ;
while ( ip ) {
if ( ! strcmp ( ast_get_ignorepat_name ( ip ) , ignorepat ) ) {
if ( ! strncmp ( ast_get_context_name ( c ) , word , strlen ( word ) ) ) {
if ( + + which > state ) {
char * ret = strdup ( ast_get_context_name ( c ) ) ;
free ( dupline ) ;
ast_unlock_context ( c ) ;
ast_unlock_contexts ( ) ;
return ret ;
}
}
}
ip = ast_walk_context_ignorepats ( c , ip ) ;
}
ast_unlock_context ( c ) ;
}
c = ast_walk_contexts ( c ) ;
}
free ( dupline ) ;
ast_unlock_contexts ( ) ;
return NULL ;
}
return NULL ;
}
/*
* CLI entries for commands provided by this module
*/
static struct ast_cli_entry context_dont_include_cli =
{ { " dont " , " include " , NULL } , handle_context_dont_include ,
" Remove a specified include from context " , context_dont_include_help ,
complete_context_dont_include } ;
static struct ast_cli_entry context_remove_extension_cli =
{ { " remove " , " extension " , NULL } , handle_context_remove_extension ,
" Remove a specified extension " , context_remove_extension_help ,
complete_context_remove_extension } ;
static struct ast_cli_entry context_add_include_cli =
{ { " include " , " context " , NULL } , handle_context_add_include ,
" Include context in other context " , context_add_include_help ,
complete_context_add_include } ;
static struct ast_cli_entry save_dialplan_cli =
{ { " save " , " dialplan " , NULL } , handle_save_dialplan ,
" Save dialplan " , save_dialplan_help } ;
static struct ast_cli_entry context_add_extension_cli =
{ { " add " , " extension " , NULL } , handle_context_add_extension ,
" Add new extension into context " , context_add_extension_help ,
complete_context_add_extension } ;
static struct ast_cli_entry context_add_ignorepat_cli =
{ { " add " , " ignorepat " , NULL } , handle_context_add_ignorepat ,
" Add new ignore pattern " , context_add_ignorepat_help ,
complete_context_add_ignorepat } ;
static struct ast_cli_entry context_remove_ignorepat_cli =
{ { " remove " , " ignorepat " , NULL } , handle_context_remove_ignorepat ,
" Remove ignore pattern from context " , context_remove_ignorepat_help ,
complete_context_remove_ignorepat } ;
2003-07-14 15:33:21 +00:00
static struct ast_cli_entry reload_extensions_cli =
{ { " extensions " , " reload " , NULL } , handle_reload_extensions ,
" Reload extensions and *only* extensions " , reload_extensions_help } ;
2001-09-12 21:29:54 +00:00
/*
* Standard module functions . . .
*/
1999-10-13 04:15:49 +00:00
int unload_module ( void )
{
2001-09-12 21:29:54 +00:00
ast_cli_unregister ( & context_add_extension_cli ) ;
if ( static_config & & ! write_protect_config )
ast_cli_unregister ( & save_dialplan_cli ) ;
ast_cli_unregister ( & context_add_include_cli ) ;
ast_cli_unregister ( & context_dont_include_cli ) ;
ast_cli_unregister ( & context_remove_extension_cli ) ;
ast_cli_unregister ( & context_remove_ignorepat_cli ) ;
ast_cli_unregister ( & context_add_ignorepat_cli ) ;
2003-07-14 15:33:21 +00:00
ast_cli_unregister ( & reload_extensions_cli ) ;
2001-04-17 16:49:37 +00:00
ast_context_destroy ( NULL , registrar ) ;
1999-10-13 04:15:49 +00:00
return 0 ;
}
2001-04-17 16:49:37 +00:00
static int pbx_load_module ( void )
1999-10-13 04:15:49 +00:00
{
struct ast_config * cfg ;
struct ast_variable * v ;
2001-09-12 21:29:54 +00:00
char * cxt , * ext , * pri , * appl , * data , * tc , * cidmatch ;
1999-10-13 04:15:49 +00:00
struct ast_context * con ;
2003-02-12 13:59:15 +00:00
char * start , * 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 ;
1999-10-13 04:15:49 +00:00
2005-01-25 06:10:20 +00:00
cfg = ast_config_load ( config ) ;
1999-10-13 04:15:49 +00:00
if ( cfg ) {
/* Use existing config to populate the PBX table */
2001-09-12 21:29:54 +00:00
static_config = ast_true ( ast_variable_retrieve ( cfg , " general " ,
" static " ) ) ;
write_protect_config = ast_true ( ast_variable_retrieve ( cfg , " general " ,
" writeprotect " ) ) ;
2004-10-16 19:46:02 +00:00
autofallthrough_config = ast_true ( ast_variable_retrieve ( cfg , " general " ,
" autofallthrough " ) ) ;
2003-02-12 13:59:15 +00:00
v = ast_variable_browse ( cfg , " globals " ) ;
while ( v ) {
2003-08-03 19:26:09 +00:00
memset ( realvalue , 0 , sizeof ( realvalue ) ) ;
2003-08-03 18:33:50 +00:00
pbx_substitute_variables_helper ( NULL , v - > value , realvalue , sizeof ( realvalue ) - 1 ) ;
pbx_builtin_setvar_helper ( NULL , v - > name , realvalue ) ;
2003-02-12 13:59:15 +00:00
v = v - > next ;
}
1999-10-13 04:15:49 +00:00
cxt = ast_category_browse ( cfg , NULL ) ;
while ( cxt ) {
2004-02-23 05:37:24 +00:00
/* All categories but "general" or "globals" are considered contexts */
2003-02-12 13:59:15 +00:00
if ( ! strcasecmp ( cxt , " general " ) | | ! strcasecmp ( cxt , " globals " ) ) {
1999-10-13 04:15:49 +00:00
cxt = ast_category_browse ( cfg , cxt ) ;
continue ;
}
2003-07-14 15:33:21 +00:00
if ( ( con = ast_context_create ( & local_contexts , cxt , registrar ) ) ) {
1999-10-13 04:15:49 +00:00
v = ast_variable_browse ( cfg , cxt ) ;
while ( v ) {
2001-03-30 16:31:28 +00:00
if ( ! strcasecmp ( v - > name , " exten " ) ) {
2003-01-30 15:03:20 +00:00
char * stringp = NULL ;
2003-03-30 22:55:42 +00:00
int ipri = - 2 ;
2003-08-03 18:39:51 +00:00
char realext [ 256 ] = " " ;
2004-10-03 05:08:51 +00:00
char * plus ;
2001-03-30 16:31:28 +00:00
tc = strdup ( v - > value ) ;
2003-01-30 15:03:20 +00:00
if ( tc ! = NULL ) {
stringp = tc ;
ext = strsep ( & stringp , " , " ) ;
if ( ! ext )
ext = " " ;
2004-10-03 16:15:44 +00:00
cidmatch = strchr ( ext , ' / ' ) ;
if ( cidmatch ) {
* cidmatch = ' \0 ' ;
cidmatch + + ;
ast_shrink_phone_number ( cidmatch ) ;
}
2003-01-30 15:03:20 +00:00
pri = strsep ( & stringp , " , " ) ;
if ( ! pri )
pri = " " ;
2004-10-03 04:19:59 +00:00
label = strchr ( pri , ' ( ' ) ;
if ( label ) {
* label = ' \0 ' ;
label + + ;
end = strchr ( label , ' ) ' ) ;
if ( end )
* end = ' \0 ' ;
else
ast_log ( LOG_WARNING , " Label missing trailing ')' at line %d \n " , v - > lineno ) ;
}
2004-10-03 05:08:51 +00:00
plus = strchr ( pri , ' + ' ) ;
if ( plus ) {
* plus = ' \0 ' ;
plus + + ;
}
2003-03-30 22:55:42 +00:00
if ( ! strcmp ( pri , " hint " ) )
ipri = PRIORITY_HINT ;
2004-10-02 20:43:16 +00:00
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 " ) ;
2004-10-03 05:08:51 +00:00
} else {
2003-11-23 22:40:37 +00:00
if ( sscanf ( pri , " %i " , & ipri ) ! = 1 ) {
2004-10-03 16:15:44 +00:00
if ( ( ipri = ast_findlabel_extension2 ( NULL , con , ext , pri , cidmatch ) ) < 1 ) {
ast_log ( LOG_WARNING , " Invalid priority/label '%s' at line %d \n " , pri , v - > lineno ) ;
ipri = 0 ;
}
2003-11-23 22:40:37 +00:00
}
}
2003-02-12 13:59:15 +00:00
appl = stringp ;
2003-01-30 15:03:20 +00:00
if ( ! appl )
appl = " " ;
2003-03-18 06:00:18 +00:00
if ( ! ( start = strchr ( appl , ' ( ' ) ) ) {
if ( stringp )
appl = strsep ( & stringp , " , " ) ;
else
appl = " " ;
}
2003-02-12 13:59:15 +00:00
if ( start & & ( end = strrchr ( appl , ' ) ' ) ) ) {
* start = * end = ' \0 ' ;
data = start + 1 ;
2004-06-14 22:05:12 +00:00
process_quotes_and_slashes ( data , ' , ' , ' | ' ) ;
2003-02-12 13:59:15 +00:00
} else if ( stringp ! = NULL & & * stringp = = ' " ' ) {
2003-01-30 15:03:20 +00:00
stringp + + ;
data = strsep ( & stringp , " \" " ) ;
stringp + + ;
} else {
2003-03-18 06:00:18 +00:00
if ( stringp )
data = strsep ( & stringp , " , " ) ;
else
data = " " ;
2003-01-30 15:03:20 +00:00
}
2001-09-12 21:29:54 +00:00
2003-01-30 15:03:20 +00:00
if ( ! data )
data = " " ;
2003-11-23 22:45:42 +00:00
while ( * appl & & ( * appl < 33 ) ) appl + + ;
2003-08-03 18:39:51 +00:00
pbx_substitute_variables_helper ( NULL , ext , realext , sizeof ( realext ) - 1 ) ;
2003-11-23 22:40:37 +00:00
if ( ipri ) {
2004-10-03 05:08:51 +00:00
if ( plus )
ipri + = atoi ( plus ) ;
2004-10-02 20:43:16 +00:00
lastpri = ipri ;
2005-04-15 06:08:47 +00:00
if ( ! 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 ) ;
2004-10-03 04:19:59 +00:00
if ( ast_add_extension2 ( con , 0 , realext , ipri , label , cidmatch , appl , strdup ( data ) , FREE , registrar ) ) {
2003-11-23 22:40:37 +00:00
ast_log ( LOG_WARNING , " Unable to register extension at line %d \n " , v - > lineno ) ;
}
2003-01-30 15:03:20 +00:00
}
free ( tc ) ;
} else fprintf ( stderr , " Error strdup returned NULL in %s \n " , __PRETTY_FUNCTION__ ) ;
2001-03-30 16:31:28 +00:00
} else if ( ! strcasecmp ( v - > name , " include " ) ) {
2003-08-03 19:26:09 +00:00
memset ( realvalue , 0 , sizeof ( realvalue ) ) ;
2003-08-03 18:39:51 +00:00
pbx_substitute_variables_helper ( NULL , v - > value , realvalue , sizeof ( realvalue ) - 1 ) ;
if ( ast_context_add_include2 ( con , realvalue , registrar ) )
2001-03-30 16:31:28 +00:00
ast_log ( LOG_WARNING , " Unable to include context '%s' in context '%s' \n " , v - > value , cxt ) ;
2001-09-12 21:29:54 +00:00
} else if ( ! strcasecmp ( v - > name , " ignorepat " ) ) {
2003-08-03 19:26:09 +00:00
memset ( realvalue , 0 , sizeof ( realvalue ) ) ;
2003-08-03 18:39:51 +00:00
pbx_substitute_variables_helper ( NULL , v - > value , realvalue , sizeof ( realvalue ) - 1 ) ;
if ( ast_context_add_ignorepat2 ( con , realvalue , registrar ) )
2001-09-12 21:29:54 +00:00
ast_log ( LOG_WARNING , " Unable to include ignorepat '%s' in context '%s' \n " , v - > value , cxt ) ;
2005-01-13 05:14:56 +00:00
} else if ( ! strcasecmp ( v - > name , " switch " ) | | ! strcasecmp ( v - > name , " lswitch " ) | | ! strcasecmp ( v - > name , " eswitch " ) ) {
2003-01-30 15:03:20 +00:00
char * stringp = NULL ;
2003-08-03 19:26:09 +00:00
memset ( realvalue , 0 , sizeof ( realvalue ) ) ;
2004-10-24 02:53:24 +00:00
if ( ! strcasecmp ( v - > name , " switch " ) )
pbx_substitute_variables_helper ( NULL , v - > value , realvalue , sizeof ( realvalue ) - 1 ) ;
else
strncpy ( realvalue , v - > value , sizeof ( realvalue ) - 1 ) ;
2003-08-03 18:39:51 +00:00
tc = realvalue ;
2003-01-30 15:03:20 +00:00
stringp = tc ;
appl = strsep ( & stringp , " / " ) ;
data = strsep ( & stringp , " " ) ;
2001-09-12 21:29:54 +00:00
if ( ! data )
data = " " ;
2005-01-13 05:14:56 +00:00
if ( ast_context_add_switch2 ( con , appl , data , ! strcasecmp ( v - > name , " eswitch " ) , registrar ) )
2001-09-12 21:29:54 +00:00
ast_log ( LOG_WARNING , " Unable to include switch '%s' in context '%s' \n " , v - > value , cxt ) ;
1999-10-13 04:15:49 +00:00
}
v = v - > next ;
}
}
cxt = ast_category_browse ( cfg , cxt ) ;
}
2005-01-25 06:10:20 +00:00
ast_config_destroy ( cfg ) ;
1999-10-13 04:15:49 +00:00
}
2003-07-14 17:16:47 +00:00
ast_merge_contexts_and_delete ( & local_contexts , registrar ) ;
2003-10-25 17:50:06 +00:00
for ( con = ast_walk_contexts ( NULL ) ; con ; con = ast_walk_contexts ( con ) )
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 ;
}
2001-04-17 16:49:37 +00:00
int load_module ( void )
{
2001-09-12 21:29:54 +00:00
if ( pbx_load_module ( ) ) return - 1 ;
ast_cli_register ( & context_remove_extension_cli ) ;
ast_cli_register ( & context_dont_include_cli ) ;
ast_cli_register ( & context_add_include_cli ) ;
if ( static_config & & ! write_protect_config )
ast_cli_register ( & save_dialplan_cli ) ;
ast_cli_register ( & context_add_extension_cli ) ;
ast_cli_register ( & context_add_ignorepat_cli ) ;
ast_cli_register ( & context_remove_ignorepat_cli ) ;
2003-07-14 15:33:21 +00:00
ast_cli_register ( & reload_extensions_cli ) ;
2001-09-12 21:29:54 +00:00
return 0 ;
2001-04-17 16:49:37 +00:00
}
int reload ( void )
{
ast_context_destroy ( NULL , registrar ) ;
2003-02-13 06:00:14 +00:00
/* For martin's global variables, don't clear them on reload */
#if 0
2003-02-12 13:59:15 +00:00
pbx_builtin_clear_globals ( ) ;
2003-02-13 06:00:14 +00:00
# endif
2001-09-12 21:29:54 +00:00
pbx_load_module ( ) ;
2001-04-17 16:49:37 +00:00
return 0 ;
}
1999-10-13 04:15:49 +00:00
int usecount ( void )
{
return 0 ;
}
char * description ( void )
{
return dtext ;
}
2001-03-30 16:31:28 +00:00
char * key ( void )
{
return ASTERISK_GPL_KEY ;
}