|
|
|
@ -109,6 +109,15 @@ struct ast_sorcery_object_wizard {
|
|
|
|
|
|
|
|
|
|
/*! \brief Wizard is acting as an object cache */
|
|
|
|
|
unsigned int caching:1;
|
|
|
|
|
|
|
|
|
|
/*! \brief Wizard is read_only */
|
|
|
|
|
unsigned int read_only:1;
|
|
|
|
|
|
|
|
|
|
/*! \brief Wizard allows others of the same type */
|
|
|
|
|
unsigned int allow_duplicates:1;
|
|
|
|
|
|
|
|
|
|
/*! \brief Wizard arguments */
|
|
|
|
|
char wizard_args[0];
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/*! \brief Interface for a sorcery object type wizards */
|
|
|
|
@ -802,6 +811,35 @@ int ast_sorcery_get_wizard_mapping(struct ast_sorcery *sorcery,
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int __ast_sorcery_object_type_remove_wizard(struct ast_sorcery *sorcery,
|
|
|
|
|
const char *object_type_name, const char *module, const char *wizard_type_name,
|
|
|
|
|
const char *wizard_args)
|
|
|
|
|
{
|
|
|
|
|
RAII_VAR(struct ast_sorcery_object_type *, object_type,
|
|
|
|
|
ao2_find(sorcery->types, object_type_name, OBJ_SEARCH_KEY), ao2_cleanup);
|
|
|
|
|
int res = -1;
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
if (!object_type) {
|
|
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
AST_VECTOR_RW_WRLOCK(&object_type->wizards);
|
|
|
|
|
for (i = 0; i < AST_VECTOR_SIZE(&object_type->wizards); i++) {
|
|
|
|
|
struct ast_sorcery_object_wizard *wizard = AST_VECTOR_GET(&object_type->wizards, i);
|
|
|
|
|
|
|
|
|
|
if (strcmp(wizard->wizard->callbacks.name, wizard_type_name) == 0
|
|
|
|
|
&& strcmp(S_OR(wizard->wizard_args, ""), S_OR(wizard_args, "")) == 0) {
|
|
|
|
|
ao2_cleanup(AST_VECTOR_REMOVE_ORDERED(&object_type->wizards, i));
|
|
|
|
|
res = 0;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
AST_VECTOR_RW_UNLOCK(&object_type->wizards);
|
|
|
|
|
|
|
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*! \brief Internal function removes a wizard mapping */
|
|
|
|
|
int __ast_sorcery_remove_wizard_mapping(struct ast_sorcery *sorcery,
|
|
|
|
|
const char *type, const char *module, const char *name)
|
|
|
|
@ -822,29 +860,35 @@ int __ast_sorcery_remove_wizard_mapping(struct ast_sorcery *sorcery,
|
|
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*! \brief Internal function which creates an object type and inserts a wizard mapping */
|
|
|
|
|
enum ast_sorcery_apply_result __ast_sorcery_insert_wizard_mapping(struct ast_sorcery *sorcery,
|
|
|
|
|
const char *type, const char *module, const char *name, const char *data,
|
|
|
|
|
unsigned int caching, int position)
|
|
|
|
|
enum ast_sorcery_apply_result __ast_sorcery_object_type_insert_wizard(struct ast_sorcery *sorcery,
|
|
|
|
|
const char *object_type_name, const char *module, const char *wizard_type_name,
|
|
|
|
|
const char *wizard_args, enum ast_sorcery_wizard_apply_flags flags, int position,
|
|
|
|
|
struct ast_sorcery_wizard **wizard, void **wizard_data)
|
|
|
|
|
{
|
|
|
|
|
RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, type, OBJ_KEY), ao2_cleanup);
|
|
|
|
|
RAII_VAR(struct ast_sorcery_internal_wizard *, wizard, ao2_find(wizards, name, OBJ_KEY), ao2_cleanup);
|
|
|
|
|
RAII_VAR(struct ast_sorcery_object_wizard *, object_wizard, ao2_alloc(sizeof(*object_wizard), sorcery_object_wizard_destructor), ao2_cleanup);
|
|
|
|
|
RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, object_type_name, OBJ_KEY), ao2_cleanup);
|
|
|
|
|
RAII_VAR(struct ast_sorcery_internal_wizard *, internal_wizard, ao2_find(wizards, wizard_type_name, OBJ_KEY), ao2_cleanup);
|
|
|
|
|
RAII_VAR(struct ast_sorcery_object_wizard *, object_wizard, NULL, ao2_cleanup);
|
|
|
|
|
int created = 0;
|
|
|
|
|
|
|
|
|
|
object_wizard = ao2_alloc(sizeof(*object_wizard)
|
|
|
|
|
+ (ast_strlen_zero(wizard_args) ? 0 : strlen(wizard_args) + 1),
|
|
|
|
|
sorcery_object_wizard_destructor);
|
|
|
|
|
|
|
|
|
|
if (!object_wizard) {
|
|
|
|
|
return AST_SORCERY_APPLY_FAIL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!wizard || wizard->callbacks.module != ast_module_running_ref(wizard->callbacks.module)) {
|
|
|
|
|
ast_log(LOG_ERROR, "Wizard '%s' could not be applied to object type '%s' as it was not found\n",
|
|
|
|
|
name, type);
|
|
|
|
|
if (!internal_wizard
|
|
|
|
|
|| internal_wizard->callbacks.module != ast_module_running_ref(internal_wizard->callbacks.module)) {
|
|
|
|
|
ast_log(LOG_ERROR,
|
|
|
|
|
"Wizard '%s' could not be applied to object type '%s' as it was not found\n",
|
|
|
|
|
wizard_type_name, object_type_name);
|
|
|
|
|
return AST_SORCERY_APPLY_FAIL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!object_type) {
|
|
|
|
|
if (!(object_type = sorcery_object_type_alloc(type, module))) {
|
|
|
|
|
ast_module_unref(wizard->callbacks.module);
|
|
|
|
|
if (!(object_type = sorcery_object_type_alloc(object_type_name, module))) {
|
|
|
|
|
ast_module_unref(internal_wizard->callbacks.module);
|
|
|
|
|
return AST_SORCERY_APPLY_FAIL;
|
|
|
|
|
}
|
|
|
|
|
created = 1;
|
|
|
|
@ -855,29 +899,34 @@ enum ast_sorcery_apply_result __ast_sorcery_insert_wizard_mapping(struct ast_sor
|
|
|
|
|
struct ast_sorcery_object_wizard *found;
|
|
|
|
|
|
|
|
|
|
#define WIZARD_COMPARE(a, b) ((a)->wizard == (b))
|
|
|
|
|
found = AST_VECTOR_GET_CMP(&object_type->wizards, wizard, WIZARD_COMPARE);
|
|
|
|
|
found = AST_VECTOR_GET_CMP(&object_type->wizards, internal_wizard, WIZARD_COMPARE);
|
|
|
|
|
#undef WIZARD_COMPARE
|
|
|
|
|
if (found) {
|
|
|
|
|
if (found
|
|
|
|
|
&& !((flags & AST_SORCERY_WIZARD_APPLY_ALLOW_DUPLICATE) || found->allow_duplicates)) {
|
|
|
|
|
ast_debug(1, "Wizard %s already applied to object type %s\n",
|
|
|
|
|
wizard->callbacks.name, object_type->name);
|
|
|
|
|
internal_wizard->callbacks.name, object_type->name);
|
|
|
|
|
AST_VECTOR_RW_UNLOCK(&object_type->wizards);
|
|
|
|
|
ast_module_unref(wizard->callbacks.module);
|
|
|
|
|
ast_module_unref(internal_wizard->callbacks.module);
|
|
|
|
|
return AST_SORCERY_APPLY_DUPLICATE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ast_debug(5, "Calling wizard %s open callback on object type %s\n",
|
|
|
|
|
name, object_type->name);
|
|
|
|
|
if (wizard->callbacks.open && !(object_wizard->data = wizard->callbacks.open(data))) {
|
|
|
|
|
wizard_type_name, object_type->name);
|
|
|
|
|
if (internal_wizard->callbacks.open && !(object_wizard->data = internal_wizard->callbacks.open(wizard_args))) {
|
|
|
|
|
ast_log(LOG_WARNING, "Wizard '%s' failed to open mapping for object type '%s' with data: %s\n",
|
|
|
|
|
name, object_type->name, S_OR(data, ""));
|
|
|
|
|
wizard_type_name, object_type->name, S_OR(wizard_args, ""));
|
|
|
|
|
AST_VECTOR_RW_UNLOCK(&object_type->wizards);
|
|
|
|
|
ast_module_unref(wizard->callbacks.module);
|
|
|
|
|
ast_module_unref(internal_wizard->callbacks.module);
|
|
|
|
|
return AST_SORCERY_APPLY_FAIL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
object_wizard->wizard = ao2_bump(wizard);
|
|
|
|
|
object_wizard->caching = caching;
|
|
|
|
|
object_wizard->wizard = ao2_bump(internal_wizard);
|
|
|
|
|
object_wizard->caching = !!(flags & AST_SORCERY_WIZARD_APPLY_CACHING);
|
|
|
|
|
object_wizard->read_only = !!(flags & AST_SORCERY_WIZARD_APPLY_READONLY);
|
|
|
|
|
if (wizard_args) {
|
|
|
|
|
strcpy(object_wizard->wizard_args, wizard_args); /* Safe */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (position == AST_SORCERY_WIZARD_POSITION_LAST) {
|
|
|
|
|
position = AST_VECTOR_SIZE(&object_type->wizards);
|
|
|
|
@ -895,17 +944,36 @@ enum ast_sorcery_apply_result __ast_sorcery_insert_wizard_mapping(struct ast_sor
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NOTIFY_INSTANCE_OBSERVERS(sorcery->observers, wizard_mapped,
|
|
|
|
|
sorcery->module_name, sorcery, type, &wizard->callbacks, data, object_wizard->data);
|
|
|
|
|
sorcery->module_name, sorcery, object_type_name, &internal_wizard->callbacks, wizard_args,
|
|
|
|
|
object_wizard->data);
|
|
|
|
|
|
|
|
|
|
if (wizard) {
|
|
|
|
|
*wizard = &internal_wizard->callbacks;
|
|
|
|
|
}
|
|
|
|
|
if (wizard_data) {
|
|
|
|
|
*wizard_data = object_wizard->data;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return AST_SORCERY_APPLY_SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*! \brief Internal function which creates an object type and inserts a wizard mapping */
|
|
|
|
|
enum ast_sorcery_apply_result __ast_sorcery_insert_wizard_mapping(struct ast_sorcery *sorcery,
|
|
|
|
|
const char *object_type_name, const char *module, const char *wizard_type_name,
|
|
|
|
|
const char *wizard_args, unsigned int caching, int position)
|
|
|
|
|
{
|
|
|
|
|
return __ast_sorcery_object_type_insert_wizard(sorcery, object_type_name, module, wizard_type_name,
|
|
|
|
|
wizard_args, caching ? AST_SORCERY_WIZARD_APPLY_CACHING : AST_SORCERY_WIZARD_APPLY_NONE,
|
|
|
|
|
position, NULL, NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*! \brief Internal function which creates an object type and adds a wizard mapping */
|
|
|
|
|
enum ast_sorcery_apply_result __ast_sorcery_apply_wizard_mapping(struct ast_sorcery *sorcery,
|
|
|
|
|
const char *type, const char *module, const char *name, const char *data, unsigned int caching)
|
|
|
|
|
const char *object_type_name, const char *module, const char *wizard_type_name,
|
|
|
|
|
const char *wizard_args, unsigned int caching)
|
|
|
|
|
{
|
|
|
|
|
return __ast_sorcery_insert_wizard_mapping(sorcery, type, module, name, data,
|
|
|
|
|
caching, AST_SORCERY_WIZARD_POSITION_LAST);
|
|
|
|
|
return __ast_sorcery_insert_wizard_mapping(sorcery, object_type_name, module, wizard_type_name,
|
|
|
|
|
wizard_args, caching, AST_SORCERY_WIZARD_POSITION_LAST);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
enum ast_sorcery_apply_result __ast_sorcery_apply_config(struct ast_sorcery *sorcery, const char *name, const char *module)
|
|
|
|
@ -1904,7 +1972,7 @@ struct ao2_container *ast_sorcery_retrieve_by_prefix(const struct ast_sorcery *s
|
|
|
|
|
/*! \brief Internal function which returns if the wizard has created the object */
|
|
|
|
|
static int sorcery_wizard_create(const struct ast_sorcery_object_wizard *object_wizard, const struct sorcery_details *details)
|
|
|
|
|
{
|
|
|
|
|
if (!object_wizard->wizard->callbacks.create) {
|
|
|
|
|
if (!object_wizard->wizard->callbacks.create || object_wizard->read_only) {
|
|
|
|
|
ast_debug(5, "Sorcery wizard '%s' does not support creation\n", object_wizard->wizard->callbacks.name);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
@ -2015,7 +2083,7 @@ static int sorcery_observers_notify_update(void *data)
|
|
|
|
|
/*! \brief Internal function which returns if a wizard has updated the object */
|
|
|
|
|
static int sorcery_wizard_update(const struct ast_sorcery_object_wizard *object_wizard, const struct sorcery_details *details)
|
|
|
|
|
{
|
|
|
|
|
if (!object_wizard->wizard->callbacks.update) {
|
|
|
|
|
if (!object_wizard->wizard->callbacks.update || object_wizard->read_only) {
|
|
|
|
|
ast_debug(5, "Sorcery wizard '%s' does not support updating\n", object_wizard->wizard->callbacks.name);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
@ -2103,7 +2171,7 @@ static int sorcery_observers_notify_delete(void *data)
|
|
|
|
|
/*! \brief Internal function which returns if a wizard has deleted the object */
|
|
|
|
|
static int sorcery_wizard_delete(const struct ast_sorcery_object_wizard *object_wizard, const struct sorcery_details *details)
|
|
|
|
|
{
|
|
|
|
|
if (!object_wizard->wizard->callbacks.delete) {
|
|
|
|
|
if (!object_wizard->wizard->callbacks.delete || object_wizard->read_only) {
|
|
|
|
|
ast_debug(5, "Sorcery wizard '%s' does not support deletion\n", object_wizard->wizard->callbacks.name);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|