diff --git a/coreapi/carddav.c b/coreapi/carddav.c index 683b9dddd..78b70f695 100644 --- a/coreapi/carddav.c +++ b/coreapi/carddav.c @@ -110,6 +110,12 @@ static void linphone_carddav_vcards_pulled(LinphoneCardDavContext *cdc, MSList * if (local_friend) { LinphoneFriend *lf2 = (LinphoneFriend *)local_friend->data; + lf->storage_id = lf2->storage_id; + lf->pol = lf2->pol; + lf->subscribe = lf2->subscribe; + lf->refkey = ms_strdup(lf2->refkey); + lf->presence_received = lf2->presence_received; + if (cdc->contact_updated_cb) { ms_debug("Contact updated: %s", linphone_friend_get_name(lf)); cdc->contact_updated_cb(cdc, lf, lf2); @@ -169,41 +175,33 @@ end: } static int find_matching_vcard(LinphoneCardDavResponse *response, LinphoneFriend *lf) { - LinphoneVCard *lvc1 = linphone_vcard_new_from_vcard4_buffer(response->vcard); - LinphoneVCard *lvc2 = linphone_friend_get_vcard(lf); - const char *uid1 = NULL, *uid2 = NULL; - if (!lvc1 || !lvc2) { - if (lvc1) linphone_vcard_free(lvc1); + if (!response->url || !lf || !lf->vcard || !linphone_vcard_get_url(lf->vcard)) { return 1; } - uid1 = linphone_vcard_get_uid(lvc1); - uid2 = linphone_vcard_get_uid(lvc2); - linphone_vcard_free(lvc1); - if (!uid1 || !uid2) { - return 1; - } - return strcmp(uid1, uid2); + return strcmp(response->url, linphone_vcard_get_url(lf->vcard)); } static void linphone_carddav_vcards_fetched(LinphoneCardDavContext *cdc, MSList *vCards) { if (vCards != NULL && ms_list_size(vCards) > 0) { MSList *friends = cdc->friend_list->friends; MSList *friends_to_remove = NULL; + MSList *temp_list = NULL; while (friends) { LinphoneFriend *lf = (LinphoneFriend *)friends->data; if (lf) { MSList *vCard = ms_list_find_custom(vCards, (int (*)(const void*, const void*))find_matching_vcard, lf); if (!vCard) { - ms_error("Local friend %s isn't in the remote vCard list, delete it", linphone_friend_get_name(lf)); - friends_to_remove = ms_list_append(friends_to_remove, lf); + ms_debug("Local friend %s isn't in the remote vCard list, delete it", linphone_friend_get_name(lf)); + temp_list = ms_list_append(temp_list, linphone_friend_ref(lf)); } else { LinphoneCardDavResponse *response = (LinphoneCardDavResponse *)vCard->data; ms_debug("Local friend %s is in the remote vCard list, check eTag", linphone_friend_get_name(lf)); if (response) { LinphoneVCard *lvc = linphone_friend_get_vcard(lf); - ms_debug("Local friend eTag is %s, remote vCard eTag is %s", linphone_vcard_get_etag(lvc), response->etag); - if (lvc && strcmp(linphone_vcard_get_etag(lvc), response->etag) == 0) { + const char *etag = linphone_vcard_get_etag(lvc); + ms_debug("Local friend eTag is %s, remote vCard eTag is %s", etag, response->etag); + if (lvc && etag && strcmp(etag, response->etag) == 0) { ms_list_remove(vCards, vCard); ms_free(response); } @@ -212,17 +210,18 @@ static void linphone_carddav_vcards_fetched(LinphoneCardDavContext *cdc, MSList } friends = ms_list_next(friends); } + friends_to_remove = temp_list; while(friends_to_remove) { LinphoneFriend *lf = (LinphoneFriend *)friends_to_remove->data; if (lf) { if (cdc->contact_removed_cb) { - ms_error("Contact removed: %s", linphone_friend_get_name(lf)); + ms_debug("Contact removed: %s", linphone_friend_get_name(lf)); cdc->contact_removed_cb(cdc, lf); } } friends_to_remove = ms_list_next(friends_to_remove); } - friends_to_remove = ms_list_free(friends_to_remove); + temp_list = ms_list_free_with_data(temp_list, (void (*)(void *))linphone_friend_unref); linphone_carddav_pull_vcards(cdc, vCards); } diff --git a/coreapi/friendlist.c b/coreapi/friendlist.c index e022014fc..fa8ba996b 100644 --- a/coreapi/friendlist.c +++ b/coreapi/friendlist.c @@ -72,6 +72,14 @@ void linphone_friend_list_cbs_set_contact_deleted(LinphoneFriendListCbs *cbs, Li cbs->contact_deleted_cb = cb; } +LinphoneFriendListContactUpdatedCb linphone_friend_list_cbs_get_contact_updated(const LinphoneFriendListCbs *cbs) { + return cbs->contact_updated_cb; +} + +void linphone_friend_list_cbs_set_contact_updated(LinphoneFriendListCbs *cbs, LinphoneFriendListContactUpdatedCb cb) { + cbs->contact_updated_cb = cb; +} + static char * create_resource_list_xml(const LinphoneFriendList *list) { char *xml_content = NULL; MSList *elem; @@ -423,6 +431,16 @@ static void carddav_done(LinphoneCardDavContext *cdc, bool_t success, const char linphone_carddav_context_destroy(cdc); } +LinphoneFriendListStatus _linphone_friend_list_remove_friend(LinphoneFriendList *list, MSList *elem, LinphoneFriend *lf) { + if (!elem) { + return LinphoneFriendListNonExistentFriend; + } + lf->friend_list = NULL; + linphone_friend_unref(lf); + list->friends = ms_list_remove_link(list->friends, elem); + return LinphoneFriendListOK; +} + LinphoneFriendListStatus linphone_friend_list_remove_friend(LinphoneFriendList *list, LinphoneFriend *lf) { MSList *elem = ms_list_find(list->friends, lf); LinphoneCardDavContext *cdc = linphone_carddav_context_new(list); @@ -436,10 +454,7 @@ LinphoneFriendListStatus linphone_friend_list_remove_friend(LinphoneFriendList * linphone_carddav_delete_vcard(cdc, lf); } - lf->friend_list = NULL; - linphone_friend_unref(lf); - list->friends = ms_list_remove_link(list->friends, elem); - return LinphoneFriendListOK; + return _linphone_friend_list_remove_friend(list, elem, lf); } void linphone_friend_list_update_dirty_friends(LinphoneFriendList *list) { @@ -472,11 +487,7 @@ static void carddav_created(LinphoneCardDavContext *cdc, LinphoneFriend *lf) { static void carddav_removed(LinphoneCardDavContext *cdc, LinphoneFriend *lf) { if (cdc) { LinphoneFriendList *lfl = cdc->friend_list; - MSList *elem = ms_list_find(lfl->friends, lf); - if (elem) { - linphone_friend_unref(lf); - lfl->friends = ms_list_remove_link(lfl->friends, elem); - } + linphone_friend_list_remove_friend(lfl, lf); if (cdc->friend_list->cbs->contact_deleted_cb) { cdc->friend_list->cbs->contact_deleted_cb(lfl, lf); } @@ -484,7 +495,17 @@ static void carddav_removed(LinphoneCardDavContext *cdc, LinphoneFriend *lf) { } static void carddav_updated(LinphoneCardDavContext *cdc, LinphoneFriend *lf_new, LinphoneFriend *lf_old) { - //TODO + if (cdc) { + LinphoneFriendList *lfl = cdc->friend_list; + MSList *elem = ms_list_find(lfl->friends, lf_old); + if (elem) { + _linphone_friend_list_remove_friend(lfl, elem, lf_old); + } + _linphone_friend_list_add_friend(lfl, lf_new); + if (cdc->friend_list->cbs->contact_updated_cb) { + cdc->friend_list->cbs->contact_updated_cb(lfl, lf_new, lf_old); + } + } } void linphone_friend_list_synchronize_friends_from_server(LinphoneFriendList *list) { diff --git a/coreapi/friendlist.h b/coreapi/friendlist.h index 9f083eabe..c58c2930a 100644 --- a/coreapi/friendlist.h +++ b/coreapi/friendlist.h @@ -160,6 +160,7 @@ LinphoneFriendListStatus _linphone_friend_list_add_friend(LinphoneFriendList *li * @return LinphoneFriendListOK if removed successfully, LinphoneFriendListNonExistentFriend if the friend is not in the list. **/ LINPHONE_PUBLIC LinphoneFriendListStatus linphone_friend_list_remove_friend(LinphoneFriendList *list, LinphoneFriend *afriend); +LinphoneFriendListStatus _linphone_friend_list_remove_friend(LinphoneFriendList *list, MSList *elem, LinphoneFriend *lf); /** * Find a friend in the friend list using a LinphoneAddress. @@ -232,6 +233,11 @@ typedef void (*LinphoneFriendListContactCreatedCb)(LinphoneFriendList *list, Lin **/ typedef void (*LinphoneFriendListContactDeletedCb)(LinphoneFriendList *list, LinphoneFriend *lf); +/** + * Callback used to notify a contact has been updated on the CardDAV server +**/ +typedef void (*LinphoneFriendListContactUpdatedCb)(LinphoneFriendList *list, LinphoneFriend *new_friend, LinphoneFriend *old_friend); + /** * Get the LinphoneFriendListCbs object associated with a LinphoneFriendList. * @param[in] request LinphoneXmlRpcRequest object @@ -294,6 +300,20 @@ LINPHONE_PUBLIC LinphoneFriendListContactDeletedCb linphone_friend_list_cbs_get_ **/ LINPHONE_PUBLIC void linphone_friend_list_cbs_set_contact_deleted(LinphoneFriendListCbs *cbs, LinphoneFriendListContactDeletedCb cb); +/** + * Get the contact updated callback. + * @param[in] cbs LinphoneFriendListCbs object. + * @return The current contact updated callback. +**/ +LINPHONE_PUBLIC LinphoneFriendListContactUpdatedCb linphone_friend_list_cbs_get_contact_updated(const LinphoneFriendListCbs *cbs); + +/** + * Set the contact updated callback. + * @param[in] cbs LinphoneFriendListCbs object. + * @param[in] cb The contact updated to be used. +**/ +LINPHONE_PUBLIC void linphone_friend_list_cbs_set_contact_updated(LinphoneFriendListCbs *cbs, LinphoneFriendListContactUpdatedCb cb); + /** * * @param[in] list LinphoneFriendList object. diff --git a/coreapi/private.h b/coreapi/private.h index 1ed4fbd6c..ea871211d 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -700,6 +700,7 @@ struct _LinphoneFriendListCbs { void *user_data; LinphoneFriendListContactCreatedCb contact_created_cb; LinphoneFriendListContactDeletedCb contact_deleted_cb; + LinphoneFriendListContactUpdatedCb contact_updated_cb; }; BELLE_SIP_DECLARE_VPTR(LinphoneFriendListCbs); diff --git a/tester/vcard_tester.c b/tester/vcard_tester.c index 6cdf253db..d678c3549 100644 --- a/tester/vcard_tester.c +++ b/tester/vcard_tester.c @@ -395,11 +395,18 @@ static void carddav_contact_deleted(LinphoneFriendList *list, LinphoneFriend *lf stats->removed_contact_count++; } +static void carddav_contact_updated(LinphoneFriendList *list, LinphoneFriend *new_friend, LinphoneFriend *old_friend) { + LinphoneCardDAVStats *stats = (LinphoneCardDAVStats *)linphone_friend_list_cbs_get_user_data(list->cbs); + stats->updated_contact_count++; +} + static void carddav_integration(void) { LinphoneCoreManager *manager = linphone_core_manager_new2("carddav_rc", FALSE); LinphoneFriendList *lfl = linphone_core_create_friend_list(manager->lc); LinphoneVCard *lvc = linphone_vcard_new_from_vcard4_buffer("BEGIN:VCARD\r\nVERSION:4.0\r\nFN:Margaux Clerc\r\nIMPP;TYPE=work:sip:margaux@sip.linphone.org\r\nEND:VCARD\r\n"); LinphoneFriend *lf = linphone_friend_new_from_vcard(lvc); + LinphoneVCard *lvc2 = NULL; + LinphoneFriend *lf2 = NULL; LinphoneFriendListCbs *cbs = NULL; LinphoneCardDAVStats *stats = (LinphoneCardDAVStats *)ms_new0(LinphoneCardDAVStats, 1); @@ -408,6 +415,7 @@ static void carddav_integration(void) { linphone_friend_list_cbs_set_user_data(cbs, stats); linphone_friend_list_cbs_set_contact_created(cbs, carddav_contact_created); linphone_friend_list_cbs_set_contact_deleted(cbs, carddav_contact_deleted); + linphone_friend_list_cbs_set_contact_updated(cbs, carddav_contact_updated); linphone_core_add_friend_list(manager->lc, lfl); BC_ASSERT_PTR_NULL(linphone_vcard_get_uid(lvc)); @@ -425,12 +433,21 @@ static void carddav_integration(void) { BC_ASSERT_EQUAL_FATAL(_linphone_friend_list_add_friend(lfl, lf), LinphoneFriendListOK, int, "%d"); linphone_friend_unref(lf); + lvc2 = linphone_vcard_new_from_vcard4_buffer("BEGIN:VCARD\r\nVERSION:4.0\r\nFN:Sylvain Berfini\r\nIMPP:sip:sylvain.linphone.org\r\nUID:1f08dd48-29ac-4097-8e48-8596d7776283\r\nEND:VCARD\r\n"); + linphone_vcard_set_url(lvc2, "/sabredav/addressbookserver.php/addressbooks/sylvain/default/me.vcf"); + lf2 = linphone_friend_new_from_vcard(lvc2); + BC_ASSERT_EQUAL_FATAL(_linphone_friend_list_add_friend(lfl, lf2), LinphoneFriendListOK, int, "%d"); + linphone_friend_unref(lf2); + lf2 = NULL; + BC_ASSERT_EQUAL(lfl->revision, 0, int, "%i"); linphone_friend_list_synchronize_friends_from_server(lfl); - wait_for_until(manager->lc, NULL, &stats->new_contact_count, 1, 2000); - BC_ASSERT_EQUAL(stats->new_contact_count, 1, int, "%i"); + wait_for_until(manager->lc, NULL, &stats->new_contact_count, 0, 2000); + BC_ASSERT_EQUAL(stats->new_contact_count, 0, int, "%i"); wait_for_until(manager->lc, NULL, &stats->removed_contact_count, 1, 2000); BC_ASSERT_EQUAL(stats->removed_contact_count, 1, int, "%i"); + wait_for_until(manager->lc, NULL, &stats->updated_contact_count, 1, 2000); + BC_ASSERT_EQUAL(stats->updated_contact_count, 1, int, "%i"); BC_ASSERT_NOT_EQUAL(lfl->revision, 0, int, "%i"); BC_ASSERT_EQUAL_FATAL(ms_list_size(lfl->friends), 1, int, "%i");