diff --git a/coreapi/carddav.c b/coreapi/carddav.c
index 55c8860f6..f1a63d073 100644
--- a/coreapi/carddav.c
+++ b/coreapi/carddav.c
@@ -55,30 +55,157 @@ void* linphone_carddav_get_user_data(LinphoneCardDavContext *cdc) {
return cdc->user_data;
}
-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: find out if there are new/delete URLs and compare eTags with the current vCards
+void linphone_carddav_synchronize(LinphoneCardDavContext *cdc) {
+ linphone_carddav_get_current_ctag(cdc);
+}
+
+static void linphone_carddav_sync_done(LinphoneCardDavContext *cdc, bool_t success, const char *msg) {
+ if (success) {
+ linphone_core_set_carddav_current_ctag(cdc->lc, cdc->ctag);
}
+
if (cdc->sync_done_cb) {
- cdc->sync_done_cb(cdc, TRUE, "TODO: remove lated");
+ cdc->sync_done_cb(cdc, success, msg);
}
}
+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
+ }
+ ms_list_free(vCards);
+ linphone_carddav_sync_done(cdc, TRUE, "");
+}
+
+static MSList* parse_vcards_from_xml_response(const char *body) {
+ MSList *result = NULL;
+ xmlparsing_context_t *xml_ctx = linphone_xmlparsing_context_new();
+ xmlSetGenericErrorFunc(xml_ctx, linphone_xmlparsing_genericxml_error);
+ xml_ctx->doc = xmlReadDoc((const unsigned char*)body, 0, NULL, 0);
+ if (xml_ctx->doc != NULL) {
+ if (linphone_create_xml_xpath_context(xml_ctx) < 0) goto end;
+ linphone_xml_xpath_context_init_carddav_ns(xml_ctx);
+ {
+ xmlXPathObjectPtr etags = linphone_get_xml_xpath_object_for_node_list(xml_ctx, "/d:multistatus/d:response/d:propstat/d:prop/d:getetag");
+ xmlXPathObjectPtr hrefs = linphone_get_xml_xpath_object_for_node_list(xml_ctx, "/d:multistatus/d:response/d:href");
+ xmlXPathObjectPtr vcards = linphone_get_xml_xpath_object_for_node_list(xml_ctx, "/d:multistatus/d:response/d:propstat/d:prop/card:address-data");
+ if (etags != NULL && hrefs != NULL && vcards != NULL) {
+ if (etags->nodesetval != NULL && hrefs->nodesetval != NULL && vcards->nodesetval != NULL) {
+ xmlNodeSetPtr etags_nodes = etags->nodesetval;
+ xmlNodeSetPtr hrefs_nodes = hrefs->nodesetval;
+ xmlNodeSetPtr vcards_nodes = vcards->nodesetval;
+ if (etags_nodes->nodeNr >= 1 && hrefs_nodes->nodeNr == etags_nodes->nodeNr && vcards_nodes->nodeNr == etags_nodes->nodeNr) {
+ int i;
+ for (i = 0; i < vcards_nodes->nodeNr; i++) {
+ xmlNodePtr etag_node = etags_nodes->nodeTab[i];
+ xmlNodePtr href_node = hrefs_nodes->nodeTab[i];
+ xmlNodePtr vcard_node = vcards_nodes->nodeTab[i];
+ if (vcard_node->children != NULL) {
+ char *etag = (char *)xmlNodeListGetString(xml_ctx->doc, etag_node->children, 1);
+ char *url = (char *)xmlNodeListGetString(xml_ctx->doc, href_node->children, 1);
+ char *vcard = (char *)xmlNodeListGetString(xml_ctx->doc, vcard_node->children, 1);
+ LinphoneCardDavResponse *response = ms_new0(LinphoneCardDavResponse, 1);
+ response->etag = ms_strdup(etag);
+ response->url = ms_strdup(url);
+ response->vcard = ms_strdup(vcard);
+ result = ms_list_append(result, response);
+ ms_debug("Added vCard object with eTag %s, URL %s and vCard %s", etag, url, vcard);
+ }
+ }
+ }
+ }
+ xmlXPathFreeObject(vcards);
+ xmlXPathFreeObject(etags);
+ xmlXPathFreeObject(hrefs);
+ }
+ }
+ }
+end:
+ linphone_xmlparsing_context_destroy(xml_ctx);
+ return result;
+}
+
+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
+ linphone_carddav_pull_vcards(cdc, vCards);
+ }
+ ms_list_free(vCards);
+}
+
+static MSList* parse_vcards_etags_from_xml_response(const char *body) {
+ MSList *result = NULL;
+ xmlparsing_context_t *xml_ctx = linphone_xmlparsing_context_new();
+ xmlSetGenericErrorFunc(xml_ctx, linphone_xmlparsing_genericxml_error);
+ xml_ctx->doc = xmlReadDoc((const unsigned char*)body, 0, NULL, 0);
+ if (xml_ctx->doc != NULL) {
+ if (linphone_create_xml_xpath_context(xml_ctx) < 0) goto end;
+ linphone_xml_xpath_context_init_carddav_ns(xml_ctx);
+ {
+ xmlXPathObjectPtr etags = linphone_get_xml_xpath_object_for_node_list(xml_ctx, "/d:multistatus/d:response/d:propstat/d:prop/d:getetag");
+ xmlXPathObjectPtr hrefs = linphone_get_xml_xpath_object_for_node_list(xml_ctx, "/d:multistatus/d:response/d:href");
+ if (etags != NULL && hrefs != NULL) {
+ if (etags->nodesetval != NULL && hrefs->nodesetval != NULL) {
+ xmlNodeSetPtr etags_nodes = etags->nodesetval;
+ xmlNodeSetPtr hrefs_nodes = hrefs->nodesetval;
+ if (etags_nodes->nodeNr >= 1 && hrefs_nodes->nodeNr == etags_nodes->nodeNr) {
+ int i;
+ for (i = 0; i < etags_nodes->nodeNr; i++) {
+ xmlNodePtr etag_node = etags_nodes->nodeTab[i];
+ xmlNodePtr href_node = hrefs_nodes->nodeTab[i];
+ if (etag_node->children != NULL && href_node->children != NULL) {
+ char *etag = (char *)xmlNodeListGetString(xml_ctx->doc, etag_node->children, 1);
+ char *url = (char *)xmlNodeListGetString(xml_ctx->doc, href_node->children, 1);
+ LinphoneCardDavResponse *response = ms_new0(LinphoneCardDavResponse, 1);
+ response->etag = ms_strdup(etag);
+ response->url = ms_strdup(url);
+ result = ms_list_append(result, response);
+ ms_debug("Added vCard object with eTag %s and URL %s", etag, url);
+ }
+ }
+ }
+ }
+ xmlXPathFreeObject(etags);
+ xmlXPathFreeObject(hrefs);
+ }
+ }
+ }
+end:
+ linphone_xmlparsing_context_destroy(xml_ctx);
+ return result;
+}
+
static void linphone_carddav_ctag_fetched(LinphoneCardDavContext *cdc, int ctag) {
+ ms_debug("Remote cTag for CardDAV addressbook is %i, local one is %i", ctag, cdc->ctag);
if (ctag == -1 || ctag > cdc->ctag) {
cdc->ctag = ctag;
linphone_carddav_fetch_vcards(cdc);
} else {
ms_message("No changes found on server, skipping sync");
- if (cdc->sync_done_cb) {
- cdc->sync_done_cb(cdc, TRUE, "Synchronization skipped because cTag already up to date");
- }
+ linphone_carddav_sync_done(cdc, TRUE, "Synchronization skipped because cTag already up to date");
}
}
-void linphone_carddav_synchronize(LinphoneCardDavContext *cdc) {
- linphone_carddav_get_current_ctag(cdc);
+static int parse_ctag_value_from_xml_response(const char *body) {
+ int result = -1;
+ xmlparsing_context_t *xml_ctx = linphone_xmlparsing_context_new();
+ xmlSetGenericErrorFunc(xml_ctx, linphone_xmlparsing_genericxml_error);
+ xml_ctx->doc = xmlReadDoc((const unsigned char*)body, 0, NULL, 0);
+ if (xml_ctx->doc != NULL) {
+ char *response = NULL;
+ if (linphone_create_xml_xpath_context(xml_ctx) < 0) goto end;
+ linphone_xml_xpath_context_init_carddav_ns(xml_ctx);
+ response = linphone_get_xml_text_content(xml_ctx, "/d:multistatus/d:response/d:propstat/d:prop/x1:getctag");
+ if (response) {
+ result = atoi(response);
+ linphone_free_xml_text_content(response);
+ }
+ }
+end:
+ linphone_xmlparsing_context_destroy(xml_ctx);
+ return result;
}
static void process_response_from_carddav_request(void *data, const belle_http_response_event_t *event) {
@@ -88,16 +215,16 @@ static void process_response_from_carddav_request(void *data, const belle_http_r
int code = belle_http_response_get_status_code(event->response);
if (code == 207 || code == 200) {
const char *body = belle_sip_message_get_body((belle_sip_message_t *)event->response);
- ms_message("CardDAV query response body: %s", body);
query->status = LinphoneCardDavQueryStatusOk;
switch(query->type) {
case LinphoneCardDavQueryTypePropfind:
- linphone_carddav_ctag_fetched(query->context, 0);//TODO parse value from body
+ linphone_carddav_ctag_fetched(query->context, parse_ctag_value_from_xml_response(body));
break;
case LinphoneCardDavQueryTypeAddressbookQuery:
- linphone_carddav_vcards_fetched(query->context, NULL);//TODO parse value from body
+ linphone_carddav_vcards_fetched(query->context, parse_vcards_etags_from_xml_response(body));
break;
case LinphoneCardDavQueryTypeAddressbookMultiget:
+ linphone_carddav_vcards_pulled(query->context, parse_vcards_from_xml_response(body));
break;
}
} else {
@@ -109,12 +236,10 @@ static void process_response_from_carddav_request(void *data, const belle_http_r
static void process_io_error_from_carddav_request(void *data, const belle_sip_io_error_event_t *event) {
LinphoneCardDavQuery *query = (LinphoneCardDavQuery *)data;
- ms_error("I/O Error during CardDAV request sending");
+ ms_error("I/O error during CardDAV request sending");
query->status = LinphoneCardDavQueryStatusFailed;
ms_free(query);
- if (query->context->sync_done_cb) {
- query->context->sync_done_cb(query->context, FALSE, "I/O Error during CardDAV request sending");
- }
+ linphone_carddav_sync_done(query->context, FALSE, "I/O error during CardDAV request sending");
}
static void process_auth_requested_from_carddav_request(void *data, belle_sip_auth_event_t *event) {
@@ -131,10 +256,8 @@ static void process_auth_requested_from_carddav_request(void *data, belle_sip_au
}
} else {
query->status = LinphoneCardDavQueryStatusFailed;
- ms_error("Authentication error during CardDAV request sending");
- if (query->context->sync_done_cb) {
- query->context->sync_done_cb(query->context, FALSE, "Authentication error during CardDAV request sending");
- }
+ ms_error("Authentication requested during CardDAV request sending, and username/password weren't provided");
+ linphone_carddav_sync_done(query->context, FALSE, "Authentication requested during CardDAV request sending, and username/password weren't provided");
}
}
@@ -203,7 +326,7 @@ static LinphoneCardDavQuery* linphone_carddav_create_addressbook_query(LinphoneC
LinphoneCardDavQuery *query = (LinphoneCardDavQuery *)ms_new0(LinphoneCardDavQuery, 1);
query->context = cdc;
query->depth = "1";
- query->body = "";
+ query->body = "";
query->method = "REPORT";
query->url = cdc->server_url;
query->type = LinphoneCardDavQueryTypeAddressbookQuery;
@@ -218,13 +341,27 @@ void linphone_carddav_fetch_vcards(LinphoneCardDavContext *cdc) {
static LinphoneCardDavQuery* linphone_carddav_create_addressbook_multiget_query(LinphoneCardDavContext *cdc, MSList *vcards) {
LinphoneCardDavQuery *query = (LinphoneCardDavQuery *)ms_new0(LinphoneCardDavQuery, 1);
+ char body[(ms_list_size(vcards)+1)*100];
+ MSList *iterator = vcards;
+
query->context = cdc;
query->depth = "1";
query->method = "REPORT";
query->url = cdc->server_url;
query->type = LinphoneCardDavQueryTypeAddressbookMultiget;
query->status = LinphoneCardDavQueryStatusIdle;
- //TODO: body
+
+ sprintf(body, "%s", "");
+ while (iterator) {
+ LinphoneCardDavResponse *response = (LinphoneCardDavResponse *)iterator->data;
+ char temp_body[100];
+ sprintf(temp_body, "%s", response->url);
+ sprintf(body, "%s%s", body, temp_body);
+ iterator = ms_list_next(iterator);
+ }
+ sprintf(body, "%s%s", body, "");
+ query->body = ms_strdup(body);
+
return query;
}
diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c
index 3a306ad78..2baee1e21 100644
--- a/coreapi/linphonecore.c
+++ b/coreapi/linphonecore.c
@@ -7511,7 +7511,7 @@ void linphone_core_set_carddav_current_ctag(LinphoneCore *lc, int ctag) {
int linphone_core_get_carddav_last_ctag(LinphoneCore *lc) {
if (lc) {
LpConfig *lpc = linphone_core_get_config(lc);
- return lp_config_get_int(lpc, "carddav", "ctag", -1);
+ return lp_config_get_int(lpc, "carddav", "ctag", 0);
}
- return -1;
+ return 0;
}
\ No newline at end of file
diff --git a/coreapi/private.h b/coreapi/private.h
index f3c21934d..4197bcba8 100644
--- a/coreapi/private.h
+++ b/coreapi/private.h
@@ -1328,6 +1328,7 @@ char * linphone_get_xml_text_content(xmlparsing_context_t *xml_ctx, const char *
const char * linphone_get_xml_attribute_text_content(xmlparsing_context_t *xml_ctx, const char *xpath_expression, const char *attribute_name);
void linphone_free_xml_text_content(const char *text);
xmlXPathObjectPtr linphone_get_xml_xpath_object_for_node_list(xmlparsing_context_t *xml_ctx, const char *xpath_expression);
+void linphone_xml_xpath_context_init_carddav_ns(xmlparsing_context_t *xml_ctx);
/*****************************************************************************
* OTHER UTILITY FUNCTIONS *
diff --git a/coreapi/xml.c b/coreapi/xml.c
index 28d773add..0b4e29077 100644
--- a/coreapi/xml.c
+++ b/coreapi/xml.c
@@ -123,3 +123,11 @@ void linphone_free_xml_text_content(const char *text) {
xmlXPathObjectPtr linphone_get_xml_xpath_object_for_node_list(xmlparsing_context_t *xml_ctx, const char *xpath_expression) {
return xmlXPathEvalExpression((const xmlChar *)xpath_expression, xml_ctx->xpath_ctx);
}
+
+void linphone_xml_xpath_context_init_carddav_ns(xmlparsing_context_t *xml_ctx) {
+ if (xml_ctx && xml_ctx->xpath_ctx) {
+ xmlXPathRegisterNs(xml_ctx->xpath_ctx, (const xmlChar*)"d", (const xmlChar*)"DAV:");
+ xmlXPathRegisterNs(xml_ctx->xpath_ctx, (const xmlChar*)"card", (const xmlChar*)"urn:ietf:params:xml:ns:carddav");
+ xmlXPathRegisterNs(xml_ctx->xpath_ctx, (const xmlChar*)"x1", (const xmlChar*)"http://calendarserver.org/ns/");
+ }
+}
\ No newline at end of file