00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #include "asterisk.h"
00026
00027 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 275105 $")
00028
00029 #include "asterisk/_private.h"
00030
00031 #include <regex.h>
00032
00033 #include "asterisk/module.h"
00034 #include "asterisk/utils.h"
00035 #include "asterisk/lock.h"
00036 #include "asterisk/data.h"
00037 #include "asterisk/astobj2.h"
00038 #include "asterisk/xml.h"
00039 #include "asterisk/cli.h"
00040 #include "asterisk/term.h"
00041 #include "asterisk/manager.h"
00042 #include "asterisk/test.h"
00043 #include "asterisk/frame.h"
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062 #define NUM_DATA_NODE_BUCKETS 59
00063 #define NUM_DATA_RESULT_BUCKETS 59
00064 #define NUM_DATA_SEARCH_BUCKETS 59
00065 #define NUM_DATA_FILTER_BUCKETS 59
00066
00067
00068 static const uint32_t latest_handler_compatible_version = 0;
00069
00070
00071 static const uint32_t latest_query_compatible_version = 0;
00072
00073
00074 static const uint32_t current_handler_version = AST_DATA_HANDLER_VERSION;
00075
00076
00077 static const uint32_t current_query_version = AST_DATA_QUERY_VERSION;
00078
00079
00080
00081 struct ast_data {
00082 enum ast_data_type type;
00083
00084
00085 union {
00086 int32_t sint;
00087 uint32_t uint;
00088 double dbl;
00089 unsigned int boolean;
00090 char *str;
00091 char character;
00092 struct in_addr ipaddr;
00093 void *ptr;
00094 } payload;
00095
00096
00097
00098 const struct data_filter *filter;
00099
00100
00101 struct ao2_container *children;
00102
00103 char name[0];
00104 };
00105
00106
00107 enum data_search_comparison {
00108 DATA_CMP_UNKNOWN,
00109 DATA_CMP_EQ,
00110 DATA_CMP_NEQ,
00111 DATA_CMP_GT,
00112 DATA_CMP_GE,
00113 DATA_CMP_LT,
00114 DATA_CMP_LE
00115 };
00116
00117
00118 struct ast_data_search {
00119
00120 char *value;
00121
00122 enum data_search_comparison cmp_type;
00123
00124 struct ao2_container *children;
00125
00126 char name[0];
00127 };
00128
00129 struct data_filter;
00130
00131
00132 struct data_filter {
00133
00134 struct ao2_container *children;
00135
00136 AST_LIST_HEAD_NOLOCK(glob_list_t, data_filter) glob_list;
00137
00138 AST_LIST_ENTRY(data_filter) list;
00139
00140 char name[0];
00141 };
00142
00143
00144 struct data_provider {
00145
00146 const struct ast_data_handler *handler;
00147
00148 struct ast_module *module;
00149
00150 struct ao2_container *children;
00151
00152 const char *registrar;
00153
00154 char name[0];
00155 };
00156
00157
00158 struct ast_data_iterator {
00159
00160 struct ao2_iterator internal_iterator;
00161
00162 struct ast_data *last;
00163
00164 const char *pattern;
00165
00166 regex_t regex_pattern;
00167
00168 unsigned int is_pattern:1;
00169 };
00170
00171 struct {
00172
00173 struct ao2_container *container;
00174
00175 ast_rwlock_t lock;
00176 } root_data;
00177
00178 static void __data_result_print_cli(int fd, const struct ast_data *root, uint32_t depth);
00179
00180
00181
00182
00183
00184
00185 static int data_provider_hash(const void *obj, const int flags)
00186 {
00187 const struct data_provider *node = obj;
00188 return ast_str_case_hash(node->name);
00189 }
00190
00191
00192
00193
00194
00195
00196 static int data_provider_cmp(void *obj1, void *obj2, int flags)
00197 {
00198 struct data_provider *node1 = obj1, *node2 = obj2;
00199 return strcasecmp(node1->name, node2->name) ? 0 : CMP_MATCH;
00200 }
00201
00202
00203
00204
00205
00206 static int data_result_hash(const void *obj, const int flags)
00207 {
00208 const struct ast_data *node = obj;
00209 return ast_str_hash(node->name);
00210 }
00211
00212
00213
00214
00215
00216 static int data_result_cmp(void *obj, void *arg, int flags)
00217 {
00218 struct ast_data *node1 = obj, *node2 = arg;
00219 return strcasecmp(node1->name, node2->name) ? 0 : CMP_MATCH;
00220 }
00221
00222
00223
00224
00225
00226
00227 #define data_write_lock() ast_rwlock_wrlock(&root_data.lock)
00228
00229
00230
00231
00232
00233
00234 #define data_read_lock() ast_rwlock_rdlock(&root_data.lock)
00235
00236
00237
00238
00239
00240 #define data_unlock() ast_rwlock_unlock(&root_data.lock)
00241
00242
00243
00244
00245
00246
00247
00248
00249
00250
00251 static int data_structure_compatible(int structure_version, uint32_t latest_compatible,
00252 uint32_t current)
00253 {
00254 if (structure_version >= latest_compatible && structure_version <= current) {
00255 return 1;
00256 }
00257
00258 ast_log(LOG_ERROR, "A module is not compatible with the"
00259 "current data api version\n");
00260
00261 return 0;
00262 }
00263
00264
00265
00266
00267
00268
00269
00270
00271
00272 static char *next_node_name(char **path)
00273 {
00274 char *res;
00275
00276 do {
00277 res = strsep(path, "/");
00278 } while (res && ast_strlen_zero(res));
00279
00280 return res;
00281 }
00282
00283
00284
00285
00286
00287 static void data_provider_destructor(void *obj)
00288 {
00289 struct data_provider *provider = obj;
00290
00291 ao2_ref(provider->children, -1);
00292 }
00293
00294
00295
00296
00297
00298
00299
00300
00301
00302
00303 static struct data_provider *data_provider_new(const char *name,
00304 const struct ast_data_handler *handler, const char *registrar)
00305 {
00306 struct data_provider *node;
00307 size_t namelen;
00308
00309 namelen = strlen(name) + 1;
00310
00311 node = ao2_alloc(sizeof(*node) + namelen, data_provider_destructor);
00312 if (!node) {
00313 return NULL;
00314 }
00315
00316 node->handler = handler;
00317 node->registrar = registrar;
00318 strcpy(node->name, name);
00319
00320
00321 if (!(node->children = ao2_container_alloc(NUM_DATA_NODE_BUCKETS,
00322 data_provider_hash, data_provider_cmp))) {
00323 ao2_ref(node, -1);
00324 return NULL;
00325 }
00326
00327 return node;
00328 }
00329
00330
00331
00332
00333
00334
00335
00336
00337
00338
00339
00340 static struct data_provider *data_provider_add_child(struct ao2_container *parent,
00341 const char *name, const struct ast_data_handler *handler, const char *registrar)
00342 {
00343 struct data_provider *child;
00344
00345 child = data_provider_new(name, handler, registrar);
00346 if (!child) {
00347 return NULL;
00348 }
00349
00350 ao2_link(parent, child);
00351
00352 return child;
00353 }
00354
00355
00356
00357
00358
00359
00360
00361
00362
00363
00364
00365 static struct data_provider *data_provider_find(struct ao2_container *parent,
00366 const char *name, const char *registrar)
00367 {
00368 struct data_provider *find_node, *found;
00369
00370
00371 find_node = data_provider_new(name, NULL, NULL);
00372 if (!find_node) {
00373 return NULL;
00374 }
00375
00376 found = ao2_find(parent, find_node, OBJ_POINTER);
00377
00378
00379 ao2_ref(find_node, -1);
00380
00381 if (found && found->registrar && registrar) {
00382 if (strcmp(found->registrar, registrar)) {
00383
00384 ast_debug(1, "Registrar doesn't match, node was registered"
00385 " by '%s' and we are searching for '%s'\n",
00386 found->registrar, registrar);
00387 ao2_ref(found, -1);
00388 return NULL;
00389 }
00390 }
00391
00392 return found;
00393 }
00394
00395
00396
00397
00398
00399
00400
00401
00402
00403
00404
00405 static int data_provider_release(struct ao2_container *parent, const char *path,
00406 const char *registrar)
00407 {
00408 char *node_name, *rpath;
00409 struct data_provider *child;
00410 int ret = 0;
00411
00412 rpath = ast_strdupa(path);
00413
00414 node_name = next_node_name(&rpath);
00415 if (!node_name) {
00416 return -1;
00417 }
00418
00419 child = data_provider_find(parent, node_name, registrar);
00420 if (!child) {
00421 return -1;
00422 }
00423
00424
00425 if (!child->handler && rpath) {
00426 ret = data_provider_release(child->children, rpath, registrar);
00427 }
00428
00429
00430 if (!ret && !ao2_container_count(child->children)) {
00431 ao2_unlink(parent, child);
00432 }
00433
00434 ao2_ref(child, -1);
00435
00436 return ret;
00437 }
00438
00439
00440
00441
00442
00443
00444
00445
00446 static void data_provider_release_all(struct ao2_container *parent,
00447 const char *registrar)
00448 {
00449 struct ao2_iterator i;
00450 struct data_provider *node;
00451
00452 i = ao2_iterator_init(parent, 0);
00453 while ((node = ao2_iterator_next(&i))) {
00454 if (!node->handler) {
00455
00456 data_provider_release_all(node->children, registrar);
00457 if (!ao2_container_count(node->children)) {
00458
00459 ao2_unlink(parent, node);
00460 }
00461 } else {
00462 if (!strcmp(node->registrar, registrar)) {
00463
00464 ao2_unlink(parent, node);
00465 }
00466 }
00467 ao2_ref(node, -1);
00468 }
00469 ao2_iterator_destroy(&i);
00470
00471 }
00472
00473
00474
00475
00476
00477
00478
00479
00480
00481
00482
00483 static struct data_provider *data_provider_create(struct ao2_container *parent,
00484 const char *path, const char *registrar)
00485 {
00486 char *rpath, *node_name;
00487 struct data_provider *child, *ret = NULL;
00488
00489 rpath = ast_strdupa(path);
00490
00491 node_name = next_node_name(&rpath);
00492 if (!node_name) {
00493
00494 return NULL;
00495 }
00496
00497 child = data_provider_find(parent, node_name, NULL);
00498
00499 if (!child) {
00500
00501 child = data_provider_add_child(parent, node_name, NULL, registrar);
00502 }
00503
00504 if (rpath) {
00505 ret = data_provider_create(child->children, rpath, registrar);
00506 if (ret) {
00507 ao2_ref(child, -1);
00508 }
00509 }
00510
00511 return ret ? ret : child;
00512 }
00513
00514 int __ast_data_register(const char *path, const struct ast_data_handler *handler,
00515 const char *registrar, struct ast_module *mod)
00516 {
00517 struct data_provider *node;
00518
00519 if (!path) {
00520 return -1;
00521 }
00522
00523
00524 if (!data_structure_compatible(handler->version,
00525 latest_handler_compatible_version,
00526 current_handler_version)) {
00527 return -1;
00528 }
00529
00530
00531 data_write_lock();
00532
00533 node = data_provider_create(root_data.container, path, registrar);
00534 if (!node) {
00535 ast_log(LOG_ERROR, "Unable to create the specified path (%s) "
00536 "for '%s'.\n", path, registrar);
00537 data_unlock();
00538 return -1;
00539 }
00540
00541 if (ao2_container_count(node->children) || node->handler) {
00542 ast_log(LOG_ERROR, "The node '%s' was already registered. "
00543 "We were unable to register '%s' for registrar '%s'.\n",
00544 node->name, path, registrar);
00545 ao2_ref(node, -1);
00546 data_unlock();
00547 return -1;
00548 }
00549
00550
00551 node->handler = handler;
00552 node->module = mod;
00553
00554 ao2_ref(node, -1);
00555
00556 data_unlock();
00557
00558 return 0;
00559 }
00560
00561 int __ast_data_register_multiple(const struct ast_data_entry *data_entries,
00562 size_t entries, const char *registrar, struct ast_module *mod)
00563 {
00564 int i, res;
00565
00566 for (i = 0; i < entries; i++) {
00567 res = __ast_data_register(data_entries[i].path, data_entries[i].handler,
00568 registrar, mod);
00569 if (res) {
00570
00571
00572 while ((--i) >= 0) {
00573 __ast_data_unregister(data_entries[i].path, registrar);
00574 }
00575 return -1;
00576 }
00577 }
00578
00579 return 0;
00580 }
00581
00582 int __ast_data_unregister(const char *path, const char *registrar)
00583 {
00584 int ret = 0;
00585
00586 data_write_lock();
00587 if (path) {
00588 ret = data_provider_release(root_data.container, path, registrar);
00589 } else {
00590 data_provider_release_all(root_data.container, registrar);
00591 }
00592 data_unlock();
00593
00594 if (path && ret) {
00595 ast_log(LOG_ERROR, "Unable to unregister '%s' for '%s'\n",
00596 path, registrar);
00597 }
00598
00599 return ret;
00600 }
00601
00602
00603
00604
00605
00606
00607
00608
00609 static int data_search_comparison_char(char a)
00610 {
00611 switch (a) {
00612 case '!':
00613 case '=':
00614 case '<':
00615 case '>':
00616 return 1;
00617 }
00618
00619 return 0;
00620 }
00621
00622
00623
00624
00625
00626 static enum data_search_comparison data_search_comparison_type(const char *comparison)
00627 {
00628 if (!strcmp(comparison, "=")) {
00629 return DATA_CMP_EQ;
00630 } else if (!strcmp(comparison, "!=")) {
00631 return DATA_CMP_NEQ;
00632 } else if (!strcmp(comparison, "<")) {
00633 return DATA_CMP_LT;
00634 } else if (!strcmp(comparison, ">")) {
00635 return DATA_CMP_GT;
00636 } else if (!strcmp(comparison, "<=")) {
00637 return DATA_CMP_LE;
00638 } else if (!strcmp(comparison, ">=")) {
00639 return DATA_CMP_GE;
00640 }
00641
00642 return DATA_CMP_UNKNOWN;
00643 }
00644
00645
00646
00647
00648
00649 static int data_search_hash(const void *obj, const int flags)
00650 {
00651 const struct ast_data_search *node = obj;
00652 return ast_str_hash(node->name);
00653 }
00654
00655
00656
00657
00658
00659 static int data_search_cmp(void *obj, void *arg, int flags)
00660 {
00661 struct ast_data_search *node1 = obj, *node2 = arg;
00662 return strcasecmp(node1->name, node2->name) ? 0 : CMP_MATCH;
00663 }
00664
00665
00666
00667
00668
00669 static void data_search_destructor(void *obj)
00670 {
00671 struct ast_data_search *node = obj;
00672
00673 if (node->value) {
00674 ast_free(node->value);
00675 }
00676
00677 ao2_ref(node->children, -1);
00678 }
00679
00680
00681
00682
00683
00684
00685
00686 static struct ast_data_search *data_search_alloc(const char *name)
00687 {
00688 struct ast_data_search *res;
00689 size_t name_len = strlen(name) + 1;
00690
00691 res = ao2_alloc(sizeof(*res) + name_len, data_search_destructor);
00692 if (!res) {
00693 return NULL;
00694 }
00695
00696 res->children = ao2_container_alloc(NUM_DATA_SEARCH_BUCKETS, data_search_hash,
00697 data_search_cmp);
00698
00699 if (!res) {
00700 ao2_ref(res, -1);
00701 return NULL;
00702 }
00703
00704 strcpy(res->name, name);
00705
00706 return res;
00707 }
00708
00709
00710
00711
00712
00713
00714
00715
00716
00717
00718 static struct ast_data_search *data_search_find(struct ao2_container *parent,
00719 const char *name)
00720 {
00721 struct ast_data_search *find_node, *found;
00722
00723 find_node = data_search_alloc(name);
00724 if (!find_node) {
00725 return NULL;
00726 }
00727
00728 found = ao2_find(parent, find_node, OBJ_POINTER);
00729
00730
00731 ao2_ref(find_node, -1);
00732
00733 return found;
00734 }
00735
00736
00737
00738
00739
00740
00741
00742
00743
00744 static struct ast_data_search *data_search_add_child(struct ao2_container *parent,
00745 const char *name)
00746 {
00747 struct ast_data_search *child;
00748
00749 child = data_search_alloc(name);
00750 if (!child) {
00751 return NULL;
00752 }
00753
00754 ao2_link(parent, child);
00755
00756 return child;
00757 }
00758
00759
00760
00761
00762
00763
00764
00765
00766
00767 static struct ast_data_search *data_search_create(struct ao2_container *parent,
00768 const char *path)
00769 {
00770 char *rpath, *node_name;
00771 struct ast_data_search *child = NULL;
00772 struct ao2_container *current = parent;
00773
00774 rpath = ast_strdupa(path);
00775
00776 node_name = next_node_name(&rpath);
00777 while (node_name) {
00778 child = data_search_find(current, node_name);
00779 if (!child) {
00780 child = data_search_add_child(current, node_name);
00781 }
00782 ao2_ref(child, -1);
00783 current = child->children;
00784 node_name = next_node_name(&rpath);
00785 }
00786
00787 return child;
00788 }
00789
00790
00791
00792
00793
00794
00795
00796
00797 static struct ast_data_search *data_search_generate(const char *search_string)
00798 {
00799 struct ast_str *name, *value, *comparison;
00800 char *elements, *search_string_dup, *saveptr;
00801 int i;
00802 struct ast_data_search *root, *child;
00803 enum data_search_comparison cmp_type;
00804 size_t search_string_len;
00805
00806 if (!search_string) {
00807 ast_log(LOG_ERROR, "You must pass a valid search string.\n");
00808 return NULL;
00809 }
00810
00811 search_string_len = strlen(search_string);
00812
00813 name = ast_str_create(search_string_len);
00814 if (!name) {
00815 return NULL;
00816 }
00817 value = ast_str_create(search_string_len);
00818 if (!value) {
00819 ast_free(name);
00820 return NULL;
00821 }
00822 comparison = ast_str_create(search_string_len);
00823 if (!comparison) {
00824 ast_free(name);
00825 ast_free(value);
00826 return NULL;
00827 }
00828
00829 search_string_dup = ast_strdupa(search_string);
00830
00831
00832 root = data_search_alloc("/");
00833 if (!root) {
00834 ast_free(name);
00835 ast_free(value);
00836 ast_free(comparison);
00837 return NULL;
00838 }
00839
00840 for (elements = strtok_r(search_string_dup, ",", &saveptr); elements;
00841 elements = strtok_r(NULL, ",", &saveptr)) {
00842
00843 ast_str_reset(name);
00844 for (i = 0; !data_search_comparison_char(elements[i]) &&
00845 elements[i]; i++) {
00846 ast_str_append(&name, 0, "%c", elements[i]);
00847 }
00848
00849
00850 if (!data_search_comparison_char(elements[i])) {
00851
00852
00853 ast_log(LOG_ERROR, "Invalid search string!\n");
00854 continue;
00855 }
00856
00857
00858 ast_str_reset(comparison);
00859 for (; data_search_comparison_char(elements[i]) && elements[i]; i++) {
00860 ast_str_append(&comparison, 0, "%c", elements[i]);
00861 }
00862
00863
00864 ast_str_reset(value);
00865 for (; elements[i]; i++) {
00866 ast_str_append(&value, 0, "%c", elements[i]);
00867 }
00868
00869 cmp_type = data_search_comparison_type(ast_str_buffer(comparison));
00870 if (cmp_type == DATA_CMP_UNKNOWN) {
00871 ast_log(LOG_ERROR, "Invalid comparison '%s'\n",
00872 ast_str_buffer(comparison));
00873 continue;
00874 }
00875
00876
00877 child = data_search_create(root->children, ast_str_buffer(name));
00878 if (child) {
00879 child->cmp_type = cmp_type;
00880 child->value = ast_strdup(ast_str_buffer(value));
00881 }
00882 }
00883
00884 ast_free(name);
00885 ast_free(value);
00886 ast_free(comparison);
00887
00888 return root;
00889 }
00890
00891
00892
00893
00894
00895
00896 static void data_search_release(struct ast_data_search *search)
00897 {
00898 ao2_ref(search, -1);
00899 }
00900
00901
00902
00903
00904
00905
00906
00907
00908
00909
00910 static inline int data_search_comparison_result(int cmpval,
00911 enum data_search_comparison comparison_type)
00912 {
00913 switch (comparison_type) {
00914 case DATA_CMP_GE:
00915 if (cmpval >= 0) {
00916 return 0;
00917 }
00918 break;
00919 case DATA_CMP_LE:
00920 if (cmpval <= 0) {
00921 return 0;
00922 }
00923 break;
00924 case DATA_CMP_EQ:
00925 if (cmpval == 0) {
00926 return 0;
00927 }
00928 break;
00929 case DATA_CMP_NEQ:
00930 if (cmpval != 0) {
00931 return 0;
00932 }
00933 break;
00934 case DATA_CMP_LT:
00935 if (cmpval < 0) {
00936 return 0;
00937 }
00938 break;
00939 case DATA_CMP_GT:
00940 if (cmpval > 0) {
00941 return 0;
00942 }
00943 break;
00944 case DATA_CMP_UNKNOWN:
00945 break;
00946 }
00947 return 1;
00948 }
00949
00950
00951
00952
00953
00954
00955
00956
00957
00958 static struct ast_data_search *data_search_get_node(const struct ast_data_search *node,
00959 const char *path)
00960 {
00961 char *savepath, *node_name;
00962 struct ast_data_search *child, *current = (struct ast_data_search *) node;
00963
00964 if (!node) {
00965 return NULL;
00966 }
00967
00968 savepath = ast_strdupa(path);
00969 node_name = next_node_name(&savepath);
00970
00971 while (node_name) {
00972 child = data_search_find(current->children, node_name);
00973 if (current != node) {
00974 ao2_ref(current, -1);
00975 }
00976 if (!child) {
00977 return NULL;
00978 };
00979 current = child;
00980 node_name = next_node_name(&savepath);
00981 }
00982
00983 return current;
00984 }
00985
00986
00987
00988
00989
00990
00991
00992
00993
00994
00995
00996
00997
00998 static int data_search_cmp_string(const struct ast_data_search *root, const char *name,
00999 char *value)
01000 {
01001 struct ast_data_search *child;
01002 enum data_search_comparison cmp_type;
01003 int ret;
01004
01005 child = data_search_get_node(root, name);
01006 if (!child) {
01007 return 0;
01008 }
01009
01010 ret = strcmp(value, child->value);
01011 cmp_type = child->cmp_type;
01012
01013 ao2_ref(child, -1);
01014
01015 return data_search_comparison_result(ret, cmp_type);
01016 }
01017
01018
01019
01020
01021
01022
01023
01024
01025
01026
01027
01028
01029
01030 static int data_search_cmp_ptr(const struct ast_data_search *root, const char *name,
01031 void *ptr)
01032 {
01033 struct ast_data_search *child;
01034 enum data_search_comparison cmp_type;
01035 void *node_ptr;
01036
01037 child = data_search_get_node(root, name);
01038 if (!child) {
01039 return 0;
01040 }
01041
01042 cmp_type = child->cmp_type;
01043
01044 if (sscanf(child->value, "%p", &node_ptr) <= 0) {
01045 return 1;
01046 }
01047
01048 ao2_ref(child, -1);
01049
01050 return data_search_comparison_result((node_ptr - ptr), cmp_type);
01051 }
01052
01053
01054
01055
01056
01057
01058
01059
01060
01061
01062
01063
01064
01065 static int data_search_cmp_ipaddr(const struct ast_data_search *root, const char *name,
01066 struct in_addr addr)
01067 {
01068 struct ast_data_search *child;
01069 enum data_search_comparison cmp_type;
01070 struct in_addr node_addr;
01071
01072 child = data_search_get_node(root, name);
01073 if (!child) {
01074 return 0;
01075 }
01076 cmp_type = child->cmp_type;
01077
01078 inet_aton(child->value, &node_addr);
01079
01080 ao2_ref(child, -1);
01081
01082 return data_search_comparison_result((node_addr.s_addr - addr.s_addr), cmp_type);
01083 }
01084
01085
01086
01087
01088
01089
01090
01091
01092
01093
01094
01095
01096
01097 static int data_search_cmp_bool(const struct ast_data_search *root, const char *name,
01098 unsigned int value)
01099 {
01100 struct ast_data_search *child;
01101 unsigned int node_value;
01102 enum data_search_comparison cmp_type;
01103
01104 child = data_search_get_node(root, name);
01105 if (!child) {
01106 return 0;
01107 }
01108
01109 node_value = abs(ast_true(child->value));
01110 cmp_type = child->cmp_type;
01111
01112 ao2_ref(child, -1);
01113
01114 return data_search_comparison_result(value - node_value, cmp_type);
01115 }
01116
01117
01118
01119
01120
01121
01122
01123
01124
01125
01126
01127
01128
01129 static int data_search_cmp_dbl(const struct ast_data_search *root, const char *name,
01130 double value)
01131 {
01132 struct ast_data_search *child;
01133 double node_value;
01134 enum data_search_comparison cmp_type;
01135
01136 child = data_search_get_node(root, name);
01137 if (!child) {
01138 return 0;
01139 }
01140
01141 node_value = strtod(child->value, NULL);
01142 cmp_type = child->cmp_type;
01143
01144 ao2_ref(child, -1);
01145
01146 return data_search_comparison_result(value - node_value, cmp_type);
01147 }
01148
01149
01150
01151
01152
01153
01154
01155
01156
01157
01158
01159
01160
01161 static int data_search_cmp_uint(const struct ast_data_search *root, const char *name,
01162 unsigned int value)
01163 {
01164 struct ast_data_search *child;
01165 unsigned int node_value;
01166 enum data_search_comparison cmp_type;
01167
01168 child = data_search_get_node(root, name);
01169 if (!child) {
01170 return 0;
01171 }
01172
01173 node_value = atoi(child->value);
01174 cmp_type = child->cmp_type;
01175
01176 ao2_ref(child, -1);
01177
01178 return data_search_comparison_result(value - node_value, cmp_type);
01179 }
01180
01181
01182
01183
01184
01185
01186
01187
01188
01189
01190
01191
01192
01193 static int data_search_cmp_int(const struct ast_data_search *root, const char *name,
01194 int value)
01195 {
01196 struct ast_data_search *child;
01197 int node_value;
01198 enum data_search_comparison cmp_type;
01199
01200 child = data_search_get_node(root, name);
01201 if (!child) {
01202 return 0;
01203 }
01204
01205 node_value = atoi(child->value);
01206 cmp_type = child->cmp_type;
01207
01208 ao2_ref(child, -1);
01209
01210 return data_search_comparison_result(value - node_value, cmp_type);
01211 }
01212
01213
01214
01215
01216
01217
01218
01219
01220
01221
01222
01223
01224
01225 static int data_search_cmp_char(const struct ast_data_search *root, const char *name,
01226 char value)
01227 {
01228 struct ast_data_search *child;
01229 char node_value;
01230 enum data_search_comparison cmp_type;
01231
01232 child = data_search_get_node(root, name);
01233 if (!child) {
01234 return 0;
01235 }
01236
01237 node_value = *(child->value);
01238 cmp_type = child->cmp_type;
01239
01240 ao2_ref(child, -1);
01241
01242 return data_search_comparison_result(value - node_value, cmp_type);
01243 }
01244
01245
01246
01247
01248
01249
01250
01251
01252 static inline int data_search_mapping_find(const struct ast_data_mapping_structure *map,
01253 size_t mapping_len,
01254 const char *member_name)
01255 {
01256 int i;
01257
01258 for (i = 0; i < mapping_len; i++) {
01259 if (!strcmp(map[i].name, member_name)) {
01260 return i;
01261 }
01262 }
01263
01264 return -1;
01265 }
01266
01267 int __ast_data_search_cmp_structure(const struct ast_data_search *search,
01268 const struct ast_data_mapping_structure *mapping, size_t mapping_len,
01269 void *structure, const char *structure_name)
01270 {
01271 struct ao2_iterator i;
01272 struct ast_data_search *node, *struct_children;
01273 int member, notmatch = 0;
01274
01275 if (!search) {
01276 return 0;
01277 }
01278
01279 struct_children = data_search_get_node(search, structure_name);
01280 if (!struct_children) {
01281 return 0;
01282 }
01283
01284 i = ao2_iterator_init(struct_children->children, 0);
01285 while ((node = ao2_iterator_next(&i))) {
01286 member = data_search_mapping_find(mapping, mapping_len, node->name);
01287 if (member < 0) {
01288
01289 ao2_ref(node, -1);
01290 ao2_ref(struct_children, -1);
01291 ao2_iterator_destroy(&i);
01292 return 0;
01293 }
01294
01295 notmatch = 0;
01296 switch (mapping[member].type) {
01297 case AST_DATA_PASSWORD:
01298 notmatch = data_search_cmp_string(struct_children,
01299 node->name,
01300 mapping[member].get.AST_DATA_PASSWORD(structure));
01301 break;
01302 case AST_DATA_TIMESTAMP:
01303 notmatch = data_search_cmp_uint(struct_children,
01304 node->name,
01305 mapping[member].get.AST_DATA_TIMESTAMP(structure));
01306 break;
01307 case AST_DATA_SECONDS:
01308 notmatch = data_search_cmp_uint(struct_children,
01309 node->name,
01310 mapping[member].get.AST_DATA_SECONDS(structure));
01311 break;
01312 case AST_DATA_MILLISECONDS:
01313 notmatch = data_search_cmp_uint(struct_children,
01314 node->name,
01315 mapping[member].get.AST_DATA_MILLISECONDS(structure));
01316 break;
01317 case AST_DATA_STRING:
01318 notmatch = data_search_cmp_string(struct_children,
01319 node->name,
01320 mapping[member].get.AST_DATA_STRING(structure));
01321 break;
01322 case AST_DATA_CHARACTER:
01323 notmatch = data_search_cmp_char(struct_children,
01324 node->name,
01325 mapping[member].get.AST_DATA_CHARACTER(structure));
01326 break;
01327 case AST_DATA_INTEGER:
01328 notmatch = data_search_cmp_int(struct_children,
01329 node->name,
01330 mapping[member].get.AST_DATA_INTEGER(structure));
01331 break;
01332 case AST_DATA_BOOLEAN:
01333 notmatch = data_search_cmp_bool(struct_children,
01334 node->name,
01335 mapping[member].get.AST_DATA_BOOLEAN(structure));
01336 break;
01337 case AST_DATA_UNSIGNED_INTEGER:
01338 notmatch = data_search_cmp_uint(struct_children,
01339 node->name,
01340 mapping[member].get.AST_DATA_UNSIGNED_INTEGER(structure));
01341 break;
01342 case AST_DATA_DOUBLE:
01343 notmatch = data_search_cmp_dbl(struct_children,
01344 node->name,
01345 mapping[member].get.AST_DATA_DOUBLE(structure));
01346 break;
01347 case AST_DATA_IPADDR:
01348 notmatch = data_search_cmp_ipaddr(struct_children,
01349 node->name,
01350 mapping[member].get.AST_DATA_IPADDR(structure));
01351 break;
01352 case AST_DATA_POINTER:
01353 notmatch = data_search_cmp_ptr(struct_children,
01354 node->name,
01355 mapping[member].get.AST_DATA_POINTER(structure));
01356 break;
01357 case AST_DATA_CONTAINER:
01358 break;
01359 }
01360
01361 ao2_ref(node, -1);
01362 }
01363 ao2_iterator_destroy(&i);
01364
01365 ao2_ref(struct_children, -1);
01366
01367 return notmatch;
01368 }
01369
01370
01371
01372
01373
01374 static void data_result_destructor(void *obj)
01375 {
01376 struct ast_data *root = obj;
01377
01378 switch (root->type) {
01379 case AST_DATA_PASSWORD:
01380 case AST_DATA_STRING:
01381 ast_free(root->payload.str);
01382 ao2_ref(root->children, -1);
01383 break;
01384 case AST_DATA_POINTER:
01385 case AST_DATA_CHARACTER:
01386 case AST_DATA_CONTAINER:
01387 case AST_DATA_INTEGER:
01388 case AST_DATA_TIMESTAMP:
01389 case AST_DATA_SECONDS:
01390 case AST_DATA_MILLISECONDS:
01391 case AST_DATA_UNSIGNED_INTEGER:
01392 case AST_DATA_DOUBLE:
01393 case AST_DATA_BOOLEAN:
01394 case AST_DATA_IPADDR:
01395 ao2_ref(root->children, -1);
01396 break;
01397 }
01398 }
01399
01400 static struct ast_data *data_result_create(const char *name)
01401 {
01402 struct ast_data *res;
01403 size_t namelen;
01404
01405 namelen = ast_strlen_zero(name) ? 1 : strlen(name) + 1;
01406
01407 res = ao2_alloc(sizeof(*res) + namelen, data_result_destructor);
01408 if (!res) {
01409 return NULL;
01410 }
01411
01412 strcpy(res->name, namelen ? name : "");
01413
01414
01415 res->children = ao2_container_alloc(NUM_DATA_RESULT_BUCKETS, data_result_hash,
01416 data_result_cmp);
01417 if (!res->children) {
01418 ao2_ref(res, -1);
01419 return NULL;
01420 }
01421
01422
01423 res->type = AST_DATA_CONTAINER;
01424
01425 return res;
01426 }
01427
01428
01429
01430
01431
01432
01433
01434
01435
01436 static struct ast_data *data_result_find_child(struct ast_data *root, const char *name)
01437 {
01438 struct ast_data *found, *find_node;
01439
01440 find_node = data_result_create(name);
01441 if (!find_node) {
01442 return NULL;
01443 }
01444
01445 found = ao2_find(root->children, find_node, OBJ_POINTER);
01446
01447
01448 ao2_ref(find_node, -1);
01449
01450 return found;
01451 }
01452
01453 int ast_data_search_match(const struct ast_data_search *search, struct ast_data *data)
01454 {
01455 struct ao2_iterator i, ii;
01456 struct ast_data_search *s, *s_child;
01457 struct ast_data *d_child;
01458 int notmatch = 1;
01459
01460 if (!search) {
01461 return 1;
01462 }
01463
01464 s_child = data_search_find(search->children, data->name);
01465 if (!s_child) {
01466
01467 ao2_ref(s_child, -1);
01468 return 1;
01469 }
01470
01471 i = ao2_iterator_init(s_child->children, 0);
01472 while ((s = ao2_iterator_next(&i))) {
01473 if (!ao2_container_count(s->children)) {
01474
01475 d_child = data_result_find_child(data, s->name);
01476 if (!d_child) {
01477 ao2_ref(s, -1);
01478 notmatch = 1;
01479 continue;
01480 }
01481
01482 switch (d_child->type) {
01483 case AST_DATA_PASSWORD:
01484 case AST_DATA_STRING:
01485 notmatch = data_search_cmp_string(s_child, d_child->name,
01486 d_child->payload.str);
01487 break;
01488 case AST_DATA_CHARACTER:
01489 notmatch = data_search_cmp_char(s_child, d_child->name,
01490 d_child->payload.character);
01491 break;
01492 case AST_DATA_INTEGER:
01493 notmatch = data_search_cmp_int(s_child, d_child->name,
01494 d_child->payload.sint);
01495 break;
01496 case AST_DATA_BOOLEAN:
01497 notmatch = data_search_cmp_bool(s_child, d_child->name,
01498 d_child->payload.boolean);
01499 break;
01500 case AST_DATA_UNSIGNED_INTEGER:
01501 notmatch = data_search_cmp_uint(s_child, d_child->name,
01502 d_child->payload.uint);
01503 break;
01504 case AST_DATA_TIMESTAMP:
01505 case AST_DATA_SECONDS:
01506 case AST_DATA_MILLISECONDS:
01507 case AST_DATA_DOUBLE:
01508 notmatch = data_search_cmp_uint(s_child, d_child->name,
01509 d_child->payload.dbl);
01510 break;
01511 case AST_DATA_IPADDR:
01512 notmatch = data_search_cmp_ipaddr(s_child, d_child->name,
01513 d_child->payload.ipaddr);
01514 break;
01515 case AST_DATA_POINTER:
01516 notmatch = data_search_cmp_ptr(s_child, d_child->name,
01517 d_child->payload.ptr);
01518 break;
01519 case AST_DATA_CONTAINER:
01520 break;
01521 }
01522 ao2_ref(d_child, -1);
01523 } else {
01524 ii = ao2_iterator_init(data->children, 0);
01525 while ((d_child = ao2_iterator_next(&ii))) {
01526 if (strcmp(d_child->name, s->name)) {
01527 ao2_ref(d_child, -1);
01528 continue;
01529 }
01530 if (!(notmatch = !ast_data_search_match(s_child, d_child))) {
01531
01532 ao2_ref(d_child, -1);
01533 break;
01534 }
01535 ao2_ref(d_child, -1);
01536 }
01537 ao2_iterator_destroy(&ii);
01538 }
01539 ao2_ref(s, -1);
01540 if (notmatch) {
01541
01542 break;
01543 }
01544 }
01545 ao2_iterator_destroy(&i);
01546
01547 ao2_ref(s_child, -1);
01548
01549 return !notmatch;
01550 }
01551
01552
01553
01554
01555
01556
01557
01558
01559
01560 static struct ast_data *data_result_get_node(struct ast_data *node,
01561 const char *path)
01562 {
01563 char *savepath, *node_name;
01564 struct ast_data *child, *current = node;
01565
01566 savepath = ast_strdupa(path);
01567 node_name = next_node_name(&savepath);
01568
01569 while (node_name) {
01570 child = data_result_find_child(current, node_name);
01571 if (current != node) {
01572 ao2_ref(current, -1);
01573 }
01574 if (!child) {
01575 return NULL;
01576 }
01577 current = child;
01578 node_name = next_node_name(&savepath);
01579 }
01580
01581
01582 if (current != node) {
01583 ao2_ref(current, -1);
01584 }
01585
01586 return current;
01587 }
01588
01589
01590
01591
01592
01593
01594
01595 static void data_result_add_child(struct ast_data *root, struct ast_data *child)
01596 {
01597 ao2_link(root->children, child);
01598 }
01599
01600
01601
01602
01603
01604 static int data_filter_hash(const void *obj, const int flags)
01605 {
01606 const struct data_filter *node = obj;
01607 return ast_str_hash(node->name);
01608 }
01609
01610
01611
01612
01613
01614 static int data_filter_cmp(void *obj, void *arg, int flags)
01615 {
01616 struct data_filter *node1 = obj, *node2 = arg;
01617 return strcasecmp(node1->name, node2->name) ? 0 : CMP_MATCH;
01618 }
01619
01620
01621
01622
01623
01624
01625 static void data_filter_destructor(void *obj)
01626 {
01627 struct data_filter *filter = obj, *globres;
01628
01629 AST_LIST_TRAVERSE(&(filter->glob_list), globres, list) {
01630 ao2_ref(globres, -1);
01631 }
01632
01633 ao2_ref(filter->children, -1);
01634 }
01635
01636
01637
01638
01639
01640
01641
01642 static struct data_filter *data_filter_alloc(const char *name)
01643 {
01644 char *globname, *token;
01645 struct data_filter *res, *globfilter;
01646 size_t name_len = strlen(name) + 1;
01647
01648 res = ao2_alloc(sizeof(*res) + name_len, data_filter_destructor);
01649 if (!res) {
01650 return NULL;
01651 }
01652
01653 res->children = ao2_container_alloc(NUM_DATA_FILTER_BUCKETS, data_filter_hash,
01654 data_filter_cmp);
01655
01656 if (!res) {
01657 ao2_ref(res, -1);
01658 return NULL;
01659 }
01660
01661 strcpy(res->name, name);
01662
01663 if (strchr(res->name, '*')) {
01664 globname = ast_strdupa(res->name);
01665
01666 while ((token = strsep(&globname, "*"))) {
01667 globfilter = data_filter_alloc(token);
01668 AST_LIST_INSERT_TAIL(&(res->glob_list), globfilter, list);
01669 }
01670 }
01671
01672 return res;
01673 }
01674
01675
01676
01677
01678
01679
01680 static void data_filter_release(struct data_filter *filter)
01681 {
01682 ao2_ref(filter, -1);
01683 }
01684
01685
01686
01687
01688
01689
01690
01691
01692
01693
01694 static struct data_filter *data_filter_find(struct ao2_container *parent,
01695 const char *name)
01696 {
01697 int i, olend, orend, globfound;
01698 size_t name_len = strlen(name), glob_len;
01699 struct ao2_iterator iter;
01700 struct data_filter *find_node, *found, *globres;
01701
01702 find_node = data_filter_alloc(name);
01703 if (!find_node) {
01704 return NULL;
01705 }
01706
01707 found = ao2_find(parent, find_node, OBJ_POINTER);
01708
01709
01710 ao2_ref(find_node, -1);
01711
01712 if (found) {
01713 return found;
01714 }
01715
01716 iter = ao2_iterator_init(parent, 0);
01717 while ((found = ao2_iterator_next(&iter))) {
01718 if (!AST_LIST_EMPTY(&(found->glob_list))) {
01719 i = 0;
01720 globfound = 1;
01721
01722 olend = ast_strlen_zero(AST_LIST_FIRST(&(found->glob_list))->name);
01723 orend = ast_strlen_zero(AST_LIST_LAST(&(found->glob_list))->name);
01724
01725 AST_LIST_TRAVERSE(&(found->glob_list), globres, list) {
01726 if (!*globres->name) {
01727 continue;
01728 }
01729
01730 glob_len = strlen(globres->name);
01731
01732 if (!i && !olend) {
01733 if (strncasecmp(name, globres->name, glob_len)) {
01734 globfound = 0;
01735 break;
01736 }
01737
01738 i += glob_len;
01739 continue;
01740 }
01741
01742 for (globfound = 0; name_len - i >= glob_len; ++i) {
01743 if (!strncasecmp(name + i, globres->name, glob_len)) {
01744 globfound = 1;
01745 i += glob_len;
01746 break;
01747 }
01748 }
01749
01750 if (!globfound) {
01751 break;
01752 }
01753 }
01754
01755 if (globfound && (i == name_len || orend)) {
01756 ao2_iterator_destroy(&iter);
01757 return found;
01758 }
01759 }
01760
01761 ao2_ref(found, -1);
01762 }
01763 ao2_iterator_destroy(&iter);
01764
01765 return NULL;
01766 }
01767
01768
01769
01770
01771
01772
01773
01774
01775 static struct data_filter *data_filter_add_child(struct ao2_container *root,
01776 char *name)
01777 {
01778 struct data_filter *node;
01779
01780 node = data_filter_find(root, name);
01781 if (node) {
01782 return node;
01783 }
01784
01785 node = data_filter_alloc(name);
01786 if (!node) {
01787 return NULL;
01788 }
01789
01790 ao2_link(root, node);
01791
01792 return node;
01793 }
01794
01795
01796
01797
01798
01799
01800
01801
01802
01803 static int data_filter_add_nodes(struct ao2_container *root, char *path)
01804 {
01805 struct data_filter *node;
01806 char *savepath, *saveptr, *token, *node_name;
01807 int ret = 0;
01808
01809 if (!path) {
01810 return 0;
01811 }
01812
01813 savepath = ast_strdupa(path);
01814
01815 node_name = next_node_name(&savepath);
01816
01817 if (!node_name) {
01818 return 0;
01819 }
01820
01821 for (token = strtok_r(node_name, "|", &saveptr);
01822 token; token = strtok_r(NULL, "|", &saveptr)) {
01823 node = data_filter_add_child(root, token);
01824 if (!node) {
01825 continue;
01826 }
01827 data_filter_add_nodes(node->children, savepath);
01828 ret = 1;
01829 ao2_ref(node, -1);
01830 }
01831
01832 return ret;
01833 }
01834
01835
01836
01837
01838
01839
01840 static struct data_filter *data_filter_generate(const char *constfilter)
01841 {
01842 struct data_filter *filter = NULL;
01843 char *strfilter, *token, *saveptr;
01844 int node_added = 0;
01845
01846 if (!constfilter) {
01847 return NULL;
01848 }
01849
01850 strfilter = ast_strdupa(constfilter);
01851
01852 filter = data_filter_alloc("/");
01853 if (!filter) {
01854 return NULL;
01855 }
01856
01857 for (token = strtok_r(strfilter, ",", &saveptr); token;
01858 token = strtok_r(NULL, ",", &saveptr)) {
01859 node_added = data_filter_add_nodes(filter->children, token);
01860 }
01861
01862 if (!node_added) {
01863 ao2_ref(filter, -1);
01864 return NULL;
01865 }
01866
01867 return filter;
01868 }
01869
01870
01871
01872
01873
01874
01875
01876
01877
01878
01879 static struct ast_data *data_result_generate_node(const struct ast_data_query *query,
01880 const struct data_provider *root_provider,
01881 const char *parent_node_name,
01882 const struct ast_data_search *search,
01883 const struct data_filter *filter)
01884 {
01885 struct ast_data *generated, *node;
01886 struct ao2_iterator i;
01887 struct data_provider *provider;
01888 struct ast_data_search *search_child = NULL;
01889 struct data_filter *filter_child;
01890
01891 node = data_result_create(parent_node_name);
01892 if (!node) {
01893 ast_log(LOG_ERROR, "Unable to allocate '%s' node\n", parent_node_name);
01894 return NULL;
01895 }
01896
01897 if (root_provider->module) {
01898 ast_module_ref(root_provider->module);
01899 }
01900
01901
01902 if (root_provider->handler && root_provider->handler->get) {
01903 node->filter = filter;
01904 root_provider->handler->get(search, node);
01905 if (root_provider->module) {
01906 ast_module_unref(root_provider->module);
01907 }
01908 return node;
01909 }
01910
01911 if (root_provider->module) {
01912 ast_module_unref(root_provider->module);
01913 }
01914
01915
01916 i = ao2_iterator_init(root_provider->children, 0);
01917 while ((provider = ao2_iterator_next(&i))) {
01918 filter_child = NULL;
01919 generated = NULL;
01920
01921
01922 if (search) {
01923 search_child = data_search_find(search->children, provider->name);
01924 }
01925
01926 if (filter) {
01927 filter_child = data_filter_find(filter->children, provider->name);
01928 }
01929
01930 if (!filter || filter_child) {
01931
01932
01933 generated = data_result_generate_node(query, provider,
01934 provider->name,
01935 search_child, filter_child);
01936 }
01937
01938
01939 if (search_child) {
01940 ao2_ref(search_child, -1);
01941 }
01942
01943
01944 if (filter_child) {
01945 ao2_ref(filter_child, -1);
01946 }
01947
01948 if (generated) {
01949 data_result_add_child(node, generated);
01950 ao2_ref(generated, -1);
01951 }
01952
01953 ao2_ref(provider, -1);
01954 }
01955 ao2_iterator_destroy(&i);
01956
01957 return node;
01958 }
01959
01960
01961
01962
01963
01964
01965
01966
01967
01968 static struct ast_data *data_result_generate(const struct ast_data_query *query,
01969 const char *search_path)
01970 {
01971 char *node_name, *tmp_path;
01972 struct data_provider *provider_child, *tmp_provider_child;
01973 struct ast_data *result, *result_filtered;
01974 struct ast_data_search *search = NULL, *search_child = NULL;
01975 struct data_filter *filter = NULL, *filter_child = NULL;
01976
01977 if (!search_path) {
01978
01979 return NULL;
01980 }
01981
01982 tmp_path = ast_strdupa(search_path);
01983
01984
01985 node_name = next_node_name(&tmp_path);
01986 if (!node_name) {
01987 return NULL;
01988 }
01989 provider_child = data_provider_find(root_data.container, node_name, NULL);
01990
01991
01992 while (provider_child) {
01993 node_name = next_node_name(&tmp_path);
01994 if (!node_name) {
01995 break;
01996 }
01997
01998 tmp_provider_child = data_provider_find(provider_child->children,
01999 node_name, NULL);
02000
02001
02002 ao2_ref(provider_child, -1);
02003
02004 provider_child = tmp_provider_child;
02005 }
02006
02007 if (!provider_child) {
02008 ast_log(LOG_ERROR, "Invalid path '%s', '%s' not found.\n",
02009 tmp_path, node_name);
02010 return NULL;
02011 }
02012
02013
02014 if (query->search) {
02015 search = data_search_generate(query->search);
02016 if (search) {
02017 search_child = data_search_find(search->children,
02018 provider_child->name);
02019 }
02020 }
02021
02022
02023 if (query->filter) {
02024 filter = data_filter_generate(query->filter);
02025 if (filter) {
02026 filter_child = data_filter_find(filter->children,
02027 provider_child->name);
02028 }
02029 }
02030
02031 result = data_result_generate_node(query, provider_child, provider_child->name,
02032 search_child, filter_child);
02033
02034
02035 ao2_ref(provider_child, -1);
02036
02037
02038 if (search_child) {
02039 ao2_ref(search_child, -1);
02040 }
02041
02042 if (filter_child) {
02043 ao2_ref(filter_child, -1);
02044 }
02045
02046 if (search) {
02047 data_search_release(search);
02048 }
02049
02050 result_filtered = result;
02051
02052
02053 if (filter) {
02054 data_filter_release(filter);
02055 }
02056
02057 return result_filtered;
02058 }
02059
02060 struct ast_data *ast_data_get(const struct ast_data_query *query)
02061 {
02062 struct ast_data *res;
02063
02064
02065 if (!data_structure_compatible(query->version, latest_query_compatible_version,
02066 current_query_version)) {
02067 return NULL;
02068 }
02069
02070 data_read_lock();
02071 res = data_result_generate(query, query->path);
02072 data_unlock();
02073
02074 if (!res) {
02075 ast_log(LOG_ERROR, "Unable to get data from %s\n", query->path);
02076 return NULL;
02077 }
02078
02079 return res;
02080 }
02081
02082 #ifdef HAVE_LIBXML2
02083
02084
02085
02086
02087
02088
02089 static void data_get_xml_add_child(struct ast_data *parent_data,
02090 struct ast_xml_node *parent_xml)
02091 {
02092 struct ao2_iterator i;
02093 struct ast_data *node;
02094 struct ast_xml_node *child_xml;
02095 char node_content[256];
02096
02097 i = ao2_iterator_init(parent_data->children, 0);
02098 while ((node = ao2_iterator_next(&i))) {
02099 child_xml = ast_xml_new_node(node->name);
02100 if (!child_xml) {
02101 ao2_ref(node, -1);
02102 continue;
02103 }
02104
02105 switch (node->type) {
02106 case AST_DATA_CONTAINER:
02107 data_get_xml_add_child(node, child_xml);
02108 break;
02109 case AST_DATA_PASSWORD:
02110 ast_xml_set_text(child_xml, node->payload.str);
02111 break;
02112 case AST_DATA_TIMESTAMP:
02113 snprintf(node_content, sizeof(node_content), "%d",
02114 node->payload.uint);
02115 ast_xml_set_text(child_xml, node_content);
02116 break;
02117 case AST_DATA_SECONDS:
02118 snprintf(node_content, sizeof(node_content), "%d",
02119 node->payload.uint);
02120 ast_xml_set_text(child_xml, node_content);
02121 break;
02122 case AST_DATA_MILLISECONDS:
02123 snprintf(node_content, sizeof(node_content), "%d",
02124 node->payload.uint);
02125 ast_xml_set_text(child_xml, node_content);
02126 break;
02127 case AST_DATA_STRING:
02128 ast_xml_set_text(child_xml, node->payload.str);
02129 break;
02130 case AST_DATA_CHARACTER:
02131 snprintf(node_content, sizeof(node_content), "%c",
02132 node->payload.character);
02133 ast_xml_set_text(child_xml, node_content);
02134 break;
02135 case AST_DATA_INTEGER:
02136 snprintf(node_content, sizeof(node_content), "%d",
02137 node->payload.sint);
02138 ast_xml_set_text(child_xml, node_content);
02139 break;
02140 case AST_DATA_UNSIGNED_INTEGER:
02141 snprintf(node_content, sizeof(node_content), "%u",
02142 node->payload.uint);
02143 ast_xml_set_text(child_xml, node_content);
02144 break;
02145 case AST_DATA_DOUBLE:
02146 snprintf(node_content, sizeof(node_content), "%f",
02147 node->payload.dbl);
02148 ast_xml_set_text(child_xml, node_content);
02149 break;
02150 case AST_DATA_BOOLEAN:
02151 if (node->payload.boolean) {
02152 ast_xml_set_text(child_xml, "true");
02153 } else {
02154 ast_xml_set_text(child_xml, "false");
02155 }
02156 break;
02157 case AST_DATA_POINTER:
02158 snprintf(node_content, sizeof(node_content), "%p",
02159 node->payload.ptr);
02160 ast_xml_set_text(child_xml, node_content);
02161 break;
02162 case AST_DATA_IPADDR:
02163 snprintf(node_content, sizeof(node_content), "%s",
02164 ast_inet_ntoa(node->payload.ipaddr));
02165 ast_xml_set_text(child_xml, node_content);
02166 break;
02167 }
02168 ast_xml_add_child(parent_xml, child_xml);
02169
02170 ao2_ref(node, -1);
02171 }
02172 ao2_iterator_destroy(&i);
02173
02174 }
02175
02176 struct ast_xml_doc *ast_data_get_xml(const struct ast_data_query *query)
02177 {
02178 struct ast_xml_doc *doc;
02179 struct ast_xml_node *root;
02180 struct ast_data *res;
02181
02182 res = ast_data_get(query);
02183 if (!res) {
02184 return NULL;
02185 }
02186
02187 doc = ast_xml_new();
02188 if (!doc) {
02189 return NULL;
02190 }
02191
02192 root = ast_xml_new_node(res->name);
02193 if (!root) {
02194 ast_xml_close(doc);
02195 }
02196
02197 ast_xml_set_root(doc, root);
02198
02199 data_get_xml_add_child(res, root);
02200
02201 ast_data_free(res);
02202
02203 return doc;
02204 }
02205 #endif
02206
02207 enum ast_data_type ast_data_retrieve_type(struct ast_data *node, const char *path)
02208 {
02209 struct ast_data *internal;
02210
02211 internal = data_result_get_node(node, path);
02212 if (!internal) {
02213 return -1;
02214 }
02215
02216 return internal->type;
02217 }
02218
02219 char *ast_data_retrieve_name(struct ast_data *node)
02220 {
02221 return node->name;
02222 }
02223
02224
02225
02226
02227
02228
02229
02230
02231
02232
02233
02234 static struct ast_data *__ast_data_add(struct ast_data *root, const char *name,
02235 enum ast_data_type type, void *ptr)
02236 {
02237 struct ast_data *node;
02238 struct data_filter *filter, *filter_child = NULL;
02239
02240 if (!root || !root->children) {
02241
02242 return NULL;
02243 }
02244
02245
02246 if (root->filter) {
02247 filter = data_filter_find(root->filter->children, name);
02248 if (!filter) {
02249 return NULL;
02250 }
02251 ao2_ref(filter, -1);
02252 }
02253
02254 node = data_result_create(name);
02255 if (!node) {
02256 return NULL;
02257 }
02258
02259 node->type = type;
02260
02261 switch (type) {
02262 case AST_DATA_BOOLEAN:
02263 node->payload.boolean = *(unsigned int *) ptr;
02264 break;
02265 case AST_DATA_INTEGER:
02266 node->payload.sint = *(int *) ptr;
02267 break;
02268 case AST_DATA_TIMESTAMP:
02269 case AST_DATA_SECONDS:
02270 case AST_DATA_MILLISECONDS:
02271 case AST_DATA_UNSIGNED_INTEGER:
02272 node->payload.uint = *(unsigned int *) ptr;
02273 break;
02274 case AST_DATA_DOUBLE:
02275 node->payload.dbl = *(double *) ptr;
02276 break;
02277 case AST_DATA_PASSWORD:
02278 case AST_DATA_STRING:
02279 node->payload.str = (char *) ptr;
02280 break;
02281 case AST_DATA_CHARACTER:
02282 node->payload.character = *(char *) ptr;
02283 break;
02284 case AST_DATA_POINTER:
02285 node->payload.ptr = ptr;
02286 break;
02287 case AST_DATA_IPADDR:
02288 node->payload.ipaddr = *(struct in_addr *) ptr;
02289 break;
02290 case AST_DATA_CONTAINER:
02291 if (root->filter) {
02292 filter_child = data_filter_find(root->filter->children, name);
02293 if (filter_child) {
02294
02295 ao2_ref(filter_child, -1);
02296 }
02297 }
02298 node->filter = filter_child;
02299 break;
02300 default:
02301 break;
02302 }
02303
02304 data_result_add_child(root, node);
02305
02306 ao2_ref(node, -1);
02307
02308 return node;
02309 }
02310
02311 struct ast_data *ast_data_add_node(struct ast_data *root, const char *name)
02312 {
02313 return __ast_data_add(root, name, AST_DATA_CONTAINER, NULL);
02314 }
02315
02316 struct ast_data *ast_data_add_int(struct ast_data *root, const char *name, int value)
02317 {
02318 return __ast_data_add(root, name, AST_DATA_INTEGER, &value);
02319 }
02320
02321 struct ast_data *ast_data_add_char(struct ast_data *root, const char *name, char value)
02322 {
02323 return __ast_data_add(root, name, AST_DATA_CHARACTER, &value);
02324 }
02325
02326 struct ast_data *ast_data_add_uint(struct ast_data *root, const char *name,
02327 unsigned int value)
02328 {
02329 return __ast_data_add(root, name, AST_DATA_UNSIGNED_INTEGER, &value);
02330 }
02331
02332 struct ast_data *ast_data_add_dbl(struct ast_data *root, const char *childname,
02333 double dbl)
02334 {
02335 return __ast_data_add(root, childname, AST_DATA_DOUBLE, &dbl);
02336 }
02337
02338 struct ast_data *ast_data_add_bool(struct ast_data *root, const char *childname,
02339 unsigned int boolean)
02340 {
02341 return __ast_data_add(root, childname, AST_DATA_BOOLEAN, &boolean);
02342 }
02343
02344 struct ast_data *ast_data_add_ipaddr(struct ast_data *root, const char *childname,
02345 struct in_addr addr)
02346 {
02347 return __ast_data_add(root, childname, AST_DATA_IPADDR, &addr);
02348 }
02349
02350 struct ast_data *ast_data_add_ptr(struct ast_data *root, const char *childname,
02351 void *ptr)
02352 {
02353 return __ast_data_add(root, childname, AST_DATA_POINTER, ptr);
02354 }
02355
02356 struct ast_data *ast_data_add_timestamp(struct ast_data *root, const char *childname,
02357 unsigned int timestamp)
02358 {
02359 return __ast_data_add(root, childname, AST_DATA_TIMESTAMP, ×tamp);
02360 }
02361
02362 struct ast_data *ast_data_add_seconds(struct ast_data *root, const char *childname,
02363 unsigned int seconds)
02364 {
02365 return __ast_data_add(root, childname, AST_DATA_SECONDS, &seconds);
02366 }
02367
02368 struct ast_data *ast_data_add_milliseconds(struct ast_data *root, const char *childname,
02369 unsigned int milliseconds)
02370 {
02371 return __ast_data_add(root, childname, AST_DATA_MILLISECONDS, &milliseconds);
02372 }
02373
02374 struct ast_data *ast_data_add_password(struct ast_data *root, const char *childname,
02375 const char *value)
02376 {
02377 char *name;
02378 size_t namelen = 1 + (ast_strlen_zero(value) ? 0 : strlen(value));
02379 struct ast_data *res;
02380
02381 if (!(name = ast_malloc(namelen))) {
02382 return NULL;
02383 }
02384
02385 strcpy(name, (ast_strlen_zero(value) ? "" : value));
02386
02387 res = __ast_data_add(root, childname, AST_DATA_PASSWORD, name);
02388 if (!res) {
02389 ast_free(name);
02390 }
02391
02392 return res;
02393 }
02394
02395 struct ast_data *ast_data_add_str(struct ast_data *root, const char *childname,
02396 const char *value)
02397 {
02398 char *name;
02399 size_t namelen = 1 + (ast_strlen_zero(value) ? 0 : strlen(value));
02400 struct ast_data *res;
02401
02402 if (!(name = ast_malloc(namelen))) {
02403 return NULL;
02404 }
02405
02406 strcpy(name, (ast_strlen_zero(value) ? "" : value));
02407
02408 res = __ast_data_add(root, childname, AST_DATA_STRING, name);
02409 if (!res) {
02410 ast_free(name);
02411 }
02412
02413 return res;
02414 }
02415
02416 int __ast_data_add_structure(struct ast_data *root,
02417 const struct ast_data_mapping_structure *mapping, size_t mapping_len,
02418 void *structure)
02419 {
02420 int i;
02421
02422 for (i = 0; i < mapping_len; i++) {
02423 switch (mapping[i].type) {
02424 case AST_DATA_INTEGER:
02425 ast_data_add_int(root, mapping[i].name,
02426 mapping[i].get.AST_DATA_INTEGER(structure));
02427 break;
02428 case AST_DATA_UNSIGNED_INTEGER:
02429 ast_data_add_uint(root, mapping[i].name,
02430 mapping[i].get.AST_DATA_UNSIGNED_INTEGER(structure));
02431 break;
02432 case AST_DATA_DOUBLE:
02433 ast_data_add_dbl(root, mapping[i].name,
02434 mapping[i].get.AST_DATA_DOUBLE(structure));
02435 break;
02436 case AST_DATA_BOOLEAN:
02437 ast_data_add_bool(root, mapping[i].name,
02438 mapping[i].get.AST_DATA_BOOLEAN(structure));
02439 break;
02440 case AST_DATA_PASSWORD:
02441 ast_data_add_password(root, mapping[i].name,
02442 mapping[i].get.AST_DATA_PASSWORD(structure));
02443 break;
02444 case AST_DATA_TIMESTAMP:
02445 ast_data_add_timestamp(root, mapping[i].name,
02446 mapping[i].get.AST_DATA_TIMESTAMP(structure));
02447 break;
02448 case AST_DATA_SECONDS:
02449 ast_data_add_seconds(root, mapping[i].name,
02450 mapping[i].get.AST_DATA_SECONDS(structure));
02451 break;
02452 case AST_DATA_MILLISECONDS:
02453 ast_data_add_milliseconds(root, mapping[i].name,
02454 mapping[i].get.AST_DATA_MILLISECONDS(structure));
02455 break;
02456 case AST_DATA_STRING:
02457 ast_data_add_str(root, mapping[i].name,
02458 mapping[i].get.AST_DATA_STRING(structure));
02459 break;
02460 case AST_DATA_CHARACTER:
02461 ast_data_add_char(root, mapping[i].name,
02462 mapping[i].get.AST_DATA_CHARACTER(structure));
02463 break;
02464 case AST_DATA_CONTAINER:
02465 break;
02466 case AST_DATA_IPADDR:
02467 ast_data_add_ipaddr(root, mapping[i].name,
02468 mapping[i].get.AST_DATA_IPADDR(structure));
02469 break;
02470 case AST_DATA_POINTER:
02471 ast_data_add_ptr(root, mapping[i].name,
02472 mapping[i].get.AST_DATA_POINTER(structure));
02473 break;
02474 }
02475 }
02476
02477 return 0;
02478 }
02479
02480 void ast_data_remove_node(struct ast_data *root, struct ast_data *child)
02481 {
02482 ao2_unlink(root->children, child);
02483 }
02484
02485 void ast_data_free(struct ast_data *root)
02486 {
02487
02488 ao2_ref(root, -1);
02489 }
02490
02491 struct ast_data_iterator *ast_data_iterator_init(struct ast_data *tree,
02492 const char *elements)
02493 {
02494 struct ast_data_iterator *iterator;
02495 struct ao2_iterator i;
02496 struct ast_data *internal = tree;
02497 char *path, *ptr = NULL;
02498
02499
02500
02501 if (elements) {
02502 path = ast_strdupa(elements);
02503
02504 ptr = strrchr(path, '/');
02505 if (ptr) {
02506 *ptr = '\0';
02507 internal = data_result_get_node(tree, path);
02508 if (!internal) {
02509 return NULL;
02510 }
02511 }
02512 }
02513
02514 iterator = ast_calloc(1, sizeof(*iterator));
02515 if (!iterator) {
02516 return NULL;
02517 }
02518
02519 i = ao2_iterator_init(internal->children, 0);
02520
02521 iterator->pattern = (ptr ? strrchr(elements, '/') + 1 : elements);
02522
02523
02524 if (!regcomp(&(iterator->regex_pattern), iterator->pattern,
02525 REG_EXTENDED | REG_NOSUB | REG_ICASE)) {
02526 iterator->is_pattern = 1;
02527 }
02528
02529 iterator->internal_iterator = i;
02530
02531 return iterator;
02532 }
02533
02534 void ast_data_iterator_end(struct ast_data_iterator *iterator)
02535 {
02536
02537 if (iterator->last) {
02538 ao2_ref(iterator->last, -1);
02539 }
02540
02541
02542 if (iterator->is_pattern) {
02543 regfree(&(iterator->regex_pattern));
02544 }
02545
02546 ao2_iterator_destroy(&(iterator->internal_iterator));
02547
02548 ast_free(iterator);
02549 iterator = NULL;
02550 }
02551
02552 struct ast_data *ast_data_iterator_next(struct ast_data_iterator *iterator)
02553 {
02554 struct ast_data *res;
02555
02556 if (iterator->last) {
02557
02558 ao2_ref(iterator->last, -1);
02559 }
02560
02561 while ((res = ao2_iterator_next(&iterator->internal_iterator))) {
02562
02563
02564 if (!iterator->pattern) {
02565 break;
02566 }
02567
02568
02569
02570 if (iterator->is_pattern && !regexec(&(iterator->regex_pattern),
02571 res->name, 0, NULL, 0)) {
02572 break;
02573 }
02574
02575
02576
02577 if (!iterator->is_pattern && (iterator->pattern &&
02578 !strcasecmp(res->name, iterator->pattern))) {
02579 break;
02580 }
02581
02582 ao2_ref(res, -1);
02583 }
02584
02585 iterator->last = res;
02586
02587 return res;
02588 }
02589
02590 int ast_data_retrieve(struct ast_data *tree, const char *path,
02591 struct ast_data_retrieve *content)
02592 {
02593 struct ast_data *node;
02594
02595 if (!content) {
02596 return -1;
02597 }
02598
02599 node = data_result_get_node(tree, path);
02600 if (!node) {
02601 ast_log(LOG_ERROR, "Invalid internal node %s\n", path);
02602 return -1;
02603 }
02604
02605 content->type = node->type;
02606 switch (node->type) {
02607 case AST_DATA_STRING:
02608 content->value.AST_DATA_STRING = node->payload.str;
02609 break;
02610 case AST_DATA_PASSWORD:
02611 content->value.AST_DATA_PASSWORD = node->payload.str;
02612 break;
02613 case AST_DATA_TIMESTAMP:
02614 content->value.AST_DATA_TIMESTAMP = node->payload.uint;
02615 break;
02616 case AST_DATA_SECONDS:
02617 content->value.AST_DATA_SECONDS = node->payload.uint;
02618 break;
02619 case AST_DATA_MILLISECONDS:
02620 content->value.AST_DATA_MILLISECONDS = node->payload.uint;
02621 break;
02622 case AST_DATA_CHARACTER:
02623 content->value.AST_DATA_CHARACTER = node->payload.character;
02624 break;
02625 case AST_DATA_INTEGER:
02626 content->value.AST_DATA_INTEGER = node->payload.sint;
02627 break;
02628 case AST_DATA_UNSIGNED_INTEGER:
02629 content->value.AST_DATA_UNSIGNED_INTEGER = node->payload.uint;
02630 break;
02631 case AST_DATA_BOOLEAN:
02632 content->value.AST_DATA_BOOLEAN = node->payload.boolean;
02633 break;
02634 case AST_DATA_IPADDR:
02635 content->value.AST_DATA_IPADDR = node->payload.ipaddr;
02636 break;
02637 case AST_DATA_DOUBLE:
02638 content->value.AST_DATA_DOUBLE = node->payload.dbl;
02639 break;
02640 case AST_DATA_CONTAINER:
02641 break;
02642 case AST_DATA_POINTER:
02643 content->value.AST_DATA_POINTER = node->payload.ptr;
02644 break;
02645 }
02646
02647 return 0;
02648 }
02649
02650
02651
02652
02653
02654 static const struct {
02655 enum ast_data_type type;
02656 int color;
02657 } data_result_color[] = {
02658 { AST_DATA_STRING, COLOR_BLUE },
02659 { AST_DATA_PASSWORD, COLOR_BRBLUE },
02660 { AST_DATA_TIMESTAMP, COLOR_CYAN },
02661 { AST_DATA_SECONDS, COLOR_MAGENTA },
02662 { AST_DATA_MILLISECONDS, COLOR_BRMAGENTA },
02663 { AST_DATA_CHARACTER, COLOR_GRAY },
02664 { AST_DATA_INTEGER, COLOR_RED },
02665 { AST_DATA_UNSIGNED_INTEGER, COLOR_RED },
02666 { AST_DATA_DOUBLE, COLOR_RED },
02667 { AST_DATA_BOOLEAN, COLOR_BRRED },
02668 { AST_DATA_CONTAINER, COLOR_GREEN },
02669 { AST_DATA_IPADDR, COLOR_BROWN },
02670 { AST_DATA_POINTER, COLOR_YELLOW },
02671 };
02672
02673
02674
02675
02676
02677
02678
02679 static int data_result_get_color(enum ast_data_type type)
02680 {
02681 int i;
02682 for (i = 0; i < ARRAY_LEN(data_result_color); i++) {
02683 if (data_result_color[i].type == type) {
02684 return data_result_color[i].color;
02685 }
02686 }
02687
02688 return COLOR_BLUE;
02689 }
02690
02691
02692
02693
02694
02695
02696
02697
02698 static void data_result_print_cli_node(int fd, const struct ast_data *node, uint32_t depth)
02699 {
02700 int i;
02701 struct ast_str *tabs, *output;
02702
02703 tabs = ast_str_create(depth * 10 + 1);
02704 if (!tabs) {
02705 return;
02706 }
02707 ast_str_reset(tabs);
02708 for (i = 0; i < depth; i++) {
02709 ast_str_append(&tabs, 0, " ");
02710 }
02711
02712 output = ast_str_create(20);
02713 if (!output) {
02714 ast_free(tabs);
02715 return;
02716 }
02717
02718 ast_str_reset(output);
02719 ast_term_color_code(&output, data_result_get_color(node->type), 0);
02720
02721 switch (node->type) {
02722 case AST_DATA_POINTER:
02723 ast_str_append(&output, 0, "%s%s: %p\n", ast_str_buffer(tabs),
02724 node->name, node->payload.ptr);
02725 break;
02726 case AST_DATA_PASSWORD:
02727 ast_str_append(&output, 0, "%s%s: \"%s\"\n",
02728 ast_str_buffer(tabs),
02729 node->name,
02730 node->payload.str);
02731 break;
02732 case AST_DATA_STRING:
02733 ast_str_append(&output, 0, "%s%s: \"%s\"\n",
02734 ast_str_buffer(tabs),
02735 node->name,
02736 node->payload.str);
02737 break;
02738 case AST_DATA_CHARACTER:
02739 ast_str_append(&output, 0, "%s%s: \'%c\'\n",
02740 ast_str_buffer(tabs),
02741 node->name,
02742 node->payload.character);
02743 break;
02744 case AST_DATA_CONTAINER:
02745 ast_str_append(&output, 0, "%s%s\n", ast_str_buffer(tabs),
02746 node->name);
02747 break;
02748 case AST_DATA_TIMESTAMP:
02749 ast_str_append(&output, 0, "%s%s: %d\n", ast_str_buffer(tabs),
02750 node->name,
02751 node->payload.uint);
02752 break;
02753 case AST_DATA_SECONDS:
02754 ast_str_append(&output, 0, "%s%s: %d\n", ast_str_buffer(tabs),
02755 node->name,
02756 node->payload.uint);
02757 break;
02758 case AST_DATA_MILLISECONDS:
02759 ast_str_append(&output, 0, "%s%s: %d\n", ast_str_buffer(tabs),
02760 node->name,
02761 node->payload.uint);
02762 break;
02763 case AST_DATA_INTEGER:
02764 ast_str_append(&output, 0, "%s%s: %d\n", ast_str_buffer(tabs),
02765 node->name,
02766 node->payload.sint);
02767 break;
02768 case AST_DATA_UNSIGNED_INTEGER:
02769 ast_str_append(&output, 0, "%s%s: %u\n", ast_str_buffer(tabs),
02770 node->name,
02771 node->payload.uint);
02772 break;
02773 case AST_DATA_DOUBLE:
02774 ast_str_append(&output, 0, "%s%s: %lf\n", ast_str_buffer(tabs),
02775 node->name,
02776 node->payload.dbl);
02777 break;
02778 case AST_DATA_BOOLEAN:
02779 ast_str_append(&output, 0, "%s%s: %s\n", ast_str_buffer(tabs),
02780 node->name,
02781 ((node->payload.boolean) ? "True" : "False"));
02782 break;
02783 case AST_DATA_IPADDR:
02784 ast_str_append(&output, 0, "%s%s: %s\n", ast_str_buffer(tabs),
02785 node->name,
02786 ast_inet_ntoa(node->payload.ipaddr));
02787 break;
02788 }
02789
02790 ast_free(tabs);
02791
02792 ast_term_color_code(&output, COLOR_WHITE, 0);
02793
02794 ast_cli(fd, "%s", ast_str_buffer(output));
02795
02796 ast_free(output);
02797
02798 if (node->type == AST_DATA_CONTAINER) {
02799 __data_result_print_cli(fd, node, depth + 1);
02800 }
02801 }
02802
02803
02804
02805
02806
02807
02808
02809
02810 static void __data_result_print_cli(int fd, const struct ast_data *root, uint32_t depth)
02811 {
02812 struct ao2_iterator iter;
02813 struct ast_data *node;
02814
02815 if (root->type == AST_DATA_CONTAINER) {
02816 iter = ao2_iterator_init(root->children, 0);
02817 while ((node = ao2_iterator_next(&iter))) {
02818 data_result_print_cli_node(fd, node, depth + 1);
02819 ao2_ref(node, -1);
02820 }
02821 ao2_iterator_destroy(&iter);
02822 } else {
02823 data_result_print_cli_node(fd, root, depth);
02824 }
02825 }
02826
02827
02828
02829
02830
02831
02832
02833 static void data_result_print_cli(int fd, const struct ast_data *root)
02834 {
02835 struct ast_str *output;
02836
02837
02838 output = ast_str_create(30);
02839 if (!output) {
02840 return;
02841 }
02842
02843 ast_term_color_code(&output, data_result_get_color(root->type), 0);
02844 ast_str_append(&output, 0, "%s\n", root->name);
02845 ast_term_color_code(&output, COLOR_WHITE, 0);
02846 ast_cli(fd, "%s", ast_str_buffer(output));
02847 ast_free(output);
02848
02849 __data_result_print_cli(fd, root, 0);
02850
02851 ast_cli(fd, "\n");
02852 }
02853
02854
02855
02856
02857
02858 static char *handle_cli_data_get(struct ast_cli_entry *e, int cmd,
02859 struct ast_cli_args *a)
02860 {
02861 struct ast_data_query query = {
02862 .version = AST_DATA_QUERY_VERSION
02863 };
02864 struct ast_data *tree;
02865
02866 switch (cmd) {
02867 case CLI_INIT:
02868 e->command = "data get";
02869 e->usage = ""
02870 "Usage: data get <path> [<search> [<filter>]]\n"
02871 " Get the tree based on a path.\n";
02872 return NULL;
02873 case CLI_GENERATE:
02874 return NULL;
02875 }
02876
02877 if (a->argc < e->args + 1) {
02878 return CLI_SHOWUSAGE;
02879 }
02880
02881 query.path = (char *) a->argv[e->args];
02882
02883 if (a->argc > e->args + 1) {
02884 query.search = (char *) a->argv[e->args + 1];
02885 }
02886
02887 if (a->argc > e->args + 2) {
02888 query.filter = (char *) a->argv[e->args + 2];
02889 }
02890
02891 tree = ast_data_get(&query);
02892 if (!tree) {
02893 return CLI_FAILURE;
02894 }
02895
02896 data_result_print_cli(a->fd, tree);
02897
02898 ast_data_free(tree);
02899
02900 return CLI_SUCCESS;
02901 }
02902
02903
02904
02905
02906
02907
02908
02909
02910
02911 static void data_provider_print_cli(int fd, const char *name,
02912 struct ao2_container *container, struct ast_str *path)
02913 {
02914 struct ao2_iterator i;
02915 struct ast_str *current_path;
02916 struct data_provider *provider;
02917
02918 current_path = ast_str_create(60);
02919 if (!current_path) {
02920 return;
02921 }
02922
02923 ast_str_reset(current_path);
02924 if (path) {
02925 ast_str_set(¤t_path, 0, "%s/%s", ast_str_buffer(path), name);
02926 } else {
02927 ast_str_set(¤t_path, 0, "%s", name);
02928 }
02929
02930 i = ao2_iterator_init(container, 0);
02931 while ((provider = ao2_iterator_next(&i))) {
02932 if (provider->handler) {
02933
02934 ast_cli(fd, "%s/%s (", ast_str_buffer(current_path),
02935 provider->name);
02936 if (provider->handler->get) {
02937 ast_cli(fd, "get");
02938 }
02939 ast_cli(fd, ") [%s]\n", provider->registrar);
02940 }
02941 data_provider_print_cli(fd, provider->name, provider->children,
02942 current_path);
02943 ao2_ref(provider, -1);
02944 }
02945 ao2_iterator_destroy(&i);
02946
02947 ast_free(current_path);
02948 }
02949
02950
02951
02952
02953
02954 static char *handle_cli_data_show_providers(struct ast_cli_entry *e, int cmd,
02955 struct ast_cli_args *a)
02956 {
02957 switch (cmd) {
02958 case CLI_INIT:
02959 e->command = "data show providers";
02960 e->usage = ""
02961 "Usage: data show providers\n"
02962 " Show the list of registered providers\n";
02963 return NULL;
02964 case CLI_GENERATE:
02965 return NULL;
02966 }
02967
02968 data_read_lock();
02969 data_provider_print_cli(a->fd, "", root_data.container, NULL);
02970 data_unlock();
02971
02972 return CLI_SUCCESS;
02973 }
02974
02975
02976
02977
02978
02979 static struct ast_cli_entry cli_data[] = {
02980 AST_CLI_DEFINE(handle_cli_data_get, "Data API get"),
02981 AST_CLI_DEFINE(handle_cli_data_show_providers, "Show data providers")
02982 };
02983
02984
02985
02986
02987
02988
02989
02990
02991
02992 static void data_result_manager_output(struct mansession *s, const char *name,
02993 struct ao2_container *container, struct ast_str *path, int id)
02994 {
02995 struct ao2_iterator i;
02996 struct ast_str *current_path;
02997 struct ast_data *node;
02998 int current_id = id;
02999
03000 current_path = ast_str_create(60);
03001 if (!current_path) {
03002 return;
03003 }
03004
03005 ast_str_reset(current_path);
03006 if (path) {
03007 ast_str_set(¤t_path, 0, "%s.%s", ast_str_buffer(path), name);
03008 } else {
03009 ast_str_set(¤t_path, 0, "%s", name);
03010 }
03011
03012 i = ao2_iterator_init(container, 0);
03013 while ((node = ao2_iterator_next(&i))) {
03014
03015 if (node->type != AST_DATA_CONTAINER) {
03016 astman_append(s, "%d-%s.%s", id, ast_str_buffer(current_path),
03017 node->name);
03018 }
03019 switch (node->type) {
03020 case AST_DATA_CONTAINER:
03021 data_result_manager_output(s, node->name, node->children, current_path, ++current_id);
03022 break;
03023 case AST_DATA_INTEGER:
03024 astman_append(s, ": %d\r\n", node->payload.sint);
03025 break;
03026 case AST_DATA_TIMESTAMP:
03027 case AST_DATA_SECONDS:
03028 case AST_DATA_MILLISECONDS:
03029 case AST_DATA_UNSIGNED_INTEGER:
03030 astman_append(s, ": %u\r\n", node->payload.uint);
03031 break;
03032 case AST_DATA_PASSWORD:
03033 astman_append(s, ": %s\r\n", node->payload.str);
03034 break;
03035 case AST_DATA_STRING:
03036 astman_append(s, ": %s\r\n", node->payload.str);
03037 break;
03038 case AST_DATA_CHARACTER:
03039 astman_append(s, ": %c\r\n", node->payload.character);
03040 break;
03041 case AST_DATA_IPADDR:
03042 astman_append(s, ": %s\r\n", ast_inet_ntoa(node->payload.ipaddr));
03043 break;
03044 case AST_DATA_POINTER:
03045 break;
03046 case AST_DATA_DOUBLE:
03047 astman_append(s, ": %f\r\n", node->payload.dbl);
03048 break;
03049 case AST_DATA_BOOLEAN:
03050 astman_append(s, ": %s\r\n",
03051 (node->payload.boolean ? "True" : "False"));
03052 break;
03053 }
03054
03055 ao2_ref(node, -1);
03056 }
03057 ao2_iterator_destroy(&i);
03058
03059 ast_free(current_path);
03060 }
03061
03062
03063
03064
03065
03066 static int manager_data_get(struct mansession *s, const struct message *m)
03067 {
03068 const char *path = astman_get_header(m, "Path");
03069 const char *search = astman_get_header(m, "Search");
03070 const char *filter = astman_get_header(m, "Filter");
03071 const char *id = astman_get_header(m, "ActionID");
03072 struct ast_data *res;
03073 struct ast_data_query query = {
03074 .version = AST_DATA_QUERY_VERSION,
03075 .path = (char *) path,
03076 .search = (char *) search,
03077 .filter = (char *) filter,
03078 };
03079
03080 if (ast_strlen_zero(path)) {
03081 astman_send_error(s, m, "'Path' parameter not specified");
03082 return 0;
03083 }
03084
03085 res = ast_data_get(&query);
03086 if (!res) {
03087 astman_send_error(s, m, "No data returned");
03088 return 0;
03089 }
03090
03091 astman_append(s, "Event: DataGet Tree\r\n");
03092 if (!ast_strlen_zero(id)) {
03093 astman_append(s, "ActionID: %s\r\n", id);
03094 }
03095 data_result_manager_output(s, res->name, res->children, NULL, 0);
03096 astman_append(s, "\r\n");
03097
03098 ast_data_free(res);
03099
03100 return RESULT_SUCCESS;
03101 }
03102
03103 int ast_data_add_codecs(struct ast_data *root, const char *node_name, format_t capability)
03104 {
03105 struct ast_data *codecs, *codec;
03106 size_t fmlist_size;
03107 const struct ast_format_list *fmlist;
03108 int x;
03109
03110 codecs = ast_data_add_node(root, node_name);
03111 if (!codecs) {
03112 return -1;
03113 }
03114 fmlist = ast_get_format_list(&fmlist_size);
03115 for (x = 0; x < fmlist_size; x++) {
03116 if (fmlist[x].bits & capability) {
03117 codec = ast_data_add_node(codecs, "codec");
03118 if (!codec) {
03119 return -1;
03120 }
03121 ast_data_add_str(codec, "name", fmlist[x].name);
03122 ast_data_add_int(codec, "samplespersecond", fmlist[x].samplespersecond);
03123 ast_data_add_str(codec, "description", fmlist[x].desc);
03124 ast_data_add_int(codec, "frame_length", fmlist[x].fr_len);
03125 }
03126 }
03127
03128 return 0;
03129 }
03130
03131 #ifdef TEST_FRAMEWORK
03132
03133
03134
03135
03136
03137
03138 struct test_structure {
03139 int a_int;
03140 unsigned int b_bool:1;
03141 char *c_str;
03142 unsigned int a_uint;
03143 };
03144
03145
03146
03147
03148
03149 #define DATA_EXPORT_TEST_STRUCTURE(MEMBER) \
03150 MEMBER(test_structure, a_int, AST_DATA_INTEGER) \
03151 MEMBER(test_structure, b_bool, AST_DATA_BOOLEAN) \
03152 MEMBER(test_structure, c_str, AST_DATA_STRING) \
03153 MEMBER(test_structure, a_uint, AST_DATA_UNSIGNED_INTEGER)
03154
03155 AST_DATA_STRUCTURE(test_structure, DATA_EXPORT_TEST_STRUCTURE);
03156
03157
03158
03159
03160
03161 static int test_data_full_provider(const struct ast_data_search *search,
03162 struct ast_data *root)
03163 {
03164 struct ast_data *test_structure;
03165 struct test_structure local_test_structure = {
03166 .a_int = 10,
03167 .b_bool = 1,
03168 .c_str = "test string",
03169 .a_uint = 20
03170 };
03171
03172 test_structure = ast_data_add_node(root, "test_structure");
03173 if (!test_structure) {
03174 ast_debug(1, "Internal data api error\n");
03175 return 0;
03176 }
03177
03178
03179 ast_data_add_structure(test_structure, test_structure, &local_test_structure);
03180
03181 if (!ast_data_search_match(search, test_structure)) {
03182 ast_data_remove_node(root, test_structure);
03183 }
03184
03185 return 0;
03186 }
03187
03188
03189
03190
03191
03192 static const struct ast_data_handler full_provider = {
03193 .version = AST_DATA_HANDLER_VERSION,
03194 .get = test_data_full_provider
03195 };
03196
03197
03198
03199
03200
03201 static const struct ast_data_entry test_providers[] = {
03202 AST_DATA_ENTRY("test/node1/node11/node111", &full_provider)
03203 };
03204
03205 AST_TEST_DEFINE(test_data_get)
03206 {
03207 struct ast_data *res, *node;
03208 struct ast_data_iterator *i;
03209 struct ast_data_query query = {
03210 .version = AST_DATA_QUERY_VERSION,
03211 .path = "test/node1/node11/node111",
03212 .search = "node111/test_structure/a_int=10",
03213 .filter = "node111/test_structure/a*int"
03214 };
03215
03216 switch (cmd) {
03217 case TEST_INIT:
03218 info->name = "data_test";
03219 info->category = "/main/data/";
03220 info->summary = "Data API unit test";
03221 info->description =
03222 "Tests whether data API get implementation works as expected.";
03223 return AST_TEST_NOT_RUN;
03224 case TEST_EXECUTE:
03225 break;
03226 }
03227
03228 ast_data_register_multiple_core(test_providers, ARRAY_LEN(test_providers));
03229
03230 res = ast_data_get(&query);
03231 if (!res) {
03232 ast_test_status_update(test, "Unable to get tree.");
03233 ast_data_unregister("test/node1/node11/node111");
03234 return AST_TEST_FAIL;
03235 }
03236
03237
03238 i = ast_data_iterator_init(res, "test_structure/");
03239 if (!i) {
03240 ast_test_status_update(test, "Unable to initiate the iterator.");
03241 ast_data_free(res);
03242 ast_data_unregister("test/node1/node11/node111");
03243 return AST_TEST_FAIL;
03244 }
03245
03246
03247 while ((node = ast_data_iterator_next(i))) {
03248 if (!strcmp(ast_data_retrieve_name(node), "a_int")) {
03249 if (ast_data_retrieve_int(node, "/") != 10) {
03250 ast_data_iterator_end(i);
03251 ast_data_free(res);
03252 ast_data_unregister("test/node1/node11/node111");
03253 return AST_TEST_FAIL;
03254 }
03255 } else if (!strcmp(ast_data_retrieve_name(node), "a_uint")) {
03256 if (ast_data_retrieve_uint(node, "/") != 20) {
03257 ast_data_iterator_end(i);
03258 ast_data_free(res);
03259 ast_data_unregister("test/node1/node11/node111");
03260 return AST_TEST_FAIL;
03261 }
03262 }
03263 }
03264
03265
03266 ast_data_iterator_end(i);
03267
03268 ast_data_free(res);
03269
03270 ast_data_unregister("test/node1/node11/node111");
03271
03272 return AST_TEST_PASS;
03273 }
03274
03275 #endif
03276
03277 int ast_data_init(void)
03278 {
03279 int res = 0;
03280
03281 ast_rwlock_init(&root_data.lock);
03282
03283 if (!(root_data.container = ao2_container_alloc(NUM_DATA_NODE_BUCKETS,
03284 data_provider_hash, data_provider_cmp))) {
03285 return -1;
03286 }
03287
03288 res |= ast_cli_register_multiple(cli_data, ARRAY_LEN(cli_data));
03289
03290 res |= ast_manager_register_xml("DataGet", 0, manager_data_get);
03291
03292 #ifdef TEST_FRAMEWORK
03293 AST_TEST_REGISTER(test_data_get);
03294 #endif
03295
03296 return res;
03297 }