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