[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