summaryrefslogtreecommitdiff
path: root/main/presencestate.c
diff options
context:
space:
mode:
Diffstat (limited to 'main/presencestate.c')
-rw-r--r--main/presencestate.c187
1 files changed, 158 insertions, 29 deletions
diff --git a/main/presencestate.c b/main/presencestate.c
index 07df7429d..529979bac 100644
--- a/main/presencestate.c
+++ b/main/presencestate.c
@@ -66,6 +66,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/presencestate.h"
#include "asterisk/pbx.h"
#include "asterisk/app.h"
+#include "asterisk/test.h"
/*! \brief Device state strings for printing */
static const struct {
@@ -146,42 +147,74 @@ static enum ast_presence_state presence_state_cached(const char *presence_provid
static enum ast_presence_state ast_presence_state_helper(const char *presence_provider, char **subtype, char **message, int check_cache)
{
- struct presence_state_provider *provider;
- char *address;
- char *label = ast_strdupa(presence_provider);
- int res = AST_PRESENCE_INVALID;
-
- if (check_cache) {
- res = presence_state_cached(presence_provider, subtype, message);
- if (res != AST_PRESENCE_INVALID) {
- return res;
+ char *labels = ast_strdupa(presence_provider);
+ char *label;
+ enum ast_presence_state state = AST_PRESENCE_INVALID;
+ enum ast_presence_state state_order[] = {
+ [AST_PRESENCE_INVALID] = 0,
+ [AST_PRESENCE_NOT_SET] = 1,
+ [AST_PRESENCE_AVAILABLE] = 2,
+ [AST_PRESENCE_UNAVAILABLE] = 3,
+ [AST_PRESENCE_CHAT] = 4,
+ [AST_PRESENCE_AWAY] = 5,
+ [AST_PRESENCE_XA] = 6,
+ [AST_PRESENCE_DND] = 7
+ };
+
+ while ((label = strsep(&labels, "&"))) {
+ enum ast_presence_state next_state = AST_PRESENCE_INVALID;
+ char *next_subtype = NULL;
+ char *next_message = NULL;
+
+ if (check_cache) {
+ next_state = presence_state_cached(label, &next_subtype, &next_message);
}
- }
- if ((address = strchr(label, ':'))) {
- *address = '\0';
- address++;
- } else {
- ast_log(LOG_WARNING, "No label found for presence state provider: %s\n", presence_provider);
- return res;
- }
+ if (next_state == AST_PRESENCE_INVALID) {
+ struct presence_state_provider *provider;
+ const struct ast_channel_tech *chan_tech;
+ char *address;
+
+ if ((address = strchr(label, '/'))) {
+ *address++ = '\0';
+
+ if ((chan_tech = ast_get_channel_tech(label)) && chan_tech->presencestate) {
+ next_state = chan_tech->presencestate(address, &next_subtype, &next_message);
+ }
+ } else if ((address = strchr(label, ':'))) {
+ *address++ = '\0';
+
+ AST_RWLIST_RDLOCK(&presence_state_providers);
+ AST_RWLIST_TRAVERSE(&presence_state_providers, provider, list) {
+ ast_debug(5, "Checking provider %s with %s\n", provider->label, label);
+
+ if (!strcasecmp(provider->label, label)) {
+ next_state = provider->callback(address, &next_subtype, &next_message);
+ break;
+ }
+ }
+ AST_RWLIST_UNLOCK(&presence_state_providers);
+
+ if (!provider) {
+ ast_log(LOG_WARNING, "No provider found for label: %s\n", label);
+ }
+ } else {
+ ast_log(LOG_WARNING, "No label found for presence state provider: %s\n", label);
+ }
+ }
- AST_RWLIST_RDLOCK(&presence_state_providers);
- AST_RWLIST_TRAVERSE(&presence_state_providers, provider, list) {
- ast_debug(5, "Checking provider %s with %s\n", provider->label, label);
+ if (state_order[next_state] > state_order[state]) {
+ state = next_state;
- if (!strcasecmp(provider->label, label)) {
- res = provider->callback(address, subtype, message);
- break;
- }
- }
- AST_RWLIST_UNLOCK(&presence_state_providers);
+ ast_free(*subtype);
+ ast_free(*message);
- if (!provider) {
- ast_log(LOG_WARNING, "No provider found for label %s\n", label);
+ *subtype = next_subtype;
+ *message = next_message;
+ }
}
- return res;
+ return state;
}
enum ast_presence_state ast_presence_state(const char *presence_provider, char **subtype, char **message)
@@ -354,6 +387,99 @@ static const char *presence_state_get_id(struct stasis_message *msg)
return presence_state->provider;
}
+#if defined(TEST_FRAMEWORK)
+
+#define TEST_CATEGORY "/main/presence"
+
+static int presence_test_alice_state = AST_PRESENCE_UNAVAILABLE;
+static int presence_test_bob_state = AST_PRESENCE_UNAVAILABLE;
+
+static int presence_test_presencestate(const char *label, char **subtype, char **message)
+{
+ if (!strcmp(label, "Alice")) {
+ return presence_test_alice_state;
+ } else if (!strcmp(label, "Bob")) {
+ return presence_test_bob_state;
+ } else {
+ return AST_PRESENCE_UNAVAILABLE;
+ }
+}
+
+static struct ast_channel_tech presence_test_tech = {
+ .type = "PresenceTestChannel",
+ .description = "Presence test technology",
+ .presencestate = presence_test_presencestate,
+};
+
+AST_TEST_DEFINE(test_presence_chan)
+{
+ int res = AST_TEST_FAIL;
+ char provider[80];
+ enum ast_presence_state state;
+ char *subtype = NULL, *message = NULL;
+
+ switch (cmd) {
+ case TEST_INIT:
+ info->name = "channel_presence";
+ info->category = TEST_CATEGORY;
+ info->summary = "Channel presence state tests";
+ info->description = "Creates test channel technology and then test the presence state callback";
+ return AST_TEST_NOT_RUN;
+ case TEST_EXECUTE:
+ break;
+ }
+
+ if (ast_channel_register(&presence_test_tech)) {
+ ast_log(LOG_WARNING, "Unable to register channel type '%s'\n", presence_test_tech.type);
+ goto presence_test_cleanup;
+ }
+
+ /* Check Alice's state */
+ snprintf(provider, sizeof(provider), "%s/Alice", presence_test_tech.type);
+
+ presence_test_alice_state = AST_PRESENCE_AVAILABLE;
+ state = ast_presence_state_nocache(provider, &subtype, &message);
+
+ if (state != presence_test_alice_state) {
+ ast_log(LOG_WARNING, "Presence state of '%s' returned '%s' instead of the expected value '%s'\n",
+ provider, ast_presence_state2str(state), ast_presence_state2str(presence_test_alice_state));
+ goto presence_test_cleanup;
+ }
+
+ /* Check Alice's and Bob's state, Alice's should win as DND > AVAILABLE */
+ snprintf(provider, sizeof(provider), "%s/Alice&%s/Bob", presence_test_tech.type, presence_test_tech.type);
+
+ presence_test_alice_state = AST_PRESENCE_DND;
+ presence_test_bob_state = AST_PRESENCE_UNAVAILABLE;
+ state = ast_presence_state_nocache(provider, &subtype, &message);
+
+ if (state != presence_test_alice_state) {
+ ast_log(LOG_WARNING, "Presence state of '%s' returned '%s' instead of the expected value '%s'\n",
+ provider, ast_presence_state2str(state), ast_presence_state2str(presence_test_alice_state));
+ goto presence_test_cleanup;
+ }
+
+ /* Check Alice's and Bob's state, Bob's should now win as AVAILABLE < UNAVAILABLE */
+ presence_test_alice_state = AST_PRESENCE_AVAILABLE;
+ state = ast_presence_state_nocache(provider, &subtype, &message);
+
+ if (state != presence_test_bob_state) {
+ ast_log(LOG_WARNING, "Presence state of '%s' returned '%s' instead of the expected value '%s'\n",
+ provider, ast_presence_state2str(state), ast_presence_state2str(presence_test_bob_state));
+ goto presence_test_cleanup;
+ }
+
+ res = AST_TEST_PASS;
+
+presence_test_cleanup:
+ ast_channel_unregister(&presence_test_tech);
+ ast_free(subtype);
+ ast_free(message);
+
+ return res;
+}
+#endif
+
static void presence_state_engine_cleanup(void)
{
ao2_cleanup(presence_state_topic_all);
@@ -362,6 +488,7 @@ static void presence_state_engine_cleanup(void)
presence_state_cache = NULL;
presence_state_topic_cached = stasis_caching_unsubscribe_and_join(presence_state_topic_cached);
STASIS_MESSAGE_TYPE_CLEANUP(ast_presence_state_message_type);
+ AST_TEST_UNREGISTER(test_presence_chan);
}
int ast_presence_state_engine_init(void)
@@ -387,6 +514,8 @@ int ast_presence_state_engine_init(void)
return -1;
}
+ AST_TEST_REGISTER(test_presence_chan);
+
return 0;
}