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:
Patrick Ohly 2012-11-01 14:39:31 +01:00
commit 340579cbdb
17 changed files with 397 additions and 87 deletions

4
.gitignore vendored
View File

@ -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

View File

@ -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,

View File

@ -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=

View File

@ -65,12 +65,26 @@ class KCalExtendedData
public:
KCalExtendedData(KCalExtendedSource *parent,
const QString &notebook,
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 &params) :
KCalExtendedSource::KCalExtendedSource(const SyncSourceParams &params, 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";

View File

@ -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 &params);
public:
enum Type {
Event = 0,
Todo = 1,
Journal = 2
};
KCalExtendedSource(const SyncSourceParams &params, 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

View File

@ -27,7 +27,7 @@ SE_BEGIN_CXX
static SyncSource *createSource(const SyncSourceParams &params)
{
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 &params)
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

View File

@ -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 */

View File

@ -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 */

View File

@ -68,12 +68,12 @@ static SyncSource *createSource(const SyncSourceParams &params)
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;
}

View File

@ -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);
}

View File

@ -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"

View File

@ -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 \

View File

@ -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

View File

@ -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();
}

View File

@ -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; }

View File

@ -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

View File

@ -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;
}