[asterisk-commits] mmichelson: branch mmichelson/features_config r389518 - /team/mmichelson/feat...
SVN commits to the Asterisk project
asterisk-commits at lists.digium.com
Wed May 22 13:40:00 CDT 2013
Author: mmichelson
Date: Wed May 22 13:39:56 2013
New Revision: 389518
URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=389518
Log:
Use channel datastore to store feature config values per-channel.
Tested from dialplan and can use the FEATURE and FEATUREMAP functions
to read/write feature values.
Next step is to write public functions to get at subsets of the data.
Modified:
team/mmichelson/features_config/main/features.c
Modified: team/mmichelson/features_config/main/features.c
URL: http://svnview.digium.com/svn/asterisk/team/mmichelson/features_config/main/features.c?view=diff&rev=389518&r1=389517&r2=389518
==============================================================================
--- team/mmichelson/features_config/main/features.c (original)
+++ team/mmichelson/features_config/main/features.c Wed May 22 13:39:56 2013
@@ -662,6 +662,399 @@
struct ast_flags peer_features;
};
+struct features_global_config {
+ struct ast_features_general_config *general;
+ struct ast_features_xfer_config *xfer;
+ struct ast_features_pickup_config *pickup;
+};
+
+struct features_featuremap {
+ AST_DECLARE_STRING_FIELDS (
+ AST_STRING_FIELD(blindxfer);
+ AST_STRING_FIELD(disconnect);
+ AST_STRING_FIELD(automon);
+ AST_STRING_FIELD(atxfer);
+ AST_STRING_FIELD(parkcall);
+ AST_STRING_FIELD(automixmon);
+ );
+};
+
+struct features_applicationmap {
+ /* XXX STUB */
+};
+
+struct features_config {
+ struct features_global_config *global;
+ struct features_featuremap *featuremap;
+ struct features_applicationmap *applicationmap;
+};
+
+static struct aco_type global_option = {
+ .type = ACO_GLOBAL,
+ .name = "globals",
+ .category_match = ACO_WHITELIST,
+ .category = "^general$",
+ .item_offset = offsetof(struct features_config, global),
+};
+
+static struct aco_type featuremap_option = {
+ .type = ACO_GLOBAL,
+ .name = "featuremap",
+ .category_match = ACO_WHITELIST,
+ .category = "^featuremap$",
+ .item_offset = offsetof(struct features_config, featuremap),
+};
+
+static struct aco_type applicationmap_option = {
+ .type = ACO_GLOBAL,
+ .name = "applicationmap",
+ .category_match = ACO_WHITELIST,
+ .category = "^applicationmap$",
+ .item_offset = offsetof(struct features_config, applicationmap),
+};
+
+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_file features_conf = {
+ .filename = "features.conf",
+ .types = ACO_TYPES(&global_option, &featuremap_option, &applicationmap_option),
+};
+
+AO2_GLOBAL_OBJ_STATIC(globals);
+
+static void features_config_destructor(void *obj)
+{
+ struct features_config *cfg = obj;
+
+ ao2_cleanup(cfg->global);
+ ao2_cleanup(cfg->featuremap);
+ ao2_cleanup(cfg->applicationmap);
+}
+
+static void featuremap_config_destructor(void *obj)
+{
+ struct features_featuremap *cfg = obj;
+
+ ast_string_field_free_memory(cfg);
+}
+
+static void applicationmap_config_destructor (void *obj)
+{
+ /* XXX STUB */
+}
+
+static void global_config_destructor(void *obj)
+{
+ struct features_global_config *cfg = obj;
+
+ ao2_cleanup(cfg->general);
+ ao2_cleanup(cfg->xfer);
+ ao2_cleanup(cfg->pickup);
+}
+
+static void xfer_destructor(void *obj)
+{
+ struct ast_features_xfer_config *cfg = obj;
+
+ ast_string_field_free_memory(cfg);
+}
+
+static void pickup_destructor(void *obj)
+{
+ struct ast_features_pickup_config *cfg = obj;
+
+ ast_string_field_free_memory(cfg);
+}
+
+static struct features_global_config *global_config_alloc(void)
+{
+ RAII_VAR(struct features_global_config *, cfg, NULL, ao2_cleanup);
+
+ cfg = ao2_alloc(sizeof(*cfg), global_config_destructor);
+ if (!cfg) {
+ return NULL;
+ }
+
+ cfg->general = ao2_alloc(sizeof(*cfg->general), NULL);
+ if (!cfg->general) {
+ return NULL;
+ }
+
+ cfg->xfer = ao2_alloc(sizeof(*cfg->xfer), xfer_destructor);
+ if (!cfg->xfer || ast_string_field_init(cfg->xfer, 32)) {
+ return NULL;
+ }
+
+ cfg->pickup = ao2_alloc(sizeof(*cfg->pickup), pickup_destructor);
+ if (!cfg->pickup || ast_string_field_init(cfg->pickup, 32)) {
+ return NULL;
+ }
+
+ ao2_ref(cfg, +1);
+ return cfg;
+}
+
+static void *features_config_alloc(void)
+{
+ RAII_VAR(struct features_config *, cfg, NULL, ao2_cleanup);
+
+ cfg = ao2_alloc(sizeof(*cfg), features_config_destructor);
+ if (!cfg) {
+ return NULL;
+ }
+
+ cfg->global = global_config_alloc();;
+ if (!cfg->global) {
+ return NULL;
+ }
+
+ cfg->featuremap = ao2_alloc(sizeof(*cfg->featuremap), featuremap_config_destructor);
+ if (!cfg->featuremap || ast_string_field_init(cfg->featuremap, 32)) {
+ return NULL;
+ }
+
+ cfg->applicationmap = ao2_alloc(sizeof(*cfg->applicationmap),
+ applicationmap_config_destructor);
+ if (!cfg->applicationmap) {
+ return NULL;
+ }
+
+ ao2_ref(cfg, +1);
+ return cfg;
+}
+
+static void general_copy(struct ast_features_general_config *dest, const struct ast_features_general_config *src)
+{
+ *dest = *src;
+}
+
+static void xfer_copy(struct ast_features_xfer_config *dest, const struct ast_features_xfer_config *src)
+{
+ ast_string_fields_copy(dest, src);
+ dest->transferdigittimeout = src->transferdigittimeout;
+ dest->atxfernoanswertimeout = src->atxfernoanswertimeout;
+ dest->atxferloopdelay = src->atxferloopdelay;
+ dest->atxfercallbackretries = src->atxfercallbackretries;
+ dest->atxferdropcall = src->atxferdropcall;
+}
+
+static void pickup_copy(struct ast_features_pickup_config *dest, const struct ast_features_pickup_config *src)
+{
+ ast_string_fields_copy(dest, src);
+}
+
+static void global_copy(struct features_global_config *dest, const struct features_global_config *src)
+{
+ general_copy(dest->general, src->general);
+ xfer_copy(dest->xfer, src->xfer);
+ pickup_copy(dest->pickup, src->pickup);
+}
+
+static void featuremap_copy(struct features_featuremap *dest, const struct features_featuremap *src)
+{
+ ast_string_fields_copy(dest, src);
+}
+
+static void applicationmap_copy(struct features_applicationmap *dest, const struct features_applicationmap *src)
+{
+ /* XXX STUB */
+}
+
+static void features_copy(struct features_config *dest, const struct features_config *src)
+{
+ global_copy(dest->global, src->global);
+ featuremap_copy(dest->featuremap, src->featuremap);
+ applicationmap_copy(dest->applicationmap, src->applicationmap);
+}
+
+static struct features_config *features_config_dup(const struct features_config *orig)
+{
+ struct features_config *dup;
+
+ dup = features_config_alloc();
+ if (!dup) {
+ return NULL;
+ }
+
+ features_copy(dup, orig);
+
+ return dup;
+}
+
+static int general_set(struct ast_features_general_config *general, const char *name,
+ const char *value)
+{
+ int res = 0;
+
+ if (!strcasecmp(name, "featuredigittimeout")) {
+ res = ast_parse_arg(value, PARSE_INT32, &general->featuredigittimeout);
+ } else {
+ /* Unrecognized option */
+ res = -1;
+ }
+
+ return res;
+}
+
+static int general_get(struct ast_features_general_config *general, const char *field,
+ char *buf, size_t len)
+{
+ int res = 0;
+
+ if (!strcasecmp(field, "featuredigittimeout")) {
+ snprintf(buf, len, "%u", general->featuredigittimeout);
+ } else {
+ /* Unrecognized option */
+ res = -1;
+ }
+
+ return res;
+}
+
+static int xfer_set(struct ast_features_xfer_config *xfer, const char *name,
+ const char *value)
+{
+ int res = 0;
+
+ if (!strcasecmp(name, "transferdigittimeout")) {
+ res = ast_parse_arg(value, PARSE_INT32, &xfer->transferdigittimeout);
+ } else if (!strcasecmp(name, "atxfernoanswertimeout")) {
+ res = ast_parse_arg(value, PARSE_INT32, &xfer->atxfernoanswertimeout);
+ } else if (!strcasecmp(name, "atxferloopdelay")) {
+ res = ast_parse_arg(value, PARSE_INT32, &xfer->atxferloopdelay);
+ } else if (!strcasecmp(name, "atxfercallbackretries")) {
+ res = ast_parse_arg(value, PARSE_INT32, &xfer->atxfercallbackretries);
+ } else if (!strcasecmp(name, "atxferdropcall")) {
+ xfer->atxferdropcall = ast_true(value);
+ } else if (!strcasecmp(name, "xfersound")) {
+ ast_string_field_set(xfer, xfersound, value);
+ } else if (!strcasecmp(name, "xferfailsound")) {
+ ast_string_field_set(xfer, xferfailsound, value);
+ } else {
+ /* Unrecognized option */
+ res = -1;
+ }
+
+ return res;
+}
+
+static int xfer_get(struct ast_features_xfer_config *xfer, const char *field,
+ char *buf, size_t len)
+{
+ int res = 0;
+
+ if (!strcasecmp(field, "transferdigittimeout")) {
+ snprintf(buf, len, "%u", xfer->transferdigittimeout);
+ } else if (!strcasecmp(field, "atxfernoanswertimeout")) {
+ snprintf(buf, len, "%u", xfer->atxfernoanswertimeout);
+ } else if (!strcasecmp(field, "atxferloopdelay")) {
+ snprintf(buf, len, "%u", xfer->atxferloopdelay);
+ } else if (!strcasecmp(field, "atxfercallbackretries")) {
+ snprintf(buf, len, "%u", xfer->atxfercallbackretries);
+ } else if (!strcasecmp(field, "atxferdropcall")) {
+ snprintf(buf, len, "%u", xfer->atxferdropcall);
+ } else if (!strcasecmp(field, "xfersound")) {
+ ast_copy_string(buf, xfer->xfersound, len);
+ } else if (!strcasecmp(field, "xferfailsound")) {
+ ast_copy_string(buf, xfer->xferfailsound, len);
+ } else {
+ /* Unrecognized option */
+ res = -1;
+ }
+
+ return res;
+}
+
+static int pickup_set(struct ast_features_pickup_config *pickup, const char *name,
+ const char *value)
+{
+ int res = 0;
+
+ if (!strcasecmp(name, "pickupsound")) {
+ ast_string_field_set(pickup, pickupsound, value);
+ } else if (!strcasecmp(name, "pickupfailsound")) {
+ ast_string_field_set(pickup, pickupfailsound, value);
+ } else if (!strcasecmp(name, "pickupexten")) {
+ ast_string_field_set(pickup, pickupexten, value);
+ } else {
+ /* Unrecognized option */
+ res = -1;
+ }
+
+ return res;
+}
+
+static int pickup_get(struct ast_features_pickup_config *pickup, const char *field,
+ char *buf, size_t len)
+{
+ int res = 0;
+
+ if (!strcasecmp(field, "pickupsound")) {
+ ast_copy_string(buf, pickup->pickupsound, len);
+ } else if (!strcasecmp(field, "pickupfailsound")) {
+ ast_copy_string(buf, pickup->pickupfailsound, len);
+ } else if (!strcasecmp(field, "pickupexten")) {
+ ast_copy_string(buf, pickup->pickupexten, len);
+ } else {
+ /* Unrecognized option */
+ res = -1;
+ }
+
+ return res;
+}
+
+static int featuremap_set(struct features_featuremap *featuremap, const char *name,
+ const char *value)
+{
+ int res = 0;
+
+ if (!strcasecmp(name, "blindxfer")) {
+ ast_string_field_set(featuremap, blindxfer, value);
+ } else if (!strcasecmp(name, "disconnect")) {
+ ast_string_field_set(featuremap, disconnect, value);
+ } else if (!strcasecmp(name, "automon")) {
+ ast_string_field_set(featuremap, automon, value);
+ } else if (!strcasecmp(name, "atxfer")) {
+ ast_string_field_set(featuremap, atxfer, value);
+ } else if (!strcasecmp(name, "automixmon")) {
+ ast_string_field_set(featuremap, atxfer, value);
+ } else {
+ /* Unrecognized option */
+ res = -1;
+ }
+
+ return res;
+}
+
+static int featuremap_get(struct features_featuremap *featuremap, const char *field,
+ char *buf, size_t len)
+{
+ int res = 0;
+
+ if (!strcasecmp(field, "blindxfer")) {
+ ast_copy_string(buf, featuremap->blindxfer, len);
+ } else if (!strcasecmp(field, "disconnect")) {
+ ast_copy_string(buf, featuremap->disconnect, len);
+ } else if (!strcasecmp(field, "automon")) {
+ ast_copy_string(buf, featuremap->automon, len);
+ } else if (!strcasecmp(field, "atxfer")) {
+ ast_copy_string(buf, featuremap->atxfer, len);
+ } else if (!strcasecmp(field, "automixmon")) {
+ ast_copy_string(buf, featuremap->automixmon, len);
+ } else {
+ /* Unrecognized option */
+ res = -1;
+ }
+
+ return res;
+}
+
+CONFIG_INFO_CORE("features", cfg_info, globals, features_config_alloc,
+ .files = ACO_FILES(&features_conf),
+);
+
#if defined(ATXFER_NULL_TECH)
/*!
* \internal
@@ -1455,8 +1848,6 @@
return pu;
}
-static unsigned int get_parkingtime(struct ast_channel *chan, struct ast_parkinglot *parkinglot);
-
/* Park a call */
static int park_call_full(struct ast_channel *chan, struct ast_channel *peer, struct ast_park_call_args *args)
{
@@ -1490,7 +1881,10 @@
}
pu->start = ast_tvnow();
- pu->parkingtime = (args->timeout > 0) ? args->timeout : get_parkingtime(chan, pu->parkinglot);
+ /* XXX This line was changed to not use get_parkingtime. This is just a placeholder message, because
+ * likely this entire function is going away.
+ */
+ pu->parkingtime = args->timeout;
if (args->extout)
*(args->extout) = pu->parkingnum;
@@ -3141,75 +3535,17 @@
return find_dynamic_feature(name);
}
-struct feature_exten {
- char sname[FEATURE_SNAME_LEN];
- char exten[FEATURE_MAX_LEN];
-};
-
-struct feature_datastore {
- struct ao2_container *feature_map;
-
- /*!
- * \brief specified in seconds, stored in milliseconds
- *
- * \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_datastore *feature_ds = data;
-
- if (feature_ds->feature_map) {
- ao2_ref(feature_ds->feature_map, -1);
- feature_ds->feature_map = NULL;
- }
-
- ast_free(feature_ds);
+ struct features_config *cfg = data;
+ ao2_cleanup(cfg);
}
static void *feature_ds_duplicate(void *data)
{
- struct feature_datastore *old_ds = data;
- struct feature_datastore *new_ds;
-
- if (!(new_ds = ast_calloc(1, sizeof(*new_ds)))) {
- return NULL;
- }
-
- if (old_ds->feature_map) {
- ao2_ref(old_ds->feature_map, +1);
- new_ds->feature_map = old_ds->feature_map;
- }
-
- new_ds->parkingtime = old_ds->parkingtime;
- new_ds->parkingtime_is_set = old_ds->parkingtime_is_set;
-
- return new_ds;
+ struct features_config *old_cfg = data;
+
+ return features_config_dup(old_cfg);
}
static const struct ast_datastore_info feature_ds_info = {
@@ -3226,35 +3562,40 @@
*
* \return the data on the FEATURE datastore, or NULL on error
*/
-static struct feature_datastore *get_feature_ds(struct ast_channel *chan)
-{
- struct feature_datastore *feature_ds;
+static struct features_config *get_feature_ds(struct ast_channel *chan)
+{
+ RAII_VAR(struct features_config *, orig, NULL, ao2_cleanup);
+ struct features_config *cfg;
struct ast_datastore *ds;
if ((ds = ast_channel_datastore_find(chan, &feature_ds_info, NULL))) {
- feature_ds = ds->data;
- return feature_ds;
- }
-
- if (!(feature_ds = ast_calloc(1, sizeof(*feature_ds)))) {
+ cfg = ds->data;
+ ao2_ref(cfg, +1);
+ return cfg;
+ }
+
+ orig = ao2_global_obj_ref(globals);
+ if (!orig) {
return NULL;
}
- if (!(feature_ds->feature_map = ao2_container_alloc(7, feature_exten_hash, feature_exten_cmp))) {
- feature_ds_destroy(feature_ds);
+ cfg = features_config_dup(orig);
+ if (!cfg) {
return NULL;
}
if (!(ds = ast_datastore_alloc(&feature_ds_info, NULL))) {
- feature_ds_destroy(feature_ds);
+ ao2_cleanup(cfg);
return NULL;
}
- ds->data = feature_ds;
+ /* Give the datastore a reference to the config */
+ ao2_ref(cfg, +1);
+ ds->data = cfg;
ast_channel_datastore_add(chan, ds);
- return feature_ds;
+ return cfg;
}
static struct ast_datastore *get_feature_chan_ds(struct ast_channel *chan)
@@ -3263,7 +3604,7 @@
if (!(ds = ast_channel_datastore_find(chan, &feature_ds_info, NULL))) {
/* Hasn't been created yet. Trigger creation. */
- get_feature_ds(chan);
+ RAII_VAR(struct features_config *, cfg, get_feature_ds(chan), ao2_cleanup);
ds = ast_channel_datastore_find(chan, &feature_ds_info, NULL);
}
@@ -3282,37 +3623,15 @@
static int builtin_feature_get_exten(struct ast_channel *chan, const char *feature_name,
char *buf, size_t len)
{
- struct ast_call_feature *feature;
- struct feature_datastore *feature_ds;
- struct feature_exten *fe = NULL;
-
- *buf = '\0';
-
- if (!(feature = ast_find_call_feature(feature_name))) {
+ RAII_VAR(struct features_config *, cfg, NULL, ao2_cleanup);
+ SCOPED_CHANNELLOCK(lock, chan);
+
+ cfg = get_feature_ds(chan);
+ if (!cfg) {
return -1;
}
- ast_copy_string(buf, feature->exten, len);
-
- ast_unlock_call_features();
-
- ast_channel_lock(chan);
- if ((feature_ds = get_feature_ds(chan))) {
- fe = ao2_find(feature_ds->feature_map, feature_name, OBJ_KEY);
- }
- ast_channel_unlock(chan);
-
- ast_rdlock_call_features();
-
- if (fe) {
- ao2_lock(fe);
- ast_copy_string(buf, fe->exten, len);
- ao2_unlock(fe);
- ao2_ref(fe, -1);
- fe = NULL;
- }
-
- return 0;
+ return featuremap_get(cfg->featuremap, feature_name, buf, len);
}
/*!
@@ -4166,45 +4485,39 @@
}
res = 0;
- ast_rdlock_call_features();
if (ast_test_flag(flags, AST_FEATURE_REDIRECT)) {
+ if (!builtin_feature_get_exten(chan, "blindxfer", dtmf, sizeof(dtmf))
+ && !ast_strlen_zero(dtmf)) {
/* Add atxfer and blind transfer. */
- builtin_feature_get_exten(chan, "blindxfer", dtmf, sizeof(dtmf));
- if (!ast_strlen_zero(dtmf)) {
/* BUGBUG need to supply a blind transfer structure and destructor to use other than defaults */
res |= ast_bridge_features_enable(features, AST_BRIDGE_BUILTIN_BLINDTRANSFER, dtmf, NULL, NULL, 1);
}
- builtin_feature_get_exten(chan, "atxfer", dtmf, sizeof(dtmf));
- if (!ast_strlen_zero(dtmf)) {
+ if (!builtin_feature_get_exten(chan, "atxfer", dtmf, sizeof(dtmf)) &&
+ !ast_strlen_zero(dtmf)) {
/* BUGBUG need to supply an attended transfer structure and destructor to use other than defaults */
res |= ast_bridge_features_enable(features, AST_BRIDGE_BUILTIN_ATTENDEDTRANSFER, dtmf, NULL, NULL, 1);
}
}
- if (ast_test_flag(flags, AST_FEATURE_DISCONNECT)) {
- builtin_feature_get_exten(chan, "disconnect", dtmf, sizeof(dtmf));
- if (ast_strlen_zero(dtmf)) {
- res |= ast_bridge_features_enable(features, AST_BRIDGE_BUILTIN_HANGUP, dtmf, NULL, NULL, 1);
- }
- }
- if (ast_test_flag(flags, AST_FEATURE_PARKCALL)) {
- builtin_feature_get_exten(chan, "parkcall", dtmf, sizeof(dtmf));
- if (!ast_strlen_zero(dtmf)) {
- res |= ast_bridge_features_enable(features, AST_BRIDGE_BUILTIN_PARKCALL, dtmf, NULL, NULL, 1);
- }
- }
- if (ast_test_flag(flags, AST_FEATURE_AUTOMON)) {
- builtin_feature_get_exten(chan, "automon", dtmf, sizeof(dtmf));
- if (!ast_strlen_zero(dtmf)) {
- res |= ast_bridge_features_enable(features, AST_BRIDGE_BUILTIN_AUTOMON, dtmf, NULL, NULL, 1);
- }
- }
- if (ast_test_flag(flags, AST_FEATURE_AUTOMIXMON)) {
- builtin_feature_get_exten(chan, "automixmon", dtmf, sizeof(dtmf));
- if (!ast_strlen_zero(dtmf)) {
- res |= ast_bridge_features_enable(features, AST_BRIDGE_BUILTIN_AUTOMIXMON, dtmf, NULL, NULL, 1);
- }
- }
- ast_unlock_call_features();
+ if (ast_test_flag(flags, AST_FEATURE_DISCONNECT) &&
+ !builtin_feature_get_exten(chan, "disconnect", dtmf, sizeof(dtmf)) &&
+ !ast_strlen_zero(dtmf)) {
+ res |= ast_bridge_features_enable(features, AST_BRIDGE_BUILTIN_HANGUP, dtmf, NULL, NULL, 1);
+ }
+ if (ast_test_flag(flags, AST_FEATURE_PARKCALL) &&
+ !builtin_feature_get_exten(chan, "parkcall", dtmf, sizeof(dtmf)) &&
+ !ast_strlen_zero(dtmf)) {
+ res |= ast_bridge_features_enable(features, AST_BRIDGE_BUILTIN_PARKCALL, dtmf, NULL, NULL, 1);
+ }
+ if (ast_test_flag(flags, AST_FEATURE_AUTOMON) &&
+ !builtin_feature_get_exten(chan, "automon", dtmf, sizeof(dtmf)) &&
+ !ast_strlen_zero(dtmf)) {
+ res |= ast_bridge_features_enable(features, AST_BRIDGE_BUILTIN_AUTOMON, dtmf, NULL, NULL, 1);
+ }
+ if (ast_test_flag(flags, AST_FEATURE_AUTOMIXMON) &&
+ !builtin_feature_get_exten(chan, "automixmon", dtmf, sizeof(dtmf)) &&
+ !ast_strlen_zero(dtmf)) {
+ res |= ast_bridge_features_enable(features, AST_BRIDGE_BUILTIN_AUTOMIXMON, dtmf, NULL, NULL, 1);
+ }
#if 0 /* BUGBUG don't report errors untill all of the builtin features are supported. */
return res ? -1 : 0;
@@ -6405,174 +6718,35 @@
return 0;
}
-struct features_global_config {
- struct ast_features_general_config *general;
- struct ast_features_xfer_config *xfer;
- struct ast_features_pickup_config *pickup;
-};
-
-struct features_featuremap {
- AST_DECLARE_STRING_FIELDS (
- AST_STRING_FIELD(blindxfer);
- AST_STRING_FIELD(disconnect);
- AST_STRING_FIELD(automon);
- AST_STRING_FIELD(atxfer);
- AST_STRING_FIELD(parkcall);
- AST_STRING_FIELD(automixmon);
- );
-};
-
-struct features_applicationmap {
- /* XXX STUB */
-};
-
-struct features_config {
- struct features_global_config *global;
- struct features_featuremap *featuremap;
- struct features_applicationmap *applicationmap;
-};
-
-static struct aco_type global_option = {
- .type = ACO_GLOBAL,
- .name = "globals",
- .category_match = ACO_WHITELIST,
- .category = "^general$",
- .item_offset = offsetof(struct features_config, global),
-};
-
-static struct aco_type featuremap_option = {
- .type = ACO_GLOBAL,
- .name = "featuremap",
- .category_match = ACO_WHITELIST,
- .category = "^featuremap$",
- .item_offset = offsetof(struct features_config, featuremap),
-};
-
-static struct aco_type applicationmap_option = {
- .type = ACO_GLOBAL,
- .name = "applicationmap",
- .category_match = ACO_WHITELIST,
- .category = "^applicationmap$",
- .item_offset = offsetof(struct features_config, applicationmap),
-};
-
-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_file features_conf = {
- .filename = "features.conf",
- .types = ACO_TYPES(&global_option, &featuremap_option, &applicationmap_option),
-};
-
-AO2_GLOBAL_OBJ_STATIC(globals);
-
-static void features_config_destructor(void *obj)
-{
- struct features_config *cfg = obj;
-
- ao2_cleanup(cfg->global);
- ao2_cleanup(cfg->featuremap);
- ao2_cleanup(cfg->applicationmap);
-}
-
-static void featuremap_config_destructor(void *obj)
-{
- struct features_featuremap *cfg = obj;
-
- ast_string_field_free_memory(cfg);
-}
-
-static void applicationmap_config_destructor (void *obj)
-{
- /* XXX STUB */
-}
-
-static void global_config_destructor(void *obj)
-{
- struct features_global_config *cfg = obj;
-
- ao2_cleanup(cfg->general);
- ao2_cleanup(cfg->xfer);
- ao2_cleanup(cfg->pickup);
-}
-
-static void xfer_destructor(void *obj)
-{
- struct ast_features_xfer_config *cfg = obj;
-
- ast_string_field_free_memory(cfg);
-}
-
-static void pickup_destructor(void *obj)
-{
- struct ast_features_pickup_config *cfg = obj;
-
- ast_string_field_free_memory(cfg);
-}
-
-static struct features_global_config *global_config_alloc(void)
-{
- RAII_VAR(struct features_global_config *, cfg, NULL, ao2_cleanup);
-
- cfg = ao2_alloc(sizeof(*cfg), global_config_destructor);
+struct ast_features_general_config *ast_get_features_general_config(void)
+{
+ RAII_VAR(struct features_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
+
if (!cfg) {
return NULL;
}
- cfg->general = ao2_alloc(sizeof(*cfg->general), NULL);
- if (!cfg->general) {
- return NULL;
- }
-
- cfg->xfer = ao2_alloc(sizeof(*cfg->xfer), xfer_destructor);
- if (!cfg->xfer || ast_string_field_init(cfg->xfer, 32)) {
- return NULL;
- }
-
- cfg->pickup = ao2_alloc(sizeof(*cfg->pickup), pickup_destructor);
- if (!cfg->pickup || ast_string_field_init(cfg->pickup, 32)) {
- return NULL;
- }
-
- ao2_ref(cfg, +1);
- return cfg;
-}
-
-static void *features_config_alloc(void)
-{
- RAII_VAR(struct features_config *, cfg, NULL, ao2_cleanup);
-
- cfg = ao2_alloc(sizeof(*cfg), features_config_destructor);
+ ast_assert(cfg->global && cfg->global->general);
+
+ ao2_ref(cfg->global->general, +1);
+ return cfg->global->general;
+}
+
+struct ast_features_xfer_config *ast_get_features_xfer_config(void)
+{
+ RAII_VAR(struct features_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
+
if (!cfg) {
return NULL;
}
- cfg->global = global_config_alloc();;
- if (!cfg->global) {
- return NULL;
- }
-
- cfg->featuremap = ao2_alloc(sizeof(*cfg->featuremap), featuremap_config_destructor);
- if (!cfg->featuremap || ast_string_field_init(cfg->featuremap, 32)) {
- return NULL;
- }
-
- cfg->applicationmap = ao2_alloc(sizeof(*cfg->applicationmap),
- applicationmap_config_destructor);
- if (!cfg->applicationmap) {
- return NULL;
- }
-
- ao2_ref(cfg, +1);
- return cfg;
-}
-
-CONFIG_INFO_CORE("features", cfg_info, globals, features_config_alloc,
- .files = ACO_FILES(&features_conf),
-);
-
-struct ast_features_general_config *ast_get_features_general_config(void)
+ ast_assert(cfg->global && cfg->global->xfer);
+
+ ao2_ref(cfg->global->xfer, +1);
+ return cfg->global->xfer;
+}
+
+struct ast_features_pickup_config *ast_get_features_pickup_config(void)
{
RAII_VAR(struct features_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
@@ -6580,34 +6754,6 @@
return NULL;
}
- ast_assert(cfg->global && cfg->global->general);
-
- ao2_ref(cfg->global->general, +1);
- return cfg->global->general;
-}
-
-struct ast_features_xfer_config *ast_get_features_xfer_config(void)
-{
- RAII_VAR(struct features_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
-
- if (!cfg) {
- return NULL;
- }
-
- ast_assert(cfg->global && cfg->global->xfer);
-
- ao2_ref(cfg->global->xfer, +1);
- return cfg->global->xfer;
-}
-
-struct ast_features_pickup_config *ast_get_features_pickup_config(void)
-{
- RAII_VAR(struct features_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
-
- if (!cfg) {
- return NULL;
- }
-
ast_assert(cfg->global && cfg->global->pickup);
ao2_ref(cfg->global->pickup, +1);
@@ -6626,13 +6772,8 @@
{
struct features_global_config *global = obj;
struct ast_features_general_config *general = global->general;
-
- if (!strcasecmp(var->name, "featuredigittimeout")) {
- return ast_parse_arg(var->value, PARSE_INT32, &general->featuredigittimeout);
- } else {
- /* Unrecognized option */
- return -1;
- }
+
+ return general_set(general, var->name, var->value);
}
static int xfer_handler(const struct aco_option *opt,
@@ -6641,27 +6782,7 @@
struct features_global_config *global = obj;
struct ast_features_xfer_config *xfer = global->xfer;
- if (!strcasecmp(var->name, "transferdigittimeout")) {
- return ast_parse_arg(var->value, PARSE_INT32, &xfer->transferdigittimeout);
- } else if (!strcasecmp(var->name, "atxfernoanswertimeout")) {
- return ast_parse_arg(var->value, PARSE_INT32, &xfer->atxfernoanswertimeout);
- } else if (!strcasecmp(var->name, "atxferloopdelay")) {
- return ast_parse_arg(var->value, PARSE_INT32, &xfer->atxferloopdelay);
- } else if (!strcasecmp(var->name, "atxfercallbackretries")) {
- return ast_parse_arg(var->value, PARSE_INT32, &xfer->atxfercallbackretries);
- } else if (!strcasecmp(var->name, "atxferdropcall")) {
- xfer->atxferdropcall = ast_true(var->value);
- return 0;
- } else if (!strcasecmp(var->name, "xfersound")) {
- ast_string_field_set(xfer, xfersound, var->value);
- return 0;
- } else if (!strcasecmp(var->name, "xferfailsound")) {
- ast_string_field_set(xfer, xferfailsound, var->value);
- return 0;
- } else {
- /* Unrecognized option */
- return -1;
- }
+ return xfer_set(xfer, var->name, var->value);
}
static int pickup_handler(const struct aco_option *opt,
@@ -6670,19 +6791,15 @@
struct features_global_config *global = obj;
struct ast_features_pickup_config *pickup = global->pickup;
- if (!strcasecmp(var->name, "pickupsound")) {
- ast_string_field_set(pickup, pickupsound, var->value);
- return 0;
- } else if (!strcasecmp(var->name, "pickupfailsound")) {
- ast_string_field_set(pickup, pickupfailsound, var->value);
- return 0;
- } else if (!strcasecmp(var->name, "pickupexten")) {
- ast_string_field_set(pickup, pickupexten, var->value);
- return 0;
- } else {
- /* Unrecognized option */
- return -1;
- }
+ return pickup_set(pickup, var->name, var->value);
+}
+
+static int featuremap_handler(const struct aco_option *opt,
+ struct ast_variable *var, void *obj)
+{
+ struct features_featuremap *featuremap = obj;
+
+ return featuremap_set(featuremap, var->name, var->value);
}
static int really_load_config(int reload)
@@ -6717,18 +6834,18 @@
aco_option_register_custom(&cfg_info, "pickupfailsound", ACO_EXACT, global_options,
"", pickup_handler, 0);
- aco_option_register(&cfg_info, "blindxfer", ACO_EXACT, featuremap_options,
- "#", OPT_STRINGFIELD_T, 0, STRFLDSET(struct features_featuremap, blindxfer));
- aco_option_register(&cfg_info, "disconnect", ACO_EXACT, featuremap_options,
- "*", OPT_STRINGFIELD_T, 0, STRFLDSET(struct features_featuremap, disconnect));
- aco_option_register(&cfg_info, "automon", ACO_EXACT, featuremap_options,
- "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct features_featuremap, automon));
- aco_option_register(&cfg_info, "atxfer", ACO_EXACT, featuremap_options,
- "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct features_featuremap, atxfer));
- aco_option_register(&cfg_info, "parkcall", ACO_EXACT, featuremap_options,
- "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct features_featuremap, parkcall));
- aco_option_register(&cfg_info, "automixmon", ACO_EXACT, featuremap_options,
- "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct features_featuremap, automixmon));
+ aco_option_register_custom(&cfg_info, "blindxfer", ACO_EXACT, featuremap_options,
+ "#", featuremap_handler, 0);
+ aco_option_register_custom(&cfg_info, "disconnect", ACO_EXACT, featuremap_options,
+ "*", featuremap_handler, 0);
+ aco_option_register_custom(&cfg_info, "automon", ACO_EXACT, featuremap_options,
+ "", featuremap_handler, 0);
+ aco_option_register_custom(&cfg_info, "atxfer", ACO_EXACT, featuremap_options,
+ "", featuremap_handler, 0);
+ aco_option_register_custom(&cfg_info, "parkcall", ACO_EXACT, featuremap_options,
+ "", featuremap_handler, 0);
+ aco_option_register_custom(&cfg_info, "automixmon", ACO_EXACT, featuremap_options,
+ "", featuremap_handler, 0);
/* XXX This regex may need to be more specific */
aco_option_register_custom(&cfg_info, "^.*$", ACO_REGEX, applicationmap_options,
@@ -8333,69 +8450,32 @@
}
#endif /* defined(TEST_FRAMEWORK) */
-/*!
- * \internal
- * \brief Get parkingtime for a channel
- */
-static unsigned int get_parkingtime(struct ast_channel *chan, struct ast_parkinglot *parkinglot)
-{
- const char *parkinglot_name;
- struct feature_datastore *feature_ds;
- unsigned int parkingtime;
-
- ast_channel_lock(chan);
-
- feature_ds = get_feature_ds(chan);
- if (feature_ds && feature_ds->parkingtime_is_set) {
- parkingtime = feature_ds->parkingtime;
- ast_channel_unlock(chan);
- return parkingtime;
- }
-
- parkinglot_name = ast_strdupa(S_OR(ast_channel_parkinglot(chan), ""));
-
- ast_channel_unlock(chan);
-
- if (!parkinglot) {
- if (!ast_strlen_zero(parkinglot_name)) {
- parkinglot = find_parkinglot(parkinglot_name);
- }
-
- if (!parkinglot) {
- parkinglot = parkinglot_addref(default_parkinglot);
- }
- } else {
- /* Just to balance the unref below */
- parkinglot_addref(parkinglot);
- }
-
- parkingtime = parkinglot->cfg.parkingtime;
-
- parkinglot_unref(parkinglot);
-
- return parkingtime;
-}
-
static int feature_read(struct ast_channel *chan, const char *cmd, char *data,
char *buf, size_t len)
{
- int res = 0;
-
- 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);
+ 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");
- } else {
+ 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);
- res = -1;
}
return res;
@@ -8404,37 +8484,29 @@
static int feature_write(struct ast_channel *chan, const char *cmd, char *data,
const char *value)
{
- int res = 0;
- struct feature_datastore *feature_ds;
-
- ast_channel_lock(chan);
-
- if (!(feature_ds = get_feature_ds(chan))) {
- res = -1;
- goto return_cleanup;
- }
-
- if (!strcasecmp(data, "parkingtime")) {
- feature_ds->parkingtime_is_set = 1;
- if (sscanf(value, "%30u", &feature_ds->parkingtime) == 1) {
- feature_ds->parkingtime *= 1000; /* stored in ms */
- } else {
- ast_log(LOG_WARNING, "'%s' is not a valid parkingtime\n", value);
- feature_ds->parkingtime_is_set = 0;
- res = -1;
- }
- } else if (!strcasecmp(data, "inherit")) {
- struct ast_datastore *ds;
- if ((ds = get_feature_chan_ds(chan))) {
+ 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;
}
- } else {
+ 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);
- res = -1;
- }
-
-return_cleanup:
- ast_channel_unlock(chan);
+ }
return res;
}
@@ -8444,13 +8516,11 @@
{
int res;
- ast_rdlock_call_features();
-
- if ((res = builtin_feature_get_exten(chan, data, buf, len))) {
+ res = builtin_feature_get_exten(chan, data, buf, len);
+
+ if (res) {
ast_log(LOG_WARNING, "Invalid argument '%s' to FEATUREMAP()\n", data);
}
-
- ast_unlock_call_features();
return res;
}
@@ -8458,41 +8528,19 @@
static int featuremap_write(struct ast_channel *chan, const char *cmd, char *data,
const char *value)
{
- struct feature_datastore *feature_ds;
- struct feature_exten *fe;
- struct ast_call_feature *feat;
-
- ast_rdlock_call_features();
- feat = ast_find_call_feature(data);
- ast_unlock_call_features();
- if (!feat) {
+ 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;
}
-
- ast_channel_lock(chan);
-
- if (!(feature_ds = get_feature_ds(chan))) {
- ast_channel_unlock(chan);
- return -1;
- }
-
- if (!(fe = ao2_find(feature_ds->feature_map, data, OBJ_KEY))) {
- if (!(fe = ao2_alloc(sizeof(*fe), NULL))) {
- ast_channel_unlock(chan);
- return -1;
- }
- ast_copy_string(fe->sname, data, sizeof(fe->sname));
- ao2_link(feature_ds->feature_map, fe);
- }
-
- ast_channel_unlock(chan);
-
- ao2_lock(fe);
- ast_copy_string(fe->exten, value, sizeof(fe->exten));
- ao2_unlock(fe);
- ao2_ref(fe, -1);
- fe = NULL;
return 0;
}
More information about the asterisk-commits
mailing list