summaryrefslogtreecommitdiff
path: root/main/features.c
diff options
context:
space:
mode:
authorRussell Bryant <russell@russellbryant.com>2013-04-09 06:16:42 +0000
committerRussell Bryant <russell@russellbryant.com>2013-04-09 06:16:42 +0000
commitee05bdec92c1ef72634ffb6c7743864172b1d487 (patch)
treec7b32e3e5512c6dd53ad050e4f5a3c75e1348b10 /main/features.c
parent98f2318559d6dfbd12f0c839619e6145c5016904 (diff)
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
Diffstat (limited to 'main/features.c')
-rw-r--r--main/features.c85
1 files changed, 69 insertions, 16 deletions
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$")
<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;