summaryrefslogtreecommitdiff
path: root/main/sorcery.c
diff options
context:
space:
mode:
Diffstat (limited to 'main/sorcery.c')
-rw-r--r--main/sorcery.c136
1 files changed, 120 insertions, 16 deletions
diff --git a/main/sorcery.c b/main/sorcery.c
index 99e4c5586..cf4cd0213 100644
--- a/main/sorcery.c
+++ b/main/sorcery.c
@@ -58,6 +58,21 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
/*! \brief Thread pool for observers */
static struct ast_threadpool *threadpool;
+/*! \brief Structure for internal sorcery object information */
+struct ast_sorcery_object {
+ /*! \brief Unique identifier of this object */
+ char id[AST_UUID_STR_LEN];
+
+ /*! \brief Type of object */
+ char type[MAX_OBJECT_TYPE];
+
+ /*! \brief Optional object destructor */
+ ao2_destructor_fn destructor;
+
+ /*! \brief Extended object fields */
+ struct ast_variable *extended;
+};
+
/*! \brief Structure for registered object type */
struct ast_sorcery_object_type {
/*! \brief Unique name of the object type */
@@ -525,6 +540,24 @@ int __ast_sorcery_apply_default(struct ast_sorcery *sorcery, const char *type, c
return sorcery_apply_wizard_mapping(sorcery, type, module, name, data, 0);
}
+static int sorcery_extended_config_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
+{
+ return ast_sorcery_object_set_extended(obj, var->name, var->value);
+}
+
+static int sorcery_extended_fields_handler(const void *obj, struct ast_variable **fields)
+{
+ const struct ast_sorcery_object_details *details = obj;
+
+ if (details->object->extended) {
+ *fields = ast_variables_dup(details->object->extended);
+ } else {
+ *fields = NULL;
+ }
+
+ return 0;
+}
+
int ast_sorcery_object_register(struct ast_sorcery *sorcery, const char *type, aco_type_item_alloc alloc, sorcery_transform_handler transform, sorcery_apply_handler apply)
{
RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, type, OBJ_KEY), ao2_cleanup);
@@ -547,6 +580,10 @@ int ast_sorcery_object_register(struct ast_sorcery *sorcery, const char *type, a
return -1;
}
+ if (ast_sorcery_object_fields_register(sorcery, type, "^@", sorcery_extended_config_handler, sorcery_extended_fields_handler)) {
+ return -1;
+ }
+
return 0;
}
@@ -784,7 +821,7 @@ void ast_sorcery_ref(struct ast_sorcery *sorcery)
struct ast_variable *ast_sorcery_objectset_create(const struct ast_sorcery *sorcery, const void *object)
{
const struct ast_sorcery_object_details *details = object;
- RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, details->type, OBJ_KEY), ao2_cleanup);
+ RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, details->object->type, OBJ_KEY), ao2_cleanup);
struct ao2_iterator i;
struct ast_sorcery_object_field *object_field;
struct ast_variable *fields = NULL;
@@ -816,7 +853,7 @@ struct ast_variable *ast_sorcery_objectset_create(const struct ast_sorcery *sorc
continue;
}
- if (!res) {
+ if (!res && tmp) {
tmp->next = fields;
fields = tmp;
}
@@ -836,7 +873,7 @@ struct ast_variable *ast_sorcery_objectset_create(const struct ast_sorcery *sorc
struct ast_json *ast_sorcery_objectset_json_create(const struct ast_sorcery *sorcery, const void *object)
{
const struct ast_sorcery_object_details *details = object;
- RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, details->type, OBJ_KEY), ao2_cleanup);
+ RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, details->object->type, OBJ_KEY), ao2_cleanup);
struct ao2_iterator i;
struct ast_sorcery_object_field *object_field;
struct ast_json *json = ast_json_object_create();
@@ -898,7 +935,7 @@ struct ast_json *ast_sorcery_objectset_json_create(const struct ast_sorcery *sor
int ast_sorcery_objectset_apply(const struct ast_sorcery *sorcery, void *object, struct ast_variable *objectset)
{
const struct ast_sorcery_object_details *details = object;
- RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, details->type, OBJ_KEY), ao2_cleanup);
+ RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, details->object->type, OBJ_KEY), ao2_cleanup);
RAII_VAR(struct ast_variable *, transformed, NULL, ast_variables_destroy);
struct ast_variable *field;
int res = 0;
@@ -914,7 +951,7 @@ int ast_sorcery_objectset_apply(const struct ast_sorcery *sorcery, void *object,
}
for (; field; field = field->next) {
- if ((res = aco_process_var(&object_type->type, details->id, field, object))) {
+ if ((res = aco_process_var(&object_type->type, details->object->id, field, object))) {
break;
}
}
@@ -977,6 +1014,32 @@ int ast_sorcery_changeset_create(const struct ast_variable *original, const stru
return res;
}
+static void sorcery_object_destructor(void *object)
+{
+ struct ast_sorcery_object_details *details = object;
+
+ if (details->object->destructor) {
+ details->object->destructor(object);
+ }
+
+ ast_variables_destroy(details->object->extended);
+}
+
+void *ast_sorcery_generic_alloc(size_t size, ao2_destructor_fn destructor)
+{
+ void *object = ao2_alloc_options(size + sizeof(struct ast_sorcery_object), sorcery_object_destructor, AO2_ALLOC_OPT_LOCK_NOLOCK);
+ struct ast_sorcery_object_details *details = object;
+
+ if (!object) {
+ return NULL;
+ }
+
+ details->object = object + size;
+ details->object->destructor = destructor;
+
+ return object;
+}
+
void *ast_sorcery_alloc(const struct ast_sorcery *sorcery, const char *type, const char *id)
{
RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, type, OBJ_KEY), ao2_cleanup);
@@ -988,12 +1051,12 @@ void *ast_sorcery_alloc(const struct ast_sorcery *sorcery, const char *type, con
}
if (ast_strlen_zero(id)) {
- ast_uuid_generate_str(details->id, sizeof(details->id));
+ ast_uuid_generate_str(details->object->id, sizeof(details->object->id));
} else {
- ast_copy_string(details->id, id, sizeof(details->id));
+ ast_copy_string(details->object->id, id, sizeof(details->object->id));
}
- ast_copy_string(details->type, type, sizeof(details->type));
+ ast_copy_string(details->object->type, type, sizeof(details->object->type));
if (aco_set_defaults(&object_type->type, id, details)) {
ao2_ref(details, -1);
@@ -1006,8 +1069,8 @@ void *ast_sorcery_alloc(const struct ast_sorcery *sorcery, const char *type, con
void *ast_sorcery_copy(const struct ast_sorcery *sorcery, const void *object)
{
const struct ast_sorcery_object_details *details = object;
- RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, details->type, OBJ_KEY), ao2_cleanup);
- struct ast_sorcery_object_details *copy = ast_sorcery_alloc(sorcery, details->type, details->id);
+ RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, details->object->type, OBJ_KEY), ao2_cleanup);
+ struct ast_sorcery_object_details *copy = ast_sorcery_alloc(sorcery, details->object->type, details->object->id);
RAII_VAR(struct ast_variable *, objectset, NULL, ast_variables_destroy);
int res = 0;
@@ -1120,7 +1183,6 @@ void *ast_sorcery_retrieve_by_fields(const struct ast_sorcery *sorcery, const ch
unsigned int cached = 0;
if (!object_type) {
- ast_log(LOG_NOTICE, "Can't find object type '%s'\n", type);
return NULL;
}
@@ -1222,7 +1284,7 @@ static int sorcery_observers_notify_create(void *data)
int ast_sorcery_create(const struct ast_sorcery *sorcery, void *object)
{
const struct ast_sorcery_object_details *details = object;
- RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, details->type, OBJ_KEY), ao2_cleanup);
+ RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, details->object->type, OBJ_KEY), ao2_cleanup);
RAII_VAR(struct ast_sorcery_object_wizard *, object_wizard, NULL, ao2_cleanup);
struct sorcery_details sdetails = {
.sorcery = sorcery,
@@ -1281,7 +1343,7 @@ static int sorcery_wizard_update(void *obj, void *arg, int flags)
int ast_sorcery_update(const struct ast_sorcery *sorcery, void *object)
{
const struct ast_sorcery_object_details *details = object;
- RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, details->type, OBJ_KEY), ao2_cleanup);
+ RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, details->object->type, OBJ_KEY), ao2_cleanup);
RAII_VAR(struct ast_sorcery_object_wizard *, object_wizard, NULL, ao2_cleanup);
struct sorcery_details sdetails = {
.sorcery = sorcery,
@@ -1340,7 +1402,7 @@ static int sorcery_wizard_delete(void *obj, void *arg, int flags)
int ast_sorcery_delete(const struct ast_sorcery *sorcery, void *object)
{
const struct ast_sorcery_object_details *details = object;
- RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, details->type, OBJ_KEY), ao2_cleanup);
+ RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, details->object->type, OBJ_KEY), ao2_cleanup);
RAII_VAR(struct ast_sorcery_object_wizard *, object_wizard, NULL, ao2_cleanup);
struct sorcery_details sdetails = {
.sorcery = sorcery,
@@ -1371,13 +1433,55 @@ void ast_sorcery_unref(struct ast_sorcery *sorcery)
const char *ast_sorcery_object_get_id(const void *object)
{
const struct ast_sorcery_object_details *details = object;
- return details->id;
+ return details->object->id;
}
const char *ast_sorcery_object_get_type(const void *object)
{
const struct ast_sorcery_object_details *details = object;
- return details->type;
+ return details->object->type;
+}
+
+const char *ast_sorcery_object_get_extended(const void *object, const char *name)
+{
+ const struct ast_sorcery_object_details *details = object;
+ struct ast_variable *field;
+
+ for (field = details->object->extended; field; field = field->next) {
+ if (!strcmp(field->name + 1, name)) {
+ return field->value;
+ }
+ }
+
+ return NULL;
+}
+
+int ast_sorcery_object_set_extended(const void *object, const char *name, const char *value)
+{
+ RAII_VAR(struct ast_variable *, field, NULL, ast_variables_destroy);
+ struct ast_variable *extended = ast_variable_new(name, value, ""), *previous = NULL;
+ const struct ast_sorcery_object_details *details = object;
+
+ if (!extended) {
+ return -1;
+ }
+
+ for (field = details->object->extended; field; previous = field, field = field->next) {
+ if (!strcmp(field->name, name)) {
+ if (previous) {
+ previous->next = field->next;
+ } else {
+ details->object->extended = field->next;
+ }
+ field->next = NULL;
+ break;
+ }
+ }
+
+ extended->next = details->object->extended;
+ details->object->extended = extended;
+
+ return 0;
}
int ast_sorcery_observer_add(const struct ast_sorcery *sorcery, const char *type, const struct ast_sorcery_observer *callbacks)