Commit 873493b6 authored by Sylvain Berfini's avatar Sylvain Berfini 🎩

More work on CardDAV sync: store etag and url for each vcard in db, call the...

More work on CardDAV sync: store etag and url for each vcard in db, call the correct callbacks and improved tester using stats
parent 6fc86237
......@@ -61,7 +61,10 @@ void linphone_carddav_synchronize(LinphoneCardDavContext *cdc) {
static void linphone_carddav_sync_done(LinphoneCardDavContext *cdc, bool_t success, const char *msg) {
if (success) {
ms_debug("CardDAV sync successful, saving new cTag: %i", cdc->ctag);
linphone_core_set_carddav_current_ctag(cdc->lc, cdc->ctag);
} else {
ms_error("CardDAV sync failure: %s", msg);
}
if (cdc->sync_done_cb) {
......@@ -69,9 +72,37 @@ static void linphone_carddav_sync_done(LinphoneCardDavContext *cdc, bool_t succe
}
}
static int find_matching_friend(LinphoneFriend *lf1, LinphoneFriend *lf2) {
LinphoneVCard *lvc1 = linphone_friend_get_vcard(lf1);
LinphoneVCard *lvc2 = linphone_friend_get_vcard(lf2);
return strcmp(linphone_vcard_get_uid(lvc1), linphone_vcard_get_uid(lvc2));
}
static void linphone_carddav_vcards_pulled(LinphoneCardDavContext *cdc, MSList *vCards) {
if (vCards != NULL && ms_list_size(vCards) > 0) {
//TODO: find out which one is new and which one is an update and call the according callback
MSList *localFriends = linphone_core_fetch_friends_from_db(cdc->lc);
while (vCards) {
LinphoneCardDavResponse *vCard = (LinphoneCardDavResponse *)vCards->data;
if (vCard) {
LinphoneVCard *lvc = linphone_vcard_new_from_vcard4_buffer(vCard->vcard);
LinphoneFriend *lf = linphone_friend_new_from_vcard(lvc);
MSList *local_friend = ms_list_find_custom(localFriends, (int (*)(const void*, const void*))find_matching_friend, lf);
if (local_friend) {
LinphoneFriend *lf2 = (LinphoneFriend *)local_friend->data;
if (cdc->contact_updated_cb) {
ms_debug("Contact updated: %s", linphone_friend_get_name(lf));
cdc->contact_updated_cb(cdc, lf, lf2);
}
} else {
if (cdc->contact_created_cb) {
ms_debug("Contact created: %s", linphone_friend_get_name(lf));
cdc->contact_created_cb(cdc, lf);
}
}
}
vCards = ms_list_next(vCards);
}
ms_list_free(localFriends);
}
ms_list_free(vCards);
linphone_carddav_sync_done(cdc, TRUE, "");
......@@ -116,11 +147,42 @@ end:
return result;
}
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);
return strcmp(linphone_vcard_get_uid(lvc1), linphone_vcard_get_uid(lvc2));
}
static void linphone_carddav_vcards_fetched(LinphoneCardDavContext *cdc, MSList *vCards) {
if (vCards != NULL && ms_list_size(vCards) > 0) {
//MSList *localFriends = linphone_core_fetch_friends_from_db(cdc->lc);
//TODO: call onDelete from the ones that are in localFriends but not in vCards
//TODO: remove from vCards the one that are in localFriends and for which the eTag hasn't changed
MSList *localFriends = linphone_core_fetch_friends_from_db(cdc->lc);
MSList *friends = localFriends;
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_debug("Local friend %s isn't in the remote vCard list, delete it", linphone_friend_get_name(lf));
if (cdc->contact_removed_cb) {
lf = linphone_friend_ref(lf);
ms_debug("Contact removed: %s", linphone_friend_get_name(lf));
cdc->contact_removed_cb(cdc, 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) {
ms_list_remove(vCards, vCard);
}
}
}
}
friends = ms_list_next(friends);
}
ms_list_free(localFriends);
linphone_carddav_pull_vcards(cdc, vCards);
}
ms_list_free(vCards);
......@@ -291,6 +353,18 @@ void linphone_carddav_set_synchronization_done_callback(LinphoneCardDavContext *
cdc->sync_done_cb = cb;
}
void linphone_carddav_set_new_contact_callback(LinphoneCardDavContext *cdc, LinphoneCardDavContactCreatedCb cb) {
cdc->contact_created_cb = cb;
}
void linphone_carddav_set_updated_contact_callback(LinphoneCardDavContext *cdc, LinphoneCardDavContactUpdatedCb cb) {
cdc->contact_updated_cb = cb;
}
void linphone_carddav_set_removed_contact_callback(LinphoneCardDavContext *cdc, LinphoneCardDavContactRemovedCb cb) {
cdc->contact_removed_cb = cb;
}
static LinphoneCardDavQuery* linphone_carddav_create_propfind_query(LinphoneCardDavContext *cdc) {
LinphoneCardDavQuery *query = (LinphoneCardDavQuery *)ms_new0(LinphoneCardDavQuery, 1);
query->context = cdc;
......@@ -340,10 +414,12 @@ static LinphoneCardDavQuery* linphone_carddav_create_addressbook_multiget_query(
sprintf(body, "%s", "<card:addressbook-multiget xmlns:d=\"DAV:\" xmlns:card=\"urn:ietf:params:xml:ns:carddav\"><d:prop><d:getetag /><card:address-data content-type='text-vcard' version='4.0'/></d:prop>");
while (iterator) {
LinphoneCardDavResponse *response = (LinphoneCardDavResponse *)iterator->data;
char temp_body[100];
sprintf(temp_body, "<d:href>%s</d:href>", response->url);
sprintf(body, "%s%s", body, temp_body);
iterator = ms_list_next(iterator);
if (response) {
char temp_body[100];
sprintf(temp_body, "<d:href>%s</d:href>", response->url);
sprintf(body, "%s%s", body, temp_body);
iterator = ms_list_next(iterator);
}
}
sprintf(body, "%s%s", body, "</card:addressbook-multiget>");
query->body = ms_strdup(body);
......
......@@ -46,17 +46,17 @@ typedef struct _LinphoneCardDavResponse LinphoneCardDavResponse;
/**
* Callback used to notify a new contact has been created on the CardDAV server
**/
typedef void (*LinphoneCardDavContactCreatedCb)(LinphoneFriend *lf);
typedef void (*LinphoneCardDavContactCreatedCb)(LinphoneCardDavContext *cdc, LinphoneFriend *lf);
/**
* Callback used to notify a contact has been updated on the CardDAV server
**/
typedef void (*LinphoneCardDavContactUpdatedCb)(LinphoneFriend *lf);
typedef void (*LinphoneCardDavContactUpdatedCb)(LinphoneCardDavContext *cdc, LinphoneFriend *new_friend, LinphoneFriend *old_friend);
/**
* Callback used to notify a contact has been removed on the CardDAV server
**/
typedef void (*LinphoneCardDavContactRemovedCb)(LinphoneFriend *lf);
typedef void (*LinphoneCardDavContactRemovedCb)(LinphoneCardDavContext *cdc, LinphoneFriend *lf);
/**
* Callback used to notify a contact has been removed on the CardDAV server
......@@ -117,6 +117,27 @@ LINPHONE_PUBLIC void linphone_carddav_delete_vcard(LinphoneCardDavContext *cdc,
*/
LINPHONE_PUBLIC void linphone_carddav_set_synchronization_done_callback(LinphoneCardDavContext *cdc, LinphoneCardDavSynchronizationDoneCb cb);
/**
* Set the new contact callback.
* @param cdc LinphoneCardDavContext object
* @param cb The new contact callback to be used.
*/
LINPHONE_PUBLIC void linphone_carddav_set_new_contact_callback(LinphoneCardDavContext *cdc, LinphoneCardDavContactCreatedCb cb);
/**
* Set the updated contact callback.
* @param cdc LinphoneCardDavContext object
* @param cb The updated contact callback to be used.
*/
LINPHONE_PUBLIC void linphone_carddav_set_updated_contact_callback(LinphoneCardDavContext *cdc, LinphoneCardDavContactUpdatedCb cb);
/**
* Set the removed contact callback.
* @param cdc LinphoneCardDavContext object
* @param cb The removed contact callback to be used.
*/
LINPHONE_PUBLIC void linphone_carddav_set_removed_contact_callback(LinphoneCardDavContext *cdc, LinphoneCardDavContactRemovedCb cb);
/**
* Retrieves the current cTag value for the remote server
* @param cdc LinphoneCardDavContext object
......
......@@ -935,6 +935,8 @@ static void linphone_create_table(sqlite3* db) {
"send_subscribe INTEGER,"
"ref_key TEXT,"
"vCard TEXT,"
"vCard_etag TEXT,"
"vCard_url TEXT,"
"presence_received INTEGER"
");",
0, 0, &errmsg);
......@@ -992,7 +994,9 @@ void linphone_core_friends_storage_close(LinphoneCore *lc) {
* | 3 | send_subscribe
* | 4 | ref_key
* | 5 | vCard
* | 6 | presence_received
* | 6 | vCard eTag
* | 7 | vCard URL
* | 8 | presence_received
*/
static int create_friend(void *data, int argc, char **argv, char **colName) {
MSList **list = (MSList **)data;
......@@ -1001,7 +1005,11 @@ static int create_friend(void *data, int argc, char **argv, char **colName) {
unsigned int storage_id = atoi(argv[0]);
vcard = linphone_vcard_new_from_vcard4_buffer(argv[5]);
lf = linphone_friend_new_from_vcard(vcard);
if (vcard) {
linphone_vcard_set_etag(vcard, argv[6]);
linphone_vcard_set_url(vcard, argv[7]);
lf = linphone_friend_new_from_vcard(vcard);
}
if (!lf) {
LinphoneAddress *addr = linphone_address_new(argv[1]);
lf = linphone_friend_new();
......@@ -1009,8 +1017,8 @@ static int create_friend(void *data, int argc, char **argv, char **colName) {
}
linphone_friend_set_inc_subscribe_policy(lf, atoi(argv[2]));
linphone_friend_send_subscribe(lf, atoi(argv[3]));
linphone_friend_set_ref_key(lf, argv[4]);
lf->presence_received = atoi(argv[6]);
linphone_friend_set_ref_key(lf, ms_strdup(argv[4]));
lf->presence_received = atoi(argv[8]);
lf->storage_id = storage_id;
*list = ms_list_append(*list, linphone_friend_ref(lf));
......@@ -1044,27 +1052,33 @@ void linphone_core_store_friend_in_db(LinphoneCore *lc, LinphoneFriend *lf) {
if (lc && lc->friends_db) {
char *buf;
int store_friends = lp_config_get_int(lc->config, "misc", "store_friends", 1);
LinphoneVCard *vcard = linphone_friend_get_vcard(lf);
if (!store_friends) {
return;
}
if (lf->storage_id > 0) {
buf = sqlite3_mprintf("UPDATE friends SET sip_uri=%Q,subscribe_policy=%i,send_subscribe=%i,ref_key=%Q,vCard=%Q,presence_received=%i WHERE (id = %i);",
buf = sqlite3_mprintf("UPDATE friends SET sip_uri=%Q,subscribe_policy=%i,send_subscribe=%i,ref_key=%Q,vCard=%Q,vCard_etag=%Q,vCard_url=%Q,presence_received=%i WHERE (id = %i);",
linphone_address_as_string(linphone_friend_get_address(lf)),
lf->pol,
lf->subscribe,
lf->refkey,
linphone_vcard_as_vcard4_string(linphone_friend_get_vcard(lf)),
linphone_vcard_as_vcard4_string(vcard),
linphone_vcard_get_etag(vcard),
linphone_vcard_get_url(vcard),
lf->presence_received,
lf->storage_id
);
} else {
buf = sqlite3_mprintf("INSERT INTO friends VALUES(NULL,%Q,%i,%i,%Q,%Q,%i);",
buf = sqlite3_mprintf("INSERT INTO friends VALUES(NULL,%Q,%i,%i,%Q,%Q,%Q,%Q,%i);",
linphone_address_as_string(linphone_friend_get_address(lf)),
lf->pol,
lf->subscribe,
lf->refkey,
linphone_vcard_as_vcard4_string(linphone_friend_get_vcard(lf)),
linphone_vcard_as_vcard4_string(vcard),
linphone_vcard_get_etag(vcard),
linphone_vcard_get_url(vcard),
lf->presence_received
);
}
......
......@@ -23,6 +23,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
struct _LinphoneVCard {
shared_ptr<belcard::BelCard> belCard;
const char *etag;
const char *url;
};
extern "C" LinphoneVCard* linphone_vcard_new(void) {
......@@ -150,4 +152,27 @@ extern "C" MSList* linphone_vcard_get_sip_addresses(const LinphoneVCard *vCard)
}
}
return result;
}
extern "C" const char* linphone_vcard_get_uid(const LinphoneVCard *vCard) {
if (vCard->belCard->getUniqueId()) {
return vCard->belCard->getUniqueId()->getValue().c_str();
}
return NULL;
}
extern "C" void linphone_vcard_set_etag(LinphoneVCard *vCard, const char * etag) {
vCard->etag = ms_strdup(etag);
}
extern "C" const char* linphone_vcard_get_etag(const LinphoneVCard *vCard) {
return vCard->etag;
}
extern "C" void linphone_vcard_set_url(LinphoneVCard *vCard, const char * url) {
vCard->url = ms_strdup(url);
}
extern "C" const char* linphone_vcard_get_url(const LinphoneVCard *vCard) {
return vCard->url;
}
\ No newline at end of file
......@@ -119,6 +119,14 @@ LINPHONE_PUBLIC void linphone_vcard_edit_main_sip_address(LinphoneVCard *vCard,
*/
LINPHONE_PUBLIC MSList* linphone_vcard_get_sip_addresses(const LinphoneVCard *vCard);
const char* linphone_vcard_get_uid(const LinphoneVCard *vCard);
void linphone_vcard_set_etag(LinphoneVCard *vCard, const char * etag);
const char* linphone_vcard_get_etag(const LinphoneVCard *vCard);
void linphone_vcard_set_url(LinphoneVCard *vCard, const char * url);
const char* linphone_vcard_get_url(const LinphoneVCard *vCard);
/**
* @}
*/
......
......@@ -69,4 +69,24 @@ void linphone_vcard_edit_main_sip_address(LinphoneVCard *vCard, const char *sip_
MSList* linphone_vcard_get_sip_addresses(const LinphoneVCard *vCard) {
return NULL;
}
const char* linphone_vcard_get_uid(const LinphoneVCard *vCard) {
return NULL;
}
void linphone_vcard_set_etag(LinphoneVCard *vCard, const char * etag) {
}
const char* linphone_vcard_get_etag(const LinphoneVCard *vCard) {
return NULL;
}
void linphone_vcard_set_url(LinphoneVCard *vCard, const char * url) {
}
const char* linphone_vcard_get_url(const LinphoneVCard *vCard) {
return NULL;
}
\ No newline at end of file
......@@ -184,24 +184,62 @@ end:
}
#endif
typedef struct _LinphoneCardDAVStats {
int sync_done_count;
int new_contact_count;
int removed_contact_count;
int updated_contact_count;
} LinphoneCardDAVStats;
static void carddav_sync_done(LinphoneCardDavContext *c, bool_t success, const char *message) {
LinphoneCardDAVStats *stats = (LinphoneCardDAVStats *)linphone_carddav_get_user_data(c);
BC_ASSERT_TRUE(success);
stats->sync_done_count++;
linphone_carddav_destroy(c);
}
static void carddav_new_contact(LinphoneCardDavContext *c, LinphoneFriend *lf) {
LinphoneCardDAVStats *stats = (LinphoneCardDAVStats *)linphone_carddav_get_user_data(c);
BC_ASSERT_PTR_NOT_NULL_FATAL(lf);
stats->new_contact_count++;
linphone_friend_unref(lf);
}
static void carddav_removed_contact(LinphoneCardDavContext *c, LinphoneFriend *lf) {
LinphoneCardDAVStats *stats = (LinphoneCardDAVStats *)linphone_carddav_get_user_data(c);
BC_ASSERT_PTR_NOT_NULL_FATAL(lf);
stats->removed_contact_count++;
linphone_friend_unref(lf);
}
static void carddav_updated_contact(LinphoneCardDavContext *c, LinphoneFriend *lf1, LinphoneFriend *lf2) {
LinphoneCardDAVStats *stats = (LinphoneCardDAVStats *)linphone_carddav_get_user_data(c);
BC_ASSERT_PTR_NOT_NULL_FATAL(lf1);
BC_ASSERT_PTR_NOT_NULL_FATAL(lf2);
stats->updated_contact_count++;
linphone_friend_unref(lf1);
linphone_friend_unref(lf2);
}
static void carddav_sync(void) {
LinphoneCoreManager *manager = linphone_core_manager_new2("carddav_rc", FALSE);
LinphoneCardDavContext *c = linphone_core_create_carddav_context(manager->lc);
LinphoneCardDAVStats *stats = (LinphoneCardDAVStats *)ms_new0(LinphoneCardDAVStats, 1);
BC_ASSERT_PTR_NOT_NULL_FATAL(c);
BC_ASSERT_PTR_NOT_NULL(c->server_url);
BC_ASSERT_PTR_NOT_NULL(c->username);
BC_ASSERT_PTR_NOT_NULL(c->ha1);
linphone_carddav_set_user_data(c, stats);
linphone_carddav_set_synchronization_done_callback(c, carddav_sync_done);
linphone_carddav_set_new_contact_callback(c, carddav_new_contact);
linphone_carddav_set_removed_contact_callback(c, carddav_removed_contact);
linphone_carddav_set_updated_contact_callback(c, carddav_updated_contact);
linphone_carddav_synchronize(c);
wait_for_until(manager->lc, NULL, NULL, 1, 1000);
wait_for_until(manager->lc, NULL, &stats->new_contact_count, 1, 2000);
wait_for_until(manager->lc, NULL, &stats->sync_done_count, 1, 2000);
linphone_core_manager_destroy(manager);
}
#else
......@@ -219,7 +257,7 @@ test_t vcard_tests[] = {
{ "Friends storage migration from rc to db", friends_migration },
{ "Friends storage in sqlite database", friends_sqlite_storage },
#endif
{ "CardDAV synchronization", carddav_sync }
{ "CardDAV synchronization", carddav_sync },
#else
{ "Dummy test", dummy_test }
#endif
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment