cf4cd02137ba42e1e8da68658fa151a977e78c08
[asterisk/asterisk.git] / main / sorcery.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2012 - 2013, Digium, Inc.
5  *
6  * Joshua Colp <jcolp@digium.com>
7  *
8  * See http://www.asterisk.org for more information about
9  * the Asterisk project. Please do not directly contact
10  * any of the maintainers of this project for assistance;
11  * the project provides a web site, mailing lists and IRC
12  * channels for your use.
13  *
14  * This program is free software, distributed under the terms of
15  * the GNU General Public License Version 2. See the LICENSE file
16  * at the top of the source tree.
17  */
18
19 /*! \file
20  *
21  * \brief Sorcery Data Access Layer API
22  *
23  * \author Joshua Colp <jcolp@digium.com>
24  */
25
26 /*** MODULEINFO
27         <support_level>core</support_level>
28  ***/
29
30 #include "asterisk.h"
31
32 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
33
34 #include "asterisk/logger.h"
35 #include "asterisk/sorcery.h"
36 #include "asterisk/astobj2.h"
37 #include "asterisk/strings.h"
38 #include "asterisk/config_options.h"
39 #include "asterisk/netsock2.h"
40 #include "asterisk/module.h"
41 #include "asterisk/taskprocessor.h"
42 #include "asterisk/threadpool.h"
43 #include "asterisk/json.h"
44
45 /* To prevent DEBUG_FD_LEAKS from interfering with things we undef open and close */
46 #undef open
47 #undef close
48
49 /*! \brief Number of buckets for wizards (should be prime for performance reasons) */
50 #define WIZARD_BUCKETS 7
51
52 /*! \brief Number of buckets for types (should be prime for performance reasons) */
53 #define TYPE_BUCKETS 53
54
55 /*! \brief Maximum length of an object field name */
56 #define MAX_OBJECT_FIELD 128
57
58 /*! \brief Thread pool for observers */
59 static struct ast_threadpool *threadpool;
60
61 /*! \brief Structure for internal sorcery object information */
62 struct ast_sorcery_object {
63         /*! \brief Unique identifier of this object */
64         char id[AST_UUID_STR_LEN];
65
66         /*! \brief Type of object */
67         char type[MAX_OBJECT_TYPE];
68
69         /*! \brief Optional object destructor */
70         ao2_destructor_fn destructor;
71
72         /*! \brief Extended object fields */
73         struct ast_variable *extended;
74 };
75
76 /*! \brief Structure for registered object type */
77 struct ast_sorcery_object_type {
78         /*! \brief Unique name of the object type */
79         char name[MAX_OBJECT_TYPE];
80
81         /*! \brief Optional transformation callback */
82         sorcery_transform_handler transform;
83
84         /*! \brief Optional object set apply callback */
85         sorcery_apply_handler apply;
86
87         /*! \brief Optional object copy callback */
88         sorcery_copy_handler copy;
89
90         /*! \brief Optional object diff callback */
91         sorcery_diff_handler diff;
92
93         /*! \brief Wizard instances */
94         struct ao2_container *wizards;
95
96         /*! \brief Object fields */
97         struct ao2_container *fields;
98
99         /*! \brief Configuration framework general information */
100         struct aco_info *info;
101
102         /*! \brief Configuration framework file information */
103         struct aco_file *file;
104
105         /*! \brief Type details */
106         struct aco_type type;
107
108         /*! \brief Observers */
109         struct ao2_container *observers;
110
111         /*! \brief Serializer for observers */
112         struct ast_taskprocessor *serializer;
113 };
114
115 /*! \brief Structure for registered object type observer */
116 struct ast_sorcery_object_type_observer {
117         /*! \brief Pointer to the observer implementation */
118         const struct ast_sorcery_observer *callbacks;
119 };
120
121 /*! \brief Structure used for observer invocations */
122 struct sorcery_observer_invocation {
123         /*! \brief Pointer to the object type */
124         struct ast_sorcery_object_type *object_type;
125
126         /*! \brief Pointer to the object */
127         void *object;
128 };
129
130 /*! \brief Structure for registered object field */
131 struct ast_sorcery_object_field {
132         /*! \brief Name of the field */
133         char name[MAX_OBJECT_FIELD];
134
135         /*! \brief Callback function for translation of a single value */
136         sorcery_field_handler handler;
137
138         /*! \brief Callback function for translation of multiple values */
139         sorcery_fields_handler multiple_handler;
140
141         /*! \brief Position of the field */
142         intptr_t args[];
143 };
144
145 /*! \brief Structure for a wizard instance which operates on objects */
146 struct ast_sorcery_object_wizard {
147         /*! \brief Wizard interface itself */
148         struct ast_sorcery_wizard *wizard;
149
150         /*! \brief Unique data for the wizard */
151         void *data;
152
153         /*! \brief Wizard is acting as an object cache */
154         unsigned int caching:1;
155 };
156
157 /*! \brief Full structure for sorcery */
158 struct ast_sorcery {
159         /*! \brief Container for known object types */
160         struct ao2_container *types;
161 };
162
163 /*! \brief Structure for passing load/reload details */
164 struct sorcery_load_details {
165         /*! \brief Sorcery structure in use */
166         const struct ast_sorcery *sorcery;
167
168         /*! \brief Type of object being loaded */
169         const char *type;
170
171         /*! \brief Whether this is a reload or not */
172         unsigned int reload:1;
173 };
174
175 /*! \brief Registered sorcery wizards */
176 struct ao2_container *wizards;
177
178 static int int_handler_fn(const void *obj, const intptr_t *args, char **buf)
179 {
180         int *field = (int *)(obj + args[0]);
181         return (ast_asprintf(buf, "%d", *field) < 0) ? -1 : 0;
182 }
183
184 static int uint_handler_fn(const void *obj, const intptr_t *args, char **buf)
185 {
186         unsigned int *field = (unsigned int *)(obj + args[0]);
187         return (ast_asprintf(buf, "%u", *field) < 0) ? -1 : 0;
188 }
189
190 static int double_handler_fn(const void *obj, const intptr_t *args, char **buf)
191 {
192         double *field = (double *)(obj + args[0]);
193         return (ast_asprintf(buf, "%f", *field) < 0) ? -1 : 0;
194 }
195
196 static int stringfield_handler_fn(const void *obj, const intptr_t *args, char **buf)
197 {
198         ast_string_field *field = (const char **)(obj + args[0]);
199         return !(*buf = ast_strdup(*field)) ? -1 : 0;
200 }
201
202 static int bool_handler_fn(const void *obj, const intptr_t *args, char **buf)
203 {
204         unsigned int *field = (unsigned int *)(obj + args[0]);
205         return !(*buf = ast_strdup(*field ? "true" : "false")) ? -1 : 0;
206 }
207
208 static int sockaddr_handler_fn(const void *obj, const intptr_t *args, char **buf)
209 {
210         struct ast_sockaddr *field = (struct ast_sockaddr *)(obj + args[0]);
211         return !(*buf = ast_strdup(ast_sockaddr_stringify(field))) ? -1 : 0;
212 }
213
214 static int chararray_handler_fn(const void *obj, const intptr_t *args, char **buf)
215 {
216         char *field = (char *)(obj + args[0]);
217         return !(*buf = ast_strdup(field)) ? -1 : 0;
218 }
219
220 static sorcery_field_handler sorcery_field_default_handler(enum aco_option_type type)
221 {
222         switch(type) {
223         case OPT_BOOL_T: return bool_handler_fn;
224         case OPT_CHAR_ARRAY_T: return chararray_handler_fn;
225         case OPT_DOUBLE_T: return double_handler_fn;
226         case OPT_INT_T: return int_handler_fn;
227         case OPT_SOCKADDR_T: return sockaddr_handler_fn;
228         case OPT_STRINGFIELD_T: return stringfield_handler_fn;
229         case OPT_UINT_T: return uint_handler_fn;
230
231         default:
232         case OPT_CUSTOM_T: return NULL;
233         }
234
235         return NULL;
236 }
237
238 /*! \brief Hashing function for sorcery wizards */
239 static int sorcery_wizard_hash(const void *obj, const int flags)
240 {
241         const struct ast_sorcery_wizard *wizard = obj;
242         const char *name = obj;
243
244         return ast_str_hash(flags & OBJ_KEY ? name : wizard->name);
245 }
246
247 /*! \brief Comparator function for sorcery wizards */
248 static int sorcery_wizard_cmp(void *obj, void *arg, int flags)
249 {
250         struct ast_sorcery_wizard *wizard1 = obj, *wizard2 = arg;
251         const char *name = arg;
252
253         return !strcmp(wizard1->name, flags & OBJ_KEY ? name : wizard2->name) ? CMP_MATCH | CMP_STOP : 0;
254 }
255
256 int ast_sorcery_init(void)
257 {
258         struct ast_threadpool_options options = {
259                 .version = AST_THREADPOOL_OPTIONS_VERSION,
260                 .auto_increment = 1,
261                 .max_size = 0,
262                 .idle_timeout = 60,
263                 .initial_size = 0,
264         };
265         ast_assert(wizards == NULL);
266
267         if (!(threadpool = ast_threadpool_create("Sorcery", NULL, &options))) {
268                 return -1;
269         }
270
271         if (!(wizards = ao2_container_alloc(WIZARD_BUCKETS, sorcery_wizard_hash, sorcery_wizard_cmp))) {
272                 ast_threadpool_shutdown(threadpool);
273                 return -1;
274         }
275
276         return 0;
277 }
278
279 int __ast_sorcery_wizard_register(const struct ast_sorcery_wizard *interface, struct ast_module *module)
280 {
281         struct ast_sorcery_wizard *wizard;
282         int res = -1;
283
284         ast_assert(!ast_strlen_zero(interface->name));
285
286         ao2_lock(wizards);
287
288         if ((wizard = ao2_find(wizards, interface->name, OBJ_KEY | OBJ_NOLOCK))) {
289                 ast_log(LOG_WARNING, "Attempted to register sorcery wizard '%s' twice\n",
290                         interface->name);
291                 goto done;
292         }
293
294         if (!(wizard = ao2_alloc(sizeof(*wizard), NULL))) {
295                 goto done;
296         }
297
298         *wizard = *interface;
299         wizard->module = module;
300
301         ao2_link_flags(wizards, wizard, OBJ_NOLOCK);
302         res = 0;
303
304         ast_verb(2, "Sorcery registered wizard '%s'\n", interface->name);
305
306 done:
307         ao2_cleanup(wizard);
308         ao2_unlock(wizards);
309
310         return res;
311 }
312
313 int ast_sorcery_wizard_unregister(const struct ast_sorcery_wizard *interface)
314 {
315         RAII_VAR(struct ast_sorcery_wizard *, wizard, ao2_find(wizards, interface->name, OBJ_KEY | OBJ_UNLINK), ao2_cleanup);
316
317         if (wizard) {
318                 ast_verb(2, "Sorcery unregistered wizard '%s'\n", interface->name);
319                 return 0;
320         } else {
321                 return -1;
322         }
323 }
324
325 /*! \brief Destructor called when sorcery structure is destroyed */
326 static void sorcery_destructor(void *obj)
327 {
328         struct ast_sorcery *sorcery = obj;
329
330         ao2_cleanup(sorcery->types);
331 }
332
333 /*! \brief Hashing function for sorcery types */
334 static int sorcery_type_hash(const void *obj, const int flags)
335 {
336         const struct ast_sorcery_object_type *type = obj;
337         const char *name = obj;
338
339         return ast_str_hash(flags & OBJ_KEY ? name : type->name);
340 }
341
342 /*! \brief Comparator function for sorcery types */
343 static int sorcery_type_cmp(void *obj, void *arg, int flags)
344 {
345         struct ast_sorcery_object_type *type1 = obj, *type2 = arg;
346         const char *name = arg;
347
348         return !strcmp(type1->name, flags & OBJ_KEY ? name : type2->name) ? CMP_MATCH | CMP_STOP : 0;
349 }
350
351 struct ast_sorcery *ast_sorcery_open(void)
352 {
353         struct ast_sorcery *sorcery;
354
355         if (!(sorcery = ao2_alloc(sizeof(*sorcery), sorcery_destructor))) {
356                 return NULL;
357         }
358
359         if (!(sorcery->types = ao2_container_alloc_options(AO2_ALLOC_OPT_LOCK_RWLOCK, TYPE_BUCKETS, sorcery_type_hash, sorcery_type_cmp))) {
360                 ao2_ref(sorcery, -1);
361                 sorcery = NULL;
362         }
363
364         return sorcery;
365 }
366
367 /*! \brief Destructor function for object types */
368 static void sorcery_object_type_destructor(void *obj)
369 {
370         struct ast_sorcery_object_type *object_type = obj;
371
372         ao2_cleanup(object_type->wizards);
373         ao2_cleanup(object_type->fields);
374         ao2_cleanup(object_type->observers);
375
376         if (object_type->info) {
377                 aco_info_destroy(object_type->info);
378                 ast_free(object_type->info);
379         }
380
381         ast_free(object_type->file);
382
383         ast_taskprocessor_unreference(object_type->serializer);
384 }
385
386 /*! \brief Internal function which allocates an object type structure */
387 static struct ast_sorcery_object_type *sorcery_object_type_alloc(const char *type, const char *module)
388 {
389         struct ast_sorcery_object_type *object_type;
390         char uuid[AST_UUID_STR_LEN];
391
392         if (!(object_type = ao2_alloc(sizeof(*object_type), sorcery_object_type_destructor))) {
393                 return NULL;
394         }
395
396         /* Order matters for object wizards */
397         if (!(object_type->wizards = ao2_container_alloc_options(AO2_ALLOC_OPT_LOCK_NOLOCK, 1, NULL, NULL))) {
398                 ao2_ref(object_type, -1);
399                 return NULL;
400         }
401
402         if (!(object_type->fields = ao2_container_alloc_options(AO2_ALLOC_OPT_LOCK_NOLOCK, 1, NULL, NULL))) {
403                 ao2_ref(object_type, -1);
404                 return NULL;
405         }
406
407         if (!(object_type->observers = ao2_container_alloc_options(AO2_ALLOC_OPT_LOCK_RWLOCK, 1, NULL, NULL))) {
408                 ao2_ref(object_type, -1);
409                 return NULL;
410         }
411
412         if (!(object_type->info = ast_calloc(1, sizeof(*object_type->info) + 2 * sizeof(object_type->info->files[0])))) {
413                 ao2_ref(object_type, -1);
414                 return NULL;
415         }
416
417         if (!(object_type->file = ast_calloc(1, sizeof(*object_type->file) + 2 * sizeof(object_type->file->types[0])))) {
418                 ao2_ref(object_type, -1);
419                 return NULL;
420         }
421
422         if (!ast_uuid_generate_str(uuid, sizeof(uuid))) {
423                 ao2_ref(object_type, -1);
424                 return NULL;
425         }
426
427         if (!(object_type->serializer = ast_threadpool_serializer(uuid, threadpool))) {
428                 ao2_ref(object_type, -1);
429                 return NULL;
430         }
431
432         object_type->info->files[0] = object_type->file;
433         object_type->info->files[1] = NULL;
434         object_type->info->module = module;
435
436         ast_copy_string(object_type->name, type, sizeof(object_type->name));
437
438         return object_type;
439 }
440
441 /*! \brief Object wizard destructor */
442 static void sorcery_object_wizard_destructor(void *obj)
443 {
444         struct ast_sorcery_object_wizard *object_wizard = obj;
445
446         if (object_wizard->data) {
447                 object_wizard->wizard->close(object_wizard->data);
448         }
449
450         if (object_wizard->wizard) {
451                 ast_module_unref(object_wizard->wizard->module);
452         }
453 }
454
455 /*! \brief Internal function which creates an object type and adds a wizard mapping */
456 static int sorcery_apply_wizard_mapping(struct ast_sorcery *sorcery, const char *type, const char *module, const char *name, const char *data, unsigned int caching)
457 {
458         RAII_VAR(struct ast_sorcery_object_type *, object_type,  ao2_find(sorcery->types, type, OBJ_KEY), ao2_cleanup);
459         RAII_VAR(struct ast_sorcery_wizard *, wizard, ao2_find(wizards, name, OBJ_KEY), ao2_cleanup);
460         RAII_VAR(struct ast_sorcery_object_wizard *, object_wizard, ao2_alloc(sizeof(*object_wizard), sorcery_object_wizard_destructor), ao2_cleanup);
461         int created = 0;
462
463         if (!wizard || !object_wizard) {
464                 return -1;
465         }
466
467         if (!object_type) {
468                 if (!(object_type = sorcery_object_type_alloc(type, module))) {
469                         return -1;
470                 }
471                 created = 1;
472         }
473
474         if (wizard->open && !(object_wizard->data = wizard->open(data))) {
475                 return -1;
476         }
477
478         ast_module_ref(wizard->module);
479
480         object_wizard->wizard = wizard;
481         object_wizard->caching = caching;
482
483         ao2_link(object_type->wizards, object_wizard);
484
485         if (created) {
486                 ao2_link(sorcery->types, object_type);
487         }
488
489         return 0;
490 }
491
492 int __ast_sorcery_apply_config(struct ast_sorcery *sorcery, const char *name, const char *module)
493 {
494         struct ast_flags flags = { 0 };
495         struct ast_config *config = ast_config_load2("sorcery.conf", "sorcery", flags);
496         struct ast_variable *mapping;
497         int res = 0;
498
499         if (!config || (config == CONFIG_STATUS_FILEMISSING) || (config == CONFIG_STATUS_FILEINVALID)) {
500                 return -1;
501         }
502
503         for (mapping = ast_variable_browse(config, name); mapping; mapping = mapping->next) {
504                 RAII_VAR(char *, mapping_name, ast_strdup(mapping->name), ast_free);
505                 RAII_VAR(char *, mapping_value, ast_strdup(mapping->value), ast_free);
506                 char *options = mapping_name, *name = strsep(&options, "/");
507                 char *data = mapping_value, *wizard = strsep(&data, ",");
508                 unsigned int caching = 0;
509
510                 /* If no wizard exists just skip, nothing we can do */
511                 if (ast_strlen_zero(wizard)) {
512                         continue;
513                 }
514
515                 /* If the wizard is configured as a cache treat it as such */
516                 if (!ast_strlen_zero(options) && strstr(options, "cache")) {
517                         caching = 1;
518                 }
519
520                 /* Any error immediately causes us to stop */
521                 if ((res = sorcery_apply_wizard_mapping(sorcery, name, module, wizard, data, caching))) {
522                         break;
523                 }
524         }
525
526         ast_config_destroy(config);
527
528         return res;
529 }
530
531 int __ast_sorcery_apply_default(struct ast_sorcery *sorcery, const char *type, const char *module, const char *name, const char *data)
532 {
533         RAII_VAR(struct ast_sorcery_object_type *, object_type,  ao2_find(sorcery->types, type, OBJ_KEY), ao2_cleanup);
534
535         /* Defaults can not be added if any existing mapping exists */
536         if (object_type) {
537                 return -1;
538         }
539
540         return sorcery_apply_wizard_mapping(sorcery, type, module, name, data, 0);
541 }
542
543 static int sorcery_extended_config_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
544 {
545         return ast_sorcery_object_set_extended(obj, var->name, var->value);
546 }
547
548 static int sorcery_extended_fields_handler(const void *obj, struct ast_variable **fields)
549 {
550         const struct ast_sorcery_object_details *details = obj;
551
552         if (details->object->extended) {
553                 *fields = ast_variables_dup(details->object->extended);
554         } else {
555                 *fields = NULL;
556         }
557
558         return 0;
559 }
560
561 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)
562 {
563         RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, type, OBJ_KEY), ao2_cleanup);
564
565         if (!object_type || object_type->type.item_alloc) {
566                 return -1;
567         }
568
569         object_type->type.name = object_type->name;
570         object_type->type.type = ACO_ITEM;
571         object_type->type.category = "";
572         object_type->type.item_alloc = alloc;
573
574         object_type->transform = transform;
575         object_type->apply = apply;
576         object_type->file->types[0] = &object_type->type;
577         object_type->file->types[1] = NULL;
578
579         if (aco_info_init(object_type->info)) {
580                 return -1;
581         }
582
583         if (ast_sorcery_object_fields_register(sorcery, type, "^@", sorcery_extended_config_handler, sorcery_extended_fields_handler)) {
584                 return -1;
585         }
586
587         return 0;
588 }
589
590 void ast_sorcery_object_set_copy_handler(struct ast_sorcery *sorcery, const char *type, sorcery_copy_handler copy)
591 {
592         RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, type, OBJ_KEY), ao2_cleanup);
593
594         if (!object_type) {
595                 return;
596         }
597
598         object_type->copy = copy;
599 }
600
601 void ast_sorcery_object_set_diff_handler(struct ast_sorcery *sorcery, const char *type, sorcery_diff_handler diff)
602 {
603         RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, type, OBJ_KEY), ao2_cleanup);
604
605         if (!object_type) {
606                 return;
607         }
608
609         object_type->diff = diff;
610 }
611
612 int ast_sorcery_object_fields_register(struct ast_sorcery *sorcery, const char *type, const char *regex, aco_option_handler config_handler, sorcery_fields_handler sorcery_handler)
613 {
614         RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, type, OBJ_KEY), ao2_cleanup);
615         RAII_VAR(struct ast_sorcery_object_field *, object_field, NULL, ao2_cleanup);
616
617         if (!object_type || !object_type->type.item_alloc || !config_handler || !(object_field = ao2_alloc(sizeof(*object_field), NULL))) {
618                 return -1;
619         }
620
621         ast_copy_string(object_field->name, regex, sizeof(object_field->name));
622         object_field->multiple_handler = sorcery_handler;
623
624         ao2_link(object_type->fields, object_field);
625         __aco_option_register(object_type->info, regex, ACO_REGEX, object_type->file->types, "", OPT_CUSTOM_T, config_handler, 0, 0);
626
627         return 0;
628 }
629
630 int __ast_sorcery_object_field_register(struct ast_sorcery *sorcery, const char *type, const char *name, const char *default_val, enum aco_option_type opt_type,
631                                         aco_option_handler config_handler, sorcery_field_handler sorcery_handler, unsigned int flags, size_t argc, ...)
632 {
633         RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, type, OBJ_KEY), ao2_cleanup);
634         RAII_VAR(struct ast_sorcery_object_field *, object_field, NULL, ao2_cleanup);
635         int pos;
636         va_list args;
637
638         if (!strcmp(type, "id") || !object_type || !object_type->type.item_alloc) {
639                 return -1;
640         }
641
642         if (!sorcery_handler) {
643                 sorcery_handler = sorcery_field_default_handler(opt_type);
644         }
645
646         if (!(object_field = ao2_alloc(sizeof(*object_field) + argc * sizeof(object_field->args[0]), NULL))) {
647                 return -1;
648         }
649
650         ast_copy_string(object_field->name, name, sizeof(object_field->name));
651         object_field->handler = sorcery_handler;
652
653         va_start(args, argc);
654         for (pos = 0; pos < argc; pos++) {
655                 object_field->args[pos] = va_arg(args, size_t);
656         }
657         va_end(args);
658
659         ao2_link(object_type->fields, object_field);
660
661         /* TODO: Improve this hack */
662         if (!argc) {
663                 __aco_option_register(object_type->info, name, ACO_EXACT, object_type->file->types, default_val, opt_type, config_handler, flags, argc);
664         } else if (argc == 1) {
665                 __aco_option_register(object_type->info, name, ACO_EXACT, object_type->file->types, default_val, opt_type, config_handler, flags, argc,
666                                       object_field->args[0]);
667         } else if (argc == 2) {
668                 __aco_option_register(object_type->info, name, ACO_EXACT, object_type->file->types, default_val, opt_type, config_handler, flags, argc,
669                                       object_field->args[0], object_field->args[1]);
670         } else if (argc == 3) {
671                 __aco_option_register(object_type->info, name, ACO_EXACT, object_type->file->types, default_val, opt_type, config_handler, flags, argc,
672                                       object_field->args[0], object_field->args[1], object_field->args[2]);
673         } else {
674                 ast_assert(0); /* The hack... she does us no good for this */
675         }
676
677         return 0;
678 }
679
680 static int sorcery_wizard_load(void *obj, void *arg, int flags)
681 {
682         struct ast_sorcery_object_wizard *wizard = obj;
683         struct sorcery_load_details *details = arg;
684         void (*load)(void *data, const struct ast_sorcery *sorcery, const char *type);
685
686         load = !details->reload ? wizard->wizard->load : wizard->wizard->reload;
687
688         if (load) {
689                 load(wizard->data, details->sorcery, details->type);
690         }
691
692         return 0;
693 }
694
695 /*! \brief Destructor for observer invocation */
696 static void sorcery_observer_invocation_destroy(void *obj)
697 {
698         struct sorcery_observer_invocation *invocation = obj;
699
700         ao2_cleanup(invocation->object_type);
701         ao2_cleanup(invocation->object);
702 }
703
704 /*! \brief Allocator function for observer invocation */
705 static struct sorcery_observer_invocation *sorcery_observer_invocation_alloc(struct ast_sorcery_object_type *object_type, void *object)
706 {
707         struct sorcery_observer_invocation *invocation = ao2_alloc(sizeof(*invocation), sorcery_observer_invocation_destroy);
708
709         if (!invocation) {
710                 return NULL;
711         }
712
713         ao2_ref(object_type, +1);
714         invocation->object_type = object_type;
715
716         if (object) {
717                 ao2_ref(object, +1);
718                 invocation->object = object;
719         }
720
721         return invocation;
722 }
723
724 /*! \brief Internal callback function which notifies an individual observer that an object type has been loaded */
725 static int sorcery_observer_notify_loaded(void *obj, void *arg, int flags)
726 {
727         const struct ast_sorcery_object_type_observer *observer = obj;
728
729         if (observer->callbacks->loaded) {
730                 observer->callbacks->loaded(arg);
731         }
732
733         return 0;
734 }
735
736 /*! \brief Internal callback function which notifies observers that an object type has been loaded */
737 static int sorcery_observers_notify_loaded(void *data)
738 {
739         struct sorcery_observer_invocation *invocation = data;
740
741         ao2_callback(invocation->object_type->observers, OBJ_NODATA, sorcery_observer_notify_loaded, invocation->object_type->name);
742         ao2_cleanup(invocation);
743
744         return 0;
745 }
746
747 static int sorcery_object_load(void *obj, void *arg, int flags)
748 {
749         struct ast_sorcery_object_type *type = obj;
750         struct sorcery_load_details *details = arg;
751
752         details->type = type->name;
753         ao2_callback(type->wizards, OBJ_NODATA, sorcery_wizard_load, details);
754
755         if (ao2_container_count(type->observers)) {
756                 struct sorcery_observer_invocation *invocation = sorcery_observer_invocation_alloc(type, NULL);
757
758                 if (invocation && ast_taskprocessor_push(type->serializer, sorcery_observers_notify_loaded, invocation)) {
759                         ao2_cleanup(invocation);
760                 }
761         }
762
763         return 0;
764 }
765
766 void ast_sorcery_load(const struct ast_sorcery *sorcery)
767 {
768         struct sorcery_load_details details = {
769                 .sorcery = sorcery,
770                 .reload = 0,
771         };
772
773         ao2_callback(sorcery->types, OBJ_NODATA, sorcery_object_load, &details);
774 }
775
776 void ast_sorcery_load_object(const struct ast_sorcery *sorcery, const char *type)
777 {
778         RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, type, OBJ_KEY), ao2_cleanup);
779         struct sorcery_load_details details = {
780                 .sorcery = sorcery,
781                 .reload = 0,
782         };
783
784         if (!object_type) {
785                 return;
786         }
787
788         sorcery_object_load(object_type, &details, 0);
789 }
790
791 void ast_sorcery_reload(const struct ast_sorcery *sorcery)
792 {
793         struct sorcery_load_details details = {
794                 .sorcery = sorcery,
795                 .reload = 1,
796         };
797
798         ao2_callback(sorcery->types, OBJ_NODATA, sorcery_object_load, &details);
799 }
800
801 void ast_sorcery_reload_object(const struct ast_sorcery *sorcery, const char *type)
802 {
803         RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, type, OBJ_KEY), ao2_cleanup);
804         struct sorcery_load_details details = {
805                 .sorcery = sorcery,
806                 .reload = 1,
807         };
808
809         if (!object_type) {
810                 return;
811         }
812
813         sorcery_object_load(object_type, &details, 0);
814 }
815
816 void ast_sorcery_ref(struct ast_sorcery *sorcery)
817 {
818         ao2_ref(sorcery, +1);
819 }
820
821 struct ast_variable *ast_sorcery_objectset_create(const struct ast_sorcery *sorcery, const void *object)
822 {
823         const struct ast_sorcery_object_details *details = object;
824         RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, details->object->type, OBJ_KEY), ao2_cleanup);
825         struct ao2_iterator i;
826         struct ast_sorcery_object_field *object_field;
827         struct ast_variable *fields = NULL;
828         int res = 0;
829
830         if (!object_type) {
831                 return NULL;
832         }
833
834         i = ao2_iterator_init(object_type->fields, 0);
835
836         for (; (object_field = ao2_iterator_next(&i)) && !res; ao2_ref(object_field, -1)) {
837                 struct ast_variable *tmp = NULL;
838
839                 if (object_field->multiple_handler) {
840                         if ((res = object_field->multiple_handler(object, &tmp))) {
841                                 ast_variables_destroy(tmp);
842                         }
843                 } else if (object_field->handler) {
844                         char *buf = NULL;
845
846                         if ((res = object_field->handler(object, object_field->args, &buf)) ||
847                                 !(tmp = ast_variable_new(object_field->name, S_OR(buf, ""), ""))) {
848                                 res = -1;
849                         }
850
851                         ast_free(buf);
852                 } else {
853                         continue;
854                 }
855
856                 if (!res && tmp) {
857                         tmp->next = fields;
858                         fields = tmp;
859                 }
860         }
861
862         ao2_iterator_destroy(&i);
863
864         /* If any error occurs we destroy all fields handled before so a partial objectset is not returned */
865         if (res) {
866                 ast_variables_destroy(fields);
867                 fields = NULL;
868         }
869
870         return fields;
871 }
872
873 struct ast_json *ast_sorcery_objectset_json_create(const struct ast_sorcery *sorcery, const void *object)
874 {
875         const struct ast_sorcery_object_details *details = object;
876         RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, details->object->type, OBJ_KEY), ao2_cleanup);
877         struct ao2_iterator i;
878         struct ast_sorcery_object_field *object_field;
879         struct ast_json *json = ast_json_object_create();
880         int res = 0;
881
882         if (!object_type || !json) {
883                 return NULL;
884         }
885
886         i = ao2_iterator_init(object_type->fields, 0);
887
888         for (; (object_field = ao2_iterator_next(&i)) && !res; ao2_ref(object_field, -1)) {
889                 if (object_field->multiple_handler) {
890                         struct ast_variable *tmp = NULL;
891                         struct ast_variable *field;
892
893                         if ((res = object_field->multiple_handler(object, &tmp))) {
894                                 break;
895                         }
896
897                         for (field = tmp; field; field = field->next) {
898                                 struct ast_json *value = ast_json_string_create(field->value);
899
900                                 if (value && ast_json_object_set(json, field->name, value)) {
901                                         ast_json_unref(value);
902                                         res = -1;
903                                 }
904                         }
905
906                         ast_variables_destroy(tmp);
907                 } else if (object_field->handler) {
908                         char *buf = NULL;
909                         struct ast_json *value = NULL;
910
911                         if ((res = object_field->handler(object, object_field->args, &buf)) ||
912                                 !(value = ast_json_string_create(buf)) ||
913                                 ast_json_object_set(json, object_field->name, value)) {
914                                 ast_json_unref(value);
915                                 res = -1;
916                         }
917
918                         ast_free(buf);
919                 } else {
920                         continue;
921                 }
922         }
923
924         ao2_iterator_destroy(&i);
925
926         /* If any error occurs we destroy the JSON object so a partial objectset is not returned */
927         if (res) {
928                 ast_json_unref(json);
929                 json = NULL;
930         }
931
932         return json;
933 }
934
935 int ast_sorcery_objectset_apply(const struct ast_sorcery *sorcery, void *object, struct ast_variable *objectset)
936 {
937         const struct ast_sorcery_object_details *details = object;
938         RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, details->object->type, OBJ_KEY), ao2_cleanup);
939         RAII_VAR(struct ast_variable *, transformed, NULL, ast_variables_destroy);
940         struct ast_variable *field;
941         int res = 0;
942
943         if (!object_type) {
944                 return -1;
945         }
946
947         if (object_type->transform && (transformed = object_type->transform(objectset))) {
948                 field = transformed;
949         } else {
950                 field = objectset;
951         }
952
953         for (; field; field = field->next) {
954                 if ((res = aco_process_var(&object_type->type, details->object->id, field, object))) {
955                         break;
956                 }
957         }
958
959         if (!res && object_type->apply) {
960                 res = object_type->apply(sorcery, object);
961         }
962
963         return res;
964 }
965
966 static const struct ast_variable *sorcery_find_field(const struct ast_variable *fields, const char *name)
967 {
968         const struct ast_variable *field;
969
970         /* Search the linked list of fields to find the correct one */
971         for (field = fields; field; field = field->next) {
972                 if (!strcmp(field->name, name)) {
973                         return field;
974                 }
975         }
976
977         return NULL;
978 }
979
980 int ast_sorcery_changeset_create(const struct ast_variable *original, const struct ast_variable *modified, struct ast_variable **changes)
981 {
982         const struct ast_variable *field;
983         int res = 0;
984
985         *changes = NULL;
986
987         /* Unless the ast_variable list changes when examined... it can't differ from itself */
988         if (original == modified) {
989                 return 0;
990         }
991
992         for (field = modified; field; field = field->next) {
993                 const struct ast_variable *old = sorcery_find_field(original, field->name);
994
995                 if (!old || strcmp(old->value, field->value)) {
996                         struct ast_variable *tmp;
997
998                         if (!(tmp = ast_variable_new(field->name, field->value, ""))) {
999                                 res = -1;
1000                                 break;
1001                         }
1002
1003                         tmp->next = *changes;
1004                         *changes = tmp;
1005                 }
1006         }
1007
1008         /* If an error occurred do not return a partial changeset */
1009         if (res) {
1010                 ast_variables_destroy(*changes);
1011                 *changes = NULL;
1012         }
1013
1014         return res;
1015 }
1016
1017 static void sorcery_object_destructor(void *object)
1018 {
1019         struct ast_sorcery_object_details *details = object;
1020
1021         if (details->object->destructor) {
1022                 details->object->destructor(object);
1023         }
1024
1025         ast_variables_destroy(details->object->extended);
1026 }
1027
1028 void *ast_sorcery_generic_alloc(size_t size, ao2_destructor_fn destructor)
1029 {
1030         void *object = ao2_alloc_options(size + sizeof(struct ast_sorcery_object), sorcery_object_destructor, AO2_ALLOC_OPT_LOCK_NOLOCK);
1031         struct ast_sorcery_object_details *details = object;
1032
1033         if (!object) {
1034                 return NULL;
1035         }
1036
1037         details->object = object + size;
1038         details->object->destructor = destructor;
1039
1040         return object;
1041 }
1042
1043 void *ast_sorcery_alloc(const struct ast_sorcery *sorcery, const char *type, const char *id)
1044 {
1045         RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, type, OBJ_KEY), ao2_cleanup);
1046         struct ast_sorcery_object_details *details;
1047
1048         if (!object_type || !object_type->type.item_alloc ||
1049             !(details = object_type->type.item_alloc(id))) {
1050                 return NULL;
1051         }
1052
1053         if (ast_strlen_zero(id)) {
1054                 ast_uuid_generate_str(details->object->id, sizeof(details->object->id));
1055         } else {
1056                 ast_copy_string(details->object->id, id, sizeof(details->object->id));
1057         }
1058
1059         ast_copy_string(details->object->type, type, sizeof(details->object->type));
1060
1061         if (aco_set_defaults(&object_type->type, id, details)) {
1062                 ao2_ref(details, -1);
1063                 return NULL;
1064         }
1065
1066         return details;
1067 }
1068
1069 void *ast_sorcery_copy(const struct ast_sorcery *sorcery, const void *object)
1070 {
1071         const struct ast_sorcery_object_details *details = object;
1072         RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, details->object->type, OBJ_KEY), ao2_cleanup);
1073         struct ast_sorcery_object_details *copy = ast_sorcery_alloc(sorcery, details->object->type, details->object->id);
1074         RAII_VAR(struct ast_variable *, objectset, NULL, ast_variables_destroy);
1075         int res = 0;
1076
1077         if (!copy) {
1078                 return NULL;
1079         } else if (object_type->copy) {
1080                 res = object_type->copy(object, copy);
1081         } else if ((objectset = ast_sorcery_objectset_create(sorcery, object))) {
1082                 res = ast_sorcery_objectset_apply(sorcery, copy, objectset);
1083         } else {
1084                 /* No native copy available and could not create an objectset, this copy has failed */
1085                 res = -1;
1086         }
1087
1088         if (res) {
1089                 ao2_cleanup(copy);
1090                 copy = NULL;
1091         }
1092
1093         return copy;
1094 }
1095
1096 int ast_sorcery_diff(const struct ast_sorcery *sorcery, const void *original, const void *modified, struct ast_variable **changes)
1097 {
1098         RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, ast_sorcery_object_get_type(original), OBJ_KEY), ao2_cleanup);
1099
1100         *changes = NULL;
1101
1102         if (strcmp(ast_sorcery_object_get_type(original), ast_sorcery_object_get_type(modified))) {
1103                 return -1;
1104         }
1105
1106         if (original == modified) {
1107                 return 0;
1108         } else if (!object_type->diff) {
1109                 RAII_VAR(struct ast_variable *, objectset1, NULL, ast_variables_destroy);
1110                 RAII_VAR(struct ast_variable *, objectset2, NULL, ast_variables_destroy);
1111
1112                 objectset1 = ast_sorcery_objectset_create(sorcery, original);
1113                 objectset2 = ast_sorcery_objectset_create(sorcery, modified);
1114
1115                 return ast_sorcery_changeset_create(objectset1, objectset2, changes);
1116         } else {
1117                 return object_type->diff(original, modified, changes);
1118         }
1119 }
1120
1121 /*! \brief Structure used when calling create, update, or delete */
1122 struct sorcery_details {
1123         /*! \brief Pointer to the sorcery instance */
1124         const struct ast_sorcery *sorcery;
1125         /*! \brief Pointer to the object itself */
1126         void *obj;
1127 };
1128
1129 /*! \brief Internal function used to create an object in caching wizards */
1130 static int sorcery_cache_create(void *obj, void *arg, int flags)
1131 {
1132         const struct ast_sorcery_object_wizard *object_wizard = obj;
1133         const struct sorcery_details *details = arg;
1134
1135         if (!object_wizard->caching || !object_wizard->wizard->create) {
1136                 return 0;
1137         }
1138
1139         object_wizard->wizard->create(details->sorcery, object_wizard->data, details->obj);
1140
1141         return 0;
1142 }
1143
1144 void *ast_sorcery_retrieve_by_id(const struct ast_sorcery *sorcery, const char *type, const char *id)
1145 {
1146         RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, type, OBJ_KEY), ao2_cleanup);
1147         void *object = NULL;
1148         struct ao2_iterator i;
1149         struct ast_sorcery_object_wizard *wizard;
1150         unsigned int cached = 0;
1151
1152         if (!object_type || ast_strlen_zero(id)) {
1153                 return NULL;
1154         }
1155
1156         i = ao2_iterator_init(object_type->wizards, 0);
1157         for (; (wizard = ao2_iterator_next(&i)); ao2_ref(wizard, -1)) {
1158                 if (wizard->wizard->retrieve_id &&
1159                     !(object = wizard->wizard->retrieve_id(sorcery, wizard->data, object_type->name, id))) {
1160                         continue;
1161                 }
1162
1163                 cached = wizard->caching;
1164
1165                 ao2_ref(wizard, -1);
1166                 break;
1167         }
1168         ao2_iterator_destroy(&i);
1169
1170         if (!cached && object) {
1171                 ao2_callback(object_type->wizards, 0, sorcery_cache_create, object);
1172         }
1173
1174         return object;
1175 }
1176
1177 void *ast_sorcery_retrieve_by_fields(const struct ast_sorcery *sorcery, const char *type, unsigned int flags, struct ast_variable *fields)
1178 {
1179         RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, type, OBJ_KEY), ao2_cleanup);
1180         void *object = NULL;
1181         struct ao2_iterator i;
1182         struct ast_sorcery_object_wizard *wizard;
1183         unsigned int cached = 0;
1184
1185         if (!object_type) {
1186                 return NULL;
1187         }
1188
1189         /* If returning multiple objects create a container to store them in */
1190         if ((flags & AST_RETRIEVE_FLAG_MULTIPLE)) {
1191                 if (!(object = ao2_container_alloc_options(AO2_ALLOC_OPT_LOCK_NOLOCK, 1, NULL, NULL))) {
1192                         return NULL;
1193                 }
1194         }
1195
1196         /* Inquire with the available wizards for retrieval */
1197         i = ao2_iterator_init(object_type->wizards, 0);
1198         for (; (wizard = ao2_iterator_next(&i)); ao2_ref(wizard, -1)) {
1199                 if ((flags & AST_RETRIEVE_FLAG_MULTIPLE)) {
1200                         if (wizard->wizard->retrieve_multiple) {
1201                                 wizard->wizard->retrieve_multiple(sorcery, wizard->data, object_type->name, object, fields);
1202                         }
1203                 } else if (fields && wizard->wizard->retrieve_fields) {
1204                         if (wizard->wizard->retrieve_fields) {
1205                                 object = wizard->wizard->retrieve_fields(sorcery, wizard->data, object_type->name, fields);
1206                         }
1207                 }
1208
1209                 if ((flags & AST_RETRIEVE_FLAG_MULTIPLE) || !object) {
1210                         continue;
1211                 }
1212
1213                 cached = wizard->caching;
1214
1215                 ao2_ref(wizard, -1);
1216                 break;
1217         }
1218         ao2_iterator_destroy(&i);
1219
1220         /* If we are returning a single object and it came from a non-cache source create it in any caches */
1221         if (!(flags & AST_RETRIEVE_FLAG_MULTIPLE) && !cached && object) {
1222                 ao2_callback(object_type->wizards, 0, sorcery_cache_create, object);
1223         }
1224
1225         return object;
1226 }
1227
1228 struct ao2_container *ast_sorcery_retrieve_by_regex(const struct ast_sorcery *sorcery, const char *type, const char *regex)
1229 {
1230         RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, type, OBJ_KEY), ao2_cleanup);
1231         struct ao2_container *objects;
1232         struct ao2_iterator i;
1233         struct ast_sorcery_object_wizard *wizard;
1234
1235         if (!object_type || !(objects = ao2_container_alloc_options(AO2_ALLOC_OPT_LOCK_NOLOCK, 1, NULL, NULL))) {
1236                 return NULL;
1237         }
1238
1239         i = ao2_iterator_init(object_type->wizards, 0);
1240         for (; (wizard = ao2_iterator_next(&i)); ao2_ref(wizard, -1)) {
1241                 if (!wizard->wizard->retrieve_regex) {
1242                         continue;
1243                 }
1244
1245                 wizard->wizard->retrieve_regex(sorcery, wizard->data, object_type->name, objects, regex);
1246         }
1247         ao2_iterator_destroy(&i);
1248
1249         return objects;
1250 }
1251
1252 /*! \brief Internal function which returns if the wizard has created the object */
1253 static int sorcery_wizard_create(void *obj, void *arg, int flags)
1254 {
1255         const struct ast_sorcery_object_wizard *object_wizard = obj;
1256         const struct sorcery_details *details = arg;
1257
1258         return (!object_wizard->caching && !object_wizard->wizard->create(details->sorcery, object_wizard->data, details->obj)) ? CMP_MATCH | CMP_STOP : 0;
1259 }
1260
1261 /*! \brief Internal callback function which notifies an individual observer that an object has been created */
1262 static int sorcery_observer_notify_create(void *obj, void *arg, int flags)
1263 {
1264         const struct ast_sorcery_object_type_observer *observer = obj;
1265
1266         if (observer->callbacks->created) {
1267                 observer->callbacks->created(arg);
1268         }
1269
1270         return 0;
1271 }
1272
1273 /*! \brief Internal callback function which notifies observers that an object has been created */
1274 static int sorcery_observers_notify_create(void *data)
1275 {
1276         struct sorcery_observer_invocation *invocation = data;
1277
1278         ao2_callback(invocation->object_type->observers, OBJ_NODATA, sorcery_observer_notify_create, invocation->object);
1279         ao2_cleanup(invocation);
1280
1281         return 0;
1282 }
1283
1284 int ast_sorcery_create(const struct ast_sorcery *sorcery, void *object)
1285 {
1286         const struct ast_sorcery_object_details *details = object;
1287         RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, details->object->type, OBJ_KEY), ao2_cleanup);
1288         RAII_VAR(struct ast_sorcery_object_wizard *, object_wizard, NULL, ao2_cleanup);
1289         struct sorcery_details sdetails = {
1290                 .sorcery = sorcery,
1291                 .obj = object,
1292         };
1293
1294         if (!object_type) {
1295                 return -1;
1296         }
1297
1298         if ((object_wizard = ao2_callback(object_type->wizards, 0, sorcery_wizard_create, &sdetails)) &&
1299                 ao2_container_count(object_type->observers)) {
1300                 struct sorcery_observer_invocation *invocation = sorcery_observer_invocation_alloc(object_type, object);
1301
1302                 if (invocation && ast_taskprocessor_push(object_type->serializer, sorcery_observers_notify_create, invocation)) {
1303                         ao2_cleanup(invocation);
1304                 }
1305         }
1306
1307         return object_wizard ? 0 : -1;
1308 }
1309
1310 /*! \brief Internal callback function which notifies an individual observer that an object has been updated */
1311 static int sorcery_observer_notify_update(void *obj, void *arg, int flags)
1312 {
1313         const struct ast_sorcery_object_type_observer *observer = obj;
1314
1315         if (observer->callbacks->updated) {
1316                 observer->callbacks->updated(arg);
1317         }
1318
1319         return 0;
1320 }
1321
1322 /*! \brief Internal callback function which notifies observers that an object has been updated */
1323 static int sorcery_observers_notify_update(void *data)
1324 {
1325         struct sorcery_observer_invocation *invocation = data;
1326
1327         ao2_callback(invocation->object_type->observers, OBJ_NODATA, sorcery_observer_notify_update, invocation->object);
1328         ao2_cleanup(invocation);
1329
1330         return 0;
1331 }
1332
1333 /*! \brief Internal function which returns if a wizard has updated the object */
1334 static int sorcery_wizard_update(void *obj, void *arg, int flags)
1335 {
1336         const struct ast_sorcery_object_wizard *object_wizard = obj;
1337         const struct sorcery_details *details = arg;
1338
1339         return (object_wizard->wizard->update && !object_wizard->wizard->update(details->sorcery, object_wizard->data, details->obj) &&
1340                 !object_wizard->caching) ? CMP_MATCH | CMP_STOP : 0;
1341 }
1342
1343 int ast_sorcery_update(const struct ast_sorcery *sorcery, void *object)
1344 {
1345         const struct ast_sorcery_object_details *details = object;
1346         RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, details->object->type, OBJ_KEY), ao2_cleanup);
1347         RAII_VAR(struct ast_sorcery_object_wizard *, object_wizard, NULL, ao2_cleanup);
1348         struct sorcery_details sdetails = {
1349                 .sorcery = sorcery,
1350                 .obj = object,
1351         };
1352
1353         if (!object_type) {
1354                 return -1;
1355         }
1356
1357         if ((object_wizard = ao2_callback(object_type->wizards, 0, sorcery_wizard_update, &sdetails)) &&
1358                 ao2_container_count(object_type->observers)) {
1359                 struct sorcery_observer_invocation *invocation = sorcery_observer_invocation_alloc(object_type, object);
1360
1361                 if (invocation && ast_taskprocessor_push(object_type->serializer, sorcery_observers_notify_update, invocation)) {
1362                         ao2_cleanup(invocation);
1363                 }
1364         }
1365
1366         return object_wizard ? 0 : -1;
1367 }
1368
1369 /*! \brief Internal callback function which notifies an individual observer that an object has been deleted */
1370 static int sorcery_observer_notify_delete(void *obj, void *arg, int flags)
1371 {
1372         const struct ast_sorcery_object_type_observer *observer = obj;
1373
1374         if (observer->callbacks->deleted) {
1375                 observer->callbacks->deleted(arg);
1376         }
1377
1378         return 0;
1379 }
1380
1381 /*! \brief Internal callback function which notifies observers that an object has been deleted */
1382 static int sorcery_observers_notify_delete(void *data)
1383 {
1384         struct sorcery_observer_invocation *invocation = data;
1385
1386         ao2_callback(invocation->object_type->observers, OBJ_NODATA, sorcery_observer_notify_delete, invocation->object);
1387         ao2_cleanup(invocation);
1388
1389         return 0;
1390 }
1391
1392 /*! \brief Internal function which returns if a wizard has deleted the object */
1393 static int sorcery_wizard_delete(void *obj, void *arg, int flags)
1394 {
1395         const struct ast_sorcery_object_wizard *object_wizard = obj;
1396         const struct sorcery_details *details = arg;
1397
1398         return (object_wizard->wizard->delete && !object_wizard->wizard->delete(details->sorcery, object_wizard->data, details->obj) &&
1399                 !object_wizard->caching) ? CMP_MATCH | CMP_STOP : 0;
1400 }
1401
1402 int ast_sorcery_delete(const struct ast_sorcery *sorcery, void *object)
1403 {
1404         const struct ast_sorcery_object_details *details = object;
1405         RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, details->object->type, OBJ_KEY), ao2_cleanup);
1406         RAII_VAR(struct ast_sorcery_object_wizard *, object_wizard, NULL, ao2_cleanup);
1407         struct sorcery_details sdetails = {
1408                 .sorcery = sorcery,
1409                 .obj = object,
1410         };
1411
1412         if (!object_type) {
1413                 return -1;
1414         }
1415
1416         if ((object_wizard = ao2_callback(object_type->wizards, 0, sorcery_wizard_delete, &sdetails)) &&
1417                 ao2_container_count(object_type->observers)) {
1418                 struct sorcery_observer_invocation *invocation = sorcery_observer_invocation_alloc(object_type, object);
1419
1420                 if (invocation && ast_taskprocessor_push(object_type->serializer, sorcery_observers_notify_delete, invocation)) {
1421                         ao2_cleanup(invocation);
1422                 }
1423         }
1424
1425         return object_wizard ? 0 : -1;
1426 }
1427
1428 void ast_sorcery_unref(struct ast_sorcery *sorcery)
1429 {
1430         ao2_cleanup(sorcery);
1431 }
1432
1433 const char *ast_sorcery_object_get_id(const void *object)
1434 {
1435         const struct ast_sorcery_object_details *details = object;
1436         return details->object->id;
1437 }
1438
1439 const char *ast_sorcery_object_get_type(const void *object)
1440 {
1441         const struct ast_sorcery_object_details *details = object;
1442         return details->object->type;
1443 }
1444
1445 const char *ast_sorcery_object_get_extended(const void *object, const char *name)
1446 {
1447         const struct ast_sorcery_object_details *details = object;
1448         struct ast_variable *field;
1449
1450         for (field = details->object->extended; field; field = field->next) {
1451                 if (!strcmp(field->name + 1, name)) {
1452                         return field->value;
1453                 }
1454         }
1455
1456         return NULL;
1457 }
1458
1459 int ast_sorcery_object_set_extended(const void *object, const char *name, const char *value)
1460 {
1461         RAII_VAR(struct ast_variable *, field, NULL, ast_variables_destroy);
1462         struct ast_variable *extended = ast_variable_new(name, value, ""), *previous = NULL;
1463         const struct ast_sorcery_object_details *details = object;
1464
1465         if (!extended) {
1466                 return -1;
1467         }
1468
1469         for (field = details->object->extended; field; previous = field, field = field->next) {
1470                 if (!strcmp(field->name, name)) {
1471                         if (previous) {
1472                                 previous->next = field->next;
1473                         } else {
1474                                 details->object->extended = field->next;
1475                         }
1476                         field->next = NULL;
1477                         break;
1478                 }
1479         }
1480
1481         extended->next = details->object->extended;
1482         details->object->extended = extended;
1483
1484         return 0;
1485 }
1486
1487 int ast_sorcery_observer_add(const struct ast_sorcery *sorcery, const char *type, const struct ast_sorcery_observer *callbacks)
1488 {
1489         RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, type, OBJ_KEY), ao2_cleanup);
1490         struct ast_sorcery_object_type_observer *observer;
1491
1492         if (!object_type || !callbacks) {
1493                 return -1;
1494         }
1495
1496         if (!(observer = ao2_alloc(sizeof(*observer), NULL))) {
1497                 return -1;
1498         }
1499
1500         observer->callbacks = callbacks;
1501         ao2_link(object_type->observers, observer);
1502         ao2_ref(observer, -1);
1503
1504         return 0;
1505 }
1506
1507 /*! \brief Internal callback function for removing an observer */
1508 static int sorcery_observer_remove(void *obj, void *arg, int flags)
1509 {
1510         const struct ast_sorcery_object_type_observer *observer = obj;
1511
1512         return (observer->callbacks == arg) ? CMP_MATCH | CMP_STOP : 0;
1513 }
1514
1515 void ast_sorcery_observer_remove(const struct ast_sorcery *sorcery, const char *type, struct ast_sorcery_observer *callbacks)
1516 {
1517         RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, type, OBJ_KEY), ao2_cleanup);
1518
1519         if (!object_type) {
1520                 return;
1521         }
1522
1523         ao2_callback(object_type->observers, OBJ_NODATA | OBJ_UNLINK, sorcery_observer_remove, callbacks);
1524 }