Add inheritance support to FEATURE()/FEATUREMAP().

The settings saved on the channel for FEATURE()/FEATUREMAP() were only
for that channel.  This patch adds the ability to have these settings
inherited to child channels if you set FEATURE(inherit)=yes.

Closes issue ASTERISK-21306.

Review: https://reviewboard.asterisk.org/r/2415/


git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@385088 65c4cc65-6c06-0410-ace0-fbb531ad65f3
changes/78/78/1
Russell Bryant 12 years ago
parent 98f2318559
commit ee05bdec92

@ -89,6 +89,10 @@ Features
* PARKINGSLOT and PARKEDLOT channel variables will now be set for a parked
channel even when comebactoorigin=yes
* You can now have the settings for a channel updated using the FEATURE()
and FEATUREMAP() functions inherited to child channels by setting
FEATURE(inherit)=yes.
Logging
-------------------
* When performing queue pause/unpause on an interface without specifying an

@ -438,6 +438,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
<para>The allowed values are:</para>
<enumlist>
<enum name="parkingtime"><para>Specified in seconds.</para></enum>
<enum name="inherit"><para>Inherit feature settings made in FEATURE or FEATUREMAP to child channels.</para></enum>
</enumlist>
</parameter>
</syntax>
@ -3333,11 +3334,31 @@ struct feature_ds {
* \todo XXX This isn't pretty. At some point it would be nice to have all
* of the global / [general] options in a config object that we store here
* instead of handling each one manually.
*
* \note If anything gets added here, don't forget to update
* feature_ds_duplicate, as well.
* */
unsigned int parkingtime;
unsigned int parkingtime_is_set:1;
};
static int feature_exten_hash(const void *obj, int flags)
{
const struct feature_exten *fe = obj;
const char *sname = obj;
return ast_str_hash(flags & OBJ_KEY ? sname : fe->sname);
}
static int feature_exten_cmp(void *obj, void *arg, int flags)
{
const struct feature_exten *fe = obj, *fe2 = arg;
const char *sname = arg;
return !strcmp(fe->sname, flags & OBJ_KEY ? sname : fe2->sname) ?
CMP_MATCH | CMP_STOP : 0;
}
static void feature_ds_destroy(void *data)
{
struct feature_ds *feature_ds = data;
@ -3350,28 +3371,32 @@ static void feature_ds_destroy(void *data)
ast_free(feature_ds);
}
static const struct ast_datastore_info feature_ds_info = {
.type = "FEATURE",
.destroy = feature_ds_destroy,
};
static int feature_exten_hash(const void *obj, int flags)
static void *feature_ds_duplicate(void *data)
{
const struct feature_exten *fe = obj;
const char *sname = obj;
struct feature_ds *old_ds = data;
struct feature_ds *new_ds;
return ast_str_hash(flags & OBJ_KEY ? sname : fe->sname);
}
if (!(new_ds = ast_calloc(1, sizeof(*new_ds)))) {
return NULL;
}
static int feature_exten_cmp(void *obj, void *arg, int flags)
{
const struct feature_exten *fe = obj, *fe2 = arg;
const char *sname = arg;
if (old_ds->feature_map) {
ao2_ref(old_ds->feature_map, +1);
new_ds->feature_map = old_ds->feature_map;
}
return !strcmp(fe->sname, flags & OBJ_KEY ? sname : fe2->sname) ?
CMP_MATCH | CMP_STOP : 0;
new_ds->parkingtime = old_ds->parkingtime;
new_ds->parkingtime_is_set = old_ds->parkingtime_is_set;
return new_ds;
}
static const struct ast_datastore_info feature_ds_info = {
.type = "FEATURE",
.destroy = feature_ds_destroy,
.duplicate = feature_ds_duplicate,
};
/*!
* \internal
* \brief Find or create feature datastore on a channel
@ -3411,6 +3436,19 @@ static struct feature_ds *get_feature_ds(struct ast_channel *chan)
return feature_ds;
}
static struct ast_datastore *get_feature_chan_ds(struct ast_channel *chan)
{
struct ast_datastore *ds;
if (!(ds = ast_channel_datastore_find(chan, &feature_ds_info, NULL))) {
/* Hasn't been created yet. Trigger creation. */
get_feature_ds(chan);
ds = ast_channel_datastore_find(chan, &feature_ds_info, NULL);
}
return ds;
}
/*!
* \internal
* \brief Get the extension for a given builtin feature
@ -8964,6 +9002,16 @@ static int feature_read(struct ast_channel *chan, const char *cmd, char *data,
if (!strcasecmp(data, "parkingtime")) {
snprintf(buf, len, "%u", get_parkingtime(chan, NULL) / 1000);
} else if (!strcasecmp(data, "inherit")) {
struct ast_datastore *ds;
unsigned int inherit;
ast_channel_lock(chan);
ds = get_feature_chan_ds(chan);
inherit = ds ? ds->inheritance : 0;
ast_channel_unlock(chan);
snprintf(buf, len, "%s", inherit ? "yes" : "no");
} else {
ast_log(LOG_WARNING, "Invalid argument '%s' to FEATURE()\n", data);
res = -1;
@ -8994,6 +9042,11 @@ static int feature_write(struct ast_channel *chan, const char *cmd, char *data,
feature_ds->parkingtime_is_set = 0;
res = -1;
}
} else if (!strcasecmp(data, "inherit")) {
struct ast_datastore *ds;
if ((ds = get_feature_chan_ds(chan))) {
ds->inheritance = ast_true(value) ? DATASTORE_INHERIT_FOREVER : 0;
}
} else {
ast_log(LOG_WARNING, "Invalid argument '%s' to FEATURE()\n", data);
res = -1;

Loading…
Cancel
Save