diff --git a/coreapi/friend.c b/coreapi/friend.c index 24960a7aaec782685d40b21a93f2aeaeb401f9f1..a7631bab5c0816ccc5ff29008183872f67c933b5 100644 --- a/coreapi/friend.c +++ b/coreapi/friend.c @@ -955,34 +955,87 @@ LinphoneOnlineStatus linphone_friend_get_status(const LinphoneFriend *lf) { } const LinphonePresenceModel *linphone_friend_get_presence_model(const LinphoneFriend *lf) { - const LinphonePresenceModel *presence = NULL; + const LinphonePresenceModel *result = NULL; LinphoneFriend *const_lf = (LinphoneFriend *)lf; const bctbx_list_t *addrs = linphone_friend_get_addresses(const_lf); bctbx_list_t *phones = NULL; bctbx_list_t *it; + time_t presence_model_latest_timestamp = 0; for (it = (bctbx_list_t *)addrs; it != NULL; it = it->next) { LinphoneAddress *addr = (LinphoneAddress *)it->data; char *uri = linphone_address_as_string_uri_only(addr); - presence = linphone_friend_get_presence_model_for_uri_or_tel(const_lf, uri); + const LinphonePresenceModel *presence = linphone_friend_get_presence_model_for_uri_or_tel(const_lf, uri); + if (presence) { + time_t timestamp = linphone_presence_model_get_timestamp(presence); + if (result == NULL || timestamp > presence_model_latest_timestamp) { + presence_model_latest_timestamp = timestamp; + result = presence; + } + } ms_free(uri); - if (presence) break; } - if (presence) return presence; phones = linphone_friend_get_phone_numbers(const_lf); for (it = phones; it != NULL; it = it->next) { - presence = linphone_friend_get_presence_model_for_uri_or_tel(const_lf, static_cast<const char *>(it->data)); - if (presence) break; + const char *phone_number = static_cast<const char *>(it->data); + const LinphonePresenceModel *presence = + linphone_friend_get_presence_model_for_uri_or_tel(const_lf, phone_number); + if (presence) { + time_t timestamp = linphone_presence_model_get_timestamp(presence); + if (result == NULL || timestamp > presence_model_latest_timestamp) { + presence_model_latest_timestamp = timestamp; + result = presence; + } + } } bctbx_list_free_with_data(phones, bctbx_free); - return presence; + return result; } LinphoneConsolidatedPresence linphone_friend_get_consolidated_presence(const LinphoneFriend *lf) { - const LinphonePresenceModel *model = linphone_friend_get_presence_model(lf); - if (!model) return LinphoneConsolidatedPresenceOffline; - return linphone_presence_model_get_consolidated_presence(model); + LinphoneConsolidatedPresence result = LinphoneConsolidatedPresenceOffline; + LinphoneFriend *const_lf = (LinphoneFriend *)lf; + const bctbx_list_t *addrs = linphone_friend_get_addresses(const_lf); + bctbx_list_t *phones = NULL; + bctbx_list_t *it; + + for (it = (bctbx_list_t *)addrs; it != NULL; it = it->next) { + LinphoneAddress *addr = (LinphoneAddress *)it->data; + char *uri = linphone_address_as_string_uri_only(addr); + const LinphonePresenceModel *presence = linphone_friend_get_presence_model_for_uri_or_tel(const_lf, uri); + ms_free(uri); + if (presence) { + LinphoneConsolidatedPresence consolidated = linphone_presence_model_get_consolidated_presence(presence); + if (consolidated != LinphoneConsolidatedPresenceOffline) { + result = consolidated; + if (result == LinphoneConsolidatedPresenceOnline) { + break; + } + } + } + } + if (result == LinphoneConsolidatedPresenceOnline) { + return result; + } + + phones = linphone_friend_get_phone_numbers(const_lf); + for (it = phones; it != NULL; it = it->next) { + const char *phone_number = static_cast<const char *>(it->data); + const LinphonePresenceModel *presence = + linphone_friend_get_presence_model_for_uri_or_tel(const_lf, phone_number); + if (presence) { + LinphoneConsolidatedPresence consolidated = linphone_presence_model_get_consolidated_presence(presence); + if (consolidated != LinphoneConsolidatedPresenceOffline) { + result = consolidated; + if (result == LinphoneConsolidatedPresenceOnline) { + break; + } + } + } + } + bctbx_list_free_with_data(phones, bctbx_free); + return result; } const LinphonePresenceModel *linphone_friend_get_presence_model_for_uri_or_tel(const LinphoneFriend *lf, diff --git a/coreapi/friendlist.c b/coreapi/friendlist.c index d3286fa2c2290b910e7e947ffa8f2920d5de6f15..a29254aece7af8f03acf6d314dda56c9992e1a0d 100644 --- a/coreapi/friendlist.c +++ b/coreapi/friendlist.c @@ -771,7 +771,7 @@ _linphone_friend_list_remove_friend(LinphoneFriendList *list, LinphoneFriend *lf #if defined(HAVE_SQLITE) && defined(VCARD_ENABLED) - if (lf && lf->lc && lf->lc->friends_db) { + if (lf && lf->lc && linphone_friend_list_database_storage_enabled(list)) { linphone_core_remove_friend_from_db(lf->lc, lf); } diff --git a/include/linphone/friend.h b/include/linphone/friend.h index b00cc682fa933936549d8454b131fdf7266bcd05..c467cb81d7f8dfe0248bf5041dfca446498d2277 100644 --- a/include/linphone/friend.h +++ b/include/linphone/friend.h @@ -199,7 +199,8 @@ LINPHONE_PUBLIC void linphone_friend_done(LinphoneFriend *linphone_friend); LINPHONE_PUBLIC LinphoneSubscriptionState linphone_friend_get_subscription_state(const LinphoneFriend *linphone_friend); /** - * Get the presence model of a friend + * Get the presence model of a friend. If a friend has more than one SIP address and phone number, + * this method will return the most recent presence model using linphone_presence_model_get_timestamp(). * @param linphone_friend A #LinphoneFriend object @notnil * @return A #LinphonePresenceModel object, or NULL if the friend do not have presence information (in which case he is * considered offline). @maybenil @@ -208,6 +209,7 @@ LINPHONE_PUBLIC const LinphonePresenceModel *linphone_friend_get_presence_model( /** * Get the consolidated presence of a friend. + * It will return the "most open" presence found if more than one presence model are found. * @param linphone_friend #LinphoneFriend object @notnil * @return The #LinphoneConsolidatedPresence of the friend */ diff --git a/tester/presence_server_tester.c b/tester/presence_server_tester.c index 347569dfd7bfe14976694b5936525b7080882c47..782758173d9acf47e991cda3b034371f033ebcd1 100644 --- a/tester/presence_server_tester.c +++ b/tester/presence_server_tester.c @@ -700,6 +700,75 @@ static void test_presence_list_without_compression(void) { test_presence_list_base(FALSE); } +static void test_presence_list_same_friend_two_addresses(void) { + LinphoneCoreManager *laure = linphone_core_presence_manager_new("laure_tcp_rc"); + linphone_core_set_user_agent(laure->lc, "bypass", NULL); + LinphoneCoreManager *marie = linphone_core_presence_manager_new("marie_rc"); + linphone_core_set_user_agent(marie->lc, "bypass", NULL); + LinphoneCoreManager *pauline = + linphone_core_presence_manager_new(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc"); + linphone_core_set_user_agent(pauline->lc, "bypass", NULL); + const char *rls_uri = "sip:rls@sip.example.org"; + LinphoneFriendList *lfl; + LinphoneFriend *lf; + const char *marie_identity; + bctbx_list_t *lcs = NULL; + + marie_identity = get_identity(marie); + + enable_publish_verified(marie, TRUE); + enable_publish_verified(pauline, TRUE); + enable_publish_verified(laure, TRUE); + + lcs = bctbx_list_append(lcs, laure->lc); + lcs = bctbx_list_append(lcs, marie->lc); + lcs = bctbx_list_append(lcs, pauline->lc); + + linphone_core_set_consolidated_presence(marie->lc, LinphoneConsolidatedPresenceBusy); + linphone_core_set_consolidated_presence(pauline->lc, LinphoneConsolidatedPresenceOnline); + + lfl = linphone_core_create_friend_list(laure->lc); + linphone_friend_list_set_rls_uri(lfl, rls_uri); + lf = linphone_core_create_friend_with_address(laure->lc, marie_identity); + linphone_friend_add_address(lf, pauline->identity); + linphone_friend_list_add_friend(lfl, lf); + linphone_core_remove_friend_list(laure->lc, linphone_core_get_default_friend_list(laure->lc)); + linphone_core_add_friend_list(laure->lc, lfl); + linphone_friend_unref(lf); + + linphone_friend_list_update_subscriptions(lfl); + + wait_for_list(lcs, &laure->stat.number_of_NotifyPresenceReceived, 6, + 4000); // one event by known friend by notify, 4 if test is started independently in + BC_ASSERT_GREATER(laure->stat.number_of_NotifyPresenceReceived, 3, int, "%d"); + BC_ASSERT_LOWER(laure->stat.number_of_NotifyPresenceReceived, 6, int, "%d"); + BC_ASSERT_GREATER( + linphone_friend_list_get_expected_notification_version(linphone_core_get_default_friend_list(laure->lc)), 1, + int, "%d"); + BC_ASSERT_LOWER( + linphone_friend_list_get_expected_notification_version(linphone_core_get_default_friend_list(laure->lc)), 2, + int, "%d"); + lf = linphone_friend_list_find_friend_by_address(linphone_core_get_default_friend_list(laure->lc), + get_identity_address(marie)); + if (!BC_ASSERT_PTR_NOT_NULL(lf)) goto end; + BC_ASSERT_EQUAL(linphone_friend_get_consolidated_presence(lf), LinphoneConsolidatedPresenceOnline, int, "%d"); + if (!BC_ASSERT_TRUE(linphone_friend_is_presence_received(lf))) goto end; + + const LinphonePresenceModel *marie_presence_model = + linphone_friend_get_presence_model_for_uri_or_tel(lf, marie_identity); + BC_ASSERT_PTR_NOT_NULL(marie_presence_model); + LinphoneConsolidatedPresence marie_presence = + linphone_presence_model_get_consolidated_presence(marie_presence_model); + BC_ASSERT_EQUAL(marie_presence, LinphoneConsolidatedPresenceBusy, int, "%d"); + +end: + linphone_friend_list_unref(lfl); + bctbx_list_free(lcs); + linphone_core_manager_destroy(laure); + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + #if 0 static void test_presence_list_subscribe_before_publish(void) { LinphoneCoreManager *laure = linphone_core_manager_new("laure_tcp_rc"); @@ -1703,6 +1772,7 @@ static void publish_with_dual_identity(void) { BC_ASSERT_EQUAL(pauline->stat.number_of_LinphonePublishOk, 4, int, "%i"); linphone_core_manager_destroy(pauline); } + static void publish_with_network_state_changes(void) { LinphoneCoreManager *marie = linphone_core_manager_new("marie_rc"); LinphoneCoreManager *pauline = @@ -2547,6 +2617,7 @@ test_t presence_server_tests[] = { TEST_NO_TAG("Disabled presence", subscribe_presence_disabled), TEST_NO_TAG("Presence list", test_presence_list), TEST_NO_TAG("Presence list without compression", test_presence_list_without_compression), + TEST_NO_TAG("Presence list with two SIP addresses for same friend", test_presence_list_same_friend_two_addresses), TEST_NO_TAG("Presence list, subscription expiration for unknown contact", test_presence_list_subscription_expire_for_unknown), TEST_NO_TAG("Presence list, silent subscription expiration", presence_list_subscribe_dialog_expire),