aboutsummaryrefslogtreecommitdiffstats
path: root/main
diff options
context:
space:
mode:
authoreliel <eliel@f38db490-d61c-443f-a65b-d21fe96a405b>2010-07-08 14:48:42 +0000
committereliel <eliel@f38db490-d61c-443f-a65b-d21fe96a405b>2010-07-08 14:48:42 +0000
commit7a61a43adbc1ef91229e7757f6ac88619adff202 (patch)
tree80476efaba3fcc99c7526182d9ad935264c099eb /main
parentf28601a4b00a7b39fd8d3826b02c98e4b868e476 (diff)
Implement AstData API data providers as part of the GSOC 2010 project,
midterm evaluation. Review: https://reviewboard.asterisk.org/r/757/ git-svn-id: http://svn.digium.com/svn/asterisk/trunk@274727 f38db490-d61c-443f-a65b-d21fe96a405b
Diffstat (limited to 'main')
-rw-r--r--main/cdr.c48
-rw-r--r--main/channel.c301
-rw-r--r--main/data.c494
-rw-r--r--main/indications.c41
-rw-r--r--main/pbx.c52
5 files changed, 850 insertions, 86 deletions
diff --git a/main/cdr.c b/main/cdr.c
index db277af29..f14af2cb9 100644
--- a/main/cdr.c
+++ b/main/cdr.c
@@ -49,6 +49,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/config.h"
#include "asterisk/cli.h"
#include "asterisk/stringfields.h"
+#include "asterisk/data.h"
/*! Default AMA flag for billing records (CDR's) */
int ast_default_amaflags = AST_CDR_DOCUMENTATION;
@@ -1635,3 +1636,50 @@ int ast_cdr_engine_reload(void)
return do_reload(1);
}
+int ast_cdr_data_add_structure(struct ast_data *tree, struct ast_cdr *cdr, int recur)
+{
+ struct ast_cdr *tmpcdr;
+ struct ast_data *level;
+ struct ast_var_t *variables;
+ const char *var, *val;
+ int x = 1, i;
+ char workspace[256];
+ char *tmp;
+
+ if (!cdr) {
+ return -1;
+ }
+
+ for (tmpcdr = cdr; tmpcdr; tmpcdr = (recur ? tmpcdr->next : NULL)) {
+ level = ast_data_add_node(tree, "level");
+ if (!level) {
+ continue;
+ }
+
+ ast_data_add_int(level, "level_number", x);
+
+ AST_LIST_TRAVERSE(&tmpcdr->varshead, variables, entries) {
+ if (variables && (var = ast_var_name(variables)) &&
+ (val = ast_var_value(variables)) && !ast_strlen_zero(var)
+ && !ast_strlen_zero(val)) {
+ ast_data_add_str(level, var, val);
+ } else {
+ break;
+ }
+ }
+
+ for (i = 0; cdr_readonly_vars[i]; i++) {
+ workspace[0] = 0; /* null out the workspace, because the cdr_get_tv() won't write anything if time is NULL, so you get old vals */
+ ast_cdr_getvar(tmpcdr, cdr_readonly_vars[i], &tmp, workspace, sizeof(workspace), 0, 0);
+ if (!tmp) {
+ continue;
+ }
+ ast_data_add_str(level, cdr_readonly_vars[i], tmp);
+ }
+
+ x++;
+ }
+
+ return 0;
+}
+
diff --git a/main/channel.c b/main/channel.c
index af2c036a9..f6d9ada94 100644
--- a/main/channel.c
+++ b/main/channel.c
@@ -72,6 +72,10 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include <sys/epoll.h>
#endif
+#ifdef HAVE_PRI
+#include "sig_pri.h"
+#endif
+
struct ast_epoll_data {
struct ast_channel *chan;
int which;
@@ -135,6 +139,17 @@ static AST_RWLIST_HEAD_STATIC(backends, chanlist);
#define NUM_CHANNEL_BUCKETS 1567
#endif
+#define DATA_EXPORT_CALLERID(MEMBER) \
+ MEMBER(ast_callerid, cid_dnid, AST_DATA_STRING) \
+ MEMBER(ast_callerid, cid_num, AST_DATA_STRING) \
+ MEMBER(ast_callerid, cid_name, AST_DATA_STRING) \
+ MEMBER(ast_callerid, cid_ani, AST_DATA_STRING) \
+ MEMBER(ast_callerid, cid_pres, AST_DATA_INTEGER) \
+ MEMBER(ast_callerid, cid_ani2, AST_DATA_INTEGER) \
+ MEMBER(ast_callerid, cid_tag, AST_DATA_STRING)
+
+AST_DATA_STRUCTURE(ast_callerid, DATA_EXPORT_CALLERID);
+
#define DATA_EXPORT_CHANNEL(MEMBER) \
MEMBER(ast_channel, blockproc, AST_DATA_STRING) \
MEMBER(ast_channel, appl, AST_DATA_STRING) \
@@ -151,28 +166,14 @@ static AST_RWLIST_HEAD_STATIC(backends, chanlist);
MEMBER(ast_channel, parkinglot, AST_DATA_STRING) \
MEMBER(ast_channel, hangupsource, AST_DATA_STRING) \
MEMBER(ast_channel, dialcontext, AST_DATA_STRING) \
- MEMBER(ast_channel, _softhangup, AST_DATA_INTEGER) \
- MEMBER(ast_channel, streamid, AST_DATA_INTEGER) \
- MEMBER(ast_channel, vstreamid, AST_DATA_INTEGER) \
- MEMBER(ast_channel, oldwriteformat, AST_DATA_INTEGER) \
- MEMBER(ast_channel, _state, AST_DATA_INTEGER) \
MEMBER(ast_channel, rings, AST_DATA_INTEGER) \
MEMBER(ast_channel, priority, AST_DATA_INTEGER) \
MEMBER(ast_channel, macropriority, AST_DATA_INTEGER) \
- MEMBER(ast_channel, amaflags, AST_DATA_INTEGER) \
MEMBER(ast_channel, adsicpe, AST_DATA_INTEGER) \
MEMBER(ast_channel, fin, AST_DATA_UNSIGNED_INTEGER) \
MEMBER(ast_channel, fout, AST_DATA_UNSIGNED_INTEGER) \
- MEMBER(ast_channel, hangupcause, AST_DATA_INTEGER) \
- MEMBER(ast_channel, flags, AST_DATA_UNSIGNED_INTEGER) \
- MEMBER(ast_channel, nativeformats, AST_DATA_INTEGER) \
- MEMBER(ast_channel, readformat, AST_DATA_INTEGER) \
- MEMBER(ast_channel, writeformat, AST_DATA_INTEGER) \
- MEMBER(ast_channel, rawreadformat, AST_DATA_INTEGER) \
- MEMBER(ast_channel, rawwriteformat, AST_DATA_INTEGER) \
MEMBER(ast_channel, emulate_dtmf_duration, AST_DATA_UNSIGNED_INTEGER) \
MEMBER(ast_channel, visible_indication, AST_DATA_INTEGER) \
- MEMBER(ast_channel, transfercapability, AST_DATA_INTEGER) \
MEMBER(ast_channel, context, AST_DATA_STRING) \
MEMBER(ast_channel, exten, AST_DATA_STRING) \
MEMBER(ast_channel, macrocontext, AST_DATA_STRING) \
@@ -259,9 +260,170 @@ struct ast_variable *ast_channeltype_list(void)
return var;
}
-int ast_channel_data_add_structure(struct ast_data *tree, struct ast_channel *chan)
+static void channel_data_add_flags(struct ast_data *tree,
+ struct ast_channel *chan)
+{
+ ast_data_add_bool(tree, "DEFER_DTMF", ast_test_flag(chan, AST_FLAG_DEFER_DTMF));
+ ast_data_add_bool(tree, "WRITE_INT", ast_test_flag(chan, AST_FLAG_WRITE_INT));
+ ast_data_add_bool(tree, "BLOCKING", ast_test_flag(chan, AST_FLAG_BLOCKING));
+ ast_data_add_bool(tree, "ZOMBIE", ast_test_flag(chan, AST_FLAG_ZOMBIE));
+ ast_data_add_bool(tree, "EXCEPTION", ast_test_flag(chan, AST_FLAG_EXCEPTION));
+ ast_data_add_bool(tree, "MOH", ast_test_flag(chan, AST_FLAG_MOH));
+ ast_data_add_bool(tree, "SPYING", ast_test_flag(chan, AST_FLAG_SPYING));
+ ast_data_add_bool(tree, "NBRIDGE", ast_test_flag(chan, AST_FLAG_NBRIDGE));
+ ast_data_add_bool(tree, "IN_AUTOLOOP", ast_test_flag(chan, AST_FLAG_IN_AUTOLOOP));
+ ast_data_add_bool(tree, "OUTGOING", ast_test_flag(chan, AST_FLAG_OUTGOING));
+ ast_data_add_bool(tree, "IN_DTMF", ast_test_flag(chan, AST_FLAG_IN_DTMF));
+ ast_data_add_bool(tree, "EMULATE_DTMF", ast_test_flag(chan, AST_FLAG_EMULATE_DTMF));
+ ast_data_add_bool(tree, "END_DTMF_ONLY", ast_test_flag(chan, AST_FLAG_END_DTMF_ONLY));
+ ast_data_add_bool(tree, "ANSWERED_ELSEWHERE", ast_test_flag(chan, AST_FLAG_ANSWERED_ELSEWHERE));
+ ast_data_add_bool(tree, "MASQ_NOSTREAM", ast_test_flag(chan, AST_FLAG_MASQ_NOSTREAM));
+ ast_data_add_bool(tree, "BRIDGE_HANGUP_RUN", ast_test_flag(chan, AST_FLAG_BRIDGE_HANGUP_RUN));
+ ast_data_add_bool(tree, "BRIDGE_HANGUP_DONT", ast_test_flag(chan, AST_FLAG_BRIDGE_HANGUP_DONT));
+ ast_data_add_bool(tree, "DISABLE_WORKAROUNDS", ast_test_flag(chan, AST_FLAG_DISABLE_WORKAROUNDS));
+}
+
+static const char *callerid_ton2str(int ton)
+{
+#ifdef HAVE_PRI
+ switch (ton) {
+ case PRI_TON_INTERNATIONAL:
+ return "International Number";
+ case PRI_TON_NATIONAL:
+ return "National Number";
+ case PRI_TON_NET_SPECIFIC:
+ return "Network Specific Number";
+ case PRI_TON_SUBSCRIBER:
+ return "Subscriber Number";
+ case PRI_TON_ABBREVIATED:
+ return "Abbreviated number";
+ case PRI_TON_RESERVED:
+ return "Reserved Number";
+ case PRI_TON_UNKNOWN:
+ default:
+ return "Unknown Number Type";
+ }
+#endif
+ return "";
+}
+
+int ast_channel_data_add_structure(struct ast_data *tree,
+ struct ast_channel *chan, int add_bridged)
{
- return ast_data_add_structure(ast_channel, tree, chan);
+ struct ast_channel *bc;
+ struct ast_data *data_bridged, *data_cdr, *data_flags, *data_zones;
+ struct ast_data *data_callerid, *enum_node, *data_softhangup;
+
+ if (!tree) {
+ return -1;
+ }
+
+ ast_data_add_structure(ast_channel, tree, chan);
+
+ if (add_bridged) {
+ bc = ast_bridged_channel(chan);
+ if (bc) {
+ data_bridged = ast_data_add_node(tree, "bridged");
+ if (!data_bridged) {
+ return -1;
+ }
+ ast_channel_data_add_structure(data_bridged, bc, 0);
+ }
+ }
+
+ ast_data_add_codecs(tree, "oldwriteformat", chan->oldwriteformat);
+ ast_data_add_codecs(tree, "nativeformats", chan->nativeformats);
+ ast_data_add_codecs(tree, "readformat", chan->readformat);
+ ast_data_add_codecs(tree, "writeformat", chan->writeformat);
+ ast_data_add_codecs(tree, "rawreadformat", chan->rawreadformat);
+ ast_data_add_codecs(tree, "rawwriteformat", chan->rawwriteformat);
+
+ /* state */
+ enum_node = ast_data_add_node(tree, "state");
+ if (!enum_node) {
+ return -1;
+ }
+ ast_data_add_str(enum_node, "text", ast_state2str(chan->_state));
+ ast_data_add_int(enum_node, "value", chan->_state);
+
+ /* hangupcause */
+ enum_node = ast_data_add_node(tree, "hangupcause");
+ if (!enum_node) {
+ return -1;
+ }
+ ast_data_add_str(enum_node, "text", ast_cause2str(chan->hangupcause));
+ ast_data_add_int(enum_node, "value", chan->hangupcause);
+
+ /* amaflags */
+ enum_node = ast_data_add_node(tree, "amaflags");
+ if (!enum_node) {
+ return -1;
+ }
+ ast_data_add_str(enum_node, "text", ast_cdr_flags2str(chan->amaflags));
+ ast_data_add_int(enum_node, "value", chan->amaflags);
+
+ /* transfercapability */
+ enum_node = ast_data_add_node(tree, "transfercapability");
+ if (!enum_node) {
+ return -1;
+ }
+ ast_data_add_str(enum_node, "text", ast_transfercapability2str(chan->transfercapability));
+ ast_data_add_int(enum_node, "value", chan->transfercapability);
+
+ /* _softphangup */
+ data_softhangup = ast_data_add_node(tree, "softhangup");
+ if (!data_softhangup) {
+ return -1;
+ }
+ ast_data_add_bool(data_softhangup, "dev", chan->_softhangup & AST_SOFTHANGUP_DEV);
+ ast_data_add_bool(data_softhangup, "asyncgoto", chan->_softhangup & AST_SOFTHANGUP_ASYNCGOTO);
+ ast_data_add_bool(data_softhangup, "shutdown", chan->_softhangup & AST_SOFTHANGUP_SHUTDOWN);
+ ast_data_add_bool(data_softhangup, "timeout", chan->_softhangup & AST_SOFTHANGUP_TIMEOUT);
+ ast_data_add_bool(data_softhangup, "appunload", chan->_softhangup & AST_SOFTHANGUP_APPUNLOAD);
+ ast_data_add_bool(data_softhangup, "explicit", chan->_softhangup & AST_SOFTHANGUP_EXPLICIT);
+ ast_data_add_bool(data_softhangup, "unbridge", chan->_softhangup & AST_SOFTHANGUP_UNBRIDGE);
+
+ /* channel flags */
+ data_flags = ast_data_add_node(tree, "flags");
+ if (!data_flags) {
+ return -1;
+ }
+ channel_data_add_flags(data_flags, chan);
+
+ ast_data_add_uint(tree, "timetohangup", chan->whentohangup.tv_sec);
+
+ /* callerid */
+ data_callerid = ast_data_add_node(tree, "callerid");
+ if (!data_callerid) {
+ return -1;
+ }
+ ast_data_add_structure(ast_callerid, data_callerid, &(chan->cid));
+ /* insert the callerid ton */
+ enum_node = ast_data_add_node(data_callerid, "cid_ton");
+ if (!enum_node) {
+ return -1;
+ }
+ ast_data_add_int(enum_node, "value", chan->cid.cid_ton);
+ ast_data_add_str(enum_node, "text", callerid_ton2str(chan->cid.cid_ton));
+
+ /* tone zone */
+ if (chan->zone) {
+ data_zones = ast_data_add_node(tree, "zone");
+ if (!data_zones) {
+ return -1;
+ }
+ ast_tone_zone_data_add_structure(data_zones, chan->zone);
+ }
+
+ /* insert cdr */
+ data_cdr = ast_data_add_node(tree, "cdr");
+ if (!data_cdr) {
+ return -1;
+ }
+
+ ast_cdr_data_add_structure(data_cdr, chan->cdr, 1);
+
+ return 0;
}
int ast_channel_data_cmp_structure(const struct ast_data_search *tree,
@@ -6790,52 +6952,29 @@ int ast_plc_reload(void)
static int data_channels_provider_handler(const struct ast_data_search *search,
struct ast_data *root)
{
- struct ast_channel *c, *bc;
+ struct ast_channel *c;
struct ast_channel_iterator *iter = NULL;
- struct ast_data *data_channel, *data_bridged;
- int channel_match, bridged_match;
-
- channel_match = ast_data_search_has_condition(search,
- "channel");
- bridged_match = ast_data_search_has_condition(search,
- "channel/bridged");
+ struct ast_data *data_channel;
for (iter = ast_channel_iterator_all_new();
iter && (c = ast_channel_iterator_next(iter)); ast_channel_unref(c)) {
ast_channel_lock(c);
- if (channel_match &&
- ast_channel_data_cmp_structure(search, c, "channel")) {
- ast_channel_unlock(c);
- continue;
- }
-
- bc = ast_bridged_channel(c);
-
- if (bridged_match && bc &&
- ast_channel_data_cmp_structure(search, bc, "channel/bridged")) {
- ast_channel_unlock(c);
- continue;
- }
-
data_channel = ast_data_add_node(root, "channel");
if (!data_channel) {
ast_channel_unlock(c);
continue;
}
- ast_channel_data_add_structure(data_channel, c);
-
- if (bc) {
- data_bridged = ast_data_add_node(data_channel, "bridged");
- if (!data_bridged) {
- ast_channel_unlock(c);
- continue;
- }
- ast_channel_data_add_structure(data_bridged, bc);
+ if (ast_channel_data_add_structure(data_channel, c, 1) < 0) {
+ ast_log(LOG_ERROR, "Unable to add channel structure for channel: %s\n", c->name);
}
ast_channel_unlock(c);
+
+ if (!ast_data_search_match(search, data_channel)) {
+ ast_data_remove_node(root, data_channel);
+ }
}
if (iter) {
ast_channel_iterator_destroy(iter);
@@ -6846,6 +6985,64 @@ static int data_channels_provider_handler(const struct ast_data_search *search,
/*!
* \internal
+ * \brief Implements the channeltypes provider.
+ */
+static int data_channeltypes_provider_handler(const struct ast_data_search *search,
+ struct ast_data *data_root)
+{
+ struct chanlist *cl;
+ struct ast_data *data_type;
+
+ AST_RWLIST_RDLOCK(&backends);
+ AST_RWLIST_TRAVERSE(&backends, cl, list) {
+ data_type = ast_data_add_node(data_root, "type");
+ if (!data_type) {
+ continue;
+ }
+ ast_data_add_str(data_type, "name", cl->tech->type);
+ ast_data_add_str(data_type, "description", cl->tech->description);
+ ast_data_add_bool(data_type, "devicestate", cl->tech->devicestate ? 1 : 0);
+ ast_data_add_bool(data_type, "indications", cl->tech->indicate ? 1 : 0);
+ ast_data_add_bool(data_type, "transfer", cl->tech->transfer ? 1 : 0);
+ ast_data_add_bool(data_type, "send_digit_begin", cl->tech->send_digit_begin ? 1 : 0);
+ ast_data_add_bool(data_type, "send_digit_end", cl->tech->send_digit_end ? 1 : 0);
+ ast_data_add_bool(data_type, "call", cl->tech->call ? 1 : 0);
+ ast_data_add_bool(data_type, "hangup", cl->tech->hangup ? 1 : 0);
+ ast_data_add_bool(data_type, "answer", cl->tech->answer ? 1 : 0);
+ ast_data_add_bool(data_type, "read", cl->tech->read ? 1 : 0);
+ ast_data_add_bool(data_type, "write", cl->tech->write ? 1 : 0);
+ ast_data_add_bool(data_type, "send_text", cl->tech->send_text ? 1 : 0);
+ ast_data_add_bool(data_type, "send_image", cl->tech->send_image ? 1 : 0);
+ ast_data_add_bool(data_type, "send_html", cl->tech->send_html ? 1 : 0);
+ ast_data_add_bool(data_type, "exception", cl->tech->exception ? 1 : 0);
+ ast_data_add_bool(data_type, "bridge", cl->tech->bridge ? 1 : 0);
+ ast_data_add_bool(data_type, "early_bridge", cl->tech->early_bridge ? 1 : 0);
+ ast_data_add_bool(data_type, "fixup", cl->tech->fixup ? 1 : 0);
+ ast_data_add_bool(data_type, "setoption", cl->tech->setoption ? 1 : 0);
+ ast_data_add_bool(data_type, "queryoption", cl->tech->queryoption ? 1 : 0);
+ ast_data_add_bool(data_type, "write_video", cl->tech->write_video ? 1 : 0);
+ ast_data_add_bool(data_type, "write_text", cl->tech->write_text ? 1 : 0);
+ ast_data_add_bool(data_type, "bridged_channel", cl->tech->bridged_channel ? 1 : 0);
+ ast_data_add_bool(data_type, "func_channel_read", cl->tech->func_channel_read ? 1 : 0);
+ ast_data_add_bool(data_type, "func_channel_write", cl->tech->func_channel_write ? 1 : 0);
+ ast_data_add_bool(data_type, "get_base_channel", cl->tech->get_base_channel ? 1 : 0);
+ ast_data_add_bool(data_type, "set_base_channel", cl->tech->set_base_channel ? 1 : 0);
+ ast_data_add_bool(data_type, "get_pvt_uniqueid", cl->tech->get_pvt_uniqueid ? 1 : 0);
+ ast_data_add_bool(data_type, "cc_callback", cl->tech->cc_callback ? 1 : 0);
+
+ ast_data_add_codecs(data_type, "capabilities", cl->tech->capabilities);
+
+ if (!ast_data_search_match(search, data_type)) {
+ ast_data_remove_node(data_root, data_type);
+ }
+ }
+ AST_RWLIST_UNLOCK(&backends);
+
+ return 0;
+}
+
+/*!
+ * \internal
* \brief /asterisk/core/channels provider.
*/
static const struct ast_data_handler channels_provider = {
@@ -6853,8 +7050,18 @@ static const struct ast_data_handler channels_provider = {
.get = data_channels_provider_handler
};
+/*!
+ * \internal
+ * \brief /asterisk/core/channeltypes provider.
+ */
+static const struct ast_data_handler channeltypes_provider = {
+ .version = AST_DATA_HANDLER_VERSION,
+ .get = data_channeltypes_provider_handler
+};
+
static const struct ast_data_entry channel_providers[] = {
AST_DATA_ENTRY("/asterisk/core/channels", &channels_provider),
+ AST_DATA_ENTRY("/asterisk/core/channeltypes", &channeltypes_provider),
};
void ast_channels_init(void)
diff --git a/main/data.c b/main/data.c
index c402c4fa6..2a4559c04 100644
--- a/main/data.c
+++ b/main/data.c
@@ -40,6 +40,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/term.h"
#include "asterisk/manager.h"
#include "asterisk/test.h"
+#include "asterisk/frame.h"
/*** DOCUMENTATION
<manager name="DataGet" language="en_US">
@@ -85,8 +86,9 @@ struct ast_data {
int32_t sint;
uint32_t uint;
double dbl;
- unsigned int boolean:1;
+ unsigned int boolean;
char *str;
+ char character;
struct in_addr ipaddr;
void *ptr;
} payload;
@@ -981,7 +983,19 @@ static struct ast_data_search *data_search_get_node(const struct ast_data_search
return current;
}
-int ast_data_search_cmp_string(const struct ast_data_search *root, const char *name,
+/*!
+ * \internal
+ * \brief Based on a search tree, evaluate the specified 'name' inside the tree with the
+ * current string value.
+ * .search = "somename=somestring"
+ * name = "somename"
+ * value is the current value of something and will be evaluated against "somestring".
+ * \param[in] root The root node pointer of the search tree.
+ * \param[in] name The name of the specific.
+ * \param[in] value The value to compare.
+ * \returns The strcmp return value.
+ */
+static int data_search_cmp_string(const struct ast_data_search *root, const char *name,
char *value)
{
struct ast_data_search *child;
@@ -1001,7 +1015,19 @@ int ast_data_search_cmp_string(const struct ast_data_search *root, const char *n
return data_search_comparison_result(ret, cmp_type);
}
-int ast_data_search_cmp_ptr(const struct ast_data_search *root, const char *name,
+/*!
+ * \internal
+ * \brief Based on a search tree, evaluate the specified 'name' inside the tree with the
+ * current pointer address value.
+ * .search = "something=0x32323232"
+ * name = "something"
+ * value is the current value of something and will be evaluated against "0x32323232".
+ * \param[in] root The root node pointer of the search tree.
+ * \param[in] name The name of the specific.
+ * \param[in] ptr The pointer address to compare.
+ * \returns The (value - current_value) result.
+ */
+static int data_search_cmp_ptr(const struct ast_data_search *root, const char *name,
void *ptr)
{
struct ast_data_search *child;
@@ -1024,7 +1050,19 @@ int ast_data_search_cmp_ptr(const struct ast_data_search *root, const char *name
return data_search_comparison_result((node_ptr - ptr), cmp_type);
}
-int ast_data_search_cmp_ipaddr(const struct ast_data_search *root, const char *name,
+/*!
+ * \internal
+ * \brief Based on a search tree, evaluate the specified 'name' inside the tree with the
+ * current ipv4 address value.
+ * .search = "something=192.168.2.2"
+ * name = "something"
+ * value is the current value of something and will be evaluated against "192.168.2.2".
+ * \param[in] root The root node pointer of the search tree.
+ * \param[in] name The name of the specific.
+ * \param[in] addr The ipv4 address value to compare.
+ * \returns The (value - current_value) result.
+ */
+static int data_search_cmp_ipaddr(const struct ast_data_search *root, const char *name,
struct in_addr addr)
{
struct ast_data_search *child;
@@ -1044,7 +1082,19 @@ int ast_data_search_cmp_ipaddr(const struct ast_data_search *root, const char *n
return data_search_comparison_result((node_addr.s_addr - addr.s_addr), cmp_type);
}
-int ast_data_search_cmp_bool(const struct ast_data_search *root, const char *name,
+/*!
+ * \internal
+ * \brief Based on a search tree, evaluate the specified 'name' inside the tree with the
+ * current boolean value.
+ * .search = "something=true"
+ * name = "something"
+ * value is the current value of something and will be evaluated against "true".
+ * \param[in] root The root node pointer of the search tree.
+ * \param[in] name The name of the specific.
+ * \param[in] value The boolean value to compare.
+ * \returns The (value - current_value) result.
+ */
+static int data_search_cmp_bool(const struct ast_data_search *root, const char *name,
unsigned int value)
{
struct ast_data_search *child;
@@ -1064,7 +1114,19 @@ int ast_data_search_cmp_bool(const struct ast_data_search *root, const char *nam
return data_search_comparison_result(value - node_value, cmp_type);
}
-int ast_data_search_cmp_dbl(const struct ast_data_search *root, const char *name,
+/*!
+ * \internal
+ * \brief Based on a search tree, evaluate the specified 'name' inside the tree with the
+ * current double value.
+ * .search = "something=222"
+ * name = "something"
+ * value is the current value of something and will be evaluated against "222".
+ * \param[in] root The root node pointer of the search tree.
+ * \param[in] name The name of the specific.
+ * \param[in] value The double value to compare.
+ * \returns The (value - current_value) result.
+ */
+static int data_search_cmp_dbl(const struct ast_data_search *root, const char *name,
double value)
{
struct ast_data_search *child;
@@ -1084,7 +1146,19 @@ int ast_data_search_cmp_dbl(const struct ast_data_search *root, const char *name
return data_search_comparison_result(value - node_value, cmp_type);
}
-int ast_data_search_cmp_uint(const struct ast_data_search *root, const char *name,
+/*!
+ * \internal
+ * \brief Based on a search tree, evaluate the specified 'name' inside the tree with the
+ * current unsigned integer value.
+ * .search = "something=10"
+ * name = "something"
+ * value is the current value of something and will be evaluated against "10".
+ * \param[in] root The root node pointer of the search tree.
+ * \param[in] name The name of the specific.
+ * \param[in] value The unsigned value to compare.
+ * \returns The strcmp return value.
+ */
+static int data_search_cmp_uint(const struct ast_data_search *root, const char *name,
unsigned int value)
{
struct ast_data_search *child;
@@ -1104,7 +1178,19 @@ int ast_data_search_cmp_uint(const struct ast_data_search *root, const char *nam
return data_search_comparison_result(value - node_value, cmp_type);
}
-int ast_data_search_cmp_int(const struct ast_data_search *root, const char *name,
+/*!
+ * \internal
+ * \brief Based on a search tree, evaluate the specified 'name' inside the tree with the
+ * current signed integer value.
+ * .search = "something=10"
+ * name = "something"
+ * value is the current value of something and will be evaluated against "10".
+ * \param[in] root The root node pointer of the search tree.
+ * \param[in] name The name of the specific.
+ * \param[in] value The value to compare.
+ * \returns The strcmp return value.
+ */
+static int data_search_cmp_int(const struct ast_data_search *root, const char *name,
int value)
{
struct ast_data_search *child;
@@ -1126,6 +1212,38 @@ int ast_data_search_cmp_int(const struct ast_data_search *root, const char *name
/*!
* \internal
+ * \brief Based on a search tree, evaluate the specified 'name' inside the tree with the
+ * current character value.
+ * .search = "something=c"
+ * name = "something"
+ * value is the current value of something and will be evaluated against "c".
+ * \param[in] root The root node pointer of the search tree.
+ * \param[in] name The name of the specific.
+ * \param[in] value The boolean value to compare.
+ * \returns The (value - current_value) result.
+ */
+static int data_search_cmp_char(const struct ast_data_search *root, const char *name,
+ char value)
+{
+ struct ast_data_search *child;
+ char node_value;
+ enum data_search_comparison cmp_type;
+
+ child = data_search_get_node(root, name);
+ if (!child) {
+ return 0;
+ }
+
+ node_value = *(child->value);
+ cmp_type = child->cmp_type;
+
+ ao2_ref(child, -1);
+
+ return data_search_comparison_result(value - node_value, cmp_type);
+}
+
+/*!
+ * \internal
* \brief Get the member pointer, from a mapping structure, based on its name.
* \XXX We will need to improve performance here!!.
* \retval <0 if the member was not found.
@@ -1146,21 +1264,6 @@ static inline int data_search_mapping_find(const struct ast_data_mapping_structu
return -1;
}
-int ast_data_search_has_condition(const struct ast_data_search *search,
- const char *compare_condition)
-{
- struct ast_data_search *child;
-
- child = data_search_get_node(search, compare_condition);
- if (!child) {
- return 0;
- }
-
- ao2_ref(child, -1);
-
- return 1;
-}
-
int __ast_data_search_cmp_structure(const struct ast_data_search *search,
const struct ast_data_mapping_structure *mapping, size_t mapping_len,
void *structure, const char *structure_name)
@@ -1191,38 +1294,63 @@ int __ast_data_search_cmp_structure(const struct ast_data_search *search,
notmatch = 0;
switch (mapping[member].type) {
+ case AST_DATA_PASSWORD:
+ notmatch = data_search_cmp_string(struct_children,
+ node->name,
+ mapping[member].get.AST_DATA_PASSWORD(structure));
+ break;
+ case AST_DATA_TIMESTAMP:
+ notmatch = data_search_cmp_uint(struct_children,
+ node->name,
+ mapping[member].get.AST_DATA_TIMESTAMP(structure));
+ break;
+ case AST_DATA_SECONDS:
+ notmatch = data_search_cmp_uint(struct_children,
+ node->name,
+ mapping[member].get.AST_DATA_SECONDS(structure));
+ break;
+ case AST_DATA_MILLISECONDS:
+ notmatch = data_search_cmp_uint(struct_children,
+ node->name,
+ mapping[member].get.AST_DATA_MILLISECONDS(structure));
+ break;
case AST_DATA_STRING:
- notmatch = ast_data_search_cmp_string(struct_children,
+ notmatch = data_search_cmp_string(struct_children,
node->name,
mapping[member].get.AST_DATA_STRING(structure));
break;
+ case AST_DATA_CHARACTER:
+ notmatch = data_search_cmp_char(struct_children,
+ node->name,
+ mapping[member].get.AST_DATA_CHARACTER(structure));
+ break;
case AST_DATA_INTEGER:
- notmatch = ast_data_search_cmp_int(struct_children,
+ notmatch = data_search_cmp_int(struct_children,
node->name,
mapping[member].get.AST_DATA_INTEGER(structure));
break;
case AST_DATA_BOOLEAN:
- notmatch = ast_data_search_cmp_bool(struct_children,
+ notmatch = data_search_cmp_bool(struct_children,
node->name,
mapping[member].get.AST_DATA_BOOLEAN(structure));
break;
case AST_DATA_UNSIGNED_INTEGER:
- notmatch = ast_data_search_cmp_uint(struct_children,
+ notmatch = data_search_cmp_uint(struct_children,
node->name,
mapping[member].get.AST_DATA_UNSIGNED_INTEGER(structure));
break;
case AST_DATA_DOUBLE:
- notmatch = ast_data_search_cmp_dbl(struct_children,
+ notmatch = data_search_cmp_dbl(struct_children,
node->name,
mapping[member].get.AST_DATA_DOUBLE(structure));
break;
case AST_DATA_IPADDR:
- notmatch = ast_data_search_cmp_ipaddr(struct_children,
+ notmatch = data_search_cmp_ipaddr(struct_children,
node->name,
mapping[member].get.AST_DATA_IPADDR(structure));
break;
case AST_DATA_POINTER:
- notmatch = ast_data_search_cmp_ptr(struct_children,
+ notmatch = data_search_cmp_ptr(struct_children,
node->name,
mapping[member].get.AST_DATA_POINTER(structure));
break;
@@ -1248,11 +1376,18 @@ static void data_result_destructor(void *obj)
struct ast_data *root = obj;
switch (root->type) {
- case AST_DATA_POINTER:
+ case AST_DATA_PASSWORD:
case AST_DATA_STRING:
- ast_free(root->payload.ptr);
+ ast_free(root->payload.str);
+ ao2_ref(root->children, -1);
+ break;
+ case AST_DATA_POINTER:
+ case AST_DATA_CHARACTER:
case AST_DATA_CONTAINER:
case AST_DATA_INTEGER:
+ case AST_DATA_TIMESTAMP:
+ case AST_DATA_SECONDS:
+ case AST_DATA_MILLISECONDS:
case AST_DATA_UNSIGNED_INTEGER:
case AST_DATA_DOUBLE:
case AST_DATA_BOOLEAN:
@@ -1315,6 +1450,105 @@ static struct ast_data *data_result_find_child(struct ast_data *root, const char
return found;
}
+int ast_data_search_match(const struct ast_data_search *search, struct ast_data *data)
+{
+ struct ao2_iterator i, ii;
+ struct ast_data_search *s, *s_child;
+ struct ast_data *d_child;
+ int notmatch = 1;
+
+ if (!search) {
+ return 1;
+ }
+
+ s_child = data_search_find(search->children, data->name);
+ if (!s_child) {
+ /* nothing to compare */
+ ao2_ref(s_child, -1);
+ return 1;
+ }
+
+ i = ao2_iterator_init(s_child->children, 0);
+ while ((s = ao2_iterator_next(&i))) {
+ if (!ao2_container_count(s->children)) {
+ /* compare this search node with every data node */
+ d_child = data_result_find_child(data, s->name);
+ if (!d_child) {
+ ao2_ref(s, -1);
+ notmatch = 1;
+ continue;
+ }
+
+ switch (d_child->type) {
+ case AST_DATA_PASSWORD:
+ case AST_DATA_STRING:
+ notmatch = data_search_cmp_string(s_child, d_child->name,
+ d_child->payload.str);
+ break;
+ case AST_DATA_CHARACTER:
+ notmatch = data_search_cmp_char(s_child, d_child->name,
+ d_child->payload.character);
+ break;
+ case AST_DATA_INTEGER:
+ notmatch = data_search_cmp_int(s_child, d_child->name,
+ d_child->payload.sint);
+ break;
+ case AST_DATA_BOOLEAN:
+ notmatch = data_search_cmp_bool(s_child, d_child->name,
+ d_child->payload.boolean);
+ break;
+ case AST_DATA_UNSIGNED_INTEGER:
+ notmatch = data_search_cmp_uint(s_child, d_child->name,
+ d_child->payload.uint);
+ break;
+ case AST_DATA_TIMESTAMP:
+ case AST_DATA_SECONDS:
+ case AST_DATA_MILLISECONDS:
+ case AST_DATA_DOUBLE:
+ notmatch = data_search_cmp_uint(s_child, d_child->name,
+ d_child->payload.dbl);
+ break;
+ case AST_DATA_IPADDR:
+ notmatch = data_search_cmp_ipaddr(s_child, d_child->name,
+ d_child->payload.ipaddr);
+ break;
+ case AST_DATA_POINTER:
+ notmatch = data_search_cmp_ptr(s_child, d_child->name,
+ d_child->payload.ptr);
+ break;
+ case AST_DATA_CONTAINER:
+ break;
+ }
+ ao2_ref(d_child, -1);
+ } else {
+ ii = ao2_iterator_init(data->children, 0);
+ while ((d_child = ao2_iterator_next(&ii))) {
+ if (strcmp(d_child->name, s->name)) {
+ ao2_ref(d_child, -1);
+ continue;
+ }
+ if (!(notmatch = !ast_data_search_match(s_child, d_child))) {
+ /* do not continue if we have a match. */
+ ao2_ref(d_child, -1);
+ break;
+ }
+ ao2_ref(d_child, -1);
+ }
+ ao2_iterator_destroy(&ii);
+ }
+ ao2_ref(s, -1);
+ if (notmatch) {
+ /* do not continue if we don't have a match. */
+ break;
+ }
+ }
+ ao2_iterator_destroy(&i);
+
+ ao2_ref(s_child, -1);
+
+ return !notmatch;
+}
+
/*!
* \internal
* \brief Get an internal node, from the result set.
@@ -1872,9 +2106,32 @@ static void data_get_xml_add_child(struct ast_data *parent_data,
case AST_DATA_CONTAINER:
data_get_xml_add_child(node, child_xml);
break;
+ case AST_DATA_PASSWORD:
+ ast_xml_set_text(child_xml, node->payload.str);
+ break;
+ case AST_DATA_TIMESTAMP:
+ snprintf(node_content, sizeof(node_content), "%d",
+ node->payload.uint);
+ ast_xml_set_text(child_xml, node_content);
+ break;
+ case AST_DATA_SECONDS:
+ snprintf(node_content, sizeof(node_content), "%d",
+ node->payload.uint);
+ ast_xml_set_text(child_xml, node_content);
+ break;
+ case AST_DATA_MILLISECONDS:
+ snprintf(node_content, sizeof(node_content), "%d",
+ node->payload.uint);
+ ast_xml_set_text(child_xml, node_content);
+ break;
case AST_DATA_STRING:
ast_xml_set_text(child_xml, node->payload.str);
break;
+ case AST_DATA_CHARACTER:
+ snprintf(node_content, sizeof(node_content), "%c",
+ node->payload.character);
+ ast_xml_set_text(child_xml, node_content);
+ break;
case AST_DATA_INTEGER:
snprintf(node_content, sizeof(node_content), "%d",
node->payload.sint);
@@ -2006,15 +2263,24 @@ static struct ast_data *__ast_data_add(struct ast_data *root, const char *name,
node->payload.boolean = *(unsigned int *) ptr;
break;
case AST_DATA_INTEGER:
- node->payload.sint = *(unsigned int *) ptr;
+ node->payload.sint = *(int *) ptr;
break;
+ case AST_DATA_TIMESTAMP:
+ case AST_DATA_SECONDS:
+ case AST_DATA_MILLISECONDS:
case AST_DATA_UNSIGNED_INTEGER:
- node->payload.sint = *(unsigned int *) ptr;
+ node->payload.uint = *(unsigned int *) ptr;
break;
case AST_DATA_DOUBLE:
node->payload.dbl = *(double *) ptr;
break;
+ case AST_DATA_PASSWORD:
case AST_DATA_STRING:
+ node->payload.str = (char *) ptr;
+ break;
+ case AST_DATA_CHARACTER:
+ node->payload.character = *(char *) ptr;
+ break;
case AST_DATA_POINTER:
node->payload.ptr = ptr;
break;
@@ -2052,6 +2318,11 @@ struct ast_data *ast_data_add_int(struct ast_data *root, const char *name, int v
return __ast_data_add(root, name, AST_DATA_INTEGER, &value);
}
+struct ast_data *ast_data_add_char(struct ast_data *root, const char *name, char value)
+{
+ return __ast_data_add(root, name, AST_DATA_CHARACTER, &value);
+}
+
struct ast_data *ast_data_add_uint(struct ast_data *root, const char *name,
unsigned int value)
{
@@ -2082,6 +2353,45 @@ struct ast_data *ast_data_add_ptr(struct ast_data *root, const char *childname,
return __ast_data_add(root, childname, AST_DATA_POINTER, ptr);
}
+struct ast_data *ast_data_add_timestamp(struct ast_data *root, const char *childname,
+ unsigned int timestamp)
+{
+ return __ast_data_add(root, childname, AST_DATA_TIMESTAMP, &timestamp);
+}
+
+struct ast_data *ast_data_add_seconds(struct ast_data *root, const char *childname,
+ unsigned int seconds)
+{
+ return __ast_data_add(root, childname, AST_DATA_SECONDS, &seconds);
+}
+
+struct ast_data *ast_data_add_milliseconds(struct ast_data *root, const char *childname,
+ unsigned int milliseconds)
+{
+ return __ast_data_add(root, childname, AST_DATA_MILLISECONDS, &milliseconds);
+}
+
+struct ast_data *ast_data_add_password(struct ast_data *root, const char *childname,
+ const char *value)
+{
+ char *name;
+ size_t namelen = 1 + (ast_strlen_zero(value) ? 0 : strlen(value));
+ struct ast_data *res;
+
+ if (!(name = ast_malloc(namelen))) {
+ return NULL;
+ }
+
+ strcpy(name, (ast_strlen_zero(value) ? "" : value));
+
+ res = __ast_data_add(root, childname, AST_DATA_PASSWORD, name);
+ if (!res) {
+ ast_free(name);
+ }
+
+ return res;
+}
+
struct ast_data *ast_data_add_str(struct ast_data *root, const char *childname,
const char *value)
{
@@ -2127,10 +2437,30 @@ int __ast_data_add_structure(struct ast_data *root,
ast_data_add_bool(root, mapping[i].name,
mapping[i].get.AST_DATA_BOOLEAN(structure));
break;
+ case AST_DATA_PASSWORD:
+ ast_data_add_password(root, mapping[i].name,
+ mapping[i].get.AST_DATA_PASSWORD(structure));
+ break;
+ case AST_DATA_TIMESTAMP:
+ ast_data_add_timestamp(root, mapping[i].name,
+ mapping[i].get.AST_DATA_TIMESTAMP(structure));
+ break;
+ case AST_DATA_SECONDS:
+ ast_data_add_seconds(root, mapping[i].name,
+ mapping[i].get.AST_DATA_SECONDS(structure));
+ break;
+ case AST_DATA_MILLISECONDS:
+ ast_data_add_milliseconds(root, mapping[i].name,
+ mapping[i].get.AST_DATA_MILLISECONDS(structure));
+ break;
case AST_DATA_STRING:
ast_data_add_str(root, mapping[i].name,
mapping[i].get.AST_DATA_STRING(structure));
break;
+ case AST_DATA_CHARACTER:
+ ast_data_add_char(root, mapping[i].name,
+ mapping[i].get.AST_DATA_CHARACTER(structure));
+ break;
case AST_DATA_CONTAINER:
break;
case AST_DATA_IPADDR:
@@ -2277,6 +2607,21 @@ int ast_data_retrieve(struct ast_data *tree, const char *path,
case AST_DATA_STRING:
content->value.AST_DATA_STRING = node->payload.str;
break;
+ case AST_DATA_PASSWORD:
+ content->value.AST_DATA_PASSWORD = node->payload.str;
+ break;
+ case AST_DATA_TIMESTAMP:
+ content->value.AST_DATA_TIMESTAMP = node->payload.uint;
+ break;
+ case AST_DATA_SECONDS:
+ content->value.AST_DATA_SECONDS = node->payload.uint;
+ break;
+ case AST_DATA_MILLISECONDS:
+ content->value.AST_DATA_MILLISECONDS = node->payload.uint;
+ break;
+ case AST_DATA_CHARACTER:
+ content->value.AST_DATA_CHARACTER = node->payload.character;
+ break;
case AST_DATA_INTEGER:
content->value.AST_DATA_INTEGER = node->payload.sint;
break;
@@ -2310,7 +2655,12 @@ static const struct {
enum ast_data_type type;
int color;
} data_result_color[] = {
- { AST_DATA_STRING, COLOR_CYAN },
+ { AST_DATA_STRING, COLOR_BLUE },
+ { AST_DATA_PASSWORD, COLOR_BRBLUE },
+ { AST_DATA_TIMESTAMP, COLOR_CYAN },
+ { AST_DATA_SECONDS, COLOR_MAGENTA },
+ { AST_DATA_MILLISECONDS, COLOR_BRMAGENTA },
+ { AST_DATA_CHARACTER, COLOR_GRAY },
{ AST_DATA_INTEGER, COLOR_RED },
{ AST_DATA_UNSIGNED_INTEGER, COLOR_RED },
{ AST_DATA_DOUBLE, COLOR_RED },
@@ -2373,16 +2723,43 @@ static void data_result_print_cli_node(int fd, const struct ast_data *node, uint
ast_str_append(&output, 0, "%s%s: %p\n", ast_str_buffer(tabs),
node->name, node->payload.ptr);
break;
+ case AST_DATA_PASSWORD:
+ ast_str_append(&output, 0, "%s%s: \"%s\"\n",
+ ast_str_buffer(tabs),
+ node->name,
+ node->payload.str);
+ break;
case AST_DATA_STRING:
ast_str_append(&output, 0, "%s%s: \"%s\"\n",
ast_str_buffer(tabs),
node->name,
node->payload.str);
break;
+ case AST_DATA_CHARACTER:
+ ast_str_append(&output, 0, "%s%s: \'%c\'\n",
+ ast_str_buffer(tabs),
+ node->name,
+ node->payload.character);
+ break;
case AST_DATA_CONTAINER:
ast_str_append(&output, 0, "%s%s\n", ast_str_buffer(tabs),
node->name);
break;
+ case AST_DATA_TIMESTAMP:
+ ast_str_append(&output, 0, "%s%s: %d\n", ast_str_buffer(tabs),
+ node->name,
+ node->payload.uint);
+ break;
+ case AST_DATA_SECONDS:
+ ast_str_append(&output, 0, "%s%s: %d\n", ast_str_buffer(tabs),
+ node->name,
+ node->payload.uint);
+ break;
+ case AST_DATA_MILLISECONDS:
+ ast_str_append(&output, 0, "%s%s: %d\n", ast_str_buffer(tabs),
+ node->name,
+ node->payload.uint);
+ break;
case AST_DATA_INTEGER:
ast_str_append(&output, 0, "%s%s: %d\n", ast_str_buffer(tabs),
node->name,
@@ -2470,6 +2847,8 @@ static void data_result_print_cli(int fd, const struct ast_data *root)
ast_free(output);
__data_result_print_cli(fd, root, 0);
+
+ ast_cli(fd, "\n");
}
/*!
@@ -2644,12 +3023,21 @@ static void data_result_manager_output(struct mansession *s, const char *name,
case AST_DATA_INTEGER:
astman_append(s, ": %d\r\n", node->payload.sint);
break;
+ case AST_DATA_TIMESTAMP:
+ case AST_DATA_SECONDS:
+ case AST_DATA_MILLISECONDS:
case AST_DATA_UNSIGNED_INTEGER:
astman_append(s, ": %u\r\n", node->payload.uint);
break;
+ case AST_DATA_PASSWORD:
+ astman_append(s, ": %s\r\n", node->payload.str);
+ break;
case AST_DATA_STRING:
astman_append(s, ": %s\r\n", node->payload.str);
break;
+ case AST_DATA_CHARACTER:
+ astman_append(s, ": %c\r\n", node->payload.character);
+ break;
case AST_DATA_IPADDR:
astman_append(s, ": %s\r\n", ast_inet_ntoa(node->payload.ipaddr));
break;
@@ -2712,6 +3100,34 @@ static int manager_data_get(struct mansession *s, const struct message *m)
return RESULT_SUCCESS;
}
+int ast_data_add_codecs(struct ast_data *root, const char *node_name, format_t capability)
+{
+ struct ast_data *codecs, *codec;
+ size_t fmlist_size;
+ const struct ast_format_list *fmlist;
+ int x;
+
+ codecs = ast_data_add_node(root, node_name);
+ if (!codecs) {
+ return -1;
+ }
+ fmlist = ast_get_format_list(&fmlist_size);
+ for (x = 0; x < fmlist_size; x++) {
+ if (fmlist[x].bits & capability) {
+ codec = ast_data_add_node(codecs, "codec");
+ if (!codec) {
+ return -1;
+ }
+ ast_data_add_str(codec, "name", fmlist[x].name);
+ ast_data_add_int(codec, "samplespersecond", fmlist[x].samplespersecond);
+ ast_data_add_str(codec, "description", fmlist[x].desc);
+ ast_data_add_int(codec, "frame_length", fmlist[x].fr_len);
+ }
+ }
+
+ return 0;
+}
+
#ifdef TEST_FRAMEWORK
/*!
@@ -2753,10 +3169,6 @@ static int test_data_full_provider(const struct ast_data_search *search,
.a_uint = 20
};
- if (ast_data_search_cmp_structure(search, test_structure, &local_test_structure, "test_structure")) {
- return 0;
- }
-
test_structure = ast_data_add_node(root, "test_structure");
if (!test_structure) {
ast_debug(1, "Internal data api error\n");
@@ -2766,6 +3178,10 @@ static int test_data_full_provider(const struct ast_data_search *search,
/* add the complete structure. */
ast_data_add_structure(test_structure, test_structure, &local_test_structure);
+ if (!ast_data_search_match(search, test_structure)) {
+ ast_data_remove_node(root, test_structure);
+ }
+
return 0;
}
diff --git a/main/indications.c b/main/indications.c
index 0687648bc..b2d65bcc7 100644
--- a/main/indications.c
+++ b/main/indications.c
@@ -38,9 +38,23 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/cli.h"
#include "asterisk/module.h"
#include "asterisk/astobj2.h"
+#include "asterisk/data.h"
#include "asterisk/_private.h" /* _init(), _reload() */
+#define DATA_EXPORT_TONE_ZONE(MEMBER) \
+ MEMBER(ast_tone_zone, country, AST_DATA_STRING) \
+ MEMBER(ast_tone_zone, description, AST_DATA_STRING) \
+ MEMBER(ast_tone_zone, nrringcadence, AST_DATA_UNSIGNED_INTEGER)
+
+AST_DATA_STRUCTURE(ast_tone_zone, DATA_EXPORT_TONE_ZONE);
+
+#define DATA_EXPORT_TONE_ZONE_SOUND(MEMBER) \
+ MEMBER(ast_tone_zone_sound, name, AST_DATA_STRING) \
+ MEMBER(ast_tone_zone_sound, data, AST_DATA_STRING)
+
+AST_DATA_STRUCTURE(ast_tone_zone_sound, DATA_EXPORT_TONE_ZONE_SOUND);
+
/* Globals */
static const char config[] = "indications.conf";
@@ -1102,6 +1116,33 @@ static int ast_tone_zone_cmp(void *obj, void *arg, int flags)
CMP_MATCH | CMP_STOP : 0;
}
+int ast_tone_zone_data_add_structure(struct ast_data *tree, struct ast_tone_zone *zone)
+{
+ struct ast_data *data_zone_sound;
+ struct ast_tone_zone_sound *s;
+
+ ast_data_add_structure(ast_tone_zone, tree, zone);
+
+ if (AST_LIST_EMPTY(&zone->tones)) {
+ return 0;
+ }
+
+ data_zone_sound = ast_data_add_node(tree, "tones");
+ if (!data_zone_sound) {
+ return -1;
+ }
+
+ ast_tone_zone_lock(zone);
+
+ AST_LIST_TRAVERSE(&zone->tones, s, entry) {
+ ast_data_add_structure(ast_tone_zone_sound, data_zone_sound, s);
+ }
+
+ ast_tone_zone_unlock(zone);
+
+ return 0;
+}
+
/*! \brief Load indications module */
int ast_indications_init(void)
{
diff --git a/main/pbx.c b/main/pbx.c
index 24203ede7..dbc4db497 100644
--- a/main/pbx.c
+++ b/main/pbx.c
@@ -9717,6 +9717,57 @@ static void device_state_cb(const struct ast_event *event, void *unused)
}
}
+/*!
+ * \internal
+ * \brief Implements the hints data provider.
+ */
+static int hints_data_provider_get(const struct ast_data_search *search,
+ struct ast_data *data_root)
+{
+ struct ast_data *data_hint;
+ struct ast_hint *hint;
+ int watchers;
+ struct ast_state_cb *watcher;
+
+ AST_RWLIST_RDLOCK(&hints);
+ if (AST_RWLIST_EMPTY(&hints)) {
+ AST_RWLIST_UNLOCK(&hints);
+ return 0;
+ }
+
+ AST_RWLIST_TRAVERSE(&hints, hint, list) {
+ watchers = 0;
+ AST_LIST_TRAVERSE(&hint->callbacks, watcher, entry) {
+ watchers++;
+ }
+ data_hint = ast_data_add_node(data_root, "hint");
+ if (!data_hint) {
+ continue;
+ }
+ ast_data_add_str(data_hint, "extension", ast_get_extension_name(hint->exten));
+ ast_data_add_str(data_hint, "context", ast_get_context_name(ast_get_extension_context(hint->exten)));
+ ast_data_add_str(data_hint, "application", ast_get_extension_app(hint->exten));
+ ast_data_add_str(data_hint, "state", ast_extension_state2str(hint->laststate));
+ ast_data_add_int(data_hint, "watchers", watchers);
+
+ if (!ast_data_search_match(search, data_hint)) {
+ ast_data_remove_node(data_root, data_hint);
+ }
+ }
+ AST_RWLIST_UNLOCK(&hints);
+
+ return 0;
+}
+
+static const struct ast_data_handler hints_data_provider = {
+ .version = AST_DATA_HANDLER_VERSION,
+ .get = hints_data_provider_get
+};
+
+static const struct ast_data_entry pbx_data_providers[] = {
+ AST_DATA_ENTRY("asterisk/core/hints", &hints_data_provider),
+};
+
int load_pbx(void)
{
int x;
@@ -9729,6 +9780,7 @@ int load_pbx(void)
ast_verb(1, "Registering builtin applications:\n");
ast_cli_register_multiple(pbx_cli, ARRAY_LEN(pbx_cli));
+ ast_data_register_multiple_core(pbx_data_providers, ARRAY_LEN(pbx_data_providers));
__ast_custom_function_register(&exception_function, NULL);
__ast_custom_function_register(&testtime_function, NULL);