Fix a crash on reload by using calloc() instead of malloc() to ensure that
data is properly initialized. (issue #9765, reported by MatsK, patch from eliel) git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@66724 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
parent
0b2db74e5a
commit
8ea9dcc221
|
@ -2301,7 +2301,7 @@ static int timezone_add(char *zonename, char *config)
|
||||||
struct minivm_zone *newzone;
|
struct minivm_zone *newzone;
|
||||||
char *msg_format, *timezone;
|
char *msg_format, *timezone;
|
||||||
|
|
||||||
newzone = malloc(sizeof(struct minivm_zone));
|
newzone = ast_calloc(1, sizeof(struct minivm_zone));
|
||||||
if (newzone == NULL)
|
if (newzone == NULL)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
|
|
@ -100,3 +100,20 @@ context => parkedcalls ; Which context parked calls are in
|
||||||
;unpauseMonitor => #3,self/callee,UnPauseMonitor ;Allow the callee to unpause monitoring
|
;unpauseMonitor => #3,self/callee,UnPauseMonitor ;Allow the callee to unpause monitoring
|
||||||
; ;on their channel
|
; ;on their channel
|
||||||
;
|
;
|
||||||
|
; GROUPS
|
||||||
|
; Groups are groupings of features defined in [applicationmap]
|
||||||
|
; that can have their own key mappings.
|
||||||
|
;
|
||||||
|
; Groups are defined as a configuration section,
|
||||||
|
; and can be set as part of DYNAMIC_FEATURES in
|
||||||
|
; the same way that a normal feature can...
|
||||||
|
; etc:
|
||||||
|
;
|
||||||
|
; Set(DYNAMIC_FEATURES=myGroupName);
|
||||||
|
;
|
||||||
|
; example:
|
||||||
|
; [myGroupName] ; defines the group named myGroupName
|
||||||
|
; testfeature => #9 ; associates testfeature with the group and the keycode #9
|
||||||
|
; pauseMonitor ; associates pauseMonitor with the group and the keycode
|
||||||
|
; ; defined in [applicationmap]
|
||||||
|
|
||||||
|
|
|
@ -78,6 +78,20 @@ enum {
|
||||||
AST_FEATURE_FLAG_BYBOTH = (3 << 3),
|
AST_FEATURE_FLAG_BYBOTH = (3 << 3),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct feature_group_exten {
|
||||||
|
AST_LIST_ENTRY(feature_group_exten) entry;
|
||||||
|
char exten[FEATURE_MAX_LEN];
|
||||||
|
struct ast_call_feature *feature;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct feature_group {
|
||||||
|
AST_LIST_ENTRY(feature_group) entry;
|
||||||
|
char gname[80];
|
||||||
|
AST_LIST_HEAD_NOLOCK(, feature_group_exten) features;
|
||||||
|
};
|
||||||
|
|
||||||
|
static AST_RWLIST_HEAD_STATIC(feature_groups, feature_group);
|
||||||
|
|
||||||
static char *parkedcall = "ParkedCall";
|
static char *parkedcall = "ParkedCall";
|
||||||
|
|
||||||
static int parkaddhints = 0; /*!< Add parking hints automatically */
|
static int parkaddhints = 0; /*!< Add parking hints automatically */
|
||||||
|
@ -1010,7 +1024,7 @@ static int builtin_atxfer(struct ast_channel *chan, struct ast_channel *peer, st
|
||||||
AST_RWLOCK_DEFINE_STATIC(features_lock);
|
AST_RWLOCK_DEFINE_STATIC(features_lock);
|
||||||
|
|
||||||
static struct ast_call_feature builtin_features[] =
|
static struct ast_call_feature builtin_features[] =
|
||||||
{
|
{
|
||||||
{ AST_FEATURE_REDIRECT, "Blind Transfer", "blindxfer", "#", "#", builtin_blindtransfer, AST_FEATURE_FLAG_NEEDSDTMF, "" },
|
{ AST_FEATURE_REDIRECT, "Blind Transfer", "blindxfer", "#", "#", builtin_blindtransfer, AST_FEATURE_FLAG_NEEDSDTMF, "" },
|
||||||
{ AST_FEATURE_REDIRECT, "Attended Transfer", "atxfer", "", "", builtin_atxfer, AST_FEATURE_FLAG_NEEDSDTMF, "" },
|
{ AST_FEATURE_REDIRECT, "Attended Transfer", "atxfer", "", "", builtin_atxfer, AST_FEATURE_FLAG_NEEDSDTMF, "" },
|
||||||
{ AST_FEATURE_AUTOMON, "One Touch Monitor", "automon", "", "", builtin_automonitor, AST_FEATURE_FLAG_NEEDSDTMF, "" },
|
{ AST_FEATURE_AUTOMON, "One Touch Monitor", "automon", "", "", builtin_automonitor, AST_FEATURE_FLAG_NEEDSDTMF, "" },
|
||||||
|
@ -1037,6 +1051,64 @@ void ast_register_feature(struct ast_call_feature *feature)
|
||||||
ast_verbose(VERBOSE_PREFIX_2 "Registered Feature '%s'\n",feature->sname);
|
ast_verbose(VERBOSE_PREFIX_2 "Registered Feature '%s'\n",feature->sname);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*! \brief This function must be called while feature_groups is locked... */
|
||||||
|
static struct feature_group* register_group(const char *fgname)
|
||||||
|
{
|
||||||
|
struct feature_group *fg;
|
||||||
|
|
||||||
|
if (!fgname) {
|
||||||
|
ast_log(LOG_NOTICE, "You didn't pass a new group name!\n");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
fg = ast_calloc(1, sizeof(*fg));
|
||||||
|
|
||||||
|
if (!fg) {
|
||||||
|
ast_log(LOG_ERROR, "Failed to allocate memory for group '%s'\n", fgname);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
ast_copy_string(fg->gname, fgname, sizeof(fg->gname));
|
||||||
|
|
||||||
|
AST_LIST_INSERT_HEAD(&feature_groups, fg, entry);
|
||||||
|
|
||||||
|
if (option_verbose >= 2)
|
||||||
|
ast_verbose(VERBOSE_PREFIX_2 "Registered group '%s'\n", fg->gname);
|
||||||
|
|
||||||
|
return fg;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! \brief This function must be called while feature_groups is locked... */
|
||||||
|
|
||||||
|
static void register_group_feature(struct feature_group *fg, const char *exten, struct ast_call_feature *feature)
|
||||||
|
{
|
||||||
|
struct feature_group_exten *fge;
|
||||||
|
|
||||||
|
fge = ast_calloc(1, sizeof(*fge));
|
||||||
|
|
||||||
|
if (!fge) return;
|
||||||
|
|
||||||
|
if (!fg) {
|
||||||
|
ast_log(LOG_NOTICE, "You didn't pass a group!\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!feature) {
|
||||||
|
ast_log(LOG_NOTICE, "You didn't pass a feature!\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ast_copy_string(fge->exten, (ast_strlen_zero(exten) ? feature->exten : exten), sizeof(fge->exten));
|
||||||
|
|
||||||
|
fge->feature = feature;
|
||||||
|
|
||||||
|
AST_LIST_INSERT_HEAD(&fg->features, fge, entry);
|
||||||
|
|
||||||
|
if (option_verbose >= 2)
|
||||||
|
ast_verbose(VERBOSE_PREFIX_2 "Registered feature '%s' for group '%s' at exten '%s'\n",
|
||||||
|
feature->sname, fg->gname, exten);
|
||||||
|
}
|
||||||
|
|
||||||
/*! \brief unregister feature from feature_list */
|
/*! \brief unregister feature from feature_list */
|
||||||
void ast_unregister_feature(struct ast_call_feature *feature)
|
void ast_unregister_feature(struct ast_call_feature *feature)
|
||||||
{
|
{
|
||||||
|
@ -1073,6 +1145,44 @@ static struct ast_call_feature *find_dynamic_feature(const char *name)
|
||||||
return tmp;
|
return tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*! \brief Remove all groups in the list */
|
||||||
|
static void ast_unregister_groups(void)
|
||||||
|
{
|
||||||
|
struct feature_group *fg;
|
||||||
|
struct feature_group_exten *fge;
|
||||||
|
|
||||||
|
AST_RWLIST_WRLOCK(&feature_groups);
|
||||||
|
while ((fg = AST_LIST_REMOVE_HEAD(&feature_groups, entry))) {
|
||||||
|
while ((fge = AST_LIST_REMOVE_HEAD(&fg->features, entry)))
|
||||||
|
free(fge);
|
||||||
|
free(fg);
|
||||||
|
}
|
||||||
|
AST_RWLIST_UNLOCK(&feature_groups);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! \brief Find a group by name */
|
||||||
|
static struct feature_group *find_group(const char *name) {
|
||||||
|
struct feature_group *fg = NULL;
|
||||||
|
|
||||||
|
AST_LIST_TRAVERSE(&feature_groups, fg, entry) {
|
||||||
|
if (!strcasecmp(fg->gname, name))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return fg;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct feature_group_exten *find_group_exten(struct feature_group *fg, const char *code) {
|
||||||
|
struct feature_group_exten *fge = NULL;
|
||||||
|
|
||||||
|
AST_LIST_TRAVERSE(&fg->features, fge, entry) {
|
||||||
|
if(!strcasecmp(fge->exten, code))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return fge;
|
||||||
|
}
|
||||||
|
|
||||||
void ast_rdlock_call_features(void)
|
void ast_rdlock_call_features(void)
|
||||||
{
|
{
|
||||||
ast_rwlock_rdlock(&features_lock);
|
ast_rwlock_rdlock(&features_lock);
|
||||||
|
@ -1197,6 +1307,8 @@ static int ast_feature_interpret(struct ast_channel *chan, struct ast_channel *p
|
||||||
struct ast_flags features;
|
struct ast_flags features;
|
||||||
int res = FEATURE_RETURN_PASSDIGITS;
|
int res = FEATURE_RETURN_PASSDIGITS;
|
||||||
struct ast_call_feature *feature;
|
struct ast_call_feature *feature;
|
||||||
|
struct feature_group *fg = NULL;
|
||||||
|
struct feature_group_exten *fge;
|
||||||
const char *dynamic_features=pbx_builtin_getvar_helper(chan,"DYNAMIC_FEATURES");
|
const char *dynamic_features=pbx_builtin_getvar_helper(chan,"DYNAMIC_FEATURES");
|
||||||
char *tmp, *tok;
|
char *tmp, *tok;
|
||||||
|
|
||||||
|
@ -1229,9 +1341,23 @@ static int ast_feature_interpret(struct ast_channel *chan, struct ast_channel *p
|
||||||
tmp = ast_strdupa(dynamic_features);
|
tmp = ast_strdupa(dynamic_features);
|
||||||
|
|
||||||
while ((tok = strsep(&tmp, "#"))) {
|
while ((tok = strsep(&tmp, "#"))) {
|
||||||
AST_LIST_LOCK(&feature_list);
|
AST_RWLIST_RDLOCK(&feature_groups);
|
||||||
if (!(feature = find_dynamic_feature(tok)))
|
|
||||||
|
fg = find_group(tok);
|
||||||
|
|
||||||
|
if (fg && (fge = find_group_exten(fg, code))) {
|
||||||
|
res = fge->feature->operation(chan, peer, config, code, sense);
|
||||||
|
AST_RWLIST_UNLOCK(&feature_groups);
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
AST_RWLIST_UNLOCK(&feature_groups);
|
||||||
|
AST_LIST_LOCK(&feature_list);
|
||||||
|
|
||||||
|
if(!(feature = find_dynamic_feature(tok))) {
|
||||||
|
AST_LIST_UNLOCK(&feature_list);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
/* Feature is up for consideration */
|
/* Feature is up for consideration */
|
||||||
if (!strcmp(feature->exten, code)) {
|
if (!strcmp(feature->exten, code)) {
|
||||||
|
@ -2454,11 +2580,22 @@ static int load_config(void)
|
||||||
{
|
{
|
||||||
int start = 0, end = 0;
|
int start = 0, end = 0;
|
||||||
int res;
|
int res;
|
||||||
|
int i;
|
||||||
struct ast_context *con = NULL;
|
struct ast_context *con = NULL;
|
||||||
struct ast_config *cfg = NULL;
|
struct ast_config *cfg = NULL;
|
||||||
struct ast_variable *var = NULL;
|
struct ast_variable *var = NULL;
|
||||||
|
struct feature_group *fg = NULL;
|
||||||
char old_parking_ext[AST_MAX_EXTENSION];
|
char old_parking_ext[AST_MAX_EXTENSION];
|
||||||
char old_parking_con[AST_MAX_EXTENSION] = "";
|
char old_parking_con[AST_MAX_EXTENSION] = "";
|
||||||
|
char *ctg;
|
||||||
|
static const char *categories[] = {
|
||||||
|
/* Categories in features.conf that are not
|
||||||
|
* to be parsed as group categories
|
||||||
|
*/
|
||||||
|
"general",
|
||||||
|
"featuremap",
|
||||||
|
"applicationmap"
|
||||||
|
};
|
||||||
|
|
||||||
if (!ast_strlen_zero(parking_con)) {
|
if (!ast_strlen_zero(parking_con)) {
|
||||||
strcpy(old_parking_ext, parking_ext);
|
strcpy(old_parking_ext, parking_ext);
|
||||||
|
@ -2672,6 +2809,40 @@ static int load_config(void)
|
||||||
if (option_verbose >= 1)
|
if (option_verbose >= 1)
|
||||||
ast_verbose(VERBOSE_PREFIX_2 "Mapping Feature '%s' to app '%s(%s)' with code '%s'\n", var->name, app, app_args, exten);
|
ast_verbose(VERBOSE_PREFIX_2 "Mapping Feature '%s' to app '%s(%s)' with code '%s'\n", var->name, app, app_args, exten);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ast_unregister_groups();
|
||||||
|
AST_RWLIST_WRLOCK(&feature_groups);
|
||||||
|
|
||||||
|
ctg = NULL;
|
||||||
|
struct ast_call_feature *feature;
|
||||||
|
while ((ctg = ast_category_browse(cfg, ctg))) {
|
||||||
|
for (i = 0; i < ARRAY_LEN(categories); i++) {
|
||||||
|
if (!strcasecmp(categories[i], ctg))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i < ARRAY_LEN(categories))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!(fg = register_group(ctg)))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
for (var = ast_variable_browse(cfg, ctg); var; var = var->next) {
|
||||||
|
AST_LIST_LOCK(&feature_list);
|
||||||
|
if(!(feature = find_dynamic_feature(var->name)) &&
|
||||||
|
!(feature = ast_find_call_feature(var->name))) {
|
||||||
|
AST_LIST_UNLOCK(&feature_list);
|
||||||
|
ast_log(LOG_WARNING, "Feature '%s' was not found.\n", var->name);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
AST_LIST_UNLOCK(&feature_list);
|
||||||
|
|
||||||
|
register_group_feature(fg, var->value, feature);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AST_RWLIST_UNLOCK(&feature_groups);
|
||||||
|
|
||||||
ast_config_destroy(cfg);
|
ast_config_destroy(cfg);
|
||||||
|
|
||||||
/* Remove the old parking extension */
|
/* Remove the old parking extension */
|
||||||
|
|
Loading…
Reference in New Issue