Fix a variety of memory leaks
[asterisk/asterisk.git] / main / data.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2009, Eliel C. Sardanons (LU1ALY) <eliels@gmail.com>
5  *
6  * See http://www.asterisk.org for more information about
7  * the Asterisk project. Please do not directly contact
8  * any of the maintainers of this project for assistance;
9  * the project provides a web site, mailing lists and IRC
10  * channels for your use.
11  *
12  * This program is free software, distributed under the terms of
13  * the GNU General Public License Version 2. See the LICENSE file
14  * at the top of the source tree.
15  */
16
17 /*! \file
18  *
19  * \brief Data retrieval API.
20  *
21  * \author Brett Bryant <brettbryant@gmail.com>
22  * \author Eliel C. Sardanons (LU1ALY) <eliels@gmail.com>
23  */
24
25 #include "asterisk.h"
26
27 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
28
29 #include "asterisk/_private.h"
30
31 #include <regex.h>
32
33 #include "asterisk/module.h"
34 #include "asterisk/utils.h"
35 #include "asterisk/lock.h"
36 #include "asterisk/data.h"
37 #include "asterisk/astobj2.h"
38 #include "asterisk/xml.h"
39 #include "asterisk/cli.h"
40 #include "asterisk/term.h"
41 #include "asterisk/manager.h"
42 #include "asterisk/test.h"
43 #include "asterisk/frame.h"
44
45 /*** DOCUMENTATION
46         <manager name="DataGet" language="en_US">
47                 <synopsis>
48                         Retrieve the data api tree.
49                 </synopsis>
50                 <syntax>
51                         <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
52                         <parameter name="Path" required="true" />
53                         <parameter name="Search" />
54                         <parameter name="Filter" />
55                 </syntax>
56                 <description>
57                         <para>Retrieve the data api tree.</para>
58                 </description>
59         </manager>
60  ***/
61
62 #define NUM_DATA_NODE_BUCKETS   59
63 #define NUM_DATA_RESULT_BUCKETS 59
64 #define NUM_DATA_SEARCH_BUCKETS 59
65 #define NUM_DATA_FILTER_BUCKETS 59
66
67 /*! \brief The last compatible version. */
68 static const uint32_t latest_handler_compatible_version = 0;
69
70 /*! \brief The last compatible version. */
71 static const uint32_t latest_query_compatible_version = 0;
72
73 /*! \brief Current handler structure version. */
74 static const uint32_t current_handler_version = AST_DATA_HANDLER_VERSION;
75
76 /*! \brief Current query structure version. */
77 static const uint32_t current_query_version = AST_DATA_QUERY_VERSION;
78
79 /*! \brief The data tree to be returned by the callbacks and
80            managed by functions local to this file. */
81 struct ast_data {
82         enum ast_data_type type;
83
84         /*! \brief The node content. */
85         union {
86                 int32_t sint;
87                 uint32_t uint;
88                 double dbl;
89                 unsigned int boolean;
90                 char *str;
91                 char character;
92                 struct in_addr ipaddr;
93                 void *ptr;
94         } payload;
95
96         /*! \brief The filter node that depends on the current node,
97          * this is used only when creating the result tree. */
98         const struct data_filter *filter;
99
100         /*! \brief The list of nodes inside this node. */
101         struct ao2_container *children;
102         /*! \brief The name of the node. */
103         char name[0];
104 };
105
106 /*! \brief Type of comparisons allow in the search string. */
107 enum data_search_comparison {
108         DATA_CMP_UNKNOWN,
109         DATA_CMP_EQ,    /* =  */
110         DATA_CMP_NEQ,   /* != */
111         DATA_CMP_GT,    /* >  */
112         DATA_CMP_GE,    /* >= */
113         DATA_CMP_LT,    /* <  */
114         DATA_CMP_LE     /* <= */
115 };
116
117 /*! \brief The list of nodes with their search requirement. */
118 struct ast_data_search {
119         /*! \brief The value of the comparison. */
120         char *value;
121         /*! \brief The type of comparison. */
122         enum data_search_comparison cmp_type;
123         /*! \brief reference another node. */
124         struct ao2_container *children;
125         /*! \brief The name of the node we are trying to compare. */
126         char name[0];
127 };
128
129 struct data_filter;
130
131 /*! \brief The filter node. */
132 struct data_filter {
133         /*! \brief node childrens. */
134         struct ao2_container *children;
135         /*! \brief glob list */
136         AST_LIST_HEAD_NOLOCK(glob_list_t, data_filter) glob_list;
137         /*! \brief glob list entry */
138         AST_LIST_ENTRY(data_filter) list;
139         /*! \brief node name. */
140         char name[0];
141 };
142
143 /*! \brief A data container node pointing to the registered handler. */
144 struct data_provider {
145         /*! \brief node content handler. */
146         const struct ast_data_handler *handler;
147         /*! \brief Module providing this handler. */
148         struct ast_module *module;
149         /*! \brief children nodes. */
150         struct ao2_container *children;
151         /*! \brief Who registered this node. */
152         const char *registrar;
153         /*! \brief Node name. */
154         char name[0];
155 };
156
157 /*! \brief This structure is used by the iterator. */
158 struct ast_data_iterator {
159         /*! \brief The internal iterator. */
160         struct ao2_iterator internal_iterator;
161         /*! \brief The last returned node. */
162         struct ast_data *last;
163         /*! \brief The iterator pattern. */
164         const char *pattern;
165         /*! \brief The compiled patter. */
166         regex_t regex_pattern;
167         /*! \brief is a regular expression. */
168         unsigned int is_pattern:1;
169 };
170
171 struct {
172         /*! \brief The asterisk data main content structure. */
173         struct ao2_container *container;
174         /*! \brief asterisk data locking mechanism. */
175         ast_rwlock_t lock;
176 } root_data;
177
178 static void __data_result_print_cli(int fd, const struct ast_data *root, uint32_t depth);
179
180 /*!
181  * \internal
182  * \brief Common string hash function.
183  * \see ast_data_init
184  */
185 static int data_provider_hash(const void *obj, const int flags)
186 {
187         const struct data_provider *node = obj;
188         return ast_str_case_hash(node->name);
189 }
190
191 /*!
192  * \internal
193  * \brief Compare two data_provider's.
194  * \see ast_data_init
195  */
196 static int data_provider_cmp(void *obj1, void *obj2, int flags)
197 {
198         struct data_provider *node1 = obj1, *node2 = obj2;
199         return strcasecmp(node1->name, node2->name) ? 0 : CMP_MATCH;
200 }
201
202 /*!
203  * \internal
204  * \brief Common string hash function for data nodes
205  */
206 static int data_result_hash(const void *obj, const int flags)
207 {
208         const struct ast_data *node = obj;
209         return ast_str_hash(node->name);
210 }
211
212 /*!
213  * \internal
214  * \brief Common string comparison function
215  */
216 static int data_result_cmp(void *obj, void *arg, int flags)
217 {
218         struct ast_data *node1 = obj, *node2 = arg;
219         return strcasecmp(node1->name, node2->name) ? 0 : CMP_MATCH;
220 }
221
222 /*!
223  * \internal
224  * \brief Lock the data registered handlers structure for writing.
225  * \see data_unlock
226  */
227 #define data_write_lock() ast_rwlock_wrlock(&root_data.lock)
228
229 /*!
230  * \internal
231  * \brief Lock the data registered handlers structure for reading.
232  * \see data_unlock
233  */
234 #define data_read_lock() ast_rwlock_rdlock(&root_data.lock)
235
236 /*!
237  * \internal
238  * \brief Unlock the data registered handlers structure.
239  */
240 #define data_unlock() ast_rwlock_unlock(&root_data.lock)
241
242 /*!
243  * \internal
244  * \brief Check if a version is compatible with the current core.
245  * \param[in] structure_version The current structure version.
246  * \param[in] latest_compatible The latest compatible version.
247  * \param[in] current The current Data API version.
248  * \retval 1 If the module is compatible.
249  * \retval 0 If the module is NOT compatible.
250  */
251 static int data_structure_compatible(int structure_version, uint32_t latest_compatible,
252         uint32_t current)
253 {
254         if (structure_version >= latest_compatible && structure_version <= current) {
255                 return 1;
256         }
257
258         ast_log(LOG_ERROR, "A module is not compatible with the"
259                 "current data api version\n");
260
261         return 0;
262 }
263
264 /*!
265  * \internal
266  * \brief Get the next node name in a path (/node1/node2)
267  *        Avoid null nodes like //node1//node2/node3.
268  * \param[in] path The path where we are going to search for the next node name.
269  * \retval The next node name we found inside the given path.
270  * \retval NULL if there are no more node names.
271  */
272 static char *next_node_name(char **path)
273 {
274         char *res;
275
276         do {
277                 res = strsep(path, "/");
278         } while (res && ast_strlen_zero(res));
279
280         return res;
281 }
282
283 /*!
284  * \internal
285  * \brief Release the memory allocated by a call to ao2_alloc.
286  */
287 static void data_provider_destructor(void *obj)
288 {
289         struct data_provider *provider = obj;
290
291         ao2_ref(provider->children, -1);
292 }
293
294 /*!
295  * \internal
296  * \brief Create a new data node.
297  * \param[in] name The name of the node we are going to create.
298  * \param[in] handler The handler registered for this node.
299  * \param[in] registrar The name of the registrar.
300  * \retval NULL on error.
301  * \retval The allocated data node structure.
302  */
303 static struct data_provider *data_provider_new(const char *name,
304         const struct ast_data_handler *handler, const char *registrar)
305 {
306         struct data_provider *node;
307         size_t namelen;
308
309         namelen = strlen(name) + 1;
310
311         node = ao2_alloc(sizeof(*node) + namelen, data_provider_destructor);
312         if (!node) {
313                 return NULL;
314         }
315
316         node->handler = handler;
317         node->registrar = registrar;
318         strcpy(node->name, name);
319
320         /* initialize the childrens container. */
321         if (!(node->children = ao2_container_alloc(NUM_DATA_NODE_BUCKETS,
322                         data_provider_hash, data_provider_cmp))) {
323                 ao2_ref(node, -1);
324                 return NULL;
325         }
326
327         return node;
328 }
329
330 /*!
331  * \internal
332  * \brief Add a child node named 'name' to the 'parent' node.
333  * \param[in] parent Where to add the child node.
334  * \param[in] name The name of the child node.
335  * \param[in] handler The handler structure.
336  * \param[in] registrar Who registered this node.
337  * \retval NULL on error.
338  * \retval A newly allocated child in parent.
339  */
340 static struct data_provider *data_provider_add_child(struct ao2_container *parent,
341         const char *name, const struct ast_data_handler *handler, const char *registrar)
342 {
343         struct data_provider *child;
344
345         child = data_provider_new(name, handler, registrar);
346         if (!child) {
347                 return NULL;
348         }
349
350         ao2_link(parent, child);
351
352         return child;
353 }
354
355 /*!
356  * \internal
357  * \brief Find a child node, based on his name.
358  * \param[in] parent Where to find the node.
359  * \param[in] name The node name to find.
360  * \param[in] registrar Also check if the node was being used by this registrar.
361  * \retval NULL if a node wasn't found.
362  * \retval The node found.
363  * \note Remember to decrement the ref count of the returned node after using it.
364  */
365 static struct data_provider *data_provider_find(struct ao2_container *parent,
366         const char *name, const char *registrar)
367 {
368         struct data_provider *find_node, *found;
369
370         /* XXX avoid allocating a new data node for searching... */
371         find_node = data_provider_new(name, NULL, NULL);
372         if (!find_node) {
373                 return NULL;
374         }
375
376         found = ao2_find(parent, find_node, OBJ_POINTER);
377
378         /* free the created node used for searching. */
379         ao2_ref(find_node, -1);
380
381         if (found && found->registrar && registrar) {
382                 if (strcmp(found->registrar, registrar)) {
383                         /* if the name doesn't match, do not return this node. */
384                         ast_debug(1, "Registrar doesn't match, node was registered"
385                                 " by '%s' and we are searching for '%s'\n",
386                                 found->registrar, registrar);
387                         ao2_ref(found, -1);
388                         return NULL;
389                 }
390         }
391
392         return found;
393 }
394
395 /*!
396  * \internal
397  * \brief Release a group of nodes.
398  * \param[in] parent The parent node.
399  * \param[in] path The path of nodes to release.
400  * \param[in] registrar Who registered this node.
401  * \retval <0 on error.
402  * \retval 0 on success.
403  * \see data_provider_create
404  */
405 static int data_provider_release(struct ao2_container *parent, const char *path,
406         const char *registrar)
407 {
408         char *node_name, *rpath;
409         struct data_provider *child;
410         int ret = 0;
411
412         rpath = ast_strdupa(path);
413
414         node_name = next_node_name(&rpath);
415         if (!node_name) {
416                 return -1;
417         }
418
419         child = data_provider_find(parent, node_name, registrar);
420         if (!child) {
421                 return -1;
422         }
423
424         /* if this is not a terminal node. */
425         if (!child->handler && rpath) {
426                 ret = data_provider_release(child->children, rpath, registrar);
427         }
428
429         /* if this node is empty, unlink it. */
430         if (!ret && !ao2_container_count(child->children)) {
431                 ao2_unlink(parent, child);
432         }
433
434         ao2_ref(child, -1);
435
436         return ret;
437 }
438
439 /*!
440  * \internal
441  * \brief Release every node registered by 'registrar'.
442  * \param[in] parent The parent node.
443  * \param[in] registrar
444  * \see __ast_data_unregister
445  */
446 static void data_provider_release_all(struct ao2_container *parent,
447         const char *registrar)
448 {
449         struct ao2_iterator i;
450         struct data_provider *node;
451
452         i = ao2_iterator_init(parent, 0);
453         while ((node = ao2_iterator_next(&i))) {
454                 if (!node->handler) {
455                         /* this is a non-terminal node, go inside it. */
456                         data_provider_release_all(node->children, registrar);
457                         if (!ao2_container_count(node->children)) {
458                                 /* if this node was left empty, unlink it. */
459                                 ao2_unlink(parent, node);
460                         }
461                 } else {
462                         if (!strcmp(node->registrar, registrar)) {
463                                 /* if the registrars match, release it! */
464                                 ao2_unlink(parent, node);
465                         }
466                 }
467                 ao2_ref(node, -1);
468         }
469         ao2_iterator_destroy(&i);
470
471 }
472
473 /*!
474  * \internal
475  * \brief Create the middle nodes for the specified path (asterisk/testnode1/childnode)
476  * \param[in] parent Where to add the middle nodes structure.
477  * \param[in] path The path of nodes to add.
478  * \param[in] registrar Who is trying to create this node provider.
479  * \retval NULL on error.
480  * \retval The created node.
481  * \see data_provider_release
482  */
483 static struct data_provider *data_provider_create(struct ao2_container *parent,
484         const char *path, const char *registrar)
485 {
486         char *rpath, *node_name;
487         struct data_provider *child, *ret = NULL;
488
489         rpath = ast_strdupa(path);
490
491         node_name = next_node_name(&rpath);
492         if (!node_name) {
493                 /* no more nodes to create. */
494                 return NULL;
495         }
496
497         child = data_provider_find(parent, node_name, NULL);
498
499         if (!child) {
500                 /* nodes without handler are non-terminal nodes. */
501                 child = data_provider_add_child(parent, node_name, NULL, registrar);
502         }
503
504         if (rpath) {
505                 ret = data_provider_create(child->children, rpath, registrar);
506                 if (ret) {
507                         ao2_ref(child, -1);
508                 }
509         }
510
511         return ret ? ret : child;
512 }
513
514 int __ast_data_register(const char *path, const struct ast_data_handler *handler,
515         const char *registrar, struct ast_module *mod)
516 {
517         struct data_provider *node;
518
519         if (!path) {
520                 return -1;
521         }
522
523         /* check if the handler structure is compatible. */
524         if (!data_structure_compatible(handler->version,
525                 latest_handler_compatible_version,
526                 current_handler_version)) {
527                 return -1;
528         }
529
530         /* create the node structure for the registered handler. */
531         data_write_lock();
532
533         node = data_provider_create(root_data.container, path, registrar);
534         if (!node) {
535                 ast_log(LOG_ERROR, "Unable to create the specified path (%s) "
536                         "for '%s'.\n", path, registrar);
537                 data_unlock();
538                 return -1;
539         }
540
541         if (ao2_container_count(node->children) || node->handler) {
542                 ast_log(LOG_ERROR, "The node '%s' was already registered. "
543                         "We were unable to register '%s' for registrar '%s'.\n",
544                         node->name, path, registrar);
545                 ao2_ref(node, -1);
546                 data_unlock();
547                 return -1;
548         }
549
550         /* add handler to that node. */
551         node->handler = handler;
552         node->module = mod;
553
554         ao2_ref(node, -1);
555
556         data_unlock();
557
558         return 0;
559 }
560
561 int __ast_data_register_multiple(const struct ast_data_entry *data_entries,
562         size_t entries, const char *registrar, struct ast_module *mod)
563 {
564         int i, res;
565
566         for (i = 0; i < entries; i++) {
567                 res = __ast_data_register(data_entries[i].path, data_entries[i].handler,
568                                 registrar, mod);
569                 if (res) {
570                         /* unregister all the already registered nodes, and make
571                          * this an atomic action. */
572                         while ((--i) >= 0) {
573                                 __ast_data_unregister(data_entries[i].path, registrar);
574                         }
575                         return -1;
576                 }
577         }
578
579         return 0;
580 }
581
582 int __ast_data_unregister(const char *path, const char *registrar)
583 {
584         int ret = 0;
585
586         data_write_lock();
587         if (path) {
588                 ret = data_provider_release(root_data.container, path, registrar);
589         } else {
590                 data_provider_release_all(root_data.container, registrar);
591         }
592         data_unlock();
593
594         if (path && ret) {
595                 ast_log(LOG_ERROR, "Unable to unregister '%s' for '%s'\n",
596                         path, registrar);
597         }
598
599         return ret;
600 }
601
602 /*!
603  * \internal
604  * \brief Is a char used to specify a comparison?
605  * \param[in] a Character to evaluate.
606  * \retval 1 It is a char used to specify a comparison.
607  * \retval 0 It is NOT a char used to specify a comparison.
608  */
609 static int data_search_comparison_char(char a)
610 {
611         switch (a) {
612         case '!':
613         case '=':
614         case '<':
615         case '>':
616                 return 1;
617         }
618
619         return 0;
620 }
621
622 /*!
623  * \internal
624  * \brief Get the type of comparison.
625  */
626 static enum data_search_comparison data_search_comparison_type(const char *comparison)
627 {
628         if (!strcmp(comparison, "=")) {
629                 return DATA_CMP_EQ;
630         } else if (!strcmp(comparison, "!=")) {
631                 return DATA_CMP_NEQ;
632         } else if (!strcmp(comparison, "<")) {
633                 return DATA_CMP_LT;
634         } else if (!strcmp(comparison, ">")) {
635                 return DATA_CMP_GT;
636         } else if (!strcmp(comparison, "<=")) {
637                 return DATA_CMP_LE;
638         } else if (!strcmp(comparison, ">=")) {
639                 return DATA_CMP_GE;
640         }
641
642         return DATA_CMP_UNKNOWN;
643 }
644
645 /*!
646  * \internal
647  * \brief Common string hash function for data nodes
648  */
649 static int data_search_hash(const void *obj, const int flags)
650 {
651         const struct ast_data_search *node = obj;
652         return ast_str_hash(node->name);
653 }
654
655 /*!
656  * \internal
657  * \brief Common string comparison function
658  */
659 static int data_search_cmp(void *obj, void *arg, int flags)
660 {
661         struct ast_data_search *node1 = obj, *node2 = arg;
662         return strcasecmp(node1->name, node2->name) ? 0 : CMP_MATCH;
663 }
664
665 /*!
666  * \internal
667  * \brief Destroy the ao2 search node.
668  */
669 static void data_search_destructor(void *obj)
670 {
671         struct ast_data_search *node = obj;
672
673         if (node->value) {
674                 ast_free(node->value);
675         }
676
677         ao2_ref(node->children, -1);
678 }
679
680 /*!
681  * \internal
682  * \brief Allocate a search node.
683  * \retval NULL on error.
684  * \retval non-NULL The allocated search node structure.
685  */
686 static struct ast_data_search *data_search_alloc(const char *name)
687 {
688         struct ast_data_search *res;
689         size_t name_len = strlen(name) + 1;
690
691         res = ao2_alloc(sizeof(*res) + name_len, data_search_destructor);
692         if (!res) {
693                 return NULL;
694         }
695
696         res->children = ao2_container_alloc(NUM_DATA_SEARCH_BUCKETS, data_search_hash,
697                 data_search_cmp);
698
699         if (!res->children) {
700                 ao2_ref(res, -1);
701                 return NULL;
702         }
703
704         strcpy(res->name, name);
705
706         return res;
707 }
708
709 /*!
710  * \internal
711  * \brief Find a child node, based on his name.
712  * \param[in] parent Where to find the node.
713  * \param[in] name The node name to find.
714  * \retval NULL if a node wasn't found.
715  * \retval The node found.
716  * \note Remember to decrement the ref count of the returned node after using it.
717  */
718 static struct ast_data_search *data_search_find(struct ao2_container *parent,
719         const char *name)
720 {
721         struct ast_data_search *find_node, *found;
722
723         find_node = data_search_alloc(name);
724         if (!find_node) {
725                 return NULL;
726         }
727
728         found = ao2_find(parent, find_node, OBJ_POINTER);
729
730         /* free the created node used for searching. */
731         ao2_ref(find_node, -1);
732
733         return found;
734 }
735
736 /*!
737  * \internal
738  * \brief Add a child node named 'name' to the 'parent' node.
739  * \param[in] parent Where to add the child node.
740  * \param[in] name The name of the child node.
741  * \retval NULL on error.
742  * \retval A newly allocated child in parent.
743  */
744 static struct ast_data_search *data_search_add_child(struct ao2_container *parent,
745         const char *name)
746 {
747         struct ast_data_search *child;
748
749         child = data_search_alloc(name);
750         if (!child) {
751                 return NULL;
752         }
753
754         ao2_link(parent, child);
755
756         return child;
757 }
758
759 /*!
760  * \internal
761  * \brief Create the middle nodes for the specified path (asterisk/testnode1/childnode)
762  * \param[in] parent Where to add the middle nodes structure.
763  * \param[in] path The path of nodes to add.
764  * \retval NULL on error.
765  * \retval The created node.
766  */
767 static struct ast_data_search *data_search_create(struct ao2_container *parent,
768         const char *path)
769 {
770         char *rpath, *node_name;
771         struct ast_data_search *child = NULL;
772         struct ao2_container *current = parent;
773
774         rpath = ast_strdupa(path);
775
776         node_name = next_node_name(&rpath);
777         while (node_name) {
778                 child = data_search_find(current, node_name);
779                 if (!child) {
780                         child = data_search_add_child(current, node_name);
781                 }
782                 ao2_ref(child, -1);
783                 current = child->children;
784                 node_name = next_node_name(&rpath);
785         }
786
787         return child;
788 }
789
790 /*!
791  * \internal
792  * \brief Allocate a tree with the search string parsed.
793  * \param[in] search_string The search string.
794  * \retval NULL on error.
795  * \retval non-NULL A dynamically allocated search tree.
796  */
797 static struct ast_data_search *data_search_generate(const char *search_string)
798 {
799         struct ast_str *name, *value, *comparison;
800         char *elements, *search_string_dup, *saveptr;
801         int i;
802         struct ast_data_search *root, *child;
803         enum data_search_comparison cmp_type;
804         size_t search_string_len;
805
806         if (!search_string) {
807                 ast_log(LOG_ERROR, "You must pass a valid search string.\n");
808                 return NULL;
809         }
810
811         search_string_len = strlen(search_string);
812
813         name = ast_str_create(search_string_len);
814         if (!name) {
815                 return NULL;
816         }
817         value = ast_str_create(search_string_len);
818         if (!value) {
819                 ast_free(name);
820                 return NULL;
821         }
822         comparison = ast_str_create(search_string_len);
823         if (!comparison) {
824                 ast_free(name);
825                 ast_free(value);
826                 return NULL;
827         }
828
829         search_string_dup = ast_strdupa(search_string);
830
831         /* Create the root node (just used as a container) */
832         root = data_search_alloc("/");
833         if (!root) {
834                 ast_free(name);
835                 ast_free(value);
836                 ast_free(comparison);
837                 return NULL;
838         }
839
840         for (elements = strtok_r(search_string_dup, ",", &saveptr); elements;
841                 elements = strtok_r(NULL, ",", &saveptr)) {
842                 /* Parse the name */
843                 ast_str_reset(name);
844                 for (i = 0; !data_search_comparison_char(elements[i]) &&
845                         elements[i]; i++) {
846                         ast_str_append(&name, 0, "%c", elements[i]);
847                 }
848
849                 /* check if the syntax is ok. */
850                 if (!data_search_comparison_char(elements[i])) {
851                         /* if this is the end of the string, then this is
852                          * an error! */
853                         ast_log(LOG_ERROR, "Invalid search string!\n");
854                         continue;
855                 }
856
857                 /* parse the comparison string. */
858                 ast_str_reset(comparison);
859                 for (; data_search_comparison_char(elements[i]) && elements[i]; i++) {
860                         ast_str_append(&comparison, 0, "%c", elements[i]);
861                 }
862
863                 /* parse the value string. */
864                 ast_str_reset(value);
865                 for (; elements[i]; i++) {
866                         ast_str_append(&value, 0, "%c", elements[i]);
867                 }
868
869                 cmp_type = data_search_comparison_type(ast_str_buffer(comparison));
870                 if (cmp_type == DATA_CMP_UNKNOWN) {
871                         ast_log(LOG_ERROR, "Invalid comparison '%s'\n",
872                                 ast_str_buffer(comparison));
873                         continue;
874                 }
875
876                 /* add this node to the tree. */
877                 child = data_search_create(root->children, ast_str_buffer(name));
878                 if (child) {
879                         child->cmp_type = cmp_type;
880                         child->value = ast_strdup(ast_str_buffer(value));
881                 }
882         }
883
884         ast_free(name);
885         ast_free(value);
886         ast_free(comparison);
887
888         return root;
889 }
890
891 /*!
892  * \internal
893  * \brief Release the allocated memory for the search tree.
894  * \param[in] search The search tree root node.
895  */
896 static void data_search_release(struct ast_data_search *search)
897 {
898         ao2_ref(search, -1);
899 }
900
901 /*!
902  * \internal
903  * \brief Based on the kind of comparison and the result in cmpval, return
904  *        if it matches.
905  * \param[in] cmpval A result returned by a strcmp() for example.
906  * \param[in] comparison_type The kind of comparison (<,>,=,!=,...)
907  * \retval 1 If the comparison doesn't match.
908  * \retval 0 If the comparison matches.
909  */
910 static inline int data_search_comparison_result(int cmpval,
911         enum data_search_comparison comparison_type)
912 {
913         switch (comparison_type) {
914         case DATA_CMP_GE:
915                 if (cmpval >= 0) {
916                         return 0;
917                 }
918                 break;
919         case DATA_CMP_LE:
920                 if (cmpval <= 0) {
921                         return 0;
922                 }
923                 break;
924         case DATA_CMP_EQ:
925                 if (cmpval == 0) {
926                         return 0;
927                 }
928                 break;
929         case DATA_CMP_NEQ:
930                 if (cmpval != 0) {
931                         return 0;
932                 }
933                 break;
934         case DATA_CMP_LT:
935                 if (cmpval < 0) {
936                         return 0;
937                 }
938                 break;
939         case DATA_CMP_GT:
940                 if (cmpval > 0) {
941                         return 0;
942                 }
943                 break;
944         case DATA_CMP_UNKNOWN:
945                 break;
946         }
947         return 1;
948 }
949
950 /*!
951  * \internal
952  * \brief Get an internal node, from the search tree.
953  * \param[in] node A node container.
954  * \param[in] path The path to the needed internal node.
955  * \retval NULL if the internal node is not found.
956  * \retval non-NULL the internal node with path 'path'.
957  */
958 static struct ast_data_search *data_search_get_node(const struct ast_data_search *node,
959         const char *path)
960 {
961         char *savepath, *node_name;
962         struct ast_data_search *child, *current = (struct ast_data_search *) node;
963
964         if (!node) {
965                 return NULL;
966         }
967
968         savepath = ast_strdupa(path);
969         node_name = next_node_name(&savepath);
970
971         while (node_name) {
972                 child = data_search_find(current->children, node_name);
973                 if (current != node) {
974                         ao2_ref(current, -1);
975                 }
976                 if (!child) {
977                         return NULL;
978                 };
979                 current = child;
980                 node_name = next_node_name(&savepath);
981         }
982
983         return current;
984 }
985
986 /*!
987  * \internal
988  * \brief Based on a search tree, evaluate the specified 'name' inside the tree with the
989  *        current string value.
990  *        .search = "somename=somestring"
991  *        name = "somename"
992  *        value is the current value of something and will be evaluated against "somestring".
993  * \param[in] root The root node pointer of the search tree.
994  * \param[in] name The name of the specific.
995  * \param[in] value The value to compare.
996  * \returns The strcmp return value.
997  */
998 static int data_search_cmp_string(const struct ast_data_search *root, const char *name,
999         char *value)
1000 {
1001         struct ast_data_search *child;
1002         enum data_search_comparison cmp_type;
1003         int ret;
1004
1005         child = data_search_get_node(root, name);
1006         if (!child) {
1007                 return 0;
1008         }
1009
1010         ret = strcmp(value, child->value);
1011         cmp_type = child->cmp_type;
1012
1013         ao2_ref(child, -1);
1014
1015         return data_search_comparison_result(ret, cmp_type);
1016 }
1017
1018 /*!
1019  * \internal
1020  * \brief Based on a search tree, evaluate the specified 'name' inside the tree with the
1021  *        current pointer address value.
1022  *        .search = "something=0x32323232"
1023  *        name = "something"
1024  *        value is the current value of something and will be evaluated against "0x32323232".
1025  * \param[in] root The root node pointer of the search tree.
1026  * \param[in] name The name of the specific.
1027  * \param[in] ptr The pointer address to compare.
1028  * \returns The (value - current_value) result.
1029  */
1030 static int data_search_cmp_ptr(const struct ast_data_search *root, const char *name,
1031         void *ptr)
1032 {
1033         struct ast_data_search *child;
1034         enum data_search_comparison cmp_type;
1035         void *node_ptr;
1036
1037         child = data_search_get_node(root, name);
1038         if (!child) {
1039                 return 0;
1040         }
1041
1042         cmp_type = child->cmp_type;
1043
1044         if (sscanf(child->value, "%p", &node_ptr) <= 0) {
1045                 ao2_ref(child, -1);
1046                 return 1;
1047         }
1048
1049         ao2_ref(child, -1);
1050
1051         return data_search_comparison_result((node_ptr - ptr), cmp_type);
1052 }
1053
1054 /*!
1055  * \internal
1056  * \brief Based on a search tree, evaluate the specified 'name' inside the tree with the
1057  *        current ipv4 address value.
1058  *        .search = "something=192.168.2.2"
1059  *        name = "something"
1060  *        value is the current value of something and will be evaluated against "192.168.2.2".
1061  * \param[in] root The root node pointer of the search tree.
1062  * \param[in] name The name of the specific.
1063  * \param[in] addr The ipv4 address value to compare.
1064  * \returns The (value - current_value) result.
1065  */
1066 static int data_search_cmp_ipaddr(const struct ast_data_search *root, const char *name,
1067         struct in_addr addr)
1068 {
1069         struct ast_data_search *child;
1070         enum data_search_comparison cmp_type;
1071         struct in_addr node_addr;
1072
1073         child = data_search_get_node(root, name);
1074         if (!child) {
1075                 return 0;
1076         }
1077         cmp_type = child->cmp_type;
1078
1079         inet_aton(child->value, &node_addr);
1080
1081         ao2_ref(child, -1);
1082
1083         return data_search_comparison_result((node_addr.s_addr - addr.s_addr), cmp_type);
1084 }
1085
1086 /*!
1087  * \internal
1088  * \brief Based on a search tree, evaluate the specified 'name' inside the tree with the
1089  *        current boolean value.
1090  *        .search = "something=true"
1091  *        name = "something"
1092  *        value is the current value of something and will be evaluated against "true".
1093  * \param[in] root The root node pointer of the search tree.
1094  * \param[in] name The name of the specific.
1095  * \param[in] value The boolean value to compare.
1096  * \returns The (value - current_value) result.
1097  */
1098 static int data_search_cmp_bool(const struct ast_data_search *root, const char *name,
1099         unsigned int value)
1100 {
1101         struct ast_data_search *child;
1102         unsigned int node_value;
1103         enum data_search_comparison cmp_type;
1104
1105         child = data_search_get_node(root, name);
1106         if (!child) {
1107                 return 0;
1108         }
1109
1110         node_value = abs(ast_true(child->value));
1111         cmp_type = child->cmp_type;
1112
1113         ao2_ref(child, -1);
1114
1115         return data_search_comparison_result(value - node_value, cmp_type);
1116 }
1117
1118 /*!
1119  * \internal
1120  * \brief Based on a search tree, evaluate the specified 'name' inside the tree with the
1121  *        current double value.
1122  *        .search = "something=222"
1123  *        name = "something"
1124  *        value is the current value of something and will be evaluated against "222".
1125  * \param[in] root The root node pointer of the search tree.
1126  * \param[in] name The name of the specific.
1127  * \param[in] value The double value to compare.
1128  * \returns The (value - current_value) result.
1129  */
1130 static int data_search_cmp_dbl(const struct ast_data_search *root, const char *name,
1131         double value)
1132 {
1133         struct ast_data_search *child;
1134         double node_value;
1135         enum data_search_comparison cmp_type;
1136
1137         child = data_search_get_node(root, name);
1138         if (!child) {
1139                 return 0;
1140         }
1141
1142         node_value = strtod(child->value, NULL);
1143         cmp_type = child->cmp_type;
1144
1145         ao2_ref(child, -1);
1146
1147         return data_search_comparison_result(value - node_value, cmp_type);
1148 }
1149
1150 /*!
1151  * \internal
1152  * \brief Based on a search tree, evaluate the specified 'name' inside the tree with the
1153  *        current unsigned integer value.
1154  *        .search = "something=10"
1155  *        name = "something"
1156  *        value is the current value of something and will be evaluated against "10".
1157  * \param[in] root The root node pointer of the search tree.
1158  * \param[in] name The name of the specific.
1159  * \param[in] value The unsigned value to compare.
1160  * \returns The strcmp return value.
1161  */
1162 static int data_search_cmp_uint(const struct ast_data_search *root, const char *name,
1163         unsigned int value)
1164 {
1165         struct ast_data_search *child;
1166         unsigned int node_value;
1167         enum data_search_comparison cmp_type;
1168
1169         child = data_search_get_node(root, name);
1170         if (!child) {
1171                 return 0;
1172         }
1173
1174         node_value = atoi(child->value);
1175         cmp_type = child->cmp_type;
1176
1177         ao2_ref(child, -1);
1178
1179         return data_search_comparison_result(value - node_value, cmp_type);
1180 }
1181
1182 /*!
1183  * \internal
1184  * \brief Based on a search tree, evaluate the specified 'name' inside the tree with the
1185  *        current signed integer value.
1186  *        .search = "something=10"
1187  *        name = "something"
1188  *        value is the current value of something and will be evaluated against "10".
1189  * \param[in] root The root node pointer of the search tree.
1190  * \param[in] name The name of the specific.
1191  * \param[in] value The value to compare.
1192  * \returns The strcmp return value.
1193  */
1194 static int data_search_cmp_int(const struct ast_data_search *root, const char *name,
1195         int value)
1196 {
1197         struct ast_data_search *child;
1198         int node_value;
1199         enum data_search_comparison cmp_type;
1200
1201         child = data_search_get_node(root, name);
1202         if (!child) {
1203                 return 0;
1204         }
1205
1206         node_value = atoi(child->value);
1207         cmp_type = child->cmp_type;
1208
1209         ao2_ref(child, -1);
1210
1211         return data_search_comparison_result(value - node_value, cmp_type);
1212 }
1213
1214 /*!
1215  * \internal
1216  * \brief Based on a search tree, evaluate the specified 'name' inside the tree with the
1217  *        current character value.
1218  *        .search = "something=c"
1219  *        name = "something"
1220  *        value is the current value of something and will be evaluated against "c".
1221  * \param[in] root The root node pointer of the search tree.
1222  * \param[in] name The name of the specific.
1223  * \param[in] value The boolean value to compare.
1224  * \returns The (value - current_value) result.
1225  */
1226 static int data_search_cmp_char(const struct ast_data_search *root, const char *name,
1227         char value)
1228 {
1229         struct ast_data_search *child;
1230         char node_value;
1231         enum data_search_comparison cmp_type;
1232
1233         child = data_search_get_node(root, name);
1234         if (!child) {
1235                 return 0;
1236         }
1237
1238         node_value = *(child->value);
1239         cmp_type = child->cmp_type;
1240
1241         ao2_ref(child, -1);
1242
1243         return data_search_comparison_result(value - node_value, cmp_type);
1244 }
1245
1246 /*!
1247  * \internal
1248  * \brief Get the member pointer, from a mapping structure, based on its name.
1249  * \XXX We will need to improve performance here!!.
1250  * \retval <0 if the member was not found.
1251  * \retval >=0 The member position in the mapping structure.
1252  */
1253 static inline int data_search_mapping_find(const struct ast_data_mapping_structure *map,
1254         size_t mapping_len,
1255         const char *member_name)
1256 {
1257         int i;
1258
1259         for (i = 0; i < mapping_len; i++) {
1260                 if (!strcmp(map[i].name, member_name)) {
1261                         return i;
1262                 }
1263         }
1264
1265         return -1;
1266 }
1267
1268 int __ast_data_search_cmp_structure(const struct ast_data_search *search,
1269         const struct ast_data_mapping_structure *mapping, size_t mapping_len,
1270         void *structure, const char *structure_name)
1271 {
1272         struct ao2_iterator i;
1273         struct ast_data_search *node, *struct_children;
1274         int member, notmatch = 0;
1275
1276         if (!search) {
1277                 return 0;
1278         }
1279
1280         struct_children = data_search_get_node(search, structure_name);
1281         if (!struct_children) {
1282                 return 0;
1283         }
1284
1285         i = ao2_iterator_init(struct_children->children, 0);
1286         while ((node = ao2_iterator_next(&i))) {
1287                 member = data_search_mapping_find(mapping, mapping_len, node->name);
1288                 if (member < 0) {
1289                         /* the structure member name doesn't match! */
1290                         ao2_ref(node, -1);
1291                         ao2_ref(struct_children, -1);
1292                         ao2_iterator_destroy(&i);
1293                         return 0;
1294                 }
1295
1296                 notmatch = 0;
1297                 switch (mapping[member].type) {
1298                 case AST_DATA_PASSWORD:
1299                         notmatch = data_search_cmp_string(struct_children,
1300                                 node->name,
1301                                 mapping[member].get.AST_DATA_PASSWORD(structure));
1302                         break;
1303                 case AST_DATA_TIMESTAMP:
1304                         notmatch = data_search_cmp_uint(struct_children,
1305                                 node->name,
1306                                 mapping[member].get.AST_DATA_TIMESTAMP(structure));
1307                         break;
1308                 case AST_DATA_SECONDS:
1309                         notmatch = data_search_cmp_uint(struct_children,
1310                                 node->name,
1311                                 mapping[member].get.AST_DATA_SECONDS(structure));
1312                         break;
1313                 case AST_DATA_MILLISECONDS:
1314                         notmatch = data_search_cmp_uint(struct_children,
1315                                 node->name,
1316                                 mapping[member].get.AST_DATA_MILLISECONDS(structure));
1317                         break;
1318                 case AST_DATA_STRING:
1319                         notmatch = data_search_cmp_string(struct_children,
1320                                 node->name,
1321                                 mapping[member].get.AST_DATA_STRING(structure));
1322                         break;
1323                 case AST_DATA_CHARACTER:
1324                         notmatch = data_search_cmp_char(struct_children,
1325                                 node->name,
1326                                 mapping[member].get.AST_DATA_CHARACTER(structure));
1327                         break;
1328                 case AST_DATA_INTEGER:
1329                         notmatch = data_search_cmp_int(struct_children,
1330                                 node->name,
1331                                 mapping[member].get.AST_DATA_INTEGER(structure));
1332                         break;
1333                 case AST_DATA_BOOLEAN:
1334                         notmatch = data_search_cmp_bool(struct_children,
1335                                 node->name,
1336                                 mapping[member].get.AST_DATA_BOOLEAN(structure));
1337                         break;
1338                 case AST_DATA_UNSIGNED_INTEGER:
1339                         notmatch = data_search_cmp_uint(struct_children,
1340                                 node->name,
1341                                 mapping[member].get.AST_DATA_UNSIGNED_INTEGER(structure));
1342                         break;
1343                 case AST_DATA_DOUBLE:
1344                         notmatch = data_search_cmp_dbl(struct_children,
1345                                 node->name,
1346                                 mapping[member].get.AST_DATA_DOUBLE(structure));
1347                         break;
1348                 case AST_DATA_IPADDR:
1349                         notmatch = data_search_cmp_ipaddr(struct_children,
1350                                 node->name,
1351                                 mapping[member].get.AST_DATA_IPADDR(structure));
1352                         break;
1353                 case AST_DATA_POINTER:
1354                         notmatch = data_search_cmp_ptr(struct_children,
1355                                 node->name,
1356                                 mapping[member].get.AST_DATA_POINTER(structure));
1357                         break;
1358                 case AST_DATA_CONTAINER:
1359                         break;
1360                 }
1361
1362                 ao2_ref(node, -1);
1363         }
1364         ao2_iterator_destroy(&i);
1365
1366         ao2_ref(struct_children, -1);
1367
1368         return notmatch;
1369 }
1370
1371 /*!
1372  * \internal
1373  * \brief Release the memory allocated by a call to ao2_alloc.
1374  */
1375 static void data_result_destructor(void *obj)
1376 {
1377         struct ast_data *root = obj;
1378
1379         switch (root->type) {
1380         case AST_DATA_PASSWORD:
1381         case AST_DATA_STRING:
1382                 ast_free(root->payload.str);
1383                 ao2_ref(root->children, -1);
1384                 break;
1385         case AST_DATA_POINTER:
1386         case AST_DATA_CHARACTER:
1387         case AST_DATA_CONTAINER:
1388         case AST_DATA_INTEGER:
1389         case AST_DATA_TIMESTAMP:
1390         case AST_DATA_SECONDS:
1391         case AST_DATA_MILLISECONDS:
1392         case AST_DATA_UNSIGNED_INTEGER:
1393         case AST_DATA_DOUBLE:
1394         case AST_DATA_BOOLEAN:
1395         case AST_DATA_IPADDR:
1396                 ao2_ref(root->children, -1);
1397                 break;
1398         }
1399 }
1400
1401 static struct ast_data *data_result_create(const char *name)
1402 {
1403         struct ast_data *res;
1404         size_t namelen;
1405
1406         namelen = ast_strlen_zero(name) ? 1 : strlen(name) + 1;
1407
1408         res = ao2_alloc(sizeof(*res) + namelen, data_result_destructor);
1409         if (!res) {
1410                 return NULL;
1411         }
1412
1413         strcpy(res->name, namelen ? name : "");
1414
1415         /* initialize the children container */
1416         res->children = ao2_container_alloc(NUM_DATA_RESULT_BUCKETS, data_result_hash,
1417                 data_result_cmp);
1418         if (!res->children) {
1419                 ao2_ref(res, -1);
1420                 return NULL;
1421         }
1422
1423         /* set this node as a container. */
1424         res->type = AST_DATA_CONTAINER;
1425
1426         return res;
1427 }
1428
1429 /*!
1430  * \internal
1431  * \brief Find a child node, based on its name.
1432  * \param[in] root The starting point.
1433  * \param[in] name The child name.
1434  * \retval NULL if the node wasn't found.
1435  * \retval non-NULL the node we were looking for.
1436  */
1437 static struct ast_data *data_result_find_child(struct ast_data *root, const char *name)
1438 {
1439         struct ast_data *found, *find_node;
1440
1441         find_node = data_result_create(name);
1442         if (!find_node) {
1443                 return NULL;
1444         }
1445
1446         found = ao2_find(root->children, find_node, OBJ_POINTER);
1447
1448         /* release the temporary created node used for searching. */
1449         ao2_ref(find_node, -1);
1450
1451         return found;
1452 }
1453
1454 int ast_data_search_match(const struct ast_data_search *search, struct ast_data *data)
1455 {
1456         struct ao2_iterator i, ii;
1457         struct ast_data_search *s, *s_child;
1458         struct ast_data *d_child;
1459         int notmatch = 1;
1460
1461         if (!search) {
1462                 return 1;
1463         }
1464
1465         s_child = data_search_find(search->children, data->name);
1466         if (!s_child) {
1467                 /* nothing to compare */
1468                 ao2_ref(s_child, -1);
1469                 return 1;
1470         }
1471
1472         i = ao2_iterator_init(s_child->children, 0);
1473         while ((s = ao2_iterator_next(&i))) {
1474                 if (!ao2_container_count(s->children)) {
1475                         /* compare this search node with every data node */
1476                         d_child = data_result_find_child(data, s->name);
1477                         if (!d_child) {
1478                                 ao2_ref(s, -1);
1479                                 notmatch = 1;
1480                                 continue;
1481                         }
1482
1483                         switch (d_child->type) {
1484                         case AST_DATA_PASSWORD:
1485                         case AST_DATA_STRING:
1486                                 notmatch = data_search_cmp_string(s_child, d_child->name,
1487                                         d_child->payload.str);
1488                                 break;
1489                         case AST_DATA_CHARACTER:
1490                                 notmatch = data_search_cmp_char(s_child, d_child->name,
1491                                         d_child->payload.character);
1492                                 break;
1493                         case AST_DATA_INTEGER:
1494                                 notmatch = data_search_cmp_int(s_child, d_child->name,
1495                                         d_child->payload.sint);
1496                                 break;
1497                         case AST_DATA_BOOLEAN:
1498                                 notmatch = data_search_cmp_bool(s_child, d_child->name,
1499                                         d_child->payload.boolean);
1500                                 break;
1501                         case AST_DATA_UNSIGNED_INTEGER:
1502                                 notmatch = data_search_cmp_uint(s_child, d_child->name,
1503                                         d_child->payload.uint);
1504                                 break;
1505                         case AST_DATA_TIMESTAMP:
1506                         case AST_DATA_SECONDS:
1507                         case AST_DATA_MILLISECONDS:
1508                         case AST_DATA_DOUBLE:
1509                                 notmatch = data_search_cmp_uint(s_child, d_child->name,
1510                                         d_child->payload.dbl);
1511                                 break;
1512                         case AST_DATA_IPADDR:
1513                                 notmatch = data_search_cmp_ipaddr(s_child, d_child->name,
1514                                         d_child->payload.ipaddr);
1515                                 break;
1516                         case AST_DATA_POINTER:
1517                                 notmatch = data_search_cmp_ptr(s_child, d_child->name,
1518                                         d_child->payload.ptr);
1519                                 break;
1520                         case AST_DATA_CONTAINER:
1521                                 break;
1522                         }
1523                         ao2_ref(d_child, -1);
1524                 } else {
1525                         ii = ao2_iterator_init(data->children, 0);
1526                         while ((d_child = ao2_iterator_next(&ii))) {
1527                                 if (strcmp(d_child->name, s->name)) {
1528                                         ao2_ref(d_child, -1);
1529                                         continue;
1530                                 }
1531                                 if (!(notmatch = !ast_data_search_match(s_child, d_child))) {
1532                                         /* do not continue if we have a match. */
1533                                         ao2_ref(d_child, -1);
1534                                         break;
1535                                 }
1536                                 ao2_ref(d_child, -1);
1537                         }
1538                         ao2_iterator_destroy(&ii);
1539                 }
1540                 ao2_ref(s, -1);
1541                 if (notmatch) {
1542                         /* do not continue if we don't have a match. */
1543                         break;
1544                 }
1545         }
1546         ao2_iterator_destroy(&i);
1547
1548         ao2_ref(s_child, -1);
1549
1550         return !notmatch;
1551 }
1552
1553 /*!
1554  * \internal
1555  * \brief Get an internal node, from the result set.
1556  * \param[in] node A node container.
1557  * \param[in] path The path to the needed internal node.
1558  * \retval NULL if the internal node is not found.
1559  * \retval non-NULL the internal node with path 'path'.
1560  */
1561 static struct ast_data *data_result_get_node(struct ast_data *node,
1562         const char *path)
1563 {
1564         char *savepath, *node_name;
1565         struct ast_data *child, *current = node;
1566
1567         savepath = ast_strdupa(path);
1568         node_name = next_node_name(&savepath);
1569
1570         while (node_name) {
1571                 child = data_result_find_child(current, node_name);
1572                 if (current != node) {
1573                         ao2_ref(current, -1);
1574                 }
1575                 if (!child) {
1576                         return NULL;
1577                 }
1578                 current = child;
1579                 node_name = next_node_name(&savepath);
1580         }
1581
1582         /* do not increment the refcount of the returned object. */
1583         if (current != node) {
1584                 ao2_ref(current, -1);
1585         }
1586
1587         return current;
1588 }
1589
1590 /*!
1591  * \internal
1592  * \brief Add a child to the specified root node.
1593  * \param[in] root The root node pointer.
1594  * \param[in] child The child to add to the root node.
1595  */
1596 static void data_result_add_child(struct ast_data *root, struct ast_data *child)
1597 {
1598         ao2_link(root->children, child);
1599 }
1600
1601 /*!
1602  * \internal
1603  * \brief Common string hash function for data nodes
1604  */
1605 static int data_filter_hash(const void *obj, const int flags)
1606 {
1607         const struct data_filter *node = obj;
1608         return ast_str_hash(node->name);
1609 }
1610
1611 /*!
1612  * \internal
1613  * \brief Common string comparison function
1614  */
1615 static int data_filter_cmp(void *obj, void *arg, int flags)
1616 {
1617         struct data_filter *node1 = obj, *node2 = arg;
1618         return strcasecmp(node1->name, node2->name) ? 0 : CMP_MATCH;
1619 }
1620
1621 /*!
1622  * \internal
1623  * \brief Destroy a data filter tree.
1624  * \param[in] obj Data filter list to be destroyed.
1625  */
1626 static void data_filter_destructor(void *obj)
1627 {
1628         struct data_filter *filter = obj, *globres;
1629
1630         AST_LIST_TRAVERSE(&(filter->glob_list), globres, list) {
1631                 ao2_ref(globres, -1);
1632         }
1633
1634         ao2_ref(filter->children, -1);
1635 }
1636
1637 /*!
1638  * \internal
1639  * \brief Allocate a filter node.
1640  * \retval NULL on error.
1641  * \retval non-NULL The allocated search node structure.
1642  */
1643 static struct data_filter *data_filter_alloc(const char *name)
1644 {
1645         char *globname, *token;
1646         struct data_filter *res, *globfilter;
1647         size_t name_len = strlen(name) + 1;
1648
1649         res = ao2_alloc(sizeof(*res) + name_len, data_filter_destructor);
1650         if (!res) {
1651                 return NULL;
1652         }
1653
1654         res->children = ao2_container_alloc(NUM_DATA_FILTER_BUCKETS, data_filter_hash,
1655                 data_filter_cmp);
1656
1657         if (!res->children) {
1658                 ao2_ref(res, -1);
1659                 return NULL;
1660         }
1661
1662         strcpy(res->name, name);
1663
1664         if (strchr(res->name, '*')) {
1665                 globname = ast_strdupa(res->name);
1666
1667                 while ((token = strsep(&globname, "*"))) {
1668                         globfilter = data_filter_alloc(token);
1669                         AST_LIST_INSERT_TAIL(&(res->glob_list), globfilter, list);
1670                 }
1671         }
1672
1673         return res;
1674 }
1675
1676 /*!
1677  * \internal
1678  * \brief Release a filter tree.
1679  * \param[in] filter The filter tree root node.
1680  */
1681 static void data_filter_release(struct data_filter *filter)
1682 {
1683         ao2_ref(filter, -1);
1684 }
1685
1686 /*!
1687  * \internal
1688  * \brief Find a child node, based on his name.
1689  * \param[in] parent Where to find the node.
1690  * \param[in] name The node name to find.
1691  * \retval NULL if a node wasn't found.
1692  * \retval The node found.
1693  * \note Remember to decrement the ref count of the returned node after using it.
1694  */
1695 static struct data_filter *data_filter_find(struct ao2_container *parent,
1696         const char *name)
1697 {
1698         int i, olend, orend, globfound;
1699         size_t name_len = strlen(name), glob_len;
1700         struct ao2_iterator iter;
1701         struct data_filter *find_node, *found, *globres;
1702
1703         find_node = data_filter_alloc(name);
1704         if (!find_node) {
1705                 return NULL;
1706         }
1707
1708         found = ao2_find(parent, find_node, OBJ_POINTER);
1709
1710         /* free the created node used for searching. */
1711         ao2_ref(find_node, -1);
1712
1713         if (found) {
1714                 return found;
1715         }
1716
1717         iter = ao2_iterator_init(parent, 0);
1718         while ((found = ao2_iterator_next(&iter))) {
1719                 if (!AST_LIST_EMPTY(&(found->glob_list))) {
1720                         i = 0;
1721                         globfound = 1;
1722
1723                         olend = ast_strlen_zero(AST_LIST_FIRST(&(found->glob_list))->name);
1724                         orend = ast_strlen_zero(AST_LIST_LAST(&(found->glob_list))->name);
1725
1726                         AST_LIST_TRAVERSE(&(found->glob_list), globres, list) {
1727                                 if (!*globres->name) {
1728                                         continue;
1729                                 }
1730
1731                                 glob_len = strlen(globres->name);
1732
1733                                 if (!i && !olend) {
1734                                         if (strncasecmp(name, globres->name, glob_len)) {
1735                                                 globfound = 0;
1736                                                 break;
1737                                         }
1738
1739                                         i += glob_len;
1740                                         continue;
1741                                 }
1742
1743                                 for (globfound = 0; name_len - i >= glob_len; ++i) {
1744                                         if (!strncasecmp(name + i, globres->name, glob_len)) {
1745                                                 globfound = 1;
1746                                                 i += glob_len;
1747                                                 break;
1748                                         }
1749                                 }
1750
1751                                 if (!globfound) {
1752                                         break;
1753                                 }
1754                         }
1755
1756                         if (globfound && (i == name_len || orend)) {
1757                                 ao2_iterator_destroy(&iter);
1758                                 return found;
1759                         }
1760                 }
1761
1762                 ao2_ref(found, -1);
1763         }
1764         ao2_iterator_destroy(&iter);
1765
1766         return NULL;
1767 }
1768
1769 /*!
1770  * \internal
1771  * \brief Add a child to the specified node.
1772  * \param[in] root The root node where to add the child.
1773  * \param[in] name The name of the node to add.
1774  * \note Remember to decrement the ref count after using the returned node.
1775  */
1776 static struct data_filter *data_filter_add_child(struct ao2_container *root,
1777         char *name)
1778 {
1779         struct data_filter *node;
1780
1781         node = data_filter_find(root, name);
1782         if (node) {
1783                 return node;
1784         }
1785
1786         node = data_filter_alloc(name);
1787         if (!node) {
1788                 return NULL;
1789         }
1790
1791         ao2_link(root, node);
1792
1793         return node;
1794 }
1795
1796 /*!
1797  * \internal
1798  * \brief Add a node to a filter list from a path
1799  * \param[in] Filter list to add the path onto.
1800  * \param[in] The path to add into the filter list.
1801  * \retval NULL on error.
1802  * \retval non-NULL A tree with the wanted nodes.
1803  */
1804 static int data_filter_add_nodes(struct ao2_container *root, char *path)
1805 {
1806         struct data_filter *node;
1807         char *savepath, *saveptr, *token, *node_name;
1808         int ret = 0;
1809
1810         if (!path) {
1811                 return 0;
1812         }
1813
1814         savepath = ast_strdupa(path);
1815
1816         node_name = next_node_name(&savepath);
1817
1818         if (!node_name) {
1819                 return 0;
1820         }
1821
1822         for (token = strtok_r(node_name, "|", &saveptr);
1823                         token; token = strtok_r(NULL, "|", &saveptr)) {
1824                 node = data_filter_add_child(root, token);
1825                 if (!node) {
1826                         continue;
1827                 }
1828                 data_filter_add_nodes(node->children, savepath);
1829                 ret = 1;
1830                 ao2_ref(node, -1);
1831         }
1832
1833         return ret;
1834 }
1835
1836 /*!
1837  * \internal
1838  * \brief Generate a filter list based on a filter string provided by the API user.
1839  * \param[in] A filter string to create a filter from.
1840  */
1841 static struct data_filter *data_filter_generate(const char *constfilter)
1842 {
1843         struct data_filter *filter = NULL;
1844         char *strfilter, *token, *saveptr;
1845         int node_added = 0;
1846
1847         if (!constfilter) {
1848                 return NULL;
1849         }
1850
1851         strfilter = ast_strdupa(constfilter);
1852
1853         filter = data_filter_alloc("/");
1854         if (!filter) {
1855                 return NULL;
1856         }
1857
1858         for (token = strtok_r(strfilter, ",", &saveptr); token;
1859                         token = strtok_r(NULL, ",", &saveptr)) {
1860                 node_added = data_filter_add_nodes(filter->children, token);
1861         }
1862
1863         if (!node_added) {
1864                 ao2_ref(filter, -1);
1865                 return NULL;
1866         }
1867
1868         return filter;
1869 }
1870
1871 /*!
1872  * \internal
1873  * \brief Generate all the tree from a specified provider.
1874  * \param[in] query The query executed.
1875  * \param[in] root_provider The provider specified in the path of the query.
1876  * \param[in] parent_node_name The root node name.
1877  * \retval NULL on error.
1878  * \retval non-NULL The generated result tree.
1879  */
1880 static struct ast_data *data_result_generate_node(const struct ast_data_query *query,
1881         const struct data_provider *root_provider,
1882         const char *parent_node_name,
1883         const struct ast_data_search *search,
1884         const struct data_filter *filter)
1885 {
1886         struct ast_data *generated, *node;
1887         struct ao2_iterator i;
1888         struct data_provider *provider;
1889         struct ast_data_search *search_child = NULL;
1890         struct data_filter *filter_child;
1891
1892         node = data_result_create(parent_node_name);
1893         if (!node) {
1894                 ast_log(LOG_ERROR, "Unable to allocate '%s' node\n", parent_node_name);
1895                 return NULL;
1896         }
1897
1898         if (root_provider->module) {
1899                 ast_module_ref(root_provider->module);
1900         }
1901
1902         /* if this is a terminal node, just run the callback function. */
1903         if (root_provider->handler && root_provider->handler->get) {
1904                 node->filter = filter;
1905                 root_provider->handler->get(search, node);
1906                 if (root_provider->module) {
1907                         ast_module_unref(root_provider->module);
1908                 }
1909                 return node;
1910         }
1911
1912         if (root_provider->module) {
1913                 ast_module_unref(root_provider->module);
1914         }
1915
1916         /* if this is not a terminal node, generate every child node. */
1917         i = ao2_iterator_init(root_provider->children, 0);
1918         while ((provider = ao2_iterator_next(&i))) {
1919                 filter_child = NULL;
1920                 generated = NULL;
1921
1922                 /* get the internal search node. */
1923                 if (search) {
1924                         search_child = data_search_find(search->children, provider->name);
1925                 }
1926                 /* get the internal filter node. */
1927                 if (filter) {
1928                         filter_child = data_filter_find(filter->children, provider->name);
1929                 }
1930
1931                 if (!filter || filter_child) {
1932                         /* only generate the internal node, if we have something to
1933                          * generate based on the filtering string. */
1934                         generated = data_result_generate_node(query, provider,
1935                                 provider->name,
1936                                 search_child, filter_child);
1937                 }
1938
1939                 /* decrement the refcount of the internal search node. */
1940                 if (search_child) {
1941                         ao2_ref(search_child, -1);
1942                 }
1943
1944                 /* decrement the refcount of the internal filter node. */
1945                 if (filter_child) {
1946                         ao2_ref(filter_child, -1);
1947                 }
1948
1949                 if (generated) {
1950                         data_result_add_child(node, generated);
1951                         ao2_ref(generated, -1);
1952                 }
1953
1954                 ao2_ref(provider, -1);
1955         }
1956         ao2_iterator_destroy(&i);
1957
1958         return node;
1959 }
1960
1961 /*!
1962  * \internal
1963  * \brief Generate a result tree based on a query.
1964  * \param[in] query The complete query structure.
1965  * \param[in] search_path The path to retrieve.
1966  * \retval NULL on error.
1967  * \retval non-NULL The generated data result.
1968  */
1969 static struct ast_data *data_result_generate(const struct ast_data_query *query,
1970         const char *search_path)
1971 {
1972         char *node_name, *tmp_path;
1973         struct data_provider *provider_child, *tmp_provider_child;
1974         struct ast_data *result, *result_filtered;
1975         struct ast_data_search *search = NULL, *search_child = NULL;
1976         struct data_filter *filter = NULL, *filter_child = NULL;
1977
1978         if (!search_path) {
1979                 /* generate all the trees?. */
1980                 return NULL;
1981         }
1982
1983         tmp_path = ast_strdupa(search_path);
1984
1985         /* start searching the root node name */
1986         node_name = next_node_name(&tmp_path);
1987         if (!node_name) {
1988                 return NULL;
1989         }
1990         provider_child = data_provider_find(root_data.container, node_name, NULL);
1991
1992         /* continue with the rest of the path. */
1993         while (provider_child) {
1994                 node_name = next_node_name(&tmp_path);
1995                 if (!node_name) {
1996                         break;
1997                 }
1998
1999                 tmp_provider_child = data_provider_find(provider_child->children,
2000                                 node_name, NULL);
2001
2002                 /* release the reference from this child */
2003                 ao2_ref(provider_child, -1);
2004
2005                 provider_child = tmp_provider_child;
2006         }
2007
2008         if (!provider_child) {
2009                 ast_log(LOG_ERROR, "Invalid path '%s', '%s' not found.\n",
2010                                 tmp_path, node_name);
2011                 return NULL;
2012         }
2013
2014         /* generate the search tree. */
2015         if (query->search) {
2016                 search = data_search_generate(query->search);
2017                 if (search) {
2018                         search_child = data_search_find(search->children,
2019                                 provider_child->name);
2020                 }
2021         }
2022
2023         /* generate the filter tree. */
2024         if (query->filter) {
2025                 filter = data_filter_generate(query->filter);
2026                 if (filter) {
2027                         filter_child = data_filter_find(filter->children,
2028                                 provider_child->name);
2029                 }
2030         }
2031
2032         result = data_result_generate_node(query, provider_child, provider_child->name,
2033                         search_child, filter_child);
2034
2035         /* release the requested provider. */
2036         ao2_ref(provider_child, -1);
2037
2038         /* release the generated search tree. */
2039         if (search_child) {
2040                 ao2_ref(search_child, -1);
2041         }
2042
2043         if (filter_child) {
2044                 ao2_ref(filter_child, -1);
2045         }
2046
2047         if (search) {
2048                 data_search_release(search);
2049         }
2050
2051         result_filtered = result;
2052
2053         /* release the generated filter tree. */
2054         if (filter) {
2055                 data_filter_release(filter);
2056         }
2057
2058         return result_filtered;
2059 }
2060
2061 struct ast_data *ast_data_get(const struct ast_data_query *query)
2062 {
2063         struct ast_data *res;
2064
2065         /* check compatibility */
2066         if (!data_structure_compatible(query->version, latest_query_compatible_version,
2067                 current_query_version)) {
2068                 return NULL;
2069         }
2070
2071         data_read_lock();
2072         res = data_result_generate(query, query->path);
2073         data_unlock();
2074
2075         if (!res) {
2076                 ast_log(LOG_ERROR, "Unable to get data from %s\n", query->path);
2077                 return NULL;
2078         }
2079
2080         return res;
2081 }
2082
2083 #ifdef HAVE_LIBXML2
2084 /*!
2085  * \internal
2086  * \brief Helper function to move an ast_data tree to xml.
2087  * \param[in] parent_data The initial ast_data node to be passed to xml.
2088  * \param[out] parent_xml The root node to insert the xml.
2089  */
2090 static void data_get_xml_add_child(struct ast_data *parent_data,
2091         struct ast_xml_node *parent_xml)
2092 {
2093         struct ao2_iterator i;
2094         struct ast_data *node;
2095         struct ast_xml_node *child_xml;
2096         char node_content[256];
2097
2098         i = ao2_iterator_init(parent_data->children, 0);
2099         while ((node = ao2_iterator_next(&i))) {
2100                 child_xml = ast_xml_new_node(node->name);
2101                 if (!child_xml) {
2102                         ao2_ref(node, -1);
2103                         continue;
2104                 }
2105
2106                 switch (node->type) {
2107                 case AST_DATA_CONTAINER:
2108                         data_get_xml_add_child(node, child_xml);
2109                         break;
2110                 case AST_DATA_PASSWORD:
2111                         ast_xml_set_text(child_xml, node->payload.str);
2112                         break;
2113                 case AST_DATA_TIMESTAMP:
2114                         snprintf(node_content, sizeof(node_content), "%d",
2115                                 node->payload.uint);
2116                         ast_xml_set_text(child_xml, node_content);
2117                         break;
2118                 case AST_DATA_SECONDS:
2119                         snprintf(node_content, sizeof(node_content), "%d",
2120                                 node->payload.uint);
2121                         ast_xml_set_text(child_xml, node_content);
2122                         break;
2123                 case AST_DATA_MILLISECONDS:
2124                         snprintf(node_content, sizeof(node_content), "%d",
2125                                 node->payload.uint);
2126                         ast_xml_set_text(child_xml, node_content);
2127                         break;
2128                 case AST_DATA_STRING:
2129                         ast_xml_set_text(child_xml, node->payload.str);
2130                         break;
2131                 case AST_DATA_CHARACTER:
2132                         snprintf(node_content, sizeof(node_content), "%c",
2133                                 node->payload.character);
2134                         ast_xml_set_text(child_xml, node_content);
2135                         break;
2136                 case AST_DATA_INTEGER:
2137                         snprintf(node_content, sizeof(node_content), "%d",
2138                                 node->payload.sint);
2139                         ast_xml_set_text(child_xml, node_content);
2140                         break;
2141                 case AST_DATA_UNSIGNED_INTEGER:
2142                         snprintf(node_content, sizeof(node_content), "%u",
2143                                 node->payload.uint);
2144                         ast_xml_set_text(child_xml, node_content);
2145                         break;
2146                 case AST_DATA_DOUBLE:
2147                         snprintf(node_content, sizeof(node_content), "%f",
2148                                 node->payload.dbl);
2149                         ast_xml_set_text(child_xml, node_content);
2150                         break;
2151                 case AST_DATA_BOOLEAN:
2152                         if (node->payload.boolean) {
2153                                 ast_xml_set_text(child_xml, "true");
2154                         } else {
2155                                 ast_xml_set_text(child_xml, "false");
2156                         }
2157                         break;
2158                 case AST_DATA_POINTER:
2159                         snprintf(node_content, sizeof(node_content), "%p",
2160                                 node->payload.ptr);
2161                         ast_xml_set_text(child_xml, node_content);
2162                         break;
2163                 case AST_DATA_IPADDR:
2164                         snprintf(node_content, sizeof(node_content), "%s",
2165                                 ast_inet_ntoa(node->payload.ipaddr));
2166                         ast_xml_set_text(child_xml, node_content);
2167                         break;
2168                 }
2169                 ast_xml_add_child(parent_xml, child_xml);
2170
2171                 ao2_ref(node, -1);
2172         }
2173         ao2_iterator_destroy(&i);
2174
2175 }
2176
2177 struct ast_xml_doc *ast_data_get_xml(const struct ast_data_query *query)
2178 {
2179         struct ast_xml_doc *doc;
2180         struct ast_xml_node *root;
2181         struct ast_data *res;
2182
2183         res = ast_data_get(query);
2184         if (!res) {
2185                 return NULL;
2186         }
2187
2188         doc = ast_xml_new();
2189         if (!doc) {
2190                 ast_data_free(res);
2191                 return NULL;
2192         }
2193
2194         root = ast_xml_new_node(res->name);
2195         if (!root) {
2196                 ast_xml_close(doc);
2197         }
2198
2199         ast_xml_set_root(doc, root);
2200
2201         data_get_xml_add_child(res, root);
2202
2203         ast_data_free(res);
2204
2205         return doc;
2206 }
2207 #endif
2208
2209 enum ast_data_type ast_data_retrieve_type(struct ast_data *node, const char *path)
2210 {
2211         struct ast_data *internal;
2212
2213         internal = data_result_get_node(node, path);
2214         if (!internal) {
2215                 return -1;
2216         }
2217
2218         return internal->type;
2219 }
2220
2221 char *ast_data_retrieve_name(struct ast_data *node)
2222 {
2223         return node->name;
2224 }
2225
2226 /*!
2227  * \internal
2228  * \brief Insert a child node inside a passed parent node.
2229  * \param root Where we are going to insert the child node.
2230  * \param name The name of the child node to add.
2231  * \param type The type of content inside the child node.
2232  * \param ptr The actual content of the child node.
2233  * \retval NULL on error.
2234  * \retval non-NULL The added child node pointer.
2235  */
2236 static struct ast_data *__ast_data_add(struct ast_data *root, const char *name,
2237         enum ast_data_type type, void *ptr)
2238 {
2239         struct ast_data *node;
2240         struct data_filter *filter, *filter_child = NULL;
2241
2242         if (!root || !root->children) {
2243                 /* invalid data result node. */
2244                 return NULL;
2245         }
2246
2247         /* check if we need to add this node, based on the filter. */
2248         if (root->filter) {
2249                 filter = data_filter_find(root->filter->children, name);
2250                 if (!filter) {
2251                         return NULL;
2252                 }
2253                 ao2_ref(filter, -1);
2254         }
2255
2256         node = data_result_create(name);
2257         if (!node) {
2258                 return NULL;
2259         }
2260
2261         node->type = type;
2262
2263         switch (type) {
2264         case AST_DATA_BOOLEAN:
2265                 node->payload.boolean = *(unsigned int *) ptr;
2266                 break;
2267         case AST_DATA_INTEGER:
2268                 node->payload.sint = *(int *) ptr;
2269                 break;
2270         case AST_DATA_TIMESTAMP:
2271         case AST_DATA_SECONDS:
2272         case AST_DATA_MILLISECONDS:
2273         case AST_DATA_UNSIGNED_INTEGER:
2274                 node->payload.uint = *(unsigned int *) ptr;
2275                 break;
2276         case AST_DATA_DOUBLE:
2277                 node->payload.dbl = *(double *) ptr;
2278                 break;
2279         case AST_DATA_PASSWORD:
2280         case AST_DATA_STRING:
2281                 node->payload.str = (char *) ptr;
2282                 break;
2283         case AST_DATA_CHARACTER:
2284                 node->payload.character = *(char *) ptr;
2285                 break;
2286         case AST_DATA_POINTER:
2287                 node->payload.ptr = ptr;
2288                 break;
2289         case AST_DATA_IPADDR:
2290                 node->payload.ipaddr = *(struct in_addr *) ptr;
2291                 break;
2292         case AST_DATA_CONTAINER:
2293                 if (root->filter) {
2294                         filter_child = data_filter_find(root->filter->children, name);
2295                         if (filter_child) {
2296                                 /* do not increment the refcount because it is not neccesary. */
2297                                 ao2_ref(filter_child, -1);
2298                         }
2299                 }
2300                 node->filter = filter_child;
2301                 break;
2302         default:
2303                 break;
2304         }
2305
2306         data_result_add_child(root, node);
2307
2308         ao2_ref(node, -1);
2309
2310         return node;
2311 }
2312
2313 struct ast_data *ast_data_add_node(struct ast_data *root, const char *name)
2314 {
2315         return __ast_data_add(root, name, AST_DATA_CONTAINER, NULL);
2316 }
2317
2318 struct ast_data *ast_data_add_int(struct ast_data *root, const char *name, int value)
2319 {
2320         return __ast_data_add(root, name, AST_DATA_INTEGER, &value);
2321 }
2322
2323 struct ast_data *ast_data_add_char(struct ast_data *root, const char *name, char value)
2324 {
2325         return __ast_data_add(root, name, AST_DATA_CHARACTER, &value);
2326 }
2327
2328 struct ast_data *ast_data_add_uint(struct ast_data *root, const char *name,
2329         unsigned int value)
2330 {
2331         return __ast_data_add(root, name, AST_DATA_UNSIGNED_INTEGER, &value);
2332 }
2333
2334 struct ast_data *ast_data_add_dbl(struct ast_data *root, const char *childname,
2335         double dbl)
2336 {
2337         return __ast_data_add(root, childname, AST_DATA_DOUBLE, &dbl);
2338 }
2339
2340 struct ast_data *ast_data_add_bool(struct ast_data *root, const char *childname,
2341         unsigned int boolean)
2342 {
2343         return __ast_data_add(root, childname, AST_DATA_BOOLEAN, &boolean);
2344 }
2345
2346 struct ast_data *ast_data_add_ipaddr(struct ast_data *root, const char *childname,
2347         struct in_addr addr)
2348 {
2349         return __ast_data_add(root, childname, AST_DATA_IPADDR, &addr);
2350 }
2351
2352 struct ast_data *ast_data_add_ptr(struct ast_data *root, const char *childname,
2353         void *ptr)
2354 {
2355         return __ast_data_add(root, childname, AST_DATA_POINTER, ptr);
2356 }
2357
2358 struct ast_data *ast_data_add_timestamp(struct ast_data *root, const char *childname,
2359         unsigned int timestamp)
2360 {
2361         return __ast_data_add(root, childname, AST_DATA_TIMESTAMP, &timestamp);
2362 }
2363
2364 struct ast_data *ast_data_add_seconds(struct ast_data *root, const char *childname,
2365         unsigned int seconds)
2366 {
2367         return __ast_data_add(root, childname, AST_DATA_SECONDS, &seconds);
2368 }
2369
2370 struct ast_data *ast_data_add_milliseconds(struct ast_data *root, const char *childname,
2371         unsigned int milliseconds)
2372 {
2373         return __ast_data_add(root, childname, AST_DATA_MILLISECONDS, &milliseconds);
2374 }
2375
2376 struct ast_data *ast_data_add_password(struct ast_data *root, const char *childname,
2377         const char *value)
2378 {
2379         char *name;
2380         size_t namelen = 1 + (ast_strlen_zero(value) ? 0 : strlen(value));
2381         struct ast_data *res;
2382
2383         if (!(name = ast_malloc(namelen))) {
2384                 return NULL;
2385         }
2386
2387         strcpy(name, (ast_strlen_zero(value) ? "" : value));
2388
2389         res = __ast_data_add(root, childname, AST_DATA_PASSWORD, name);
2390         if (!res) {
2391                 ast_free(name);
2392         }
2393
2394         return res;
2395 }
2396
2397 struct ast_data *ast_data_add_str(struct ast_data *root, const char *childname,
2398         const char *value)
2399 {
2400         char *name;
2401         size_t namelen = 1 + (ast_strlen_zero(value) ? 0 : strlen(value));
2402         struct ast_data *res;
2403
2404         if (!(name = ast_malloc(namelen))) {
2405                 return NULL;
2406         }
2407
2408         strcpy(name, (ast_strlen_zero(value) ? "" : value));
2409
2410         res = __ast_data_add(root, childname, AST_DATA_STRING, name);
2411         if (!res) {
2412                 ast_free(name);
2413         }
2414
2415         return res;
2416 }
2417
2418 int __ast_data_add_structure(struct ast_data *root,
2419         const struct ast_data_mapping_structure *mapping, size_t mapping_len,
2420         void *structure)
2421 {
2422         int i;
2423
2424         for (i = 0; i < mapping_len; i++) {
2425                 switch (mapping[i].type) {
2426                 case AST_DATA_INTEGER:
2427                         ast_data_add_int(root, mapping[i].name,
2428                                 mapping[i].get.AST_DATA_INTEGER(structure));
2429                         break;
2430                 case AST_DATA_UNSIGNED_INTEGER:
2431                         ast_data_add_uint(root, mapping[i].name,
2432                                 mapping[i].get.AST_DATA_UNSIGNED_INTEGER(structure));
2433                         break;
2434                 case AST_DATA_DOUBLE:
2435                         ast_data_add_dbl(root, mapping[i].name,
2436                                 mapping[i].get.AST_DATA_DOUBLE(structure));
2437                         break;
2438                 case AST_DATA_BOOLEAN:
2439                         ast_data_add_bool(root, mapping[i].name,
2440                                 mapping[i].get.AST_DATA_BOOLEAN(structure));
2441                         break;
2442                 case AST_DATA_PASSWORD:
2443                         ast_data_add_password(root, mapping[i].name,
2444                                 mapping[i].get.AST_DATA_PASSWORD(structure));
2445                         break;
2446                 case AST_DATA_TIMESTAMP:
2447                         ast_data_add_timestamp(root, mapping[i].name,
2448                                 mapping[i].get.AST_DATA_TIMESTAMP(structure));
2449                         break;
2450                 case AST_DATA_SECONDS:
2451                         ast_data_add_seconds(root, mapping[i].name,
2452                                 mapping[i].get.AST_DATA_SECONDS(structure));
2453                         break;
2454                 case AST_DATA_MILLISECONDS:
2455                         ast_data_add_milliseconds(root, mapping[i].name,
2456                                 mapping[i].get.AST_DATA_MILLISECONDS(structure));
2457                         break;
2458                 case AST_DATA_STRING:
2459                         ast_data_add_str(root, mapping[i].name,
2460                                 mapping[i].get.AST_DATA_STRING(structure));
2461                         break;
2462                 case AST_DATA_CHARACTER:
2463                         ast_data_add_char(root, mapping[i].name,
2464                                 mapping[i].get.AST_DATA_CHARACTER(structure));
2465                         break;
2466                 case AST_DATA_CONTAINER:
2467                         break;
2468                 case AST_DATA_IPADDR:
2469                         ast_data_add_ipaddr(root, mapping[i].name,
2470                                 mapping[i].get.AST_DATA_IPADDR(structure));
2471                         break;
2472                 case AST_DATA_POINTER:
2473                         ast_data_add_ptr(root, mapping[i].name,
2474                                 mapping[i].get.AST_DATA_POINTER(structure));
2475                         break;
2476                 }
2477         }
2478
2479         return 0;
2480 }
2481
2482 void ast_data_remove_node(struct ast_data *root, struct ast_data *child)
2483 {
2484         ao2_unlink(root->children, child);
2485 }
2486
2487 void ast_data_free(struct ast_data *root)
2488 {
2489         /* destroy it, this will destroy all the internal nodes. */
2490         ao2_ref(root, -1);
2491 }
2492
2493 struct ast_data_iterator *ast_data_iterator_init(struct ast_data *tree,
2494         const char *elements)
2495 {
2496         struct ast_data_iterator *iterator;
2497         struct ao2_iterator i;
2498         struct ast_data *internal = tree;
2499         char *path, *ptr = NULL;
2500
2501         if (!elements) {
2502                 return NULL;
2503         }
2504
2505         /* tree is the node we want to use to iterate? or we are going
2506          * to iterate thow an internal node? */
2507         path = ast_strdupa(elements);
2508
2509         ptr = strrchr(path, '/');
2510         if (ptr) {
2511                 *ptr = '\0';
2512                 internal = data_result_get_node(tree, path);
2513                 if (!internal) {
2514                         return NULL;
2515                 }
2516         }
2517
2518         iterator = ast_calloc(1, sizeof(*iterator));
2519         if (!iterator) {
2520                 return NULL;
2521         }
2522
2523         i = ao2_iterator_init(internal->children, 0);
2524
2525         iterator->pattern = (ptr ? strrchr(elements, '/') + 1 : elements);
2526
2527         /* is the last node a regular expression?, compile it! */
2528         if (!regcomp(&(iterator->regex_pattern), iterator->pattern,
2529                         REG_EXTENDED | REG_NOSUB | REG_ICASE)) {
2530                 iterator->is_pattern = 1;
2531         }
2532
2533         iterator->internal_iterator = i;
2534
2535         return iterator;
2536 }
2537
2538 void ast_data_iterator_end(struct ast_data_iterator *iterator)
2539 {
2540         /* decrement the reference counter. */
2541         if (iterator->last) {
2542                 ao2_ref(iterator->last, -1);
2543         }
2544
2545         /* release the generated pattern. */
2546         if (iterator->is_pattern) {
2547                 regfree(&(iterator->regex_pattern));
2548         }
2549
2550         ao2_iterator_destroy(&(iterator->internal_iterator));
2551
2552         ast_free(iterator);
2553         iterator = NULL;
2554 }
2555
2556 struct ast_data *ast_data_iterator_next(struct ast_data_iterator *iterator)
2557 {
2558         struct ast_data *res;
2559
2560         if (iterator->last) {
2561                 /* release the last retrieved node reference. */
2562                 ao2_ref(iterator->last, -1);
2563         }
2564
2565         while ((res = ao2_iterator_next(&iterator->internal_iterator))) {
2566                 /* if there is no node name pattern specified, return
2567                  * the next node. */
2568                 if (!iterator->pattern) {
2569                         break;
2570                 }
2571
2572                 /* if the pattern is a regular expression, check if this node
2573                  * matches. */
2574                 if (iterator->is_pattern && !regexec(&(iterator->regex_pattern),
2575                         res->name, 0, NULL, 0)) {
2576                         break;
2577                 }
2578
2579                 /* if there is a pattern specified, check if this node matches
2580                  * the wanted node names. */
2581                 if (!iterator->is_pattern && (iterator->pattern &&
2582                                 !strcasecmp(res->name, iterator->pattern))) {
2583                         break;
2584                 }
2585
2586                 ao2_ref(res, -1);
2587         }
2588
2589         iterator->last = res;
2590
2591         return res;
2592 }
2593
2594 int ast_data_retrieve(struct ast_data *tree, const char *path,
2595         struct ast_data_retrieve *content)
2596 {
2597         struct ast_data *node;
2598
2599         if (!content) {
2600                 return -1;
2601         }
2602
2603         node = data_result_get_node(tree, path);
2604         if (!node) {
2605                 ast_log(LOG_ERROR, "Invalid internal node %s\n", path);
2606                 return -1;
2607         }
2608
2609         content->type = node->type;
2610         switch (node->type) {
2611         case AST_DATA_STRING:
2612                 content->value.AST_DATA_STRING = node->payload.str;
2613                 break;
2614         case AST_DATA_PASSWORD:
2615                 content->value.AST_DATA_PASSWORD = node->payload.str;
2616                 break;
2617         case AST_DATA_TIMESTAMP:
2618                 content->value.AST_DATA_TIMESTAMP = node->payload.uint;
2619                 break;
2620         case AST_DATA_SECONDS:
2621                 content->value.AST_DATA_SECONDS = node->payload.uint;
2622                 break;
2623         case AST_DATA_MILLISECONDS:
2624                 content->value.AST_DATA_MILLISECONDS = node->payload.uint;
2625                 break;
2626         case AST_DATA_CHARACTER:
2627                 content->value.AST_DATA_CHARACTER = node->payload.character;
2628                 break;
2629         case AST_DATA_INTEGER:
2630                 content->value.AST_DATA_INTEGER = node->payload.sint;
2631                 break;
2632         case AST_DATA_UNSIGNED_INTEGER:
2633                 content->value.AST_DATA_UNSIGNED_INTEGER = node->payload.uint;
2634                 break;
2635         case AST_DATA_BOOLEAN:
2636                 content->value.AST_DATA_BOOLEAN = node->payload.boolean;
2637                 break;
2638         case AST_DATA_IPADDR:
2639                 content->value.AST_DATA_IPADDR = node->payload.ipaddr;
2640                 break;
2641         case AST_DATA_DOUBLE:
2642                 content->value.AST_DATA_DOUBLE = node->payload.dbl;
2643                 break;
2644         case AST_DATA_CONTAINER:
2645                 break;
2646         case AST_DATA_POINTER:
2647                 content->value.AST_DATA_POINTER = node->payload.ptr;
2648                 break;
2649         }
2650
2651         return 0;
2652 }
2653
2654 /*!
2655  * \internal
2656  * \brief One color for each node type.
2657  */
2658 static const struct {
2659         enum ast_data_type type;
2660         int color;
2661 } data_result_color[] = {
2662         { AST_DATA_STRING, COLOR_BLUE },
2663         { AST_DATA_PASSWORD, COLOR_BRBLUE },
2664         { AST_DATA_TIMESTAMP, COLOR_CYAN },
2665         { AST_DATA_SECONDS, COLOR_MAGENTA },
2666         { AST_DATA_MILLISECONDS, COLOR_BRMAGENTA },
2667         { AST_DATA_CHARACTER, COLOR_GRAY },
2668         { AST_DATA_INTEGER, COLOR_RED },
2669         { AST_DATA_UNSIGNED_INTEGER, COLOR_RED },
2670         { AST_DATA_DOUBLE, COLOR_RED },
2671         { AST_DATA_BOOLEAN, COLOR_BRRED },
2672         { AST_DATA_CONTAINER, COLOR_GREEN },
2673         { AST_DATA_IPADDR, COLOR_BROWN },
2674         { AST_DATA_POINTER, COLOR_YELLOW },
2675 };
2676
2677 /*!
2678  * \internal
2679  * \brief Get the color configured for a specific node type.
2680  * \param[in] type The node type.
2681  * \returns The color specified for the passed type.
2682  */
2683 static int data_result_get_color(enum ast_data_type type)
2684 {
2685         int i;
2686         for (i = 0; i < ARRAY_LEN(data_result_color); i++) {
2687                 if (data_result_color[i].type == type) {
2688                         return data_result_color[i].color;
2689                 }
2690         }
2691
2692         return COLOR_BLUE;
2693 }
2694
2695 /*!
2696  * \internal
2697  * \brief Print a node to the CLI.
2698  * \param[in] fd The CLI file descriptor.
2699  * \param[in] node The node to print.
2700  * \param[in] depth The actual node depth in the tree.
2701  */
2702 static void data_result_print_cli_node(int fd, const struct ast_data *node, uint32_t depth)
2703 {
2704         int i;
2705         struct ast_str *tabs, *output;
2706
2707         tabs = ast_str_create(depth * 10 + 1);
2708         if (!tabs) {
2709                 return;
2710         }
2711         ast_str_reset(tabs);
2712         for (i = 0; i < depth; i++) {
2713                 ast_str_append(&tabs, 0, "  ");
2714         }
2715
2716         output = ast_str_create(20);
2717         if (!output) {
2718                 ast_free(tabs);
2719                 return;
2720         }
2721
2722         ast_str_reset(output);
2723         ast_term_color_code(&output, data_result_get_color(node->type), 0);
2724
2725         switch (node->type) {
2726         case AST_DATA_POINTER:
2727                 ast_str_append(&output, 0, "%s%s: %p\n", ast_str_buffer(tabs),
2728                                 node->name, node->payload.ptr);
2729                 break;
2730         case AST_DATA_PASSWORD:
2731                 ast_str_append(&output, 0, "%s%s: \"%s\"\n",
2732                                 ast_str_buffer(tabs),
2733                                 node->name,
2734                                 node->payload.str);
2735                 break;
2736         case AST_DATA_STRING:
2737                 ast_str_append(&output, 0, "%s%s: \"%s\"\n",
2738                                 ast_str_buffer(tabs),
2739                                 node->name,
2740                                 node->payload.str);
2741                 break;
2742         case AST_DATA_CHARACTER:
2743                 ast_str_append(&output, 0, "%s%s: \'%c\'\n",
2744                                 ast_str_buffer(tabs),
2745                                 node->name,
2746                                 node->payload.character);
2747                 break;
2748         case AST_DATA_CONTAINER:
2749                 ast_str_append(&output, 0, "%s%s\n", ast_str_buffer(tabs),
2750                                 node->name);
2751                 break;
2752         case AST_DATA_TIMESTAMP:
2753                 ast_str_append(&output, 0, "%s%s: %d\n", ast_str_buffer(tabs),
2754                                 node->name,
2755                                 node->payload.uint);
2756                 break;
2757         case AST_DATA_SECONDS:
2758                 ast_str_append(&output, 0, "%s%s: %d\n", ast_str_buffer(tabs),
2759                                 node->name,
2760                                 node->payload.uint);
2761                 break;
2762         case AST_DATA_MILLISECONDS:
2763                 ast_str_append(&output, 0, "%s%s: %d\n", ast_str_buffer(tabs),
2764                                 node->name,
2765                                 node->payload.uint);
2766                 break;
2767         case AST_DATA_INTEGER:
2768                 ast_str_append(&output, 0, "%s%s: %d\n", ast_str_buffer(tabs),
2769                                 node->name,
2770                                 node->payload.sint);
2771                 break;
2772         case AST_DATA_UNSIGNED_INTEGER:
2773                 ast_str_append(&output, 0, "%s%s: %u\n", ast_str_buffer(tabs),
2774                                 node->name,
2775                                 node->payload.uint);
2776                 break;
2777         case AST_DATA_DOUBLE:
2778                 ast_str_append(&output, 0, "%s%s: %lf\n", ast_str_buffer(tabs),
2779                                 node->name,
2780                                 node->payload.dbl);
2781                 break;
2782         case AST_DATA_BOOLEAN:
2783                 ast_str_append(&output, 0, "%s%s: %s\n", ast_str_buffer(tabs),
2784                                 node->name,
2785                                 ((node->payload.boolean) ? "True" : "False"));
2786                 break;
2787         case AST_DATA_IPADDR:
2788                 ast_str_append(&output, 0, "%s%s: %s\n", ast_str_buffer(tabs),
2789                                 node->name,
2790                                 ast_inet_ntoa(node->payload.ipaddr));
2791                 break;
2792         }
2793
2794         ast_free(tabs);
2795
2796         ast_term_color_code(&output, COLOR_WHITE, 0);
2797
2798         ast_cli(fd, "%s", ast_str_buffer(output));
2799
2800         ast_free(output);
2801
2802         if (node->type == AST_DATA_CONTAINER) {
2803                 __data_result_print_cli(fd, node, depth + 1);
2804         }
2805 }
2806
2807 /*!
2808  * \internal
2809  * \brief Print out an ast_data tree to the CLI.
2810  * \param[in] fd The CLI file descriptor.
2811  * \param[in] root The root node of the tree.
2812  * \param[in] depth Actual depth.
2813  */
2814 static void __data_result_print_cli(int fd, const struct ast_data *root, uint32_t depth)
2815 {
2816         struct ao2_iterator iter;
2817         struct ast_data *node;
2818
2819         if (root->type == AST_DATA_CONTAINER) {
2820                 iter = ao2_iterator_init(root->children, 0);
2821                 while ((node = ao2_iterator_next(&iter))) {
2822                         data_result_print_cli_node(fd, node, depth + 1);
2823                         ao2_ref(node, -1);
2824                 }
2825                 ao2_iterator_destroy(&iter);
2826         } else {
2827                 data_result_print_cli_node(fd, root, depth);
2828         }
2829 }
2830
2831 /*!
2832  * \internal
2833  * \brief
2834  * \param[in] fd The CLI file descriptor.
2835  * \param[in] root The root node of the tree.
2836  */
2837 static void data_result_print_cli(int fd, const struct ast_data *root)
2838 {
2839         struct ast_str *output;
2840
2841         /* print the initial node. */
2842         output = ast_str_create(30);
2843         if (!output) {
2844                 return;
2845         }
2846
2847         ast_term_color_code(&output, data_result_get_color(root->type), 0);
2848         ast_str_append(&output, 0, "%s\n", root->name);
2849         ast_term_color_code(&output, COLOR_WHITE, 0);
2850         ast_cli(fd, "%s", ast_str_buffer(output));
2851         ast_free(output);
2852
2853         __data_result_print_cli(fd, root, 0);
2854
2855         ast_cli(fd, "\n");
2856 }
2857
2858 /*!
2859  * \internal
2860  * \brief Handle the CLI command "data get".
2861  */
2862 static char *handle_cli_data_get(struct ast_cli_entry *e, int cmd,
2863                 struct ast_cli_args *a)
2864 {
2865         struct ast_data_query query = {
2866                 .version = AST_DATA_QUERY_VERSION
2867         };
2868         struct ast_data *tree;
2869
2870         switch (cmd) {
2871         case CLI_INIT:
2872                 e->command = "data get";
2873                 e->usage = ""
2874                         "Usage: data get <path> [<search> [<filter>]]\n"
2875                         "       Get the tree based on a path.\n";
2876                 return NULL;
2877         case CLI_GENERATE:
2878                 return NULL;
2879         }
2880
2881         if (a->argc < e->args + 1) {
2882                 return CLI_SHOWUSAGE;
2883         }
2884
2885         query.path = (char *) a->argv[e->args];
2886
2887         if (a->argc > e->args + 1) {
2888                 query.search = (char *) a->argv[e->args + 1];
2889         }
2890
2891         if (a->argc > e->args + 2) {
2892                 query.filter = (char *) a->argv[e->args + 2];
2893         }
2894
2895         tree = ast_data_get(&query);
2896         if (!tree) {
2897                 return CLI_FAILURE;
2898         }
2899
2900         data_result_print_cli(a->fd, tree);
2901
2902         ast_data_free(tree);
2903
2904         return CLI_SUCCESS;
2905 }
2906
2907 /*!
2908  * \internal
2909  * \brief Print the list of data providers.
2910  * \param[in] fd The CLI file descriptor.
2911  * \param[in] name The last node visited name.
2912  * \param[in] container The childrens of the last node.
2913  * \param[in] path The path to the current node.
2914  */
2915 static void data_provider_print_cli(int fd, const char *name,
2916         struct ao2_container *container, struct ast_str *path)
2917 {
2918         struct ao2_iterator i;
2919         struct ast_str *current_path;
2920         struct data_provider *provider;
2921
2922         current_path = ast_str_create(60);
2923         if (!current_path) {
2924                 return;
2925         }
2926
2927         ast_str_reset(current_path);
2928         if (path) {
2929                 ast_str_set(&current_path, 0, "%s/%s", ast_str_buffer(path), name);
2930         } else {
2931                 ast_str_set(&current_path, 0, "%s", name);
2932         }
2933
2934         i = ao2_iterator_init(container, 0);
2935         while ((provider = ao2_iterator_next(&i))) {
2936                 if (provider->handler) {
2937                         /* terminal node, print it. */
2938                         ast_cli(fd, "%s/%s (", ast_str_buffer(current_path),
2939                                 provider->name);
2940                         if (provider->handler->get) {
2941                                 ast_cli(fd, "get");
2942                         }
2943                         ast_cli(fd, ") [%s]\n", provider->registrar);
2944                 }
2945                 data_provider_print_cli(fd, provider->name, provider->children,
2946                         current_path);
2947                 ao2_ref(provider, -1);
2948         }
2949         ao2_iterator_destroy(&i);
2950
2951         ast_free(current_path);
2952 }
2953
2954 /*!
2955  * \internal
2956  * \brief Handle CLI command "data show providers"
2957  */
2958 static char *handle_cli_data_show_providers(struct ast_cli_entry *e, int cmd,
2959                 struct ast_cli_args *a)
2960 {
2961         switch (cmd) {
2962         case CLI_INIT:
2963                 e->command = "data show providers";
2964                 e->usage = ""
2965                         "Usage: data show providers\n"
2966                         "       Show the list of registered providers\n";
2967                 return NULL;
2968         case CLI_GENERATE:
2969                 return NULL;
2970         }
2971
2972         data_read_lock();
2973         data_provider_print_cli(a->fd, "", root_data.container, NULL);
2974         data_unlock();
2975
2976         return CLI_SUCCESS;
2977 }
2978
2979 /*!
2980  * \internal
2981  * \brief Data API CLI commands.
2982  */
2983 static struct ast_cli_entry cli_data[] = {
2984         AST_CLI_DEFINE(handle_cli_data_get, "Data API get"),
2985         AST_CLI_DEFINE(handle_cli_data_show_providers, "Show data providers")
2986 };
2987
2988 /*!
2989  * \internal
2990  * \brief Output a tree to the AMI.
2991  * \param[in] s AMI session.
2992  * \param[in] name The root node name.
2993  * \param[in] container The root container.
2994  * \param[in] path The current path.
2995  */
2996 static void data_result_manager_output(struct mansession *s, const char *name,
2997         struct ao2_container *container, struct ast_str *path, int id)
2998 {
2999         struct ao2_iterator i;
3000         struct ast_str *current_path;
3001         struct ast_data *node;
3002         int current_id = id;
3003
3004         current_path = ast_str_create(60);
3005         if (!current_path) {
3006                 return;
3007         }
3008
3009         ast_str_reset(current_path);
3010         if (path) {
3011                 ast_str_set(&current_path, 0, "%s.%s", ast_str_buffer(path), name);
3012         } else {
3013                 ast_str_set(&current_path, 0, "%s", name);
3014         }
3015
3016         i = ao2_iterator_init(container, 0);
3017         while ((node = ao2_iterator_next(&i))) {
3018                 /* terminal node, print it. */
3019                 if (node->type != AST_DATA_CONTAINER) {
3020                         astman_append(s, "%d-%s.%s", id, ast_str_buffer(current_path),
3021                                         node->name);
3022                 }
3023                 switch (node->type) {
3024                 case AST_DATA_CONTAINER:
3025                         data_result_manager_output(s, node->name, node->children, current_path, ++current_id);
3026                         break;
3027                 case AST_DATA_INTEGER:
3028                         astman_append(s, ": %d\r\n", node->payload.sint);
3029                         break;
3030                 case AST_DATA_TIMESTAMP:
3031                 case AST_DATA_SECONDS:
3032                 case AST_DATA_MILLISECONDS:
3033                 case AST_DATA_UNSIGNED_INTEGER:
3034                         astman_append(s, ": %u\r\n", node->payload.uint);
3035                         break;
3036                 case AST_DATA_PASSWORD:
3037                         astman_append(s, ": %s\r\n", node->payload.str);
3038                         break;
3039                 case AST_DATA_STRING:
3040                         astman_append(s, ": %s\r\n", node->payload.str);
3041                         break;
3042                 case AST_DATA_CHARACTER:
3043                         astman_append(s, ": %c\r\n", node->payload.character);
3044                         break;
3045                 case AST_DATA_IPADDR:
3046                         astman_append(s, ": %s\r\n", ast_inet_ntoa(node->payload.ipaddr));
3047                         break;
3048                 case AST_DATA_POINTER:
3049                         break;
3050                 case AST_DATA_DOUBLE:
3051                         astman_append(s, ": %f\r\n", node->payload.dbl);
3052                         break;
3053                 case AST_DATA_BOOLEAN:
3054                         astman_append(s, ": %s\r\n",
3055                                 (node->payload.boolean ? "True" : "False"));
3056                         break;
3057                 }
3058
3059                 ao2_ref(node, -1);
3060         }
3061         ao2_iterator_destroy(&i);
3062
3063         ast_free(current_path);
3064 }
3065
3066 /*!
3067  * \internal
3068  * \brief Implements the manager action: "DataGet".
3069  */
3070 static int manager_data_get(struct mansession *s, const struct message *m)
3071 {
3072         const char *path = astman_get_header(m, "Path");
3073         const char *search = astman_get_header(m, "Search");
3074         const char *filter = astman_get_header(m, "Filter");
3075         const char *id = astman_get_header(m, "ActionID");
3076         struct ast_data *res;
3077         struct ast_data_query query = {
3078                 .version = AST_DATA_QUERY_VERSION,
3079                 .path = (char *) path,
3080                 .search = (char *) search,
3081                 .filter = (char *) filter,
3082         };
3083
3084         if (ast_strlen_zero(path)) {
3085                 astman_send_error(s, m, "'Path' parameter not specified");
3086                 return 0;
3087         }
3088
3089         res = ast_data_get(&query);
3090         if (!res) {
3091                 astman_send_error(s, m, "No data returned");
3092                 return 0;
3093         }
3094
3095         astman_append(s, "Event: DataGet Tree\r\n");
3096         if (!ast_strlen_zero(id)) {
3097                 astman_append(s, "ActionID: %s\r\n", id);
3098         }
3099         data_result_manager_output(s, res->name, res->children, NULL, 0);
3100         astman_append(s, "\r\n");
3101
3102         ast_data_free(res);
3103
3104         return RESULT_SUCCESS;
3105 }
3106
3107 int ast_data_add_codec(struct ast_data *root, const char *node_name, struct ast_format *format)
3108 {
3109         struct ast_data *codecs, *codec;
3110         size_t fmlist_size;
3111         const struct ast_format_list *fmlist;
3112         int x;
3113
3114         codecs = ast_data_add_node(root, node_name);
3115         if (!codecs) {
3116                 return -1;
3117         }
3118         fmlist = ast_format_list_get(&fmlist_size);
3119         for (x = 0; x < fmlist_size; x++) {
3120                 if (ast_format_cmp(&fmlist[x].format, format) == AST_FORMAT_CMP_EQUAL) {
3121                         codec = ast_data_add_node(codecs, "codec");
3122                         if (!codec) {
3123                                 ast_format_list_destroy(fmlist);
3124                                 return -1;
3125                         }
3126                         ast_data_add_str(codec, "name", fmlist[x].name);
3127                         ast_data_add_int(codec, "samplespersecond", fmlist[x].samplespersecond);
3128                         ast_data_add_str(codec, "description", fmlist[x].desc);
3129                         ast_data_add_int(codec, "frame_length", fmlist[x].fr_len);
3130                 }
3131         }
3132         ast_format_list_destroy(fmlist);
3133
3134         return 0;
3135 }
3136
3137 int ast_data_add_codecs(struct ast_data *root, const char *node_name, struct ast_format_cap *cap)
3138 {
3139         struct ast_data *codecs, *codec;
3140         size_t fmlist_size;
3141         const struct ast_format_list *fmlist;
3142         int x;
3143
3144         codecs = ast_data_add_node(root, node_name);
3145         if (!codecs) {
3146                 return -1;
3147         }
3148         fmlist = ast_format_list_get(&fmlist_size);
3149         for (x = 0; x < fmlist_size; x++) {
3150                 if (ast_format_cap_iscompatible(cap, &fmlist[x].format)) {
3151                         codec = ast_data_add_node(codecs, "codec");
3152                         if (!codec) {
3153                                 ast_format_list_destroy(fmlist);
3154                                 return -1;
3155                         }
3156                         ast_data_add_str(codec, "name", fmlist[x].name);
3157                         ast_data_add_int(codec, "samplespersecond", fmlist[x].samplespersecond);
3158                         ast_data_add_str(codec, "description", fmlist[x].desc);
3159                         ast_data_add_int(codec, "frame_length", fmlist[x].fr_len);
3160                 }
3161         }
3162         ast_format_list_destroy(fmlist);
3163
3164         return 0;
3165 }
3166
3167 #ifdef TEST_FRAMEWORK
3168
3169 /*!
3170  * \internal
3171  * \brief Structure used to test how to add a complete structure,
3172  *        and how to compare it.
3173  */
3174 struct test_structure {
3175         int a_int;
3176         unsigned int b_bool:1;
3177         char *c_str;
3178         unsigned int a_uint;
3179 };
3180
3181 /*!
3182  * \internal
3183  * \brief test_structure mapping.
3184  */
3185 #define DATA_EXPORT_TEST_STRUCTURE(MEMBER)                              \
3186         MEMBER(test_structure, a_int, AST_DATA_INTEGER)                 \
3187         MEMBER(test_structure, b_bool, AST_DATA_BOOLEAN)                \
3188         MEMBER(test_structure, c_str, AST_DATA_STRING)                  \
3189         MEMBER(test_structure, a_uint, AST_DATA_UNSIGNED_INTEGER)
3190
3191 AST_DATA_STRUCTURE(test_structure, DATA_EXPORT_TEST_STRUCTURE);
3192
3193 /*!
3194  * \internal
3195  * \brief Callback implementation.
3196  */
3197 static int test_data_full_provider(const struct ast_data_search *search,
3198                 struct ast_data *root)
3199 {
3200         struct ast_data *test_structure;
3201         struct test_structure local_test_structure = {
3202                 .a_int = 10,
3203                 .b_bool = 1,
3204                 .c_str = "test string",
3205                 .a_uint = 20
3206         };
3207
3208         test_structure = ast_data_add_node(root, "test_structure");
3209         if (!test_structure) {
3210                 ast_debug(1, "Internal data api error\n");
3211                 return 0;
3212         }
3213
3214         /* add the complete structure. */
3215         ast_data_add_structure(test_structure, test_structure, &local_test_structure);
3216
3217         if (!ast_data_search_match(search, test_structure)) {
3218                 ast_data_remove_node(root, test_structure);
3219         }
3220
3221         return 0;
3222 }
3223
3224 /*!
3225  * \internal
3226  * \brief Handler definition for the full provider.
3227  */
3228 static const struct ast_data_handler full_provider = {
3229         .version = AST_DATA_HANDLER_VERSION,
3230         .get = test_data_full_provider
3231 };
3232
3233 /*!
3234  * \internal
3235  * \brief Structure used to define multiple providers at once.
3236  */
3237 static const struct ast_data_entry test_providers[] = {
3238         AST_DATA_ENTRY("test/node1/node11/node111", &full_provider)
3239 };
3240
3241 AST_TEST_DEFINE(test_data_get)
3242 {
3243         struct ast_data *res, *node;
3244         struct ast_data_iterator *i;
3245         struct ast_data_query query = {
3246                 .version = AST_DATA_QUERY_VERSION,
3247                 .path = "test/node1/node11/node111",
3248                 .search = "node111/test_structure/a_int=10",
3249                 .filter = "node111/test_structure/a*int"
3250         };
3251
3252         switch (cmd) {
3253         case TEST_INIT:
3254                 info->name = "data_test";
3255                 info->category = "/main/data/";
3256                 info->summary = "Data API unit test";
3257                 info->description =
3258                         "Tests whether data API get implementation works as expected.";
3259                 return AST_TEST_NOT_RUN;
3260         case TEST_EXECUTE:
3261                 break;
3262         }
3263
3264         ast_data_register_multiple_core(test_providers, ARRAY_LEN(test_providers));
3265
3266         res = ast_data_get(&query);
3267         if (!res) {
3268                 ast_test_status_update(test, "Unable to get tree.");
3269                 ast_data_unregister("test/node1/node11/node111");
3270                 return AST_TEST_FAIL;
3271         }
3272
3273         /* initiate the iterator and check for errors. */
3274         i = ast_data_iterator_init(res, "test_structure/");
3275         if (!i) {
3276                 ast_test_status_update(test, "Unable to initiate the iterator.");
3277                 ast_data_free(res);
3278                 ast_data_unregister("test/node1/node11/node111");
3279                 return AST_TEST_FAIL;
3280         }
3281
3282         /* walk the returned nodes. */
3283         while ((node = ast_data_iterator_next(i))) {
3284                 if (!strcmp(ast_data_retrieve_name(node), "a_int")) {
3285                         if (ast_data_retrieve_int(node, "/") != 10) {
3286                                 ast_data_iterator_end(i);
3287                                 ast_data_free(res);
3288                                 ast_data_unregister("test/node1/node11/node111");
3289                                 return AST_TEST_FAIL;
3290                         }
3291                 } else if (!strcmp(ast_data_retrieve_name(node), "a_uint")) {
3292                         if (ast_data_retrieve_uint(node, "/") != 20) {
3293                                 ast_data_iterator_end(i);
3294                                 ast_data_free(res);
3295                                 ast_data_unregister("test/node1/node11/node111");
3296                                 return AST_TEST_FAIL;
3297                         }
3298                 }
3299         }
3300
3301         /* finish the iterator. */
3302         ast_data_iterator_end(i);
3303
3304         ast_data_free(res);
3305
3306         ast_data_unregister("test/node1/node11/node111");
3307
3308         return AST_TEST_PASS;
3309 }
3310
3311 #endif
3312
3313 int ast_data_init(void)
3314 {
3315         int res = 0;
3316
3317         ast_rwlock_init(&root_data.lock);
3318
3319         if (!(root_data.container = ao2_container_alloc(NUM_DATA_NODE_BUCKETS,
3320                 data_provider_hash, data_provider_cmp))) {
3321                 return -1;
3322         }
3323
3324         res |= ast_cli_register_multiple(cli_data, ARRAY_LEN(cli_data));
3325
3326         res |= ast_manager_register_xml_core("DataGet", 0, manager_data_get);
3327
3328 #ifdef TEST_FRAMEWORK
3329         AST_TEST_REGISTER(test_data_get);
3330 #endif
3331
3332         return res;
3333 }