diff --git a/coreapi/friendlist.c b/coreapi/friendlist.c index 023583528..6c48520d1 100644 --- a/coreapi/friendlist.c +++ b/coreapi/friendlist.c @@ -116,9 +116,7 @@ static bctbx_list_t * uri_list(const LinphoneFriendList *list) { if (addr) { char *uri = linphone_address_as_string_uri_only(addr); if (uri) { - if (bctbx_list_find_custom(uri_list, (bctbx_compare_func)strcmp, uri) == NULL) { - uri_list = bctbx_list_insert_sorted(uri_list, uri, (bctbx_compare_func)strcasecmp); - } + uri_list = bctbx_list_prepend(uri_list, uri); } } iterator = bctbx_list_next(iterator); @@ -128,9 +126,7 @@ static bctbx_list_t * uri_list(const LinphoneFriendList *list) { const char *number = (const char *)bctbx_list_get_data(iterator); const char *uri = linphone_friend_phone_number_to_sip_uri(lf, number); if (uri) { - if (bctbx_list_find_custom(uri_list, (bctbx_compare_func)strcmp, uri) == NULL) { - uri_list = bctbx_list_insert_sorted(uri_list, ms_strdup(uri), (bctbx_compare_func)strcasecmp); - } + uri_list = bctbx_list_prepend(uri_list, ms_strdup(uri)); } iterator = bctbx_list_next(iterator); } @@ -256,30 +252,31 @@ static void linphone_friend_list_parse_multipart_related_body(LinphoneFriendList resource_object = linphone_get_xml_xpath_object_for_node_list(xml_ctx, "/rlmi:list/rlmi:resource"); if ((resource_object != NULL) && (resource_object->nodesetval != NULL)) { for (i = 1; i <= resource_object->nodesetval->nodeNr; i++) { - LinphoneAddress* addr; - snprintf(xpath_str, sizeof(xpath_str), "/rlmi:list/rlmi:resource[%i]/@uri", i); - uri = linphone_get_xml_text_content(xml_ctx, xpath_str); - if (uri == NULL) continue; - addr = linphone_address_new(uri); - if (!addr) continue; - lf = linphone_friend_list_find_friend_by_address(list, addr); - linphone_address_unref(addr); - if (lf != NULL) { - const char *state = NULL; - snprintf(xpath_str, sizeof(xpath_str),"/rlmi:list/rlmi:resource[%i]/rlmi:instance/@state", i); - state = linphone_get_xml_text_content(xml_ctx, xpath_str); - if ((state != NULL) && (strcmp(state, "active") == 0)) { - const char *cid = NULL; - snprintf(xpath_str, sizeof(xpath_str),"/rlmi:list/rlmi:resource[%i]/rlmi:instance/@cid", i); - cid = linphone_get_xml_text_content(xml_ctx, xpath_str); - if (cid != NULL) { - presence_part = linphone_content_find_part_by_header(body, "Content-Id", cid); - if (presence_part == NULL) { - ms_warning("rlmi+xml: Cannot find part with Content-Id: %s", cid); - } else { - SalPresenceModel *presence = NULL; - linphone_notify_parse_presence(linphone_content_get_type(presence_part), linphone_content_get_subtype(presence_part), linphone_content_get_string_buffer(presence_part), &presence); - if (presence != NULL) { + const char *state = NULL; + snprintf(xpath_str, sizeof(xpath_str),"/rlmi:list/rlmi:resource[%i]/rlmi:instance/@state", i); + state = linphone_get_xml_text_content(xml_ctx, xpath_str); + if ((state != NULL) && (strcmp(state, "active") == 0)) { + const char *cid = NULL; + snprintf(xpath_str, sizeof(xpath_str),"/rlmi:list/rlmi:resource[%i]/rlmi:instance/@cid", i); + cid = linphone_get_xml_text_content(xml_ctx, xpath_str); + if (cid != NULL) { + presence_part = linphone_content_find_part_by_header(body, "Content-Id", cid); + if (presence_part == NULL) { + ms_warning("rlmi+xml: Cannot find part with Content-Id: %s", cid); + } else { + SalPresenceModel *presence = NULL; + linphone_notify_parse_presence(linphone_content_get_type(presence_part), linphone_content_get_subtype(presence_part), linphone_content_get_string_buffer(presence_part), &presence); + if (presence != NULL) { + // Try to reduce CPU cost of linphone_address_new and find_friend_by_address by only doing it when we know for sure we have a presence to notify + LinphoneAddress* addr; + snprintf(xpath_str, sizeof(xpath_str), "/rlmi:list/rlmi:resource[%i]/@uri", i); + uri = linphone_get_xml_text_content(xml_ctx, xpath_str); + if (uri == NULL) continue; + addr = linphone_address_new(uri); + if (!addr) continue; + lf = linphone_friend_list_find_friend_by_address(list, addr); + linphone_address_unref(addr); + if (lf) { const char *phone_number = linphone_friend_sip_uri_to_phone_number(lf, uri); lf->presence_received = TRUE; if (phone_number) linphone_friend_set_presence_model_for_uri_or_tel(lf, phone_number, (LinphonePresenceModel *)presence); @@ -291,16 +288,15 @@ static void linphone_friend_list_parse_multipart_related_body(LinphoneFriendList linphone_core_notify_notify_presence_received_for_uri_or_tel(list->lc, lf, uri, (LinphonePresenceModel *)presence); linphone_core_notify_notify_presence_received(list->lc, lf); } + linphone_free_xml_text_content(uri); } linphone_content_unref(presence_part); } } - if (cid != NULL) linphone_free_xml_text_content(cid); + linphone_free_xml_text_content(cid); } - if (state != NULL) linphone_free_xml_text_content(state); - lf->subscribe_active = TRUE; } - linphone_free_xml_text_content(uri); + if (state != NULL) linphone_free_xml_text_content(state); } } if (resource_object != NULL) xmlXPathFreeObject(resource_object); @@ -768,6 +764,7 @@ static void linphone_friend_list_send_list_subscription(LinphoneFriendList *list linphone_event_refresh_subscribe(list->event); } else { LinphoneContent *content; + bctbx_list_t * elem = NULL; int expires = lp_config_get_int(list->lc->config, "sip", "rls_presence_expires", 3600); list->expected_notification_version = 0; if (list->content_digest != NULL) ms_free(list->content_digest); @@ -792,6 +789,10 @@ static void linphone_friend_list_send_list_subscription(LinphoneFriendList *list linphone_content_set_encoding(content, "deflate"); linphone_event_add_custom_header(list->event, "Accept-Encoding", "deflate"); } + for (elem = list->friends; elem != NULL; elem = bctbx_list_next(elem)) { + LinphoneFriend *lf = (LinphoneFriend *)elem->data; + lf->subscribe_active = TRUE; + } linphone_event_send_subscribe(list->event, content); linphone_content_unref(content); linphone_event_set_user_data(list->event, list); diff --git a/tester/presence_server_tester.c b/tester/presence_server_tester.c index d833bda7c..37b407a7b 100644 --- a/tester/presence_server_tester.c +++ b/tester/presence_server_tester.c @@ -393,15 +393,12 @@ static void test_presence_list_base(bool_t enable_compression) { lf = linphone_friend_list_find_friend_by_uri(linphone_core_get_default_friend_list(laure->lc), marie_identity); BC_ASSERT_EQUAL(linphone_friend_get_status(lf), LinphoneStatusBusy, int, "%d"); if (!BC_ASSERT_TRUE(lf->presence_received)) goto end; - if (!BC_ASSERT_TRUE(lf->subscribe_active)) goto end; lf = linphone_friend_list_find_friend_by_uri(linphone_core_get_default_friend_list(laure->lc), pauline_identity); BC_ASSERT_EQUAL(linphone_friend_get_status(lf), LinphoneStatusVacation, int, "%d"); if (!BC_ASSERT_TRUE(lf->presence_received)) goto end; - if (!BC_ASSERT_TRUE(lf->subscribe_active)) goto end; lf = linphone_friend_list_find_friend_by_uri(linphone_core_get_default_friend_list(laure->lc), "sip:michelle@sip.inexistentdomain.com"); BC_ASSERT_EQUAL(linphone_friend_get_status(lf), LinphoneStatusOffline, int, "%d"); BC_ASSERT_FALSE(lf->presence_received); - if (!BC_ASSERT_TRUE(lf->subscribe_active)) goto end; lfl = linphone_core_create_friend_list(marie->lc); linphone_friend_list_set_rls_uri(lfl, rls_uri); @@ -419,7 +416,6 @@ static void test_presence_list_base(bool_t enable_compression) { lf = linphone_friend_list_find_friend_by_uri(linphone_core_get_default_friend_list(marie->lc), laure_identity); BC_ASSERT_EQUAL(linphone_friend_get_status(lf), LinphoneStatusOnline, int, "%d"); if (!BC_ASSERT_TRUE(lf->presence_received)) goto end; - if (!BC_ASSERT_TRUE(lf->subscribe_active)) goto end; lfl = linphone_core_create_friend_list(pauline->lc); linphone_friend_list_set_rls_uri(lfl, rls_uri); @@ -437,7 +433,6 @@ static void test_presence_list_base(bool_t enable_compression) { lf = linphone_friend_list_find_friend_by_uri(linphone_core_get_default_friend_list(pauline->lc), marie_identity); BC_ASSERT_EQUAL(linphone_friend_get_status(lf), LinphoneStatusBusy, int, "%d"); if (!BC_ASSERT_TRUE(lf->presence_received)) goto end; - if (!BC_ASSERT_TRUE(lf->subscribe_active)) goto end; linphone_core_set_presence_model(marie->lc, linphone_core_create_presence_model_with_activity(marie->lc, LinphonePresenceActivityOnThePhone, NULL)); @@ -547,11 +542,9 @@ static void test_presence_list_subscribe_before_publish(void) { lf = linphone_friend_list_find_friend_by_uri(linphone_core_get_default_friend_list(laure->lc), pauline_identity); BC_ASSERT_EQUAL(linphone_friend_get_status(lf), LinphoneStatusVacation, int, "%d"); BC_ASSERT_TRUE(lf->presence_received); - BC_ASSERT_TRUE(lf->subscribe_active); lf = linphone_friend_list_find_friend_by_uri(linphone_core_get_default_friend_list(laure->lc), "sip:michelle@sip.inexistentdomain.com"); BC_ASSERT_EQUAL(linphone_friend_get_status(lf), LinphoneStatusOffline, int, "%d"); BC_ASSERT_FALSE(lf->presence_received); - BC_ASSERT_TRUE(lf->subscribe_active); enable_publish(laure, FALSE); enable_publish(pauline, FALSE); @@ -625,11 +618,9 @@ static void test_presence_list_subscribe_with_error(bool_t io_error) { lf = linphone_friend_list_find_friend_by_uri(linphone_core_get_default_friend_list(laure->lc), pauline_identity); BC_ASSERT_EQUAL(linphone_friend_get_status(lf), LinphoneStatusVacation, int, "%d"); BC_ASSERT_TRUE(lf->presence_received); - BC_ASSERT_TRUE(lf->subscribe_active); lf = linphone_friend_list_find_friend_by_uri(linphone_core_get_default_friend_list(laure->lc), "sip:michelle@sip.inexistentdomain.com"); BC_ASSERT_EQUAL(linphone_friend_get_status(lf), LinphoneStatusOffline, int, "%d"); BC_ASSERT_FALSE(lf->presence_received); - BC_ASSERT_TRUE(lf->subscribe_active); BC_ASSERT_TRUE(wait_for_until(laure->lc, pauline->lc, &laure->stat.number_of_LinphonePresenceActivityVacation, 2, 6000)); if (io_error) { @@ -996,6 +987,28 @@ static void long_term_presence_with_crossed_references(void) { }else ms_warning("Test skipped, no vcard support"); } +static void long_term_presence_list_for_many_friends(void) { + if (linphone_core_vcard_supported()) { + LinphoneFriendList *friends; + char *import_filepath = bc_tester_res("vcards/presence.vcf"); + LinphoneCoreManager *pauline; + + pauline = linphone_core_manager_new(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc"); + + friends = linphone_core_create_friend_list(pauline->lc); + linphone_friend_list_set_rls_uri(friends, "sip:rls@sip.example.org"); + linphone_friend_list_import_friends_from_vcard4_file(friends, import_filepath); + linphone_core_remove_friend_list(pauline->lc, linphone_core_get_default_friend_list(pauline->lc)); + linphone_core_add_friend_list(pauline->lc, friends); + linphone_core_refresh_registers(pauline->lc); + linphone_friend_list_unref(friends); + + BC_ASSERT_TRUE(wait_for(pauline->lc,NULL,&pauline->stat.number_of_NotifyPresenceReceived,1)); + + linphone_core_manager_destroy(pauline); + } else ms_warning("Test skipped, no vcard support"); +} + test_t presence_server_tests[] = { TEST_NO_TAG("Simple", simple), TEST_NO_TAG("Fast activity change", fast_activity_change), @@ -1010,6 +1023,7 @@ test_t presence_server_tests[] = { TEST_ONE_TAG("Long term presence phone alias",long_term_presence_phone_alias, "longterm"), TEST_ONE_TAG("Long term presence phone alias 2",long_term_presence_phone_alias2, "longterm"), TEST_ONE_TAG("Long term presence list",long_term_presence_list, "longterm"), + TEST_ONE_TAG("Long term presence list for many friends",long_term_presence_list_for_many_friends, "longterm"), TEST_ONE_TAG("Long term presence with +164 phone, without sip",long_term_presence_with_e164_phone_without_sip, "longterm"), TEST_ONE_TAG("Long term presence with phone, without sip",long_term_presence_with_phone_without_sip, "longterm"), TEST_ONE_TAG("Long term presence with cross references", long_term_presence_with_crossed_references,"longtern"),