diff --git a/funcs/func_presencestate.c b/funcs/func_presencestate.c index 8c916e891cf6f746ea564530efe00c33408394e2..26b311d0e194cc821f8a69ae1b891a9183e16dae 100644 --- a/funcs/func_presencestate.c +++ b/funcs/func_presencestate.c @@ -71,7 +71,9 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") <optionlist> <option name="e"> <para>On Write - Use this option when the subtype and message provided are Base64 - encoded. On Read - Retrieves message/subtype in Base64 encoded form.</para> + encoded. The values will be stored encoded within Asterisk, but all consumers of + the presence state (e.g. the SIP presence event package) will receive decoded values.</para> + <para>On Read - Retrieves unencoded message/subtype in Base64 encoded form.</para> </option> </optionlist> </parameter> @@ -229,7 +231,18 @@ static int presence_write(struct ast_channel *chan, const char *cmd, char *data, ast_db_put(astdb_family, data, value); - ast_presence_state_changed_literal(state, subtype, message, tmp); + if (strchr(options, 'e')) { + /* Let's decode the values before sending them to stasis, yes? */ + char decoded_subtype[256] = { 0, }; + char decoded_message[256] = { 0, }; + + ast_base64decode((unsigned char *) decoded_subtype, subtype, sizeof(decoded_subtype) -1); + ast_base64decode((unsigned char *) decoded_message, message, sizeof(decoded_message) -1); + + ast_presence_state_changed_literal(state, decoded_subtype, decoded_message, tmp); + } else { + ast_presence_state_changed_literal(state, subtype, message, tmp); + } return 0; } @@ -643,12 +656,39 @@ AST_TEST_DEFINE(test_invalid_parse_data) return res; } +#define PRES_STATE "away" +#define PRES_SUBTYPE "down the hall" +#define PRES_MESSAGE "Quarterly financial meeting" + struct test_cb_data { struct ast_presence_state_message *presence_state; /* That's right. I'm using a semaphore */ sem_t sem; }; +static struct test_cb_data *test_cb_data_alloc(void) +{ + struct test_cb_data *cb_data = ast_calloc(1, sizeof(*cb_data)); + + if (!cb_data) { + return NULL; + } + + if (sem_init(&cb_data->sem, 0, 0)) { + ast_free(cb_data); + return NULL; + } + + return cb_data; +} + +static void test_cb_data_destroy(struct test_cb_data *cb_data) +{ + ao2_cleanup(cb_data->presence_state); + sem_destroy(&cb_data->sem); + ast_free(cb_data); +} + static void test_cb(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg) { struct test_cb_data *cb_data = userdata; @@ -661,15 +701,48 @@ static void test_cb(void *userdata, struct stasis_subscription *sub, struct stas sem_post(&cb_data->sem); } -/* XXX This test could probably stand to be moved since - * it does not test func_presencestate but rather code in - * presencestate.h and presencestate.c. However, the convenience - * of presence_write() makes this a nice location for this test. - */ -AST_TEST_DEFINE(test_presence_state_change) +static enum ast_test_result_state presence_change_common(struct ast_test *test, + const char *state, const char *subtype, const char *message, const char *options, + char *out_state, size_t out_state_size, + char *out_subtype, size_t out_subtype_size, + char *out_message, size_t out_message_size) { + RAII_VAR(struct test_cb_data *, cb_data, test_cb_data_alloc(), test_cb_data_destroy); struct stasis_subscription *test_sub; - struct test_cb_data *cb_data; + char pres[1301]; + + if (!(test_sub = stasis_subscribe(ast_presence_state_topic_all(), test_cb, cb_data))) { + return AST_TEST_FAIL; + } + + if (ast_strlen_zero(options)) { + snprintf(pres, sizeof(pres), "%s,%s,%s", state, subtype, message); + } else { + snprintf(pres, sizeof(pres), "%s,%s,%s,%s", state, subtype, message, options); + } + + if (presence_write(NULL, "PRESENCESTATE", "CustomPresence:TestPresenceStateChange", pres)) { + test_sub = stasis_unsubscribe_and_join(test_sub); + return AST_TEST_FAIL; + } + + sem_wait(&cb_data->sem); + + ast_copy_string(out_state, ast_presence_state2str(cb_data->presence_state->state), out_state_size); + ast_copy_string(out_subtype, cb_data->presence_state->subtype, out_subtype_size); + ast_copy_string(out_message, cb_data->presence_state->message, out_message_size); + + test_sub = stasis_unsubscribe_and_join(test_sub); + ast_db_del("CustomPresence", "TestPresenceStateChange"); + + return AST_TEST_PASS; +} + +AST_TEST_DEFINE(test_presence_state_change) +{ + char out_state[32]; + char out_subtype[32]; + char out_message[32]; switch (cmd) { case TEST_INIT: @@ -683,34 +756,66 @@ AST_TEST_DEFINE(test_presence_state_change) break; } - cb_data = ast_calloc(1, sizeof(*cb_data)); - if (!cb_data) { + if (presence_change_common(test, PRES_STATE, PRES_SUBTYPE, PRES_MESSAGE, NULL, + out_state, sizeof(out_state), + out_subtype, sizeof(out_subtype), + out_message, sizeof(out_message)) == AST_TEST_FAIL) { return AST_TEST_FAIL; } - if (!(test_sub = stasis_subscribe(ast_presence_state_topic_all(), test_cb, cb_data))) { + if (strcmp(out_state, PRES_STATE) || + strcmp(out_subtype, PRES_SUBTYPE) || + strcmp(out_message, PRES_MESSAGE)) { + ast_test_status_update(test, "Unexpected presence values, %s != %s, %s != %s, or %s != %s\n", + PRES_STATE, out_state, + PRES_SUBTYPE, out_subtype, + PRES_MESSAGE, out_message); return AST_TEST_FAIL; } - if (sem_init(&cb_data->sem, 0, 0)) { - return AST_TEST_FAIL; - } + return AST_TEST_PASS; +} - presence_write(NULL, "PRESENCESTATE", "CustomPresence:TestPresenceStateChange", "away,down the hall,Quarterly financial meeting"); - sem_wait(&cb_data->sem); - if (cb_data->presence_state->state != AST_PRESENCE_AWAY || - strcmp(cb_data->presence_state->provider, "CustomPresence:TestPresenceStateChange") || - strcmp(cb_data->presence_state->subtype, "down the hall") || - strcmp(cb_data->presence_state->message, "Quarterly financial meeting")) { - return AST_TEST_FAIL; +AST_TEST_DEFINE(test_presence_state_base64_encode) +{ + char out_state[32]; + char out_subtype[32]; + char out_message[32]; + char encoded_subtype[64]; + char encoded_message[64]; + + switch (cmd) { + case TEST_INIT: + info->name = "test_presence_state_base64_encode"; + info->category = "/funcs/func_presence/"; + info->summary = "presence state base64 encoding"; + info->description = + "Ensure that base64-encoded presence state is stored base64-encoded but\n" + "is presented to consumers decoded."; + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; } - test_sub = stasis_unsubscribe_and_join(test_sub); + ast_base64encode(encoded_subtype, (unsigned char *) PRES_SUBTYPE, strlen(PRES_SUBTYPE), sizeof(encoded_subtype) - 1); + ast_base64encode(encoded_message, (unsigned char *) PRES_MESSAGE, strlen(PRES_MESSAGE), sizeof(encoded_message) - 1); - ao2_cleanup(cb_data->presence_state); - ast_free((char *)cb_data); + if (presence_change_common(test, PRES_STATE, encoded_subtype, encoded_message, "e", + out_state, sizeof(out_state), + out_subtype, sizeof(out_subtype), + out_message, sizeof(out_message)) == AST_TEST_FAIL) { + return AST_TEST_FAIL; + } - ast_db_del("CustomPresence", "TestPresenceStateChange"); + if (strcmp(out_state, PRES_STATE) || + strcmp(out_subtype, PRES_SUBTYPE) || + strcmp(out_message, PRES_MESSAGE)) { + ast_test_status_update(test, "Unexpected presence values, %s != %s, %s != %s, or %s != %s\n", + PRES_STATE, out_state, + PRES_SUBTYPE, out_subtype, + PRES_MESSAGE, out_message); + return AST_TEST_FAIL; + } return AST_TEST_PASS; } @@ -728,6 +833,7 @@ static int unload_module(void) AST_TEST_UNREGISTER(test_valid_parse_data); AST_TEST_UNREGISTER(test_invalid_parse_data); AST_TEST_UNREGISTER(test_presence_state_change); + AST_TEST_UNREGISTER(test_presence_state_base64_encode); #endif return res; } @@ -767,6 +873,7 @@ static int load_module(void) AST_TEST_REGISTER(test_valid_parse_data); AST_TEST_REGISTER(test_invalid_parse_data); AST_TEST_REGISTER(test_presence_state_change); + AST_TEST_REGISTER(test_presence_state_base64_encode); #endif return res;