[asterisk-commits] mmichelson: branch mmichelson/features_config r389724 - /team/mmichelson/feat...
SVN commits to the Asterisk project
asterisk-commits at lists.digium.com
Fri May 24 09:20:50 CDT 2013
Author: mmichelson
Date: Fri May 24 09:20:46 2013
New Revision: 389724
URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=389724
Log:
Add handling for feature groups.
Modified:
team/mmichelson/features_config/main/features_config.c
Modified: team/mmichelson/features_config/main/features_config.c
URL: http://svnview.digium.com/svn/asterisk/team/mmichelson/features_config/main/features_config.c?view=diff&rev=389724&r1=389723&r2=389724
==============================================================================
--- team/mmichelson/features_config/main/features_config.c (original)
+++ team/mmichelson/features_config/main/features_config.c Fri May 24 09:20:46 2013
@@ -96,10 +96,109 @@
}
}
+struct featuregroup_item {
+ AST_DECLARE_STRING_FIELDS(
+ AST_STRING_FIELD(appmap_item_name);
+ AST_STRING_FIELD(dtmf_override);
+ );
+ struct applicationmap_item *appmap_item;
+};
+
+static void featuregroup_item_destructor(void *obj)
+{
+ struct featuregroup_item *item = obj;
+
+ ast_string_field_free_memory(item);
+ ao2_cleanup(item->appmap_item);
+}
+
+static int group_item_hash(const void *obj, int flags)
+{
+ const struct featuregroup_item *item;
+ const char *key;
+
+ switch (flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY)) {
+ case OBJ_KEY:
+ key = obj;
+ return ast_str_case_hash(key);
+ case OBJ_PARTIAL_KEY:
+ ast_assert(0);
+ return 0;
+ case OBJ_POINTER:
+ default:
+ item = obj;
+ return ast_str_case_hash(item->appmap_item_name);
+ }
+}
+
+static int group_item_cmp(void *obj, void *arg, int flags)
+{
+ struct featuregroup_item *item1 = obj;
+ struct featuregroup_item *item2;
+ const char *key2;
+
+ switch(flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY)) {
+ case OBJ_KEY:
+ key2 = arg;
+ return strcasecmp(item1->appmap_item_name, key2) ? 0 : CMP_MATCH;
+ case OBJ_PARTIAL_KEY:
+ key2 = arg;
+ return strncasecmp(item1->appmap_item_name, key2, strlen(key2)) ? 0 : CMP_MATCH;
+ case OBJ_POINTER:
+ item2 = arg;
+ return strcasecmp(item1->appmap_item_name, item2->appmap_item_name) ? 0 : CMP_MATCH;
+ default:
+ return CMP_STOP;
+ }
+}
+
+struct featuregroup {
+ const char *name;
+ struct ao2_container *items;
+};
+
+static void *featuregroup_find(struct ao2_container *group_container, const char *category)
+{
+ return ao2_find(group_container, category, OBJ_KEY);
+}
+
+static void featuregroup_destructor(void *obj)
+{
+ struct featuregroup *group = obj;
+
+ ast_free((char *) group->name);
+ ao2_cleanup(group->items);
+}
+
+static void *featuregroup_alloc(const char *cat)
+{
+ struct featuregroup *group;
+
+ group = ao2_alloc(sizeof(*group), featuregroup_destructor);
+ if (!group) {
+ return NULL;
+ }
+
+ group->name = ast_strdup(cat);
+ if (!group->name) {
+ ao2_cleanup(group);
+ return NULL;
+ }
+
+ group->items = ao2_container_alloc(5, group_item_hash, group_item_cmp);
+ if (!group->items) {
+ ao2_cleanup(group);
+ return NULL;
+ }
+
+ return group;
+}
+
struct features_config {
struct features_global_config *global;
struct ast_featuremap_config *featuremap;
struct ao2_container *applicationmap;
+ struct ao2_container *featuregroups;
};
static struct aco_type global_option = {
@@ -126,9 +225,20 @@
.item_offset = offsetof(struct features_config, applicationmap),
};
+static struct aco_type featuregroup_option = {
+ .type = ACO_ITEM,
+ .name = "featuregroup",
+ .category_match = ACO_BLACKLIST,
+ .category = "(^general$|^featuremap$|^applicationmap$)",
+ .item_offset = offsetof(struct features_config, featuregroups),
+ .item_alloc = featuregroup_alloc,
+ .item_find = featuregroup_find,
+};
+
struct aco_type *global_options[] = ACO_TYPES(&global_option);
struct aco_type *featuremap_options[] = ACO_TYPES(&featuremap_option);
struct aco_type *applicationmap_options[] = ACO_TYPES(&applicationmap_option);
+struct aco_type *featuregroup_options[] = ACO_TYPES(&featuregroup_option);
struct aco_file features_conf = {
.filename = "features.conf",
@@ -465,10 +575,6 @@
return res;
}
-CONFIG_INFO_CORE("features", cfg_info, globals, features_config_alloc,
- .files = ACO_FILES(&features_conf),
-);
-
static void feature_ds_destroy(void *data)
{
struct features_config *cfg = data;
@@ -741,6 +847,27 @@
return 0;
}
+static int featuregroup_handler(const struct aco_option *opt,
+ struct ast_variable *var, void *obj)
+{
+ RAII_VAR(struct featuregroup_item *, item, NULL, ao2_cleanup);
+ struct ao2_container *featuregroups = obj;
+
+ item = ao2_alloc(sizeof(*item), featuregroup_item_destructor);
+ if (!item || ast_string_field_init(item, 32)) {
+ return -1;
+ }
+
+ ast_string_field_set(item, appmap_item_name, var->name);
+ ast_string_field_set(item, dtmf_override, var->value);
+
+ ao2_link(featuregroups, item);
+
+ /* We wait to look up the application map item in the preapply callback */
+
+ return 0;
+}
+
static int general_handler(const struct aco_option *opt,
struct ast_variable *var, void *obj)
{
@@ -775,6 +902,163 @@
return featuremap_set(featuremap, var->name, var->value);
}
+
+static int check_featuregroup_item(void *obj, void *arg, void *data, int flags)
+{
+ RAII_VAR(struct applicationmap_item *, appmap_item, NULL, ao2_cleanup);
+ struct featuregroup_item *fg_item = obj;
+ int *err = arg;
+ struct ao2_container *applicationmap = data;
+
+ appmap_item = ao2_find(applicationmap, fg_item->appmap_item_name, OBJ_KEY);
+ if (!appmap_item) {
+ *err = 1;
+ return CMP_STOP;
+ }
+
+ return 0;
+}
+
+static int check_featuregroup(void *obj, void *arg, void *data, int flags)
+{
+ struct featuregroup *group = obj;
+ int *err = arg;
+
+ ao2_callback_data(group->items, 0, check_featuregroup_item, arg, data);
+
+ if (*err) {
+ ast_log(LOG_WARNING, "Featuregroup %s refers to non-existent applicationmap item\n",
+ group->name);
+ }
+
+ return *err ? CMP_STOP : 0;
+}
+
+static int features_pre_apply_config(void)
+{
+ RAII_VAR(struct features_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
+ int err = 0;
+
+ /* Now that the entire config has been processed, we can check that the featuregroup
+ * items refer to actual applicationmap items.
+ */
+
+ ao2_callback_data(cfg->featuregroups, 0, check_featuregroup, &err, cfg->applicationmap);
+
+ return err;
+}
+
+CONFIG_INFO_CORE("features", cfg_info, globals, features_config_alloc,
+ .files = ACO_FILES(&features_conf),
+ .pre_apply_config = features_pre_apply_config,
+);
+
+static int feature_read(struct ast_channel *chan, const char *cmd, char *data,
+ char *buf, size_t len)
+{
+ int res;
+ RAII_VAR(struct features_config *, cfg, NULL, ao2_cleanup);
+ SCOPED_CHANNELLOCK(lock, chan);
+
+ if (!strcasecmp(data, "inherit")) {
+ struct ast_datastore *ds = get_feature_chan_ds(chan);
+ unsigned int inherit = ds ? ds->inheritance : 0;
+
+ snprintf(buf, len, "%s", inherit ? "yes" : "no");
+ return 0;
+ }
+
+ cfg = get_feature_ds(chan);
+ if (!cfg) {
+ return -1;
+ }
+
+ res = general_get(cfg->global->general, data, buf, len) &&
+ xfer_get(cfg->global->xfer, data, buf, len) &&
+ pickup_get(cfg->global->pickup, data, buf, len);
+
+ if (res) {
+ ast_log(LOG_WARNING, "Invalid argument '%s' to FEATURE()\n", data);
+ }
+
+ return res;
+}
+
+static int feature_write(struct ast_channel *chan, const char *cmd, char *data,
+ const char *value)
+{
+ int res;
+ RAII_VAR(struct features_config *, cfg, NULL, ao2_cleanup);
+ SCOPED_CHANNELLOCK(lock, chan);
+
+ if (!strcasecmp(data, "inherit")) {
+ struct ast_datastore *ds = get_feature_chan_ds(chan);
+ if (ds) {
+ ds->inheritance = ast_true(value) ? DATASTORE_INHERIT_FOREVER : 0;
+ }
+ return 0;
+ }
+
+ if (!(cfg = get_feature_ds(chan))) {
+ return -1;
+ }
+
+ res = general_set(cfg->global->general, data, value) &&
+ xfer_set(cfg->global->xfer, data, value) &&
+ pickup_set(cfg->global->pickup, data, value);
+
+ if (res) {
+ ast_log(LOG_WARNING, "Invalid argument '%s' to FEATURE()\n", data);
+ }
+
+ return res;
+}
+
+static int featuremap_read(struct ast_channel *chan, const char *cmd, char *data,
+ char *buf, size_t len)
+{
+ int res;
+
+ res = builtin_feature_get_exten(chan, data, buf, len);
+
+ if (res) {
+ ast_log(LOG_WARNING, "Invalid argument '%s' to FEATUREMAP()\n", data);
+ }
+
+ return res;
+}
+
+static int featuremap_write(struct ast_channel *chan, const char *cmd, char *data,
+ const char *value)
+{
+ int res;
+ RAII_VAR(struct features_config *, cfg, NULL, ao2_cleanup);
+ SCOPED_CHANNELLOCK(lock, chan);
+
+ if (!(cfg = get_feature_ds(chan))) {
+ return -1;
+ }
+
+ res = featuremap_set(cfg->featuremap, data, value);
+ if (res) {
+ ast_log(LOG_WARNING, "Invalid argument '%s' to FEATUREMAP()\n", data);
+ return -1;
+ }
+
+ return 0;
+}
+
+static struct ast_custom_function feature_function = {
+ .name = "FEATURE",
+ .read = feature_read,
+ .write = feature_write
+};
+
+static struct ast_custom_function featuremap_function = {
+ .name = "FEATUREMAP",
+ .read = featuremap_read,
+ .write = featuremap_write
+};
static int load_config(int reload)
{
@@ -825,11 +1109,9 @@
aco_option_register_custom(&cfg_info, "^.*$", ACO_REGEX, applicationmap_options,
"", applicationmap_handler, 0);
-#if 0
/* XXX This regex may need to be more specific */
- aco_option_register_custom(&cfg_info, "^.*$", ACO_REGEX, dynamicfeaturemap_options,
- "", dynamic_feature_handler, 0);
-#endif
+ aco_option_register_custom(&cfg_info, "^.*$", ACO_REGEX, featuregroup_options,
+ "", featuregroup_handler, 0);
if (aco_process_config(&cfg_info, 0) == ACO_PROCESS_ERROR) {
ast_log(LOG_ERROR, "Failed to process features.conf configuration!\n");
@@ -843,112 +1125,6 @@
return 0;
}
-static int feature_read(struct ast_channel *chan, const char *cmd, char *data,
- char *buf, size_t len)
-{
- int res;
- RAII_VAR(struct features_config *, cfg, NULL, ao2_cleanup);
- SCOPED_CHANNELLOCK(lock, chan);
-
- if (!strcasecmp(data, "inherit")) {
- struct ast_datastore *ds = get_feature_chan_ds(chan);
- unsigned int inherit = ds ? ds->inheritance : 0;
-
- snprintf(buf, len, "%s", inherit ? "yes" : "no");
- return 0;
- }
-
- cfg = get_feature_ds(chan);
- if (!cfg) {
- return -1;
- }
-
- res = general_get(cfg->global->general, data, buf, len) &&
- xfer_get(cfg->global->xfer, data, buf, len) &&
- pickup_get(cfg->global->pickup, data, buf, len);
-
- if (res) {
- ast_log(LOG_WARNING, "Invalid argument '%s' to FEATURE()\n", data);
- }
-
- return res;
-}
-
-static int feature_write(struct ast_channel *chan, const char *cmd, char *data,
- const char *value)
-{
- int res;
- RAII_VAR(struct features_config *, cfg, NULL, ao2_cleanup);
- SCOPED_CHANNELLOCK(lock, chan);
-
- if (!strcasecmp(data, "inherit")) {
- struct ast_datastore *ds = get_feature_chan_ds(chan);
- if (ds) {
- ds->inheritance = ast_true(value) ? DATASTORE_INHERIT_FOREVER : 0;
- }
- return 0;
- }
-
- if (!(cfg = get_feature_ds(chan))) {
- return -1;
- }
-
- res = general_set(cfg->global->general, data, value) &&
- xfer_set(cfg->global->xfer, data, value) &&
- pickup_set(cfg->global->pickup, data, value);
-
- if (res) {
- ast_log(LOG_WARNING, "Invalid argument '%s' to FEATURE()\n", data);
- }
-
- return res;
-}
-
-static int featuremap_read(struct ast_channel *chan, const char *cmd, char *data,
- char *buf, size_t len)
-{
- int res;
-
- res = builtin_feature_get_exten(chan, data, buf, len);
-
- if (res) {
- ast_log(LOG_WARNING, "Invalid argument '%s' to FEATUREMAP()\n", data);
- }
-
- return res;
-}
-
-static int featuremap_write(struct ast_channel *chan, const char *cmd, char *data,
- const char *value)
-{
- int res;
- RAII_VAR(struct features_config *, cfg, NULL, ao2_cleanup);
- SCOPED_CHANNELLOCK(lock, chan);
-
- if (!(cfg = get_feature_ds(chan))) {
- return -1;
- }
-
- res = featuremap_set(cfg->featuremap, data, value);
- if (res) {
- ast_log(LOG_WARNING, "Invalid argument '%s' to FEATUREMAP()\n", data);
- return -1;
- }
-
- return 0;
-}
-
-static struct ast_custom_function feature_function = {
- .name = "FEATURE",
- .read = feature_read,
- .write = feature_write
-};
-
-static struct ast_custom_function featuremap_function = {
- .name = "FEATUREMAP",
- .read = featuremap_read,
- .write = featuremap_write
-};
void ast_features_config_shutdown(void)
{
More information about the asterisk-commits
mailing list