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