1999-10-24 18:00:20 +00:00
/*
2005-09-14 20:46:50 +00:00
* Asterisk - - An open source telephony toolkit .
1999-10-24 18:00:20 +00:00
*
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
*
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-24 18:00:20 +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
*
* \ brief Configuration File Parser
2005-09-14 20:46:50 +00:00
*
2005-12-30 21:18:06 +00:00
* \ author Mark Spencer < markster @ digium . com >
*
2005-10-24 20:12:06 +00:00
* Includes the Asterisk Realtime API - ARA
2006-03-12 17:27:57 +00:00
* See doc / realtime . txt and doc / extconfig . txt
1999-10-24 18:00:20 +00:00
*/
2006-06-07 18:54:56 +00:00
# include "asterisk.h"
ASTERISK_FILE_VERSION ( __FILE__ , " $Revision$ " )
1999-10-24 18:00:20 +00:00
# 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>
2005-10-31 21:08:55 +00:00
# include <sys/stat.h>
2004-12-11 05:16:30 +00:00
# define AST_INCLUDE_GLOB 1
# ifdef AST_INCLUDE_GLOB
2005-11-01 21:53:30 +00:00
# if defined(__Darwin__) || defined(__CYGWIN__)
2004-12-19 17:33:19 +00:00
# define GLOB_ABORTED GLOB_ABEND
# endif
2004-12-11 05:16:30 +00:00
# include <glob.h>
# endif
2005-04-22 13:11:34 +00:00
2005-04-21 06:02:45 +00:00
# include "asterisk/config.h"
# include "asterisk/cli.h"
# include "asterisk/lock.h"
# include "asterisk/options.h"
# include "asterisk/logger.h"
# include "asterisk/utils.h"
# include "asterisk/channel.h"
# include "asterisk/app.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
2006-10-26 01:38:47 +00:00
2007-03-26 20:27:02 +00:00
/*! \brief Structure to keep comments for rewriting configuration files */
2007-02-24 20:29:41 +00:00
/*! \brief Structure to keep comments for rewriting configuration files */
2006-10-26 01:38:47 +00:00
struct ast_comment {
struct ast_comment * next ;
char cmt [ 0 ] ;
} ;
# define CB_INCR 250
2007-03-26 20:27:02 +00:00
static void CB_INIT ( char * * comment_buffer , int * comment_buffer_size , char * * lline_buffer , int * lline_buffer_size )
2006-10-26 01:38:47 +00:00
{
2007-03-26 20:27:02 +00:00
if ( ! ( * comment_buffer ) ) {
* comment_buffer = ast_malloc ( CB_INCR ) ;
if ( ! ( * comment_buffer ) )
2006-11-01 17:46:40 +00:00
return ;
2007-03-26 20:27:02 +00:00
( * comment_buffer ) [ 0 ] = 0 ;
* comment_buffer_size = CB_INCR ;
* lline_buffer = ast_malloc ( CB_INCR ) ;
if ( ! ( * lline_buffer ) )
2007-01-04 22:34:24 +00:00
return ;
2007-03-26 20:27:02 +00:00
( * lline_buffer ) [ 0 ] = 0 ;
* lline_buffer_size = CB_INCR ;
2006-11-01 17:46:40 +00:00
} else {
2007-03-26 20:27:02 +00:00
( * comment_buffer ) [ 0 ] = 0 ;
( * lline_buffer ) [ 0 ] = 0 ;
2006-10-26 01:38:47 +00:00
}
}
2007-03-26 20:27:02 +00:00
static void CB_ADD ( char * * comment_buffer , int * comment_buffer_size , char * str )
2006-10-26 01:38:47 +00:00
{
2007-03-26 20:27:02 +00:00
int rem = * comment_buffer_size - strlen ( * comment_buffer ) - 1 ;
2006-11-01 17:46:40 +00:00
int siz = strlen ( str ) ;
if ( rem < siz + 1 ) {
2007-03-26 20:27:02 +00:00
* comment_buffer = ast_realloc ( * comment_buffer , * comment_buffer_size + CB_INCR + siz + 1 ) ;
if ( ! ( * comment_buffer ) )
2006-11-01 17:46:40 +00:00
return ;
2007-03-26 20:27:02 +00:00
* comment_buffer_size + = CB_INCR + siz + 1 ;
2006-10-26 01:38:47 +00:00
}
2007-03-26 20:27:02 +00:00
strcat ( * comment_buffer , str ) ;
2006-10-26 01:38:47 +00:00
}
2007-03-26 20:27:02 +00:00
static void CB_ADD_LEN ( char * * comment_buffer , int * comment_buffer_size , char * str , int len )
2006-10-26 01:38:47 +00:00
{
2007-03-26 20:27:02 +00:00
int cbl = strlen ( * comment_buffer ) + 1 ;
int rem = * comment_buffer_size - cbl ;
2006-11-01 17:46:40 +00:00
if ( rem < len + 1 ) {
2007-03-26 20:27:02 +00:00
* comment_buffer = ast_realloc ( * comment_buffer , * comment_buffer_size + CB_INCR + len + 1 ) ;
if ( ! ( * comment_buffer ) )
2006-11-01 17:46:40 +00:00
return ;
2007-03-26 20:27:02 +00:00
* comment_buffer_size + = CB_INCR + len + 1 ;
2006-10-26 01:38:47 +00:00
}
2007-03-26 20:27:02 +00:00
strncat ( * comment_buffer , str , len ) ;
( * comment_buffer ) [ cbl + len - 1 ] = 0 ;
2006-10-26 01:38:47 +00:00
}
2007-03-26 20:27:02 +00:00
static void LLB_ADD ( char * * lline_buffer , int * lline_buffer_size , char * str )
2006-10-26 01:38:47 +00:00
{
2007-03-26 20:27:02 +00:00
int rem = * lline_buffer_size - strlen ( * lline_buffer ) - 1 ;
2006-11-01 17:46:40 +00:00
int siz = strlen ( str ) ;
if ( rem < siz + 1 ) {
2007-03-26 20:27:02 +00:00
* lline_buffer = ast_realloc ( * lline_buffer , * lline_buffer_size + CB_INCR + siz + 1 ) ;
if ( ! ( * lline_buffer ) )
2006-11-01 17:46:40 +00:00
return ;
2007-03-26 20:27:02 +00:00
* lline_buffer_size + = CB_INCR + siz + 1 ;
2006-10-26 01:38:47 +00:00
}
2007-03-26 20:27:02 +00:00
strcat ( * lline_buffer , str ) ;
2006-10-26 01:38:47 +00:00
}
2007-03-26 20:27:02 +00:00
static void CB_RESET ( char * * comment_buffer , char * * lline_buffer )
2006-10-26 01:38:47 +00:00
{
2007-03-26 20:27:02 +00:00
( * comment_buffer ) [ 0 ] = 0 ;
( * lline_buffer ) [ 0 ] = 0 ;
2006-10-26 01:38:47 +00:00
}
static struct ast_comment * ALLOC_COMMENT ( const char * buffer )
{
2007-06-06 21:20:11 +00:00
struct ast_comment * x ;
x = ast_calloc ( 1 , sizeof ( * x ) + strlen ( buffer ) + 1 ) ;
2006-10-26 01:38:47 +00:00
strcpy ( x - > cmt , buffer ) ;
return x ;
}
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_category {
2006-02-24 10:50:43 +00:00
char name [ 80 ] ;
2006-11-01 17:46:40 +00:00
int ignored ; /*!< do not let user of the config see this category */
2007-01-04 22:34:24 +00:00
int include_level ;
2006-10-26 01:38:47 +00:00
struct ast_comment * precomments ;
struct ast_comment * sameline ;
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 ;
2006-11-01 17:46:40 +00:00
struct ast_category * last_browse ; /*!< used to cache the last category supplied via category_browse */
2005-01-25 06:10:20 +00:00
int include_level ;
int max_include_level ;
} ;
1999-10-24 18:00:20 +00:00
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 ;
2006-02-09 16:59:50 +00:00
int name_len = strlen ( name ) + 1 ;
2005-01-25 06:10:20 +00:00
2006-02-09 16:59:50 +00:00
if ( ( variable = ast_calloc ( 1 , name_len + strlen ( value ) + 1 + sizeof ( * variable ) ) ) ) {
2005-01-25 06:10:20 +00:00
variable - > name = variable - > stuff ;
2006-02-09 16:59:50 +00:00
variable - > value = variable - > stuff + name_len ;
2005-01-25 06:10:20 +00:00
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 )
{
2006-04-06 16:06:57 +00:00
if ( ! variable )
return ;
2005-01-30 17:34:44 +00:00
if ( category - > last )
category - > last - > next = variable ;
else
category - > root = variable ;
category - > last = variable ;
2006-11-15 20:05:26 +00:00
while ( category - > last - > next )
category - > last = category - > last - > next ;
2005-01-25 06:10:20 +00:00
}
void ast_variables_destroy ( struct ast_variable * v )
{
struct ast_variable * vn ;
2007-01-23 00:11:32 +00:00
while ( v ) {
2005-01-25 06:10:20 +00:00
vn = v ;
v = v - > next ;
2007-06-06 21:20:11 +00:00
ast_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 ) ;
2006-04-06 16:06:57 +00:00
return ( cat ) ? cat - > root : NULL ;
2005-01-25 06:10:20 +00:00
}
2006-09-20 20:40:39 +00:00
const char * ast_config_option ( struct ast_config * cfg , const char * cat , const char * var )
2006-09-16 23:53:58 +00:00
{
2006-09-20 20:40:39 +00:00
const char * tmp ;
2006-09-16 23:53:58 +00:00
tmp = ast_variable_retrieve ( cfg , cat , var ) ;
if ( ! tmp )
tmp = ast_variable_retrieve ( cfg , " general " , var ) ;
return tmp ;
}
2006-09-20 20:40:39 +00:00
const 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-10-17 03:53:27 +00:00
for ( v = ast_variable_browse ( config , category ) ; v ; v = v - > next ) {
2005-01-25 06:10:20 +00:00
if ( ! strcasecmp ( variable , v - > name ) )
2005-10-17 13:53:50 +00:00
return v - > value ;
2005-10-17 03:53:27 +00:00
}
1999-12-11 20:09:45 +00:00
} 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 )
{
2006-04-06 16:06:57 +00:00
struct ast_variable * var = old - > root ;
2005-01-30 06:26:19 +00:00
old - > root = NULL ;
2006-04-06 16:06:57 +00:00
# if 1
/* we can just move the entire list in a single op */
ast_variable_append ( new , var ) ;
# else
while ( var ) {
struct ast_variable * next = var - > next ;
2005-01-30 06:26:19 +00:00
var - > next = NULL ;
ast_variable_append ( new , var ) ;
2006-04-06 16:06:57 +00:00
var = next ;
2005-01-30 06:26:19 +00:00
}
2006-04-06 16:06:57 +00:00
# endif
2005-01-30 06:26:19 +00:00
}
2005-01-25 06:10:20 +00:00
struct ast_category * ast_category_new ( const char * name )
{
struct ast_category * category ;
2006-04-06 16:06:57 +00:00
if ( ( category = ast_calloc ( 1 , sizeof ( * category ) ) ) )
2005-07-10 22:56:21 +00:00
ast_copy_string ( category - > name , name , sizeof ( category - > name ) ) ;
2005-01-25 06:10:20 +00:00
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
2006-04-06 16:06:57 +00:00
/* try exact match first, then case-insensitive match */
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 ;
2007-01-04 22:34:24 +00:00
category - > include_level = config - > include_level ;
2005-01-25 06:10:20 +00:00
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 ) ;
2007-06-06 21:20:11 +00:00
ast_free ( cat ) ;
2005-01-25 06:10:20 +00:00
}
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 )
2006-04-06 16:06:57 +00:00
cat = config - > root ;
2005-01-25 06:10:20 +00:00
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 ;
2006-04-06 16:06:57 +00:00
return ( cat ) ? cat - > name : 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 ;
2006-11-15 20:05:26 +00:00
cat - > last = NULL ;
2005-01-25 06:10:20 +00:00
return v ;
}
void ast_category_rename ( struct ast_category * cat , const char * name )
{
2005-07-10 22:56:21 +00:00
ast_copy_string ( cat - > name , name , sizeof ( cat - > name ) ) ;
2005-01-25 06:10:20 +00:00
}
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 ;
2006-04-06 16:06:57 +00:00
for ( var = base - > root ; var ; var = var - > next )
ast_variable_append ( new , variable_clone ( var ) ) ;
2005-01-30 06:26:19 +00:00
}
2005-01-25 06:10:20 +00:00
struct ast_config * ast_config_new ( void )
{
struct ast_config * config ;
2006-04-06 16:06:57 +00:00
if ( ( config = ast_calloc ( 1 , sizeof ( * config ) ) ) )
2005-01-25 06:10:20 +00:00
config - > max_include_level = MAX_INCLUDE_LEVEL ;
return config ;
2003-03-09 06:00:18 +00:00
}
2007-01-05 23:58:53 +00:00
int ast_variable_delete ( struct ast_category * category , const char * variable , const char * match )
2006-07-19 13:28:38 +00:00
{
2006-07-29 22:02:37 +00:00
struct ast_variable * cur , * prev = NULL , * curn ;
int res = - 1 ;
2006-07-19 13:28:38 +00:00
cur = category - > root ;
while ( cur ) {
if ( cur - > name = = variable ) {
if ( prev ) {
prev - > next = cur - > next ;
if ( cur = = category - > last )
category - > last = prev ;
} else {
category - > root = cur - > next ;
if ( cur = = category - > last )
category - > last = NULL ;
}
cur - > next = NULL ;
ast_variables_destroy ( cur ) ;
return 0 ;
}
prev = cur ;
cur = cur - > next ;
}
2006-07-19 17:26:47 +00:00
prev = NULL ;
2006-07-19 13:28:38 +00:00
cur = category - > root ;
while ( cur ) {
2006-07-29 22:02:37 +00:00
curn = cur - > next ;
if ( ! strcasecmp ( cur - > name , variable ) & & ( ast_strlen_zero ( match ) | | ! strcasecmp ( cur - > value , match ) ) ) {
2006-07-19 13:28:38 +00:00
if ( prev ) {
prev - > next = cur - > next ;
if ( cur = = category - > last )
category - > last = prev ;
} else {
category - > root = cur - > next ;
if ( cur = = category - > last )
category - > last = NULL ;
}
cur - > next = NULL ;
ast_variables_destroy ( cur ) ;
2006-07-29 22:02:37 +00:00
res = 0 ;
} else
prev = cur ;
cur = curn ;
2006-07-19 13:28:38 +00:00
}
2006-07-29 22:02:37 +00:00
return res ;
2006-07-19 13:28:38 +00:00
}
2007-04-20 18:23:24 +00:00
int ast_variable_update ( struct ast_category * category , const char * variable ,
const char * value , const char * match , unsigned int object )
2006-07-19 13:28:38 +00:00
{
struct ast_variable * cur , * prev = NULL , * newer ;
2007-04-20 18:23:24 +00:00
if ( ! ( newer = ast_variable_new ( variable , value ) ) )
2006-07-19 13:28:38 +00:00
return - 1 ;
2007-04-20 18:23:24 +00:00
newer - > object = object ;
for ( cur = category - > root ; cur ; prev = cur , cur = cur - > next ) {
if ( strcasecmp ( cur - > name , variable ) | |
( ! ast_strlen_zero ( match ) & & strcasecmp ( cur - > value , match ) ) )
continue ;
newer - > next = cur - > next ;
newer - > object = cur - > object | | object ;
if ( prev )
prev - > next = newer ;
else
category - > root = newer ;
if ( category - > last = = cur )
category - > last = newer ;
cur - > next = NULL ;
ast_variables_destroy ( cur ) ;
return 0 ;
2006-07-19 13:28:38 +00:00
}
if ( prev )
prev - > next = newer ;
else
category - > root = newer ;
2007-04-20 18:23:24 +00:00
2006-07-19 13:28:38 +00:00
return 0 ;
}
2007-01-05 23:58:53 +00:00
int ast_category_delete ( struct ast_config * cfg , const char * category )
2006-07-19 13:28:38 +00:00
{
struct ast_category * prev = NULL , * cat ;
cat = cfg - > root ;
2007-01-23 00:11:32 +00:00
while ( cat ) {
2006-07-19 13:28:38 +00:00
if ( cat - > name = = category ) {
ast_variables_destroy ( cat - > root ) ;
if ( prev ) {
prev - > next = cat - > next ;
if ( cat = = cfg - > last )
cfg - > last = prev ;
} else {
cfg - > root = cat - > next ;
if ( cat = = cfg - > last )
cfg - > last = NULL ;
}
2007-06-06 21:20:11 +00:00
ast_free ( cat ) ;
2006-07-19 13:28:38 +00:00
return 0 ;
}
prev = cat ;
cat = cat - > next ;
}
2006-07-19 17:26:47 +00:00
prev = NULL ;
2006-07-19 13:28:38 +00:00
cat = cfg - > root ;
2007-01-23 00:11:32 +00:00
while ( cat ) {
2006-07-19 13:28:38 +00:00
if ( ! strcasecmp ( cat - > name , category ) ) {
ast_variables_destroy ( cat - > root ) ;
if ( prev ) {
prev - > next = cat - > next ;
if ( cat = = cfg - > last )
cfg - > last = prev ;
} else {
cfg - > root = cat - > next ;
if ( cat = = cfg - > last )
cfg - > last = NULL ;
}
2007-06-06 21:20:11 +00:00
ast_free ( cat ) ;
2006-07-19 13:28:38 +00:00
return 0 ;
}
prev = cat ;
cat = cat - > next ;
}
return - 1 ;
}
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 ;
2007-01-23 00:11:32 +00:00
while ( cat ) {
2005-01-25 06:10:20 +00:00
ast_variables_destroy ( cat - > root ) ;
catn = cat ;
cat = cat - > next ;
2007-06-06 21:20:11 +00:00
ast_free ( catn ) ;
2005-01-25 06:10:20 +00:00
}
2007-06-06 21:20:11 +00:00
ast_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
2007-03-26 20:27:02 +00:00
static int process_text_line ( struct ast_config * cfg , struct ast_category * * cat , char * buf , int lineno , const char * configfile , int withcomments ,
char * * comment_buffer , int * comment_buffer_size , char * * lline_buffer , int * lline_buffer_size )
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 ;
2006-02-09 16:59:50 +00:00
if ( ! ( * cat = newcat = ast_category_new ( catname ) ) ) {
2005-01-22 22:13:11 +00:00
return - 1 ;
}
2006-10-26 01:38:47 +00:00
/* add comments */
2007-03-26 20:27:02 +00:00
if ( withcomments & & * comment_buffer & & ( * comment_buffer ) [ 0 ] ) {
newcat - > precomments = ALLOC_COMMENT ( * comment_buffer ) ;
2006-10-26 01:38:47 +00:00
}
2007-03-26 20:27:02 +00:00
if ( withcomments & & * lline_buffer & & ( * lline_buffer ) [ 0 ] ) {
newcat - > sameline = ALLOC_COMMENT ( * lline_buffer ) ;
2006-10-26 01:38:47 +00:00
}
2007-01-23 00:11:32 +00:00
if ( withcomments )
2007-03-26 20:27:02 +00:00
CB_RESET ( comment_buffer , lline_buffer ) ;
2006-10-26 01:38:47 +00:00
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 ) ;
2007-03-26 20:27:02 +00:00
if ( ! ( * cat ) ) {
2005-01-30 06:26:19 +00:00
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 ;
2007-01-23 00:11:32 +00:00
while ( * c & & ( * c > 32 ) ) c + + ;
2005-01-22 22:13:11 +00:00
if ( * c ) {
* c = ' \0 ' ;
/* Find real argument */
2006-01-07 15:18:23 +00:00
c = ast_skip_blanks ( c + 1 ) ;
2007-03-26 20:27:02 +00:00
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 " ) ;
2007-01-23 00:11:32 +00:00
if ( ! do_include )
2005-02-02 03:38:24 +00:00
do_exec = ! strcasecmp ( cur , " exec " ) ;
else
do_exec = 0 ;
2005-12-04 20:40:46 +00:00
if ( do_exec & & ! ast_opt_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 */
2007-01-23 00:11:32 +00:00
while ( ( * c = = ' < ' ) | | ( * c = = ' > ' ) | | ( * c = = ' \" ' ) ) c + + ;
2005-01-22 22:13:11 +00:00
/* 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 ) {
2005-12-26 18:35:28 +00:00
snprintf ( exec_file , sizeof ( exec_file ) , " /var/tmp/exec.%d.%ld " , ( int ) time ( NULL ) , ( long ) pthread_self ( ) ) ;
2005-02-02 03:38:24 +00:00
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 */
2006-07-19 13:28:38 +00:00
do_include = ast_config_internal_load ( cur , cfg , withcomments ) ? 1 : 0 ;
2007-01-23 00:11:32 +00:00
if ( ! ast_strlen_zero ( exec_file ) )
2005-02-02 03:38:24 +00:00
unlink ( exec_file ) ;
2007-01-23 00:11:32 +00:00
if ( ! do_include )
2005-06-07 21:28:04 +00:00
return 0 ;
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) */
2007-03-26 20:27:02 +00:00
if ( ! ( * cat ) ) {
2005-01-22 22:13:11 +00:00
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 ;
2006-02-09 16:59:50 +00:00
if ( ( v = ast_variable_new ( ast_strip ( cur ) , ast_strip ( c ) ) ) ) {
2005-01-22 22:13:11 +00:00
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 ) ;
2006-10-26 01:38:47 +00:00
/* add comments */
2007-03-26 20:27:02 +00:00
if ( withcomments & & * comment_buffer & & ( * comment_buffer ) [ 0 ] ) {
v - > precomments = ALLOC_COMMENT ( * comment_buffer ) ;
2006-10-26 01:38:47 +00:00
}
2007-03-26 20:27:02 +00:00
if ( withcomments & & * lline_buffer & & ( * lline_buffer ) [ 0 ] ) {
v - > sameline = ALLOC_COMMENT ( * lline_buffer ) ;
2006-10-26 01:38:47 +00:00
}
2007-01-23 00:11:32 +00:00
if ( withcomments )
2007-03-26 20:27:02 +00:00
CB_RESET ( comment_buffer , lline_buffer ) ;
2006-10-26 01:38:47 +00:00
2005-01-22 21:00:31 +00:00
} else {
2005-01-22 22:13:11 +00:00
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
}
2002-03-05 23:57:31 +00:00
}
return 0 ;
}
2006-07-19 13:28:38 +00:00
static struct ast_config * config_text_file_load ( const char * database , const char * table , const char * filename , struct ast_config * cfg , int withcomments )
1999-10-24 18:00:20 +00:00
{
2006-02-24 10:50:43 +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 ;
2006-02-24 10:50:43 +00:00
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 ;
2005-06-07 21:28:04 +00:00
int count = 0 ;
2005-10-31 21:08:55 +00:00
struct stat statbuf ;
2007-03-26 20:27:02 +00:00
/*! Growable string buffer */
char * comment_buffer = 0 ; /*!< this will be a comment collector.*/
int comment_buffer_size = 0 ; /*!< the amount of storage so far alloc'd for the comment_buffer */
char * lline_buffer = 0 ; /*!< A buffer for stuff behind the ; */
int lline_buffer_size = 0 ;
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 ] = = ' / ' ) {
2005-07-10 22:56:21 +00:00
ast_copy_string ( fn , filename , sizeof ( fn ) ) ;
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
2006-10-26 01:38:47 +00:00
if ( withcomments ) {
2007-03-26 20:27:02 +00:00
CB_INIT ( & comment_buffer , & comment_buffer_size , & lline_buffer , & lline_buffer_size ) ;
2007-01-04 22:34:24 +00:00
if ( ! lline_buffer | | ! comment_buffer ) {
ast_log ( LOG_ERROR , " Failed to initialize the comment buffer! \n " ) ;
return NULL ;
}
2006-10-26 01:38:47 +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 + + ) {
2005-07-10 22:56:21 +00:00
ast_copy_string ( fn , globbuf . gl_pathv [ i ] , sizeof ( fn ) ) ;
2004-12-11 05:16:30 +00:00
# endif
2005-10-31 21:08:55 +00:00
do {
2005-11-07 22:05:31 +00:00
if ( stat ( fn , & statbuf ) )
2005-10-31 21:08:55 +00:00
continue ;
2005-11-07 22:05:31 +00:00
2005-10-31 21:08:55 +00:00
if ( ! S_ISREG ( statbuf . st_mode ) ) {
ast_log ( LOG_WARNING , " '%s' is not a regular file, ignoring \n " , fn ) ;
continue ;
}
2006-09-19 16:23:45 +00:00
if ( option_verbose > 1 ) {
2005-10-31 21:08:55 +00:00
ast_verbose ( VERBOSE_PREFIX_2 " Parsing '%s': " , fn ) ;
fflush ( stdout ) ;
}
if ( ! ( f = fopen ( fn , " r " ) ) ) {
2007-06-14 19:39:12 +00:00
ast_debug ( 1 , " No file to parse: %s \n " , fn ) ;
2006-09-19 16:23:45 +00:00
if ( option_verbose > 1 )
2005-10-31 21:08:55 +00:00
ast_verbose ( " Not found (%s) \n " , strerror ( errno ) ) ;
continue ;
}
2005-06-07 21:28:04 +00:00
count + + ;
2007-06-14 19:39:12 +00:00
ast_debug ( 1 , " Parsing %s \n " , fn ) ;
2006-09-19 16:23:45 +00:00
if ( option_verbose > 1 )
2005-01-22 22:13:11 +00:00
ast_verbose ( " Found \n " ) ;
2007-01-23 00:11:32 +00:00
while ( ! feof ( f ) ) {
2005-01-22 22:13:11 +00:00
lineno + + ;
if ( fgets ( buf , sizeof ( buf ) , f ) ) {
2007-01-04 22:34:24 +00:00
if ( withcomments ) {
2007-03-26 20:27:02 +00:00
CB_ADD ( & comment_buffer , & comment_buffer_size , lline_buffer ) ; /* add the current lline buffer to the comment buffer */
2006-10-26 01:38:47 +00:00
lline_buffer [ 0 ] = 0 ; /* erase the lline buffer */
}
2005-01-22 22:13:11 +00:00
new_buf = buf ;
2006-10-26 01:38:47 +00:00
if ( comment )
2005-01-22 22:13:11 +00:00
process_buf = NULL ;
else
process_buf = buf ;
2006-10-26 01:38:47 +00:00
2005-01-22 22:13:11 +00:00
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 ;
2007-01-23 00:11:32 +00:00
} else if ( comment_p [ 1 ] = = COMMENT_TAG & & comment_p [ 2 ] = = COMMENT_TAG & & ( comment_p [ 3 ] ! = ' - ' ) ) {
2005-01-22 22:13:11 +00:00
/* 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 ) ;
2006-10-26 01:38:47 +00:00
if ( withcomments ) {
2007-03-26 20:27:02 +00:00
CB_ADD ( & comment_buffer , & comment_buffer_size , " ; " ) ;
CB_ADD_LEN ( & comment_buffer , & comment_buffer_size , oldptr + 1 , new_buf - oldptr - 1 ) ;
2006-10-26 01:38:47 +00:00
}
2005-01-22 22:13:11 +00:00
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 */
2006-10-26 01:38:47 +00:00
if ( withcomments ) {
2007-03-26 20:27:02 +00:00
LLB_ADD ( & lline_buffer , & lline_buffer_size , comment_p ) ;
2006-10-26 01:38:47 +00:00
}
2005-01-22 22:13:11 +00:00
* 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
}
2007-01-23 00:11:32 +00:00
if ( withcomments & & comment & & ! process_buf )
2006-10-26 01:38:47 +00:00
{
2007-03-26 20:27:02 +00:00
CB_ADD ( & comment_buffer , & comment_buffer_size , buf ) ; /* the whole line is a comment, store it */
2006-10-26 01:38:47 +00:00
}
2005-01-30 06:26:19 +00:00
if ( process_buf ) {
char * buf = ast_strip ( process_buf ) ;
2005-10-26 18:54:24 +00:00
if ( ! ast_strlen_zero ( buf ) ) {
2007-03-26 20:27:02 +00:00
if ( process_text_line ( cfg , & cat , buf , lineno , fn , withcomments , & comment_buffer , & comment_buffer_size , & lline_buffer , & lline_buffer_size ) ) {
2005-01-30 06:26:19 +00:00
cfg = NULL ;
break ;
}
2005-10-26 18:54:24 +00:00
}
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 ) ;
2007-01-23 00:11:32 +00:00
} while ( 0 ) ;
2004-12-04 16:09:45 +00:00
if ( comment ) {
2007-06-14 23:23:35 +00:00
ast_log ( LOG_WARNING , " Unterminated comment detected beginning on line %d \n " , nest [ comment - 1 ] ) ;
2004-12-04 16:09:45 +00:00
}
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
2007-01-04 22:34:24 +00:00
2007-01-16 01:16:57 +00:00
if ( cfg & & cfg - > include_level = = 1 & & withcomments & & comment_buffer ) {
2007-06-06 21:20:11 +00:00
ast_free ( comment_buffer ) ;
ast_free ( lline_buffer ) ;
2007-01-04 22:34:24 +00:00
comment_buffer = NULL ;
lline_buffer = NULL ;
comment_buffer_size = 0 ;
lline_buffer_size = 0 ;
2006-10-26 01:38:47 +00:00
}
2007-01-04 22:34:24 +00:00
2005-06-07 21:28:04 +00:00
if ( count = = 0 )
return NULL ;
2004-12-11 05:16:30 +00:00
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 ;
2006-02-24 10:50:43 +00:00
char fn [ 256 ] ;
2005-01-25 06:10:20 +00:00
char date [ 256 ] = " " ;
time_t t ;
struct ast_variable * var ;
struct ast_category * cat ;
2006-10-26 01:38:47 +00:00
struct ast_comment * cmt ;
2005-01-25 06:10:20 +00:00
int blanklines = 0 ;
if ( configfile [ 0 ] = = ' / ' ) {
2005-06-06 03:04:58 +00:00
ast_copy_string ( fn , configfile , sizeof ( fn ) ) ;
2004-06-17 04:53:55 +00:00
} else {
2005-05-08 17:31:09 +00:00
snprintf ( fn , sizeof ( fn ) , " %s/%s " , ast_config_AST_CONFIG_DIR , configfile ) ;
2004-06-11 00:12:35 +00:00
}
2005-01-25 06:10:20 +00:00
time ( & t ) ;
2005-07-10 22:56:21 +00:00
ast_copy_string ( date , ctime ( & t ) , sizeof ( date ) ) ;
2005-11-01 21:53:30 +00:00
# ifdef __CYGWIN__
if ( ( f = fopen ( fn , " w+ " ) ) ) {
# else
2005-01-25 06:10:20 +00:00
if ( ( f = fopen ( fn , " w " ) ) ) {
2005-11-01 21:53:30 +00:00
# endif
2006-09-19 16:23:45 +00:00
if ( option_verbose > 1 )
2006-11-15 18:44:29 +00:00
ast_verbose ( VERBOSE_PREFIX_2 " Saving '%s': " , fn ) ;
2005-01-25 06:10:20 +00:00
fprintf ( f , " ;! \n " ) ;
fprintf ( f , " ;! Automatically generated configuration file \n " ) ;
2006-11-15 20:05:26 +00:00
if ( strcmp ( configfile , fn ) )
fprintf ( f , " ;! Filename: %s (%s) \n " , configfile , fn ) ;
else
fprintf ( f , " ;! Filename: %s \n " , configfile ) ;
2005-01-25 06:10:20 +00:00
fprintf ( f , " ;! Generator: %s \n " , generator ) ;
fprintf ( f , " ;! Creation Date: %s " , date ) ;
fprintf ( f , " ;! \n " ) ;
cat = cfg - > root ;
2007-01-23 00:11:32 +00:00
while ( cat ) {
2005-01-25 06:10:20 +00:00
/* Dump section with any appropriate comment */
2006-10-26 01:38:47 +00:00
for ( cmt = cat - > precomments ; cmt ; cmt = cmt - > next )
{
if ( cmt - > cmt [ 0 ] ! = ' ; ' | | cmt - > cmt [ 1 ] ! = ' ! ' )
fprintf ( f , " %s " , cmt - > cmt ) ;
}
if ( ! cat - > precomments )
fprintf ( f , " \n " ) ;
fprintf ( f , " [%s] " , cat - > name ) ;
2007-01-23 00:11:32 +00:00
for ( cmt = cat - > sameline ; cmt ; cmt = cmt - > next )
2006-10-26 01:38:47 +00:00
{
fprintf ( f , " %s " , cmt - > cmt ) ;
}
if ( ! cat - > sameline )
fprintf ( f , " \n " ) ;
2005-01-25 06:10:20 +00:00
var = cat - > root ;
2007-01-23 00:11:32 +00:00
while ( var ) {
2006-10-26 01:38:47 +00:00
for ( cmt = var - > precomments ; cmt ; cmt = cmt - > next )
{
if ( cmt - > cmt [ 0 ] ! = ' ; ' | | cmt - > cmt [ 1 ] ! = ' ! ' )
fprintf ( f , " %s " , cmt - > cmt ) ;
}
2005-01-25 06:10:20 +00:00
if ( var - > sameline )
2006-10-26 01:38:47 +00:00
fprintf ( f , " %s %s %s %s " , var - > name , ( var - > object ? " => " : " = " ) , var - > value , var - > sameline - > cmt ) ;
2005-01-25 06:10:20 +00:00
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 ;
}
2006-07-19 13:28:38 +00:00
if ( ( option_verbose > 1 ) & & ! option_debug )
ast_verbose ( " Saved \n " ) ;
2005-01-25 06:10:20 +00:00
} else {
2007-06-14 19:39:12 +00:00
ast_debug ( 1 , " Unable to open for writing: %s \n " , fn ) ;
2006-09-19 16:23:45 +00:00
if ( option_verbose > 1 )
2006-11-15 18:44:29 +00:00
ast_verbose ( VERBOSE_PREFIX_2 " Unable to write (%s) " , strerror ( errno ) ) ;
2005-01-25 06:10:20 +00:00
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 ;
2007-06-06 21:20:11 +00:00
ast_free ( map ) ;
2005-01-25 06:10:20 +00:00
}
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 ;
2006-02-09 16:59:50 +00:00
if ( ! ( map = ast_calloc ( 1 , length ) ) )
2005-02-10 21:14:11 +00:00
return - 1 ;
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 ;
}
2006-02-14 23:08:06 +00:00
int read_config_maps ( void )
2005-01-25 06:10:20 +00:00
{
2005-06-07 21:28:04 +00:00
struct ast_config * config , * configtmp ;
2005-01-25 06:10:20 +00:00
struct ast_variable * v ;
2007-01-10 19:49:26 +00:00
char * driver , * table , * database , * stringp , * tmp ;
2005-01-25 06:10:20 +00:00
clear_config_maps ( ) ;
2005-06-07 21:28:04 +00:00
configtmp = ast_config_new ( ) ;
configtmp - > max_include_level = 1 ;
2006-07-19 13:28:38 +00:00
config = ast_config_internal_load ( extconfig_conf , configtmp , 0 ) ;
2005-06-07 21:28:04 +00:00
if ( ! config ) {
ast_config_destroy ( configtmp ) ;
2006-02-14 23:08:06 +00:00
return 0 ;
2005-06-07 21:28:04 +00:00
}
2005-01-25 06:10:20 +00:00
for ( v = ast_variable_browse ( config , " settings " ) ; v ; v = v - > next ) {
stringp = v - > value ;
driver = strsep ( & stringp , " , " ) ;
2005-12-27 06:42:29 +00:00
2007-01-10 19:49:26 +00:00
if ( ( tmp = strchr ( stringp , ' \" ' ) ) )
stringp = tmp ;
2005-12-27 06:42:29 +00:00
/* check if the database text starts with a double quote */
if ( * stringp = = ' " ' ) {
stringp + + ;
database = strsep ( & stringp , " \" " ) ;
strsep ( & stringp , " , " ) ;
} else {
/* apparently this text has no quotes */
database = strsep ( & stringp , " , " ) ;
}
2005-01-25 06:10:20 +00:00
table = strsep ( & stringp , " , " ) ;
2005-12-27 06:42:29 +00:00
2005-07-05 22:11:43 +00:00
if ( ! strcmp ( v - > name , extconfig_conf ) ) {
ast_log ( LOG_WARNING , " Cannot bind '%s'! \n " , extconfig_conf ) ;
continue ;
}
if ( ! strcmp ( v - > name , " asterisk.conf " ) ) {
ast_log ( LOG_WARNING , " Cannot bind 'asterisk.conf'! \n " ) ;
continue ;
}
if ( ! strcmp ( v - > name , " logger.conf " ) ) {
ast_log ( LOG_WARNING , " Cannot bind 'logger.conf'! \n " ) ;
2005-01-25 06:10:20 +00:00
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 ) ;
2006-02-14 23:08:06 +00:00
return 0 ;
2005-01-25 06:10:20 +00:00
}
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
}
2006-01-20 00:18:42 +00:00
/*! \brief Find realtime engine for realtime family */
2005-08-23 01:44:28 +00:00
static struct ast_config_engine * find_engine ( const char * family , char * database , int dbsiz , char * table , int tabsiz )
2002-03-05 23:57:31 +00:00
{
2005-07-05 21:17:58 +00:00
struct ast_config_engine * eng , * ret = NULL ;
2005-01-25 06:10:20 +00:00
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-07-05 21:17:58 +00:00
for ( map = config_maps ; map ; map = map - > next ) {
2005-08-23 01:44:28 +00:00
if ( ! strcasecmp ( family , map - > name ) ) {
if ( database )
ast_copy_string ( database , map - > database , dbsiz ) ;
if ( table )
ast_copy_string ( table , map - > table ? map - > table : family , tabsiz ) ;
2005-01-25 06:10:20 +00:00
break ;
2001-10-09 14:54:42 +00:00
}
}
2005-08-23 01:44:28 +00:00
/* Check if the required driver (engine) exist */
2005-01-25 06:10:20 +00:00
if ( map ) {
2005-07-05 21:17:58 +00:00
for ( eng = config_engine_list ; ! ret & & eng ; eng = eng - > next ) {
if ( ! strcasecmp ( eng - > name , map - > driver ) )
2005-01-25 06:10:20 +00:00
ret = eng ;
1999-10-24 18:00:20 +00:00
}
}
2005-07-05 21:17:58 +00:00
2005-01-25 06:10:20 +00:00
ast_mutex_unlock ( & config_lock ) ;
2005-07-05 21:17:58 +00:00
/* if we found a mapping, but the engine is not available, then issue a warning */
if ( map & & ! ret )
2005-08-23 01:44:28 +00:00
ast_log ( LOG_WARNING , " Realtime mapping for '%s' found to engine '%s', but the engine is not available \n " , map - > name , map - > driver ) ;
2005-01-25 06:10:20 +00:00
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
2006-07-19 13:28:38 +00:00
struct ast_config * ast_config_internal_load ( const char * filename , struct ast_config * cfg , int withcomments )
2004-06-17 04:53:55 +00:00
{
2006-02-24 10:50:43 +00:00
char db [ 256 ] ;
char table [ 256 ] ;
2005-01-25 06:10:20 +00:00
struct ast_config_engine * loader = & text_file_engine ;
2006-10-26 01:38:47 +00:00
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 ;
}
}
2006-07-19 13:28:38 +00:00
result = loader - > load_func ( db , table , filename , cfg , withcomments ) ;
2005-02-02 03:38:24 +00:00
2005-01-25 06:10:20 +00:00
if ( result )
result - > include_level - - ;
2007-04-26 01:29:23 +00:00
else
cfg - > include_level - - ;
2005-01-25 06:10:20 +00:00
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 ;
2006-07-19 13:28:38 +00:00
result = ast_config_internal_load ( filename , cfg , 0 ) ;
if ( ! result )
ast_config_destroy ( cfg ) ;
return result ;
}
struct ast_config * ast_config_load_with_comments ( const char * filename )
{
struct ast_config * cfg ;
struct ast_config * result ;
cfg = ast_config_new ( ) ;
if ( ! cfg )
return NULL ;
result = ast_config_internal_load ( filename , cfg , 1 ) ;
2005-01-25 06:10:20 +00:00
if ( ! result )
ast_config_destroy ( cfg ) ;
return result ;
2004-06-11 00:12:35 +00:00
}
2007-01-14 05:34:32 +00:00
static struct ast_variable * ast_load_realtime_helper ( const char * family , va_list ap )
2004-06-17 04:53:55 +00:00
{
2005-01-25 06:10:20 +00:00
struct ast_config_engine * eng ;
2006-02-24 10:50:43 +00:00
char db [ 256 ] = " " ;
char table [ 256 ] = " " ;
2005-01-25 06:10:20 +00:00
struct ast_variable * res = NULL ;
eng = find_engine ( family , db , sizeof ( db ) , table , sizeof ( table ) ) ;
if ( eng & & eng - > realtime_func )
res = eng - > realtime_func ( db , table , ap ) ;
2007-01-14 05:34:32 +00:00
return res ;
}
struct ast_variable * ast_load_realtime_all ( const char * family , . . . )
{
struct ast_variable * res ;
va_list ap ;
va_start ( ap , family ) ;
res = ast_load_realtime_helper ( family , ap ) ;
2005-01-25 06:10:20 +00:00
va_end ( ap ) ;
return res ;
2007-01-07 16:21:12 +00:00
}
struct ast_variable * ast_load_realtime ( const char * family , . . . )
{
struct ast_variable * res , * cur , * prev = NULL , * freeme = NULL ;
va_list ap ;
va_start ( ap , family ) ;
2007-01-14 05:34:32 +00:00
res = ast_load_realtime_helper ( family , ap ) ;
2007-01-07 16:21:12 +00:00
va_end ( ap ) ;
/* Eliminate blank entries */
for ( cur = res ; cur ; cur = cur - > next ) {
if ( freeme ) {
2007-06-06 21:20:11 +00:00
ast_free ( freeme ) ;
2007-01-07 16:21:12 +00:00
freeme = NULL ;
}
if ( ast_strlen_zero ( cur - > value ) ) {
if ( prev )
prev - > next = cur - > next ;
else
res = cur - > next ;
freeme = cur ;
} else {
prev = cur ;
}
}
return res ;
2004-06-11 00:12:35 +00:00
}
2005-01-25 06:10:20 +00:00
2006-01-20 00:18:42 +00:00
/*! \brief Check if realtime engine is configured for family */
2005-08-23 01:44:28 +00:00
int ast_check_realtime ( const char * family )
{
struct ast_config_engine * eng ;
eng = find_engine ( family , NULL , 0 , NULL , 0 ) ;
if ( eng )
return 1 ;
return 0 ;
}
2007-02-14 20:22:20 +00:00
/*! \brief Check if there's any realtime engines loaded */
int ast_realtime_enabled ( )
{
return config_maps ? 1 : 0 ;
}
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 ;
2006-02-24 10:50:43 +00:00
char db [ 256 ] = " " ;
char table [ 256 ] = " " ;
2005-01-25 06:10:20 +00:00
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 ;
2006-02-24 10:50:43 +00:00
char db [ 256 ] = " " ;
char table [ 256 ] = " " ;
2005-01-25 06:10:20 +00:00
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 ) ;
2007-04-11 13:41:17 +00:00
return res ;
}
int ast_store_realtime ( const char * family , . . . ) {
struct ast_config_engine * eng ;
int res = - 1 ;
char db [ 256 ] = " " ;
char table [ 256 ] = " " ;
va_list ap ;
va_start ( ap , family ) ;
eng = find_engine ( family , db , sizeof ( db ) , table , sizeof ( table ) ) ;
if ( eng & & eng - > store_func )
res = eng - > store_func ( db , table , ap ) ;
va_end ( ap ) ;
return res ;
}
int ast_destroy_realtime ( const char * family , const char * keyfield , const char * lookup , . . . ) {
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 - > destroy_func )
res = eng - > destroy_func ( db , table , keyfield , lookup , ap ) ;
va_end ( ap ) ;
2005-01-25 06:10:20 +00:00
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 ) ;
}
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 [ ] =
2006-11-02 23:16:09 +00:00
" Usage: core show config mappings \n "
2005-03-17 00:35:06 +00:00
" Shows the filenames to config engines. \n " ;
2006-09-18 19:54:18 +00:00
static struct ast_cli_entry cli_config [ ] = {
2006-11-02 23:16:09 +00:00
{ { " core " , " show " , " config " , " mappings " , NULL } ,
2006-09-18 19:54:18 +00:00
config_command , " Display config mappings (file names to config engines) " ,
2006-09-21 21:17:39 +00:00
show_config_help } ,
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 ( )
{
2006-09-18 19:54:18 +00:00
ast_cli_register_multiple ( cli_config , sizeof ( cli_config ) / sizeof ( struct ast_cli_entry ) ) ;
return 0 ;
2004-06-11 00:12:35 +00:00
}