1999-10-24 18:00:20 +00:00
/*
* Asterisk - - A telephony toolkit for Linux .
*
* Configuration File Parser
*
2005-01-21 07:06:25 +00:00
* Copyright ( C ) 1999 - 2005 , Digium , Inc .
1999-10-24 18:00:20 +00:00
*
2004-10-02 17:16:36 +00:00
* Mark Spencer < markster @ digium . com >
1999-10-24 18:00:20 +00:00
*
* This program is free software , distributed under the terms of
* the GNU General Public License
*/
# include <stdio.h>
# include <unistd.h>
# include <stdlib.h>
# include <string.h>
# include <errno.h>
2003-03-09 06:00:18 +00:00
# include <time.h>
2004-12-11 05:16:30 +00:00
# define AST_INCLUDE_GLOB 1
# ifdef AST_INCLUDE_GLOB
2004-12-19 17:33:19 +00:00
# ifdef __OSX__
# define GLOB_ABORTED GLOB_ABEND
# endif
2004-12-11 05:16:30 +00:00
# include <glob.h>
# endif
1999-10-24 18:00:20 +00:00
# include <asterisk/config.h>
2004-06-11 00:12:35 +00:00
# include <asterisk/cli.h>
# include <asterisk/lock.h>
1999-10-24 18:00:20 +00:00
# include <asterisk/options.h>
# include <asterisk/logger.h>
2004-05-04 14:54:42 +00:00
# include <asterisk/utils.h>
2005-02-02 03:38:24 +00:00
# include <asterisk/channel.h>
# include <asterisk/app.h>
1999-10-24 18:00:20 +00:00
# include "asterisk.h"
2003-01-30 15:03:20 +00:00
# include "astconf.h"
1999-10-24 18:00:20 +00:00
2004-12-04 16:09:45 +00:00
# define MAX_NESTED_COMMENTS 128
# define COMMENT_START ";--"
# define COMMENT_END "--;"
# define COMMENT_META ';'
# define COMMENT_TAG '-'
2002-03-05 23:57:31 +00:00
2005-01-25 06:10:20 +00:00
static char * extconfig_conf = " extconfig.conf " ;
2004-10-05 06:46:11 +00:00
static struct ast_config_map {
struct ast_config_map * next ;
char * name ;
char * driver ;
char * database ;
char * table ;
char stuff [ 0 ] ;
2005-01-25 06:10:20 +00:00
} * config_maps = NULL ;
AST_MUTEX_DEFINE_STATIC ( config_lock ) ;
static struct ast_config_engine * config_engine_list ;
# define MAX_INCLUDE_LEVEL 10
struct ast_comment {
struct ast_comment * next ;
char cmt [ 0 ] ;
} ;
struct ast_category {
char name [ 80 ] ;
2005-01-30 06:26:19 +00:00
int ignored ; /* do not let user of the config see this category */
2005-01-25 06:10:20 +00:00
struct ast_variable * root ;
struct ast_variable * last ;
struct ast_category * next ;
} ;
struct ast_config {
struct ast_category * root ;
struct ast_category * last ;
struct ast_category * current ;
struct ast_category * last_browse ; /* used to cache the last category supplied via category_browse */
int include_level ;
int max_include_level ;
} ;
1999-10-24 18:00:20 +00:00
2004-10-08 05:36:23 +00:00
int ast_true ( const char * s )
1999-10-24 18:00:20 +00:00
{
2000-01-06 10:19:32 +00:00
if ( ! s )
return 0 ;
1999-10-24 18:00:20 +00:00
/* Determine if this is a true value */
if ( ! strcasecmp ( s , " yes " ) | |
! strcasecmp ( s , " true " ) | |
2005-01-25 06:10:20 +00:00
! strcasecmp ( s , " y " ) | |
! strcasecmp ( s , " t " ) | |
! strcasecmp ( s , " 1 " ) | |
! strcasecmp ( s , " on " ) )
return - 1 ;
2004-03-02 07:57:06 +00:00
return 0 ;
}
2004-10-08 05:36:23 +00:00
int ast_false ( const char * s )
2004-03-02 07:57:06 +00:00
{
if ( ! s )
return 0 ;
/* Determine if this is a false value */
if ( ! strcasecmp ( s , " no " ) | |
! strcasecmp ( s , " false " ) | |
2005-01-25 06:10:20 +00:00
! strcasecmp ( s , " n " ) | |
! strcasecmp ( s , " f " ) | |
! strcasecmp ( s , " 0 " ) | |
! strcasecmp ( s , " off " ) )
return - 1 ;
1999-10-24 18:00:20 +00:00
return 0 ;
}
2005-01-25 06:10:20 +00:00
struct ast_variable * ast_variable_new ( const char * name , const char * value )
1999-10-24 18:00:20 +00:00
{
2005-01-25 06:10:20 +00:00
struct ast_variable * variable ;
int length = strlen ( name ) + strlen ( value ) + 2 + sizeof ( struct ast_variable ) ;
variable = malloc ( length ) ;
if ( variable ) {
memset ( variable , 0 , length ) ;
variable - > name = variable - > stuff ;
variable - > value = variable - > stuff + strlen ( name ) + 1 ;
strcpy ( variable - > name , name ) ;
strcpy ( variable - > value , value ) ;
2001-10-09 14:54:42 +00:00
}
2005-01-25 06:10:20 +00:00
return variable ;
}
void ast_variable_append ( struct ast_category * category , struct ast_variable * variable )
{
2005-01-30 17:34:44 +00:00
if ( category - > last )
category - > last - > next = variable ;
else
category - > root = variable ;
category - > last = variable ;
2005-01-25 06:10:20 +00:00
}
void ast_variables_destroy ( struct ast_variable * v )
{
struct ast_variable * vn ;
while ( v ) {
vn = v ;
v = v - > next ;
free ( vn ) ;
1999-10-24 18:00:20 +00:00
}
}
2005-01-25 06:10:20 +00:00
struct ast_variable * ast_variable_browse ( const struct ast_config * config , const char * category )
{
struct ast_category * cat = NULL ;
if ( category & & config - > last_browse & & ( config - > last_browse - > name = = category ) )
cat = config - > last_browse ;
else
cat = ast_category_get ( config , category ) ;
if ( cat )
return cat - > root ;
else
return NULL ;
}
char * ast_variable_retrieve ( const struct ast_config * config , const char * category , const char * variable )
1999-10-24 18:00:20 +00:00
{
struct ast_variable * v ;
2005-01-25 06:10:20 +00:00
1999-12-11 20:09:45 +00:00
if ( category ) {
2005-01-25 06:10:20 +00:00
for ( v = ast_variable_browse ( config , category ) ; v ; v = v - > next )
if ( variable = = v - > name )
2001-10-09 14:54:42 +00:00
return v - > value ;
2005-01-25 06:10:20 +00:00
for ( v = ast_variable_browse ( config , category ) ; v ; v = v - > next )
if ( ! strcasecmp ( variable , v - > name ) )
1999-12-11 20:09:45 +00:00
return v - > value ;
} else {
struct ast_category * cat ;
2005-01-25 06:10:20 +00:00
for ( cat = config - > root ; cat ; cat = cat - > next )
for ( v = cat - > root ; v ; v = v - > next )
if ( ! strcasecmp ( variable , v - > name ) )
1999-12-11 20:09:45 +00:00
return v - > value ;
1999-10-24 18:00:20 +00:00
}
2005-01-25 06:10:20 +00:00
1999-10-24 18:00:20 +00:00
return NULL ;
}
2005-01-30 06:26:19 +00:00
static struct ast_variable * variable_clone ( const struct ast_variable * old )
{
struct ast_variable * new = ast_variable_new ( old - > name , old - > value ) ;
if ( new ) {
new - > lineno = old - > lineno ;
new - > object = old - > object ;
new - > blanklines = old - > blanklines ;
/* TODO: clone comments? */
}
return new ;
}
static void move_variables ( struct ast_category * old , struct ast_category * new )
{
struct ast_variable * var ;
struct ast_variable * next ;
next = old - > root ;
old - > root = NULL ;
for ( var = next ; var ; var = next ) {
next = var - > next ;
var - > next = NULL ;
ast_variable_append ( new , var ) ;
}
}
2005-01-25 06:10:20 +00:00
struct ast_category * ast_category_new ( const char * name )
{
struct ast_category * category ;
category = malloc ( sizeof ( struct ast_category ) ) ;
if ( category ) {
memset ( category , 0 , sizeof ( struct ast_category ) ) ;
strncpy ( category - > name , name , sizeof ( category - > name ) - 1 ) ;
}
return category ;
}
2005-01-30 06:26:19 +00:00
static struct ast_category * category_get ( const struct ast_config * config , const char * category_name , int ignored )
2003-03-09 06:00:18 +00:00
{
2005-01-25 06:10:20 +00:00
struct ast_category * cat ;
2004-10-05 06:46:11 +00:00
2005-01-25 06:10:20 +00:00
for ( cat = config - > root ; cat ; cat = cat - > next ) {
2005-01-30 06:26:19 +00:00
if ( cat - > name = = category_name & & ( ignored | | ! cat - > ignored ) )
2005-01-25 06:10:20 +00:00
return cat ;
}
for ( cat = config - > root ; cat ; cat = cat - > next ) {
2005-01-30 06:26:19 +00:00
if ( ! strcasecmp ( cat - > name , category_name ) & & ( ignored | | ! cat - > ignored ) )
2005-01-25 06:10:20 +00:00
return cat ;
2005-01-22 22:13:11 +00:00
}
2004-10-05 06:46:11 +00:00
2005-01-22 22:13:11 +00:00
return NULL ;
}
2005-01-30 06:26:19 +00:00
struct ast_category * ast_category_get ( const struct ast_config * config , const char * category_name )
{
return category_get ( config , category_name , 0 ) ;
}
2005-01-25 06:10:20 +00:00
int ast_category_exist ( const struct ast_config * config , const char * category_name )
2005-01-22 22:13:11 +00:00
{
return ! ! ast_category_get ( config , category_name ) ;
2003-03-09 06:00:18 +00:00
}
2005-01-25 06:10:20 +00:00
void ast_category_append ( struct ast_config * config , struct ast_category * category )
{
if ( config - > last )
config - > last - > next = category ;
else
config - > root = category ;
config - > last = category ;
config - > current = category ;
}
2004-10-05 06:46:11 +00:00
2005-01-25 06:10:20 +00:00
void ast_category_destroy ( struct ast_category * cat )
2003-03-09 06:00:18 +00:00
{
2005-01-25 06:10:20 +00:00
ast_variables_destroy ( cat - > root ) ;
free ( cat ) ;
}
2004-10-05 06:46:11 +00:00
2005-01-30 06:26:19 +00:00
static struct ast_category * next_available_category ( struct ast_category * cat )
{
for ( ; cat & & cat - > ignored ; cat = cat - > next ) ;
return cat ;
}
2005-01-25 06:10:20 +00:00
char * ast_category_browse ( struct ast_config * config , const char * prev )
{
struct ast_category * cat = NULL ;
if ( prev & & config - > last_browse & & ( config - > last_browse - > name = = prev ) )
cat = config - > last_browse - > next ;
else if ( ! prev & & config - > root )
cat = config - > root ;
else if ( prev ) {
for ( cat = config - > root ; cat ; cat = cat - > next ) {
if ( cat - > name = = prev ) {
cat = cat - > next ;
break ;
}
2003-03-09 06:00:18 +00:00
}
2005-01-25 06:10:20 +00:00
if ( ! cat ) {
for ( cat = config - > root ; cat ; cat = cat - > next ) {
if ( ! strcasecmp ( cat - > name , prev ) ) {
cat = cat - > next ;
break ;
}
}
2003-03-09 06:00:18 +00:00
}
}
2005-01-30 06:26:19 +00:00
if ( cat )
cat = next_available_category ( cat ) ;
2005-01-25 06:10:20 +00:00
config - > last_browse = cat ;
if ( cat )
return cat - > name ;
else
return NULL ;
2003-03-09 06:00:18 +00:00
}
2005-01-25 06:10:20 +00:00
struct ast_variable * ast_category_detach_variables ( struct ast_category * cat )
2003-03-09 06:00:18 +00:00
{
2005-01-25 06:10:20 +00:00
struct ast_variable * v ;
v = cat - > root ;
cat - > root = NULL ;
return v ;
}
void ast_category_rename ( struct ast_category * cat , const char * name )
{
strncpy ( cat - > name , name , sizeof ( cat - > name ) - 1 ) ;
}
2005-01-30 06:26:19 +00:00
static void inherit_category ( struct ast_category * new , const struct ast_category * base )
{
struct ast_variable * var ;
for ( var = base - > root ; var ; var = var - > next ) {
struct ast_variable * v ;
v = variable_clone ( var ) ;
if ( v )
ast_variable_append ( new , v ) ;
}
}
2005-01-25 06:10:20 +00:00
struct ast_config * ast_config_new ( void )
{
struct ast_config * config ;
config = malloc ( sizeof ( * config ) ) ;
if ( config ) {
memset ( config , 0 , sizeof ( * config ) ) ;
config - > max_include_level = MAX_INCLUDE_LEVEL ;
2003-03-09 06:00:18 +00:00
}
2005-01-25 06:10:20 +00:00
return config ;
2003-03-09 06:00:18 +00:00
}
2005-01-25 06:10:20 +00:00
void ast_config_destroy ( struct ast_config * cfg )
2001-04-23 16:50:12 +00:00
{
2005-01-25 06:10:20 +00:00
struct ast_category * cat , * catn ;
if ( ! cfg )
return ;
cat = cfg - > root ;
while ( cat ) {
ast_variables_destroy ( cat - > root ) ;
catn = cat ;
cat = cat - > next ;
free ( catn ) ;
}
free ( cfg ) ;
2001-04-23 16:50:12 +00:00
}
2005-01-25 06:10:20 +00:00
struct ast_category * ast_config_get_current_category ( const struct ast_config * cfg )
2005-01-22 22:13:11 +00:00
{
2005-01-25 06:10:20 +00:00
return cfg - > current ;
2005-01-22 22:13:11 +00:00
}
2003-04-28 19:58:43 +00:00
2005-01-25 06:10:20 +00:00
void ast_config_set_current_category ( struct ast_config * cfg , const struct ast_category * cat )
2005-01-22 22:13:11 +00:00
{
2005-01-25 06:10:20 +00:00
/* cast below is just to silence compiler warning about dropping "const" */
cfg - > current = ( struct ast_category * ) cat ;
2005-01-22 22:13:11 +00:00
}
2004-12-28 14:53:40 +00:00
2005-01-25 06:10:20 +00:00
static int process_text_line ( struct ast_config * cfg , struct ast_category * * cat , char * buf , int lineno , const char * configfile )
2002-03-05 23:57:31 +00:00
{
char * c ;
2005-01-30 06:26:19 +00:00
char * cur = buf ;
2002-03-05 23:57:31 +00:00
struct ast_variable * v ;
2005-02-02 03:38:24 +00:00
char cmd [ 512 ] , exec_file [ 512 ] ;
int object , do_exec , do_include ;
2005-01-22 22:13:11 +00:00
/* Actually parse the entry */
if ( cur [ 0 ] = = ' [ ' ) {
2005-01-30 06:26:19 +00:00
struct ast_category * newcat = NULL ;
char * catname ;
2005-01-22 22:13:11 +00:00
/* A category header */
c = strchr ( cur , ' ] ' ) ;
if ( ! c ) {
ast_log ( LOG_WARNING , " parse error: no closing ']', line %d of %s \n " , lineno , configfile ) ;
return - 1 ;
}
2005-01-30 06:26:19 +00:00
* c + + = ' \0 ' ;
2005-01-22 22:13:11 +00:00
cur + + ;
2005-01-30 06:26:19 +00:00
if ( * c + + ! = ' ( ' )
c = NULL ;
catname = cur ;
* cat = newcat = ast_category_new ( catname ) ;
if ( ! newcat ) {
2005-01-22 22:13:11 +00:00
ast_log ( LOG_WARNING , " Out of memory, line %d of %s \n " , lineno , configfile ) ;
return - 1 ;
}
2005-01-30 06:26:19 +00:00
/* If there are options or categories to inherit from, process them now */
if ( c ) {
if ( ! ( cur = strchr ( c , ' ) ' ) ) ) {
ast_log ( LOG_WARNING , " parse error: no closing ')', line %d of %s \n " , lineno , configfile ) ;
return - 1 ;
}
* cur = ' \0 ' ;
while ( ( cur = strsep ( & c , " , " ) ) ) {
if ( ! strcasecmp ( cur , " ! " ) ) {
( * cat ) - > ignored = 1 ;
} else if ( ! strcasecmp ( cur , " + " ) ) {
* cat = category_get ( cfg , catname , 1 ) ;
if ( ! * cat ) {
ast_destroy ( cfg ) ;
if ( newcat )
ast_category_destroy ( newcat ) ;
ast_log ( LOG_WARNING , " Category addition requested, but category '%s' does not exist, line %d of %s \n " , catname , lineno , configfile ) ;
return - 1 ;
}
if ( newcat ) {
move_variables ( newcat , * cat ) ;
ast_category_destroy ( newcat ) ;
newcat = NULL ;
}
} else {
struct ast_category * base ;
base = category_get ( cfg , cur , 1 ) ;
if ( ! base ) {
ast_log ( LOG_WARNING , " Inheritance requested, but category '%s' does not exist, line %d of %s \n " , cur , lineno , configfile ) ;
return - 1 ;
}
inherit_category ( * cat , base ) ;
}
}
}
if ( newcat )
ast_category_append ( cfg , * cat ) ;
2005-01-22 22:13:11 +00:00
} else if ( cur [ 0 ] = = ' # ' ) {
/* A directive */
cur + + ;
c = cur ;
while ( * c & & ( * c > 32 ) ) c + + ;
if ( * c ) {
* c = ' \0 ' ;
c + + ;
/* Find real argument */
while ( * c & & ( * c < 33 ) ) c + + ;
if ( ! * c )
2005-01-22 21:00:31 +00:00
c = NULL ;
2005-01-22 22:13:11 +00:00
} else
c = NULL ;
2005-02-02 03:38:24 +00:00
do_include = ! strcasecmp ( cur , " include " ) ;
if ( ! do_include )
do_exec = ! strcasecmp ( cur , " exec " ) ;
else
do_exec = 0 ;
if ( do_exec & & ! option_exec_includes ) {
2005-02-02 19:48:53 +00:00
ast_log ( LOG_WARNING , " Cannot perform #exec unless execincludes option is enabled in asterisk.conf (options section)! \n " ) ;
2005-02-02 03:38:24 +00:00
do_exec = 0 ;
}
if ( do_include | | do_exec ) {
2005-01-22 22:13:11 +00:00
if ( c ) {
/* Strip off leading and trailing "'s and <>'s */
while ( ( * c = = ' < ' ) | | ( * c = = ' > ' ) | | ( * c = = ' \" ' ) ) c + + ;
/* Get rid of leading mess */
cur = c ;
while ( ! ast_strlen_zero ( cur ) ) {
c = cur + strlen ( cur ) - 1 ;
if ( ( * c = = ' > ' ) | | ( * c = = ' < ' ) | | ( * c = = ' \" ' ) )
2005-01-22 21:00:31 +00:00
* c = ' \0 ' ;
2005-01-22 22:13:11 +00:00
else
break ;
}
2005-02-02 03:38:24 +00:00
/* #exec </path/to/executable>
We create a tmp file , then we # include it , then we delete it . */
if ( do_exec ) {
snprintf ( exec_file , sizeof ( exec_file ) , " /var/tmp/exec.%ld.%ld " , time ( NULL ) , pthread_self ( ) ) ;
snprintf ( cmd , sizeof ( cmd ) , " %s > %s 2>&1 " , cur , exec_file ) ;
ast_safe_system ( cmd ) ;
cur = exec_file ;
} else
exec_file [ 0 ] = ' \0 ' ;
/* A #include */
do_include = ast_config_internal_load ( cur , cfg ) ? 1 : 0 ;
if ( ! ast_strlen_zero ( exec_file ) )
unlink ( exec_file ) ;
if ( ! do_include )
2005-01-25 06:10:20 +00:00
return - 1 ;
2005-02-02 03:38:24 +00:00
} else {
ast_log ( LOG_WARNING , " Directive '#%s' needs an argument (%s) at line %d of %s \n " ,
do_exec ? " exec " : " include " ,
do_exec ? " /path/to/executable " : " filename " ,
lineno ,
configfile ) ;
}
2005-01-22 22:13:11 +00:00
}
else
ast_log ( LOG_WARNING , " Unknown directive '%s' at line %d of %s \n " , cur , lineno , configfile ) ;
} else {
/* Just a line (variable = value) */
if ( ! * cat ) {
ast_log ( LOG_WARNING ,
" parse error: No category context for line %d of %s \n " , lineno , configfile ) ;
return - 1 ;
}
c = strchr ( cur , ' = ' ) ;
if ( c ) {
* c = 0 ;
c + + ;
/* Ignore > in => */
if ( * c = = ' > ' ) {
object = 1 ;
2005-01-22 21:00:31 +00:00
c + + ;
2005-01-22 22:13:11 +00:00
} else
object = 0 ;
2005-01-25 06:10:20 +00:00
v = ast_variable_new ( ast_strip ( cur ) , ast_strip ( c ) ) ;
2005-01-22 22:13:11 +00:00
if ( v ) {
v - > lineno = lineno ;
v - > object = object ;
/* Put and reset comments */
v - > blanklines = 0 ;
2005-01-25 06:10:20 +00:00
ast_variable_append ( * cat , v ) ;
2005-01-22 21:00:31 +00:00
} else {
2005-01-22 22:13:11 +00:00
ast_log ( LOG_WARNING , " Out of memory, line %d \n " , lineno ) ;
return - 1 ;
2005-01-22 21:00:31 +00:00
}
2005-01-22 22:13:11 +00:00
} else {
ast_log ( LOG_WARNING , " No '=' (equal sign) in line %d of %s \n " , lineno , configfile ) ;
2003-03-09 06:00:18 +00:00
}
2005-01-22 22:13:11 +00:00
2002-03-05 23:57:31 +00:00
}
return 0 ;
}
2005-01-25 06:10:20 +00:00
static struct ast_config * config_text_file_load ( const char * database , const char * table , const char * filename , struct ast_config * cfg )
1999-10-24 18:00:20 +00:00
{
char fn [ 256 ] ;
2004-06-12 14:34:15 +00:00
char buf [ 8192 ] ;
2005-01-25 06:10:20 +00:00
char * new_buf , * comment_p , * process_buf ;
1999-10-24 18:00:20 +00:00
FILE * f ;
int lineno = 0 ;
2004-12-04 16:09:45 +00:00
int comment = 0 , nest [ MAX_NESTED_COMMENTS ] ;
2005-01-25 06:10:20 +00:00
struct ast_category * cat = NULL ;
2004-12-04 16:09:45 +00:00
2005-01-25 06:10:20 +00:00
cat = ast_config_get_current_category ( cfg ) ;
2004-06-17 04:53:55 +00:00
2005-01-25 06:10:20 +00:00
if ( filename [ 0 ] = = ' / ' ) {
strncpy ( fn , filename , sizeof ( fn ) - 1 ) ;
1999-10-24 18:00:20 +00:00
} else {
2005-01-25 06:10:20 +00:00
snprintf ( fn , sizeof ( fn ) , " %s/%s " , ( char * ) ast_config_AST_CONFIG_DIR , filename ) ;
1999-10-24 18:00:20 +00:00
}
2005-01-25 06:10:20 +00:00
2004-12-11 05:16:30 +00:00
# ifdef AST_INCLUDE_GLOB
{
int glob_ret ;
glob_t globbuf ;
globbuf . gl_offs = 0 ; /* initialize it to silence gcc */
2004-12-15 16:00:10 +00:00
# ifdef SOLARIS
2004-12-15 16:01:13 +00:00
glob_ret = glob ( fn , GLOB_NOCHECK , NULL , & globbuf ) ;
2004-12-15 16:00:10 +00:00
# else
glob_ret = glob ( fn , GLOB_NOMAGIC | GLOB_BRACE , NULL , & globbuf ) ;
# endif
2004-12-11 05:16:30 +00:00
if ( glob_ret = = GLOB_NOSPACE )
ast_log ( LOG_WARNING ,
" Glob Expansion of pattern '%s' failed: Not enough memory \n " , fn ) ;
else if ( glob_ret = = GLOB_ABORTED )
ast_log ( LOG_WARNING ,
" Glob Expansion of pattern '%s' failed: Read error \n " , fn ) ;
else {
/* loop over expanded files */
int i ;
for ( i = 0 ; i < globbuf . gl_pathc ; i + + ) {
strncpy ( fn , globbuf . gl_pathv [ i ] , sizeof ( fn ) - 1 ) ;
# endif
2005-01-28 00:31:50 +00:00
if ( ( option_verbose > 1 ) & & ! option_debug ) {
1999-10-24 18:00:20 +00:00
ast_verbose ( VERBOSE_PREFIX_2 " Parsing '%s': " , fn ) ;
fflush ( stdout ) ;
}
if ( ( f = fopen ( fn , " r " ) ) ) {
if ( option_debug )
ast_log ( LOG_DEBUG , " Parsing %s \n " , fn ) ;
2005-01-28 00:31:50 +00:00
else if ( option_verbose > 1 )
2005-01-22 22:13:11 +00:00
ast_verbose ( " Found \n " ) ;
while ( ! feof ( f ) ) {
lineno + + ;
if ( fgets ( buf , sizeof ( buf ) , f ) ) {
new_buf = buf ;
if ( comment )
process_buf = NULL ;
else
process_buf = buf ;
while ( ( comment_p = strchr ( new_buf , COMMENT_META ) ) ) {
if ( ( comment_p > new_buf ) & & ( * ( comment_p - 1 ) = = ' \\ ' ) ) {
/* Yuck, gotta memmove */
memmove ( comment_p - 1 , comment_p , strlen ( comment_p ) + 1 ) ;
new_buf = comment_p ;
} else if ( comment_p [ 1 ] = = COMMENT_TAG & & comment_p [ 2 ] = = COMMENT_TAG & & ( comment_p [ 3 ] ! = ' - ' ) ) {
/* Meta-Comment start detected ";--" */
if ( comment < MAX_NESTED_COMMENTS ) {
* comment_p = ' \0 ' ;
new_buf = comment_p + 3 ;
comment + + ;
nest [ comment - 1 ] = lineno ;
2004-12-04 16:09:45 +00:00
} else {
2005-01-22 22:13:11 +00:00
ast_log ( LOG_ERROR , " Maximum nest limit of %d reached. \n " , MAX_NESTED_COMMENTS ) ;
}
} else if ( ( comment_p > = new_buf + 2 ) & &
( * ( comment_p - 1 ) = = COMMENT_TAG ) & &
( * ( comment_p - 2 ) = = COMMENT_TAG ) ) {
/* Meta-Comment end detected */
comment - - ;
new_buf = comment_p + 1 ;
if ( ! comment ) {
/* Back to non-comment now */
if ( process_buf ) {
/* Actually have to move what's left over the top, then continue */
char * oldptr ;
oldptr = process_buf + strlen ( process_buf ) ;
memmove ( oldptr , new_buf , strlen ( new_buf ) + 1 ) ;
new_buf = oldptr ;
2004-12-04 16:09:45 +00:00
} else
2005-01-22 22:13:11 +00:00
process_buf = new_buf ;
2004-12-04 16:09:45 +00:00
}
2005-01-22 22:13:11 +00:00
} else {
if ( ! comment ) {
/* If ; is found, and we are not nested in a comment,
we immediately stop all comment processing */
* comment_p = ' \0 ' ;
new_buf = comment_p ;
} else
new_buf = comment_p + 1 ;
2004-12-04 16:09:45 +00:00
}
2005-01-22 22:13:11 +00:00
}
2005-01-30 06:26:19 +00:00
if ( process_buf ) {
char * buf = ast_strip ( process_buf ) ;
if ( ! ast_strlen_zero ( buf ) )
if ( process_text_line ( cfg , & cat , buf , lineno , filename ) ) {
cfg = NULL ;
break ;
}
1999-10-24 18:00:20 +00:00
}
}
2005-01-22 22:13:11 +00:00
}
1999-10-24 18:00:20 +00:00
fclose ( f ) ;
2004-12-04 16:09:45 +00:00
} else { /* can't open file */
1999-10-24 18:00:20 +00:00
if ( option_debug )
ast_log ( LOG_DEBUG , " No file to parse: %s \n " , fn ) ;
2005-02-11 16:09:01 +00:00
else if ( option_verbose > 1 )
2003-07-01 04:08:25 +00:00
ast_verbose ( " Not found (%s) \n " , strerror ( errno ) ) ;
1999-10-24 18:00:20 +00:00
}
2004-12-04 16:09:45 +00:00
if ( comment ) {
ast_log ( LOG_WARNING , " Unterminated comment detected beginning on line %d \n " , nest [ comment ] ) ;
}
2004-12-11 05:16:30 +00:00
# ifdef AST_INCLUDE_GLOB
2005-01-25 06:10:20 +00:00
if ( ! cfg )
2004-12-11 05:16:30 +00:00
break ;
}
globfree ( & globbuf ) ;
}
}
# endif
2005-01-25 06:10:20 +00:00
return cfg ;
1999-10-24 18:00:20 +00:00
}
2005-01-25 06:10:20 +00:00
int config_text_file_save ( const char * configfile , const struct ast_config * cfg , const char * generator )
2004-06-17 04:53:55 +00:00
{
2005-01-25 06:10:20 +00:00
FILE * f ;
char fn [ 256 ] ;
char date [ 256 ] = " " ;
time_t t ;
struct ast_variable * var ;
struct ast_category * cat ;
int blanklines = 0 ;
if ( configfile [ 0 ] = = ' / ' ) {
strncpy ( fn , configfile , sizeof ( fn ) - 1 ) ;
2004-06-17 04:53:55 +00:00
} else {
2005-01-25 06:10:20 +00:00
snprintf ( fn , sizeof ( fn ) , " %s/%s " , AST_CONFIG_DIR , configfile ) ;
2004-06-11 00:12:35 +00:00
}
2005-01-25 06:10:20 +00:00
time ( & t ) ;
strncpy ( date , ctime ( & t ) , sizeof ( date ) - 1 ) ;
if ( ( f = fopen ( fn , " w " ) ) ) {
if ( ( option_verbose > 1 ) & & ! option_debug )
ast_verbose ( VERBOSE_PREFIX_2 " Saving '%s': " , fn ) ;
fprintf ( f , " ;! \n " ) ;
fprintf ( f , " ;! Automatically generated configuration file \n " ) ;
fprintf ( f , " ;! Filename: %s (%s) \n " , configfile , fn ) ;
fprintf ( f , " ;! Generator: %s \n " , generator ) ;
fprintf ( f , " ;! Creation Date: %s " , date ) ;
fprintf ( f , " ;! \n " ) ;
cat = cfg - > root ;
while ( cat ) {
/* Dump section with any appropriate comment */
fprintf ( f , " [%s] \n " , cat - > name ) ;
var = cat - > root ;
while ( var ) {
if ( var - > sameline )
fprintf ( f , " %s %s %s ; %s \n " , var - > name , ( var - > object ? " => " : " = " ) , var - > value , var - > sameline - > cmt ) ;
else
fprintf ( f , " %s %s %s \n " , var - > name , ( var - > object ? " => " : " = " ) , var - > value ) ;
if ( var - > blanklines ) {
blanklines = var - > blanklines ;
while ( blanklines - - )
fprintf ( f , " \n " ) ;
}
var = var - > next ;
}
#if 0
/* Put an empty line */
fprintf ( f , " \n " ) ;
# endif
cat = cat - > next ;
}
} else {
if ( option_debug )
printf ( " Unable to open for writing: %s \n " , fn ) ;
else if ( option_verbose > 1 )
printf ( " Unable to write (%s) " , strerror ( errno ) ) ;
return - 1 ;
}
fclose ( f ) ;
return 0 ;
}
static void clear_config_maps ( void )
{
struct ast_config_map * map ;
ast_mutex_lock ( & config_lock ) ;
while ( config_maps ) {
map = config_maps ;
config_maps = config_maps - > next ;
free ( map ) ;
}
ast_mutex_unlock ( & config_lock ) ;
}
2005-02-10 21:14:11 +00:00
static int append_mapping ( char * name , char * driver , char * database , char * table )
{
struct ast_config_map * map ;
int length ;
length = sizeof ( * map ) ;
length + = strlen ( name ) + 1 ;
length + = strlen ( driver ) + 1 ;
length + = strlen ( database ) + 1 ;
if ( table )
length + = strlen ( table ) + 1 ;
map = malloc ( length ) ;
if ( ! map )
return - 1 ;
memset ( map , 0 , length ) ;
map - > name = map - > stuff ;
strcpy ( map - > name , name ) ;
map - > driver = map - > name + strlen ( map - > name ) + 1 ;
strcpy ( map - > driver , driver ) ;
map - > database = map - > driver + strlen ( map - > driver ) + 1 ;
strcpy ( map - > database , database ) ;
if ( table ) {
map - > table = map - > database + strlen ( map - > database ) + 1 ;
strcpy ( map - > table , table ) ;
}
map - > next = config_maps ;
if ( option_verbose > 1 )
ast_verbose ( VERBOSE_PREFIX_2 " Binding %s to %s/%s/%s \n " ,
map - > name , map - > driver , map - > database , map - > table ? map - > table : map - > name ) ;
config_maps = map ;
return 0 ;
}
2005-01-25 06:10:20 +00:00
void read_config_maps ( void )
{
struct ast_config * config ;
struct ast_variable * v ;
char * driver , * table , * database , * stringp ;
clear_config_maps ( ) ;
config = ast_config_new ( ) ;
config - > max_include_level = 1 ;
config = ast_config_internal_load ( extconfig_conf , config ) ;
if ( ! config )
return ;
for ( v = ast_variable_browse ( config , " settings " ) ; v ; v = v - > next ) {
stringp = v - > value ;
driver = strsep ( & stringp , " , " ) ;
database = strsep ( & stringp , " , " ) ;
table = strsep ( & stringp , " , " ) ;
if ( ! strcmp ( v - > name , extconfig_conf ) | | ! strcmp ( v - > name , " asterisk.conf " ) ) {
ast_log ( LOG_WARNING , " Cannot bind asterisk.conf or extconfig.conf! \n " ) ;
continue ;
}
if ( ! driver | | ! database )
continue ;
2005-02-10 21:14:11 +00:00
if ( ! strcasecmp ( v - > name , " sipfriends " ) ) {
ast_log ( LOG_WARNING , " The 'sipfriends' table is obsolete, update your config to use sipusers and sippeers, though they can point to the same table. \n " ) ;
append_mapping ( " sipusers " , driver , database , table ? table : " sipfriends " ) ;
append_mapping ( " sippeers " , driver , database , table ? table : " sipfriends " ) ;
} else if ( ! strcasecmp ( v - > name , " iaxfriends " ) ) {
ast_log ( LOG_WARNING , " The 'iaxfriends' table is obsolete, update your config to use iaxusers and iaxpeers, though they can point to the same table. \n " ) ;
append_mapping ( " iaxusers " , driver , database , table ? table : " iaxfriends " ) ;
append_mapping ( " iaxpeers " , driver , database , table ? table : " iaxfriends " ) ;
} else
append_mapping ( v - > name , driver , database , table ) ;
2005-01-25 06:10:20 +00:00
}
ast_config_destroy ( config ) ;
}
int ast_config_engine_register ( struct ast_config_engine * new )
{
struct ast_config_engine * ptr ;
ast_mutex_lock ( & config_lock ) ;
if ( ! config_engine_list ) {
config_engine_list = new ;
} else {
for ( ptr = config_engine_list ; ptr - > next ; ptr = ptr - > next ) ;
ptr - > next = new ;
}
ast_mutex_unlock ( & config_lock ) ;
ast_log ( LOG_NOTICE , " Registered Config Engine %s \n " , new - > name ) ;
2004-06-11 00:12:35 +00:00
return 1 ;
}
2005-01-25 06:10:20 +00:00
int ast_config_engine_deregister ( struct ast_config_engine * del )
2004-06-17 04:53:55 +00:00
{
2005-01-25 06:10:20 +00:00
struct ast_config_engine * ptr , * last = NULL ;
ast_mutex_lock ( & config_lock ) ;
for ( ptr = config_engine_list ; ptr ; ptr = ptr - > next ) {
2004-06-17 04:53:55 +00:00
if ( ptr = = del ) {
2005-01-25 06:10:20 +00:00
if ( last )
2004-06-17 04:53:55 +00:00
last - > next = ptr - > next ;
2005-01-25 06:10:20 +00:00
else
config_engine_list = ptr - > next ;
break ;
2004-06-17 04:53:55 +00:00
}
last = ptr ;
}
2004-06-11 00:12:35 +00:00
2005-01-25 06:10:20 +00:00
ast_mutex_unlock ( & config_lock ) ;
return 0 ;
2004-06-11 00:12:35 +00:00
}
2005-01-25 06:10:20 +00:00
static struct ast_config_engine * find_engine ( const char * filename , char * database , int dbsiz , char * table , int tabsiz )
2002-03-05 23:57:31 +00:00
{
2005-01-25 06:10:20 +00:00
struct ast_config_engine * eng , * ret = NULL ;
struct ast_config_map * map ;
2002-03-05 23:57:31 +00:00
2005-01-25 06:10:20 +00:00
ast_mutex_lock ( & config_lock ) ;
2004-11-23 17:58:59 +00:00
2005-01-25 06:10:20 +00:00
map = config_maps ;
while ( map ) {
if ( ! strcasecmp ( filename , map - > name ) ) {
strncpy ( database , map - > database , dbsiz - 1 ) ;
if ( map - > table )
strncpy ( table , map - > table , tabsiz - 1 ) ;
2001-10-09 14:54:42 +00:00
else
2005-01-25 06:10:20 +00:00
strncpy ( table , filename , tabsiz - 1 ) ;
break ;
2001-10-09 14:54:42 +00:00
}
2005-01-25 06:10:20 +00:00
map = map - > next ;
2001-10-09 14:54:42 +00:00
}
2005-01-25 06:10:20 +00:00
if ( map ) {
for ( eng = config_engine_list ; eng ; eng = eng - > next ) {
if ( ! strcmp ( eng - > name , map - > driver ) ) {
ret = eng ;
break ;
}
1999-10-24 18:00:20 +00:00
}
}
2005-01-25 06:10:20 +00:00
ast_mutex_unlock ( & config_lock ) ;
return ret ;
1999-10-24 18:00:20 +00:00
}
2004-06-11 00:12:35 +00:00
2005-01-25 06:10:20 +00:00
static struct ast_config_engine text_file_engine = {
. name = " text " ,
. load_func = config_text_file_load ,
} ;
2004-06-11 00:12:35 +00:00
2005-01-25 06:10:20 +00:00
struct ast_config * ast_config_internal_load ( const char * filename , struct ast_config * cfg )
2004-06-17 04:53:55 +00:00
{
2005-01-25 06:10:20 +00:00
char db [ 256 ] ;
char table [ 256 ] ;
struct ast_config_engine * loader = & text_file_engine ;
struct ast_config * result ;
2004-06-11 00:12:35 +00:00
2005-01-25 06:10:20 +00:00
if ( cfg - > include_level = = cfg - > max_include_level ) {
ast_log ( LOG_WARNING , " Maximum Include level (%d) exceeded \n " , cfg - > max_include_level ) ;
return NULL ;
2004-06-11 00:12:35 +00:00
}
2005-01-25 06:10:20 +00:00
cfg - > include_level + + ;
if ( strcmp ( filename , extconfig_conf ) & & strcmp ( filename , " asterisk.conf " ) & & config_engine_list ) {
struct ast_config_engine * eng ;
eng = find_engine ( filename , db , sizeof ( db ) , table , sizeof ( table ) ) ;
2005-02-02 03:38:24 +00:00
2005-01-25 06:10:20 +00:00
if ( eng & & eng - > load_func ) {
loader = eng ;
} else {
eng = find_engine ( " global " , db , sizeof ( db ) , table , sizeof ( table ) ) ;
if ( eng & & eng - > load_func )
loader = eng ;
}
}
result = loader - > load_func ( db , table , filename , cfg ) ;
2005-02-02 03:38:24 +00:00
2005-01-25 06:10:20 +00:00
if ( result )
result - > include_level - - ;
return result ;
2004-06-11 00:12:35 +00:00
}
2005-01-25 06:10:20 +00:00
struct ast_config * ast_config_load ( const char * filename )
2004-06-17 04:53:55 +00:00
{
2005-01-25 06:10:20 +00:00
struct ast_config * cfg ;
struct ast_config * result ;
cfg = ast_config_new ( ) ;
if ( ! cfg )
return NULL ;
result = ast_config_internal_load ( filename , cfg ) ;
if ( ! result )
ast_config_destroy ( cfg ) ;
return result ;
2004-06-11 00:12:35 +00:00
}
2005-01-25 06:10:20 +00:00
struct ast_variable * ast_load_realtime ( const char * family , . . . )
2004-06-17 04:53:55 +00:00
{
2005-01-25 06:10:20 +00:00
struct ast_config_engine * eng ;
char db [ 256 ] = " " ;
char table [ 256 ] = " " ;
struct ast_variable * res = NULL ;
va_list ap ;
va_start ( ap , family ) ;
eng = find_engine ( family , db , sizeof ( db ) , table , sizeof ( table ) ) ;
if ( eng & & eng - > realtime_func )
res = eng - > realtime_func ( db , table , ap ) ;
va_end ( ap ) ;
return res ;
2004-06-11 00:12:35 +00:00
}
2005-01-25 06:10:20 +00:00
struct ast_config * ast_load_realtime_multientry ( const char * family , . . . )
2004-06-17 04:53:55 +00:00
{
2005-01-25 06:10:20 +00:00
struct ast_config_engine * eng ;
char db [ 256 ] = " " ;
char table [ 256 ] = " " ;
struct ast_config * res = NULL ;
va_list ap ;
va_start ( ap , family ) ;
eng = find_engine ( family , db , sizeof ( db ) , table , sizeof ( table ) ) ;
if ( eng & & eng - > realtime_multi_func )
res = eng - > realtime_multi_func ( db , table , ap ) ;
va_end ( ap ) ;
return res ;
2004-06-11 00:12:35 +00:00
}
2005-01-25 06:10:20 +00:00
int ast_update_realtime ( const char * family , const char * keyfield , const char * lookup , . . . )
2004-06-17 04:53:55 +00:00
{
2005-01-25 06:10:20 +00:00
struct ast_config_engine * eng ;
int res = - 1 ;
char db [ 256 ] = " " ;
char table [ 256 ] = " " ;
va_list ap ;
va_start ( ap , lookup ) ;
eng = find_engine ( family , db , sizeof ( db ) , table , sizeof ( table ) ) ;
if ( eng & & eng - > update_func )
res = eng - > update_func ( db , table , keyfield , lookup , ap ) ;
va_end ( ap ) ;
return res ;
2004-06-11 00:12:35 +00:00
}
2004-06-17 04:53:55 +00:00
static int config_command ( int fd , int argc , char * * argv )
{
2005-01-25 06:10:20 +00:00
struct ast_config_engine * eng ;
2004-10-05 06:46:11 +00:00
struct ast_config_map * map ;
2004-06-11 00:12:35 +00:00
2005-01-25 06:10:20 +00:00
ast_mutex_lock ( & config_lock ) ;
ast_cli ( fd , " \n \n " ) ;
for ( eng = config_engine_list ; eng ; eng = eng - > next ) {
ast_cli ( fd , " \n Config Engine: %s \n " , eng - > name ) ;
for ( map = config_maps ; map ; map = map - > next )
if ( ! strcasecmp ( map - > driver , eng - > name ) ) {
ast_cli ( fd , " ===> %s (db=%s, table=%s) \n " , map - > name , map - > database ,
map - > table ? map - > table : map - > name ) ;
break ;
}
2004-06-11 00:12:35 +00:00
}
ast_cli ( fd , " \n \n " ) ;
2005-01-25 06:10:20 +00:00
ast_mutex_unlock ( & config_lock ) ;
2004-06-17 04:53:55 +00:00
return 0 ;
2004-06-11 00:12:35 +00:00
}
2005-03-17 00:35:06 +00:00
static char show_config_help [ ] =
" Usage: show config mappings \n "
" Shows the filenames to config engines. \n " ;
2004-06-11 00:12:35 +00:00
static struct ast_cli_entry config_command_struct = {
2005-03-17 00:35:06 +00:00
{ " show " , " config " , " mappings " , NULL } , config_command , " Show Config mappings (file names to config engines) " , show_config_help , NULL
2005-01-25 06:10:20 +00:00
} ;
2004-06-11 00:12:35 +00:00
2004-06-17 04:53:55 +00:00
int register_config_cli ( )
{
2004-06-11 00:12:35 +00:00
return ast_cli_register ( & config_command_struct ) ;
}