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