diff options
author | Patrick Ohly <patrick.ohly@intel.com> | 2012-11-01 14:39:31 +0100 |
---|---|---|
committer | Patrick Ohly <patrick.ohly@intel.com> | 2012-11-01 19:13:58 +0100 |
commit | 340579cbdbd8f630846d85319b274a3e41a6313a (patch) | |
tree | e6b17f0911e3d8bd241eb74e5b14a5c0b7532740 | |
parent | 6648a36578e2c5b2e87c3bc749c81e8414f423a5 (diff) | |
parent | 0d86dc14312ac548fdd5b7c513ef2ab851964f3f (diff) |
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, ...);
-rw-r--r-- | .gitignore | 4 | ||||
-rw-r--r-- | configure.ac | 9 | ||||
-rw-r--r-- | src/backends/evolution/configure-sub.in | 5 | ||||
-rw-r--r-- | src/backends/kcalextended/KCalExtendedSource.cpp | 170 | ||||
-rw-r--r-- | src/backends/kcalextended/KCalExtendedSource.h | 19 | ||||
-rw-r--r-- | src/backends/kcalextended/KCalExtendedSourceRegister.cpp | 63 | ||||
-rw-r--r-- | src/backends/maemo/MaemoCalendarSource.cpp | 104 | ||||
-rw-r--r-- | src/backends/maemo/MaemoCalendarSource.h | 21 | ||||
-rw-r--r-- | src/backends/maemo/MaemoCalendarSourceRegister.cpp | 6 | ||||
-rw-r--r-- | src/backends/qtcontacts/QtContactsSource.cpp | 40 | ||||
-rwxr-xr-x | src/backends/webdav/syncevo-webdav-lookup.sh | 13 | ||||
-rw-r--r-- | src/backends/webdav/webdav.am | 2 | ||||
-rw-r--r-- | src/syncevo/CurlTransportAgent.cpp | 3 | ||||
-rw-r--r-- | src/syncevo/LocalTransportAgent.cpp | 2 | ||||
-rw-r--r-- | src/syncevo/SyncContext.cpp | 3 | ||||
-rw-r--r-- | src/syncevo/eds_abi_wrapper.h | 2 | ||||
-rw-r--r-- | test/ClientTest.cpp | 18 |
17 files changed, 397 insertions, 87 deletions
@@ -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 diff --git a/configure.ac b/configure.ac index 4a957425..cb66617e 100644 --- a/configure.ac +++ b/configure.ac @@ -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, diff --git a/src/backends/evolution/configure-sub.in b/src/backends/evolution/configure-sub.in index 8ffad9dc..e27b0307 100644 --- a/src/backends/evolution/configure-sub.in +++ b/src/backends/evolution/configure-sub.in @@ -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= diff --git a/src/backends/kcalextended/KCalExtendedSource.cpp b/src/backends/kcalextended/KCalExtendedSource.cpp index 8849c733..0e3cbebd 100644 --- a/src/backends/kcalextended/KCalExtendedSource.cpp +++ b/src/backends/kcalextended/KCalExtendedSource.cpp @@ -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"; diff --git a/src/backends/kcalextended/KCalExtendedSource.h b/src/backends/kcalextended/KCalExtendedSource.h index 49af80a0..179fd860 100644 --- a/src/backends/kcalextended/KCalExtendedSource.h +++ b/src/backends/kcalextended/KCalExtendedSource.h @@ -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 diff --git a/src/backends/kcalextended/KCalExtendedSourceRegister.cpp b/src/backends/kcalextended/KCalExtendedSourceRegister.cpp index 8d69696e..6a06346a 100644 --- a/src/backends/kcalextended/KCalExtendedSourceRegister.cpp +++ b/src/backends/kcalextended/KCalExtendedSourceRegister.cpp @@ -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 diff --git a/src/backends/maemo/MaemoCalendarSource.cpp b/src/backends/maemo/MaemoCalendarSource.cpp index 39a4682a..6b7300c1 100644 --- a/src/backends/maemo/MaemoCalendarSource.cpp +++ b/src/backends/maemo/MaemoCalendarSource.cpp @@ -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 */ diff --git a/src/backends/maemo/MaemoCalendarSource.h b/src/backends/maemo/MaemoCalendarSource.h index 5f68cfe7..b995600e 100644 --- a/src/backends/maemo/MaemoCalendarSource.h +++ b/src/backends/maemo/MaemoCalendarSource.h @@ -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 */ diff --git a/src/backends/maemo/MaemoCalendarSourceRegister.cpp b/src/backends/maemo/MaemoCalendarSourceRegister.cpp index a42aa8d2..fceeb909 100644 --- a/src/backends/maemo/MaemoCalendarSourceRegister.cpp +++ b/src/backends/maemo/MaemoCalendarSourceRegister.cpp @@ -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; } diff --git a/src/backends/qtcontacts/QtContactsSource.cpp b/src/backends/qtcontacts/QtContactsSource.cpp index da7b5f8b..2b94cfd5 100644 --- a/src/backends/qtcontacts/QtContactsSource.cpp +++ b/src/backends/qtcontacts/QtContactsSource.cpp @@ -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); } diff --git a/src/backends/webdav/syncevo-webdav-lookup.sh b/src/backends/webdav/syncevo-webdav-lookup.sh index a30aa1f0..88496f72 100755 --- a/src/backends/webdav/syncevo-webdav-lookup.sh +++ b/src/backends/webdav/syncevo-webdav-lookup.sh @@ -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" diff --git a/src/backends/webdav/webdav.am b/src/backends/webdav/webdav.am index 2cf392e9..10b2075b 100644 --- a/src/backends/webdav/webdav.am +++ b/src/backends/webdav/webdav.am @@ -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 \ diff --git a/src/syncevo/CurlTransportAgent.cpp b/src/syncevo/CurlTransportAgent.cpp index 8d940b3b..01d92c76 100644 --- a/src/syncevo/CurlTransportAgent.cpp +++ b/src/syncevo/CurlTransportAgent.cpp @@ -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 diff --git a/src/syncevo/LocalTransportAgent.cpp b/src/syncevo/LocalTransportAgent.cpp index 3232d0bd..f9ad91f7 100644 --- a/src/syncevo/LocalTransportAgent.cpp +++ b/src/syncevo/LocalTransportAgent.cpp @@ -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(); } diff --git a/src/syncevo/SyncContext.cpp b/src/syncevo/SyncContext.cpp index c0092a86..67e2239a 100644 --- a/src/syncevo/SyncContext.cpp +++ b/src/syncevo/SyncContext.cpp @@ -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; } diff --git a/src/syncevo/eds_abi_wrapper.h b/src/syncevo/eds_abi_wrapper.h index 2750a57c..186fab29 100644 --- a/src/syncevo/eds_abi_wrapper.h +++ b/src/syncevo/eds_abi_wrapper.h @@ -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 diff --git a/test/ClientTest.cpp b/test/ClientTest.cpp index b9bdca72..e504f2aa 100644 --- a/test/ClientTest.cpp +++ b/test/ClientTest.cpp @@ -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; } |