Merge branch 'HARMATTAN-1-3-1'
Fetched the code and its history from the 1.3.1 archives at: http://people.debian.org/~ovek/maemo/ http://people.debian.org/~ovek/harmattan/ Merged almost everything, except for Maemo/Harmattan specific build files: autogen-maemo.sh builddeb buildsrc debian The following changes were also removed, because they are either local workarounds or merge artifacts which probably also don't belong into the Maemo/Harmattan branch: diff --git a/configure.ac b/configure.ac index cb66617..2c4403c 100644 --- a/configure.ac +++ b/configure.ac @@ -44,7 +44,7 @@ if test "$enable_release_mode" = "yes"; then AC_DEFINE(SYNCEVOLUTION_STABLE_RELEASE, 1, [binary is meant for end-users]) fi -AM_INIT_AUTOMAKE([1.11.1 tar-ustar silent-rules subdir-objects -Wno-portability]) +AM_INIT_AUTOMAKE([subdir-objects -Wno-portability]) AM_PROG_CC_C_O diff --git a/src/backends/webdav/CalDAVSource.cpp b/src/backends/webdav/CalDAVSource.cpp index decd170..7d338ac 100644 --- a/src/backends/webdav/CalDAVSource.cpp +++ b/src/backends/webdav/CalDAVSource.cpp @@ -1282,6 +1282,7 @@ void CalDAVSource::Event::fixIncomingCalendar(icalcomponent *calendar) // time. bool ridInUTC = false; const icaltimezone *zone = NULL; + icalcomponent *parent = NULL; for (icalcomponent *comp = icalcomponent_get_first_component(calendar, ICAL_VEVENT_COMPONENT); comp; @@ -1295,6 +1296,7 @@ void CalDAVSource::Event::fixIncomingCalendar(icalcomponent *calendar) // is parent event? -> remember time zone unless it is UTC static const struct icaltimetype null = { 0 }; if (!memcmp(&rid, &null, sizeof(null))) { + parent = comp; struct icaltimetype dtstart = icalcomponent_get_dtstart(comp); if (!icaltime_is_utc(dtstart)) { zone = icaltime_get_timezone(dtstart); diff --git a/src/backends/webdav/CalDAVSource.h b/src/backends/webdav/CalDAVSource.h index 517ac2f..fa7c2ca 100644 --- a/src/backends/webdav/CalDAVSource.h +++ b/src/backends/webdav/CalDAVSource.h @@ -45,6 +45,10 @@ class CalDAVSource : public WebDAVSource, virtual void removeMergedItem(const std::string &luid); virtual void flushItem(const string &uid); virtual std::string getSubDescription(const string &uid, const string &subid); + virtual void updateSynthesisInfo(SynthesisInfo &info, + XMLConfigFragments &fragments) { + info.m_backendRule = "HAVE-SYNCEVOLUTION-EXDATE-DETACHED"; + } // implementation of SyncSourceLogging callback virtual std::string getDescription(const string &luid); Making SySync_ConsolePrintf a real instance inside SyncEvolution leads to link errors in other configurations. It really has to be extern. Added a comment to the master branch to make that more obvious: -extern "C" { // without curly braces, g++ 4.2 thinks the variable is extern - int (*SySync_ConsolePrintf)(FILE *stream, const char *format, ...); -} +// This is just the declaration. The actual function pointer instance +// is inside libsynthesis, which, for historic purposes, doesn't define +// it in its header files (yet). +extern "C" int (*SySync_ConsolePrintf)(FILE *stream, const char *format, ...);
This commit is contained in:
commit
340579cbdb
|
@ -23,6 +23,7 @@ Makefile.in
|
|||
/config.sub
|
||||
/configure
|
||||
/depcomp
|
||||
/INSTALL
|
||||
/install-sh
|
||||
/libtool
|
||||
/ltmain.sh
|
||||
|
@ -35,6 +36,9 @@ Makefile.in
|
|||
/syncevolution.1
|
||||
/syncevolution-*.tar.gz
|
||||
|
||||
# for Maemo build
|
||||
/libsynthesis
|
||||
|
||||
# po
|
||||
/po/*.gmo
|
||||
/po/.intltool-merge-cache
|
||||
|
|
|
@ -55,7 +55,8 @@ dnl Specify git revisions/branches without prefix, i.e., without 'origin'.
|
|||
dnl We'll sort that out below.
|
||||
define([SYNTHESISSRC_REVISION], [syncevolution-0.9])
|
||||
AC_CONFIG_HEADERS(config.h)
|
||||
LT_INIT([dlopen])
|
||||
AC_LIBTOOL_DLOPEN
|
||||
AC_PROG_LIBTOOL
|
||||
|
||||
dnl check for programs.
|
||||
AC_PROG_CXX
|
||||
|
@ -677,7 +678,11 @@ AC_SUBST(GUI_DESKTOP_FILES)
|
|||
|
||||
# C++ regular expression support is required often enough to make it
|
||||
# mandatory.
|
||||
PKG_CHECK_MODULES(PCRECPP, libpcrecpp)
|
||||
PKG_CHECK_MODULES(PCRECPP, libpcrecpp,,
|
||||
AC_CHECK_LIB(pcrecpp,main,
|
||||
AC_SUBST(PCRECPP_LIBS,-lpcrecpp),
|
||||
AC_MSG_ERROR([pcrecpp not found])
|
||||
))
|
||||
|
||||
# need rst2man for man pages
|
||||
AC_ARG_WITH(rst2man,
|
||||
|
|
|
@ -68,7 +68,10 @@ if test "$enable_evo" = "yes"; then
|
|||
# Only the EClient code supports the API in EDS 3.5.x.
|
||||
PKG_CHECK_MODULES(EDS_VERSION, [libedataserver-1.2 >= 3.5],
|
||||
[AC_DEFINE(USE_EDS_CLIENT, 1, [use e_book/cal_client_* calls])],
|
||||
[true])
|
||||
[CFLAGS_old="$CFLAGS"
|
||||
CFLAGS="$CFLAGS $EPACKAGE_CFLAGS"
|
||||
AC_CHECK_HEADERS(libedataserver/eds-version.h)
|
||||
CFLAGS="$CFLAGS_old"])
|
||||
else
|
||||
EPACKAGE_CFLAGS=
|
||||
EPACKAGE_LIBS=
|
||||
|
|
|
@ -65,12 +65,26 @@ class KCalExtendedData
|
|||
public:
|
||||
KCalExtendedData(KCalExtendedSource *parent,
|
||||
const QString ¬ebook,
|
||||
const KCalCore::IncidenceBase::IncidenceType &type) :
|
||||
const KCalExtendedSource::Type &type) :
|
||||
m_parent(parent),
|
||||
m_modified(false),
|
||||
m_notebook(notebook),
|
||||
m_type(type)
|
||||
m_notebook(notebook)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case KCalExtendedSource::Event:
|
||||
m_type = KCalCore::IncidenceBase::TypeEvent;
|
||||
break;
|
||||
case KCalExtendedSource::Todo:
|
||||
m_type = KCalCore::IncidenceBase::TypeTodo;
|
||||
break;
|
||||
case KCalExtendedSource::Journal:
|
||||
m_type = KCalCore::IncidenceBase::TypeJournal;
|
||||
break;
|
||||
default:
|
||||
m_type = KCalCore::IncidenceBase::TypeUnknown;
|
||||
break;
|
||||
}
|
||||
if (!qApp) {
|
||||
static const char *argv[] = { "SyncEvolution" };
|
||||
static int argc = 1;
|
||||
|
@ -176,25 +190,36 @@ KCalExtendedData::ItemID KCalExtendedData::getItemID(const KCalCore::Incidence::
|
|||
return ItemID(qstring2std(uid), ridStr);
|
||||
}
|
||||
|
||||
KCalExtendedSource::KCalExtendedSource(const SyncSourceParams ¶ms) :
|
||||
KCalExtendedSource::KCalExtendedSource(const SyncSourceParams ¶ms, Type type) :
|
||||
TestingSyncSource(params)
|
||||
{
|
||||
SyncSourceRevisions::init(this, this, 0, m_operations);
|
||||
SyncSourceLogging::init(InitList<std::string>("SUMMARY") + "LOCATION",
|
||||
", ",
|
||||
m_operations);
|
||||
#if 0
|
||||
// VTODO
|
||||
SyncSourceLogging::init(InitList<std::string>("SUMMARY"),
|
||||
", ",
|
||||
m_operations);
|
||||
// VJOURNAL
|
||||
SyncSourceLogging::init(InitList<std::string>("SUBJECT"),
|
||||
", ",
|
||||
m_operations);
|
||||
#endif
|
||||
switch (type)
|
||||
{
|
||||
case Event:
|
||||
SyncSourceLogging::init(InitList<std::string>("SUMMARY") + "LOCATION",
|
||||
", ",
|
||||
m_operations);
|
||||
break;
|
||||
case Todo:
|
||||
SyncSourceLogging::init(InitList<std::string>("SUMMARY"),
|
||||
", ",
|
||||
m_operations);
|
||||
break;
|
||||
case Journal:
|
||||
SyncSourceLogging::init(InitList<std::string>("SUBJECT"),
|
||||
", ",
|
||||
m_operations);
|
||||
break;
|
||||
default:
|
||||
throwError("invalid calendar type");
|
||||
break;
|
||||
}
|
||||
|
||||
m_data = NULL;
|
||||
m_type = type;
|
||||
m_delete_run = 0;
|
||||
m_insert_run = 0;
|
||||
}
|
||||
|
||||
KCalExtendedSource::~KCalExtendedSource()
|
||||
|
@ -202,14 +227,25 @@ KCalExtendedSource::~KCalExtendedSource()
|
|||
delete m_data;
|
||||
}
|
||||
|
||||
std::string KCalExtendedSource::getMimeType() const
|
||||
{
|
||||
return m_type == Journal ?
|
||||
"text/calendar+plain" :
|
||||
"text/calendar";
|
||||
}
|
||||
|
||||
std::string KCalExtendedSource::getMimeVersion() const
|
||||
{
|
||||
return "2.0";
|
||||
}
|
||||
|
||||
void KCalExtendedSource::open()
|
||||
{
|
||||
// read specified database name from "database" property
|
||||
std::string databaseID = getDatabaseID();
|
||||
|
||||
// TODO: also support todoType
|
||||
m_data = new KCalExtendedData(this, databaseID.c_str(),
|
||||
KCalCore::IncidenceBase::TypeEvent);
|
||||
m_data = new KCalExtendedData(this, databaseID.c_str(), m_type);
|
||||
m_data->m_calendar = mKCal::ExtendedCalendar::Ptr(new mKCal::ExtendedCalendar(KDateTime::Spec::LocalZone()));
|
||||
|
||||
if (databaseID.empty() || boost::starts_with(databaseID, "file://") ) {
|
||||
|
@ -227,11 +263,40 @@ void KCalExtendedSource::open()
|
|||
if (!m_data->m_storage->open()) {
|
||||
throwError("failed to open storage");
|
||||
}
|
||||
#ifdef ENABLE_MAEMO
|
||||
mKCal::Notebook::Ptr defaultNotebook;
|
||||
// For notes, we need a different default database:
|
||||
// Notes (uid:66666666-7777-8888-9999-000000000000)
|
||||
if (databaseID.empty() && m_type == Journal)
|
||||
{
|
||||
defaultNotebook = m_data->m_storage->notebook("66666666-7777-8888-9999-000000000000");
|
||||
}
|
||||
else
|
||||
{
|
||||
defaultNotebook = m_data->m_storage->defaultNotebook();
|
||||
}
|
||||
#else
|
||||
mKCal::Notebook::Ptr defaultNotebook = m_data->m_storage->defaultNotebook();
|
||||
#endif
|
||||
if (!defaultNotebook) {
|
||||
throwError("no default Notebook");
|
||||
}
|
||||
m_data->m_notebookUID = defaultNotebook->uid();
|
||||
#ifdef ENABLE_MAEMO
|
||||
} else if (boost::starts_with(databaseID, "uid:")) {
|
||||
// if databaseID has a "uid:" prefix, open existing notebook with given ID in default storage
|
||||
m_data->m_storage = mKCal::ExtendedCalendar::defaultStorage(m_data->m_calendar);
|
||||
if (!m_data->m_storage->open()) {
|
||||
throwError("failed to open storage");
|
||||
}
|
||||
QString uid = databaseID.c_str() + strlen("uid:");
|
||||
mKCal::Notebook::Ptr notebook = m_data->m_storage->notebook(uid);
|
||||
|
||||
if ( !notebook ) {
|
||||
throwError(string("no such notebook with UID \"") + uid.toStdString() + string("\" in default storage"));
|
||||
}
|
||||
m_data->m_notebookUID = notebook->uid();
|
||||
#endif
|
||||
} else {
|
||||
// use databaseID as notebook name to search for an existing notebook
|
||||
// if found use it, otherwise:
|
||||
|
@ -270,14 +335,24 @@ void KCalExtendedSource::open()
|
|||
// we are not currently using partial loading because there were
|
||||
// issues with it (BMC #6061); the load() calls elsewhere in this
|
||||
// file are commented out
|
||||
if (!m_data->m_storage->load()) {
|
||||
if (!m_data->m_storage->loadNotebookIncidences(m_data->m_notebookUID)) {
|
||||
throwError("failed to load calendar");
|
||||
}
|
||||
}
|
||||
|
||||
bool KCalExtendedSource::isEmpty()
|
||||
{
|
||||
return false;
|
||||
switch (m_data->m_type)
|
||||
{
|
||||
case KCalCore::IncidenceBase::TypeEvent:
|
||||
return !m_data->m_calendar->eventCount();
|
||||
case KCalCore::IncidenceBase::TypeTodo:
|
||||
return !m_data->m_calendar->todoCount();
|
||||
case KCalCore::IncidenceBase::TypeJournal:
|
||||
return !m_data->m_calendar->journalCount();
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
void KCalExtendedSource::close()
|
||||
|
@ -305,8 +380,7 @@ KCalExtendedSource::Databases KCalExtendedSource::getDatabases()
|
|||
{
|
||||
Databases result;
|
||||
|
||||
m_data = new KCalExtendedData(this, getDatabaseID().c_str(),
|
||||
KCalCore::IncidenceBase::TypeEvent);
|
||||
m_data = new KCalExtendedData(this, getDatabaseID().c_str(), m_type);
|
||||
m_data->m_calendar = mKCal::ExtendedCalendar::Ptr(new mKCal::ExtendedCalendar(KDateTime::Spec::LocalZone()));
|
||||
m_data->m_storage = mKCal::ExtendedCalendar::defaultStorage(m_data->m_calendar);
|
||||
if (!m_data->m_storage->open()) {
|
||||
|
@ -315,10 +389,21 @@ KCalExtendedSource::Databases KCalExtendedSource::getDatabases()
|
|||
mKCal::Notebook::List notebookList = m_data->m_storage->notebooks();
|
||||
mKCal::Notebook::List::Iterator it;
|
||||
for ( it = notebookList.begin(); it != notebookList.end(); ++it ) {
|
||||
#ifdef ENABLE_MAEMO
|
||||
string name = (*it)->name().toStdString();
|
||||
string uid = (*it)->uid().toStdString();
|
||||
// For notes, we need a different default database:
|
||||
// Notes (uid:66666666-7777-8888-9999-000000000000)
|
||||
bool isDefault = (m_type != Journal) ?
|
||||
(*it)->isDefault() :
|
||||
(uid == "66666666-7777-8888-9999-000000000000");
|
||||
result.push_back(Database( name, "uid:" + uid, isDefault ));
|
||||
#else
|
||||
bool isDefault = (*it)->isDefault();
|
||||
result.push_back(Database( (*it)->name().toStdString(),
|
||||
(m_data->m_storage).staticCast<mKCal::SqliteStorage>()->databaseName().toStdString(),
|
||||
isDefault));
|
||||
#endif
|
||||
}
|
||||
m_data->m_storage->close();
|
||||
m_data->m_calendar->close();
|
||||
|
@ -330,9 +415,10 @@ void KCalExtendedSource::beginSync(const std::string &lastToken, const std::stri
|
|||
const char *anchor = resumeToken.empty() ? lastToken.c_str() : resumeToken.c_str();
|
||||
KCalCore::Incidence::List incidences;
|
||||
// return all items
|
||||
if (!m_data->m_storage->allIncidences(&incidences, m_data->m_notebookUID)) {
|
||||
throwError("allIncidences() failed");
|
||||
}
|
||||
incidences = m_data->m_calendar->incidences();
|
||||
// if (!m_data->m_storage->allIncidences(&incidences, m_data->m_notebookUID)) {
|
||||
// throwError("allIncidences() failed");
|
||||
// }
|
||||
m_data->extractIncidences(incidences, SyncSourceChanges::ANY, *this);
|
||||
if (*anchor) {
|
||||
SE_LOG_DEBUG(NULL, NULL, "checking for changes since %s UTC", anchor);
|
||||
|
@ -372,6 +458,8 @@ std::string KCalExtendedSource::endSync(bool success)
|
|||
sleep(1 - (current - modtime));
|
||||
current = time(NULL);
|
||||
} while (current - modtime < 1);
|
||||
m_delete_run = 0;
|
||||
m_insert_run = 0;
|
||||
}
|
||||
|
||||
QDateTime now = QDateTime::currentDateTime().toUTC();
|
||||
|
@ -393,6 +481,21 @@ void KCalExtendedSource::readItem(const string &uid, std::string &item)
|
|||
|
||||
TestingSyncSource::InsertItemResult KCalExtendedSource::insertItem(const string &uid, const std::string &item)
|
||||
{
|
||||
if (m_delete_run > 0)
|
||||
{
|
||||
// Since the storage's save() might do deletes *after* inserts,
|
||||
// the final save() could fail if we're doing a refresh-from-peer
|
||||
// (where everything is first deleted and then reinserted), as
|
||||
// the inserts will fail due to the existing entries not being
|
||||
// deleted yet. To avoid the problem, make sure we save between
|
||||
// the deletes and the inserts.
|
||||
if (!m_data->m_storage->save()) {
|
||||
throwError("could not save calendar");
|
||||
}
|
||||
m_delete_run = 0;
|
||||
m_insert_run = 0;
|
||||
}
|
||||
|
||||
KCalCore::Calendar::Ptr calendar(new KCalCore::MemoryCalendar(KDateTime::Spec::LocalZone()));
|
||||
KCalCore::ICalFormat parser;
|
||||
if (!parser.fromString(calendar, std2qstring(item))) {
|
||||
|
@ -402,7 +505,7 @@ TestingSyncSource::InsertItemResult KCalExtendedSource::insertItem(const string
|
|||
if (incidences.empty()) {
|
||||
throwError("iCalendar 2.0 item empty?!");
|
||||
}
|
||||
bool updated;
|
||||
InsertItemResultState updated;
|
||||
string newUID;
|
||||
string oldUID = uid;
|
||||
|
||||
|
@ -437,7 +540,7 @@ TestingSyncSource::InsertItemResult KCalExtendedSource::insertItem(const string
|
|||
if (oldUID.empty()) {
|
||||
KCalCore::Incidence::Ptr incidence = incidences[0];
|
||||
|
||||
updated = false;
|
||||
updated = ITEM_OKAY;
|
||||
if (!m_data->m_calendar->addIncidence(incidence)) {
|
||||
throwError("could not add incidence");
|
||||
}
|
||||
|
@ -445,7 +548,7 @@ TestingSyncSource::InsertItemResult KCalExtendedSource::insertItem(const string
|
|||
newUID = m_data->getItemID(incidence).getLUID();
|
||||
} else {
|
||||
KCalCore::Incidence::Ptr incidence = incidences[0];
|
||||
updated = true;
|
||||
updated = uid.empty() ? ITEM_REPLACED : ITEM_OKAY;
|
||||
newUID = oldUID;
|
||||
KCalCore::Incidence::Ptr original = m_data->findIncidence(oldUID);
|
||||
if (!original) {
|
||||
|
@ -475,6 +578,7 @@ TestingSyncSource::InsertItemResult KCalExtendedSource::insertItem(const string
|
|||
}
|
||||
|
||||
m_data->m_modified = true;
|
||||
m_insert_run++;
|
||||
|
||||
return InsertItemResult(newUID,
|
||||
"",
|
||||
|
@ -495,14 +599,16 @@ void KCalExtendedSource::deleteItem(const string &uid)
|
|||
throwError(string("could not delete incidence") + uid);
|
||||
}
|
||||
m_data->m_modified = true;
|
||||
m_delete_run++;
|
||||
}
|
||||
|
||||
void KCalExtendedSource::listAllItems(RevisionMap_t &revisions)
|
||||
{
|
||||
KCalCore::Incidence::List incidences;
|
||||
if (!m_data->m_storage->allIncidences(&incidences, m_data->m_notebookUID)) {
|
||||
throwError("allIncidences() failed");
|
||||
}
|
||||
incidences = m_data->m_calendar->incidences();
|
||||
// if (!m_data->m_storage->allIncidences(&incidences, m_data->m_notebookUID)) {
|
||||
// throwError("allIncidences() failed");
|
||||
// }
|
||||
foreach (KCalCore::Incidence::Ptr incidence, incidences) {
|
||||
if (incidence->type() == m_data->m_type) {
|
||||
revisions[m_data->getItemID(incidence).getLUID()] = "1";
|
||||
|
|
|
@ -45,8 +45,14 @@ class KCalExtendedData;
|
|||
*/
|
||||
class KCalExtendedSource : public TestingSyncSource, private SyncSourceAdmin, private SyncSourceBlob, private SyncSourceRevisions, public SyncSourceLogging, private boost::noncopyable
|
||||
{
|
||||
public:
|
||||
KCalExtendedSource(const SyncSourceParams ¶ms);
|
||||
public:
|
||||
enum Type {
|
||||
Event = 0,
|
||||
Todo = 1,
|
||||
Journal = 2
|
||||
};
|
||||
|
||||
KCalExtendedSource(const SyncSourceParams ¶ms, Type type);
|
||||
~KCalExtendedSource();
|
||||
|
||||
protected:
|
||||
|
@ -57,7 +63,7 @@ class KCalExtendedSource : public TestingSyncSource, private SyncSourceAdmin, pr
|
|||
virtual Databases getDatabases();
|
||||
virtual void enableServerMode();
|
||||
virtual bool serverModeEnabled() const;
|
||||
virtual std::string getPeerMimeType() const { return "text/calendar"; }
|
||||
virtual std::string getPeerMimeType() const { return getMimeType(); }
|
||||
|
||||
/* implementation of SyncSourceSession interface */
|
||||
virtual void beginSync(const std::string &lastToken, const std::string &resumeToken);
|
||||
|
@ -67,8 +73,8 @@ class KCalExtendedSource : public TestingSyncSource, private SyncSourceAdmin, pr
|
|||
virtual void deleteItem(const string &luid);
|
||||
|
||||
/* implementation of SyncSourceSerialize interface */
|
||||
virtual std::string getMimeType() const { return "text/calendar"; }
|
||||
virtual std::string getMimeVersion() const { return "2.0"; }
|
||||
virtual std::string getMimeType() const;
|
||||
virtual std::string getMimeVersion() const;
|
||||
virtual InsertItemResult insertItem(const std::string &luid, const std::string &item);
|
||||
virtual void readItem(const std::string &luid, std::string &item);
|
||||
|
||||
|
@ -84,6 +90,9 @@ class KCalExtendedSource : public TestingSyncSource, private SyncSourceAdmin, pr
|
|||
|
||||
private:
|
||||
KCalExtendedData *m_data;
|
||||
Type m_type;
|
||||
unsigned m_delete_run;
|
||||
unsigned m_insert_run;
|
||||
};
|
||||
|
||||
SE_END_CXX
|
||||
|
|
|
@ -27,7 +27,7 @@ SE_BEGIN_CXX
|
|||
static SyncSource *createSource(const SyncSourceParams ¶ms)
|
||||
{
|
||||
SourceType sourceType = SyncSource::getSourceType(params.m_nodes);
|
||||
bool isMe = sourceType.m_backend == "mkcal";
|
||||
bool isMe = sourceType.m_backend == "mkcal-events";
|
||||
bool maybeMe = sourceType.m_backend == "calendar";
|
||||
|
||||
if (isMe || maybeMe) {
|
||||
|
@ -37,11 +37,44 @@ static SyncSource *createSource(const SyncSourceParams ¶ms)
|
|||
sourceType.m_format == "text/calendar") {
|
||||
return
|
||||
#ifdef ENABLE_KCALEXTENDED
|
||||
true ? new KCalExtendedSource(params) :
|
||||
true ? new KCalExtendedSource(params, KCalExtendedSource::Event) :
|
||||
#endif
|
||||
isMe ? RegisterSyncSource::InactiveSource(params) : NULL;
|
||||
}
|
||||
}
|
||||
|
||||
isMe = sourceType.m_backend == "mkcal-todos";
|
||||
maybeMe = sourceType.m_backend == "todo";
|
||||
|
||||
if (isMe || maybeMe) {
|
||||
if (sourceType.m_format == "" ||
|
||||
sourceType.m_format == "text/x-vcalendar" ||
|
||||
sourceType.m_format == "text/x-calendar" ||
|
||||
sourceType.m_format == "text/calendar") {
|
||||
return
|
||||
#ifdef ENABLE_KCALEXTENDED
|
||||
true ? new KCalExtendedSource(params, KCalExtendedSource::Todo) :
|
||||
#endif
|
||||
isMe ? RegisterSyncSource::InactiveSource(params) : NULL;
|
||||
}
|
||||
}
|
||||
|
||||
isMe = sourceType.m_backend == "mkcal-notes";
|
||||
maybeMe = sourceType.m_backend == "memo";
|
||||
|
||||
if (isMe || maybeMe) {
|
||||
if (sourceType.m_format == "" ||
|
||||
sourceType.m_format == "text/x-vcalendar" ||
|
||||
sourceType.m_format == "text/x-calendar" ||
|
||||
sourceType.m_format == "text/calendar") {
|
||||
return
|
||||
#ifdef ENABLE_KCALEXTENDED
|
||||
true ? new KCalExtendedSource(params, KCalExtendedSource::Journal) :
|
||||
#endif
|
||||
isMe ? RegisterSyncSource::InactiveSource(params) : NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -52,16 +85,36 @@ static RegisterSyncSource registerMe("KCalExtended",
|
|||
false,
|
||||
#endif
|
||||
createSource,
|
||||
"mkcal = KCalExtended = calendar\n"
|
||||
"mkcal-events = mkcal = KCalExtended = calendar\n"
|
||||
" 'database' normally is the name of a calendar\n"
|
||||
" inside the default calendar storage. If it starts\n"
|
||||
" with the 'SyncEvolution_Test_' prefix, it will be\n"
|
||||
" created as needed, otherwise it must exist.\n"
|
||||
#ifdef ENABLE_MAEMO
|
||||
" If it starts with the 'uid:' prefix, the specified\n"
|
||||
" calendar in the default SQLite storage file will\n"
|
||||
" be used. It must exist.\n"
|
||||
#endif
|
||||
" If it starts with the 'file://' prefix, the default\n"
|
||||
" calendar in the specified SQLite storage file will\n"
|
||||
" created (if needed) and used.\n",
|
||||
" created (if needed) and used.\n"
|
||||
"mkcal-todos = todo\n"
|
||||
" Same as above.\n"
|
||||
"mkcal-notes = memo\n"
|
||||
#ifdef ENABLE_MAEMO
|
||||
" Same as above. Keep in mind that, by default, notes\n"
|
||||
" are stored in their own database, separate from\n"
|
||||
" events and todos. The name of this database is\n"
|
||||
" hardcoded into the device's builtin Notes app.\n"
|
||||
" Don't override the default unless you know what\n"
|
||||
" you are doing.\n",
|
||||
#else
|
||||
" Same as above.\n",
|
||||
#endif
|
||||
Values() +
|
||||
(Aliases("mkcal") + "KCalExtended" + "MeeGo Calendar"));
|
||||
(Aliases("mkcal-events") + "mkcal" + "KCalExtended" + "MeeGo Calendar") +
|
||||
(Aliases("mkcal-todos") + "MeeGo Tasks") +
|
||||
(Aliases("mkcal-notes") + "MeeGo Notes"));
|
||||
|
||||
#ifdef ENABLE_KCALEXTENDED
|
||||
#ifdef ENABLE_UNIT_TESTS
|
||||
|
|
|
@ -46,6 +46,26 @@ MaemoCalendarSource::MaemoCalendarSource(int EntryType, int EntryFormat,
|
|||
TrackingSyncSource(params),
|
||||
entry_type(EntryType), entry_format(EntryFormat)
|
||||
{
|
||||
switch (EntryType) {
|
||||
case EVENT:
|
||||
SyncSourceLogging::init(InitList<std::string>("SUMMARY") + "LOCATION",
|
||||
", ",
|
||||
m_operations);
|
||||
break;
|
||||
case TODO:
|
||||
SyncSourceLogging::init(InitList<std::string>("SUMMARY"),
|
||||
", ",
|
||||
m_operations);
|
||||
break;
|
||||
case JOURNAL:
|
||||
SyncSourceLogging::init(InitList<std::string>("SUBJECT"),
|
||||
", ",
|
||||
m_operations);
|
||||
break;
|
||||
default:
|
||||
throwError("invalid calendar type");
|
||||
break;
|
||||
}
|
||||
mc = CMulticalendar::MCInstance();
|
||||
cal = NULL;
|
||||
if (!mc) {
|
||||
|
@ -53,17 +73,19 @@ MaemoCalendarSource::MaemoCalendarSource(int EntryType, int EntryFormat,
|
|||
}
|
||||
}
|
||||
|
||||
const char *MaemoCalendarSource::getMimeType() const
|
||||
std::string MaemoCalendarSource::getMimeType() const
|
||||
{
|
||||
switch (entry_format) {
|
||||
case -1: return "text/plain";
|
||||
case ICAL_TYPE: return "text/calendar";
|
||||
case ICAL_TYPE: return entry_type == JOURNAL ?
|
||||
"text/calendar+plain" :
|
||||
"text/calendar";
|
||||
case VCAL_TYPE: return "text/x-calendar";
|
||||
default: return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
const char *MaemoCalendarSource::getMimeVersion() const
|
||||
std::string MaemoCalendarSource::getMimeVersion() const
|
||||
{
|
||||
switch (entry_format) {
|
||||
case -1: return "1.0";
|
||||
|
@ -113,10 +135,13 @@ void MaemoCalendarSource::open()
|
|||
|
||||
bool MaemoCalendarSource::isEmpty()
|
||||
{
|
||||
// TODO: provide a real implementation. Always returning false
|
||||
// here disables the "allow slow sync when no local data" heuristic
|
||||
// for preventSlowSync=1.
|
||||
return false;
|
||||
int id = cal->getCalendarId(), err;
|
||||
switch (entry_type) {
|
||||
case EVENT: return !mc->getEventCount(id, err);
|
||||
case TODO: return !mc->getTodoCount(id, err);
|
||||
case JOURNAL: return !mc->getNoteCount(id, err);
|
||||
default: return true;
|
||||
}
|
||||
}
|
||||
|
||||
void MaemoCalendarSource::close()
|
||||
|
@ -125,9 +150,6 @@ void MaemoCalendarSource::close()
|
|||
conv = NULL;
|
||||
delete cal;
|
||||
cal = NULL;
|
||||
// since timestamps are rounded down to nearest second,
|
||||
// sleep until next second, just in case
|
||||
sleep(1);
|
||||
}
|
||||
|
||||
MaemoCalendarSource::Databases MaemoCalendarSource::getDatabases()
|
||||
|
@ -159,7 +181,9 @@ void MaemoCalendarSource::listAllItems(RevisionMap_t &revisions)
|
|||
#if 0 /* this code exposes a bug in calendar-backend, https://bugs.maemo.org/show_bug.cgi?id=8277 */
|
||||
// I've found no way to query the last modified time of a component
|
||||
// without getting the whole component.
|
||||
// This limit should hopefully reduce memory usage of that a bit
|
||||
// This limit should hopefully reduce memory usage of that a bit,
|
||||
// though it could be bad if the database happens to change
|
||||
// between getComponents() calls.
|
||||
static const int limit = 1024;
|
||||
int ofs = 0, err;
|
||||
vector< CComponent * > comps;
|
||||
|
@ -180,14 +204,20 @@ void MaemoCalendarSource::listAllItems(RevisionMap_t &revisions)
|
|||
}
|
||||
}
|
||||
#else
|
||||
// this avoids the calendar-backend bug, but may use unlimited memory;
|
||||
// hopefully the users aren't saving their entire life here!
|
||||
// Instead, get a full list of IDs from getIdList(), then
|
||||
// load each entry from the calendar one by one. The
|
||||
// alternative would be to load the whole calendar into
|
||||
// memory all at once, but that's probably not all that
|
||||
// desirable, given the N900's limited memory.
|
||||
int err;
|
||||
vector< CComponent * > comps;
|
||||
|
||||
comps = cal->getComponents(entry_type, -1, -1, err);
|
||||
BOOST_FOREACH(CComponent * c, comps) {
|
||||
revisions[c->getId()] = get_revision(c);
|
||||
vector< string > ids = cal->getIdList(entry_type, err);
|
||||
BOOST_FOREACH(std::string& id, ids) {
|
||||
CComponent *c = cal->getEntry(id, entry_type, err);
|
||||
if (!c)
|
||||
{
|
||||
throwError(string("retrieving item: ") + id);
|
||||
}
|
||||
revisions[id] = get_revision(c);
|
||||
delete c;
|
||||
}
|
||||
#endif
|
||||
|
@ -201,7 +231,7 @@ void MaemoCalendarSource::readItem(const string &uid, std::string &item, bool ra
|
|||
throwError(string("retrieving item: ") + uid);
|
||||
}
|
||||
if (entry_format == -1) {
|
||||
item = c->getDescription();
|
||||
item = c->getSummary();
|
||||
err = CALENDAR_OPERATION_SUCCESSFUL;
|
||||
} else {
|
||||
item = conv->localToIcalVcal(c, FileType(entry_format), err);
|
||||
|
@ -216,7 +246,8 @@ TrackingSyncSource::InsertItemResult MaemoCalendarSource::insertItem(const strin
|
|||
{
|
||||
int err;
|
||||
CComponent *c;
|
||||
bool r, u = false;
|
||||
bool r;
|
||||
InsertItemResultState u = ITEM_OKAY;
|
||||
TrackingSyncSource::InsertItemResult result;
|
||||
|
||||
if (cal->getCalendarType() == BIRTHDAY_CALENDAR) {
|
||||
|
@ -275,7 +306,7 @@ TrackingSyncSource::InsertItemResult MaemoCalendarSource::insertItem(const strin
|
|||
throwError(string("creating item "));
|
||||
}
|
||||
if (err == CALENDAR_ENTRY_DUPLICATED) {
|
||||
u = true;
|
||||
u = ITEM_REPLACED;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -288,6 +319,12 @@ TrackingSyncSource::InsertItemResult MaemoCalendarSource::insertItem(const strin
|
|||
void MaemoCalendarSource::removeItem(const string &uid)
|
||||
{
|
||||
int err;
|
||||
|
||||
if (cal->getCalendarType() == BIRTHDAY_CALENDAR) {
|
||||
// stubbornly refuse to try this
|
||||
throwError(string("can't sync smart calendar ") + cal->getCalendarName());
|
||||
}
|
||||
|
||||
cal->deleteComponent(uid, err);
|
||||
if (err != CALENDAR_OPERATION_SUCCESSFUL) {
|
||||
throwError(string("deleting item: ") + uid);
|
||||
|
@ -304,6 +341,31 @@ string MaemoCalendarSource::get_revision(CComponent * c)
|
|||
return revision.str();
|
||||
}
|
||||
|
||||
std::string MaemoCalendarSource::getDescription(const string &uid)
|
||||
{
|
||||
string ret;
|
||||
int err;
|
||||
CComponent * c = cal->getEntry(uid, entry_type, err);
|
||||
if (c) {
|
||||
list<string> parts;
|
||||
string str;
|
||||
str = c->getSummary();
|
||||
if (!str.empty()) {
|
||||
parts.push_back(str);
|
||||
}
|
||||
if (entry_type == EVENT)
|
||||
{
|
||||
str = c->getLocation();
|
||||
if (!str.empty()) {
|
||||
parts.push_back(str);
|
||||
}
|
||||
}
|
||||
ret = boost::join(parts, ", ");
|
||||
delete c;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
SE_END_CXX
|
||||
|
||||
#endif /* ENABLE_MAEMO_CALENDAR */
|
||||
|
|
|
@ -35,13 +35,13 @@ SE_BEGIN_CXX
|
|||
|
||||
/**
|
||||
* Implement access to Maemo calendar.
|
||||
* Change tracking is done by using the last-modified time.
|
||||
* It might be possible to improve on it by taking the last sync time
|
||||
* and calling the getAllAdded/Modified/Deleted(...) methods provided by
|
||||
* the CCalendar class, instead of comparing every single record in
|
||||
* the database like TrackingSyncSource probably needs to do otherwise.
|
||||
* Change tracking is done by using the last-modified time
|
||||
* as TrackingSyncSource revisions. While it might be possible
|
||||
* to improve performance by using the getAllAdded/Modified
|
||||
* etc methods, it would make the change tracking less robust,
|
||||
* so it doesn't seem worth it.
|
||||
*/
|
||||
class MaemoCalendarSource : public TrackingSyncSource, private boost::noncopyable
|
||||
class MaemoCalendarSource : public TrackingSyncSource, public SyncSourceLogging, private boost::noncopyable
|
||||
{
|
||||
public:
|
||||
MaemoCalendarSource(int EntryType, int EntryFormat,
|
||||
|
@ -54,8 +54,8 @@ class MaemoCalendarSource : public TrackingSyncSource, private boost::noncopyabl
|
|||
virtual bool isEmpty();
|
||||
virtual void close();
|
||||
virtual Databases getDatabases();
|
||||
virtual const char *getMimeType() const;
|
||||
virtual const char *getMimeVersion() const;
|
||||
virtual std::string getMimeType() const;
|
||||
virtual std::string getMimeVersion() const;
|
||||
virtual void getSynthesisInfo(SynthesisInfo &info,
|
||||
XMLConfigFragments &fragments);
|
||||
|
||||
|
@ -63,8 +63,11 @@ class MaemoCalendarSource : public TrackingSyncSource, private boost::noncopyabl
|
|||
virtual void listAllItems(RevisionMap_t &revisions);
|
||||
virtual InsertItemResult insertItem(const string &luid, const std::string &item, bool raw);
|
||||
void readItem(const std::string &luid, std::string &item, bool raw);
|
||||
virtual void removeItem(const string &uid);
|
||||
virtual void removeItem(const string &luid);
|
||||
|
||||
/* implementation of SyncSourceLogging interface */
|
||||
virtual std::string getDescription(const string &luid);
|
||||
|
||||
private:
|
||||
CMulticalendar *mc; /**< multicalendar */
|
||||
CCalendar *cal; /**< calendar */
|
||||
|
|
|
@ -68,12 +68,12 @@ static SyncSource *createSource(const SyncSourceParams ¶ms)
|
|||
maybeMe = sourceType.m_backend == "memo";
|
||||
|
||||
if (isMe || maybeMe) {
|
||||
if (sourceType.m_format == "" || sourceType.m_format == "text/plain") {
|
||||
return new MaemoCalendarSource(JOURNAL, -1, params);
|
||||
} else if (sourceType.m_format == "text/calendar") {
|
||||
if (sourceType.m_format == "" || sourceType.m_format == "text/calendar") {
|
||||
return new MaemoCalendarSource(JOURNAL, ICAL_TYPE, params);
|
||||
} else if (sourceType.m_format == "text/x-vcalendar") {
|
||||
return new MaemoCalendarSource(JOURNAL, VCAL_TYPE, params);
|
||||
} else if (sourceType.m_format == "text/plain") {
|
||||
return new MaemoCalendarSource(JOURNAL, -1, params);
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
@ -36,6 +36,8 @@
|
|||
#include <QContactLocalIdFilter>
|
||||
#include <QContactThumbnail>
|
||||
#include <QContactAvatar>
|
||||
#include <QContactSyncTarget>
|
||||
#include <QContactDetailFilter>
|
||||
|
||||
#include <QVersitContactExporter>
|
||||
#include <QVersitContactImporter>
|
||||
|
@ -422,17 +424,42 @@ QtContactsSource::Databases QtContactsSource::getDatabases()
|
|||
{
|
||||
Databases result;
|
||||
QStringList availableManagers = QContactManager::availableManagers();
|
||||
bool isDefault = true;
|
||||
|
||||
#if 0
|
||||
result.push_back(Database("select database via QtContacts Manager URL",
|
||||
"qtcontacts:tracker:"));
|
||||
#endif
|
||||
|
||||
foreach (QString manager, availableManagers) {
|
||||
QMap<QString, QString> params;
|
||||
QString uri = QContactManager::buildUri(manager, params);
|
||||
result.push_back(Database(manager.toStdString(),
|
||||
uri.toStdString(),
|
||||
isDefault));
|
||||
isDefault = false;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void QtContactsSource::listAllItems(RevisionMap_t &revisions)
|
||||
{
|
||||
#ifdef ENABLE_MAEMO
|
||||
QContactLocalId self_id = m_data->m_manager->selfContactId();
|
||||
#endif
|
||||
|
||||
QContactFetchRequest fetch;
|
||||
fetch.setManager(m_data->m_manager.get());
|
||||
|
||||
#ifdef ENABLE_MAEMO
|
||||
// only sync contacts from addressbook, not from Telepathy or wherever
|
||||
QContactDetailFilter filter;
|
||||
filter.setDetailDefinitionName(QContactSyncTarget::DefinitionName, QContactSyncTarget::FieldSyncTarget);
|
||||
filter.setValue("addressbook");
|
||||
filter.setMatchFlags(QContactFilter::MatchExactly);
|
||||
fetch.setFilter(filter);
|
||||
#endif
|
||||
|
||||
// only need ID and time stamps
|
||||
QContactFetchHint hint;
|
||||
hint.setOptimizationHints(QContactFetchHint::OptimizationHints(QContactFetchHint::NoRelationships|QContactFetchHint::NoBinaryBlobs));
|
||||
|
@ -443,6 +470,13 @@ void QtContactsSource::listAllItems(RevisionMap_t &revisions)
|
|||
fetch.waitForFinished();
|
||||
m_data->checkError("read all items", fetch);
|
||||
foreach (const QContact &contact, fetch.contacts()) {
|
||||
#ifdef ENABLE_MAEMO
|
||||
if (contact.localId() == self_id) {
|
||||
// Do not synchronize "self" contact
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
|
||||
string revision = QtContactsData::getRev(contact);
|
||||
string luid = QtContactsData::getLUID(contact);
|
||||
if (luid == "2147483647" &&
|
||||
|
@ -478,6 +512,10 @@ void QtContactsSource::readItem(const string &uid, std::string &item, bool raw)
|
|||
thumbnail.setThumbnail(image);
|
||||
contact.saveDetail(&thumbnail);
|
||||
}
|
||||
|
||||
// foreach (const QContactSyncTarget &target, contact.details<QContactSyncTarget>()) {
|
||||
// std::cout << " Sync Target: " << target.syncTarget().toUtf8().data() << std::endl;
|
||||
// }
|
||||
}
|
||||
|
||||
QStringList profiles;
|
||||
|
@ -559,7 +597,7 @@ TrackingSyncSource::InsertItemResult QtContactsSource::insertItem(const string &
|
|||
|
||||
return InsertItemResult(QtContactsData::getLUID(savedContact),
|
||||
QtContactsData::getRev(finalContact),
|
||||
false);
|
||||
ITEM_OKAY);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#! /bin/bash
|
||||
#! /bin/sh
|
||||
#
|
||||
# Copyright (C) 2011 Intel Corporation
|
||||
#
|
||||
|
@ -49,7 +49,7 @@ trap "[ -s $LOG ] && ( echo $0 failed to find '$TYPE $DOMAIN':; cat $LOG >&2 );
|
|||
|
||||
# find one of the supported tools for DNS queries
|
||||
TOOL=
|
||||
ALTERNATIVES="adnshost host nslookup"
|
||||
ALTERNATIVES="adnshost host /usr/lib/syncevolution/host nslookup"
|
||||
for i in $ALTERNATIVES; do
|
||||
if which $i >/dev/null; then
|
||||
TOOL=$i
|
||||
|
@ -89,11 +89,12 @@ for type in ${TYPE}s ${TYPE}; do
|
|||
PORT=`echo $res | sed -e 's;.*service = [^ ]* [^ ]* \([^ ]*\) \([^ ]*\)\.;\1;'`
|
||||
HOSTNAME=`echo $res | sed -e 's;.*service = [^ ]* [^ ]* \([^ ]*\) \([^ ]*\)\.;\2;'`
|
||||
;;
|
||||
host)
|
||||
res=`$TOOL -t srv _$type._tcp.$DOMAIN | tee -a $LOG | grep "has SRV record" | head -1`
|
||||
host|*/host)
|
||||
res=`$TOOL -t srv _$type._tcp.$DOMAIN | tee -a $LOG | grep "\<SRV\>" | head -1`
|
||||
# _caldavs._tcp.yahoo.com has SRV record 1 1 443 caldav.calendar.yahoo.com.
|
||||
PORT=`echo $res | sed -e 's;.* \([^ ]*\) \([^ ]*\)\.;\1;'`
|
||||
HOSTNAME=`echo $res | sed -e 's;.* \([^ ]*\) \([^ ]*\)\.;\2;'`
|
||||
# _caldavs._tcp.yahoo.com SRV 1 1 443 caldav.calendar.yahoo.com
|
||||
PORT=`echo $res | sed -e 's;.* \([^ ]*\) \([^. ]\+\(\.[^. ]\+\)*\)\.\?;\1;'`
|
||||
HOSTNAME=`echo $res | sed -e 's;.* \([^ ]*\) \([^. ]\+\(\.[^. ]\+\)*\)\.\?;\2;'`
|
||||
;;
|
||||
*)
|
||||
echo "unsupported tool $TOOL"
|
||||
|
|
|
@ -18,7 +18,7 @@ CLEANFILES += src/backends/webdav/syncevo-webdav-lookup
|
|||
|
||||
src/backends/webdav/syncevo-webdav-lookup: $(srcdir)/src/backends/webdav/syncevo-webdav-lookup.sh
|
||||
$(AM_V_GEN)rm -f $@ ; \
|
||||
ln -s $< $@
|
||||
cd src/backends/webdav && ln -s $(notdir $<) $(notdir $@)
|
||||
|
||||
src_backends_webdav_src = \
|
||||
src/backends/webdav/CalDAVSource.h \
|
||||
|
|
|
@ -39,6 +39,9 @@ CurlTransportAgent::CurlTransportAgent() :
|
|||
m_replyLen(0),
|
||||
m_replySize(0)
|
||||
{
|
||||
#ifdef ENABLE_MAEMO /* hack because Maemo doesn't support IPv6 yet */
|
||||
curl_easy_setopt(m_easyHandle, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
|
||||
#endif
|
||||
/*
|
||||
* set up for post where message is pushed into curl via
|
||||
* its read callback and reply is stored in write callback
|
||||
|
|
|
@ -873,7 +873,7 @@ public:
|
|||
// for a password. However, that does not cover failures
|
||||
// like the parent not asking us to sync in the first place
|
||||
// and also does not work with libdbus (https://bugs.freedesktop.org/show_bug.cgi?id=49728).
|
||||
m_forkexec->m_onQuit.connect(onParentQuit);
|
||||
m_forkexec->m_onQuit.connect(&onParentQuit);
|
||||
|
||||
m_forkexec->connect();
|
||||
}
|
||||
|
|
|
@ -2815,6 +2815,9 @@ void SyncContext::initEngine(bool logXML)
|
|||
}
|
||||
}
|
||||
|
||||
// This is just the declaration. The actual function pointer instance
|
||||
// is inside libsynthesis, which, for historic purposes, doesn't define
|
||||
// it in its header files (yet).
|
||||
extern "C" int (*SySync_ConsolePrintf)(FILE *stream, const char *format, ...);
|
||||
|
||||
static int nopPrintf(FILE *stream, const char *format, ...) { return 0; }
|
||||
|
|
|
@ -55,7 +55,9 @@
|
|||
#if defined(USE_EDS_CLIENT)
|
||||
#include <libedataserver/libedataserver.h>
|
||||
#else
|
||||
#ifdef HAVE_LIBEDATASERVER_EDS_VERSION_H
|
||||
#include <libedataserver/eds-version.h>
|
||||
#endif
|
||||
#include <libedataserver/e-source.h>
|
||||
#include <libedataserver/e-source-list.h>
|
||||
#endif
|
||||
|
|
|
@ -1758,6 +1758,24 @@ void LocalTests::testLinkedItemsParentChild() {
|
|||
CT_ASSERT_MESSAGE(exdate + " not found in:\n" + parentDataEngine, pos != parentDataEngine.npos);
|
||||
}
|
||||
|
||||
if (config.m_supportsReccurenceEXDates) {
|
||||
TestingSyncSourcePtr source;
|
||||
SOURCE_ASSERT_NO_FAILURE(source.get(), source.reset(createSourceA()));
|
||||
CLIENT_TEST_LOG("retrieve parent as reported to the Synthesis engine, check for X-SYNCEVOLUTION-EXDATE-DETACHED");
|
||||
std::string parentDataEngine;
|
||||
CT_ASSERT_NO_THROW(source->readItem(parent, parentDataEngine));
|
||||
size_t pos = childData.find("RECURRENCE-ID");
|
||||
CT_ASSERT(pos != childData.npos);
|
||||
size_t end = childData.find_first_of("\r\n", pos);
|
||||
CT_ASSERT(end != childData.npos);
|
||||
std::string exdate = childData.substr(pos, end - pos);
|
||||
boost::replace_first(exdate, "RECURRENCE-ID", "X-SYNCEVOLUTION-EXDATE-DETACHED");
|
||||
// not generated because not needed by Synthesis engine
|
||||
boost::replace_first(exdate, ";VALUE=DATE", "");
|
||||
pos = parentDataEngine.find(exdate);
|
||||
CT_ASSERT_MESSAGE(exdate + " not found in:\n" + parentDataEngine, pos != parentDataEngine.npos);
|
||||
}
|
||||
|
||||
if (getenv("CLIENT_TEST_LINKED_ITEMS_NO_DELETE")) {
|
||||
return;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue