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