Support for the new ECalClient API in EDS 3.2

SyncEvolution EDS backend currently uses the ECal API which is
deprecated as of EDS v3.2 and replaced by the new ECalClient API.
This patch brings support for this new ECalClient API (when EDS
3.2 is detected at compile time).

The new code based on the ECalClient API will enable a few
optimizations, especially the partial fetching of components to
avoid useless DBus trafic. This results in better component change
tracking by fetching only the UID/RID/REV attributes for each
component.

Note: The new code uses the new GLibSupport header instead of the
deprecated SmartPointer (eptr).
This commit is contained in:
Christophe Dumez 2011-08-08 15:35:26 +03:00 committed by Patrick Ohly
parent a44e506717
commit e46a27b8c2
6 changed files with 440 additions and 88 deletions

View file

@ -46,16 +46,6 @@ static const string
EVOLUTION_CALENDAR_PRODID("PRODID:-//ACME//NONSGML SyncEvolution//EN"),
EVOLUTION_CALENDAR_VERSION("VERSION:2.0");
class unrefECalObjectList {
public:
/** free list of ECalChange instances */
static void unref(GList *pointer) {
if (pointer) {
e_cal_free_object_list(pointer);
}
}
};
static int granularity()
{
// This long delay is necessary in combination
@ -75,35 +65,41 @@ static int granularity()
return secs;
}
EvolutionCalendarSource::EvolutionCalendarSource(ECalSourceType type,
EvolutionCalendarSource::EvolutionCalendarSource(EvolutionCalendarSourceType type,
const SyncSourceParams &params) :
EvolutionSyncSource(params, granularity()),
m_type(type)
{
switch (m_type) {
case E_CAL_SOURCE_TYPE_EVENT:
case EVOLUTION_CAL_SOURCE_TYPE_EVENTS:
SyncSourceLogging::init(InitList<std::string>("SUMMARY") + "LOCATION",
", ",
m_operations);
m_typeName = "calendar";
#ifndef USE_ECAL_CLIENT
m_newSystem = e_cal_new_system_calendar;
#endif
break;
case E_CAL_SOURCE_TYPE_TODO:
case EVOLUTION_CAL_SOURCE_TYPE_TASKS:
SyncSourceLogging::init(InitList<std::string>("SUMMARY"),
", ",
m_operations);
m_typeName = "task list";
#ifndef USE_ECAL_CLIENT
m_newSystem = e_cal_new_system_tasks;
#endif
break;
case E_CAL_SOURCE_TYPE_JOURNAL:
case EVOLUTION_CAL_SOURCE_TYPE_MEMOS:
SyncSourceLogging::init(InitList<std::string>("SUBJECT"),
", ",
m_operations);
m_typeName = "memo list";
#ifndef USE_ECAL_CLIENT
// This is not available in older Evolution versions.
// A configure check could detect that, but as this isn't
// important the functionality is simply disabled.
m_newSystem = NULL /* e_cal_new_system_memos */;
#endif
break;
default:
SyncContext::throwError("internal error, invalid calendar type");
@ -117,7 +113,11 @@ SyncSource::Databases EvolutionCalendarSource::getDatabases()
GError *gerror = NULL;
Databases result;
if (!e_cal_get_sources(&sources, m_type, &gerror)) {
#ifdef USE_ECAL_CLIENT
if (!e_cal_client_get_sources(&sources, sourceType(), &gerror)) {
#else
if (!e_cal_get_sources(&sources, sourceType(), &gerror)) {
#endif
// ignore unspecific errors (like on Maemo with no support for memos)
// and continue with empty list (perhaps defaults work)
if (!gerror) {
@ -142,6 +142,15 @@ SyncSource::Databases EvolutionCalendarSource::getDatabases()
}
}
#ifdef USE_ECAL_CLIENT
if (result.empty()) {
ECalClientCXX calendar = ECalClientCXX::steal(e_cal_client_new_system(sourceType(), NULL));
if (calendar) {
const char *uri = e_client_get_uri (E_CLIENT ((ECalClient*)calendar));
result.push_back(Database("<<system>>", uri ? uri : "<<unknown uri>>"));
}
}
#else
if (result.empty() && m_newSystem) {
eptr<ECal, GObject> calendar(m_newSystem());
if (calendar.get()) {
@ -150,10 +159,41 @@ SyncSource::Databases EvolutionCalendarSource::getDatabases()
result.push_back(Database("<<system>>", uri ? uri : "<<unknown uri>>"));
}
}
#endif
return result;
}
#ifdef USE_ECAL_CLIENT
static void
handle_error_cb (EClient */*client*/, const gchar *error_msg, gpointer user_data)
{
EvolutionCalendarSource *that = static_cast<EvolutionCalendarSource *>(user_data);
SE_LOG_ERROR(that, NULL, error_msg);
}
static gboolean
handle_authentication_cb (EClient */*client*/, ECredentials *credentials, gpointer user_data)
{
EvolutionCalendarSource *that = static_cast<EvolutionCalendarSource *>(user_data);
std::string passwd = that->getPassword();
std::string prompt = e_credentials_peek(credentials, E_CREDENTIALS_KEY_PROMPT_TEXT);
std::string key = e_credentials_peek(credentials, E_CREDENTIALS_KEY_PROMPT_KEY);
SE_LOG_DEBUG(that, NULL, "authentication requested, prompt \"%s\", key \"%s\" => %s",
prompt.c_str(), key.c_str(),
!passwd.empty() ? "returning configured password" : "no password configured");
if (!passwd.empty()) {
e_credentials_set (credentials, E_CREDENTIALS_KEY_PASSWORD, passwd.c_str());
return true;
} else {
return false;
}
}
#else
char *EvolutionCalendarSource::authenticate(const char *prompt,
const char *key)
{
@ -165,12 +205,74 @@ char *EvolutionCalendarSource::authenticate(const char *prompt,
return !passwd.empty() ? strdup(passwd.c_str()) : NULL;
}
#endif
void EvolutionCalendarSource::open()
{
ESourceList *sources;
GError *gerror = NULL;
if (!e_cal_get_sources(&sources, m_type, &gerror)) {
#ifdef USE_ECAL_CLIENT
GErrorCXX gerror;
if (!e_cal_client_get_sources (&sources, sourceType(), gerror)) {
gerror.throwError("unable to access backend databases");
}
string id = getDatabaseID();
ESource *source = findSource(sources, id);
bool onlyIfExists = true;
bool created = false;
// Open twice. This solves an issue where Evolution's CalDAV
// backend only updates its local cache *after* a sync (= while
// closing the calendar?), instead of doing it *before* a sync (in
// e_cal_open()).
//
// This workaround is applied to *all* backends because there might
// be others with similar problems and for local storage it is
// a reasonably cheap operation (so no harm there).
for (int retries = 0; retries < 2; retries++) {
if (!source) {
// might have been special "<<system>>" or "<<default>>", try that and
// creating address book from file:// URI before giving up
if ((id.empty() || id == "<<system>>")) {
m_calendar = ECalClientCXX::steal(e_cal_client_new_system(sourceType(), gerror));
} else if (!id.compare(0, 7, "file://")) {
m_calendar = ECalClientCXX::steal(e_cal_client_new_from_uri(id.c_str(), sourceType(), gerror));
} else {
throwError(string("not found: '") + id + "'");
}
created = true;
onlyIfExists = false;
} else {
m_calendar = ECalClientCXX::steal(e_cal_client_new(source, sourceType(), gerror));
}
if (!gerror.isNull()) {
gerror.throwError("create calendar");
}
// Listen for errors
g_signal_connect (m_calendar, "backend-error", G_CALLBACK (handle_error_cb), this);
// Handle authentication requests from the backend
g_signal_connect (m_calendar, "authenticate", G_CALLBACK (handle_authentication_cb), this);
if (!e_client_open_sync(E_CLIENT ((ECalClient*)m_calendar), onlyIfExists, NULL, gerror)) {
if (created) {
// opening newly created address books often failed, perhaps that also applies to calendars - try again
gerror.clear();
sleep(5);
if (!e_client_open_sync(E_CLIENT ((ECalClient*)m_calendar), onlyIfExists, NULL, gerror)) {
gerror.throwError(string("opening ") + m_typeName );
}
} else {
gerror.throwError(string("opening ") + m_typeName );
}
}
}
#else
GError *gerror = NULL;
if (!e_cal_get_sources(&sources, sourceType(), &gerror)) {
throwError("unable to access backend databases", gerror);
}
@ -194,14 +296,14 @@ void EvolutionCalendarSource::open()
if ((id.empty() || id == "<<system>>") && m_newSystem) {
m_calendar.set(m_newSystem(), (string("system ") + m_typeName).c_str());
} else if (!id.compare(0, 7, "file://")) {
m_calendar.set(e_cal_new_from_uri(id.c_str(), m_type), (string("creating ") + m_typeName).c_str());
m_calendar.set(e_cal_new_from_uri(id.c_str(), sourceType()), (string("creating ") + m_typeName).c_str());
} else {
throwError(string("not found: '") + id + "'");
}
created = true;
onlyIfExists = false;
} else {
m_calendar.set(e_cal_new(source, m_type), m_typeName.c_str());
m_calendar.set(e_cal_new(source, sourceType()), m_typeName.c_str());
}
e_cal_set_auth_func(m_calendar, eCalAuthFunc, this);
@ -220,6 +322,8 @@ void EvolutionCalendarSource::open()
}
}
#endif
g_signal_connect_after(m_calendar,
"backend-died",
G_CALLBACK(SyncContext::fatalError),
@ -235,8 +339,110 @@ bool EvolutionCalendarSource::isEmpty()
return revisions.empty();
}
#ifdef USE_ECAL_CLIENT
class ECalClientViewSyncHandler {
public:
ECalClientViewSyncHandler(ECalClientView *view, void (*processList)(const GSList *list, void *user_data), void *user_data):
m_view(view), m_processList(processList), m_userData(user_data)
{}
bool processSync(GError **gerror)
{
// Listen for view signals
g_signal_connect(m_view, "objects-added", G_CALLBACK(objectsAdded), this);
g_signal_connect(m_view, "complete", G_CALLBACK(completed), this);
// Start the view
e_cal_client_view_start (m_view, m_error);
if (!m_error.isNull()) {
g_propagate_error (gerror, m_error);
return false;
}
// Async -> Sync
m_loop.run();
e_cal_client_view_stop (m_view, NULL);
if (!m_error.isNull()) {
g_propagate_error (gerror, m_error);
return false;
} else {
return true;
}
}
static void objectsAdded(ECalClientView *ebookview,
const GSList *objects,
gpointer user_data) {
ECalClientViewSyncHandler *that = (ECalClientViewSyncHandler *)user_data;
that->m_processList(objects, that->m_userData);
}
static void completed(ECalClientView *ebookview,
const GError *error,
gpointer user_data) {
ECalClientViewSyncHandler *that = (ECalClientViewSyncHandler *)user_data;
that->m_error = error;
that->m_loop.quit();
}
public:
// Process list callback
void (*m_processList)(const GSList *list, void *user_data);
void *m_userData;
// Event loop for Async -> Sync
EvolutionAsync m_loop;
private:
// View watched
ECalClientView *m_view;
// Possible error while watching the view
GErrorCXX m_error;
};
static void list_revisions(const GSList *objects, void *user_data)
{
EvolutionCalendarSource::RevisionMap_t *revisions =
static_cast<EvolutionCalendarSource::RevisionMap_t *>(user_data);
const GSList *l;
for (l = objects; l; l = l->next) {
icalcomponent *icomp = (icalcomponent*)l->data;
EvolutionCalendarSource::ItemID id = EvolutionCalendarSource::getItemID(icomp);
string luid = id.getLUID();
string modTime = EvolutionCalendarSource::getItemModTime(icomp);
(*revisions)[luid] = modTime;
}
}
#endif
void EvolutionCalendarSource::listAllItems(RevisionMap_t &revisions)
{
#ifdef USE_ECAL_CLIENT
GErrorCXX gerror;
ECalClientView *view;
if (!e_cal_client_get_view_sync (m_calendar, "#t", &view, NULL, gerror)) {
gerror.throwError( "getting the view" );
}
ECalClientViewCXX viewPtr = ECalClientViewCXX::steal(view);
// TODO: Optimization: use set fields_of_interest (UID / REV / LAST-MODIFIED)
ECalClientViewSyncHandler handler(viewPtr, list_revisions, &revisions);
if (!handler.processSync(gerror)) {
gerror.throwError("watching view");
}
// Update m_allLUIDs
m_allLUIDs.clear();
RevisionMap_t::iterator it;
for(it = revisions.begin(); it != revisions.end(); it++) {
m_allLUIDs.insert(it->first);
}
#else
GError *gerror = NULL;
GList *nextItem;
@ -258,6 +464,7 @@ void EvolutionCalendarSource::listAllItems(RevisionMap_t &revisions)
revisions[luid] = modTime;
nextItem = nextItem->next;
}
#endif
}
void EvolutionCalendarSource::close()
@ -319,6 +526,17 @@ EvolutionCalendarSource::InsertItemResult EvolutionCalendarSource::insertItem(co
GError *gerror = NULL;
// fix up TZIDs
#ifdef USE_ECAL_CLIENT
if (!e_cal_client_check_timezones(icomp,
NULL,
e_cal_client_tzlookup,
(const void *)m_calendar.get(),
NULL,
&gerror)) {
throwError(string("fixing timezones") + data,
gerror);
}
#else
if (!e_cal_check_timezones(icomp,
NULL,
e_cal_tzlookup_ecal,
@ -327,6 +545,7 @@ EvolutionCalendarSource::InsertItemResult EvolutionCalendarSource::insertItem(co
throwError(string("fixing timezones") + data,
gerror);
}
#endif
// insert before adding/updating the event so that the new VTIMEZONE is
// immediately available should anyone want it
@ -342,7 +561,11 @@ EvolutionCalendarSource::InsertItemResult EvolutionCalendarSource::insertItem(co
// cannot add a VTIMEZONE without TZID
SE_LOG_DEBUG(this, NULL, "skipping VTIMEZONE without TZID");
} else {
#ifdef USE_ECAL_CLIENT
gboolean success = e_cal_client_add_timezone_sync(m_calendar, zone, NULL, &gerror);
#else
gboolean success = e_cal_add_timezone(m_calendar, zone, &gerror);
#endif
if (!success) {
throwError(string("error adding VTIMEZONE ") + tzid,
gerror);
@ -413,7 +636,12 @@ EvolutionCalendarSource::InsertItemResult EvolutionCalendarSource::insertItem(co
}
// creating new objects works for normal events and detached occurrences alike
#ifdef USE_ECAL_CLIENT
if(e_cal_client_create_object_sync(m_calendar, subcomp, (char **)&uid,
NULL, &gerror)) {
#else
if(e_cal_create_object(m_calendar, subcomp, (char **)&uid, &gerror)) {
#endif
// Evolution workaround: don't rely on uid being set if we already had
// one. In Evolution 2.12.1 it was set to garbage. The recurrence ID
// shouldn't have changed either.
@ -428,9 +656,15 @@ EvolutionCalendarSource::InsertItemResult EvolutionCalendarSource::insertItem(co
// Recreate any children removed earlier: when we get here,
// the parent exists and we must update it.
BOOST_FOREACH(boost::shared_ptr< eptr<icalcomponent> > &icalcomp, children) {
#ifdef USE_ECAL_CLIENT
if (!e_cal_client_modify_object_sync(m_calendar, *icalcomp,
CALOBJ_MOD_THIS, NULL,
&gerror)) {
#else
if (!e_cal_modify_object(m_calendar, *icalcomp,
CALOBJ_MOD_THIS,
&gerror)) {
#endif
throwError(string("recreating item ") + newluid, gerror);
}
}
@ -491,32 +725,55 @@ EvolutionCalendarSource::InsertItemResult EvolutionCalendarSource::insertItem(co
// Parent is gone, too, and needs to be recreated.
const char *uid = NULL;
#ifdef USE_ECAL_CLIENT
if(!e_cal_client_create_object_sync(m_calendar, subcomp, (char **)&uid,
NULL, &gerror)) {
#else
if(!e_cal_create_object(m_calendar, subcomp, (char **)&uid, &gerror)) {
#endif
throwError(string("creating updated item ") + luid, gerror);
}
// Recreate any children removed earlier: when we get here,
// the parent exists and we must update it.
BOOST_FOREACH(boost::shared_ptr< eptr<icalcomponent> > &icalcomp, children) {
#ifdef USE_ECAL_CLIENT
if (!e_cal_client_modify_object_sync(m_calendar, *icalcomp,
CALOBJ_MOD_THIS, NULL,
&gerror)) {
#else
if (!e_cal_modify_object(m_calendar, *icalcomp,
CALOBJ_MOD_THIS,
&gerror)) {
#endif
throwError(string("recreating item ") + luid, gerror);
}
}
} else {
// no children, updating is simple
#ifdef USE_ECAL_CLIENT
if (!e_cal_client_modify_object_sync(m_calendar, subcomp,
CALOBJ_MOD_ALL, NULL,
&gerror)) {
#else
if (!e_cal_modify_object(m_calendar, subcomp,
CALOBJ_MOD_ALL,
&gerror)) {
#endif
throwError(string("updating item ") + luid, gerror);
}
}
} else {
// child event
#ifdef USE_ECAL_CLIENT
if (!e_cal_client_modify_object_sync(m_calendar, subcomp,
CALOBJ_MOD_THIS, NULL,
&gerror)) {
#else
if (!e_cal_modify_object(m_calendar, subcomp,
CALOBJ_MOD_THIS,
&gerror)) {
#endif
throwError(string("updating item ") + luid, gerror);
}
}
@ -549,6 +806,21 @@ EvolutionCalendarSource::ICalComps_t EvolutionCalendarSource::removeEvents(const
}
// removes all events with that UID, including children
#ifdef USE_ECAL_CLIENT
GErrorCXX gerror;
if(!e_cal_client_remove_object_sync(m_calendar,
uid.c_str(), NULL, CALOBJ_MOD_ALL,
NULL, gerror)) {
if (gerror->domain == E_CAL_CLIENT_ERROR &&
gerror->code == E_CAL_CLIENT_ERROR_OBJECT_NOT_FOUND) {
SE_LOG_DEBUG(this, NULL, "%s: request to delete non-existant item ignored",
uid.c_str());
} else {
gerror.throwError(string("deleting item " ) + uid);
}
}
#else
GError *gerror = NULL;
if(!e_cal_remove_object(m_calendar,
uid.c_str(),
@ -562,6 +834,7 @@ EvolutionCalendarSource::ICalComps_t EvolutionCalendarSource::removeEvents(const
throwError(string("deleting item " ) + uid, gerror);
}
}
#endif
return events;
}
@ -584,18 +857,34 @@ void EvolutionCalendarSource::removeItem(const string &luid)
// recreate children
BOOST_FOREACH(boost::shared_ptr< eptr<icalcomponent> > &icalcomp, children) {
char *uid;
#ifdef USE_ECAL_CLIENT
if (!e_cal_client_create_object_sync(m_calendar, *icalcomp, &uid,
NULL, &gerror)) {
#else
if (!e_cal_create_object(m_calendar, *icalcomp, &uid, &gerror)) {
#endif
throwError(string("recreating item ") + luid, gerror);
}
}
} else if(!e_cal_remove_object_with_mod(m_calendar,
id.m_uid.c_str(),
id.m_rid.c_str(),
CALOBJ_MOD_THIS,
&gerror)) {
}
#ifdef USE_ECAL_CLIENT
else if(!e_cal_client_remove_object_sync(m_calendar,
id.m_uid.c_str(),
id.m_rid.c_str(),
CALOBJ_MOD_THIS,
NULL,
&gerror)) {
if (gerror->domain == E_CAL_CLIENT_ERROR &&
gerror->code == E_CAL_CLIENT_ERROR_OBJECT_NOT_FOUND) {
#else
else if(!e_cal_remove_object_with_mod(m_calendar,
id.m_uid.c_str(),
id.m_rid.c_str(),
CALOBJ_MOD_THIS,
&gerror)) {
if (gerror->domain == E_CALENDAR_ERROR &&
gerror->code == E_CALENDAR_STATUS_OBJECT_NOT_FOUND) {
#endif
SE_LOG_DEBUG(this, NULL, "%s: request to delete non-existant item ignored",
luid.c_str());
g_clear_error(&gerror);
@ -632,11 +921,20 @@ icalcomponent *EvolutionCalendarSource::retrieveItem(const ItemID &id)
GError *gerror = NULL;
icalcomponent *comp = NULL;
#ifdef USE_ECAL_CLIENT
if (!e_cal_client_get_object_sync(m_calendar,
id.m_uid.c_str(),
!id.m_rid.empty() ? id.m_rid.c_str() : NULL,
&comp,
NULL,
&gerror)) {
#else
if (!e_cal_get_object(m_calendar,
id.m_uid.c_str(),
!id.m_rid.empty() ? id.m_rid.c_str() : NULL,
&comp,
&gerror)) {
#endif
throwError(string("retrieving item: ") + id.getLUID(), gerror);
}
if (!comp) {
@ -651,7 +949,11 @@ string EvolutionCalendarSource::retrieveItemAsString(const ItemID &id)
eptr<icalcomponent> comp(retrieveItem(id));
eptr<char> icalstr;
#ifdef USE_ECAL_CLIENT
icalstr = e_cal_client_get_component_as_string(m_calendar, comp);
#else
icalstr = e_cal_get_component_as_string(m_calendar, comp);
#endif
if (!icalstr) {
// One reason why e_cal_get_component_as_string() can fail is
@ -723,7 +1025,7 @@ std::string EvolutionCalendarSource::getDescription(const string &luid)
descr += summary;
}
if (m_type == E_CAL_SOURCE_TYPE_EVENT) {
if (m_type == EVOLUTION_CAL_SOURCE_TYPE_EVENTS) {
const char *location = icalcomponent_get_location(comp);
if (location && location[0]) {
if (!descr.empty()) {
@ -733,7 +1035,7 @@ std::string EvolutionCalendarSource::getDescription(const string &luid)
}
}
if (m_type == E_CAL_SOURCE_TYPE_JOURNAL &&
if (m_type == EVOLUTION_CAL_SOURCE_TYPE_MEMOS &&
descr.empty()) {
// fallback to first line of body text
icalproperty *desc = icalcomponent_get_first_property(comp, ICAL_DESCRIPTION_PROPERTY);
@ -786,7 +1088,7 @@ EvolutionCalendarSource::ItemID EvolutionCalendarSource::getItemID(ECalComponent
{
icalcomponent *icomp = e_cal_component_get_icalcomponent(ecomp);
if (!icomp) {
throwError("internal error in getItemID(): ECalComponent without icalcomp");
SE_THROW("internal error in getItemID(): ECalComponent without icalcomp");
}
return getItemID(icomp);
}
@ -814,16 +1116,21 @@ string EvolutionCalendarSource::getItemModTime(ECalComponent *ecomp)
}
}
string EvolutionCalendarSource::getItemModTime(icalcomponent *icomp)
{
icalproperty *modprop = icalcomponent_get_first_property(icomp, ICAL_LASTMODIFIED_PROPERTY);
if (!modprop) {
return "";
}
struct icaltimetype modTime = icalproperty_get_lastmodified(modprop);
return icalTime2Str(modTime);
}
string EvolutionCalendarSource::getItemModTime(const ItemID &id)
{
eptr<icalcomponent> icomp(retrieveItem(id));
icalproperty *lastModified = icalcomponent_get_first_property(icomp, ICAL_LASTMODIFIED_PROPERTY);
if (!lastModified) {
return "";
} else {
struct icaltimetype modTime = icalproperty_get_lastmodified(lastModified);
return icalTime2Str(modTime);
}
return getItemModTime(icomp);
}
string EvolutionCalendarSource::icalTime2Str(const icaltimetype &tt)
@ -834,7 +1141,7 @@ string EvolutionCalendarSource::icalTime2Str(const icaltimetype &tt)
} else {
eptr<char> timestr(ical_strdup(icaltime_as_ical_string(tt)));
if (!timestr) {
throwError("cannot convert to time string");
SE_THROW("cannot convert to time string");
}
return timestr.get();
}

View file

@ -27,10 +27,26 @@
#include <boost/noncopyable.hpp>
#ifdef ENABLE_ECAL
#include <syncevo/declarations.h>
#ifdef USE_ECAL_CLIENT
SE_GOBJECT_TYPE(ECalClient)
SE_GOBJECT_TYPE(ECalClientView)
#endif
SE_BEGIN_CXX
#ifdef ENABLE_ECAL
/**
* Source type independent from ECal / ECalClient to abstract
* the two different enums in the APIs.
*/
typedef enum {
EVOLUTION_CAL_SOURCE_TYPE_EVENTS,
EVOLUTION_CAL_SOURCE_TYPE_TASKS,
EVOLUTION_CAL_SOURCE_TYPE_MEMOS
} EvolutionCalendarSourceType;
/**
* Implements access to Evolution calendars, either
@ -47,11 +63,11 @@ class EvolutionCalendarSource : public EvolutionSyncSource,
public:
/**
* @param type chooses which kind of calendar data to use:
* E_CAL_SOURCE_TYPE_TODO,
* E_CAL_SOURCE_TYPE_JOURNAL,
* E_CAL_SOURCE_TYPE_EVENT
* EVOLUTION_CAL_SOURCE_TYPE_EVENTS,
* EVOLUTION_CAL_SOURCE_TYPE_TASKS,
* EVOLUTION_CAL_SOURCE_TYPE_MEMOS
*/
EvolutionCalendarSource(ECalSourceType type,
EvolutionCalendarSource(EvolutionCalendarSourceType type,
const SyncSourceParams &params);
virtual ~EvolutionCalendarSource() { close(); }
@ -65,27 +81,6 @@ class EvolutionCalendarSource : public EvolutionSyncSource,
virtual std::string getMimeType() const { return "text/calendar"; }
virtual std::string getMimeVersion() const { return "2.0"; }
protected:
//
// implementation of TrackingSyncSource callbacks
//
virtual void listAllItems(RevisionMap_t &revisions);
virtual InsertItemResult insertItem(const string &uid, const std::string &item, bool raw);
void readItem(const std::string &luid, std::string &item, bool raw);
virtual void removeItem(const string &uid);
// implementation of SyncSourceLogging callback
virtual std::string getDescription(const string &luid);
protected:
/** valid after open(): the calendar that this source references */
eptr<ECal, GObject> m_calendar;
ECalSourceType m_type; /**< use events or todos? */
string m_typeName; /**< "calendar", "task list", "memo list" */
ECal *(*m_newSystem)(void); /**< e_cal_new_system_calendar, etc. */
/**
* An item is identified in the calendar by
* its UID (unique ID) and RID (recurrence ID).
@ -112,6 +107,54 @@ class EvolutionCalendarSource : public EvolutionSyncSource,
static string getLUID(const string &uid, const string &rid);
};
/**
* Extract item ID from calendar item. An icalcomponent must
* refer to the VEVENT/VTODO/VJOURNAL component.
*/
static ItemID getItemID(ECalComponent *ecomp);
static ItemID getItemID(icalcomponent *icomp);
/**
* Extract modification string from calendar item.
* @return empty string if no time was available
*/
static string getItemModTime(ECalComponent *ecomp);
static string getItemModTime(icalcomponent *icomp);
protected:
//
// implementation of TrackingSyncSource callbacks
//
virtual void listAllItems(RevisionMap_t &revisions);
virtual InsertItemResult insertItem(const string &uid, const std::string &item, bool raw);
void readItem(const std::string &luid, std::string &item, bool raw);
virtual void removeItem(const string &uid);
// implementation of SyncSourceLogging callback
virtual std::string getDescription(const string &luid);
protected:
/** valid after open(): the calendar that this source references */
#ifdef USE_ECAL_CLIENT
ECalClientCXX m_calendar;
#else
eptr<ECal, GObject> m_calendar;
ECal *(*m_newSystem)(void); /**< e_cal_new_system_calendar, etc. */
#endif
string m_typeName; /**< "calendar", "task list", "memo list" */
EvolutionCalendarSourceType m_type; /**< use events, tasks or memos? */
// Convenience function for source type casting
#ifdef USE_ECAL_CLIENT
ECalClientSourceType sourceType() const {
return (ECalClientSourceType)m_type;
}
#else
ECalSourceType sourceType() const {
return (ECalSourceType)m_type;
}
#endif
/**
* retrieve the item with the given id - may throw exception
*
@ -125,11 +168,12 @@ class EvolutionCalendarSource : public EvolutionSyncSource,
/** returns the type which the ical library uses for our components */
icalcomponent_kind getCompType() {
return m_type == E_CAL_SOURCE_TYPE_EVENT ? ICAL_VEVENT_COMPONENT :
m_type == E_CAL_SOURCE_TYPE_JOURNAL ? ICAL_VJOURNAL_COMPONENT :
return m_type == EVOLUTION_CAL_SOURCE_TYPE_EVENTS ? ICAL_VEVENT_COMPONENT :
m_type == EVOLUTION_CAL_SOURCE_TYPE_MEMOS ? ICAL_VJOURNAL_COMPONENT :
ICAL_VTODO_COMPONENT;
}
#ifndef USE_ECAL_CLIENT
/** ECalAuthFunc which calls the authenticate() methods */
static char *eCalAuthFunc(ECal *ecal,
const char *prompt,
@ -141,25 +185,13 @@ class EvolutionCalendarSource : public EvolutionSyncSource,
/** actual implementation of ECalAuthFunc */
char *authenticate(const char *prompt,
const char *key);
#endif
/**
* Returns the LUID of a calendar item.
*/
string getLUID(ECalComponent *ecomp);
/**
* Extract item ID from calendar item. An icalcomponent must
* refer to the VEVENT/VTODO/VJOURNAL component.
*/
ItemID getItemID(ECalComponent *ecomp);
ItemID getItemID(icalcomponent *icomp);
/**
* Extract modification string from calendar item.
* @return empty string if no time was available
*/
string getItemModTime(ECalComponent *ecomp);
/**
* Extract modification string of an item stored in
* the calendar.
@ -170,7 +202,7 @@ class EvolutionCalendarSource : public EvolutionSyncSource,
/**
* Convert to string in canonical representation.
*/
string icalTime2Str(const struct icaltimetype &tt);
static string icalTime2Str(const struct icaltimetype &tt);
/**
* A set of all existing objects. Initialized in the last call to
@ -204,12 +236,7 @@ class EvolutionCalendarSource : public EvolutionSyncSource,
ICalComps_t removeEvents(const string &uid, bool returnOnlyChildren);
};
#else
typedef int ECalSourceType;
SE_END_CXX
#endif // ENABLE_ECAL
SE_END_CXX
#endif // INCL_EVOLUTIONSYNCSOURCE

View file

@ -44,7 +44,7 @@ static SyncSource *createSource(const SyncSourceParams &params)
sourceType.m_format == "text/x-vcalendar") {
return
#ifdef ENABLE_ECAL
enabled ? new EvolutionCalendarSource(E_CAL_SOURCE_TYPE_TODO, params) :
enabled ? new EvolutionCalendarSource(EVOLUTION_CAL_SOURCE_TYPE_TASKS, params) :
#endif
isMe ? RegisterSyncSource::InactiveSource : NULL;
}
@ -61,7 +61,7 @@ static SyncSource *createSource(const SyncSourceParams &params)
} else if (sourceType.m_format == "text/calendar") {
return
#ifdef ENABLE_ECAL
enabled ? new EvolutionCalendarSource(E_CAL_SOURCE_TYPE_JOURNAL, params) :
enabled ? new EvolutionCalendarSource(EVOLUTION_CAL_SOURCE_TYPE_MEMOS, params) :
#endif
isMe ? RegisterSyncSource::InactiveSource : NULL;
} else {
@ -77,7 +77,7 @@ static SyncSource *createSource(const SyncSourceParams &params)
sourceType.m_format == "text/x-vcalendar") {
return
#ifdef ENABLE_ECAL
enabled ? new EvolutionCalendarSource(E_CAL_SOURCE_TYPE_EVENT, params) :
enabled ? new EvolutionCalendarSource(EVOLUTION_CAL_SOURCE_TYPE_EVENTS, params) :
#endif
isMe ? RegisterSyncSource::InactiveSource : NULL;
} else {

View file

@ -173,9 +173,15 @@ EvolutionCalendarSource::InsertItemResult EvolutionMemoSource::insertItem(const
char *uid = NULL;
if (!update) {
#ifdef USE_ECAL_CLIENT
if(!e_cal_client_create_object_sync(m_calendar, subcomp, &uid, NULL, &gerror)) {
if (gerror->domain == E_CAL_CLIENT_ERROR &&
gerror->code == E_CAL_CLIENT_ERROR_OBJECT_ID_ALREADY_EXISTS) {
#else
if(!e_cal_create_object(m_calendar, subcomp, &uid, &gerror)) {
if (gerror->domain == E_CALENDAR_ERROR &&
gerror->code == E_CALENDAR_STATUS_OBJECT_ID_ALREADY_EXISTS) {
#endif
// Deal with error due to adding already existing item.
// Should never happen for plain text journal entries because
// they have no embedded ID, but who knows...
@ -199,7 +205,12 @@ EvolutionCalendarSource::InsertItemResult EvolutionMemoSource::insertItem(const
icalcomponent_set_uid(subcomp, id.m_uid.c_str());
}
#ifdef USE_ECAL_CLIENT
if (!e_cal_client_modify_object_sync(m_calendar, subcomp, CALOBJ_MOD_ALL,
NULL, &gerror)) {
#else
if (!e_cal_modify_object(m_calendar, subcomp, CALOBJ_MOD_ALL, &gerror)) {
#endif
throwError(string("updating memo item ") + luid, gerror);
}
ItemID newid = getItemID(subcomp);

View file

@ -37,7 +37,8 @@ class EvolutionMemoSource : public EvolutionCalendarSource
{
public:
EvolutionMemoSource(const SyncSourceParams &params) :
EvolutionCalendarSource(E_CAL_SOURCE_TYPE_JOURNAL, params) {}
EvolutionCalendarSource(EVOLUTION_CAL_SOURCE_TYPE_MEMOS,
params) {}
//
// implementation of SyncSource

View file

@ -57,6 +57,7 @@
#include <libedataserver/e-source-list.h>
#if EDS_CHECK_VERSION(3,1,0)
#define USE_EBOOK_CLIENT 1
#define USE_ECAL_CLIENT 1
#endif
#ifdef ENABLE_EBOOK
#ifdef USE_EBOOK_CLIENT
@ -69,9 +70,14 @@
#endif
#ifdef ENABLE_ECAL
# define HANDLE_LIBICAL_MEMORY 1
#ifdef USE_ECAL_CLIENT
#include <libecal/e-cal-client.h>
#include <libecal/e-cal-check-timezones.h>
#else
#include <libecal/e-cal.h>
#endif
#endif
#endif
#ifdef ENABLE_BLUETOOTH
#include <bluetooth/sdp.h>
#include <bluetooth/sdp_lib.h>