Asterisk data retrieval API.
[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 /*!
1849  * \internal
1850  * \brief Helper function to move an ast_data tree to xml.
1851  * \param[in] parent_data The initial ast_data node to be passed to xml.
1852  * \param[out] parent_xml The root node to insert the xml.
1853  */
1854 static void data_get_xml_add_child(struct ast_data *parent_data,
1855         struct ast_xml_node *parent_xml)
1856 {
1857         struct ao2_iterator i;
1858         struct ast_data *node;
1859         struct ast_xml_node *child_xml;
1860         char node_content[256];
1861
1862         i = ao2_iterator_init(parent_data->children, 0);
1863         while ((node = ao2_iterator_next(&i))) {
1864                 child_xml = ast_xml_new_node(node->name);
1865                 if (!child_xml) {
1866                         ao2_ref(node, -1);
1867                         continue;
1868                 }
1869
1870                 switch (node->type) {
1871                 case AST_DATA_CONTAINER:
1872                         data_get_xml_add_child(node, child_xml);
1873                         break;
1874                 case AST_DATA_STRING:
1875                         ast_xml_set_text(child_xml, node->payload.str);
1876                         break;
1877                 case AST_DATA_INTEGER:
1878                         snprintf(node_content, sizeof(node_content), "%d",
1879                                 node->payload.sint);
1880                         ast_xml_set_text(child_xml, node_content);
1881                         break;
1882                 case AST_DATA_UNSIGNED_INTEGER:
1883                         snprintf(node_content, sizeof(node_content), "%u",
1884                                 node->payload.uint);
1885                         ast_xml_set_text(child_xml, node_content);
1886                         break;
1887                 case AST_DATA_DOUBLE:
1888                         snprintf(node_content, sizeof(node_content), "%f",
1889                                 node->payload.dbl);
1890                         ast_xml_set_text(child_xml, node_content);
1891                         break;
1892                 case AST_DATA_BOOLEAN:
1893                         if (node->payload.boolean) {
1894                                 ast_xml_set_text(child_xml, "true");
1895                         } else {
1896                                 ast_xml_set_text(child_xml, "false");
1897                         }
1898                         break;
1899                 case AST_DATA_POINTER:
1900                         snprintf(node_content, sizeof(node_content), "%p",
1901                                 node->payload.ptr);
1902                         ast_xml_set_text(child_xml, node_content);
1903                         break;
1904                 case AST_DATA_IPADDR:
1905                         snprintf(node_content, sizeof(node_content), "%s",
1906                                 ast_inet_ntoa(node->payload.ipaddr));
1907                         ast_xml_set_text(child_xml, node_content);
1908                         break;
1909                 }
1910                 ast_xml_add_child(parent_xml, child_xml);
1911
1912                 ao2_ref(node, -1);
1913         }
1914         ao2_iterator_destroy(&i);
1915
1916 }
1917
1918 struct ast_xml_doc *ast_data_get_xml(const struct ast_data_query *query)
1919 {
1920         struct ast_xml_doc *doc;
1921         struct ast_xml_node *root;
1922         struct ast_data *res;
1923
1924         res = ast_data_get(query);
1925         if (!res) {
1926                 return NULL;
1927         }
1928
1929         doc = ast_xml_new();
1930         if (!doc) {
1931                 return NULL;
1932         }
1933
1934         root = ast_xml_new_node(res->name);
1935         if (!root) {
1936                 ast_xml_close(doc);
1937         }
1938
1939         ast_xml_set_root(doc, root);
1940
1941         data_get_xml_add_child(res, root);
1942
1943         ast_data_free(res);
1944
1945         return doc;
1946 }
1947
1948 enum ast_data_type ast_data_retrieve_type(struct ast_data *node, const char *path)
1949 {
1950         struct ast_data *internal;
1951
1952         internal = data_result_get_node(node, path);
1953         if (!internal) {
1954                 return -1;
1955         }
1956
1957         return internal->type;
1958 }
1959
1960 char *ast_data_retrieve_name(struct ast_data *node)
1961 {
1962         return node->name;
1963 }
1964
1965 /*!
1966  * \internal
1967  * \brief Insert a child node inside a passed parent node.
1968  * \param root Where we are going to insert the child node.
1969  * \param name The name of the child node to add.
1970  * \param type The type of content inside the child node.
1971  * \param ptr The actual content of the child node.
1972  * \retval NULL on error.
1973  * \retval non-NULL The added child node pointer.
1974  */
1975 static struct ast_data *__ast_data_add(struct ast_data *root, const char *name,
1976         enum ast_data_type type, void *ptr)
1977 {
1978         struct ast_data *node;
1979         struct data_filter *filter, *filter_child = NULL;
1980
1981         if (!root || !root->children) {
1982                 /* invalid data result node. */
1983                 return NULL;
1984         }
1985
1986         /* check if we need to add this node, based on the filter. */
1987         if (root->filter) {
1988                 filter = data_filter_find(root->filter->children, name);
1989                 if (!filter) {
1990                         return NULL;
1991                 }
1992                 ao2_ref(filter, -1);
1993         }
1994
1995         node = data_result_create(name);
1996         if (!node) {
1997                 return NULL;
1998         }
1999
2000         node->type = type;
2001
2002         switch (type) {
2003         case AST_DATA_BOOLEAN:
2004                 node->payload.boolean = *(unsigned int *) ptr;
2005                 break;
2006         case AST_DATA_INTEGER:
2007                 node->payload.sint = *(unsigned int *) ptr;
2008                 break;
2009         case AST_DATA_UNSIGNED_INTEGER:
2010                 node->payload.sint = *(unsigned int *) ptr;
2011                 break;
2012         case AST_DATA_DOUBLE:
2013                 node->payload.dbl = *(double *) ptr;
2014                 break;
2015         case AST_DATA_STRING:
2016         case AST_DATA_POINTER:
2017                 node->payload.ptr = ptr;
2018                 break;
2019         case AST_DATA_IPADDR:
2020                 node->payload.ipaddr = *(struct in_addr *) ptr;
2021                 break;
2022         case AST_DATA_CONTAINER:
2023                 if (root->filter) {
2024                         filter_child = data_filter_find(root->filter->children, name);
2025                         if (filter_child) {
2026                                 /* do not increment the refcount because it is not neccesary. */
2027                                 ao2_ref(filter_child, -1);
2028                         }
2029                 }
2030                 node->filter = filter_child;
2031                 break;
2032         default:
2033                 break;
2034         }
2035
2036         data_result_add_child(root, node);
2037
2038         ao2_ref(node, -1);
2039
2040         return node;
2041 }
2042
2043 struct ast_data *ast_data_add_node(struct ast_data *root, const char *name)
2044 {
2045         return __ast_data_add(root, name, AST_DATA_CONTAINER, NULL);
2046 }
2047
2048 struct ast_data *ast_data_add_int(struct ast_data *root, const char *name, int value)
2049 {
2050         return __ast_data_add(root, name, AST_DATA_INTEGER, &value);
2051 }
2052
2053 struct ast_data *ast_data_add_uint(struct ast_data *root, const char *name,
2054         unsigned int value)
2055 {
2056         return __ast_data_add(root, name, AST_DATA_UNSIGNED_INTEGER, &value);
2057 }
2058
2059 struct ast_data *ast_data_add_dbl(struct ast_data *root, const char *childname,
2060         double dbl)
2061 {
2062         return __ast_data_add(root, childname, AST_DATA_DOUBLE, &dbl);
2063 }
2064
2065 struct ast_data *ast_data_add_bool(struct ast_data *root, const char *childname,
2066         unsigned int boolean)
2067 {
2068         return __ast_data_add(root, childname, AST_DATA_BOOLEAN, &boolean);
2069 }
2070
2071 struct ast_data *ast_data_add_ipaddr(struct ast_data *root, const char *childname,
2072         struct in_addr addr)
2073 {
2074         return __ast_data_add(root, childname, AST_DATA_IPADDR, &addr);
2075 }
2076
2077 struct ast_data *ast_data_add_ptr(struct ast_data *root, const char *childname,
2078         void *ptr)
2079 {
2080         return __ast_data_add(root, childname, AST_DATA_POINTER, ptr);
2081 }
2082
2083 struct ast_data *ast_data_add_str(struct ast_data *root, const char *childname,
2084         const char *value)
2085 {
2086         char *name;
2087         size_t namelen = 1 + (ast_strlen_zero(value) ? 0 : strlen(value));
2088         struct ast_data *res;
2089
2090         if (!(name = ast_malloc(namelen))) {
2091                 return NULL;
2092         }
2093
2094         strcpy(name, (ast_strlen_zero(value) ? "" : value));
2095
2096         res = __ast_data_add(root, childname, AST_DATA_STRING, name);
2097         if (!res) {
2098                 ast_free(name);
2099         }
2100
2101         return res;
2102 }
2103
2104 int __ast_data_add_structure(struct ast_data *root,
2105         const struct ast_data_mapping_structure *mapping, size_t mapping_len,
2106         void *structure)
2107 {
2108         int i;
2109
2110         for (i = 0; i < mapping_len; i++) {
2111                 switch (mapping[i].type) {
2112                 case AST_DATA_INTEGER:
2113                         ast_data_add_int(root, mapping[i].name,
2114                                 mapping[i].get.AST_DATA_INTEGER(structure));
2115                         break;
2116                 case AST_DATA_UNSIGNED_INTEGER:
2117                         ast_data_add_uint(root, mapping[i].name,
2118                                 mapping[i].get.AST_DATA_UNSIGNED_INTEGER(structure));
2119                         break;
2120                 case AST_DATA_DOUBLE:
2121                         ast_data_add_dbl(root, mapping[i].name,
2122                                 mapping[i].get.AST_DATA_DOUBLE(structure));
2123                         break;
2124                 case AST_DATA_BOOLEAN:
2125                         ast_data_add_bool(root, mapping[i].name,
2126                                 mapping[i].get.AST_DATA_BOOLEAN(structure));
2127                         break;
2128                 case AST_DATA_STRING:
2129                         ast_data_add_str(root, mapping[i].name,
2130                                 mapping[i].get.AST_DATA_STRING(structure));
2131                         break;
2132                 case AST_DATA_CONTAINER:
2133                         break;
2134                 case AST_DATA_IPADDR:
2135                         ast_data_add_ipaddr(root, mapping[i].name,
2136                                 mapping[i].get.AST_DATA_IPADDR(structure));
2137                         break;
2138                 case AST_DATA_POINTER:
2139                         ast_data_add_ptr(root, mapping[i].name,
2140                                 mapping[i].get.AST_DATA_POINTER(structure));
2141                         break;
2142                 }
2143         }
2144
2145         return 0;
2146 }
2147
2148 void ast_data_remove_node(struct ast_data *root, struct ast_data *child)
2149 {
2150         ao2_unlink(root->children, child);
2151 }
2152
2153 void ast_data_free(struct ast_data *root)
2154 {
2155         /* destroy it, this will destroy all the internal nodes. */
2156         ao2_ref(root, -1);
2157 }
2158
2159 struct ast_data_iterator *ast_data_iterator_init(struct ast_data *tree,
2160         const char *elements)
2161 {
2162         struct ast_data_iterator *iterator;
2163         struct ao2_iterator i;
2164         struct ast_data *internal = tree;
2165         char *path, *ptr = NULL;
2166
2167         /* tree is the node we want to use to iterate? or we are going
2168          * to iterate thow an internal node? */
2169         if (elements) {
2170                 path = ast_strdupa(elements);
2171
2172                 ptr = strrchr(path, '/');
2173                 if (ptr) {
2174                         *ptr = '\0';
2175                         internal = data_result_get_node(tree, path);
2176                         if (!internal) {
2177                                 return NULL;
2178                         }
2179                 }
2180         }
2181
2182         iterator = ast_calloc(1, sizeof(*iterator));
2183         if (!iterator) {
2184                 return NULL;
2185         }
2186
2187         i = ao2_iterator_init(internal->children, 0);
2188
2189         iterator->pattern = (ptr ? strrchr(elements, '/') + 1 : elements);
2190
2191         /* is the last node a regular expression?, compile it! */
2192         if (!regcomp(&(iterator->regex_pattern), iterator->pattern,
2193                         REG_EXTENDED | REG_NOSUB | REG_ICASE)) {
2194                 iterator->is_pattern = 1;
2195         }
2196
2197         iterator->internal_iterator = i;
2198
2199         return iterator;
2200 }
2201
2202 void ast_data_iterator_end(struct ast_data_iterator *iterator)
2203 {
2204         /* decrement the reference counter. */
2205         if (iterator->last) {
2206                 ao2_ref(iterator->last, -1);
2207         }
2208
2209         /* release the generated pattern. */
2210         if (iterator->is_pattern) {
2211                 regfree(&(iterator->regex_pattern));
2212         }
2213
2214         ao2_iterator_destroy(&(iterator->internal_iterator));
2215
2216         ast_free(iterator);
2217         iterator = NULL;
2218 }
2219
2220 struct ast_data *ast_data_iterator_next(struct ast_data_iterator *iterator)
2221 {
2222         struct ast_data *res;
2223
2224         if (iterator->last) {
2225                 /* release the last retrieved node reference. */
2226                 ao2_ref(iterator->last, -1);
2227         }
2228
2229         while ((res = ao2_iterator_next(&iterator->internal_iterator))) {
2230                 /* if there is no node name pattern specified, return
2231                  * the next node. */
2232                 if (!iterator->pattern) {
2233                         break;
2234                 }
2235
2236                 /* if the pattern is a regular expression, check if this node
2237                  * matches. */
2238                 if (iterator->is_pattern && !regexec(&(iterator->regex_pattern),
2239                         res->name, 0, NULL, 0)) {
2240                         break;
2241                 }
2242
2243                 /* if there is a pattern specified, check if this node matches
2244                  * the wanted node names. */
2245                 if (!iterator->is_pattern && (iterator->pattern &&
2246                                 !strcasecmp(res->name, iterator->pattern))) {
2247                         break;
2248                 }
2249
2250                 ao2_ref(res, -1);
2251         }
2252
2253         iterator->last = res;
2254
2255         return res;
2256 }
2257
2258 int ast_data_retrieve(struct ast_data *tree, const char *path,
2259         struct ast_data_retrieve *content)
2260 {
2261         struct ast_data *node;
2262
2263         if (!content) {
2264                 return -1;
2265         }
2266
2267         node = data_result_get_node(tree, path);
2268         if (!node) {
2269                 ast_log(LOG_ERROR, "Invalid internal node %s\n", path);
2270                 return -1;
2271         }
2272
2273         content->type = node->type;
2274         switch (node->type) {
2275         case AST_DATA_STRING:
2276                 content->value.AST_DATA_STRING = node->payload.str;
2277                 break;
2278         case AST_DATA_INTEGER:
2279                 content->value.AST_DATA_INTEGER = node->payload.sint;
2280                 break;
2281         case AST_DATA_UNSIGNED_INTEGER:
2282                 content->value.AST_DATA_UNSIGNED_INTEGER = node->payload.uint;
2283                 break;
2284         case AST_DATA_BOOLEAN:
2285                 content->value.AST_DATA_BOOLEAN = node->payload.boolean;
2286                 break;
2287         case AST_DATA_IPADDR:
2288                 content->value.AST_DATA_IPADDR = node->payload.ipaddr;
2289                 break;
2290         case AST_DATA_DOUBLE:
2291                 content->value.AST_DATA_DOUBLE = node->payload.dbl;
2292                 break;
2293         case AST_DATA_CONTAINER:
2294                 break;
2295         case AST_DATA_POINTER:
2296                 content->value.AST_DATA_POINTER = node->payload.ptr;
2297                 break;
2298         }
2299
2300         return 0;
2301 }
2302
2303 /*!
2304  * \internal
2305  * \brief One color for each node type.
2306  */
2307 static const struct {
2308         enum ast_data_type type;
2309         int color;
2310 } data_result_color[] = {
2311         { AST_DATA_STRING, COLOR_CYAN },
2312         { AST_DATA_INTEGER, COLOR_RED },
2313         { AST_DATA_UNSIGNED_INTEGER, COLOR_RED },
2314         { AST_DATA_DOUBLE, COLOR_RED },
2315         { AST_DATA_BOOLEAN, COLOR_BRRED },
2316         { AST_DATA_CONTAINER, COLOR_GREEN },
2317         { AST_DATA_IPADDR, COLOR_BROWN },
2318         { AST_DATA_POINTER, COLOR_YELLOW },
2319 };
2320
2321 /*!
2322  * \internal
2323  * \brief Get the color configured for a specific node type.
2324  * \param[in] type The node type.
2325  * \returns The color specified for the passed type.
2326  */
2327 static int data_result_get_color(enum ast_data_type type)
2328 {
2329         int i;
2330         for (i = 0; i < ARRAY_LEN(data_result_color); i++) {
2331                 if (data_result_color[i].type == type) {
2332                         return data_result_color[i].color;
2333                 }
2334         }
2335
2336         return COLOR_BLUE;
2337 }
2338
2339 /*!
2340  * \internal
2341  * \brief Print a node to the CLI.
2342  * \param[in] fd The CLI file descriptor.
2343  * \param[in] node The node to print.
2344  * \param[in] depth The actual node depth in the tree.
2345  */
2346 static void data_result_print_cli_node(int fd, const struct ast_data *node, uint32_t depth)
2347 {
2348         int i;
2349         struct ast_str *tabs, *output;
2350
2351         tabs = ast_str_create(depth * 10 + 1);
2352         if (!tabs) {
2353                 return;
2354         }
2355         ast_str_reset(tabs);
2356         for (i = 0; i < depth; i++) {
2357                 ast_str_append(&tabs, 0, "  ");
2358         }
2359
2360         output = ast_str_create(20);
2361         if (!output) {
2362                 ast_free(tabs);
2363                 return;
2364         }
2365
2366         ast_str_reset(output);
2367         ast_term_color_code(&output, data_result_get_color(node->type), 0);
2368
2369         switch (node->type) {
2370         case AST_DATA_POINTER:
2371                 ast_str_append(&output, 0, "%s%s: %p\n", ast_str_buffer(tabs),
2372                                 node->name, node->payload.ptr);
2373                 break;
2374         case AST_DATA_STRING:
2375                 ast_str_append(&output, 0, "%s%s: \"%s\"\n",
2376                                 ast_str_buffer(tabs),
2377                                 node->name,
2378                                 node->payload.str);
2379                 break;
2380         case AST_DATA_CONTAINER:
2381                 ast_str_append(&output, 0, "%s%s\n", ast_str_buffer(tabs),
2382                                 node->name);
2383                 break;
2384         case AST_DATA_INTEGER:
2385                 ast_str_append(&output, 0, "%s%s: %d\n", ast_str_buffer(tabs),
2386                                 node->name,
2387                                 node->payload.sint);
2388                 break;
2389         case AST_DATA_UNSIGNED_INTEGER:
2390                 ast_str_append(&output, 0, "%s%s: %u\n", ast_str_buffer(tabs),
2391                                 node->name,
2392                                 node->payload.uint);
2393                 break;
2394         case AST_DATA_DOUBLE:
2395                 ast_str_append(&output, 0, "%s%s: %lf\n", ast_str_buffer(tabs),
2396                                 node->name,
2397                                 node->payload.dbl);
2398                 break;
2399         case AST_DATA_BOOLEAN:
2400                 ast_str_append(&output, 0, "%s%s: %s\n", ast_str_buffer(tabs),
2401                                 node->name,
2402                                 ((node->payload.boolean) ? "True" : "False"));
2403                 break;
2404         case AST_DATA_IPADDR:
2405                 ast_str_append(&output, 0, "%s%s: %s\n", ast_str_buffer(tabs),
2406                                 node->name,
2407                                 ast_inet_ntoa(node->payload.ipaddr));
2408                 break;
2409         }
2410
2411         ast_free(tabs);
2412
2413         ast_term_color_code(&output, COLOR_WHITE, 0);
2414
2415         ast_cli(fd, "%s", ast_str_buffer(output));
2416
2417         ast_free(output);
2418
2419         if (node->type == AST_DATA_CONTAINER) {
2420                 __data_result_print_cli(fd, node, depth + 1);
2421         }
2422 }
2423
2424 /*!
2425  * \internal
2426  * \brief Print out an ast_data tree to the CLI.
2427  * \param[in] fd The CLI file descriptor.
2428  * \param[in] root The root node of the tree.
2429  * \param[in] depth Actual depth.
2430  */
2431 static void __data_result_print_cli(int fd, const struct ast_data *root, uint32_t depth)
2432 {
2433         struct ao2_iterator iter;
2434         struct ast_data *node;
2435
2436         if (root->type == AST_DATA_CONTAINER) {
2437                 iter = ao2_iterator_init(root->children, 0);
2438                 while ((node = ao2_iterator_next(&iter))) {
2439                         data_result_print_cli_node(fd, node, depth + 1);
2440                         ao2_ref(node, -1);
2441                 }
2442                 ao2_iterator_destroy(&iter);
2443         } else {
2444                 data_result_print_cli_node(fd, root, depth);
2445         }
2446 }
2447
2448 /*!
2449  * \internal
2450  * \brief
2451  * \param[in] fd The CLI file descriptor.
2452  * \param[in] root The root node of the tree.
2453  */
2454 static void data_result_print_cli(int fd, const struct ast_data *root)
2455 {
2456         struct ast_str *output;
2457
2458         /* print the initial node. */
2459         output = ast_str_create(30);
2460         if (!output) {
2461                 return;
2462         }
2463
2464         ast_term_color_code(&output, data_result_get_color(root->type), 0);
2465         ast_str_append(&output, 0, "%s\n", root->name);
2466         ast_term_color_code(&output, COLOR_WHITE, 0);
2467         ast_cli(fd, "%s", ast_str_buffer(output));
2468         ast_free(output);
2469
2470         __data_result_print_cli(fd, root, 0);
2471 }
2472
2473 /*!
2474  * \internal
2475  * \brief Handle the CLI command "data get".
2476  */
2477 static char *handle_cli_data_get(struct ast_cli_entry *e, int cmd,
2478                 struct ast_cli_args *a)
2479 {
2480         struct ast_data_query query = {
2481                 .version = AST_DATA_QUERY_VERSION
2482         };
2483         struct ast_data *tree;
2484
2485         switch (cmd) {
2486         case CLI_INIT:
2487                 e->command = "data get";
2488                 e->usage = ""
2489                         "Usage: data get <path> [<search> [<filter>]]\n"
2490                         "       Get the tree based on a path.\n";
2491                 return NULL;
2492         case CLI_GENERATE:
2493                 return NULL;
2494         }
2495
2496         if (a->argc < e->args + 1) {
2497                 return CLI_SHOWUSAGE;
2498         }
2499
2500         query.path = (char *) a->argv[e->args];
2501
2502         if (a->argc > e->args + 1) {
2503                 query.search = (char *) a->argv[e->args + 1];
2504         }
2505
2506         if (a->argc > e->args + 2) {
2507                 query.filter = (char *) a->argv[e->args + 2];
2508         }
2509
2510         tree = ast_data_get(&query);
2511         if (!tree) {
2512                 return CLI_FAILURE;
2513         }
2514
2515         data_result_print_cli(a->fd, tree);
2516
2517         ast_data_free(tree);
2518
2519         return CLI_SUCCESS;
2520 }
2521
2522 /*!
2523  * \internal
2524  * \brief Print the list of data providers.
2525  * \param[in] fd The CLI file descriptor.
2526  * \param[in] name The last node visited name.
2527  * \param[in] container The childrens of the last node.
2528  * \param[in] path The path to the current node.
2529  */
2530 static void data_provider_print_cli(int fd, const char *name,
2531         struct ao2_container *container, struct ast_str *path)
2532 {
2533         struct ao2_iterator i;
2534         struct ast_str *current_path;
2535         struct data_provider *provider;
2536
2537         current_path = ast_str_create(60);
2538         if (!current_path) {
2539                 return;
2540         }
2541
2542         ast_str_reset(current_path);
2543         if (path) {
2544                 ast_str_set(&current_path, 0, "%s/%s", ast_str_buffer(path), name);
2545         } else {
2546                 ast_str_set(&current_path, 0, "%s", name);
2547         }
2548
2549         i = ao2_iterator_init(container, 0);
2550         while ((provider = ao2_iterator_next(&i))) {
2551                 if (provider->handler) {
2552                         /* terminal node, print it. */
2553                         ast_cli(fd, "%s/%s (", ast_str_buffer(current_path),
2554                                 provider->name);
2555                         if (provider->handler->get) {
2556                                 ast_cli(fd, "get");
2557                         }
2558                         ast_cli(fd, ") [%s]\n", provider->registrar);
2559                 }
2560                 data_provider_print_cli(fd, provider->name, provider->children,
2561                         current_path);
2562                 ao2_ref(provider, -1);
2563         }
2564         ao2_iterator_destroy(&i);
2565
2566         ast_free(current_path);
2567 }
2568
2569 /*!
2570  * \internal
2571  * \brief Handle CLI command "data show providers"
2572  */
2573 static char *handle_cli_data_show_providers(struct ast_cli_entry *e, int cmd,
2574                 struct ast_cli_args *a)
2575 {
2576         switch (cmd) {
2577         case CLI_INIT:
2578                 e->command = "data show providers";
2579                 e->usage = ""
2580                         "Usage: data show providers\n"
2581                         "       Show the list of registered providers\n";
2582                 return NULL;
2583         case CLI_GENERATE:
2584                 return NULL;
2585         }
2586
2587         data_read_lock();
2588         data_provider_print_cli(a->fd, "", root_data.container, NULL);
2589         data_unlock();
2590
2591         return CLI_SUCCESS;
2592 }
2593
2594 /*!
2595  * \internal
2596  * \brief Data API CLI commands.
2597  */
2598 static struct ast_cli_entry cli_data[] = {
2599         AST_CLI_DEFINE(handle_cli_data_get, "Data API get"),
2600         AST_CLI_DEFINE(handle_cli_data_show_providers, "Show data providers")
2601 };
2602
2603 /*!
2604  * \internal
2605  * \brief Output a tree to the AMI.
2606  * \param[in] s AMI session.
2607  * \param[in] name The root node name.
2608  * \param[in] container The root container.
2609  * \param[in] path The current path.
2610  */
2611 static void data_result_manager_output(struct mansession *s, const char *name,
2612         struct ao2_container *container, struct ast_str *path, int id)
2613 {
2614         struct ao2_iterator i;
2615         struct ast_str *current_path;
2616         struct ast_data *node;
2617         int current_id = id;
2618
2619         current_path = ast_str_create(60);
2620         if (!current_path) {
2621                 return;
2622         }
2623
2624         ast_str_reset(current_path);
2625         if (path) {
2626                 ast_str_set(&current_path, 0, "%s.%s", ast_str_buffer(path), name);
2627         } else {
2628                 ast_str_set(&current_path, 0, "%s", name);
2629         }
2630
2631         i = ao2_iterator_init(container, 0);
2632         while ((node = ao2_iterator_next(&i))) {
2633                 /* terminal node, print it. */
2634                 if (node->type != AST_DATA_CONTAINER) {
2635                         astman_append(s, "%d-%s.%s", id, ast_str_buffer(current_path),
2636                                         node->name);
2637                 }
2638                 switch (node->type) {
2639                 case AST_DATA_CONTAINER:
2640                         data_result_manager_output(s, node->name, node->children, current_path, ++current_id);
2641                         break;
2642                 case AST_DATA_INTEGER:
2643                         astman_append(s, ": %d\r\n", node->payload.sint);
2644                         break;
2645                 case AST_DATA_UNSIGNED_INTEGER:
2646                         astman_append(s, ": %u\r\n", node->payload.uint);
2647                         break;
2648                 case AST_DATA_STRING:
2649                         astman_append(s, ": %s\r\n", node->payload.str);
2650                         break;
2651                 case AST_DATA_IPADDR:
2652                         astman_append(s, ": %s\r\n", ast_inet_ntoa(node->payload.ipaddr));
2653                         break;
2654                 case AST_DATA_POINTER:
2655                         break;
2656                 case AST_DATA_DOUBLE:
2657                         astman_append(s, ": %f\r\n", node->payload.dbl);
2658                         break;
2659                 case AST_DATA_BOOLEAN:
2660                         astman_append(s, ": %s\r\n",
2661                                 (node->payload.boolean ? "True" : "False"));
2662                         break;
2663                 }
2664
2665                 ao2_ref(node, -1);
2666         }
2667         ao2_iterator_destroy(&i);
2668
2669         ast_free(current_path);
2670 }
2671
2672 /*!
2673  * \internal
2674  * \brief Implements the manager action: "DataGet".
2675  */
2676 static int manager_data_get(struct mansession *s, const struct message *m)
2677 {
2678         const char *path = astman_get_header(m, "Path");
2679         const char *search = astman_get_header(m, "Search");
2680         const char *filter = astman_get_header(m, "Filter");
2681         const char *id = astman_get_header(m, "ActionID");
2682         struct ast_data *res;
2683         struct ast_data_query query = {
2684                 .version = AST_DATA_QUERY_VERSION,
2685                 .path = (char *) path,
2686                 .search = (char *) search,
2687                 .filter = (char *) filter,
2688         };
2689
2690         if (ast_strlen_zero(path)) {
2691                 astman_send_error(s, m, "'Path' parameter not specified");
2692                 return 0;
2693         }
2694
2695         res = ast_data_get(&query);
2696         if (!res) {
2697                 astman_send_error(s, m, "No data returned");
2698                 return 0;
2699         }
2700
2701         astman_append(s, "Event: DataGet Tree\r\n");
2702         if (!ast_strlen_zero(id)) {
2703                 astman_append(s, "ActionID: %s\r\n", id);
2704         }
2705         data_result_manager_output(s, res->name, res->children, NULL, 0);
2706         astman_append(s, "\r\n");
2707
2708         ast_data_free(res);
2709
2710         return RESULT_SUCCESS;
2711 }
2712
2713 #ifdef TEST_FRAMEWORK
2714
2715 /*!
2716  * \internal
2717  * \brief Structure used to test how to add a complete structure,
2718  *        and how to compare it.
2719  */
2720 struct test_structure {
2721         int a_int;
2722         unsigned int b_bool:1;
2723         char *c_str;
2724         unsigned int a_uint;
2725 };
2726
2727 /*!
2728  * \internal
2729  * \brief test_structure mapping.
2730  */
2731 #define DATA_EXPORT_TEST_STRUCTURE(MEMBER)                              \
2732         MEMBER(test_structure, a_int, AST_DATA_INTEGER)                 \
2733         MEMBER(test_structure, b_bool, AST_DATA_BOOLEAN)                \
2734         MEMBER(test_structure, c_str, AST_DATA_STRING)                  \
2735         MEMBER(test_structure, a_uint, AST_DATA_UNSIGNED_INTEGER)
2736
2737 AST_DATA_STRUCTURE(test_structure, DATA_EXPORT_TEST_STRUCTURE);
2738
2739 /*!
2740  * \internal
2741  * \brief Callback implementation.
2742  */
2743 static int test_data_full_provider(const struct ast_data_search *search,
2744                 struct ast_data *root)
2745 {
2746         struct ast_data *test_structure;
2747         struct test_structure local_test_structure = {
2748                 .a_int = 10,
2749                 .b_bool = 1,
2750                 .c_str = "test string",
2751                 .a_uint = 20
2752         };
2753
2754         if (ast_data_search_cmp_structure(search, test_structure, &local_test_structure, "test_structure")) {
2755                 return 0;
2756         }
2757
2758         test_structure = ast_data_add_node(root, "test_structure");
2759         if (!test_structure) {
2760                 ast_debug(1, "Internal data api error\n");
2761                 return 0;
2762         }
2763
2764         /* add the complete structure. */
2765         ast_data_add_structure(test_structure, test_structure, &local_test_structure);
2766
2767         return 0;
2768 }
2769
2770 /*!
2771  * \internal
2772  * \brief Handler definition for the full provider.
2773  */
2774 static const struct ast_data_handler full_provider = {
2775         .version = AST_DATA_HANDLER_VERSION,
2776         .get = test_data_full_provider
2777 };
2778
2779 /*!
2780  * \internal
2781  * \brief Structure used to define multiple providers at once.
2782  */
2783 static const struct ast_data_entry test_providers[] = {
2784         AST_DATA_ENTRY("test/node1/node11/node111", &full_provider)
2785 };
2786
2787 AST_TEST_DEFINE(test_data_get)
2788 {
2789         struct ast_data *res, *node;
2790         struct ast_data_iterator *i;
2791         struct ast_data_query query = {
2792                 .version = AST_DATA_QUERY_VERSION,
2793                 .path = "test/node1/node11/node111",
2794                 .search = "node111/test_structure/a_int=10",
2795                 .filter = "node111/test_structure/a*int"
2796         };
2797
2798         switch (cmd) {
2799         case TEST_INIT:
2800                 info->name = "data_test";
2801                 info->category = "main/data/";
2802                 info->summary = "Data API unit test";
2803                 info->description =
2804                         "Tests whether data API get implementation works as expected.";
2805                 return AST_TEST_NOT_RUN;
2806         case TEST_EXECUTE:
2807                 break;
2808         }
2809
2810         ast_data_register_multiple_core(test_providers, ARRAY_LEN(test_providers));
2811
2812         res = ast_data_get(&query);
2813         if (!res) {
2814                 ast_test_status_update(test, "Unable to get tree.");
2815                 ast_data_unregister("test/node1/node11/node111");
2816                 return AST_TEST_FAIL;
2817         }
2818
2819         /* initiate the iterator and check for errors. */
2820         i = ast_data_iterator_init(res, "test_structure/");
2821         if (!i) {
2822                 ast_test_status_update(test, "Unable to initiate the iterator.");
2823                 ast_data_free(res);
2824                 ast_data_unregister("test/node1/node11/node111");
2825                 return AST_TEST_FAIL;
2826         }
2827
2828         /* walk the returned nodes. */
2829         while ((node = ast_data_iterator_next(i))) {
2830                 if (!strcmp(ast_data_retrieve_name(node), "a_int")) {
2831                         if (ast_data_retrieve_int(node, "/") != 10) {
2832                                 ast_data_iterator_end(i);
2833                                 ast_data_free(res);
2834                                 ast_data_unregister("test/node1/node11/node111");
2835                                 return AST_TEST_FAIL;
2836                         }
2837                 } else if (!strcmp(ast_data_retrieve_name(node), "a_uint")) {
2838                         if (ast_data_retrieve_uint(node, "/") != 20) {
2839                                 ast_data_iterator_end(i);
2840                                 ast_data_free(res);
2841                                 ast_data_unregister("test/node1/node11/node111");
2842                                 return AST_TEST_FAIL;
2843                         }
2844                 }
2845         }
2846
2847         /* finish the iterator. */
2848         ast_data_iterator_end(i);
2849
2850         ast_data_free(res);
2851
2852         ast_data_unregister("test/node1/node11/node111");
2853
2854         return AST_TEST_PASS;
2855 }
2856
2857 #endif
2858
2859 int ast_data_init(void)
2860 {
2861         int res = 0;
2862
2863         ast_rwlock_init(&root_data.lock);
2864
2865         if (!(root_data.container = ao2_container_alloc(NUM_DATA_NODE_BUCKETS,
2866                 data_provider_hash, data_provider_cmp))) {
2867                 return -1;
2868         }
2869
2870         res |= ast_cli_register_multiple(cli_data, ARRAY_LEN(cli_data));
2871
2872         res |= ast_manager_register_xml("DataGet", 0, manager_data_get);
2873
2874 #ifdef TEST_FRAMEWORK
2875         AST_TEST_REGISTER(test_data_get);
2876 #endif
2877
2878         return res;
2879 }