diff --git a/coreapi/friend.c b/coreapi/friend.c index 0fdc8f6049a4b831d5d62a9291e0e9ba1ad2ebc3..33c7174d361d50ad325fe3ffc4d4759dadf74d07 100644 --- a/coreapi/friend.c +++ b/coreapi/friend.c @@ -1761,3 +1761,86 @@ int linphone_friend_get_capabilities(const LinphoneFriend *lf) { bool_t linphone_friend_has_capability(const LinphoneFriend *lf, const LinphoneFriendCapability capability) { return static_cast<bool_t>(linphone_friend_get_capabilities(lf) & capability); } + +bool_t linphone_friend_has_capability_with_version(const LinphoneFriend *lf, const LinphoneFriendCapability capability, float version) { + const LinphonePresenceModel *presence = NULL; + const bctbx_list_t* addrs = linphone_friend_get_addresses(lf); + bctbx_list_t* phones = linphone_friend_get_phone_numbers(lf); + bctbx_list_t *it; + bool_t result = FALSE; + + 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(lf, uri); + ms_free(uri); + + if (!presence) continue; + if(linphone_presence_model_has_capability_with_version(presence, capability, version)) result = TRUE; + } + for (it = phones; it!= NULL; it = it->next) { + presence = linphone_friend_get_presence_model_for_uri_or_tel(lf, reinterpret_cast<const char *>(it->data)); + + if (!presence) continue; + if(linphone_presence_model_has_capability_with_version(presence, capability, version)) result = TRUE; + } + bctbx_list_free(phones); + + return result; +} + +bool_t linphone_friend_has_capability_with_version_or_more(const LinphoneFriend *lf, const LinphoneFriendCapability capability, float version) { + const LinphonePresenceModel *presence = NULL; + const bctbx_list_t* addrs = linphone_friend_get_addresses(lf); + bctbx_list_t* phones = linphone_friend_get_phone_numbers(lf); + bctbx_list_t *it; + bool_t result = FALSE; + + 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(lf, uri); + ms_free(uri); + + if (!presence) continue; + if (linphone_presence_model_has_capability_with_version_or_more(presence, capability, version)) result = TRUE; + } + for (it = phones; it!= NULL; it = it->next) { + presence = linphone_friend_get_presence_model_for_uri_or_tel(lf, reinterpret_cast<const char *>(it->data)); + + if (!presence) continue; + if (linphone_presence_model_has_capability_with_version_or_more(presence, capability, version)) result = TRUE; + } + bctbx_list_free(phones); + + return result; +} + +float linphone_friend_get_capability_version(const LinphoneFriend *lf, const LinphoneFriendCapability capability) { + const LinphonePresenceModel *presence = NULL; + const bctbx_list_t* addrs = linphone_friend_get_addresses(lf); + bctbx_list_t* phones = linphone_friend_get_phone_numbers(lf); + bctbx_list_t *it; + float version = -1.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(lf, uri); + ms_free(uri); + + if (!presence) continue; + float presence_version = linphone_presence_model_get_capability_version(presence, capability); + if (presence_version > version) version = presence_version; + } + for (it = phones; it!= NULL; it = it->next) { + presence = linphone_friend_get_presence_model_for_uri_or_tel(lf, reinterpret_cast<const char *>(it->data)); + + if (!presence) continue; + float presence_version = linphone_presence_model_get_capability_version(presence, capability); + if (presence_version > version) version = presence_version; + } + bctbx_list_free(phones); + + return version; +} diff --git a/coreapi/presence.c b/coreapi/presence.c index 43e85573456ede39a5fd232643c2f4ad99def30a..634797cc3bbfdb147cf1e6e99641760dcf7c1cad 100644 --- a/coreapi/presence.c +++ b/coreapi/presence.c @@ -17,6 +17,10 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +#include <cmath> + +#include <bctoolbox/map.h> + #include "linphone/core.h" #include "linphone/lpconfig.h" #include "linphone/presence.h" @@ -49,6 +53,7 @@ struct _LinphonePresenceService { bctbx_list_t *notes; /**< A list of _LinphonePresenceNote structures. */ time_t timestamp; bctbx_list_t *service_descriptions; + bctbx_map_t *capabilities; }; BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphonePresenceService); @@ -138,6 +143,7 @@ static LinphonePresenceService * presence_service_new(const char *id, LinphonePr } service->status = status; service->timestamp = time(NULL); + service->capabilities = bctbx_mmap_cchar_new(); return service; } @@ -150,6 +156,7 @@ static void presence_service_uninit(LinphonePresenceService *service) { } bctbx_list_for_each(service->notes, presence_note_unref); bctbx_list_free(service->notes); + bctbx_mmap_cchar_delete_with_data(service->capabilities, bctbx_free); }; static void presence_service_unref(void *service) { @@ -814,6 +821,54 @@ LinphoneStatus linphone_presence_service_set_service_descriptions(LinphonePresen return 0; } +namespace { + const std::unordered_map<int, std::string> CapabilityToString { + { LinphoneFriendCapabilityGroupChat, "groupchat" }, + { LinphoneFriendCapabilityLimeX3dh, "lime" } + }; +} +static std::string capability_to_string (const LinphoneFriendCapability capability) { + const auto &it = CapabilityToString.find(static_cast<int>(capability)); + return (it == CapabilityToString.cend()) ? "none" : it->second; +} +static const float EPSILON = 0.1f; +bool_t linphone_presence_service_has_capability_with_version( + const LinphonePresenceService *service, + const LinphoneFriendCapability capability, + float version +) { + const auto &it = bctbx_map_cchar_find_key(service->capabilities, capability_to_string(capability).c_str()); + if (!bctbx_iterator_equals(it, bctbx_map_cchar_end(service->capabilities))) + return static_cast<bool_t>(fabs(std::stof(std::string((const char *)bctbx_pair_cchar_get_second(bctbx_iterator_cchar_get_pair(it)))) - version) < EPSILON); + + return FALSE; +} + +bool_t linphone_presence_service_has_capability_with_version_or_more( + const LinphonePresenceService *service, + const LinphoneFriendCapability capability, + float version +) { + const auto &it = bctbx_map_cchar_find_key(service->capabilities, capability_to_string(capability).c_str()); + if (!bctbx_iterator_equals(it, bctbx_map_cchar_end(service->capabilities))) + return static_cast<bool_t>(std::stof(std::string((const char *)bctbx_pair_cchar_get_second(bctbx_iterator_cchar_get_pair(it)))) >= version); + + return FALSE; +} + +float linphone_presence_service_get_capability_version(const LinphonePresenceService *service, const LinphoneFriendCapability capability) { + const auto &it = bctbx_map_cchar_find_key(service->capabilities, capability_to_string(capability).c_str()); + if (!bctbx_iterator_equals(it, bctbx_map_cchar_end(service->capabilities))) + return std::stof(std::string((const char *)bctbx_pair_cchar_get_second(bctbx_iterator_cchar_get_pair(it)))); + + return -1.0; +} + +void linphone_presence_service_add_capability(LinphonePresenceService *service, const char *capability_name, const char *version) { + const bctbx_pair_cchar_t *pair = bctbx_pair_cchar_new(capability_name, (void *)version); + bctbx_map_cchar_insert(service->capabilities, (const bctbx_pair_t *)pair); +} + unsigned int linphone_presence_service_get_nb_notes(const LinphonePresenceService *service) { return (unsigned int)bctbx_list_size(service->notes); } @@ -1157,13 +1212,13 @@ void * linphone_presence_model_get_user_data(const LinphonePresenceModel *model) } namespace { - const std::unordered_map<std::string, LinphoneFriendCapability> StringToCapability{ + const std::unordered_map<std::string, LinphoneFriendCapability> StringToCapability { { "groupchat", LinphoneFriendCapabilityGroupChat }, { "lime", LinphoneFriendCapabilityLimeX3dh } }; } static LinphoneFriendCapability get_capability_from_string (const std::string &capabilityName) { - auto it = StringToCapability.find(capabilityName); + const auto &it = StringToCapability.find(capabilityName); return (it == StringToCapability.cend()) ? LinphoneFriendCapabilityNone : it->second; } int linphone_presence_model_get_capabilities(const LinphonePresenceModel *model) { @@ -1189,6 +1244,52 @@ bool_t linphone_presence_model_has_capability(const LinphonePresenceModel *model return static_cast<bool_t>(linphone_presence_model_get_capabilities(model) & capability); } +bool_t linphone_presence_model_has_capability_with_version( + const LinphonePresenceModel *model, + const LinphoneFriendCapability capability, + float version +) { + unsigned int nbServices = linphone_presence_model_get_nb_services(model); + for (unsigned int i = 0; i < nbServices; i++) { + LinphonePresenceService *service = linphone_presence_model_get_nth_service(model, i); + if (!service) continue; + + if (linphone_presence_service_has_capability_with_version(service, capability, version)) return TRUE; + } + + return FALSE; +} + +bool_t linphone_presence_model_has_capability_with_version_or_more( + const LinphonePresenceModel *model, + const LinphoneFriendCapability capability, + float version +) { + unsigned int nbServices = linphone_presence_model_get_nb_services(model); + for (unsigned int i = 0; i < nbServices; i++) { + LinphonePresenceService *service = linphone_presence_model_get_nth_service(model, i); + if (!service) continue; + + if (linphone_presence_service_has_capability_with_version_or_more(service, capability, version)) return TRUE; + } + + return FALSE; +} + +float linphone_presence_model_get_capability_version(const LinphonePresenceModel *model, const LinphoneFriendCapability capability) { + float version = -1.0; + unsigned int nbServices = linphone_presence_model_get_nb_services(model); + for (unsigned int i = 0; i < nbServices; i++) { + LinphonePresenceService *service = linphone_presence_model_get_nth_service(model, i); + if (!service) continue; + + float service_version = linphone_presence_service_get_capability_version(service, capability); + if (service_version > version) version = service_version; + } + + return version; +} + LinphonePresenceService * linphone_presence_service_ref(LinphonePresenceService *service) { return (LinphonePresenceService *)belle_sip_object_ref(service); } @@ -1353,11 +1454,17 @@ static int process_pidf_xml_presence_services(xmlparsing_context_t *xml_ctx, Lin if (service_descriptions && service_descriptions->nodesetval) { for (int j = 1; j <= service_descriptions->nodesetval->nodeNr; j++) { char *service_id = nullptr; + char *version = nullptr; linphone_xml_xpath_context_set_node(xml_ctx, xmlXPathNodeSetItem(service_descriptions->nodesetval, j-1)); service_id = linphone_get_xml_text_content(xml_ctx, "./oma-pres:service-id"); if (service_id) { + version = linphone_get_xml_text_content(xml_ctx, "./oma-pres:version"); services = bctbx_list_append(services, ms_strdup(service_id)); + + if (service) linphone_presence_service_add_capability(service, ms_strdup(service_id), ms_strdup(version)); + linphone_free_xml_text_content(service_id); + linphone_free_xml_text_content(version); } } } diff --git a/include/linphone/friend.h b/include/linphone/friend.h index b73c5646417141e23143a8313e75d8b849484c63..c21d596b9327fa7259e5ee897ae2a18cae0ab6f6 100644 --- a/include/linphone/friend.h +++ b/include/linphone/friend.h @@ -353,6 +353,32 @@ LINPHONE_PUBLIC int linphone_friend_get_capabilities(const LinphoneFriend *lf); */ LINPHONE_PUBLIC bool_t linphone_friend_has_capability(const LinphoneFriend *lf, const LinphoneFriendCapability capability); +/** + * Returns whether or not a friend has a capbility with a given version. + * @param[in] lf #LinphoneFriend object + * @param[in] capability #LinphoneFriendCapability object + * @param[in] version the version to test + * @return whether or not a friend has a capbility with a given version or -1.0 if friend has not capability. + */ +LINPHONE_PUBLIC bool_t linphone_friend_has_capability_with_version(const LinphoneFriend *lf, const LinphoneFriendCapability capability, float version); + +/** + * Returns whether or not a friend has a capbility with a given version or more. + * @param[in] lf #LinphoneFriend object + * @param[in] capability #LinphoneFriendCapability object + * @param[in] version the version to test + * @return whether or not a friend has a capbility with a given version or more. + */ +LINPHONE_PUBLIC bool_t linphone_friend_has_capability_with_version_or_more(const LinphoneFriend *lf, const LinphoneFriendCapability capability, float version); + +/** + * Returns the version of a friend's capbility. + * @param[in] lf #LinphoneFriend object + * @param[in] capability #LinphoneFriendCapability object + * @return the version of a friend's capbility. + */ +LINPHONE_PUBLIC float linphone_friend_get_capability_version(const LinphoneFriend *lf, const LinphoneFriendCapability capability); + /** * @} */ diff --git a/include/linphone/presence.h b/include/linphone/presence.h index 2ec8448e4ddd3bf4d6287696c608606e0325edf1..446a3ce9acd6cd7e28da1351b29b9c0540982d9a 100644 --- a/include/linphone/presence.h +++ b/include/linphone/presence.h @@ -670,6 +670,40 @@ LINPHONE_PUBLIC int linphone_presence_model_get_capabilities(const LinphonePrese */ LINPHONE_PUBLIC bool_t linphone_presence_model_has_capability(const LinphonePresenceModel *model, const LinphoneFriendCapability capability); +/** + * Returns whether or not the #LinphonePresenceModel object has a given capability with a certain version. + * @param[in] model The #LinphonePresenceModel object for which to set the contact. + * @param[in] capability The capability to test. + * @param[in] version The wanted version to test. + * @return whether or not the #LinphonePresenceModel object has a given capability with a certain version. + */ +LINPHONE_PUBLIC bool_t linphone_presence_model_has_capability_with_version( + const LinphonePresenceModel *model, + const LinphoneFriendCapability capability, + float version +); + +/** + * Returns whether or not the #LinphonePresenceModel object has a given capability with a certain version or more. + * @param[in] model The #LinphonePresenceModel object for which to set the contact. + * @param[in] capability The capability to test. + * @param[in] version The wanted version to test. + * @return whether or not the #LinphonePresenceModel object has a given capability with a certain version or more. + */ +LINPHONE_PUBLIC bool_t linphone_presence_model_has_capability_with_version_or_more( + const LinphonePresenceModel *model, + const LinphoneFriendCapability capability, + float version +); + +/** + * Returns the version of the capability of a #LinphonePresenceModel. + * @param[in] model The #LinphonePresenceModel object for which to set the contact. + * @param[in] capability The capability to test. + * @return the version of the capability of a #LinphonePresenceModel or -1.0 if the model has not the capability. + */ +LINPHONE_PUBLIC float linphone_presence_model_get_capability_version(const LinphonePresenceModel *model, const LinphoneFriendCapability capability); + /** * Increase the reference count of the #LinphonePresenceService object. * @param[in] service The #LinphonePresenceService object for which the reference count is to be increased. diff --git a/tester/presence_server_tester.c b/tester/presence_server_tester.c index c990e2238e05935bbfd38b248ccbed5666ed3f76..efd4ccaf4fa7c58d82ef654b6882499ffdf32f43 100644 --- a/tester/presence_server_tester.c +++ b/tester/presence_server_tester.c @@ -1864,11 +1864,13 @@ static void notify_friend_capabilities(void) { LinphoneCoreManager *laure = linphone_core_manager_create("laure_tcp_rc"); LinphoneCoreManager *chloe = linphone_core_manager_create("chloe_rc"); LinphoneCoreManager *chloe2 = linphone_core_manager_create("chloe_rc"); + LinphoneCoreManager *chloe3 = linphone_core_manager_create("chloe_rc"); - linphone_core_set_linphone_specs(pauline->lc, "groupchat"); + linphone_core_set_linphone_specs(pauline->lc, "groupchat/1.1"); linphone_core_set_linphone_specs(pauline2->lc, "lime"); - linphone_core_set_linphone_specs(laure->lc, "groupchat"); - linphone_core_set_linphone_specs(chloe->lc, "groupchat, lime"); + linphone_core_set_linphone_specs(laure->lc, "groupchat/2.0"); + linphone_core_set_linphone_specs(chloe->lc, "groupchat/2.1, lime/1.5"); + linphone_core_set_linphone_specs(chloe3->lc, "groupchat/2.1, lime/1.7"); linphone_core_manager_start(marie, TRUE); linphone_core_manager_start(pauline, TRUE); @@ -1876,6 +1878,7 @@ static void notify_friend_capabilities(void) { linphone_core_manager_start(laure, TRUE); linphone_core_manager_start(chloe, TRUE); linphone_core_manager_start(chloe2, TRUE); + linphone_core_manager_start(chloe3, TRUE); LinphoneFriendList *mFriendList = linphone_core_get_default_friend_list(marie->lc); LinphoneFriend *mPaulineFriend = linphone_core_create_friend_with_address(marie->lc, get_identity(pauline)); @@ -1913,6 +1916,7 @@ static void notify_friend_capabilities(void) { lcs = bctbx_list_append(lcs, laure->lc); lcs = bctbx_list_append(lcs, chloe->lc); lcs = bctbx_list_append(lcs, chloe2->lc); + lcs = bctbx_list_append(lcs, chloe3->lc); linphone_core_set_user_agent(marie->lc, "full-presence-support", NULL); linphone_core_set_user_agent(marie->lc, "full-presence-support-bypass", NULL); @@ -1981,80 +1985,116 @@ static void notify_friend_capabilities(void) { BC_ASSERT_TRUE(linphone_friend_has_capability(mPaulineFriend, LinphoneFriendCapabilityGroupChat)); BC_ASSERT_TRUE(linphone_friend_get_capabilities(mPaulineFriend) & LinphoneFriendCapabilityLimeX3dh); BC_ASSERT_TRUE(linphone_friend_has_capability(mPaulineFriend, LinphoneFriendCapabilityLimeX3dh)); + BC_ASSERT_TRUE(linphone_friend_has_capability_with_version(mPaulineFriend, LinphoneFriendCapabilityGroupChat, 1.1f)); + BC_ASSERT_TRUE(linphone_friend_has_capability_with_version(mPaulineFriend, LinphoneFriendCapabilityLimeX3dh, 1.0f)); + BC_ASSERT_TRUE(linphone_friend_get_capability_version(mPaulineFriend, LinphoneFriendCapabilityGroupChat) - 1.1f < 0.1f); + BC_ASSERT_TRUE(linphone_friend_get_capability_version(mPaulineFriend, LinphoneFriendCapabilityLimeX3dh) - 1.0f < 0.1f); BC_ASSERT_TRUE(linphone_friend_get_capabilities(mLaureFriend) & LinphoneFriendCapabilityGroupChat); BC_ASSERT_TRUE(linphone_friend_has_capability(mLaureFriend, LinphoneFriendCapabilityGroupChat)); BC_ASSERT_FALSE(linphone_friend_get_capabilities(mLaureFriend) & LinphoneFriendCapabilityLimeX3dh); BC_ASSERT_FALSE(linphone_friend_has_capability(mLaureFriend, LinphoneFriendCapabilityLimeX3dh)); + BC_ASSERT_TRUE(linphone_friend_has_capability_with_version(mLaureFriend, LinphoneFriendCapabilityGroupChat, 2.0f)); + BC_ASSERT_FALSE(linphone_friend_has_capability_with_version(mLaureFriend, LinphoneFriendCapabilityLimeX3dh, 1.0f)); + BC_ASSERT_TRUE(linphone_friend_get_capability_version(mLaureFriend, LinphoneFriendCapabilityGroupChat) - 2.0f < 0.1f); + BC_ASSERT_TRUE(linphone_friend_get_capability_version(mLaureFriend, LinphoneFriendCapabilityLimeX3dh) - (-1.0f) < 0.1f); BC_ASSERT_TRUE(linphone_friend_get_capabilities(mChloeFriend) & LinphoneFriendCapabilityGroupChat); BC_ASSERT_TRUE(linphone_friend_has_capability(mChloeFriend, LinphoneFriendCapabilityGroupChat)); BC_ASSERT_TRUE(linphone_friend_get_capabilities(mChloeFriend) & LinphoneFriendCapabilityLimeX3dh); BC_ASSERT_TRUE(linphone_friend_has_capability(mChloeFriend, LinphoneFriendCapabilityLimeX3dh)); + BC_ASSERT_TRUE(linphone_friend_has_capability_with_version(mChloeFriend, LinphoneFriendCapabilityGroupChat, 2.1f)); + BC_ASSERT_TRUE(linphone_friend_has_capability_with_version(mChloeFriend, LinphoneFriendCapabilityLimeX3dh, 1.7f)); + BC_ASSERT_TRUE(linphone_friend_get_capability_version(mChloeFriend, LinphoneFriendCapabilityGroupChat) - 2.1f < 0.1f); + BC_ASSERT_TRUE(linphone_friend_get_capability_version(mChloeFriend, LinphoneFriendCapabilityLimeX3dh) - 1.7f < 0.1f); // Pauline's received presence BC_ASSERT_FALSE(linphone_friend_get_capabilities(p1MarieFriend) & LinphoneFriendCapabilityGroupChat); BC_ASSERT_FALSE(linphone_friend_has_capability(p1MarieFriend, LinphoneFriendCapabilityGroupChat)); BC_ASSERT_FALSE(linphone_friend_get_capabilities(p1MarieFriend) & LinphoneFriendCapabilityLimeX3dh); BC_ASSERT_FALSE(linphone_friend_has_capability(p1MarieFriend, LinphoneFriendCapabilityLimeX3dh)); + BC_ASSERT_FALSE(linphone_friend_has_capability_with_version(p1MarieFriend, LinphoneFriendCapabilityGroupChat, 1.0f)); + BC_ASSERT_FALSE(linphone_friend_has_capability_with_version(p1MarieFriend, LinphoneFriendCapabilityLimeX3dh, 1.0f)); BC_ASSERT_TRUE(linphone_friend_get_capabilities(p1LaureFriend) & LinphoneFriendCapabilityGroupChat); BC_ASSERT_TRUE(linphone_friend_has_capability(p1LaureFriend, LinphoneFriendCapabilityGroupChat)); BC_ASSERT_FALSE(linphone_friend_get_capabilities(p1LaureFriend) & LinphoneFriendCapabilityLimeX3dh); BC_ASSERT_FALSE(linphone_friend_has_capability(p1LaureFriend, LinphoneFriendCapabilityLimeX3dh)); + BC_ASSERT_TRUE(linphone_friend_has_capability_with_version(p1LaureFriend, LinphoneFriendCapabilityGroupChat, 2.0f)); + BC_ASSERT_FALSE(linphone_friend_has_capability_with_version(p1LaureFriend, LinphoneFriendCapabilityLimeX3dh, 1.0f)); BC_ASSERT_TRUE(linphone_friend_get_capabilities(p1ChloeFriend) & LinphoneFriendCapabilityGroupChat); BC_ASSERT_TRUE(linphone_friend_has_capability(p1ChloeFriend, LinphoneFriendCapabilityGroupChat)); BC_ASSERT_TRUE(linphone_friend_get_capabilities(p1ChloeFriend) & LinphoneFriendCapabilityLimeX3dh); BC_ASSERT_TRUE(linphone_friend_has_capability(p1ChloeFriend, LinphoneFriendCapabilityLimeX3dh)); + BC_ASSERT_TRUE(linphone_friend_has_capability_with_version(p1ChloeFriend, LinphoneFriendCapabilityGroupChat, 2.1f)); + BC_ASSERT_TRUE(linphone_friend_has_capability_with_version(p1ChloeFriend, LinphoneFriendCapabilityLimeX3dh, 1.7f)); // Pauline2's received presence BC_ASSERT_FALSE(linphone_friend_get_capabilities(p2MarieFriend) & LinphoneFriendCapabilityGroupChat); BC_ASSERT_FALSE(linphone_friend_has_capability(p2MarieFriend, LinphoneFriendCapabilityGroupChat)); BC_ASSERT_FALSE(linphone_friend_get_capabilities(p2MarieFriend) & LinphoneFriendCapabilityLimeX3dh); BC_ASSERT_FALSE(linphone_friend_has_capability(p2MarieFriend, LinphoneFriendCapabilityLimeX3dh)); + BC_ASSERT_FALSE(linphone_friend_has_capability_with_version(p2MarieFriend, LinphoneFriendCapabilityGroupChat, 1.0f)); + BC_ASSERT_FALSE(linphone_friend_has_capability_with_version(p2MarieFriend, LinphoneFriendCapabilityLimeX3dh, 1.0f)); BC_ASSERT_TRUE(linphone_friend_get_capabilities(p2LaureFriend) & LinphoneFriendCapabilityGroupChat); BC_ASSERT_TRUE(linphone_friend_has_capability(p2LaureFriend, LinphoneFriendCapabilityGroupChat)); BC_ASSERT_FALSE(linphone_friend_get_capabilities(p2LaureFriend) & LinphoneFriendCapabilityLimeX3dh); BC_ASSERT_FALSE(linphone_friend_has_capability(p2LaureFriend, LinphoneFriendCapabilityLimeX3dh)); + BC_ASSERT_TRUE(linphone_friend_has_capability_with_version(p2LaureFriend, LinphoneFriendCapabilityGroupChat, 2.0f)); + BC_ASSERT_FALSE(linphone_friend_has_capability_with_version(p2LaureFriend, LinphoneFriendCapabilityLimeX3dh, 1.0f)); BC_ASSERT_TRUE(linphone_friend_get_capabilities(p2ChloeFriend) & LinphoneFriendCapabilityGroupChat); BC_ASSERT_TRUE(linphone_friend_has_capability(p2ChloeFriend, LinphoneFriendCapabilityGroupChat)); BC_ASSERT_TRUE(linphone_friend_get_capabilities(p2ChloeFriend) & LinphoneFriendCapabilityLimeX3dh); BC_ASSERT_TRUE(linphone_friend_has_capability(p2ChloeFriend, LinphoneFriendCapabilityLimeX3dh)); + BC_ASSERT_TRUE(linphone_friend_has_capability_with_version(p2ChloeFriend, LinphoneFriendCapabilityGroupChat, 2.1f)); + BC_ASSERT_TRUE(linphone_friend_has_capability_with_version(p2ChloeFriend, LinphoneFriendCapabilityLimeX3dh, 1.7f)); // Laure's received presence BC_ASSERT_FALSE(linphone_friend_get_capabilities(lMarieFriend) & LinphoneFriendCapabilityGroupChat); BC_ASSERT_FALSE(linphone_friend_has_capability(lMarieFriend, LinphoneFriendCapabilityGroupChat)); BC_ASSERT_FALSE(linphone_friend_get_capabilities(lMarieFriend) & LinphoneFriendCapabilityLimeX3dh); BC_ASSERT_FALSE(linphone_friend_has_capability(lMarieFriend, LinphoneFriendCapabilityLimeX3dh)); + BC_ASSERT_FALSE(linphone_friend_has_capability_with_version(lMarieFriend, LinphoneFriendCapabilityGroupChat, 1.0f)); + BC_ASSERT_FALSE(linphone_friend_has_capability_with_version(lMarieFriend, LinphoneFriendCapabilityLimeX3dh, 1.0f)); BC_ASSERT_TRUE(linphone_friend_get_capabilities(lPaulineFriend) & LinphoneFriendCapabilityGroupChat); BC_ASSERT_TRUE(linphone_friend_has_capability(lPaulineFriend, LinphoneFriendCapabilityGroupChat)); BC_ASSERT_TRUE(linphone_friend_get_capabilities(lPaulineFriend) & LinphoneFriendCapabilityLimeX3dh); BC_ASSERT_TRUE(linphone_friend_has_capability(lPaulineFriend, LinphoneFriendCapabilityLimeX3dh)); + BC_ASSERT_TRUE(linphone_friend_has_capability_with_version(lPaulineFriend, LinphoneFriendCapabilityGroupChat, 1.1f)); + BC_ASSERT_TRUE(linphone_friend_has_capability_with_version(lPaulineFriend, LinphoneFriendCapabilityLimeX3dh, 1.0f)); BC_ASSERT_TRUE(linphone_friend_get_capabilities(lChloeFriend) & LinphoneFriendCapabilityGroupChat); BC_ASSERT_TRUE(linphone_friend_has_capability(lChloeFriend, LinphoneFriendCapabilityGroupChat)); BC_ASSERT_TRUE(linphone_friend_get_capabilities(lChloeFriend) & LinphoneFriendCapabilityLimeX3dh); BC_ASSERT_TRUE(linphone_friend_has_capability(lChloeFriend, LinphoneFriendCapabilityLimeX3dh)); + BC_ASSERT_TRUE(linphone_friend_has_capability_with_version(lChloeFriend, LinphoneFriendCapabilityGroupChat, 2.1f)); + BC_ASSERT_TRUE(linphone_friend_has_capability_with_version(lChloeFriend, LinphoneFriendCapabilityLimeX3dh, 1.7f)); // Chloe's received presence BC_ASSERT_FALSE(linphone_friend_get_capabilities(cMarieFriend) & LinphoneFriendCapabilityGroupChat); BC_ASSERT_FALSE(linphone_friend_has_capability(cMarieFriend, LinphoneFriendCapabilityGroupChat)); BC_ASSERT_FALSE(linphone_friend_get_capabilities(cMarieFriend) & LinphoneFriendCapabilityLimeX3dh); BC_ASSERT_FALSE(linphone_friend_has_capability(cMarieFriend, LinphoneFriendCapabilityLimeX3dh)); + BC_ASSERT_FALSE(linphone_friend_has_capability_with_version(cMarieFriend, LinphoneFriendCapabilityGroupChat, 1.0f)); + BC_ASSERT_FALSE(linphone_friend_has_capability_with_version(cMarieFriend, LinphoneFriendCapabilityLimeX3dh, 1.0f)); BC_ASSERT_TRUE(linphone_friend_get_capabilities(cPaulineFriend) & LinphoneFriendCapabilityGroupChat); BC_ASSERT_TRUE(linphone_friend_has_capability(cPaulineFriend, LinphoneFriendCapabilityGroupChat)); BC_ASSERT_TRUE(linphone_friend_get_capabilities(cPaulineFriend) & LinphoneFriendCapabilityLimeX3dh); BC_ASSERT_TRUE(linphone_friend_has_capability(cPaulineFriend, LinphoneFriendCapabilityLimeX3dh)); + BC_ASSERT_TRUE(linphone_friend_has_capability_with_version(cPaulineFriend, LinphoneFriendCapabilityGroupChat, 1.1f)); + BC_ASSERT_TRUE(linphone_friend_has_capability_with_version(cPaulineFriend, LinphoneFriendCapabilityLimeX3dh, 1.0f)); BC_ASSERT_TRUE(linphone_friend_get_capabilities(cLaureFriend) & LinphoneFriendCapabilityGroupChat); BC_ASSERT_TRUE(linphone_friend_has_capability(cLaureFriend, LinphoneFriendCapabilityGroupChat)); BC_ASSERT_FALSE(linphone_friend_get_capabilities(cLaureFriend) & LinphoneFriendCapabilityLimeX3dh); BC_ASSERT_FALSE(linphone_friend_has_capability(cLaureFriend, LinphoneFriendCapabilityLimeX3dh)); + BC_ASSERT_TRUE(linphone_friend_has_capability_with_version(cLaureFriend, LinphoneFriendCapabilityGroupChat, 2.0f)); + BC_ASSERT_FALSE(linphone_friend_has_capability_with_version(cLaureFriend, LinphoneFriendCapabilityLimeX3dh, 1.0f)); linphone_friend_unref(mPaulineFriend); linphone_friend_unref(mLaureFriend); @@ -2094,6 +2134,9 @@ static void notify_friend_capabilities(void) { linphone_core_manager_stop(chloe2); linphone_core_manager_destroy(chloe2); + linphone_core_manager_stop(chloe3); + linphone_core_manager_destroy(chloe3); + bctbx_list_free(lcs); }