Wed Jan 8 2020 09:49:46

Asterisk developer's documentation


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