From ee05bdec92c1ef72634ffb6c7743864172b1d487 Mon Sep 17 00:00:00 2001 From: Russell Bryant Date: Tue, 9 Apr 2013 06:16:42 +0000 Subject: 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 --- main/features.c | 85 ++++++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 69 insertions(+), 16 deletions(-) (limited to 'main/features.c') diff --git a/main/features.c b/main/features.c index a7206e77d..7fcdc49f8 100644 --- a/main/features.c +++ b/main/features.c @@ -438,6 +438,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") The allowed values are: Specified in seconds. + Inherit feature settings made in FEATURE or FEATUREMAP to child channels. @@ -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; -- cgit v1.2.3