diff --git a/CHANGES b/CHANGES index fa7cbff2a8..8e78afc0c2 100644 --- a/CHANGES +++ b/CHANGES @@ -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 diff --git a/main/features.c b/main/features.c index a7206e77de..7fcdc49f80 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;