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:37:40 +00:00
2007-03-26 20:06:12 +00:00
/*! \brief Structure to keep comments for rewriting configuration files */
2006-10-26 01:37:40 +00:00
struct ast_comment {
struct ast_comment * next ;
char cmt [ 0 ];
};
#define CB_INCR 250
2007-03-26 20:06:12 +00:00
static void CB_INIT ( char ** comment_buffer , int * comment_buffer_size , char ** lline_buffer , int * lline_buffer_size )
2006-10-26 01:37:40 +00:00
{
2007-03-26 20:06:12 +00:00
if ( ! ( * comment_buffer )) {
* comment_buffer = ast_malloc ( CB_INCR );
if ( ! ( * comment_buffer ))
2006-11-01 17:48:48 +00:00
return ;
2007-03-26 20:06:12 +00:00
( * comment_buffer )[ 0 ] = 0 ;
* comment_buffer_size = CB_INCR ;
* lline_buffer = ast_malloc ( CB_INCR );
if ( ! ( * lline_buffer ))
2007-01-04 22:28:29 +00:00
return ;
2007-03-26 20:06:12 +00:00
( * lline_buffer )[ 0 ] = 0 ;
* lline_buffer_size = CB_INCR ;
2006-11-01 17:48:48 +00:00
} else {
2007-03-26 20:06:12 +00:00
( * comment_buffer )[ 0 ] = 0 ;
( * lline_buffer )[ 0 ] = 0 ;
2006-10-26 01:37:40 +00:00
}
}
2007-03-26 20:06:12 +00:00
static void CB_ADD ( char ** comment_buffer , int * comment_buffer_size , char * str )
2006-10-26 01:37:40 +00:00
{
2007-03-26 20:06:12 +00:00
int rem = * comment_buffer_size - strlen ( * comment_buffer ) - 1 ;
2006-11-01 17:48:48 +00:00
int siz = strlen ( str );
if ( rem < siz + 1 ) {
2007-03-26 20:06:12 +00:00
* comment_buffer = ast_realloc ( * comment_buffer , * comment_buffer_size + CB_INCR + siz + 1 );
if ( ! ( * comment_buffer ))
2006-11-01 17:48:48 +00:00
return ;
2007-03-26 20:06:12 +00:00
* comment_buffer_size += CB_INCR + siz + 1 ;
2006-10-26 01:37:40 +00:00
}
2007-03-26 20:06:12 +00:00
strcat ( * comment_buffer , str );
2006-10-26 01:37:40 +00:00
}
2007-03-26 20:06:12 +00:00
static void CB_ADD_LEN ( char ** comment_buffer , int * comment_buffer_size , char * str , int len )
2006-10-26 01:37:40 +00:00
{
2007-03-26 20:06:12 +00:00
int cbl = strlen ( * comment_buffer ) + 1 ;
int rem = * comment_buffer_size - cbl ;
2006-11-01 17:48:48 +00:00
if ( rem < len + 1 ) {
2007-03-26 20:06:12 +00:00
* comment_buffer = ast_realloc ( * comment_buffer , * comment_buffer_size + CB_INCR + len + 1 );
if ( ! ( * comment_buffer ))
2006-11-01 17:48:48 +00:00
return ;
2007-03-26 20:06:12 +00:00
* comment_buffer_size += CB_INCR + len + 1 ;
2006-10-26 01:37:40 +00:00
}
2007-03-26 20:06:12 +00:00
strncat ( * comment_buffer , str , len );
( * comment_buffer )[ cbl + len - 1 ] = 0 ;
2006-10-26 01:37:40 +00:00
}
2007-03-26 20:06:12 +00:00
static void LLB_ADD ( char ** lline_buffer , int * lline_buffer_size , char * str )
2006-10-26 01:37:40 +00:00
{
2007-03-26 20:06:12 +00:00
int rem = * lline_buffer_size - strlen ( * lline_buffer ) - 1 ;
2006-11-01 17:48:48 +00:00
int siz = strlen ( str );
if ( rem < siz + 1 ) {
2007-03-26 20:06:12 +00:00
* lline_buffer = ast_realloc ( * lline_buffer , * lline_buffer_size + CB_INCR + siz + 1 );
if ( ! ( * lline_buffer ))
2006-11-01 17:48:48 +00:00
return ;
2007-03-26 20:06:12 +00:00
* lline_buffer_size += CB_INCR + siz + 1 ;
2006-10-26 01:37:40 +00:00
}
2007-03-26 20:06:12 +00:00
strcat ( * lline_buffer , str );
2006-10-26 01:37:40 +00:00
}
2007-03-26 20:06:12 +00:00
static void CB_RESET ( char ** comment_buffer , char ** lline_buffer )
2006-10-26 01:37:40 +00:00
{
2007-03-26 20:06:12 +00:00
( * comment_buffer )[ 0 ] = 0 ;
( * lline_buffer )[ 0 ] = 0 ;
2006-10-26 01:37:40 +00:00
}
static struct ast_comment * ALLOC_COMMENT ( const char * buffer )
{
2006-11-01 17:48:48 +00:00
struct ast_comment * x = ast_calloc ( 1 , sizeof ( struct ast_comment ) + strlen ( buffer ) + 1 );
2006-10-26 01:37:40 +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:48:48 +00:00
int ignored ; /*!< do not let user of the config see this category */
2007-01-04 22:28:29 +00:00
int include_level ;
2006-10-26 01:37:40 +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:48:48 +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:01:22 +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 ;
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 );
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:28:29 +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 );
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 )
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:01:22 +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
}
2006-07-29 22:02:37 +00:00
int ast_variable_delete ( struct ast_category * category , char * variable , 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:19:18 +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:19:18 +00:00
if ( ! ( newer = ast_variable_new ( variable , value )))
2006-07-19 13:28:38 +00:00
return - 1 ;
2007-04-20 18:19:18 +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:19:18 +00:00
2006-07-19 13:28:38 +00:00
return 0 ;
}
int ast_category_delete ( struct ast_config * cfg , char * category )
{
struct ast_category * prev = NULL , * cat ;
cat = cfg -> root ;
while ( cat ) {
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 ;
}
free ( cat );
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 ;
while ( cat ) {
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 ;
}
free ( cat );
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 ;
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
2007-03-26 20:06:12 +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:37:40 +00:00
/* add comments */
2007-03-26 20:06:12 +00:00
if ( withcomments && * comment_buffer && ( * comment_buffer )[ 0 ] ) {
newcat -> precomments = ALLOC_COMMENT ( * comment_buffer );
2006-10-26 01:37:40 +00:00
}
2007-03-26 20:06:12 +00:00
if ( withcomments && * lline_buffer && ( * lline_buffer )[ 0 ] ) {
newcat -> sameline = ALLOC_COMMENT ( * lline_buffer );
2006-10-26 01:37:40 +00:00
}
if ( withcomments )
2007-03-26 20:06:12 +00:00
CB_RESET ( comment_buffer , lline_buffer );
2006-10-26 01:37:40 +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:06:12 +00:00
if ( ! ( * cat )) {
2005-08-30 18:32:10 +00:00
ast_config_destroy ( cfg );
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 ;
while ( * c && ( * c > 32 )) c ++ ;
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:06:12 +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" );
if ( ! do_include )
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 */
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 ) {
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 ;
2005-02-02 03:38:24 +00:00
if ( ! ast_strlen_zero ( exec_file ))
unlink ( exec_file );
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:06:12 +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:37:40 +00:00
/* add comments */
2007-03-26 20:06:12 +00:00
if ( withcomments && * comment_buffer && ( * comment_buffer )[ 0 ] ) {
v -> precomments = ALLOC_COMMENT ( * comment_buffer );
2006-10-26 01:37:40 +00:00
}
2007-03-26 20:06:12 +00:00
if ( withcomments && * lline_buffer && ( * lline_buffer )[ 0 ] ) {
v -> sameline = ALLOC_COMMENT ( * lline_buffer );
2006-10-26 01:37:40 +00:00
}
if ( withcomments )
2007-03-26 20:06:12 +00:00
CB_RESET ( comment_buffer , lline_buffer );
2006-10-26 01:37:40 +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:06:12 +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:37:40 +00:00
if ( withcomments ) {
2007-03-26 20:06:12 +00:00
CB_INIT ( & comment_buffer , & comment_buffer_size , & lline_buffer , & lline_buffer_size );
2007-01-04 22:28:29 +00:00
if ( ! lline_buffer || ! comment_buffer ) {
ast_log ( LOG_ERROR , "Failed to initialize the comment buffer! \n " );
return NULL ;
}
2006-10-26 01:37:40 +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" ))) {
if ( option_debug )
ast_log ( LOG_DEBUG , "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 ++ ;
1999-10-24 18:00:20 +00:00
if ( option_debug )
ast_log ( LOG_DEBUG , "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 " );
while ( ! feof ( f )) {
lineno ++ ;
if ( fgets ( buf , sizeof ( buf ), f )) {
2007-01-04 22:28:29 +00:00
if ( withcomments ) {
2007-03-26 20:06:12 +00:00
CB_ADD ( & comment_buffer , & comment_buffer_size , lline_buffer ); /* add the current lline buffer to the comment buffer */
2006-10-26 01:37:40 +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:37:40 +00:00
if ( comment )
2005-01-22 22:13:11 +00:00
process_buf = NULL ;
else
process_buf = buf ;
2006-10-26 01:37:40 +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 ;
} 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 );
2006-10-26 01:37:40 +00:00
if ( withcomments ) {
2007-03-26 20:06:12 +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:37:40 +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:37:40 +00:00
if ( withcomments ) {
2007-03-26 20:06:12 +00:00
LLB_ADD ( & lline_buffer , & lline_buffer_size , comment_p );
2006-10-26 01:37:40 +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
}
2006-11-13 19:15:12 +00:00
if ( withcomments && comment && ! process_buf )
2006-10-26 01:37:40 +00:00
{
2007-03-26 20:06:12 +00:00
CB_ADD ( & comment_buffer , & comment_buffer_size , buf ); /* the whole line is a comment, store it */
2006-10-26 01:37:40 +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:06:12 +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 );
2005-10-31 21:08:55 +00:00
} while ( 0 );
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
2007-01-04 22:28:29 +00:00
2007-01-16 01:15:44 +00:00
if ( cfg && cfg -> include_level == 1 && withcomments && comment_buffer ) {
2007-01-04 22:28:29 +00:00
free ( comment_buffer );
free ( lline_buffer );
comment_buffer = NULL ;
lline_buffer = NULL ;
comment_buffer_size = 0 ;
lline_buffer_size = 0 ;
2006-10-26 01:37:40 +00:00
}
2007-01-04 22:28:29 +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:37:40 +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:43:30 +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:01:22 +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 ;
while ( cat ) {
/* Dump section with any appropriate comment */
2006-10-26 01:37:40 +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 );
for ( cmt = cat -> sameline ; cmt ; cmt = cmt -> next )
{
fprintf ( f , "%s" , cmt -> cmt );
}
if ( ! cat -> sameline )
fprintf ( f , " \n " );
2005-01-25 06:10:20 +00:00
var = cat -> root ;
while ( var ) {
2006-10-26 01:37:40 +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:37:40 +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 {
if ( option_debug )
2006-11-15 18:43:30 +00:00
ast_log ( LOG_DEBUG , "Unable to open for writing: %s \n " , fn );
2006-09-19 16:23:45 +00:00
if ( option_verbose > 1 )
2006-11-15 18:43:30 +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 ;
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 ;
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:46:29 +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:46:29 +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:37:40 +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 -- ;
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
}
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 ;
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 ;
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
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 ;
}
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 );
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:00:20 +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_show_config_mappings_deprecated = {
{ "show" , "config" , "mappings" , NULL },
config_command , NULL ,
NULL };
static struct ast_cli_entry cli_config [] = {
2006-11-02 23:00:20 +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)" ,
show_config_help , NULL , & cli_show_config_mappings_deprecated },
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
}