@ -1277,7 +1277,7 @@ static struct ast_call_feature builtin_features[] =
} ;
} ;
static AST_ LIST_HEAD_STATIC( feature_list , ast_call_feature ) ;
static AST_ RW LIST_HEAD_STATIC( feature_list , ast_call_feature ) ;
/*! \brief register new feature into feature_list*/
/*! \brief register new feature into feature_list*/
void ast_register_feature ( struct ast_call_feature * feature )
void ast_register_feature ( struct ast_call_feature * feature )
@ -1287,9 +1287,9 @@ void ast_register_feature(struct ast_call_feature *feature)
return ;
return ;
}
}
AST_ LIST_LOCK( & feature_list ) ;
AST_ RW LIST_WR LOCK( & feature_list ) ;
AST_ LIST_INSERT_HEAD( & feature_list , feature , feature_entry ) ;
AST_ RW LIST_INSERT_HEAD( & feature_list , feature , feature_entry ) ;
AST_ LIST_UNLOCK( & feature_list ) ;
AST_ RW LIST_UNLOCK( & feature_list ) ;
ast_verb ( 2 , " Registered Feature '%s' \n " , feature - > sname ) ;
ast_verb ( 2 , " Registered Feature '%s' \n " , feature - > sname ) ;
}
}
@ -1370,12 +1370,14 @@ static void register_group_feature(struct feature_group *fg, const char *exten,
void ast_unregister_feature ( struct ast_call_feature * feature )
void ast_unregister_feature ( struct ast_call_feature * feature )
{
{
if ( ! feature )
if ( ! feature ) {
return ;
return ;
}
AST_RWLIST_WRLOCK ( & feature_list ) ;
AST_RWLIST_REMOVE ( & feature_list , feature , feature_entry ) ;
AST_RWLIST_UNLOCK ( & feature_list ) ;
AST_LIST_LOCK ( & feature_list ) ;
AST_LIST_REMOVE ( & feature_list , feature , feature_entry ) ;
AST_LIST_UNLOCK ( & feature_list ) ;
ast_free ( feature ) ;
ast_free ( feature ) ;
}
}
@ -1384,10 +1386,11 @@ static void ast_unregister_features(void)
{
{
struct ast_call_feature * feature ;
struct ast_call_feature * feature ;
AST_ LIST_LOCK( & feature_list ) ;
AST_ RW LIST_WR LOCK( & feature_list ) ;
while ( ( feature = AST_ LIST_REMOVE_HEAD( & feature_list , feature_entry ) ) )
while ( ( feature = AST_ RW LIST_REMOVE_HEAD( & feature_list , feature_entry ) ) ) {
ast_free ( feature ) ;
ast_free ( feature ) ;
AST_LIST_UNLOCK ( & feature_list ) ;
}
AST_RWLIST_UNLOCK ( & feature_list ) ;
}
}
/*! \brief find a call feature by name */
/*! \brief find a call feature by name */
@ -1395,10 +1398,11 @@ static struct ast_call_feature *find_dynamic_feature(const char *name)
{
{
struct ast_call_feature * tmp ;
struct ast_call_feature * tmp ;
AST_ LIST_TRAVERSE( & feature_list , tmp , feature_entry ) {
AST_ RW LIST_TRAVERSE( & feature_list , tmp , feature_entry ) {
if ( ! strcasecmp ( tmp - > sname , name ) )
if ( ! strcasecmp ( tmp - > sname , name ) ) {
break ;
break ;
}
}
}
return tmp ;
return tmp ;
}
}
@ -1636,10 +1640,11 @@ static int ast_feature_interpret(struct ast_channel *chan, struct ast_channel *p
}
}
AST_RWLIST_UNLOCK ( & feature_groups ) ;
AST_RWLIST_UNLOCK ( & feature_groups ) ;
AST_LIST_LOCK ( & feature_list ) ;
AST_RWLIST_RDLOCK ( & feature_list ) ;
if ( ! ( feature = find_dynamic_feature ( tok ) ) ) {
if ( ! ( feature = find_dynamic_feature ( tok ) ) ) {
AST_ LIST_UNLOCK( & feature_list ) ;
AST_ RW LIST_UNLOCK( & feature_list ) ;
continue ;
continue ;
}
}
@ -1648,14 +1653,14 @@ static int ast_feature_interpret(struct ast_channel *chan, struct ast_channel *p
ast_verb ( 3 , " Feature Found: %s exten: %s \n " , feature - > sname , tok ) ;
ast_verb ( 3 , " Feature Found: %s exten: %s \n " , feature - > sname , tok ) ;
res = feature - > operation ( chan , peer , config , code , sense , feature ) ;
res = feature - > operation ( chan , peer , config , code , sense , feature ) ;
if ( res ! = FEATURE_RETURN_KEEPTRYING ) {
if ( res ! = FEATURE_RETURN_KEEPTRYING ) {
AST_ LIST_UNLOCK( & feature_list ) ;
AST_ RW LIST_UNLOCK( & feature_list ) ;
break ;
break ;
}
}
res = FEATURE_RETURN_PASSDIGITS ;
res = FEATURE_RETURN_PASSDIGITS ;
} else if ( ! strncmp ( feature - > exten , code , strlen ( code ) ) )
} else if ( ! strncmp ( feature - > exten , code , strlen ( code ) ) )
res = FEATURE_RETURN_STOREDIGITS ;
res = FEATURE_RETURN_STOREDIGITS ;
AST_ LIST_UNLOCK( & feature_list ) ;
AST_ RW LIST_UNLOCK( & feature_list ) ;
}
}
return res ;
return res ;
@ -1690,14 +1695,14 @@ static void set_config_flags(struct ast_channel *chan, struct ast_channel *peer,
/* while we have a feature */
/* while we have a feature */
while ( ( tok = strsep ( & tmp , " # " ) ) ) {
while ( ( tok = strsep ( & tmp , " # " ) ) ) {
AST_ LIST_LOCK( & feature_list ) ;
AST_ RW LIST_RD LOCK( & feature_list ) ;
if ( ( feature = find_dynamic_feature ( tok ) ) & & ast_test_flag ( feature , AST_FEATURE_FLAG_NEEDSDTMF ) ) {
if ( ( feature = find_dynamic_feature ( tok ) ) & & ast_test_flag ( feature , AST_FEATURE_FLAG_NEEDSDTMF ) ) {
if ( ast_test_flag ( feature , AST_FEATURE_FLAG_BYCALLER ) )
if ( ast_test_flag ( feature , AST_FEATURE_FLAG_BYCALLER ) )
ast_set_flag ( config , AST_BRIDGE_DTMF_CHANNEL_0 ) ;
ast_set_flag ( config , AST_BRIDGE_DTMF_CHANNEL_0 ) ;
if ( ast_test_flag ( feature , AST_FEATURE_FLAG_BYCALLEE ) )
if ( ast_test_flag ( feature , AST_FEATURE_FLAG_BYCALLEE ) )
ast_set_flag ( config , AST_BRIDGE_DTMF_CHANNEL_1 ) ;
ast_set_flag ( config , AST_BRIDGE_DTMF_CHANNEL_1 ) ;
}
}
AST_ LIST_UNLOCK( & feature_list ) ;
AST_ RW LIST_UNLOCK( & feature_list ) ;
}
}
}
}
}
}
@ -2873,13 +2878,13 @@ static int load_config(void)
continue ;
continue ;
}
}
AST_ LIST_LOCK( & feature_list ) ;
AST_ RW LIST_RD LOCK( & feature_list ) ;
if ( ( feature = find_dynamic_feature ( var - > name ) ) ) {
if ( ( feature = find_dynamic_feature ( var - > name ) ) ) {
AST_ LIST_UNLOCK( & feature_list ) ;
AST_ RW LIST_UNLOCK( & feature_list ) ;
ast_log ( LOG_WARNING , " Dynamic Feature '%s' specified more than once! \n " , var - > name ) ;
ast_log ( LOG_WARNING , " Dynamic Feature '%s' specified more than once! \n " , var - > name ) ;
continue ;
continue ;
}
}
AST_ LIST_UNLOCK( & feature_list ) ;
AST_ RW LIST_UNLOCK( & feature_list ) ;
if ( ! ( feature = ast_calloc ( 1 , sizeof ( * feature ) ) ) )
if ( ! ( feature = ast_calloc ( 1 , sizeof ( * feature ) ) ) )
continue ;
continue ;
@ -2947,14 +2952,14 @@ static int load_config(void)
for ( var = ast_variable_browse ( cfg , ctg ) ; var ; var = var - > next ) {
for ( var = ast_variable_browse ( cfg , ctg ) ; var ; var = var - > next ) {
struct ast_call_feature * feature ;
struct ast_call_feature * feature ;
AST_ LIST_LOCK( & feature_list ) ;
AST_ RW LIST_RD LOCK( & feature_list ) ;
if ( ! ( feature = find_dynamic_feature ( var - > name ) ) & &
if ( ! ( feature = find_dynamic_feature ( var - > name ) ) & &
! ( feature = ast_find_call_feature ( var - > name ) ) ) {
! ( feature = ast_find_call_feature ( var - > name ) ) ) {
AST_ LIST_UNLOCK( & feature_list ) ;
AST_ RW LIST_UNLOCK( & feature_list ) ;
ast_log ( LOG_WARNING , " Feature '%s' was not found. \n " , var - > name ) ;
ast_log ( LOG_WARNING , " Feature '%s' was not found. \n " , var - > name ) ;
continue ;
continue ;
}
}
AST_ LIST_UNLOCK( & feature_list ) ;
AST_ RW LIST_UNLOCK( & feature_list ) ;
register_group_feature ( fg , var - > value , feature ) ;
register_group_feature ( fg , var - > value , feature ) ;
}
}
@ -3024,13 +3029,14 @@ static char *handle_feature_show(struct ast_cli_entry *e, int cmd, struct ast_cl
ast_cli ( a - > fd , " \n " ) ;
ast_cli ( a - > fd , " \n " ) ;
ast_cli ( a - > fd , HFS_FORMAT , " Dynamic Feature " , " Default " , " Current " ) ;
ast_cli ( a - > fd , HFS_FORMAT , " Dynamic Feature " , " Default " , " Current " ) ;
ast_cli ( a - > fd , HFS_FORMAT , " --------------- " , " ------- " , " ------- " ) ;
ast_cli ( a - > fd , HFS_FORMAT , " --------------- " , " ------- " , " ------- " ) ;
if ( AST_ LIST_EMPTY( & feature_list ) )
if ( AST_ RW LIST_EMPTY( & feature_list ) ) {
ast_cli ( a - > fd , " (none) \n " ) ;
ast_cli ( a - > fd , " (none) \n " ) ;
else {
} else {
AST_ LIST_LOCK( & feature_list ) ;
AST_ RW LIST_RD LOCK( & feature_list ) ;
AST_ LIST_TRAVERSE( & feature_list , feature , feature_entry )
AST_ RW LIST_TRAVERSE( & feature_list , feature , feature_entry ) {
ast_cli ( a - > fd , HFS_FORMAT , feature - > sname , " no def " , feature - > exten ) ;
ast_cli ( a - > fd , HFS_FORMAT , feature - > sname , " no def " , feature - > exten ) ;
AST_LIST_UNLOCK ( & feature_list ) ;
}
AST_RWLIST_UNLOCK ( & feature_list ) ;
}
}
ast_cli ( a - > fd , " \n Call parking \n " ) ;
ast_cli ( a - > fd , " \n Call parking \n " ) ;
ast_cli ( a - > fd , " ------------ \n " ) ;
ast_cli ( a - > fd , " ------------ \n " ) ;