2012-06-01 16:33:25 +00:00
/*
* Asterisk - - An open source telephony toolkit .
*
* Copyright ( C ) 2012 , Digium , Inc .
*
* Mark Spencer < markster @ digium . com >
*
* 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 .
*
* This program is free software , distributed under the terms of
* the GNU General Public License Version 2. See the LICENSE file
* at the top of the source tree .
*/
/*! \file
* \ brief Configuration Option - handling
* \ author Terry Wilson < twilson @ digium . com >
*/
2012-06-15 16:20:16 +00:00
/*** MODULEINFO
< support_level > core < / support_level >
* * */
2012-06-01 16:33:25 +00:00
# include "asterisk.h"
ASTERISK_FILE_VERSION ( __FILE__ , " $Revision$ " )
# include <regex.h>
# include "asterisk/config.h"
# include "asterisk/config_options.h"
# include "asterisk/stringfields.h"
# include "asterisk/acl.h"
# include "asterisk/frame.h"
# ifdef LOW_MEMORY
# define CONFIG_OPT_BUCKETS 5
# else
# define CONFIG_OPT_BUCKETS 53
# endif /* LOW_MEMORY */
/*! \brief Bits of aco_info that shouldn't be assigned outside this file
* \ internal
*/
struct aco_info_internal {
void * pending ; /*!< The user-defined config object awaiting application */
} ;
struct aco_type_internal {
regex_t * regex ;
struct ao2_container * opts ; /*!< The container of options registered to the aco_info */
} ;
struct aco_option {
const char * name ;
2012-07-12 21:43:09 +00:00
const char * aliased_to ;
const char * default_val ;
2012-06-01 16:33:25 +00:00
enum aco_matchtype match_type ;
regex_t * name_regex ;
struct aco_type * * obj ;
enum aco_option_type type ;
aco_option_handler handler ;
unsigned int flags ;
2012-07-12 21:43:09 +00:00
unsigned char deprecated : 1 ;
2012-06-01 16:33:25 +00:00
size_t argc ;
intptr_t args [ 0 ] ;
} ;
void * aco_pending_config ( struct aco_info * info )
{
if ( ! ( info & & info - > internal ) ) {
ast_log ( LOG_ERROR , " This may not be called without an initialized aco_info! \n " ) ;
return NULL ;
}
return info - > internal - > pending ;
}
static void config_option_destroy ( void * obj )
{
struct aco_option * opt = obj ;
if ( opt - > match_type = = ACO_REGEX & & opt - > name_regex ) {
regfree ( opt - > name_regex ) ;
ast_free ( opt - > name_regex ) ;
}
}
static int int_handler_fn ( const struct aco_option * opt , struct ast_variable * var , void * obj ) ;
static int uint_handler_fn ( const struct aco_option * opt , struct ast_variable * var , void * obj ) ;
static int double_handler_fn ( const struct aco_option * opt , struct ast_variable * var , void * obj ) ;
static int sockaddr_handler_fn ( const struct aco_option * opt , struct ast_variable * var , void * obj ) ;
static int stringfield_handler_fn ( const struct aco_option * opt , struct ast_variable * var , void * obj ) ;
static int bool_handler_fn ( const struct aco_option * opt , struct ast_variable * var , void * obj ) ;
2012-06-28 01:12:06 +00:00
static int boolflag_handler_fn ( const struct aco_option * opt , struct ast_variable * var , void * obj ) ;
2012-06-01 16:33:25 +00:00
static int acl_handler_fn ( const struct aco_option * opt , struct ast_variable * var , void * obj ) ;
static int codec_handler_fn ( const struct aco_option * opt , struct ast_variable * var , void * obj ) ;
static aco_option_handler ast_config_option_default_handler ( enum aco_option_type type )
{
switch ( type ) {
case OPT_ACL_T : return acl_handler_fn ;
case OPT_BOOL_T : return bool_handler_fn ;
2012-06-28 01:12:06 +00:00
case OPT_BOOLFLAG_T : return boolflag_handler_fn ;
2012-06-01 16:33:25 +00:00
case OPT_CODEC_T : return codec_handler_fn ;
case OPT_DOUBLE_T : return double_handler_fn ;
case OPT_INT_T : return int_handler_fn ;
case OPT_SOCKADDR_T : return sockaddr_handler_fn ;
case OPT_STRINGFIELD_T : return stringfield_handler_fn ;
case OPT_UINT_T : return uint_handler_fn ;
case OPT_CUSTOM_T : return NULL ;
}
return NULL ;
}
static regex_t * build_regex ( const char * text )
{
int res ;
regex_t * regex ;
if ( ! ( regex = ast_malloc ( sizeof ( * regex ) ) ) ) {
return NULL ;
}
if ( ( res = regcomp ( regex , text , REG_EXTENDED | REG_ICASE | REG_NOSUB ) ) ) {
size_t len = regerror ( res , regex , NULL , 0 ) ;
char buf [ len ] ;
regerror ( res , regex , buf , len ) ;
ast_log ( LOG_ERROR , " Could not compile regex '%s': %s \n " , text , buf ) ;
ast_free ( regex ) ;
return NULL ;
}
return regex ;
}
2012-07-12 21:43:09 +00:00
static int link_option_to_types ( struct aco_type * * types , struct aco_option * opt )
{
size_t idx = 0 ;
struct aco_type * type ;
while ( ( type = types [ idx + + ] ) ) {
if ( ! ao2_link ( type - > internal - > opts , opt ) ) {
while ( - - idx ) {
ao2_unlink ( types [ idx ] - > internal - > opts , opt ) ;
}
return - 1 ;
}
}
return 0 ;
}
int aco_option_register_deprecated ( struct aco_info * info , const char * name , struct aco_type * * types , const char * aliased_to )
{
struct aco_option * opt ;
if ( ! info | | ast_strlen_zero ( name ) | | ast_strlen_zero ( aliased_to ) ) {
return - 1 ;
}
if ( ! ( opt = ao2_alloc ( sizeof ( * opt ) , config_option_destroy ) ) ) {
return - 1 ;
}
opt - > name = name ;
opt - > aliased_to = aliased_to ;
opt - > deprecated = 1 ;
opt - > match_type = ACO_EXACT ;
if ( link_option_to_types ( types , opt ) ) {
ao2_ref ( opt , - 1 ) ;
return - 1 ;
}
return 0 ;
}
2012-06-01 16:33:25 +00:00
int __aco_option_register ( struct aco_info * info , const char * name , enum aco_matchtype matchtype , struct aco_type * * types ,
const char * default_val , enum aco_option_type kind , aco_option_handler handler , unsigned int flags , size_t argc , . . . )
{
struct aco_option * opt ;
va_list ap ;
int tmp ;
/* Custom option types require a handler */
if ( ! handler & & kind = = OPT_CUSTOM_T ) {
return - 1 ;
}
if ( ! ( types & & types [ 0 ] ) ) {
return - 1 ;
}
if ( ! ( opt = ao2_alloc ( sizeof ( * opt ) + argc * sizeof ( opt - > args [ 0 ] ) , config_option_destroy ) ) ) {
return - 1 ;
}
if ( matchtype = = ACO_REGEX & & ! ( opt - > name_regex = build_regex ( name ) ) ) {
ao2_ref ( opt , - 1 ) ;
return - 1 ;
}
va_start ( ap , argc ) ;
for ( tmp = 0 ; tmp < argc ; tmp + + ) {
opt - > args [ tmp ] = va_arg ( ap , size_t ) ;
}
va_end ( ap ) ;
opt - > name = name ;
opt - > match_type = matchtype ;
opt - > default_val = default_val ;
opt - > type = kind ;
opt - > handler = handler ;
opt - > flags = flags ;
opt - > argc = argc ;
if ( ! opt - > handler & & ! ( opt - > handler = ast_config_option_default_handler ( opt - > type ) ) ) {
/* This should never happen */
ast_log ( LOG_ERROR , " No handler provided, and no default handler exists for type %d \n " , opt - > type ) ;
ao2_ref ( opt , - 1 ) ;
return - 1 ;
} ;
2012-07-12 21:43:09 +00:00
if ( link_option_to_types ( types , opt ) ) {
ao2_ref ( opt , - 1 ) ;
return - 1 ;
2012-06-01 16:33:25 +00:00
}
return 0 ;
}
static int config_opt_hash ( const void * obj , const int flags )
{
const struct aco_option * opt = obj ;
const char * name = ( flags & OBJ_KEY ) ? obj : opt - > name ;
return ast_str_case_hash ( name ) ;
}
static int config_opt_cmp ( void * obj , void * arg , int flags )
{
struct aco_option * opt1 = obj , * opt2 = arg ;
const char * name = ( flags & OBJ_KEY ) ? arg : opt2 - > name ;
return strcasecmp ( opt1 - > name , name ) ? 0 : CMP_MATCH | CMP_STOP ;
}
static int find_option_cb ( void * obj , void * arg , int flags )
{
struct aco_option * match = obj ;
const char * name = arg ;
switch ( match - > match_type ) {
case ACO_EXACT :
return strcasecmp ( name , match - > name ) ? 0 : CMP_MATCH | CMP_STOP ;
case ACO_REGEX :
return regexec ( match - > name_regex , name , 0 , NULL , 0 ) ? 0 : CMP_MATCH | CMP_STOP ;
}
ast_log ( LOG_ERROR , " Unknown match type. This should not be possible. \n " ) ;
return CMP_STOP ;
}
static struct aco_option * aco_option_find ( struct aco_type * type , const char * name )
{
struct aco_option * opt ;
/* Try an exact match with OBJ_KEY for the common/fast case, then iterate through
* all options for the regex cases */
if ( ! ( opt = ao2_callback ( type - > internal - > opts , OBJ_KEY , find_option_cb , ( void * ) name ) ) ) {
opt = ao2_callback ( type - > internal - > opts , 0 , find_option_cb , ( void * ) name ) ;
}
return opt ;
}
struct ao2_container * aco_option_container_alloc ( void )
{
return ao2_container_alloc ( CONFIG_OPT_BUCKETS , config_opt_hash , config_opt_cmp ) ;
}
static struct aco_type * internal_aco_type_find ( struct aco_file * file , struct ast_config * cfg , const char * category )
{
size_t x ;
struct aco_type * match ;
const char * val ;
for ( x = 0 , match = file - > types [ x ] ; match ; match = file - > types [ + + x ] ) {
/* First make sure we are an object that can service this category */
if ( ! regexec ( match - > internal - > regex , category , 0 , NULL , 0 ) = = ! match - > category_match ) {
continue ;
}
/* Then, see if we need to match a particular field */
if ( ! ast_strlen_zero ( match - > matchfield ) & & ( ! ast_strlen_zero ( match - > matchvalue ) | | match - > matchfunc ) ) {
if ( ! ( val = ast_variable_retrieve ( cfg , category , match - > matchfield ) ) ) {
ast_log ( LOG_ERROR , " Required match field '%s' not found \n " , match - > matchfield ) ;
return NULL ;
}
if ( match - > matchfunc ) {
if ( ! match - > matchfunc ( val ) ) {
continue ;
}
} else if ( strcasecmp ( val , match - > matchvalue ) ) {
continue ;
}
}
/* If we get this far, we're a match */
break ;
}
return match ;
}
static int is_preload ( struct aco_file * file , const char * cat )
{
int i ;
if ( ! file - > preload ) {
return 0 ;
}
for ( i = 0 ; ! ast_strlen_zero ( file - > preload [ i ] ) ; i + + ) {
if ( ! strcasecmp ( cat , file - > preload [ i ] ) ) {
return 1 ;
}
}
return 0 ;
}
static int process_category ( struct ast_config * cfg , struct aco_info * info , struct aco_file * file , const char * cat , int preload ) {
RAII_VAR ( void * , new_item , NULL , ao2_cleanup ) ;
struct aco_type * type ;
/* For global types, field is the global option struct. For non-global, it is the container for items.
* We do not grab a reference to these objects , as the info already holds references to them . This
* pointer is just a convenience . Do not actually store it somewhere . */
void * * field ;
/* Skip preloaded categories if we aren't preloading */
if ( ! preload & & is_preload ( file , cat ) ) {
return 0 ;
}
/* Find aco_type by category, if not found it is an error */
if ( ! ( type = internal_aco_type_find ( file , cfg , cat ) ) ) {
ast_log ( LOG_ERROR , " Could not find config type for category '%s' in '%s' \n " , cat , file - > filename ) ;
return - 1 ;
}
field = info - > internal - > pending + type - > item_offset ;
if ( ! * field ) {
ast_log ( LOG_ERROR , " No object to update! \n " ) ;
return - 1 ;
}
if ( type - > type = = ACO_GLOBAL & & * field ) {
if ( aco_set_defaults ( type , cat , * field ) ) {
ast_log ( LOG_ERROR , " In %s: Setting defaults for %s failed \n " , file - > filename , cat ) ;
return - 1 ;
}
if ( aco_process_category_options ( type , cfg , cat , * field ) ) {
ast_log ( LOG_ERROR , " In %s: Processing options for %s failed \n " , file - > filename , cat ) ;
return - 1 ;
}
} else if ( type - > type = = ACO_ITEM ) {
int new = 0 ;
/* If we have multiple definitions of a category in a file, or can set the values from multiple
* files , look up the entry if we ' ve already added it so we can merge the values together .
* Otherwise , alloc a new item . */
if ( * field ) {
if ( ! ( new_item = type - > item_find ( * field , cat ) ) ) {
if ( ! ( new_item = type - > item_alloc ( cat ) ) ) {
ast_log ( LOG_ERROR , " In %s: Could not create item for %s \n " , file - > filename , cat ) ;
return - 1 ;
}
if ( aco_set_defaults ( type , cat , new_item ) ) {
ast_log ( LOG_ERROR , " In %s: Setting defaults for %s failed \n " , file - > filename , cat ) ;
return - 1 ;
}
new = 1 ;
}
}
if ( type - > item_pre_process & & type - > item_pre_process ( new_item ) ) {
ast_log ( LOG_ERROR , " In %s: Preprocess callback for %s failed \n " , file - > filename , cat ) ;
return - 1 ;
}
if ( aco_process_category_options ( type , cfg , cat , new_item ) ) {
ast_log ( LOG_ERROR , " In %s: Processing options for %s failed \n " , file - > filename , cat ) ;
return - 1 ;
}
if ( type - > item_prelink & & type - > item_prelink ( new_item ) ) {
ast_log ( LOG_ERROR , " In %s: Pre-link callback for %s failed \n " , file - > filename , cat ) ;
return - 1 ;
}
if ( new & & ! ao2_link ( * field , new_item ) ) {
ast_log ( LOG_ERROR , " In %s: Linking config for %s failed \n " , file - > filename , cat ) ;
return - 1 ;
}
}
return 0 ;
}
static int apply_config ( struct aco_info * info )
{
ao2_global_obj_replace_unref ( * info - > global_obj , info - > internal - > pending ) ;
return 0 ;
}
2012-06-07 20:32:07 +00:00
static enum aco_process_status internal_process_ast_config ( struct aco_info * info , struct aco_file * file , struct ast_config * cfg )
2012-06-01 16:33:25 +00:00
{
const char * cat = NULL ;
if ( file - > preload ) {
int i ;
for ( i = 0 ; ! ast_strlen_zero ( file - > preload [ i ] ) ; i + + ) {
if ( process_category ( cfg , info , file , file - > preload [ i ] , 1 ) ) {
2012-06-07 20:32:07 +00:00
return ACO_PROCESS_ERROR ;
2012-06-01 16:33:25 +00:00
}
}
}
while ( ( cat = ast_category_browse ( cfg , cat ) ) ) {
if ( process_category ( cfg , info , file , cat , 0 ) ) {
2012-06-07 20:32:07 +00:00
return ACO_PROCESS_ERROR ;
2012-06-01 16:33:25 +00:00
}
}
2012-06-07 20:32:07 +00:00
return ACO_PROCESS_OK ;
2012-06-01 16:33:25 +00:00
}
2012-06-07 20:32:07 +00:00
enum aco_process_status aco_process_ast_config ( struct aco_info * info , struct aco_file * file , struct ast_config * cfg )
2012-06-01 16:33:25 +00:00
{
if ( ! ( info - > internal - > pending = info - > snapshot_alloc ( ) ) ) {
ast_log ( LOG_ERROR , " In %s: Could not allocate temporary objects \n " , file - > filename ) ;
goto error ;
}
if ( internal_process_ast_config ( info , file , cfg ) ) {
goto error ;
}
if ( info - > pre_apply_config & & info - > pre_apply_config ( ) ) {
goto error ;
}
if ( apply_config ( info ) ) {
goto error ;
} ;
ao2_cleanup ( info - > internal - > pending ) ;
2012-06-07 20:32:07 +00:00
return ACO_PROCESS_OK ;
2012-06-01 16:33:25 +00:00
error :
ao2_cleanup ( info - > internal - > pending ) ;
2012-06-07 20:32:07 +00:00
return ACO_PROCESS_ERROR ;
2012-06-01 16:33:25 +00:00
}
2012-06-07 20:32:07 +00:00
enum aco_process_status aco_process_config ( struct aco_info * info , int reload )
2012-06-01 16:33:25 +00:00
{
struct ast_config * cfg ;
struct ast_flags cfg_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 , } ;
2012-06-07 20:32:07 +00:00
int res = ACO_PROCESS_OK , x = 0 ;
2012-06-01 16:33:25 +00:00
struct aco_file * file ;
if ( ! ( info - > files [ 0 ] ) ) {
ast_log ( LOG_ERROR , " No filename given, cannot proceed! \n " ) ;
2012-06-07 20:32:07 +00:00
return ACO_PROCESS_ERROR ;
2012-06-01 16:33:25 +00:00
}
if ( ! ( info - > internal - > pending = info - > snapshot_alloc ( ) ) ) {
ast_log ( LOG_ERROR , " In %s: Could not allocate temporary objects \n " , info - > module ) ;
2012-06-07 20:32:07 +00:00
return ACO_PROCESS_ERROR ;
2012-06-01 16:33:25 +00:00
}
2012-06-07 20:32:07 +00:00
while ( res ! = ACO_PROCESS_ERROR & & ( file = info - > files [ x + + ] ) ) {
2012-06-14 13:35:07 +00:00
const char * filename = file - > filename ;
try_alias :
if ( ! ( cfg = ast_config_load ( filename , cfg_flags ) ) ) {
if ( file - > alias & & strcmp ( file - > alias , filename ) ) {
filename = file - > alias ;
goto try_alias ;
}
2012-06-01 16:33:25 +00:00
ast_log ( LOG_ERROR , " Unable to load config file '%s' \n " , file - > filename ) ;
2012-06-07 20:32:07 +00:00
res = ACO_PROCESS_ERROR ;
2012-06-01 16:33:25 +00:00
break ;
} else if ( cfg = = CONFIG_STATUS_FILEUNCHANGED ) {
ast_debug ( 1 , " %s was unchanged \n " , file - > filename ) ;
2012-06-07 20:32:07 +00:00
res = ACO_PROCESS_UNCHANGED ;
2012-06-01 16:33:25 +00:00
continue ;
} else if ( cfg = = CONFIG_STATUS_FILEINVALID ) {
ast_log ( LOG_ERROR , " Contents of %s are invalid and cannot be parsed \n " , file - > filename ) ;
2012-06-07 20:32:07 +00:00
res = ACO_PROCESS_ERROR ;
2012-06-01 16:33:25 +00:00
break ;
} else if ( cfg = = CONFIG_STATUS_FILEMISSING ) {
2012-06-14 13:35:07 +00:00
if ( file - > alias & & strcmp ( file - > alias , filename ) ) {
filename = file - > alias ;
goto try_alias ;
}
2012-06-01 16:33:25 +00:00
ast_log ( LOG_ERROR , " %s is missing! Cannot load %s \n " , file - > filename , info - > module ) ;
2012-06-07 20:32:07 +00:00
res = ACO_PROCESS_ERROR ;
2012-06-01 16:33:25 +00:00
break ;
}
res = internal_process_ast_config ( info , file , cfg ) ;
ast_config_destroy ( cfg ) ;
}
2012-06-07 20:32:07 +00:00
if ( res ! = ACO_PROCESS_OK ) {
goto end ;
}
if ( info - > pre_apply_config & & ( info - > pre_apply_config ( ) ) ) {
res = ACO_PROCESS_ERROR ;
goto end ;
}
if ( apply_config ( info ) ) {
res = ACO_PROCESS_ERROR ;
goto end ;
}
2012-06-01 16:33:25 +00:00
2012-06-14 13:41:47 +00:00
if ( info - > post_apply_config ) {
info - > post_apply_config ( ) ;
}
2012-06-07 20:32:07 +00:00
end :
2012-06-01 16:33:25 +00:00
ao2_cleanup ( info - > internal - > pending ) ;
return res ;
}
int aco_process_category_options ( struct aco_type * type , struct ast_config * cfg , const char * cat , void * obj )
{
struct ast_variable * var ;
for ( var = ast_variable_browse ( cfg , cat ) ; var ; var = var - > next ) {
RAII_VAR ( struct aco_option * , opt , aco_option_find ( type , var - > name ) , ao2_cleanup ) ;
2012-07-12 21:43:09 +00:00
if ( opt & & opt - > deprecated & & ! ast_strlen_zero ( opt - > aliased_to ) ) {
const char * alias = ast_strdupa ( opt - > aliased_to ) ;
ast_log ( LOG_WARNING , " At line %d of %s option '%s' is deprecated. Use '%s' instead \n " , var - > lineno , var - > file , var - > name , alias ) ;
ao2_ref ( opt , - 1 ) ;
opt = aco_option_find ( type , alias ) ;
}
2012-06-01 16:33:25 +00:00
if ( ! opt ) {
ast_log ( LOG_ERROR , " Could not find option suitable for category '%s' named '%s' at line %d of %s \n " , cat , var - > name , var - > lineno , var - > file ) ;
return - 1 ;
}
2012-07-12 21:43:09 +00:00
2012-06-01 16:33:25 +00:00
if ( ! opt - > handler ) {
/* It should be impossible for an option to not have a handler */
ast_log ( LOG_ERROR , " BUG! Somehow a config option for %s/%s was created with no handler! \n " , cat , var - > name ) ;
return - 1 ;
}
if ( opt - > handler ( opt , var , obj ) ) {
ast_log ( LOG_ERROR , " Error parsing %s=%s at line %d of %s \n " , var - > name , var - > value , var - > lineno , var - > file ) ;
return - 1 ;
}
}
return 0 ;
}
static void internal_type_destroy ( struct aco_type * type )
{
if ( type - > internal - > regex ) {
regfree ( type - > internal - > regex ) ;
ast_free ( type - > internal - > regex ) ;
}
ao2_cleanup ( type - > internal - > opts ) ;
type - > internal - > opts = NULL ;
ast_free ( type - > internal ) ;
type - > internal = NULL ;
}
static void internal_file_types_destroy ( struct aco_file * file )
{
size_t x ;
struct aco_type * t ;
for ( x = 0 , t = file - > types [ x ] ; t ; t = file - > types [ + + x ] ) {
internal_type_destroy ( t ) ;
t = NULL ;
}
}
static int internal_type_init ( struct aco_type * type )
{
if ( ! ( type - > internal = ast_calloc ( 1 , sizeof ( * type - > internal ) ) ) ) {
return - 1 ;
}
if ( ! ( type - > internal - > regex = build_regex ( type - > category ) ) ) {
internal_type_destroy ( type ) ;
}
if ( ! ( type - > internal - > opts = aco_option_container_alloc ( ) ) ) {
internal_type_destroy ( type ) ;
}
return 0 ;
}
int aco_info_init ( struct aco_info * info )
{
size_t x , y ;
if ( ! ( info - > internal = ast_calloc ( 1 , sizeof ( * info - > internal ) ) ) ) {
return - 1 ;
}
for ( x = 0 ; info - > files [ x ] ; x + + ) {
for ( y = 0 ; info - > files [ x ] - > types [ y ] ; y + + ) {
if ( internal_type_init ( info - > files [ x ] - > types [ y ] ) ) {
goto error ;
}
}
}
return 0 ;
error :
aco_info_destroy ( info ) ;
return - 1 ;
}
void aco_info_destroy ( struct aco_info * info )
{
int x ;
/* It shouldn't be possible for internal->pending to be in use when this is called because
* of the locks in loader . c around reloads and unloads and the fact that internal - > pending
* only exists while those locks are held */
ast_free ( info - > internal ) ;
info - > internal = NULL ;
for ( x = 0 ; info - > files [ x ] ; x + + ) {
internal_file_types_destroy ( info - > files [ x ] ) ;
}
}
int aco_set_defaults ( struct aco_type * type , const char * category , void * obj )
{
struct aco_option * opt ;
struct ao2_iterator iter ;
iter = ao2_iterator_init ( type - > internal - > opts , 0 ) ;
while ( ( opt = ao2_iterator_next ( & iter ) ) ) {
RAII_VAR ( struct ast_variable * , var , NULL , ast_variables_destroy ) ;
if ( ast_strlen_zero ( opt - > default_val ) ) {
ao2_ref ( opt , - 1 ) ;
continue ;
}
if ( ! ( var = ast_variable_new ( opt - > name , opt - > default_val , " " ) ) ) {
ao2_ref ( opt , - 1 ) ;
ao2_iterator_destroy ( & iter ) ;
return - 1 ;
}
if ( opt - > handler ( opt , var , obj ) ) {
ast_log ( LOG_ERROR , " Unable to set default for %s, %s=%s \n " , category , var - > name , var - > value ) ;
ao2_ref ( opt , - 1 ) ;
ao2_iterator_destroy ( & iter ) ;
return - 1 ;
}
ao2_ref ( opt , - 1 ) ;
}
ao2_iterator_destroy ( & iter ) ;
return 0 ;
}
2012-06-07 15:43:37 +00:00
/* Default config option handlers */
/*! \brief Default option handler for signed integers
* \ note For a description of the opt - > flags and opt - > args values , see the documentation for
* enum aco_option_type in config_options . h
*/
2012-06-01 16:33:25 +00:00
static int int_handler_fn ( const struct aco_option * opt , struct ast_variable * var , void * obj ) {
int * field = ( int * ) ( obj + opt - > args [ 0 ] ) ;
unsigned int flags = PARSE_INT32 | opt - > flags ;
int res = 0 ;
if ( opt - > flags & PARSE_IN_RANGE ) {
res = opt - > flags & PARSE_DEFAULT ?
ast_parse_arg ( var - > value , flags , field , ( int ) opt - > args [ 1 ] , ( int ) opt - > args [ 2 ] , opt - > args [ 3 ] ) :
ast_parse_arg ( var - > value , flags , field , ( int ) opt - > args [ 1 ] , ( int ) opt - > args [ 2 ] ) ;
if ( res ) {
if ( opt - > flags & PARSE_RANGE_DEFAULTS ) {
ast_log ( LOG_WARNING , " Failed to set %s=%s. Set to %d instead due to range limit (%d, %d) \n " , var - > name , var - > value , * field , ( int ) opt - > args [ 1 ] , ( int ) opt - > args [ 2 ] ) ;
res = 0 ;
} else if ( opt - > flags & PARSE_DEFAULT ) {
ast_log ( LOG_WARNING , " Failed to set %s=%s, Set to default value %d instead. \n " , var - > name , var - > value , * field ) ;
res = 0 ;
}
}
} else if ( ( opt - > flags & PARSE_DEFAULT ) & & ast_parse_arg ( var - > value , flags , field , ( int ) opt - > args [ 1 ] ) ) {
ast_log ( LOG_WARNING , " Attempted to set %s=%s, but set it to %d instead due to default) \n " , var - > name , var - > value , * field ) ;
} else {
res = ast_parse_arg ( var - > value , flags , field ) ;
}
return res ;
}
2012-06-07 15:43:37 +00:00
/*! \brief Default option handler for unsigned integers
* \ note For a description of the opt - > flags and opt - > args values , see the documentation for
* enum aco_option_type in config_options . h
*/
2012-06-01 16:33:25 +00:00
static int uint_handler_fn ( const struct aco_option * opt , struct ast_variable * var , void * obj ) {
unsigned int * field = ( unsigned int * ) ( obj + opt - > args [ 0 ] ) ;
unsigned int flags = PARSE_INT32 | opt - > flags ;
int res = 0 ;
if ( opt - > flags & PARSE_IN_RANGE ) {
res = opt - > flags & PARSE_DEFAULT ?
ast_parse_arg ( var - > value , flags , field , ( unsigned int ) opt - > args [ 1 ] , ( unsigned int ) opt - > args [ 2 ] , opt - > args [ 3 ] ) :
ast_parse_arg ( var - > value , flags , field , ( unsigned int ) opt - > args [ 1 ] , ( unsigned int ) opt - > args [ 2 ] ) ;
if ( res ) {
if ( opt - > flags & PARSE_RANGE_DEFAULTS ) {
ast_log ( LOG_WARNING , " Failed to set %s=%s. Set to %d instead due to range limit (%d, %d) \n " , var - > name , var - > value , * field , ( int ) opt - > args [ 1 ] , ( int ) opt - > args [ 2 ] ) ;
res = 0 ;
} else if ( opt - > flags & PARSE_DEFAULT ) {
ast_log ( LOG_WARNING , " Failed to set %s=%s, Set to default value %d instead. \n " , var - > name , var - > value , * field ) ;
res = 0 ;
}
}
} else if ( ( opt - > flags & PARSE_DEFAULT ) & & ast_parse_arg ( var - > value , flags , field , ( unsigned int ) opt - > args [ 1 ] ) ) {
ast_log ( LOG_WARNING , " Attempted to set %s=%s, but set it to %u instead due to default) \n " , var - > name , var - > value , * field ) ;
} else {
res = ast_parse_arg ( var - > value , flags , field ) ;
}
return res ;
}
2012-06-07 15:43:37 +00:00
/*! \brief Default option handler for doubles
* \ note For a description of the opt - > flags and opt - > args values , see the documentation for
* enum aco_option_type in config_options . h
*/
2012-06-01 16:33:25 +00:00
static int double_handler_fn ( const struct aco_option * opt , struct ast_variable * var , void * obj ) {
double * field = ( double * ) ( obj + opt - > args [ 0 ] ) ;
return ast_parse_arg ( var - > value , PARSE_DOUBLE | opt - > flags , field ) ;
}
2012-06-07 15:43:37 +00:00
/*! \brief Default handler for ACLs
* \ note For a description of the opt - > flags and opt - > args values , see the documentation for
* enum aco_option_type in config_options . h
*/
2012-06-01 16:33:25 +00:00
static int acl_handler_fn ( const struct aco_option * opt , struct ast_variable * var , void * obj ) {
struct ast_ha * * ha = ( struct ast_ha * * ) ( obj + opt - > args [ 0 ] ) ;
int error = 0 ;
2012-06-07 15:43:37 +00:00
* ha = ast_append_ha ( opt - > flags ? " permit " : " deny " , var - > value , * ha , & error ) ;
2012-06-01 16:33:25 +00:00
return error ;
}
2012-06-07 15:43:37 +00:00
/*! \brief Default option handler for codec preferences/capabilities
* \ note For a description of the opt - > flags and opt - > args values , see the documentation for
* enum aco_option_type in config_options . h
*/
2012-06-01 16:33:25 +00:00
static int codec_handler_fn ( const struct aco_option * opt , struct ast_variable * var , void * obj ) {
struct ast_codec_pref * pref = ( struct ast_codec_pref * ) ( obj + opt - > args [ 0 ] ) ;
struct ast_format_cap * * cap = ( struct ast_format_cap * * ) ( obj + opt - > args [ 1 ] ) ;
return ast_parse_allow_disallow ( pref , * cap , var - > value , opt - > flags ) ;
}
2012-06-07 15:43:37 +00:00
/*! \brief Default option handler for stringfields
* \ note For a description of the opt - > flags and opt - > args values , see the documentation for
* enum aco_option_type in config_options . h
*/
2012-06-01 16:33:25 +00:00
static int stringfield_handler_fn ( const struct aco_option * opt , struct ast_variable * var , void * obj )
{
ast_string_field * field = ( const char * * ) ( obj + opt - > args [ 0 ] ) ;
struct ast_string_field_pool * * pool = ( struct ast_string_field_pool * * ) ( obj + opt - > args [ 1 ] ) ;
struct ast_string_field_mgr * mgr = ( struct ast_string_field_mgr * ) ( obj + opt - > args [ 2 ] ) ;
ast_string_field_ptr_set_by_fields ( * pool , * mgr , field , var - > value ) ;
return 0 ;
}
2012-06-07 15:43:37 +00:00
/*! \brief Default option handler for bools (ast_true/ast_false)
* \ note For a description of the opt - > flags and opt - > args values , see the documentation for
* enum aco_option_type in config_options . h
*/
2012-06-01 16:33:25 +00:00
static int bool_handler_fn ( const struct aco_option * opt , struct ast_variable * var , void * obj )
{
unsigned int * field = ( unsigned int * ) ( obj + opt - > args [ 0 ] ) ;
* field = opt - > flags ? ast_true ( var - > value ) : ast_false ( var - > value ) ;
return 0 ;
}
2012-06-28 01:12:06 +00:00
/*! \brief Default option handler for bools (ast_true/ast_false) that are stored as flags
* \ note For a description of the opt - > flags and opt - > args values , see the documentation for
* enum aco_option_type in config_options . h
*/
static int boolflag_handler_fn ( const struct aco_option * opt , struct ast_variable * var , void * obj )
{
unsigned int * flags_field = ( unsigned int * ) ( obj + opt - > args [ 0 ] ) ;
unsigned int val = opt - > flags ? ast_true ( var - > value ) : ast_false ( var - > value ) ;
unsigned int flag = opt - > args [ 1 ] ;
if ( val ) {
* flags_field | = flag ;
} else {
* flags_field & = ~ flag ;
}
return 0 ;
}
2012-06-07 15:43:37 +00:00
/*! \brief Default handler for ast_sockaddrs
* \ note For a description of the opt - > flags and opt - > args values , see the documentation for
* enum aco_option_type in config_options . h
*/
2012-06-01 16:33:25 +00:00
static int sockaddr_handler_fn ( const struct aco_option * opt , struct ast_variable * var , void * obj )
{
struct ast_sockaddr * field = ( struct ast_sockaddr * ) ( obj + opt - > args [ 0 ] ) ;
return ast_parse_arg ( var - > value , PARSE_ADDR | opt - > flags , field ) ;
}