Hello community,
here is the log from the commit of package libkolab for openSUSE:Factory checked in at 2015-04-06 00:24:09
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/libkolab (Old)
and /work/SRC/openSUSE:Factory/.libkolab.new (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "libkolab"
Changes:
--------
--- /work/SRC/openSUSE:Factory/libkolab/libkolab.changes 2014-12-16 14:51:00.000000000 +0100
+++ /work/SRC/openSUSE:Factory/.libkolab.new/libkolab.changes 2015-04-06 00:24:11.000000000 +0200
@@ -1,0 +2,27 @@
+Thu Apr 2 08:29:12 UTC 2015 - aj@ajaissle.de
+
+- Add upstream patch:
+ + libkolab-0.6.0_check_for_generic_tag.patch
+ Make libkolab compile with upstream kdepimlibs where GENERIC
+ tags are not yet included.
+
+-------------------------------------------------------------------
+Wed Apr 1 17:24:27 UTC 2015 - aj@ajaissle.de
+
+- New upstream release 0.6.0
+- Added upstream patches:
+ + 0001-Add-support-for-exceptions.patch
+ Add support to read/write exceptions to iCal
+ + 0002-Support-for-THISANDFUTURE.patch
+ Add support to convert ThisAndFuture from and to iCal
+ + 0003-Move-QT_DECLARE_METADATA-logic-to-cmake.patch
+ Fix double declaration of KCalCore::Duration when building with
+ libcalendaring >= 4.9.1
+- Add %bcond_with tests to enable %check section when required
+
+-------------------------------------------------------------------
+Sat Mar 28 12:53:59 UTC 2015 - aj@ajaissle.de
+
+- Convert %with_kde to %bcond_without kde
+
+-------------------------------------------------------------------
Old:
----
libkolab-0.5.3.tar.gz
New:
----
0001-Add-support-for-exceptions.patch
0002-Support-for-THISANDFUTURE.patch
0003-Move-QT_DECLARE_METADATA-logic-to-cmake.patch
libkolab-0.6.0.tar.gz
libkolab-0.6.0_check_for_generic_tag.patch
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ libkolab.spec ++++++
--- /var/tmp/diff_new_pack.ZG1wNs/_old 2015-04-06 00:24:11.000000000 +0200
+++ /var/tmp/diff_new_pack.ZG1wNs/_new 2015-04-06 00:24:11.000000000 +0200
@@ -1,7 +1,7 @@
#
# spec file for package libkolab
#
-# Copyright (c) 2014 SUSE LINUX Products GmbH, Nuernberg, Germany.
+# Copyright (c) 2015 SUSE LINUX GmbH, Nuernberg, Germany.
#
# All modifications and additions to the file contributed by third parties
# remain the property of their copyright owners, unless otherwise agreed
@@ -15,32 +15,42 @@
# Please submit bugfixes or comments via http://bugs.opensuse.org/
#
-%define with_kde 1
+
%if 0%{?suse_version} < 1230 || 0%{?suse_version} == 1315
-%define with_kde 0
+%define _without_kde 1
%endif
+%bcond_without kde
+%bcond_with tests
%define php_extdir %{_libdir}/php5/extensions
%define php_confdir %{_sysconfdir}/php5/conf.d
%define libname %{name}0
Name: libkolab
-Version: 0.5.3
+Version: 0.6.0
Release: 0
Summary: Conversions from/to KDE containers
License: LGPL-2.0+ and LGPL-3.0+ and AGPL-3.0+
Group: Development/Libraries/C and C++
Url: https://kolab.org/about/libkolab
Source: http://mirror.kolabsys.com/pub/releases/%{name}-%{version}.tar.gz
+# PATCH-FIX-UPSTREAM 0001-Add-support-for-exceptions.patch
+Patch0001: 0001-Add-support-for-exceptions.patch
+# PATCH-FIX-UPSTREAM 0002-Support-for-THISANDFUTURE.patch
+Patch0002: 0002-Support-for-THISANDFUTURE.patch
+# PATCH-FIX-UPSTREAM 0003-Move-QT_DECLARE_METADATA-logic-to-cmake.patch
+Patch0003: 0003-Move-QT_DECLARE_METADATA-logic-to-cmake.patch
+# PATCH-FIX-UPSTREAM libkolab-0.6.0_check_for_generic_tag.patch
+Patch0100: libkolab-0.6.0_check_for_generic_tag.patch
BuildRequires: boost-devel
BuildRequires: cmake >= 2.6
-BuildRequires: libxerces-c-devel
BuildRequires: libkolabxml-devel >= 1.0
BuildRequires: libqt4-devel
+BuildRequires: libxerces-c-devel
BuildRequires: php-devel >= 5.3
BuildRequires: python-devel
BuildRequires: swig >= 2.0
BuildRoot: %{_tmppath}/%{name}-%{version}-build
-%if 0%{?with_kde}
+%if %{with kde}
BuildRequires: libkdepimlibs4-devel >= 4.9
%else
BuildRequires: libcalendaring-devel
@@ -90,7 +100,7 @@
Group: Development/Libraries/C and C++
Requires: %{libname} = %{version}
Requires: libXerces-c-devel
-%if 0%{?with_kde}
+%if %{with kde}
Requires: libkdepimlibs4-devel >= 4.9
%else
Requires: libcalendaring-devel
@@ -104,6 +114,10 @@
%prep
%setup -q
+%patch0001 -p1
+%patch0002 -p1
+%patch0003 -p1
+%patch0100 -p1
# Lower cmake requirements for SLE 11
%if 0%{?suse_version} < 1140
@@ -121,14 +135,18 @@
# TESTS: require X and most fail anyway
%cmake \
-DLibkolabxml_DIR=%{_libdir}/cmake/Libkolabxml \
-%if 0%{?with_kde}
+%if %{with kde}
-DUSE_LIBCALENDARING=FALSE \
%else
-DUSE_LIBCALENDARING=TRUE \
%endif
-DPHP_BINDINGS=TRUE -DPHP_INSTALL_DIR=%{php_extdir} \
-DPYTHON_BINDINGS=TRUE -DPYTHON_INSTALL_DIR=%{python_sitearch} \
+%if %{with tests}
+ -DBUILD_TESTS=TRUE \
+%else
-DBUILD_TESTS=FALSE \
+%endif
%if 0%{?suse_version} < 1310
-DCMAKE_INSTALL_PREFIX="%{_prefix}" \
-DLIB_INSTALL_DIR=%{_lib} \
@@ -141,16 +159,16 @@
# cmake: with earlier releases, we have to change dir manually, as %%cmake_install is not available
%if 0%{?suse_version} < 1310
cd build/
-%{__make} DESTDIR=%{buildroot} install
+make DESTDIR=%{buildroot} install
%else
%cmake_install
%endif
-mkdir -p %{buildroot}/%{_datadir}/php5
-mv %{buildroot}/%{php_extdir}/*.php %{buildroot}/%{_datadir}/php5/.
+mkdir -p %{buildroot}%{_datadir}/php5
+mv %{buildroot}%{php_extdir}/*.php %{buildroot}%{_datadir}/php5/.
-mkdir -p %{buildroot}/%{php_confdir}
-cat >%{buildroot}/%{php_confdir}/kolab.ini <%{buildroot}%{php_confdir}/kolab.ini <%{buildroot}%{php_confdir}/kolabdummy.ini <
From ad9c52c79a3b5de87bfa7a3f45e207e6d6ee1d4b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Sandro=20Knau=C3=9F?=
Date: Wed, 18 Feb 2015 16:54:47 +0100
Subject: [PATCH 1/2] Add support for exceptions.
Read/Write Exceptions to iCal.
KOLAB: #4618
---
icalendar/icalendar.cpp | 34 +++++++++++++++--
tests/icalendartest.cpp | 53 ++++++++++++++++++++++++++-
tests/icalendartest.h | 3 ++
tests/testfiles/v3/event/errorswithsameid.ics | 45 +++++++++++++++++++++++
tests/testfiles/v3/event/exceptions.ics | 35 ++++++++++++++++++
5 files changed, 166 insertions(+), 4 deletions(-)
create mode 100644 tests/testfiles/v3/event/errorswithsameid.ics
create mode 100644 tests/testfiles/v3/event/exceptions.ics
diff --git a/icalendar/icalendar.cpp b/icalendar/icalendar.cpp
index be7c0e6..3ed41ae 100644
--- a/icalendar/icalendar.cpp
+++ b/icalendar/icalendar.cpp
@@ -39,13 +39,21 @@ std::string toICal(const std::vector<Event> &events)
KCalCore::Calendar::Ptr calendar(new KCalCore::MemoryCalendar(Kolab::Conversion::getTimeSpec(true, std::string())));
foreach (const Event &event, events) {
KCalCore::Event::Ptr kcalEvent = Conversion::toKCalCore(event);
- kcalEvent->setCreated(KDateTime::currentUtcDateTime()); //sets dtstamp
+ if (!kcalEvent->created().isValid()) {
+ kcalEvent->setCreated(KDateTime::currentUtcDateTime()); //sets dtstamp
+ }
calendar->addEvent(kcalEvent);
+ foreach(const Event &exception, event.exceptions()) {
+ KCalCore::Event::Ptr kcalException = Conversion::toKCalCore(exception);
+ if (!kcalException->created().isValid()) {
+ kcalException->setCreated(KDateTime::currentUtcDateTime()); //sets dtstamp
+ }
+ calendar->addEvent(kcalException);
+ }
}
KCalCore::ICalFormat format;
format.setApplication("libkolab", LIBKOLAB_LIB_VERSION_STRING);
// qDebug() << format.createScheduleMessage(calendar->events().first(), KCalCore::iTIPRequest);
-
return Conversion::toStdString(format.toString(calendar));
}
@@ -57,8 +65,28 @@ std::vector< Event > fromICalEvents(const std::string &input)
format.setApplication("libkolab", LIBKOLAB_LIB_VERSION_STRING);
format.fromString(calendar, Conversion::fromStdString(input));
std::vector<Event> events;
+ QMap< QString, int > uidMap;
foreach (const KCalCore::Event::Ptr &event, calendar->events()) {
- events.push_back(Conversion::fromKCalCore(*event));
+ Event e = Conversion::fromKCalCore(*event);
+ if (!e.recurrenceID().isValid()) {
+ if (uidMap.contains(event->uid())) {
+ e.setExceptions(events.at(uidMap[event->uid()]).exceptions());
+ events[uidMap[event->uid()]] = e;
+ } else {
+ events.push_back(e);
+ uidMap.insert(event->uid(), events.size()-1);
+ }
+ } else {
+ if (!uidMap.contains(event->uid())) {
+ Event e;
+ e.setUid("");
+ events.push_back(e);
+ uidMap.insert(event->uid(), events.size()-1);
+ }
+ std::vector<Event> exceptions = events.at( uidMap[event->uid()]).exceptions();
+ exceptions.push_back(e);
+ events.at(uidMap[event->uid()]).setExceptions(exceptions);
+ }
}
return events;
}
diff --git a/tests/icalendartest.cpp b/tests/icalendartest.cpp
index 1e13d65..b1dd60b 100644
--- a/tests/icalendartest.cpp
+++ b/tests/icalendartest.cpp
@@ -24,6 +24,8 @@
#include "icalendar/icalendar.h"
#include "testhelpers.h"
+#include "testutils.h"
+#include
void ICalendarTest::testFromICalEvent()
{
@@ -32,11 +34,60 @@ void ICalendarTest::testFromICalEvent()
ev1.setStart(Kolab::cDateTime(2011,10,10,12,1,1,true));
ev1.setEnd(Kolab::cDateTime(2011,10,11,12,1,1,true));
events.push_back(ev1);
- events.push_back(ev1);
const std::vectorKolab::Event &result = Kolab::fromICalEvents(Kolab::toICal(events));
qDebug() << QString::fromStdString(Kolab::toICal(result));
}
+void ICalendarTest::testFromICalEventWithExceptions()
+{
+ QFile icalFile( getPath("v3/event/exceptions.ics") );
+ QVERIFY( icalFile.open( QFile::ReadOnly ) );
+ std::vectorKolab::Event events = Kolab::fromICalEvents(icalFile.readAll().constData());
+ QCOMPARE((int)events.size(), 1);
+ Kolab::Event out = events.at(0);
+ QCOMPARE((int)out.exceptions().size(), 2);
+}
+
+void ICalendarTest::testFromICalEventErrorsWithSameID()
+{
+ /* This is not a really usecase, it should make sure,
+ * that the underlying KCalCore strips out events with same uid/or recurrenceID.
+ * 2015/02/18: KCaclCore is only returns one event with one exception for the icalFile
+ * testdata/v3/event/errorswithsameid.ics
+ */
+ QFile icalFile( getPath("v3/event/errorswithsameid.ics") );
+ QVERIFY( icalFile.open( QFile::ReadOnly ) );
+ std::vectorKolab::Event events = Kolab::fromICalEvents(icalFile.readAll().constData());
+ QCOMPARE((int)events.size(), 1);
+ Kolab::Event out = events.at(0);
+ QCOMPARE((int)out.exceptions().size(), 1);
+}
+
+void ICalendarTest::testReadWriteForEventWithExceptions()
+{
+ std::vectorKolab::Event events;
+ Kolab::Event ev1;
+ ev1.setUid("uid");
+ ev1.setStart(Kolab::cDateTime(2011,10,10,12,1,1,true));
+ ev1.setEnd(Kolab::cDateTime(2011,10,11,12,1,1,true));
+ std::vectorKolab::Event exceptions;
+ Kolab::Event ex1;
+ ex1.setUid(ev1.uid());
+ ex1.setRecurrenceID(Kolab::cDateTime(2011,10,11,12,1,1,true), false);
+ exceptions.push_back(ex1);
+ ev1.setExceptions(exceptions);
+ Kolab::RecurrenceRule rrule;
+ rrule.setInterval(1);
+ rrule.setFrequency(Kolab::RecurrenceRule::Daily);
+ ev1.setRecurrenceRule(rrule);
+ events.push_back(ev1);
+ const std::vectorKolab::Event &result = Kolab::fromICalEvents(Kolab::toICal(events));
+ Kolab::Event out = result.at(0);
+ QCOMPARE((int)result.size(), 1);
+ QCOMPARE((int)out.exceptions().size(), 1);
+ QCOMPARE(out.exceptions().at(0).recurrenceID(), ex1.recurrenceID());
+}
+
void ICalendarTest::testToICal()
{
std::vectorKolab::Event events;
diff --git a/tests/icalendartest.h b/tests/icalendartest.h
index 4f82ecc..7e1f405 100644
--- a/tests/icalendartest.h
+++ b/tests/icalendartest.h
@@ -27,6 +27,9 @@ private slots:
// void testEventConflict_data();
void testToICal();
void testFromICalEvent();
+ void testFromICalEventWithExceptions();
+ void testReadWriteForEventWithExceptions();
+ void testFromICalEventErrorsWithSameID();
void testToITip();
void testToIMip();
diff --git a/tests/testfiles/v3/event/errorswithsameid.ics b/tests/testfiles/v3/event/errorswithsameid.ics
new file mode 100644
index 0000000..1aa12a3
--- /dev/null
+++ b/tests/testfiles/v3/event/errorswithsameid.ics
@@ -0,0 +1,45 @@
+BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//Test//
+CALSCALE:GREGORIAN
+BEGIN:VEVENT
+UID:D5A98F4AD36FE911EC7FB8F89209C4E3-FCBB6C4091F28CA0
+DTSTAMP;VALUE=DATE-TIME:20150216T000000Z
+CREATED;VALUE=DATE-TIME:20150216T000000Z
+LAST-MODIFIED;VALUE=DATE-TIME:20150216T000000Z
+RRULE:FREQ=DAILY;INTERVAL=1
+SUMMARY:Daily
+DTSTART;VALUE=DATE-TIME:20150101T010000Z
+DTEND;VALUE=DATE-TIME:20150101T020000Z
+END:VEVENT
+BEGIN:VEVENT
+UID:D5A98F4AD36FE911EC7FB8F89209C4E3-FCBB6C4091F28CA0
+DTSTAMP;VALUE=DATE-TIME:20150216T000000Z
+CREATED;VALUE=DATE-TIME:20150216T000000Z
+LAST-MODIFIED;VALUE=DATE-TIME:20150216T000000Z
+RECURRENCE-ID;VALUE=DATE-TIME;RANGE=THISANDFUTURE:20150103T000000Z
+SUMMARY:thisandfuture
+DTSTART;VALUE=DATE-TIME:20150103T020000Z
+DTEND;VALUE=DATE-TIME:20150103T030000Z
+END:VEVENT
+BEGIN:VEVENT
+UID:D5A98F4AD36FE911EC7FB8F89209C4E3-FCBB6C4091F28CA0
+DTSTAMP;VALUE=DATE-TIME:20150216T000000Z
+CREATED;VALUE=DATE-TIME:20150216T000000Z
+LAST-MODIFIED;VALUE=DATE-TIME:20150216T000000Z
+RRULE:FREQ=DAILY;INTERVAL=1
+SUMMARY:Invalid second incidence
+DTSTART;VALUE=DATE-TIME:20150101T050000Z
+DTEND;VALUE=DATE-TIME:20150101T060000Z
+END:VEVENT
+BEGIN:VEVENT
+UID:D5A98F4AD36FE911EC7FB8F89209C4E3-FCBB6C4091F28CA0
+DTSTAMP;VALUE=DATE-TIME:20150216T000000Z
+CREATED;VALUE=DATE-TIME:20150216T000000Z
+LAST-MODIFIED;VALUE=DATE-TIME:20150216T000000Z
+RECURRENCE-ID;VALUE=DATE-TIME:20150103T000000Z
+SUMMARY: same recurence id like the one with THISANDFUTURE
+DTSTART;VALUE=DATE-TIME:20150103T030000Z
+DTEND;VALUE=DATE-TIME:20150103T040000Z
+END:VEVENT
+END:VCALENDAR
\ No newline at end of file
diff --git a/tests/testfiles/v3/event/exceptions.ics b/tests/testfiles/v3/event/exceptions.ics
new file mode 100644
index 0000000..60776c6
--- /dev/null
+++ b/tests/testfiles/v3/event/exceptions.ics
@@ -0,0 +1,35 @@
+BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//Test//
+CALSCALE:GREGORIAN
+BEGIN:VEVENT
+UID:D5A98F4AD36FE911EC7FB8F89209C4E3-FCBB6C4091F28CA0
+DTSTAMP;VALUE=DATE-TIME:20150216T000000Z
+CREATED;VALUE=DATE-TIME:20150216T000000Z
+LAST-MODIFIED;VALUE=DATE-TIME:20150216T000000Z
+RRULE:FREQ=DAILY;INTERVAL=1
+SUMMARY:Daily
+DTSTART;VALUE=DATE-TIME:20150101T010000Z
+DTEND;VALUE=DATE-TIME:20150101T020000Z
+END:VEVENT
+BEGIN:VEVENT
+UID:D5A98F4AD36FE911EC7FB8F89209C4E3-FCBB6C4091F28CA0
+DTSTAMP;VALUE=DATE-TIME:20150216T000000Z
+CREATED;VALUE=DATE-TIME:20150216T000000Z
+LAST-MODIFIED;VALUE=DATE-TIME:20150216T000000Z
+RECURRENCE-ID;VALUE=DATE-TIME;RANGE=THISANDFUTURE:20150103T000000Z
+SUMMARY:thisandfuture
+DTSTART;VALUE=DATE-TIME:20150103T020000Z
+DTEND;VALUE=DATE-TIME:20150103T030000Z
+END:VEVENT
+BEGIN:VEVENT
+UID:D5A98F4AD36FE911EC7FB8F89209C4E3-FCBB6C4091F28CA0
+DTSTAMP;VALUE=DATE-TIME:20150216T000000Z
+CREATED;VALUE=DATE-TIME:20150216T000000Z
+LAST-MODIFIED;VALUE=DATE-TIME:20150216T000000Z
+RECURRENCE-ID;VALUE=DATE-TIME:20150104T000000Z
+SUMMARY: exception
+DTSTART;VALUE=DATE-TIME:20150104T030000Z
+DTEND;VALUE=DATE-TIME:20150104T040000Z
+END:VEVENT
+END:VCALENDAR
\ No newline at end of file
--
2.1.0
++++++ 0002-Support-for-THISANDFUTURE.patch ++++++
From b756fa4ceef4b953859878f3c700ed45ecaed409 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Sandro=20Knau=C3=9F?=
Date: Wed, 18 Feb 2015 16:50:59 +0100
Subject: [PATCH 2/2] Support for THISANDFUTURE
convert ThisAndFuture from/to iCal.
KOLAB: 4654
---
conversion/kcalconversion.cpp | 7 ++++---
tests/icalendartest.cpp | 3 ++-
tests/kcalconversiontest.cpp | 20 ++++++++++++++++++--
3 files changed, 24 insertions(+), 6 deletions(-)
diff --git a/conversion/kcalconversion.cpp b/conversion/kcalconversion.cpp
index a82b6a2..b06a5d0 100644
--- a/conversion/kcalconversion.cpp
+++ b/conversion/kcalconversion.cpp
@@ -661,7 +661,8 @@ void setTodoEvent(KCalCore::Incidence &i, const T &e)
i.setNonKDECustomProperty(CUSTOM_KOLAB_URL, fromStdString(e.url()));
}
if (e.recurrenceID().isValid()) {
- i.setRecurrenceId(toDate(e.recurrenceID())); //TODO THISANDFUTURE
+ i.setRecurrenceId(toDate(e.recurrenceID()));
+ i.setThisAndFuture(e.thisAndFuture());
}
setRecurrence(i, e);
foreach (const Kolab::Alarm a, e.alarms()) {
@@ -699,7 +700,7 @@ void setTodoEvent(KCalCore::Incidence &i, const T &e)
alarm->setSnoozeTime(toDuration(a.duration()));
alarm->setRepeatCount(a.numrepeat());
alarm->setEnabled(true);
- i.addAlarm(alarm);
+ i.addAlarm(alarm);
}
}
@@ -712,7 +713,7 @@ void getTodoEvent(T &i, const I &e)
i.setOrganizer(Kolab::ContactReference(Kolab::ContactReference::EmailReference, toStdString(e.organizer()->email()), toStdString(e.organizer()->name()))); //TODO handle uid too
}
i.setUrl(toStdString(e.nonKDECustomProperty(CUSTOM_KOLAB_URL)));
- i.setRecurrenceID(fromDate(e.recurrenceId()), false); //TODO THISANDFUTURE
+ i.setRecurrenceID(fromDate(e.recurrenceId()), e.thisAndFuture());
getRecurrence(i, e);
std::vector Kolab::Alarm alarms;
foreach (const KCalCore::Alarm::Ptr &a, e.alarms()) {
diff --git a/tests/icalendartest.cpp b/tests/icalendartest.cpp
index b1dd60b..bf55031 100644
--- a/tests/icalendartest.cpp
+++ b/tests/icalendartest.cpp
@@ -73,7 +73,7 @@ void ICalendarTest::testReadWriteForEventWithExceptions()
std::vectorKolab::Event exceptions;
Kolab::Event ex1;
ex1.setUid(ev1.uid());
- ex1.setRecurrenceID(Kolab::cDateTime(2011,10,11,12,1,1,true), false);
+ ex1.setRecurrenceID(Kolab::cDateTime(2011,10,11,12,1,1,true), true);
exceptions.push_back(ex1);
ev1.setExceptions(exceptions);
Kolab::RecurrenceRule rrule;
@@ -86,6 +86,7 @@ void ICalendarTest::testReadWriteForEventWithExceptions()
QCOMPARE((int)result.size(), 1);
QCOMPARE((int)out.exceptions().size(), 1);
QCOMPARE(out.exceptions().at(0).recurrenceID(), ex1.recurrenceID());
+ QCOMPARE(out.exceptions().at(0).thisAndFuture(), true);
}
void ICalendarTest::testToICal()
diff --git a/tests/kcalconversiontest.cpp b/tests/kcalconversiontest.cpp
index c62a8e0..e1d4ca9 100644
--- a/tests/kcalconversiontest.cpp
+++ b/tests/kcalconversiontest.cpp
@@ -162,7 +162,7 @@ void KCalConversionTest::testConversion_data()
kcal.setDtEnd(toDate(date2));
kcal.setTransparency(KCalCore::Event::Transparent);
- kcal.setRecurrenceId(toDate(date2)); //TODO THISANDFUTURE
+ kcal.setRecurrenceId(toDate(date2));
kcal.recurrence()->setDaily(3);
kcal.recurrence()->setDuration(5);
kcal.recurrence()->addRDateTime(toDate(date2));
@@ -231,7 +231,7 @@ void KCalConversionTest::testConversion_data()
rrule.setBymonth(intVector);
kolab.setRecurrenceRule(rrule);
- kolab.setRecurrenceID(date2, true);
+ kolab.setRecurrenceID(date2, false);
kolab.setRecurrenceDates(std::vectorKolab::cDateTime() << date2 << Kolab::cDateTime(date2.year(), date2.month(), date2.day()));
kolab.setExceptionDates(std::vectorKolab::cDateTime() << date3 << Kolab::cDateTime(date3.year(), date3.month(), date3.day()));
@@ -337,7 +337,21 @@ void KCalConversionTest::testConversion_data()
kolab.setSummary(std::string(QString("äöü%@$£é¤¼²°€Š�").toUtf8().constData()));
QTest::newRow("latin1+Unicode") << kcal << kolab;
+ }
+ {
+ KCalCore::Event kcal;
+ kcal.setUid("uid");
+ kcal.setCreated(toDate(date));
+ kcal.setLastModified(toDate(date));
+ kcal.setRecurrenceId(toDate(date));
+ kcal.setThisAndFuture(true);
+ Kolab::Event kolab;
+ kolab.setUid("uid");
+ kolab.setCreated(date);
+ kolab.setLastModified(date);
+ kolab.setRecurrenceID(date, true);
+ QTest::newRow("thisandfuture") << kcal << kolab;
}
}
@@ -361,6 +375,7 @@ void KCalConversionTest::testConversion()
QCOMPARE(e->transparency(), kcal.transparency());
QCOMPARE(*e->recurrence(), *kcal.recurrence());
QCOMPARE(e->recurrenceId(), kcal.recurrenceId());
+ QCOMPARE(e->thisAndFuture(), kcal.thisAndFuture());
QCOMPARE(e->recurrenceType(), kcal.recurrenceType());
QCOMPARE(e->summary(), kcal.summary());
QCOMPARE(e->description(), kcal.description());
@@ -396,6 +411,7 @@ void KCalConversionTest::testConversion()
QCOMPARE(b.recurrenceRule(), kolab.recurrenceRule());
QCOMPARE(b.recurrenceID(), kolab.recurrenceID());
+ QCOMPARE(b.thisAndFuture(), kolab.thisAndFuture());
QCOMPARE(b.recurrenceDates(), kolab.recurrenceDates());
QCOMPARE(b.exceptionDates(), kolab.exceptionDates());
--
2.1.0
++++++ 0003-Move-QT_DECLARE_METADATA-logic-to-cmake.patch ++++++
From e397921e73de2926a8572dfed73d2730a3ae456e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Sandro=20Knau=C3=9F?=
Date: Thu, 19 Feb 2015 12:32:58 +0100
Subject: [PATCH 3/3] Move QT_DECLARE_METADATA logic to cmake
Because libcalendaring now also have versions that
Q_DECLARE_METATYPE(KCalCore::Duration) already we make it explicit once
within cmake and once inside libcalendaring.
---
CMakeLists.txt | 4 ++++
tests/testhelpers.h | 8 ++------
2 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/CMakeLists.txt b/CMakeLists.txt
index a323b32..02783e2 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -82,6 +82,10 @@ if("${KdepimLibs_VERSION}" VERSION_GREATER "4.8.40" OR USE_LIBCALENDARING)
add_definitions(-DKDEPIMLIBS_VERSION_DEVEL)
endif()
+if ("${KdepimLibs_VERSION}" VERSION_GREATER "4.11.52")
+ add_definitions( -DLIBCALENDARING_DURATION_DECLARED)
+endif()
+
set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wnon-virtual-dtor -Wno-long-long -ansi -Wundef -Wcast-align -Wchar-subscripts -Wall -W -Wpointer-arith -Wformat-security -fno-exceptions -DQT_NO_EXCEPTIONS -fno-common -Woverloaded-virtual -fno-threadsafe-statics -fvisibility=hidden -Werror=return-type -fvisibility-inlines-hidden -fexceptions -UQT_NO_EXCEPTIONS -fPIC -g" )
# message("${CMAKE_CXX_FLAGS}")
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -DQT_NO_DEBUG")
diff --git a/tests/testhelpers.h b/tests/testhelpers.h
index f0e3889..822f9bc 100644
--- a/tests/testhelpers.h
+++ b/tests/testhelpers.h
@@ -45,12 +45,8 @@ Q_DECLARE_METATYPE(KCalCore::Event);
Q_DECLARE_METATYPE(KCalCore::Todo);
Q_DECLARE_METATYPE(KCalCore::Journal);
-#if KDEPIMLIBS_VERSION_MAJOR <= 4
-#if KDEPIMLIBS_VERSION_MINOR <= 11
-#if KDEPIMLIBS_VERSION_PATCH < 52
-Q_DECLARE_METATYPE(KCalCore::Duration);
-#endif
-#endif
+#ifndef LIBCALENDARING_DURATION_DECLARED
+ Q_DECLARE_METATYPE(KCalCore::Duration);
#endif
namespace QTest {
--
2.1.0
++++++ libkolab-0.5.3.tar.gz -> libkolab-0.6.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libkolab-0.5.3/CMakeLists.txt new/libkolab-0.6.0/CMakeLists.txt
--- old/libkolab-0.5.3/CMakeLists.txt 2014-08-26 13:39:06.000000000 +0200
+++ new/libkolab-0.6.0/CMakeLists.txt 2015-02-01 18:23:05.000000000 +0100
@@ -31,9 +31,9 @@
# 0.1.1 (patch release for 0.1.0)
# 0.2 (0.2 development version towards 0.2.0)
set(Libkolab_VERSION_MAJOR 0)
-set(Libkolab_VERSION_MINOR 5)
+set(Libkolab_VERSION_MINOR 6)
# Enable the full x.y.z version only for release versions
-set(Libkolab_VERSION_PATCH 3)
+set(Libkolab_VERSION_PATCH 0)
set(Libkolab_VERSION ${Libkolab_VERSION_MAJOR}.${Libkolab_VERSION_MINOR}.${Libkolab_VERSION_PATCH} )
#set(Libkolab_VERSION ${Libkolab_VERSION_MAJOR}.${Libkolab_VERSION_MINOR} )
set(Libkolab_VERSION_STRING ${CMAKE_PROJECT_NAME}-${Libkolab_VERSION})
@@ -55,7 +55,7 @@
include(MacroLogFeature)
# Do the building
-find_package(Libkolabxml 1.0 REQUIRED)
+find_package(Libkolabxml 1.1 REQUIRED)
macro_log_feature(Libkolabxml_FOUND "Libkolabxml" "Kolab XML Format 3 serializing library" "http://git.kolab.org/libkolabxml/" TRUE "1.0" "Required for reading/writing Kolab XML Objects")
find_package(Qt4 4.6.0 REQUIRED)
@@ -91,7 +91,7 @@
set( KDE_LIBRARIES ${Libcalendaring_LIBRARIES} )
message("${Libcalendaring_INCLUDE_DIRS} ${Libcalendaring_LIBRARIES}")
else()
- set( KDE_INCLUDES ${KDEPIMLIBS_INCLUDE_DIRS} ${KDE4_INCLUDE_DIR})
+ set( KDE_INCLUDES ${KDEPIMLIBS_INCLUDE_DIRS} ${KDE4_INCLUDES} )
set( KDE_LIBRARIES
${KDEPIMLIBS_KCALCORE_LIBS}
${KDEPIMLIBS_KABC_LIBS}
@@ -119,6 +119,17 @@
configure_file(libkolab-version.h.cmake "${CMAKE_BINARY_DIR}/libkolab-version.h" @ONLY)
+set(CMAKE_REQUIRED_FLAGS ${CMAKE_CXX_FLAGS})
+set(CMAKE_REQUIRED_INCLUDES "/opt/devel/kolab/include/")
+# include(CheckIncludeFileCXX)
+# check_include_file_cxx(akonadi/tag.h HAVE_TAG_H)
+#check_include_file_cxx doesn't work for some reason, so we use find_path instead.
+#we have to make sure that we only search in KDE_INCLUDES though, to not accidentally include a system akonadi/tag.h
+#when we're searching for one in libcalendaring.
+find_path(HAVE_TAG_H akonadi/tag.h PATHS ${KDE_INCLUDES} NO_DEFAULT_PATH NO_SYSTEM_ENVIRONMENT_PATH NO_CMAKE_PATH NO_CMAKE_ENVIRONMENT_PATH)
+find_path(HAVE_RELATION_H akonadi/relation.h PATHS ${KDE_INCLUDES} NO_DEFAULT_PATH NO_SYSTEM_ENVIRONMENT_PATH NO_CMAKE_PATH NO_CMAKE_ENVIRONMENT_PATH)
+configure_file(${CMAKE_CURRENT_SOURCE_DIR}/libkolab_config.h.in ${CMAKE_CURRENT_BINARY_DIR}/libkolab_config.h)
+
add_subdirectory(kolabformatV2)
add_subdirectory(conversion)
add_subdirectory(calendaring)
@@ -180,6 +191,7 @@
kolabformat/errorhandler.h
kolabformat/xmlobject.h
kolabformat/mimeobject.h
+ ${CMAKE_CURRENT_BINARY_DIR}/libkolab_config.h
conversion/kcalconversion.h
conversion/kabcconversion.h
conversion/commonconversion.h
@@ -209,5 +221,6 @@
if(PHP_BINDINGS)
generatePHPBindings(kolabshared shared.i)
+ generatePHPBindings(dummy dummy.i)
add_subdirectory(kolabformat/php)
endif(PHP_BINDINGS)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libkolab-0.5.3/calendaring/php/test.php new/libkolab-0.6.0/calendaring/php/test.php
--- old/libkolab-0.5.3/calendaring/php/test.php 2014-08-26 13:39:06.000000000 +0200
+++ new/libkolab-0.6.0/calendaring/php/test.php 2015-02-01 18:23:05.000000000 +0100
@@ -97,6 +97,79 @@
</icalendar>
EOF;
+$rdates = <<getNextOccurence($rstart));
+assertequal(
+ sprintf("%d-%02d-%02d %02d:%02d:%02d", $next->year(), $next->month(), $next->day(), $next->hour(), $next->minute(), $next->second()),
+ "2012-03-30 04:00:00",
+ "RDATE first recurrence"
+);
+
+$next = new cDateTime($ec->getNextOccurence($next));
+assertequal(
+ sprintf("%d-%02d-%02d %02d:%02d:%02d", $next->year(), $next->month(), $next->day(), $next->hour(), $next->minute(), $next->second()),
+ "2013-03-30 04:00:00",
+ "RDATE next recurrence"
+);
+
+$last = new cDateTime($ec->getLastOccurrence());
+assertequal(
+ sprintf("%d-%02d-%d %02d:%02d:%02d", $last->year(), $last->month(), $last->day(), $last->hour(), $last->minute(), $last->second()),
+ "2021-03-30 04:00:00",
+ "RDATE last occurence"
+);
+
// terminate with error status
exit($errors);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libkolab-0.5.3/conversion/timezoneconverter.cpp new/libkolab-0.6.0/conversion/timezoneconverter.cpp
--- old/libkolab-0.5.3/conversion/timezoneconverter.cpp 2014-08-26 13:39:06.000000000 +0200
+++ new/libkolab-0.6.0/conversion/timezoneconverter.cpp 2015-02-01 18:23:05.000000000 +0100
@@ -39,13 +39,15 @@
if (guessedTimezone.isEmpty()) {
guessedTimezone = fromGMTOffsetTimezone(tz);
}
- if (guessedTimezone.isEmpty()) {
- //slower but also finds outdated zones
- timezone = KSystemTimeZones::readZone(tz);
- if (timezone.isValid()) {
- return tz;
- }
- }
+// if (guessedTimezone.isEmpty()) {
+// //slower but also finds outdated zones
+// timezone = KSystemTimeZones::readZone(tz);
+// if (timezone.isValid()) {
+// //This thinks all kinds of shit is valid, including /etc/localtime. Let's verify again.
+// qDebug() << "found " << tz;
+// return tz;
+// }
+// }
Debug() << "Guessed timezone and found: " << guessedTimezone;
return guessedTimezone;
}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libkolab-0.5.3/dummy.i new/libkolab-0.6.0/dummy.i
--- old/libkolab-0.5.3/dummy.i 1970-01-01 01:00:00.000000000 +0100
+++ new/libkolab-0.6.0/dummy.i 2015-02-01 18:23:05.000000000 +0100
@@ -0,0 +1 @@
+/* This is a dummy plugin that does nothing. See https://issues.kolab.org/show_bug.cgi?id=2050 */
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libkolab-0.5.3/kolabformat/kolabdefinitions.h new/libkolab-0.6.0/kolabformat/kolabdefinitions.h
--- old/libkolab-0.5.3/kolabformat/kolabdefinitions.h 2014-08-26 13:39:06.000000000 +0200
+++ new/libkolab-0.6.0/kolabformat/kolabdefinitions.h 2015-02-01 18:23:05.000000000 +0100
@@ -63,6 +63,7 @@
#define KOLAB_TYPE_DICT "application/x-vnd.kolab.configuration.dictionary"
#define KOLAB_TYPE_FREEBUSY "application/x-vnd.kolab.freebusy"
#define KOLAB_TYPE_FILE "application/x-vnd.kolab.file"
+#define KOLAB_TYPE_RELATION "application/x-vnd.kolab.configuration.relation"
enum Version {
KolabV2,
@@ -78,7 +79,8 @@
DistlistObject,
NoteObject,
DictionaryConfigurationObject,
- FreebusyObject
+ FreebusyObject,
+ RelationConfigurationObject
};
}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libkolab-0.5.3/kolabformat/kolabobject.cpp new/libkolab-0.6.0/kolabformat/kolabobject.cpp
--- old/libkolab-0.5.3/kolabformat/kolabobject.cpp 2014-08-26 13:39:06.000000000 +0200
+++ new/libkolab-0.6.0/kolabformat/kolabobject.cpp 2015-02-01 18:23:05.000000000 +0100
@@ -51,6 +51,7 @@
static inline QString configurationKolabType() { return QString::fromLatin1(KOLAB_TYPE_CONFIGURATION); }
static inline QString dictKolabType() { return QString::fromLatin1(KOLAB_TYPE_DICT); }
static inline QString freebusyKolabType() { return QString::fromLatin1(KOLAB_TYPE_FREEBUSY); }
+static inline QString relationKolabType() { return QString::fromLatin1(KOLAB_TYPE_RELATION); }
static inline QString xCalMimeType() { return QString::fromLatin1(MIME_TYPE_XCAL); };
static inline QString xCardMimeType() { return QString::fromLatin1(MIME_TYPE_XCARD); };
@@ -61,6 +62,92 @@
return fromXML(xmlData, attachments);
}
+QString ownUrlDecode(QByteArray encodedParam)
+{
+ encodedParam.replace('+', ' ');
+ return QUrl::fromPercentEncoding(encodedParam);
+}
+
+RelationMember parseMemberUrl(const QString &string)
+{
+ if (string.startsWith("urn:uuid:")) {
+ RelationMember member;
+ member.gid = string.mid(9);
+ return member;
+ }
+ QUrl url(QUrl::fromEncoded(string.toLatin1()));
+ QList<QByteArray> path;
+ Q_FOREACH(const QByteArray &fragment, url.encodedPath().split('/')) {
+ path.append(ownUrlDecode(fragment).toUtf8());
+ }
+ // qDebug() << path;
+ bool isShared = false;
+ int start = path.indexOf("user");
+ if (start < 0) {
+ start = path.indexOf("shared");
+ isShared = true;
+ }
+ if (start < 0) {
+ Warning() << "Couldn't find \"user\" or \"shared\" in path: " << path;
+ return RelationMember();
+ }
+ path = path.mid(start + 1);
+ if (path.size() < 2) {
+ Warning() << "Incomplete path: " << path;
+ return RelationMember();
+ }
+ RelationMember member;
+ if (!isShared) {
+ member.user = path.takeFirst();
+ }
+ member.uid = path.takeLast().toLong();
+ member.mailbox = path;
+ member.messageId = ownUrlDecode(url.encodedQueryItemValue("message-id"));
+ member.subject = ownUrlDecode(url.encodedQueryItemValue("subject"));
+ member.date = ownUrlDecode(url.encodedQueryItemValue("date"));
+ // qDebug() << member.uid << member.mailbox;
+ return member;
+}
+
+static QByteArray join(const QList<QByteArray> &list, const QByteArray &c)
+{
+ QByteArray result;
+ Q_FOREACH (const QByteArray &a, list) {
+ result += a + c;
+ }
+ result.chop(c.size());
+ return result;
+}
+
+KOLAB_EXPORT QString generateMemberUrl(const RelationMember &member)
+{
+ if (!member.gid.isEmpty()) {
+ return QString("urn:uuid:%1").arg(member.gid);
+ }
+ QUrl url;
+ url.setScheme("imap");
+ QList<QByteArray> path;
+ path << "/";
+ if (!member.user.isEmpty()) {
+ path << "user";
+ path << QUrl::toPercentEncoding(member.user.toLatin1());
+ } else {
+ path << "shared";
+ }
+ Q_FOREACH(const QByteArray &mb, member.mailbox) {
+ path << QUrl::toPercentEncoding(mb);
+ }
+ path << QByteArray::number(member.uid);
+ url.setEncodedPath("/" + join(path, "/"));
+
+ QList > queryItems;
+ queryItems.append(qMakePair(QString::fromLatin1("message-id").toLatin1(), QUrl::toPercentEncoding(member.messageId)));
+ queryItems.append(qMakePair(QString::fromLatin1("subject").toLatin1(), QUrl::toPercentEncoding(member.subject)));
+ queryItems.append(qMakePair(QString::fromLatin1("date").toLatin1(), QUrl::toPercentEncoding(member.date)));
+ url.setEncodedQueryItems(queryItems);
+
+ return QString::fromLatin1(url.toEncoded());
+}
//@cond PRIVATE
class KolabObjectReader::Private
@@ -77,7 +164,7 @@
ObjectType readKolabV2(const KMime::Message::Ptr &msg, Kolab::ObjectType objectType);
ObjectType readKolabV3(const KMime::Message::Ptr &msg, Kolab::ObjectType objectType);
-
+
KCalCore::Incidence::Ptr mIncidence;
KABC::Addressee mAddressee;
KABC::ContactGroup mContactGroup;
@@ -90,6 +177,14 @@
ObjectType mOverrideObjectType;
Version mOverrideVersion;
bool mDoOverrideVersion;
+
+#ifdef HAVE_RELATION_H
+ Akonadi::Relation mRelation;
+#endif
+#ifdef HAVE_TAG_H
+ Akonadi::Tag mTag;
+ QStringList mTagMembers;
+#endif
};
//@endcond
@@ -101,7 +196,7 @@
KolabObjectReader::KolabObjectReader(const KMime::Message::Ptr& msg)
: d( new KolabObjectReader::Private )
{
- d->mObjectType = parseMimeMessage(msg);
+ parseMimeMessage(msg);
}
KolabObjectReader::~KolabObjectReader()
@@ -138,6 +233,8 @@
return FreebusyObject;
} else if (type.contains(dictKolabType())) { //Previous versions appended the language to the type
return DictionaryConfigurationObject;
+ } else if (type == relationKolabType()) {
+ return RelationConfigurationObject;
}
Warning() << "Unknown object type: " << type;
return Kolab::InvalidObject;
@@ -162,6 +259,8 @@
return KOLAB_TYPE_NOTE;
case DictionaryConfigurationObject:
return KOLAB_TYPE_CONFIGURATION;
+ case RelationConfigurationObject:
+ return KOLAB_TYPE_RELATION;
default:
Critical() << "unknown type "<< type;
}
@@ -181,6 +280,7 @@
return MIME_TYPE_XCARD;
case NoteObject:
case DictionaryConfigurationObject:
+ case RelationConfigurationObject:
return MIME_TYPE_KOLAB;
default:
Critical() << "unknown type "<< type;
@@ -326,6 +426,44 @@
mFreebusy = fb;
}
break;
+#ifdef HAVE_TAG_H
+ case RelationConfigurationObject: {
+ const Kolab::Configuration &configuration = Kolab::readConfiguration(xml, false);
+ const Kolab::Relation &relation = configuration.relation();
+
+ if (relation.type() == "tag") {
+ mTag = Akonadi::Tag();
+ mTag.setName(Conversion::fromStdString(relation.name()));
+ mTag.setGid(Conversion::fromStdString(configuration.uid()).toLatin1());
+ mTag.setType(Akonadi::Tag::GENERIC);
+
+ mTagMembers.reserve(relation.members().size());
+ foreach (const std::string &member, relation.members()) {
+ mTagMembers << Conversion::fromStdString(member);
+ }
+ } else if (relation.type() == "generic") {
+#ifdef HAVE_RELATION_H
+ if (relation.members().size() == 2) {
+ mRelation = Akonadi::Relation();
+ mRelation.setRemoteId(Conversion::fromStdString(configuration.uid()).toLatin1());
+ mRelation.setType(Akonadi::Relation::GENERIC);
+
+ mTagMembers.reserve(relation.members().size());
+ foreach (const std::string &member, relation.members()) {
+ mTagMembers << Conversion::fromStdString(member);
+ }
+ } else {
+ Critical() << "generic relation had wrong number of members:" << relation.members().size();
+ printMessageDebugInfo(msg);
+ }
+#endif
+ } else {
+ Critical() << "unknown configuration object type" << relation.type();
+ printMessageDebugInfo(msg);
+ }
+ }
+ break;
+#endif
default:
Critical() << "no kolab object found ";
printMessageDebugInfo(msg);
@@ -452,6 +590,35 @@
return d->mFreebusy;
}
+#ifdef HAVE_TAG_H
+bool KolabObjectReader::isTag() const
+{
+ return !d->mTag.gid().isEmpty();
+}
+
+Akonadi::Tag KolabObjectReader::getTag() const
+{
+ return d->mTag;
+}
+
+QStringList KolabObjectReader::getTagMembers() const
+{
+ return d->mTagMembers;
+}
+#endif
+
+#ifdef HAVE_RELATION_H
+bool KolabObjectReader::isRelation() const
+{
+ return d->mRelation.isValid();
+}
+
+Akonadi::Relation KolabObjectReader::getRelation() const
+{
+ return d->mRelation;
+}
+#endif
+
//Normalize incidences before serializing them
KCalCore::Incidence::Ptr normalizeIncidence(KCalCore::Incidence::Ptr original)
@@ -630,9 +797,58 @@
return Mime::createMessage(Conversion::fromStdString(freebusy.uid()), xCalMimeType(), freebusyKolabType(), Conversion::fromStdString(v3String).toUtf8(), true, getProductId(productId));
}
+#ifdef HAVE_TAG_H
+KMime::Message::Ptr writeRelationHelper(const Kolab::Relation &relation, const QByteArray &uid, const QString &productId)
+{
+ Kolab::Configuration configuration(relation); //TODO preserve creation/lastModified date
+ configuration.setUid(uid.constData());
+ const std::string &v3String = Kolab::writeConfiguration(configuration, Conversion::toStdString(getProductId(productId)));
+ ErrorHandler::handleLibkolabxmlErrors();
+ return Mime::createMessage(Conversion::fromStdString(configuration.uid()), kolabMimeType(), relationKolabType(), Conversion::fromStdString(v3String).toUtf8(), true, getProductId(productId));
+}
+
+KMime::Message::Ptr KolabObjectWriter::writeTag(const Akonadi::Tag &tag, const QStringList &members, Version v, const QString &productId)
+{
+ ErrorHandler::clearErrors();
+ if (v != KolabV3) {
+ Critical() << "only v3 implementation available";
+ }
+
+ Kolab::Relation relation(Conversion::toStdString(tag.name()), "tag");
+ std::vectorstd::string m;
+ m.reserve(members.count());
+ foreach (const QString &member, members) {
+ m.push_back(Conversion::toStdString(member));
+ }
+ relation.setMembers(m);
+
+ return writeRelationHelper(relation, tag.gid(), productId);
+}
+#endif
+
+#ifdef HAVE_RELATION_H
+KMime::Message::Ptr KolabObjectWriter::writeRelation(const Akonadi::Relation &relation, const QStringList &items, Version v, const QString &productId)
+{
+ ErrorHandler::clearErrors();
+ if (v != KolabV3) {
+ Critical() << "only v3 implementation available";
+ }
+ if (items.size() != 2) {
+ Critical() << "Wrong number of members for generic relation.";
+ return KMime::Message::Ptr();
+ }
+ Kolab::Relation kolabRelation(std::string(), "generic");
+ std::vectorstd::string m;
+ m.reserve(2);
+ m.push_back(Conversion::toStdString(items.at(0)));
+ m.push_back(Conversion::toStdString(items.at(1)));
+ kolabRelation.setMembers(m);
+ return writeRelationHelper(kolabRelation, relation.remoteId(), productId);
+}
+#endif
}; //Namespace
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libkolab-0.5.3/kolabformat/kolabobject.h new/libkolab-0.6.0/kolabformat/kolabobject.h
--- old/libkolab-0.5.3/kolabformat/kolabobject.h 2014-08-26 13:39:06.000000000 +0200
+++ new/libkolab-0.6.0/kolabformat/kolabobject.h 2015-02-01 18:23:05.000000000 +0100
@@ -20,6 +20,15 @@
#include
+#include
+
+#ifdef HAVE_TAG_H
+#include
+#include
+#endif
+#ifdef HAVE_RELATION_H
+#include
+#endif
#include
#include
#include
@@ -37,6 +46,18 @@
KOLAB_EXPORT KCalCore::Event::Ptr readV2EventXML(const QByteArray &xmlData, QStringList &attachments);
+struct KOLAB_EXPORT RelationMember {
+ QString messageId;
+ QString subject;
+ QString date;
+ QList<QByteArray> mailbox;
+ QString user;
+ qint64 uid;
+ QString gid;
+};
+KOLAB_EXPORT RelationMember parseMemberUrl(const QString &url);
+KOLAB_EXPORT QString generateMemberUrl(const RelationMember &url);
+
/**
* Class to read Kolab Mime files
*
@@ -87,9 +108,20 @@
KMime::Message::Ptr getNote() const;
QStringList getDictionary(QString &lang) const;
Freebusy getFreebusy() const;
+#ifdef HAVE_TAG_H
+ bool isTag() const;
+ Akonadi::Tag getTag() const;
+ QStringList getTagMembers() const;
+#endif
+#ifdef HAVE_RELATION_H
+ bool isRelation() const;
+ Akonadi::Relation getRelation() const;
+#endif
private:
//@cond PRIVATE
+ KolabObjectReader(const KolabObjectReader &other);
+ KolabObjectReader &operator=(const KolabObjectReader &rhs);
class Private;
Private *const d;
//@endcond
@@ -111,6 +143,12 @@
static KMime::Message::Ptr writeNote(const KMime::Message::Ptr &, Version v = KolabV3, const QString &productId = QString());
static KMime::Message::Ptr writeDictionary(const QStringList &, const QString &lang, Version v = KolabV3, const QString &productId = QString());
static KMime::Message::Ptr writeFreebusy(const Kolab::Freebusy &, Version v = KolabV3, const QString &productId = QString());
+#ifdef HAVE_TAG_H
+ static KMime::Message::Ptr writeTag(const Akonadi::Tag &, const QStringList &items, Version v = KolabV3, const QString &productId = QString());
+#endif
+#ifdef HAVE_RELATION_H
+ static KMime::Message::Ptr writeRelation(const Akonadi::Relation &, const QStringList &items, Version v = KolabV3, const QString &productId = QString());
+#endif
};
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libkolab-0.5.3/libkolab_config.h.in new/libkolab-0.6.0/libkolab_config.h.in
--- old/libkolab-0.5.3/libkolab_config.h.in 1970-01-01 01:00:00.000000000 +0100
+++ new/libkolab-0.6.0/libkolab_config.h.in 2015-02-01 18:23:05.000000000 +0100
@@ -0,0 +1,6 @@
+/* This file is generated from libkolab_config.h.cmake. */
+
+/* Whether akonadi/tag.h exists. */
+#cmakedefine HAVE_TAG_H 1
+/* Whether akonadi/relation.h exists. */
+#cmakedefine HAVE_RELATION_H 1
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libkolab-0.5.3/tests/kcalconversiontest.cpp new/libkolab-0.6.0/tests/kcalconversiontest.cpp
--- old/libkolab-0.5.3/tests/kcalconversiontest.cpp 2014-08-26 13:39:06.000000000 +0200
+++ new/libkolab-0.6.0/tests/kcalconversiontest.cpp 2015-02-01 18:23:05.000000000 +0100
@@ -504,8 +504,6 @@
QTest::addColumnKABC::Addressee( "kcal" );
QTest::addColumnKolab::Contact( "kolab" );
- Kolab::cDateTime date(2011,2,2,12,11,10,true);
- Kolab::cDateTime date2(2011,2,2,12,12,10,true);
{
KABC::Addressee kcal;
kcal.setUid("uid");
@@ -520,6 +518,20 @@
{
KABC::Addressee kcal;
kcal.setUid("uid");
+ kcal.setFormattedName("name");
+ kcal.setBirthday(QDateTime(QDate(2012,2,2)));
+
+ //Because QDateTime doesn't know date-only values we always end up with a date-time
+ Kolab::Contact kolab;
+ kolab.setUid("uid");
+ kolab.setName("name");
+ kolab.setBDay(Kolab::cDateTime(2012,2,2,0,0,0));
+
+ QTest::newRow("bday") << kcal << kolab;
+ }
+ {
+ KABC::Addressee kcal;
+ kcal.setUid("uid");
//The first address is always the preferred
kcal.setEmails(QStringList() << "email1@example.org" << "email2@example.org");
kcal.insertCustom("KOLAB", "EmailTypesemail1@example.org", "home,work");
@@ -554,12 +566,14 @@
foreach (const QString &mail, e.emails()) {
QCOMPARE(e.custom(QLatin1String("KOLAB"), QString::fromLatin1("EmailTypes%1").arg(mail)), kcal.custom(QLatin1String("KOLAB"), QString::fromLatin1("EmailTypes%1").arg(mail)));
}
+ QCOMPARE(e.birthday(), kcal.birthday());
const Kolab::Contact &b = fromKABC(kcal);
QCOMPARE(b.uid(), kolab.uid());
QCOMPARE(b.name(), kolab.name());
QCOMPARE(b.emailAddresses(), kolab.emailAddresses());
QCOMPARE(b.emailAddressPreferredIndex(), kolab.emailAddressPreferredIndex());
+ QCOMPARE(b.bDay(), kolab.bDay());
}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libkolab-0.5.3/tests/kolabobjecttest.cpp new/libkolab-0.6.0/tests/kolabobjecttest.cpp
--- old/libkolab-0.5.3/tests/kolabobjecttest.cpp 2014-08-26 13:39:06.000000000 +0200
+++ new/libkolab-0.6.0/tests/kolabobjecttest.cpp 2015-02-01 18:23:05.000000000 +0100
@@ -80,6 +80,92 @@
QCOMPARE(Kolab::ErrorHandler::instance().error(), Kolab::ErrorHandler::Critical);
}
+void KolabObjectTest::parseRelationMembers()
+{
+ {
+ QString memberString("imap:///user/jan.aachen%40lhm.klab.cc/INBOX/20?message-id=%3Cf06aa3345a25005380b47547ad161d36%40lhm.klab.cc%3E&subject=Re%3A+test&date=Tue%2C+12+Aug+2014+20%3A42%3A59+%2B0200");
+ Kolab::RelationMember member = Kolab::parseMemberUrl(memberString);
+
+ QString result = Kolab::generateMemberUrl(member);
+ qDebug() << result;
+ result.replace(QLatin1String("%20"),QLatin1String("+"));
+ QCOMPARE(result, memberString);
+ }
+
+ //user namespace by uid
+ {
+
+ Kolab::RelationMember member;
+ member.uid = 20;
+ member.mailbox = QList<QByteArray>() << "INBOX";
+ member.user = "john.doe@example.org";
+ member.messageId = "messageid";
+ member.date = "date";
+ member.subject = "subject";
+ QString url = Kolab::generateMemberUrl(member);
+ qDebug() << url;
+ Kolab::RelationMember result = Kolab::parseMemberUrl(url);
+ QCOMPARE(result.uid, member.uid);
+ QCOMPARE(result.mailbox, member.mailbox);
+ QCOMPARE(result.user, member.user);
+ QCOMPARE(result.messageId, member.messageId);
+ QCOMPARE(result.date, member.date);
+ QCOMPARE(result.subject, member.subject);
+ }
+
+ //shared namespace by uid
+ {
+
+ Kolab::RelationMember member;
+ member.uid = 20;
+ member.mailbox = QList<QByteArray>() << "foo" << "bar";
+ member.messageId = "messageid";
+ member.date = "date";
+ member.subject = "subject";
+ QString url = Kolab::generateMemberUrl(member);
+ qDebug() << url;
+ Kolab::RelationMember result = Kolab::parseMemberUrl(url);
+ QCOMPARE(result.uid, member.uid);
+ QCOMPARE(result.mailbox, member.mailbox);
+ QVERIFY(result.user.isEmpty());
+ QCOMPARE(result.messageId, member.messageId);
+ QCOMPARE(result.date, member.date);
+ QCOMPARE(result.subject, member.subject);
+ }
+
+ //by uuid/gid
+ {
+
+ Kolab::RelationMember member;
+ member.gid = "fooobar";
+ QString url = Kolab::generateMemberUrl(member);
+ qDebug() << url;
+ Kolab::RelationMember result = Kolab::parseMemberUrl(url);
+ QCOMPARE(result.gid, member.gid);
+ }
+
+ // chars to en/decode
+ {
+
+ Kolab::RelationMember member;
+ member.uid = 20;
+ member.mailbox = QList<QByteArray>() << "spaces in folders" << "+^,:@";
+ member.user = "john.doe:^@example.org";
+ member.messageId = "messageid+^,:@";
+ member.date = "date+^,:@";
+ member.subject = "subject+^,:@";
+
+ QString url = Kolab::generateMemberUrl(member);
+ qDebug() << url;
+ Kolab::RelationMember result = Kolab::parseMemberUrl(url);
+ QCOMPARE(result.uid, member.uid);
+ QCOMPARE(result.mailbox, member.mailbox);
+ QCOMPARE(result.user, member.user);
+ QCOMPARE(result.messageId, member.messageId);
+ QCOMPARE(result.date, member.date);
+ QCOMPARE(result.subject, member.subject);
+ }
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libkolab-0.5.3/tests/kolabobjecttest.h new/libkolab-0.6.0/tests/kolabobjecttest.h
--- old/libkolab-0.5.3/tests/kolabobjecttest.h 2014-08-26 13:39:06.000000000 +0200
+++ new/libkolab-0.6.0/tests/kolabobjecttest.h 2015-02-01 18:23:05.000000000 +0100
@@ -27,6 +27,7 @@
void preserveUnicode();
void dontCrashWithEmptyOrganizer();
void dontCrashWithEmptyIncidence();
+ void parseRelationMembers();
};
#endif // KOLABOBJECTTEST_H
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libkolab-0.5.3/tests/testfiles/v3/contacts/distlist.vcf.mime new/libkolab-0.6.0/tests/testfiles/v3/contacts/distlist.vcf.mime
--- old/libkolab-0.5.3/tests/testfiles/v3/contacts/distlist.vcf.mime 2014-08-26 13:39:06.000000000 +0200
+++ new/libkolab-0.6.0/tests/testfiles/v3/contacts/distlist.vcf.mime 2015-02-01 18:23:05.000000000 +0100
@@ -1,5 +1,5 @@
Date: Mon, 23 Apr 2012 12:46:37 +0200
-X-Kolab-Type: application/x-vnd.kolab.contact.distlist
+X-Kolab-Type: application/x-vnd.kolab.distribution-list
X-Kolab-Mime-Version: 3.0
User-Agent: Libkolab-0.1.0
Content-Type: multipart/mixed; boundary="nextPart1365947.WmFcbPlLFA"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libkolab-0.5.3/tests/timezonetest.cpp new/libkolab-0.6.0/tests/timezonetest.cpp
--- old/libkolab-0.5.3/tests/timezonetest.cpp 2014-08-26 13:39:06.000000000 +0200
+++ new/libkolab-0.6.0/tests/timezonetest.cpp 2015-02-01 18:23:05.000000000 +0100
@@ -85,6 +85,9 @@
QTest::newRow( "13" ) << QString::fromLatin1("(GMT-11:00) Midway Island, Samoa");
QTest::newRow( "14" ) << QString::fromLatin1("W. Europe Standard Time");
QTest::newRow( "15" ) << QString::fromLatin1("(GMT+1.00) Sarajevo/Warsaw/Zagreb");
+ //Lotus notes uses it's own set of specifiers
+// QTest::newRow( "Lotus Notes" ) << QString::fromLatin1("W. Europe");
+// QTest::newRow( "Google UTC offset" ) << QString::fromLatin1("2013-10-23T04:00:00+02:00");
}
void TimezoneTest::testFromHardcodedList()
@@ -109,57 +112,65 @@
QCOMPARE(result->dtStart().timeZone().name(), KTimeZone(QLatin1String("Africa/Lagos")).name());
}
-void TimezoneTest::testKolabObjectReader()
-{
- const Kolab::Version version = Kolab::KolabV3;
- const Kolab::ObjectType type = Kolab::EventObject;
- QString icalFileName = TESTFILEDIR+QString::fromLatin1("timezone/windowsTimezone.ics"); //To compare
- QString mimeFileName = TESTFILEDIR+QString::fromLatin1("timezone/windowsTimezoneV3.mime"); //For parsing
-
- //Parse mime message
- bool ok = false;
- const KMime::Message::Ptr &msg = readMimeFile( mimeFileName, ok );
- QVERIFY(ok);
- Kolab::KolabObjectReader reader;
- Kolab::ObjectType t = reader.parseMimeMessage(msg);
- QCOMPARE(t, type);
- QCOMPARE(reader.getVersion(), version);
- QCOMPARE(Kolab::ErrorHandler::instance().error(), Kolab::ErrorHandler::Debug);
-
- KCalCore::Incidence::Ptr convertedIncidence = reader.getIncidence();
- kDebug() << "read incidence";
-
- //Parse ICalFile for comparison
- QFile icalFile( icalFileName );
- QVERIFY( icalFile.open( QFile::ReadOnly ) );
- KCalCore::ICalFormat format;
- KCalCore::Incidence::Ptr realIncidence( format.fromString( QString::fromUtf8( icalFile.readAll() ) ) );
-
- // fix up the converted incidence for comparisson
- normalizeIncidence(convertedIncidence);
- normalizeIncidence(realIncidence);
-
- // recurrence objects are created on demand, but KCalCore::Incidence::operator==() doesn't take that into account
- // so make sure both incidences have one
- realIncidence->recurrence();
- convertedIncidence->recurrence();
-
- realIncidence->setLastModified(convertedIncidence->lastModified());
-
- //The following test is just for debugging and not really relevant
- if ( *(realIncidence.data()) != *(convertedIncidence.data()) ) {
- showDiff(format.toString( realIncidence ), format.toString( convertedIncidence ));
- }
- QVERIFY( *(realIncidence.data()) == *(convertedIncidence.data()) );
-}
+// void TimezoneTest::testKolabObjectReader()
+// {
+// const Kolab::Version version = Kolab::KolabV3;
+// const Kolab::ObjectType type = Kolab::EventObject;
+// QString icalFileName = TESTFILEDIR+QString::fromLatin1("timezone/windowsTimezone.ics"); //To compare
+// QString mimeFileName = TESTFILEDIR+QString::fromLatin1("timezone/windowsTimezoneV3.mime"); //For parsing
+//
+// //Parse mime message
+// bool ok = false;
+// const KMime::Message::Ptr &msg = readMimeFile( mimeFileName, ok );
+// QVERIFY(ok);
+// Kolab::KolabObjectReader reader;
+// Kolab::ObjectType t = reader.parseMimeMessage(msg);
+// QCOMPARE(t, type);
+// QCOMPARE(reader.getVersion(), version);
+// QCOMPARE(Kolab::ErrorHandler::instance().error(), Kolab::ErrorHandler::Debug);
+//
+// KCalCore::Incidence::Ptr convertedIncidence = reader.getIncidence();
+// kDebug() << "read incidence";
+//
+// //Parse ICalFile for comparison
+// QFile icalFile( icalFileName );
+// QVERIFY( icalFile.open( QFile::ReadOnly ) );
+// KCalCore::ICalFormat format;
+// KCalCore::Incidence::Ptr realIncidence( format.fromString( QString::fromUtf8( icalFile.readAll() ) ) );
+//
+// // fix up the converted incidence for comparisson
+// normalizeIncidence(convertedIncidence);
+// normalizeIncidence(realIncidence);
+//
+// // recurrence objects are created on demand, but KCalCore::Incidence::operator==() doesn't take that into account
+// // so make sure both incidences have one
+// realIncidence->recurrence();
+// convertedIncidence->recurrence();
+//
+// realIncidence->setLastModified(convertedIncidence->lastModified());
+//
+// //The following test is just for debugging and not really relevant
+// if ( *(realIncidence.data()) != *(convertedIncidence.data()) ) {
+// showDiff(format.toString( realIncidence ), format.toString( convertedIncidence ));
+// }
+// QVERIFY( *(realIncidence.data()) == *(convertedIncidence.data()) );
+// }
void TimezoneTest::testFindLegacyTimezone()
{
const QString normalized = TimezoneConverter::normalizeTimezone("US/Pacific");
kDebug() << normalized;
+ QEXPECT_FAIL("", "Currently broken", Continue);
QVERIFY(!normalized.isEmpty());
}
+void TimezoneTest::testIgnoreInvalidTimezone()
+{
+ const QString normalized = TimezoneConverter::normalizeTimezone("FOOOOBAR");
+ kDebug() << normalized;
+ QVERIFY(normalized.isEmpty());
+}
+
void TimezoneTest::testTimezoneDaemonAvailable()
{
//With KDE it should be available and with libcalendaring it should return true
@@ -171,9 +182,35 @@
const Kolab::cDateTime expected(2013, 10, 23, 2, 0 ,0, true);
const KDateTime input(KDateTime::fromString("2013-10-23T04:00:00+02:00", KDateTime::RFC3339Date));
const Kolab::cDateTime result = Kolab::Conversion::fromDate(input);
+ QVERIFY(!Kolab::ErrorHandler::instance().errorOccured());
QCOMPARE(result, expected);
}
+void TimezoneTest::localTimezone()
+{
+ {
+ const Kolab::cDateTime result = Kolab::Conversion::fromDate(KDateTime(QDate(2013, 10, 10), QTime(2, 0, 0), KDateTime::LocalZone));
+ QVERIFY(!result.timezone().empty());
+ QVERIFY(!Kolab::ErrorHandler::instance().errorOccured());
+ }
+ {
+ const Kolab::cDateTime result = Kolab::Conversion::fromDate(KDateTime(QDate(2013, 10, 10), QTime(2, 0, 0), KDateTime::ClockTime));
+ QVERIFY(!Kolab::ErrorHandler::instance().errorOccured());
+ }
+ {
+ const Kolab::cDateTime result = Kolab::Conversion::fromDate(KDateTime(QDate(2013, 10, 10), QTime(2, 0, 0), KDateTime::TimeZone));
+ QVERIFY(result.timezone().empty());
+ QVERIFY(!Kolab::ErrorHandler::instance().errorOccured());
+ }
+ {
+ KDateTime dt(QDate(2013, 10, 10), QTime(2, 0, 0), KTimeZone("/etc/localzone"));
+ const Kolab::cDateTime result = Kolab::Conversion::fromDate(dt);
+ kDebug() << result.timezone();
+ QVERIFY(result.timezone().empty());
+ QVERIFY(!Kolab::ErrorHandler::instance().errorOccured());
+ }
+}
+
QTEST_MAIN( TimezoneTest )
#include "timezonetest.moc"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libkolab-0.5.3/tests/timezonetest.h new/libkolab-0.6.0/tests/timezonetest.h
--- old/libkolab-0.5.3/tests/timezonetest.h 2014-08-26 13:39:06.000000000 +0200
+++ new/libkolab-0.6.0/tests/timezonetest.h 2015-02-01 18:23:05.000000000 +0100
@@ -32,10 +32,12 @@
void testFromHardcodedList_data();
void testFromHardcodedList();
void testKolabObjectWriter();
- void testKolabObjectReader();
+ // void testKolabObjectReader();
void testFindLegacyTimezone();
+ void testIgnoreInvalidTimezone();
void testTimezoneDaemonAvailable();
void testUTCOffset();
+ void localTimezone();
};
#endif // TIMEZONETEST_H
++++++ libkolab-0.6.0_check_for_generic_tag.patch ++++++
From 34edc0a846b87570c06a5942b458adb720a34a9b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Sandro=20Knau=C3=9F?=
Date: Tue, 10 Feb 2015 10:59:18 +0100
Subject: Make libkolab compile with upstream kdepimlibs
Because GENERIC tags have not entered upstream, we have to test for
support. Our integration branch not supports a feature flag to indicate
the availability of that feature.
KOLAB: #4448
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 365edac..bd53e27 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -78,6 +78,11 @@ add_definitions( -DKDEPIMLIBS_VERSION_MAJOR=${KdepimLibs_VERSION_MAJOR} )
add_definitions( -DKDEPIMLIBS_VERSION_MINOR=${KdepimLibs_VERSION_MINOR} )
add_definitions( -DKDEPIMLIBS_VERSION_PATCH=${KdepimLibs_VERSION_PATCH} )
+#Tag::GENERIC is only available at the moment at the kolab/integration branches
+if (KDEPIMLIBS_HAS_GENERIC_TAG)
+ add_definitions( -DKDEPIMLIBS_HAS_GENERIC_TAG)
+endif()
+
if("${KdepimLibs_VERSION}" VERSION_GREATER "4.8.40" OR USE_LIBCALENDARING)
add_definitions(-DKDEPIMLIBS_VERSION_DEVEL)
endif()
diff --git a/kolabformat/kolabobject.cpp b/kolabformat/kolabobject.cpp
index 681b4a5..e5c404d 100644
--- a/kolabformat/kolabobject.cpp
+++ b/kolabformat/kolabobject.cpp
@@ -435,8 +435,11 @@ ObjectType KolabObjectReader::Private::readKolabV3(const KMime::Message::Ptr &ms
mTag = Akonadi::Tag();
mTag.setName(Conversion::fromStdString(relation.name()));
mTag.setGid(Conversion::fromStdString(configuration.uid()).toLatin1());
+#ifdef KDEPIMLIBS_HAS_GENERIC_TAG
mTag.setType(Akonadi::Tag::GENERIC);
-
+#else
+ mTag.setType(Akonadi::Tag::PLAIN);
+#endif
mTagMembers.reserve(relation.members().size());
foreach (const std::string &member, relation.members()) {
mTagMembers << Conversion::fromStdString(member);
--
cgit v0.10.2