Commit a8e6cc90 authored by Sylvain Berfini's avatar Sylvain Berfini 🎩
Browse files

More work on CardDAV sync: doing propfind and addressbook-query requests

parent f85edbaa
......@@ -91,10 +91,9 @@ liblinphone_la_SOURCES=\
xml.c \
xmlrpc.c \
vtables.c \
carddav.cc \
carddav.c \
$(GITVERSION_FILE)
liblinphone_la_CXXFLAGS=-std=c++11
if BUILD_UPNP
liblinphone_la_SOURCES+=upnp.c upnp.h
endif
......@@ -121,6 +120,7 @@ endif
if BUILD_VCARD
liblinphone_la_SOURCES+=vcard.cc vcard.h
liblinphone_la_CXXFLAGS=-std=c++11
else
liblinphone_la_SOURCES+=vcard_stubs.c vcard.h
endif
......
/*
carddav.c
Copyright (C) 2015 Belledonne Communications SARL
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "linphonecore.h"
#include "private.h"
LinphoneCardDavContext* linphone_core_create_carddav_context(LinphoneCore *lc) {
LinphoneCardDavContext *carddav_context = NULL;
if (!lc) {
return NULL;
}
#ifdef VCARD_ENABLED
carddav_context = (LinphoneCardDavContext *)ms_new0(LinphoneCardDavContext, 1);
carddav_context->lc = lc;
carddav_context->server_url = linphone_core_get_carddav_server_url(lc);
carddav_context->ctag = linphone_core_get_carddav_last_ctag(lc);
carddav_context->username = linphone_core_get_carddav_username(lc);
carddav_context->password = linphone_core_get_carddav_password(lc);
carddav_context->ha1 = linphone_core_get_carddav_ha1(lc);
#else
ms_error("vCard isn't available (maybe it wasn't compiled), can't do CardDAV sync");
#endif
return carddav_context;
}
void linphone_carddav_destroy(LinphoneCardDavContext *cdc) {
if (cdc) {
ms_free(cdc);
}
}
void linphone_carddav_set_user_data(LinphoneCardDavContext *cdc, void *ud) {
cdc->user_data = ud;
}
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
}
if (cdc->sync_done_cb) {
cdc->sync_done_cb(cdc, TRUE, "TODO: remove lated");
}
}
static void linphone_carddav_ctag_fetched(LinphoneCardDavContext *cdc, int 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");
}
}
}
void linphone_carddav_synchronize(LinphoneCardDavContext *cdc) {
linphone_carddav_get_current_ctag(cdc);
}
static void process_response_from_carddav_request(void *data, const belle_http_response_event_t *event) {
LinphoneCardDavQuery *query = (LinphoneCardDavQuery *)data;
if (event->response) {
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
break;
case LinphoneCardDavQueryTypeAddressbookQuery:
linphone_carddav_vcards_fetched(query->context, NULL);//TODO parse value from body
break;
case LinphoneCardDavQueryTypeAddressbookMultiget:
break;
}
} else {
query->status = LinphoneCardDavQueryStatusFailed;
}
}
ms_free(query);
}
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");
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");
}
}
static void process_auth_requested_from_carddav_request(void *data, belle_sip_auth_event_t *event) {
LinphoneCardDavQuery *query = (LinphoneCardDavQuery *)data;
LinphoneCardDavContext *context = query->context;
if (context->username && (context->password || context->ha1)) {
belle_sip_auth_event_set_username(event, context->username);
if (context->password) {
belle_sip_auth_event_set_passwd(event, context->password);
}
if (context->ha1) {
belle_sip_auth_event_set_ha1(event, context->ha1);
}
} 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");
}
}
}
static void linphone_carddav_send_query(LinphoneCardDavQuery *query) {
belle_http_request_listener_callbacks_t cbs = { 0 };
belle_http_request_listener_t *l = NULL;
belle_generic_uri_t *uri = NULL;
belle_http_request_t *req = NULL;
belle_sip_memory_body_handler_t *bh = NULL;
uri = belle_generic_uri_parse(query->url);
if (!uri) {
belle_sip_error("Could not send request, URL %s is invalid", query->url);
query->status = LinphoneCardDavQueryStatusFailed;
return;
}
req = belle_http_request_create(query->method, uri, belle_sip_header_content_type_create("application", "xml; charset=utf-8"), belle_sip_header_create("Depth", query->depth), NULL);
if (!req) {
belle_sip_object_unref(uri);
belle_sip_error("Could not create belle_http_request_t");
query->status = LinphoneCardDavQueryStatusFailed;
return;
}
query->status = LinphoneCardDavQueryStatusPending;
bh = belle_sip_memory_body_handler_new_copy_from_buffer(query->body, strlen(query->body), NULL, NULL);
belle_sip_message_set_body_handler(BELLE_SIP_MESSAGE(req), BELLE_SIP_BODY_HANDLER(bh));
cbs.process_response = process_response_from_carddav_request;
cbs.process_io_error = process_io_error_from_carddav_request;
cbs.process_auth_requested = process_auth_requested_from_carddav_request;
l = belle_http_request_listener_create_from_callbacks(&cbs, query);
belle_http_provider_send_request(query->context->lc->http_provider, req, l);
}
void linphone_carddav_put_vcard(LinphoneCardDavContext *cdc, LinphoneFriend *lf) {
//TODO
}
void linphone_carddav_delete_vcard(LinphoneCardDavContext *cdc, LinphoneFriend *lf) {
//TODO
}
void linphone_carddav_set_synchronization_done_callback(LinphoneCardDavContext *cdc, LinphoneCardDavSynchronizationDoneCb cb) {
cdc->sync_done_cb = cb;
}
static LinphoneCardDavQuery* linphone_carddav_create_propfind_query(LinphoneCardDavContext *cdc) {
LinphoneCardDavQuery *query = (LinphoneCardDavQuery *)ms_new0(LinphoneCardDavQuery, 1);
query->context = cdc;
query->depth = "0";
query->body = "<d:propfind xmlns:d=\"DAV:\" xmlns:cs=\"http://calendarserver.org/ns/\"><d:prop><cs:getctag /></d:prop></d:propfind>";
query->method = "PROPFIND";
query->url = cdc->server_url;
query->type = LinphoneCardDavQueryTypePropfind;
query->status = LinphoneCardDavQueryStatusIdle;
return query;
}
void linphone_carddav_get_current_ctag(LinphoneCardDavContext *cdc) {
LinphoneCardDavQuery *query = linphone_carddav_create_propfind_query(cdc);
linphone_carddav_send_query(query);
}
static LinphoneCardDavQuery* linphone_carddav_create_addressbook_query(LinphoneCardDavContext *cdc) {
LinphoneCardDavQuery *query = (LinphoneCardDavQuery *)ms_new0(LinphoneCardDavQuery, 1);
query->context = cdc;
query->depth = "1";
query->body = "<card:addressbook-query 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></card:addressbook-query>";
query->method = "REPORT";
query->url = cdc->server_url;
query->type = LinphoneCardDavQueryTypeAddressbookQuery;
query->status = LinphoneCardDavQueryStatusIdle;
return query;
}
void linphone_carddav_fetch_vcards(LinphoneCardDavContext *cdc) {
LinphoneCardDavQuery *query = linphone_carddav_create_addressbook_query(cdc);
linphone_carddav_send_query(query);
}
static LinphoneCardDavQuery* linphone_carddav_create_addressbook_multiget_query(LinphoneCardDavContext *cdc, MSList *vcards) {
LinphoneCardDavQuery *query = (LinphoneCardDavQuery *)ms_new0(LinphoneCardDavQuery, 1);
query->context = cdc;
query->depth = "1";
query->method = "REPORT";
query->url = cdc->server_url;
query->type = LinphoneCardDavQueryTypeAddressbookMultiget;
query->status = LinphoneCardDavQueryStatusIdle;
//TODO: body
return query;
}
void linphone_carddav_pull_vcards(LinphoneCardDavContext *cdc, MSList *vcards_to_pull) {
LinphoneCardDavQuery *query = linphone_carddav_create_addressbook_multiget_query(cdc, vcards_to_pull);
linphone_carddav_send_query(query);
}
\ No newline at end of file
/*
carddav.cc
Copyright (C) 2015 Belledonne Communications SARL
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "carddav.h"
extern "C" void linphone_core_start_carddav_sync(LinphoneCore *lc) {
#ifdef VCARD_ENABLED
#else
ms_error("vCard isn't available (maybe it wasn't compiled), can't do CardDAV sync");
#endif
}
\ No newline at end of file
......@@ -23,10 +23,118 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#ifdef __cplusplus
extern "C" {
#endif
typedef struct _LinphoneCardDavContext LinphoneCardDavContext;
#include "linphonecore.h"
typedef enum _LinphoneCardDavQueryType {
LinphoneCardDavQueryTypePropfind,
LinphoneCardDavQueryTypeAddressbookQuery,
LinphoneCardDavQueryTypeAddressbookMultiget
} LinphoneCardDavQueryType;
LINPHONE_PUBLIC void linphone_core_start_carddav_sync(LinphoneCore *lc);
typedef enum _LinphoneCardDavQueryStatus {
LinphoneCardDavQueryStatusIdle,
LinphoneCardDavQueryStatusPending,
LinphoneCardDavQueryStatusOk,
LinphoneCardDavQueryStatusFailed
} LinphoneCardDavQueryStatus;
typedef struct _LinphoneCardDavQuery LinphoneCardDavQuery;
typedef struct _LinphoneCardDavResponse LinphoneCardDavResponse;
/**
* Callback used to notify a new contact has been created on the CardDAV server
**/
typedef void (*LinphoneCardDavContactCreatedCb)(LinphoneFriend *lf);
/**
* Callback used to notify a contact has been updated on the CardDAV server
**/
typedef void (*LinphoneCardDavContactUpdatedCb)(LinphoneFriend *lf);
/**
* Callback used to notify a contact has been removed on the CardDAV server
**/
typedef void (*LinphoneCardDavContactRemovedCb)(LinphoneFriend *lf);
/**
* Callback used to notify a contact has been removed on the CardDAV server
**/
typedef void (*LinphoneCardDavSynchronizationDoneCb)(LinphoneCardDavContext *cdc, bool_t success, const char *message);
/**
* Creates a CardDAV context for all related operations
* @param lc LinphoneCore object
* @return LinphoneCardDavContext object if vCard support is enabled and server URL is available, NULL otherwise
*/
LINPHONE_PUBLIC LinphoneCardDavContext* linphone_core_create_carddav_context(LinphoneCore *lc);
/**
* Deletes a LinphoneCardDavContext object
* @param cdc LinphoneCardDavContext object
*/
LINPHONE_PUBLIC void linphone_carddav_destroy(LinphoneCardDavContext *cdc);
/**
* Sets a user pointer to the LinphoneCardDAVContext object
* @param cdc LinphoneCardDavContext object
* @param ud The user data pointer
*/
LINPHONE_PUBLIC void linphone_carddav_set_user_data(LinphoneCardDavContext *cdc, void *ud);
/**
* Gets the user pointer set in the LinphoneCardDAVContext object
* @param cdc LinphoneCardDavContext object
* @return The user data pointer if set, NULL otherwise
*/
LINPHONE_PUBLIC void* linphone_carddav_get_user_data(LinphoneCardDavContext *cdc);
/**
* Starts a synchronization with the remote server to update local friends with server changes
* @param cdc LinphoneCardDavContext object
*/
LINPHONE_PUBLIC void linphone_carddav_synchronize(LinphoneCardDavContext *cdc);
/**
* Sends a LinphoneFriend to the CardDAV server for update or creation
* @param cdc LinphoneCardDavContext object
* @param lf a LinphoneFriend object to update/create on the server
*/
LINPHONE_PUBLIC void linphone_carddav_put_vcard(LinphoneCardDavContext *cdc, LinphoneFriend *lf);
/**
* Deletes a LinphoneFriend on the CardDAV server
* @param cdc LinphoneCardDavContext object
* @param lf a LinphoneFriend object to delete on the server
*/
LINPHONE_PUBLIC void linphone_carddav_delete_vcard(LinphoneCardDavContext *cdc, LinphoneFriend *lf);
/**
* Set the synchronization done callback.
* @param cdc LinphoneCardDavContext object
* @param cb The synchronization done callback to be used.
*/
LINPHONE_PUBLIC void linphone_carddav_set_synchronization_done_callback(LinphoneCardDavContext *cdc, LinphoneCardDavSynchronizationDoneCb cb);
/**
* Retrieves the current cTag value for the remote server
* @param cdc LinphoneCardDavContext object
*/
void linphone_carddav_get_current_ctag(LinphoneCardDavContext *cdc);
/**
* Retrieves a list of all the vCards on server side to be able to detect changes
* @param cdc LinphoneCardDavContext object
*/
void linphone_carddav_fetch_vcards(LinphoneCardDavContext *cdc);
/**
* Download asked vCards from the server
* @param cdc LinphoneCardDavContext object
* @param vcards_to_pull a MSList of LinphoneCardDavResponse objects with at least the url field filled
*/
void linphone_carddav_pull_vcards(LinphoneCardDavContext *cdc, MSList *vcards_to_pull);
#ifdef __cplusplus
}
......
......@@ -7437,12 +7437,81 @@ const char *linphone_stream_type_to_string(const LinphoneStreamType type) {
return "INVALID";
}
/*****************************************************************************
* CardDAV interface *
****************************************************************************/
void linphone_core_set_carddav_server_url(LinphoneCore *lc, const char *carddav_server_url) {
if (lc->carddav_server_url) {
ms_free(lc->carddav_server_url);
lc->carddav_server_url = NULL;
if (lc && carddav_server_url) {
LpConfig *lpc = linphone_core_get_config(lc);
lp_config_set_string(lpc, "carddav", "server_url", carddav_server_url);
}
}
const char *linphone_core_get_carddav_server_url(LinphoneCore *lc) {
if (lc) {
LpConfig *lpc = linphone_core_get_config(lc);
return lp_config_get_string(lpc, "carddav", "server_url", NULL);
}
return NULL;
}
void linphone_core_set_carddav_username(LinphoneCore *lc, const char *username) {
if (lc && username) {
LpConfig *lpc = linphone_core_get_config(lc);
lp_config_set_string(lpc, "carddav", "username", username);
}
if (carddav_server_url) {
lc->carddav_server_url = ms_strdup(carddav_server_url);
}
const char *linphone_core_get_carddav_username(LinphoneCore *lc) {
if (lc) {
LpConfig *lpc = linphone_core_get_config(lc);
return lp_config_get_string(lpc, "carddav", "username", NULL);
}
return NULL;
}
void linphone_core_set_carddav_password(LinphoneCore *lc, const char *password) {
if (lc && password) {
LpConfig *lpc = linphone_core_get_config(lc);
lp_config_set_string(lpc, "carddav", "password", password);
}
}
const char *linphone_core_get_carddav_password(LinphoneCore *lc) {
if (lc) {
LpConfig *lpc = linphone_core_get_config(lc);
return lp_config_get_string(lpc, "carddav", "password", NULL);
}
return NULL;
}
void linphone_core_set_carddav_ha1(LinphoneCore *lc, const char *ha1) {
if (lc && ha1) {
LpConfig *lpc = linphone_core_get_config(lc);
lp_config_set_string(lpc, "carddav", "ha1", ha1);
}
}
const char *linphone_core_get_carddav_ha1(LinphoneCore *lc) {
if (lc) {
LpConfig *lpc = linphone_core_get_config(lc);
return lp_config_get_string(lpc, "carddav", "ha1", NULL);
}
return NULL;
}
void linphone_core_set_carddav_current_ctag(LinphoneCore *lc, int ctag) {
if (lc) {
LpConfig *lpc = linphone_core_get_config(lc);
lp_config_set_int(lpc, "carddav", "ctag", 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 -1;
}
\ No newline at end of file
......@@ -410,6 +410,7 @@ LINPHONE_PUBLIC const char* linphone_privacy_to_string(LinphonePrivacy privacy);
#include "event.h"
#include "linphonefriend.h"
#include "xmlrpc.h"
#include "carddav.h"
#else
#include "linphone/buffer.h"
#include "linphone/call_log.h"
......@@ -418,6 +419,7 @@ LINPHONE_PUBLIC const char* linphone_privacy_to_string(LinphonePrivacy privacy);
#include "linphone/event.h"
#include "linphone/linphonefriend.h"
#include "linphone/xmlrpc.h"
#include "linphone/carddav.h"
#endif
LINPHONE_PUBLIC LinphoneAddress * linphone_address_new(const char *addr);
......@@ -4252,6 +4254,10 @@ LINPHONE_PUBLIC LinphoneTransportType linphone_transport_parse(const char* trans
*/
LINPHONE_PUBLIC LINPHONE_DEPRECATED LinphoneCallParams *linphone_core_create_default_call_parameters(LinphoneCore *lc);
/*****************************************************************************
* CardDAV interface *
****************************************************************************/
/**
* Sets the CardDAV server URL
* @param lc LinphoneCore object
......@@ -4259,6 +4265,54 @@ LINPHONE_PUBLIC LINPHONE_DEPRECATED LinphoneCallParams *linphone_core_create_def
*/
LINPHONE_PUBLIC void linphone_core_set_carddav_server_url(LinphoneCore *lc, const char *carddav_server_url);
/**
* Gets the CardDAV server URL if set
* @param lc LinphoneCore object
* @return the URL to the CardDAV server if set, otherwise NULL
*/
LINPHONE_PUBLIC const char *linphone_core_get_carddav_server_url(LinphoneCore *lc);
/**
* Sets the CardDAV server username
* @param lc LinphoneCore object
* @param username the username for the CardDAV server
*/
LINPHONE_PUBLIC void linphone_core_set_carddav_username(LinphoneCore *lc, const char *username);
/**
* Gets the CardDAV server username
* @param lc LinphoneCore object
* @return the username for the CardDAV server if set, otherwise NULL
*/
LINPHONE_PUBLIC const char *linphone_core_get_carddav_username(LinphoneCore *lc);
/**
* Sets the CardDAV server password
* @param lc LinphoneCore object
* @param password the password for the CardDAV server
*/
LINPHONE_PUBLIC void linphone_core_set_carddav_password(LinphoneCore *lc, const char *password);
/**
* Gets the CardDAV server password
* @param lc LinphoneCore object
* @return the password for the CardDAV server if set, otherwise NULL
*/
LINPHONE_PUBLIC const char *linphone_core_get_carddav_password(LinphoneCore *lc);
/**
* Sets the CardDAV server hashed password
* @param lc LinphoneCore object
* @param ha1 the hashed password for the CardDAV server
*/
LINPHONE_PUBLIC void linphone_core_set_carddav_ha1(LinphoneCore *lc, const char *ha1);
/**
* Gets the CardDAV server hashed password
* @param lc LinphoneCore object
* @return the hashed password for the CardDAV server if set, otherwise NULL
*/
LINPHONE_PUBLIC const char *linphone_core_get_carddav_ha1(LinphoneCore *lc);
#ifdef __cplusplus
}
#endif
......
......@@ -972,7 +972,6 @@ struct _LinphoneCore
jmethodID multicast_lock_acquire_id;
jmethodID multicast_lock_release_id;
#endif
char *carddav_server_url;
};
......@@ -1223,9 +1222,57 @@ struct _LinphoneAccountCreator {
BELLE_SIP_DECLARE_VPTR(LinphoneAccountCreator);
/*****************************************************************************
* CardDAV interface *
****************************************************************************/
struct _LinphoneCardDavContext {
LinphoneCore *lc;
int ctag;
const char *server_url;
const char *username;
const char *password;
const char *ha1;
void *user_data;
LinphoneCardDavContactCreatedCb contact_created_cb;
LinphoneCardDavContactUpdatedCb contact_updated_cb;
LinphoneCardDavContactRemovedCb contact_removed_cb;
LinphoneCardDavSynchronizationDoneCb sync_done_cb;
};
struct _LinphoneCardDavQuery {
LinphoneCardDavContext *context;
const char *url;
const char *method;
const char *body;
const char *depth;
LinphoneCardDavQueryType type;
LinphoneCardDavQueryStatus status;
};
struct _LinphoneCardDavResponse {
LinphoneCardDavContext *context;
const char *etag;
const char *url;
const char *vcard;
};
/**
* Sets the CardDAV server current cTag