summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--common/domain/typeimplementations.cpp7
-rw-r--r--common/log.cpp16
-rw-r--r--common/storage/entitystore.cpp2
-rw-r--r--examples/caldavresource/CMakeLists.txt2
-rw-r--r--examples/caldavresource/tests/caldavtest.cpp391
-rw-r--r--examples/carddavresource/CMakeLists.txt2
-rw-r--r--examples/carddavresource/tests/carddavtest.cpp75
-rw-r--r--examples/mailtransportresource/mailtransport.cpp22
-rw-r--r--examples/mailtransportresource/mailtransport.h3
-rw-r--r--examples/mailtransportresource/mailtransportresource.cpp6
-rw-r--r--examples/webdavcommon/CMakeLists.txt2
-rw-r--r--examples/webdavcommon/webdav.cpp34
-rw-r--r--examples/webdavcommon/webdav.h4
-rw-r--r--tests/dbwriter.cpp12
-rw-r--r--tests/pipelinetest.cpp6
15 files changed, 349 insertions, 235 deletions
diff --git a/common/domain/typeimplementations.cpp b/common/domain/typeimplementations.cpp
index c74701d..6e14501 100644
--- a/common/domain/typeimplementations.cpp
+++ b/common/domain/typeimplementations.cpp
@@ -56,7 +56,8 @@ typedef IndexConfig<Folder,
56 > FolderIndexConfig; 56 > FolderIndexConfig;
57 57
58typedef IndexConfig<Contact, 58typedef IndexConfig<Contact,
59 ValueIndex<Contact::Uid> 59 ValueIndex<Contact::Uid>,
60 ValueIndex<Contact::Addressbook>
60 > ContactIndexConfig; 61 > ContactIndexConfig;
61 62
62typedef IndexConfig<Addressbook, 63typedef IndexConfig<Addressbook,
@@ -65,12 +66,14 @@ typedef IndexConfig<Addressbook,
65 66
66typedef IndexConfig<Event, 67typedef IndexConfig<Event,
67 ValueIndex<Event::Uid>, 68 ValueIndex<Event::Uid>,
69 ValueIndex<Event::Calendar>,
68 SortedIndex<Event::StartTime>, 70 SortedIndex<Event::StartTime>,
69 SampledPeriodIndex<Event::StartTime, Event::EndTime> 71 SampledPeriodIndex<Event::StartTime, Event::EndTime>
70 > EventIndexConfig; 72 > EventIndexConfig;
71 73
72typedef IndexConfig<Todo, 74typedef IndexConfig<Todo,
73 ValueIndex<Todo::Uid> 75 ValueIndex<Todo::Uid>,
76 ValueIndex<Todo::Calendar>
74 > TodoIndexConfig; 77 > TodoIndexConfig;
75 78
76typedef IndexConfig<Calendar, 79typedef IndexConfig<Calendar,
diff --git a/common/log.cpp b/common/log.cpp
index 5156a23..e5ed29b 100644
--- a/common/log.cpp
+++ b/common/log.cpp
@@ -253,14 +253,22 @@ class DebugAreaCollector {
253public: 253public:
254 DebugAreaCollector() 254 DebugAreaCollector()
255 { 255 {
256 QMutexLocker locker(&mutex); 256 //This call can potentially print a log message (if we fail to remove the qsettings lockfile), which would result in a deadlock if we locked over all of it.
257 mDebugAreas = debugAreasConfig()->value("areas").value<QString>().split(';').toSet(); 257 const auto areas = debugAreasConfig()->value("areas").value<QString>().split(';').toSet();
258 {
259 QMutexLocker locker(&mutex);
260 mDebugAreas = areas;
261 }
258 } 262 }
259 263
260 ~DebugAreaCollector() 264 ~DebugAreaCollector()
261 { 265 {
262 QMutexLocker locker(&mutex); 266 //This call can potentially print a log message (if we fail to remove the qsettings lockfile), which would result in a deadlock if we locked over all of it.
263 mDebugAreas += debugAreasConfig()->value("areas").value<QString>().split(';').toSet(); 267 const auto areas = debugAreasConfig()->value("areas").value<QString>().split(';').toSet();
268 {
269 QMutexLocker locker(&mutex);
270 mDebugAreas += areas;
271 }
264 debugAreasConfig()->setValue("areas", QVariant::fromValue(mDebugAreas.toList().join(';'))); 272 debugAreasConfig()->setValue("areas", QVariant::fromValue(mDebugAreas.toList().join(';')));
265 } 273 }
266 274
diff --git a/common/storage/entitystore.cpp b/common/storage/entitystore.cpp
index c11f49c..daabf1f 100644
--- a/common/storage/entitystore.cpp
+++ b/common/storage/entitystore.cpp
@@ -458,7 +458,7 @@ QVector<Identifier> EntityStore::fullScan(const QByteArray &type)
458 const auto identifier = Sink::Storage::Identifier::fromDisplayByteArray(uid); 458 const auto identifier = Sink::Storage::Identifier::fromDisplayByteArray(uid);
459 if (keys.contains(identifier)) { 459 if (keys.contains(identifier)) {
460 //Not something that should persist if the replay works, so we keep a message for now. 460 //Not something that should persist if the replay works, so we keep a message for now.
461 SinkTraceCtx(d->logCtx) << "Multiple revisions for key: " << key; 461 SinkTraceCtx(d->logCtx) << "Multiple revisions for uid: " << Sink::Storage::Key::fromInternalByteArray(key) << ". This is normal if changereplay has not completed yet.";
462 } 462 }
463 keys << identifier; 463 keys << identifier;
464 return true; 464 return true;
diff --git a/examples/caldavresource/CMakeLists.txt b/examples/caldavresource/CMakeLists.txt
index d6e8408..00d1eb8 100644
--- a/examples/caldavresource/CMakeLists.txt
+++ b/examples/caldavresource/CMakeLists.txt
@@ -2,7 +2,7 @@ project(sink_resource_caldav)
2 2
3include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR}) 3include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR})
4 4
5find_package(KPimKDAV2 REQUIRED) 5find_package(KPimKDAV2 REQUIRED 0.2.0)
6find_package(KF5CalendarCore REQUIRED) 6find_package(KF5CalendarCore REQUIRED)
7 7
8add_library(${PROJECT_NAME} SHARED caldavresource.cpp) 8add_library(${PROJECT_NAME} SHARED caldavresource.cpp)
diff --git a/examples/caldavresource/tests/caldavtest.cpp b/examples/caldavresource/tests/caldavtest.cpp
index daa890d..d62616f 100644
--- a/examples/caldavresource/tests/caldavtest.cpp
+++ b/examples/caldavresource/tests/caldavtest.cpp
@@ -1,8 +1,10 @@
1#include <QtTest> 1#include <QtTest>
2 2
3#include <KDAV2/DavCollectionsFetchJob> 3#include <KDAV2/DavCollectionsFetchJob>
4#include <KDAV2/DavCollectionCreateJob>
4#include <KDAV2/DavItemFetchJob> 5#include <KDAV2/DavItemFetchJob>
5#include <KDAV2/DavItemModifyJob> 6#include <KDAV2/DavItemModifyJob>
7#include <KDAV2/DavItemCreateJob>
6#include <KDAV2/DavItemsListJob> 8#include <KDAV2/DavItemsListJob>
7#include <KDAV2/EtagCache> 9#include <KDAV2/EtagCache>
8 10
@@ -41,20 +43,82 @@ class CalDavTest : public QObject
41 resource.setProperty("server", baseUrl); 43 resource.setProperty("server", baseUrl);
42 resource.setProperty("username", username); 44 resource.setProperty("username", username);
43 Sink::SecretStore::instance().insert(resource.identifier(), password); 45 Sink::SecretStore::instance().insert(resource.identifier(), password);
44 resource.setProperty("testmode", true);
45 return resource; 46 return resource;
46 } 47 }
47 48
48 QByteArray mResourceInstanceIdentifier; 49 QByteArray mResourceInstanceIdentifier;
49 50
50 QString addedEventUid; 51 QByteArray createEvent(const QString &subject, const QString &collectionName)
51 QString addedTodoUid; 52 {
53 QUrl mainUrl{"http://localhost/dav/calendars/user/doe"};
54 mainUrl.setUserName(QStringLiteral("doe"));
55 mainUrl.setPassword(QStringLiteral("doe"));
56
57 KDAV2::DavUrl davUrl(mainUrl, KDAV2::CalDav);
58
59 auto *job = new KDAV2::DavCollectionsFetchJob(davUrl);
60 job->exec();
61
62 const auto collectionUrl = [&] {
63 for (const auto &col : job->collections()) {
64 // qWarning() << "Looking for " << collectionName << col.displayName();
65 if (col.displayName() == collectionName) {
66 return col.url().url();
67 }
68 }
69 return QUrl{};
70 }();
71
72 QUrl url{collectionUrl.toString() + subject + ".ical"};
73 url.setUserInfo(mainUrl.userInfo());
74
75 KDAV2::DavUrl testItemUrl(url, KDAV2::CardDav);
76
77 auto event = QSharedPointer<KCalCore::Event>::create();
78 event->setSummary(subject);
79 event->setDtStart(QDateTime::currentDateTime());
80 event->setDtEnd(QDateTime::currentDateTime().addSecs(3600));
81 event->setCreated(QDateTime::currentDateTime());
82 event->setUid(subject);
83
84 auto data = KCalCore::ICalFormat().toICalString(event).toUtf8();
85
86 KDAV2::DavItem item(testItemUrl, QStringLiteral("text/calendar"), data, QString());
87 auto createJob = new KDAV2::DavItemCreateJob(item);
88 createJob->exec();
89 if (createJob->error()) {
90 qWarning() << createJob->errorString();
91 }
92 return event->uid().toUtf8();
93 }
94
95 void createCollection(const QString &name)
96 {
97 QUrl mainUrl(QStringLiteral("http://localhost/dav/calendars/user/doe/") + name);
98 mainUrl.setUserName(QStringLiteral("doe"));
99 mainUrl.setPassword(QStringLiteral("doe"));
100
101 KDAV2::DavUrl davUrl(mainUrl, KDAV2::CalDav);
102 KDAV2::DavCollection collection{davUrl, name, KDAV2::DavCollection::Events};
103
104 auto createJob = new KDAV2::DavCollectionCreateJob(collection);
105 createJob->exec();
106 if (createJob->error()) {
107 qWarning() << createJob->errorString();
108 }
109 }
110
111 void resetTestEnvironment()
112 {
113 system("resetmailbox.sh");
114 }
52 115
53private slots: 116private slots:
54 117
55 void initTestCase() 118 void initTestCase()
56 { 119 {
57 Sink::Test::initTest(); 120 Sink::Test::initTest();
121 resetTestEnvironment();
58 auto resource = createResource(); 122 auto resource = createResource();
59 QVERIFY(!resource.identifier().isEmpty()); 123 QVERIFY(!resource.identifier().isEmpty());
60 VERIFYEXEC(Sink::Store::create(resource)); 124 VERIFYEXEC(Sink::Store::create(resource));
@@ -76,42 +140,73 @@ private slots:
76 VERIFYEXEC(Sink::Store::synchronize(Sink::Query().resourceFilter(mResourceInstanceIdentifier))); 140 VERIFYEXEC(Sink::Store::synchronize(Sink::Query().resourceFilter(mResourceInstanceIdentifier)));
77 VERIFYEXEC(Sink::ResourceControl::flushMessageQueue(mResourceInstanceIdentifier)); 141 VERIFYEXEC(Sink::ResourceControl::flushMessageQueue(mResourceInstanceIdentifier));
78 142
79 auto eventJob = Sink::Store::fetchAll<Event>(Sink::Query().request<Event::Uid>()) 143 QCOMPARE(Sink::Store::read<Event>({}).size(), 0);
80 .then([](const QList<Event::Ptr> &events) { QCOMPARE(events.size(), 0); }); 144 QCOMPARE(Sink::Store::read<Todo>({}).size(), 0);
81 auto todoJob = Sink::Store::fetchAll<Todo>(Sink::Query().request<Todo::Uid>()) 145
82 .then([](const QList<Todo::Ptr> &todos) { QCOMPARE(todos.size(), 0); }); 146 const auto calendars = Sink::Store::read<Calendar>(Sink::Query().request<Calendar::Name>());
147 QCOMPARE(calendars.size(), 1);
148 QCOMPARE(calendars.first().getName(), {"personal"});
149 }
150
151 void testSyncCalendars()
152 {
153 createCollection("calendar2");
154
155 Sink::SyncScope scope;
156 scope.setType<Calendar>();
157 scope.resourceFilter(mResourceInstanceIdentifier);
158
159 VERIFYEXEC(Sink::Store::synchronize(scope));
160 VERIFYEXEC(Sink::ResourceControl::flushMessageQueue(mResourceInstanceIdentifier));
161 const auto calendars = Sink::Store::read<Calendar>(Sink::Query().resourceFilter(mResourceInstanceIdentifier));
162 QCOMPARE(calendars.size(), 2);
163 }
83 164
84 VERIFYEXEC(eventJob); 165 void testSyncEvents()
85 VERIFYEXEC(todoJob); 166 {
167 createEvent("event1", "personal");
168 createEvent("event2", "personal");
169 createEvent("event3", "calendar2");
170 Sink::SyncScope scope;
171 scope.setType<Event>();
172 scope.resourceFilter(mResourceInstanceIdentifier);
173
174 VERIFYEXEC(Sink::Store::synchronize(scope));
175 VERIFYEXEC(Sink::ResourceControl::flushMessageQueue(mResourceInstanceIdentifier));
176 const auto events = Sink::Store::read<Event>(Sink::Query().resourceFilter(mResourceInstanceIdentifier));
177 QCOMPARE(events.size(), 3);
86 178
87 auto calendarJob = Sink::Store::fetchAll<Calendar>(Sink::Query().request<Calendar::Name>()) 179 //Ensure a resync works
88 .then([](const QList<Calendar::Ptr> &calendars) { 180 {
89 QCOMPARE(calendars.size(), 1); 181 VERIFYEXEC(Sink::Store::synchronize(scope));
90 for (const auto &calendar : calendars) { 182 VERIFYEXEC(Sink::ResourceControl::flushMessageQueue(mResourceInstanceIdentifier));
91 QVERIFY(calendar->getName() == "personal"); 183 const auto events = Sink::Store::read<Event>(Sink::Query().resourceFilter(mResourceInstanceIdentifier));
92 } 184 QCOMPARE(events.size(), 3);
93 }); 185 }
94 VERIFYEXEC(calendarJob);
95 186
96 SinkLog() << "Finished"; 187 //Ensure a resync after another creation works
188 createEvent("event4", "calendar2");
189 {
190 VERIFYEXEC(Sink::Store::synchronize(scope));
191 VERIFYEXEC(Sink::ResourceControl::flushMessageQueue(mResourceInstanceIdentifier));
192 const auto events = Sink::Store::read<Event>(Sink::Query().resourceFilter(mResourceInstanceIdentifier));
193 QCOMPARE(events.size(), 4);
194 }
97 } 195 }
98 196
99 void testAddEvent() 197 void testCreateModifyDeleteEvent()
100 { 198 {
101 VERIFYEXEC(Sink::Store::synchronize(Sink::Query().resourceFilter(mResourceInstanceIdentifier))); 199 VERIFYEXEC(Sink::Store::synchronize(Sink::Query().resourceFilter(mResourceInstanceIdentifier)));
102 VERIFYEXEC(Sink::ResourceControl::flushMessageQueue(mResourceInstanceIdentifier)); 200 VERIFYEXEC(Sink::ResourceControl::flushMessageQueue(mResourceInstanceIdentifier));
103 201
104 auto future = Sink::Store::fetchOne<Calendar>({}).exec(); 202 auto calendar = Sink::Store::readOne<Calendar>(Sink::Query{}.filter<Calendar::Name>("personal"));
105 future.waitForFinished();
106 QVERIFY2(!future.errorCode(), "Fetching Calendar failed");
107 auto calendar = future.value();
108 203
109 auto event = QSharedPointer<KCalCore::Event>::create(); 204 auto event = QSharedPointer<KCalCore::Event>::create();
110 event->setSummary("Hello"); 205 event->setSummary("Hello");
111 event->setDtStart(QDateTime::currentDateTime()); 206 event->setDtStart(QDateTime::currentDateTime());
112 event->setDtEnd(QDateTime::currentDateTime().addSecs(3600)); 207 event->setDtEnd(QDateTime::currentDateTime().addSecs(3600));
113 event->setCreated(QDateTime::currentDateTime()); 208 event->setCreated(QDateTime::currentDateTime());
114 addedEventUid = QUuid::createUuid().toString(); 209 auto addedEventUid = QUuid::createUuid().toString();
115 event->setUid(addedEventUid); 210 event->setUid(addedEventUid);
116 211
117 auto ical = KCalCore::ICalFormat().toICalString(event); 212 auto ical = KCalCore::ICalFormat().toICalString(event);
@@ -119,37 +214,60 @@ private slots:
119 sinkEvent.setIcal(ical.toUtf8()); 214 sinkEvent.setIcal(ical.toUtf8());
120 sinkEvent.setCalendar(calendar); 215 sinkEvent.setCalendar(calendar);
121 216
122 SinkLog() << "Adding event";
123 VERIFYEXEC(Sink::Store::create(sinkEvent)); 217 VERIFYEXEC(Sink::Store::create(sinkEvent));
124 VERIFYEXEC(Sink::ResourceControl::flushReplayQueue(mResourceInstanceIdentifier)); 218 VERIFYEXEC(Sink::ResourceControl::flushReplayQueue(mResourceInstanceIdentifier));
125 219
126 auto verifyEventCountJob = 220 auto events = Sink::Store::read<Event>(Sink::Query().filter("uid", Sink::Query::Comparator(addedEventUid)));
127 Sink::Store::fetchAll<Event>(Sink::Query().request<Event::Uid>()).then([](const QList<Event::Ptr> &events) { 221 QCOMPARE(events.size(), 1);
128 QCOMPARE(events.size(), 1); 222 QCOMPARE(events.first().getSummary(), {"Hello"});
129 }); 223
130 VERIFYEXEC(verifyEventCountJob); 224 //Modify
225 {
226 auto event = events.first();
227 auto incidence = KCalCore::ICalFormat().readIncidence(event.getIcal());
228 auto calevent = incidence.dynamicCast<KCalCore::Event>();
229 QVERIFY2(calevent, "Cannot convert to KCalCore event");
230
231 calevent->setSummary("Hello World!");
232 auto dummy = QSharedPointer<KCalCore::Event>(calevent);
233 auto newical = KCalCore::ICalFormat().toICalString(dummy);
234
235 event.setIcal(newical.toUtf8());
236
237 VERIFYEXEC(Sink::Store::modify(event));
238
239 VERIFYEXEC(Sink::Store::synchronize(Sink::Query().resourceFilter(mResourceInstanceIdentifier)));
240 VERIFYEXEC(Sink::ResourceControl::flushMessageQueue(mResourceInstanceIdentifier));
131 241
132 auto verifyEventJob = 242 auto events = Sink::Store::read<Event>(Sink::Query().filter("uid", Sink::Query::Comparator(addedEventUid)));
133 Sink::Store::fetchOne<Event>(Sink::Query().filter("uid", Sink::Query::Comparator(addedEventUid))) 243 QCOMPARE(events.size(), 1);
134 .then([](const Event &event) { QCOMPARE(event.getSummary(), {"Hello"}); }); 244 QCOMPARE(events.first().getSummary(), {"Hello World!"});
135 VERIFYEXEC(verifyEventJob); 245 }
246 //Delete
247 {
248 auto event = events.first();
249
250 VERIFYEXEC(Sink::Store::remove(event));
251 VERIFYEXEC(Sink::ResourceControl::flushMessageQueue(mResourceInstanceIdentifier));
252 VERIFYEXEC(Sink::ResourceControl::flushReplayQueue(mResourceInstanceIdentifier));
253
254 auto events = Sink::Store::read<Event>(Sink::Query().filter("uid", Sink::Query::Comparator(addedEventUid)));
255 QCOMPARE(events.size(), 0);
256 }
136 } 257 }
137 258
138 void testAddTodo() 259 void testCreateModifyDeleteTodo()
139 { 260 {
140 VERIFYEXEC(Sink::Store::synchronize(Sink::Query().resourceFilter(mResourceInstanceIdentifier))); 261 VERIFYEXEC(Sink::Store::synchronize(Sink::Query().resourceFilter(mResourceInstanceIdentifier)));
141 VERIFYEXEC(Sink::ResourceControl::flushMessageQueue(mResourceInstanceIdentifier)); 262 VERIFYEXEC(Sink::ResourceControl::flushMessageQueue(mResourceInstanceIdentifier));
142 263
143 auto job = Sink::Store::fetchOne<Calendar>({}).exec(); 264 auto calendar = Sink::Store::readOne<Calendar>(Sink::Query{}.filter<Calendar::Name>("personal"));
144 job.waitForFinished();
145 QVERIFY2(!job.errorCode(), "Fetching Calendar failed");
146 auto calendar = job.value();
147 265
148 auto todo = QSharedPointer<KCalCore::Todo>::create(); 266 auto todo = QSharedPointer<KCalCore::Todo>::create();
149 todo->setSummary("Hello"); 267 todo->setSummary("Hello");
150 todo->setDtStart(QDateTime::currentDateTime()); 268 todo->setDtStart(QDateTime::currentDateTime());
151 todo->setCreated(QDateTime::currentDateTime()); 269 todo->setCreated(QDateTime::currentDateTime());
152 addedTodoUid = QUuid::createUuid().toString(); 270 auto addedTodoUid = QUuid::createUuid().toString();
153 todo->setUid(addedTodoUid); 271 todo->setUid(addedTodoUid);
154 272
155 auto ical = KCalCore::ICalFormat().toICalString(todo); 273 auto ical = KCalCore::ICalFormat().toICalString(todo);
@@ -157,104 +275,74 @@ private slots:
157 sinkTodo.setIcal(ical.toUtf8()); 275 sinkTodo.setIcal(ical.toUtf8());
158 sinkTodo.setCalendar(calendar); 276 sinkTodo.setCalendar(calendar);
159 277
160 SinkLog() << "Adding todo";
161 VERIFYEXEC(Sink::Store::create(sinkTodo)); 278 VERIFYEXEC(Sink::Store::create(sinkTodo));
162 VERIFYEXEC(Sink::ResourceControl::flushReplayQueue(mResourceInstanceIdentifier)); 279 VERIFYEXEC(Sink::ResourceControl::flushReplayQueue(mResourceInstanceIdentifier));
163 280
164 auto verifyTodoCountJob = 281 auto todos = Sink::Store::read<Todo>(Sink::Query().filter("uid", Sink::Query::Comparator(addedTodoUid)));
165 Sink::Store::fetchAll<Todo>(Sink::Query().request<Todo::Uid>()).then([](const QList<Todo::Ptr> &todos) { 282 QCOMPARE(todos.size(), 1);
166 QCOMPARE(todos.size(), 1); 283 QCOMPARE(todos.first().getSummary(), {"Hello"});
167 });
168 VERIFYEXEC(verifyTodoCountJob);
169 284
170 auto verifyTodoJob = 285 //Modify
171 Sink::Store::fetchOne<Todo>(Sink::Query().filter("uid", Sink::Query::Comparator(addedTodoUid))) 286 {
172 .then([](const Todo &todo) { QCOMPARE(todo.getSummary(), {"Hello"}); }); 287 auto todo = todos.first();
173 VERIFYEXEC(verifyTodoJob); 288 auto incidence = KCalCore::ICalFormat().readIncidence(todo.getIcal());
174 } 289 auto caltodo = incidence.dynamicCast<KCalCore::Todo>();
175 290 QVERIFY2(caltodo, "Cannot convert to KCalCore todo");
176 void testModifyEvent()
177 {
178 VERIFYEXEC(Sink::Store::synchronize(Sink::Query().resourceFilter(mResourceInstanceIdentifier)));
179 VERIFYEXEC(Sink::ResourceControl::flushMessageQueue(mResourceInstanceIdentifier));
180
181 auto job = Sink::Store::fetchOne<Event>(
182 Sink::Query().filter("uid", Sink::Query::Comparator(addedEventUid)))
183 .exec();
184 job.waitForFinished();
185 QVERIFY2(!job.errorCode(), "Fetching Event failed");
186 auto event = job.value();
187 291
188 auto incidence = KCalCore::ICalFormat().readIncidence(event.getIcal()); 292 caltodo->setSummary("Hello World!");
189 auto calevent = incidence.dynamicCast<KCalCore::Event>(); 293 auto dummy = QSharedPointer<KCalCore::Todo>(caltodo);
190 QVERIFY2(calevent, "Cannot convert to KCalCore event"); 294 auto newical = KCalCore::ICalFormat().toICalString(dummy);
191 295
192 calevent->setSummary("Hello World!"); 296 todo.setIcal(newical.toUtf8());
193 auto dummy = QSharedPointer<KCalCore::Event>(calevent);
194 auto newical = KCalCore::ICalFormat().toICalString(dummy);
195 297
196 event.setIcal(newical.toUtf8()); 298 VERIFYEXEC(Sink::Store::modify(todo));
197 299
198 VERIFYEXEC(Sink::Store::modify(event)); 300 VERIFYEXEC(Sink::Store::synchronize(Sink::Query().resourceFilter(mResourceInstanceIdentifier)));
301 VERIFYEXEC(Sink::ResourceControl::flushMessageQueue(mResourceInstanceIdentifier));
199 302
200 VERIFYEXEC(Sink::Store::synchronize(Sink::Query().resourceFilter(mResourceInstanceIdentifier))); 303 auto todos = Sink::Store::read<Todo>(Sink::Query().filter("uid", Sink::Query::Comparator(addedTodoUid)));
201 VERIFYEXEC(Sink::ResourceControl::flushMessageQueue(mResourceInstanceIdentifier)); 304 QCOMPARE(todos.size(), 1);
305 QCOMPARE(todos.first().getSummary(), {"Hello World!"});
306 }
307 //Delete
308 {
309 auto todo = todos.first();
202 310
203 auto verifyEventCountJob = Sink::Store::fetchAll<Event>({}).then( 311 VERIFYEXEC(Sink::Store::remove(todo));
204 [](const QList<Event::Ptr> &events) { QCOMPARE(events.size(), 1); }); 312 VERIFYEXEC(Sink::ResourceControl::flushMessageQueue(mResourceInstanceIdentifier));
205 VERIFYEXEC(verifyEventCountJob); 313 VERIFYEXEC(Sink::ResourceControl::flushReplayQueue(mResourceInstanceIdentifier));
206 314
207 auto verifyEventJob = 315 auto todos = Sink::Store::read<Todo>(Sink::Query().filter("uid", Sink::Query::Comparator(addedTodoUid)));
208 Sink::Store::fetchOne<Event>(Sink::Query().filter("uid", Sink::Query::Comparator(addedEventUid))) 316 QCOMPARE(todos.size(), 0);
209 .then([](const Event &event) { QCOMPARE(event.getSummary(), {"Hello World!"}); }); 317 }
210 VERIFYEXEC(verifyEventJob);
211 } 318 }
212 319
213 void testModifyTodo() 320 void testModificationConflict()
214 { 321 {
215 VERIFYEXEC(Sink::Store::synchronize(Sink::Query().resourceFilter(mResourceInstanceIdentifier))); 322 VERIFYEXEC(Sink::Store::synchronize(Sink::Query().resourceFilter(mResourceInstanceIdentifier)));
216 VERIFYEXEC(Sink::ResourceControl::flushMessageQueue(mResourceInstanceIdentifier)); 323 VERIFYEXEC(Sink::ResourceControl::flushMessageQueue(mResourceInstanceIdentifier));
217 324
218 auto job = Sink::Store::fetchOne<Todo>( 325 auto calendar = Sink::Store::readOne<Calendar>(Sink::Query{}.filter<Calendar::Name>("personal"));
219 Sink::Query().filter("uid", Sink::Query::Comparator(addedTodoUid)))
220 .exec();
221 job.waitForFinished();
222 QVERIFY2(!job.errorCode(), "Fetching Todo failed");
223 auto todo = job.value();
224
225 auto incidence = KCalCore::ICalFormat().readIncidence(todo.getIcal());
226 auto caltodo = incidence.dynamicCast<KCalCore::Todo>();
227 QVERIFY2(caltodo, "Cannot convert to KCalCore todo");
228
229 caltodo->setSummary("Hello World!");
230 auto dummy = QSharedPointer<KCalCore::Todo>(caltodo);
231 auto newical = KCalCore::ICalFormat().toICalString(dummy);
232
233 todo.setIcal(newical.toUtf8());
234
235 VERIFYEXEC(Sink::Store::modify(todo));
236 326
237 VERIFYEXEC(Sink::Store::synchronize(Sink::Query().resourceFilter(mResourceInstanceIdentifier))); 327 auto event = QSharedPointer<KCalCore::Event>::create();
238 VERIFYEXEC(Sink::ResourceControl::flushMessageQueue(mResourceInstanceIdentifier)); 328 event->setSummary("Hello");
239 329 event->setDtStart(QDateTime::currentDateTime());
240 auto verifyTodoCountJob = Sink::Store::fetchAll<Todo>({}).then( 330 event->setDtEnd(QDateTime::currentDateTime().addSecs(3600));
241 [](const QList<Todo::Ptr> &todos) { QCOMPARE(todos.size(), 1); }); 331 event->setCreated(QDateTime::currentDateTime());
242 VERIFYEXEC(verifyTodoCountJob); 332 auto addedEventUid = QUuid::createUuid().toString();
333 event->setUid(addedEventUid);
243 334
244 auto verifyTodoJob = 335 auto ical = KCalCore::ICalFormat().toICalString(event);
245 Sink::Store::fetchOne<Todo>(Sink::Query().filter("uid", Sink::Query::Comparator(addedTodoUid))) 336 Event sinkEvent(mResourceInstanceIdentifier);
246 .then([](const Todo &todo) { QCOMPARE(todo.getSummary(), {"Hello World!"}); }); 337 sinkEvent.setIcal(ical.toUtf8());
247 VERIFYEXEC(verifyTodoJob); 338 sinkEvent.setCalendar(calendar);
248 }
249 339
250 void testSneakyModifyEvent() 340 VERIFYEXEC(Sink::Store::create(sinkEvent));
251 { 341 VERIFYEXEC(Sink::ResourceControl::flushReplayQueue(mResourceInstanceIdentifier));
252 VERIFYEXEC(Sink::Store::synchronize(Sink::Query().resourceFilter(mResourceInstanceIdentifier)));
253 VERIFYEXEC(Sink::ResourceControl::flushMessageQueue(mResourceInstanceIdentifier));
254 342
255 // Change the item without sink's knowledge 343 // Change the item without sink's knowledge
256 { 344 {
257 auto collection = ([this]() -> KDAV2::DavCollection { 345 auto collection = [&]() -> KDAV2::DavCollection {
258 QUrl url(baseUrl); 346 QUrl url(baseUrl);
259 url.setUserName(username); 347 url.setUserName(username);
260 url.setPassword(password); 348 url.setPassword(password);
@@ -262,8 +350,13 @@ private slots:
262 auto collectionsJob = new KDAV2::DavCollectionsFetchJob(davurl); 350 auto collectionsJob = new KDAV2::DavCollectionsFetchJob(davurl);
263 collectionsJob->exec(); 351 collectionsJob->exec();
264 Q_ASSERT(collectionsJob->error() == 0); 352 Q_ASSERT(collectionsJob->error() == 0);
265 return collectionsJob->collections()[0]; 353 for (const auto &col : collectionsJob->collections()) {
266 })(); 354 if (col.displayName() == "personal") {
355 return col;
356 }
357 }
358 return {};
359 }();
267 360
268 auto itemList = ([&collection]() -> KDAV2::DavItem::List { 361 auto itemList = ([&collection]() -> KDAV2::DavItem::List {
269 auto cache = std::make_shared<KDAV2::EtagCache>(); 362 auto cache = std::make_shared<KDAV2::EtagCache>();
@@ -273,12 +366,12 @@ private slots:
273 return itemsListJob->items(); 366 return itemsListJob->items();
274 })(); 367 })();
275 auto hollowDavItemIt = 368 auto hollowDavItemIt =
276 std::find_if(itemList.begin(), itemList.end(), [this](const KDAV2::DavItem &item) { 369 std::find_if(itemList.begin(), itemList.end(), [&](const KDAV2::DavItem &item) {
277 return item.url().url().path().endsWith(addedEventUid); 370 return item.url().url().path().endsWith(addedEventUid);
278 }); 371 });
279 QVERIFY(hollowDavItemIt != itemList.end()); 372 QVERIFY(hollowDavItemIt != itemList.end());
280 373
281 auto davitem = ([this, &collection, &hollowDavItemIt]() -> KDAV2::DavItem { 374 auto davitem = ([&]() -> KDAV2::DavItem {
282 QString itemUrl = collection.url().url().toEncoded() + addedEventUid; 375 QString itemUrl = collection.url().url().toEncoded() + addedEventUid;
283 auto itemFetchJob = new KDAV2::DavItemFetchJob (*hollowDavItemIt); 376 auto itemFetchJob = new KDAV2::DavItemFetchJob (*hollowDavItemIt);
284 itemFetchJob->exec(); 377 itemFetchJob->exec();
@@ -299,70 +392,22 @@ private slots:
299 QVERIFY2(itemModifyJob->error() == 0, "Cannot modify item"); 392 QVERIFY2(itemModifyJob->error() == 0, "Cannot modify item");
300 } 393 }
301 394
302 // Try to change the item with sink 395 //Change the item with sink as well
303 { 396 {
304 auto job = Sink::Store::fetchOne<Event>( 397 auto event = Sink::Store::readOne<Event>(Sink::Query().filter("uid", Sink::Query::Comparator(addedEventUid)));
305 Sink::Query().filter("uid", Sink::Query::Comparator(addedEventUid))) 398 auto calevent = KCalCore::ICalFormat().readIncidence(event.getIcal()).dynamicCast<KCalCore::Event>();
306 .exec(); 399 QVERIFY(calevent);
307 job.waitForFinished();
308 QVERIFY2(!job.errorCode(), "Fetching Event failed");
309 auto event = job.value();
310
311 auto incidence = KCalCore::ICalFormat().readIncidence(event.getIcal());
312 auto calevent = incidence.dynamicCast<KCalCore::Event>();
313 QVERIFY2(calevent, "Cannot convert to KCalCore event");
314 400
315 calevent->setSummary("Sink Hello World!"); 401 calevent->setSummary("Sink Hello World!");
316 auto dummy = QSharedPointer<KCalCore::Event>(calevent); 402 event.setIcal(KCalCore::ICalFormat().toICalString(calevent).toUtf8());
317 auto newical = KCalCore::ICalFormat().toICalString(dummy);
318 403
319 event.setIcal(newical.toUtf8()); 404 // TODO: this produced a conflict, but we're not dealing with it in any way
320
321 // TODO: make that fail
322 VERIFYEXEC(Sink::Store::modify(event)); 405 VERIFYEXEC(Sink::Store::modify(event));
323 VERIFYEXEC(Sink::ResourceControl::flushReplayQueue(mResourceInstanceIdentifier)); 406 VERIFYEXEC(Sink::ResourceControl::flushReplayQueue(mResourceInstanceIdentifier));
324 } 407 }
325 } 408 }
326 409
327 void testRemoveEvent()
328 {
329 VERIFYEXEC(Sink::Store::synchronize(Sink::Query().resourceFilter(mResourceInstanceIdentifier)));
330 VERIFYEXEC(Sink::ResourceControl::flushMessageQueue(mResourceInstanceIdentifier));
331
332 auto job = Sink::Store::fetchOne<Event>(
333 Sink::Query().filter("uid", Sink::Query::Comparator(addedEventUid)))
334 .exec();
335 job.waitForFinished();
336 QVERIFY2(!job.errorCode(), "Fetching Event failed");
337 auto event = job.value();
338
339 VERIFYEXEC(Sink::Store::remove(event));
340 VERIFYEXEC(Sink::ResourceControl::flushReplayQueue(mResourceInstanceIdentifier));
341
342 auto verifyEventCountJob = Sink::Store::fetchAll<Event>({}).then(
343 [](const QList<Event::Ptr> &events) { QCOMPARE(events.size(), 0); });
344 VERIFYEXEC(verifyEventCountJob);
345 }
346
347 void testRemoveTodo()
348 {
349 VERIFYEXEC(Sink::Store::synchronize(Sink::Query().resourceFilter(mResourceInstanceIdentifier)));
350 VERIFYEXEC(Sink::ResourceControl::flushMessageQueue(mResourceInstanceIdentifier));
351
352 auto job = Sink::Store::fetchOne<Todo>(
353 Sink::Query().filter("uid", Sink::Query::Comparator(addedTodoUid)))
354 .exec();
355 job.waitForFinished();
356 QVERIFY2(!job.errorCode(), "Fetching Todo failed");
357 auto todo = job.value();
358 410
359 VERIFYEXEC(Sink::Store::remove(todo));
360 VERIFYEXEC(Sink::ResourceControl::flushReplayQueue(mResourceInstanceIdentifier));
361
362 auto verifyTodoCountJob = Sink::Store::fetchAll<Todo>({}).then(
363 [](const QList<Todo::Ptr> &todos) { QCOMPARE(todos.size(), 0); });
364 VERIFYEXEC(verifyTodoCountJob);
365 }
366}; 411};
367 412
368QTEST_MAIN(CalDavTest) 413QTEST_MAIN(CalDavTest)
diff --git a/examples/carddavresource/CMakeLists.txt b/examples/carddavresource/CMakeLists.txt
index 0632804..97208b1 100644
--- a/examples/carddavresource/CMakeLists.txt
+++ b/examples/carddavresource/CMakeLists.txt
@@ -2,7 +2,7 @@ project(sink_resource_carddav)
2 2
3include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR}) 3include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR})
4 4
5find_package(KPimKDAV2 REQUIRED) 5find_package(KPimKDAV2 REQUIRED 0.2.0)
6 6
7add_library(${PROJECT_NAME} SHARED carddavresource.cpp) 7add_library(${PROJECT_NAME} SHARED carddavresource.cpp)
8target_link_libraries(${PROJECT_NAME} sink_webdav_common sink Qt5::Core Qt5::Network KPim::KDAV2) 8target_link_libraries(${PROJECT_NAME} sink_webdav_common sink Qt5::Core Qt5::Network KPim::KDAV2)
diff --git a/examples/carddavresource/tests/carddavtest.cpp b/examples/carddavresource/tests/carddavtest.cpp
index b0f41d1..1d6762d 100644
--- a/examples/carddavresource/tests/carddavtest.cpp
+++ b/examples/carddavresource/tests/carddavtest.cpp
@@ -11,6 +11,7 @@
11#include <KDAV2/DavUrl> 11#include <KDAV2/DavUrl>
12#include <KDAV2/DavItemCreateJob> 12#include <KDAV2/DavItemCreateJob>
13#include <KDAV2/DavCollectionsFetchJob> 13#include <KDAV2/DavCollectionsFetchJob>
14#include <KDAV2/DavCollectionCreateJob>
14#include <KDAV2/DavCollection> 15#include <KDAV2/DavCollection>
15#include <KContacts/Addressee> 16#include <KContacts/Addressee>
16#include <KContacts/VCardConverter> 17#include <KContacts/VCardConverter>
@@ -30,28 +31,28 @@ class CardDavTest : public QObject
30 resource.setProperty("server", "http://localhost/dav/addressbooks/user/doe"); 31 resource.setProperty("server", "http://localhost/dav/addressbooks/user/doe");
31 resource.setProperty("username", "doe"); 32 resource.setProperty("username", "doe");
32 Sink::SecretStore::instance().insert(resource.identifier(), "doe"); 33 Sink::SecretStore::instance().insert(resource.identifier(), "doe");
33 resource.setProperty("testmode", true);
34 return resource; 34 return resource;
35 } 35 }
36 36
37 37
38 QByteArray mResourceInstanceIdentifier; 38 QByteArray mResourceInstanceIdentifier;
39 39
40 void createContact(const QString &firstname, const QString &lastname) 40 void createContact(const QString &firstname, const QString &lastname, const QString &collectionName)
41 { 41 {
42 QUrl mainUrl(QStringLiteral("http://localhost/dav/addressbooks/user/doe")); 42 QUrl mainUrl(QStringLiteral("http://localhost/dav/addressbooks/user/doe"));
43 mainUrl.setUserName(QStringLiteral("doe")); 43 mainUrl.setUserName(QStringLiteral("doe"));
44 mainUrl.setPassword(QStringLiteral("doe")); 44 mainUrl.setPassword(QStringLiteral("doe"));
45 45
46
47 KDAV2::DavUrl davUrl(mainUrl, KDAV2::CardDav); 46 KDAV2::DavUrl davUrl(mainUrl, KDAV2::CardDav);
48 47
49 auto *job = new KDAV2::DavCollectionsFetchJob(davUrl); 48 auto *job = new KDAV2::DavCollectionsFetchJob(davUrl);
50 job->exec(); 49 job->exec();
51 50
52 const auto collectionUrl = [&] { 51 const auto collectionUrl = [&] {
53 if (!job->collections().isEmpty()) { 52 for (const auto &col : job->collections()) {
54 return job->collections().first().url().url(); 53 if (col.displayName() == collectionName) {
54 return col.url().url();
55 }
55 } 56 }
56 return QUrl{}; 57 return QUrl{};
57 }(); 58 }();
@@ -69,11 +70,33 @@ class CardDavTest : public QObject
69 } 70 }
70 } 71 }
71 72
73 void createCollection(const QString &name)
74 {
75 QUrl mainUrl(QStringLiteral("http://localhost/dav/addressbooks/user/doe/") + name);
76 mainUrl.setUserName(QStringLiteral("doe"));
77 mainUrl.setPassword(QStringLiteral("doe"));
78
79 KDAV2::DavUrl davUrl(mainUrl, KDAV2::CardDav);
80 KDAV2::DavCollection collection{davUrl, name, KDAV2::DavCollection::Contacts};
81
82 auto createJob = new KDAV2::DavCollectionCreateJob(collection);
83 createJob->exec();
84 if (createJob->error()) {
85 qWarning() << createJob->errorString();
86 }
87 }
88
89 void resetTestEnvironment()
90 {
91 system("resetmailbox.sh");
92 }
93
72private slots: 94private slots:
73 95
74 void initTestCase() 96 void initTestCase()
75 { 97 {
76 Sink::Test::initTest(); 98 Sink::Test::initTest();
99 resetTestEnvironment();
77 auto resource = createResource(); 100 auto resource = createResource();
78 QVERIFY(!resource.identifier().isEmpty()); 101 QVERIFY(!resource.identifier().isEmpty());
79 VERIFYEXEC(Sink::Store::create(resource)); 102 VERIFYEXEC(Sink::Store::create(resource));
@@ -90,10 +113,25 @@ private slots:
90 VERIFYEXEC(Sink::ResourceControl::start(mResourceInstanceIdentifier)); 113 VERIFYEXEC(Sink::ResourceControl::start(mResourceInstanceIdentifier));
91 } 114 }
92 115
116 void testSyncAddressbooks()
117 {
118 createCollection("addressbook2");
119
120 Sink::SyncScope scope;
121 scope.setType<Addressbook>();
122 scope.resourceFilter(mResourceInstanceIdentifier);
123
124 VERIFYEXEC(Sink::Store::synchronize(scope));
125 VERIFYEXEC(Sink::ResourceControl::flushMessageQueue(mResourceInstanceIdentifier));
126 const auto addressbooks = Sink::Store::read<Addressbook>(Sink::Query().resourceFilter(mResourceInstanceIdentifier));
127 QCOMPARE(addressbooks.size(), 2);
128 }
129
93 void testSyncContacts() 130 void testSyncContacts()
94 { 131 {
95 createContact("john", "doe"); 132 createContact("john", "doe", "personal");
96 createContact("jane", "doe"); 133 createContact("jane", "doe", "personal");
134 createContact("fred", "durst", "addressbook2");
97 Sink::SyncScope scope; 135 Sink::SyncScope scope;
98 scope.setType<Sink::ApplicationDomain::Contact>(); 136 scope.setType<Sink::ApplicationDomain::Contact>();
99 scope.resourceFilter(mResourceInstanceIdentifier); 137 scope.resourceFilter(mResourceInstanceIdentifier);
@@ -101,27 +139,24 @@ private slots:
101 VERIFYEXEC(Sink::Store::synchronize(scope)); 139 VERIFYEXEC(Sink::Store::synchronize(scope));
102 VERIFYEXEC(Sink::ResourceControl::flushMessageQueue(mResourceInstanceIdentifier)); 140 VERIFYEXEC(Sink::ResourceControl::flushMessageQueue(mResourceInstanceIdentifier));
103 const auto contacts = Sink::Store::read<Sink::ApplicationDomain::Contact>(Sink::Query().resourceFilter(mResourceInstanceIdentifier)); 141 const auto contacts = Sink::Store::read<Sink::ApplicationDomain::Contact>(Sink::Query().resourceFilter(mResourceInstanceIdentifier));
104 QCOMPARE(contacts.size(), 2); 142 QCOMPARE(contacts.size(), 3);
105 143
106 //Ensure a resync works 144 //Ensure a resync works
107 { 145 {
108 VERIFYEXEC(Sink::Store::synchronize(scope)); 146 VERIFYEXEC(Sink::Store::synchronize(scope));
109 VERIFYEXEC(Sink::ResourceControl::flushMessageQueue(mResourceInstanceIdentifier)); 147 VERIFYEXEC(Sink::ResourceControl::flushMessageQueue(mResourceInstanceIdentifier));
110 const auto contacts = Sink::Store::read<Sink::ApplicationDomain::Contact>(Sink::Query().resourceFilter(mResourceInstanceIdentifier)); 148 const auto contacts = Sink::Store::read<Sink::ApplicationDomain::Contact>(Sink::Query().resourceFilter(mResourceInstanceIdentifier));
111 QCOMPARE(contacts.size(), 2); 149 QCOMPARE(contacts.size(), 3);
112 } 150 }
113 }
114 151
115 void testSyncAddressbooks() 152 //Ensure a resync after another creation works
116 { 153 createContact("alf", "alf", "addressbook2");
117 Sink::SyncScope scope; 154 {
118 scope.setType<Addressbook>(); 155 VERIFYEXEC(Sink::Store::synchronize(scope));
119 scope.resourceFilter(mResourceInstanceIdentifier); 156 VERIFYEXEC(Sink::ResourceControl::flushMessageQueue(mResourceInstanceIdentifier));
120 157 const auto contacts = Sink::Store::read<Sink::ApplicationDomain::Contact>(Sink::Query().resourceFilter(mResourceInstanceIdentifier));
121 VERIFYEXEC(Sink::Store::synchronize(scope)); 158 QCOMPARE(contacts.size(), 4);
122 VERIFYEXEC(Sink::ResourceControl::flushMessageQueue(mResourceInstanceIdentifier)); 159 }
123 const auto addressbooks = Sink::Store::read<Addressbook>(Sink::Query().resourceFilter(mResourceInstanceIdentifier));
124 QCOMPARE(addressbooks.size(), 1);
125 } 160 }
126 161
127 void testAddContact() 162 void testAddContact()
diff --git a/examples/mailtransportresource/mailtransport.cpp b/examples/mailtransportresource/mailtransport.cpp
index ce24d7f..c455b7c 100644
--- a/examples/mailtransportresource/mailtransport.cpp
+++ b/examples/mailtransportresource/mailtransport.cpp
@@ -83,7 +83,7 @@ CurlVersionInfo getVersionInfo()
83bool sendMessageCurl(const char *to[], int numTos, 83bool sendMessageCurl(const char *to[], int numTos,
84 const char *cc[], int numCcs, 84 const char *cc[], int numCcs,
85 const char *msg, 85 const char *msg,
86 bool useTls, 86 bool useStarttls,
87 const char* from, 87 const char* from,
88 const char *username, const char *password, 88 const char *username, const char *password,
89 const char *server, bool verifyPeer, const QByteArray &cacert, QByteArray &errorMessage, 89 const char *server, bool verifyPeer, const QByteArray &cacert, QByteArray &errorMessage,
@@ -107,7 +107,7 @@ bool sendMessageCurl(const char *to[], int numTos,
107 107
108 curl_easy_setopt(curl, CURLOPT_URL, server); 108 curl_easy_setopt(curl, CURLOPT_URL, server);
109 109
110 if (useTls) { 110 if (useStarttls) {
111 curl_easy_setopt(curl, CURLOPT_USE_SSL, (long)CURLUSESSL_ALL); 111 curl_easy_setopt(curl, CURLOPT_USE_SSL, (long)CURLUSESSL_ALL);
112 } 112 }
113 113
@@ -186,6 +186,7 @@ MailTransport::SendResult MailTransport::sendMessage(const KMime::Message::Ptr &
186 ccList << mb.address(); 186 ccList << mb.address();
187 } 187 }
188 const bool verifyPeer = options.testFlag(VerifyPeers); 188 const bool verifyPeer = options.testFlag(VerifyPeers);
189 const bool useStarttls = options.testFlag(UseStarttls);
189 const bool useTls = options.testFlag(UseTls); 190 const bool useTls = options.testFlag(UseTls);
190 191
191 const int numTos = toList.size(); 192 const int numTos = toList.size();
@@ -199,12 +200,21 @@ MailTransport::SendResult MailTransport::sendMessage(const KMime::Message::Ptr &
199 for (int i = 0; i < numCcs; i++) { 200 for (int i = 0; i < numCcs; i++) {
200 cc[i] = ccList.at(i); 201 cc[i] = ccList.at(i);
201 } 202 }
202 //Because curl will fail with smtps, but it won't tell you why.
203 auto serverAddress = server; 203 auto serverAddress = server;
204 serverAddress.replace("smtps://", "smtp://"); 204 if (serverAddress.startsWith("smtps://")) {
205 serverAddress = serverAddress.mid(8);
206 }
207 if (serverAddress.startsWith("smtp://")) {
208 serverAddress = serverAddress.mid(7);
209 }
210 if (useStarttls) {
211 serverAddress = "smtp://" + serverAddress;
212 } else if (useTls) {
213 serverAddress = "smtps://" + serverAddress;
214 }
205 215
206 const auto versionInfo = getVersionInfo(); 216 const auto versionInfo = getVersionInfo();
207 if (useTls && !versionInfo.supportsSsl) { 217 if ((useTls || useStarttls) && !versionInfo.supportsSsl) {
208 qCWarning(mailtransportCategory) << "libcurl built without ssl support: " << versionInfo.info; 218 qCWarning(mailtransportCategory) << "libcurl built without ssl support: " << versionInfo.info;
209 } 219 }
210 220
@@ -212,7 +222,7 @@ MailTransport::SendResult MailTransport::sendMessage(const KMime::Message::Ptr &
212 QByteArray errorMessage; 222 QByteArray errorMessage;
213 auto ret = sendMessageCurl(to, numTos, cc, numCcs, 223 auto ret = sendMessageCurl(to, numTos, cc, numCcs,
214 message->encodedContent(), 224 message->encodedContent(),
215 useTls, 225 useStarttls,
216 from.isEmpty() ? nullptr : from, 226 from.isEmpty() ? nullptr : from,
217 username, password, 227 username, password,
218 serverAddress, verifyPeer, cacert, 228 serverAddress, verifyPeer, cacert,
diff --git a/examples/mailtransportresource/mailtransport.h b/examples/mailtransportresource/mailtransport.h
index 0fa5a66..0f53c2b 100644
--- a/examples/mailtransportresource/mailtransport.h
+++ b/examples/mailtransportresource/mailtransport.h
@@ -27,7 +27,8 @@ namespace MailTransport
27{ 27{
28 enum Option { 28 enum Option {
29 UseTls = 1, 29 UseTls = 1,
30 VerifyPeers = 2 30 UseStarttls = 2,
31 VerifyPeers = 4
31 }; 32 };
32 Q_DECLARE_FLAGS(Options, Option); 33 Q_DECLARE_FLAGS(Options, Option);
33 34
diff --git a/examples/mailtransportresource/mailtransportresource.cpp b/examples/mailtransportresource/mailtransportresource.cpp
index 10d94bc..9163d3b 100644
--- a/examples/mailtransportresource/mailtransportresource.cpp
+++ b/examples/mailtransportresource/mailtransportresource.cpp
@@ -127,7 +127,11 @@ public:
127 } else { 127 } else {
128 MailTransport::Options options; 128 MailTransport::Options options;
129 if (settings.server.contains("smtps")) { 129 if (settings.server.contains("smtps")) {
130 options |= MailTransport::UseTls; 130 if (settings.server.contains("465")) {
131 options |= MailTransport::UseTls;
132 } else {
133 options |= MailTransport::UseStarttls;
134 }
131 } 135 }
132 136
133 SinkLog() << "Sending message " << settings.server << settings.username << "CaCert: " << settings.cacert << "Using tls: " << bool(options & MailTransport::UseTls); 137 SinkLog() << "Sending message " << settings.server << settings.username << "CaCert: " << settings.cacert << "Using tls: " << bool(options & MailTransport::UseTls);
diff --git a/examples/webdavcommon/CMakeLists.txt b/examples/webdavcommon/CMakeLists.txt
index c4e99f2..51bf151 100644
--- a/examples/webdavcommon/CMakeLists.txt
+++ b/examples/webdavcommon/CMakeLists.txt
@@ -2,7 +2,7 @@ project(sink_webdav_common)
2 2
3set(CMAKE_CXX_STANDARD 14) 3set(CMAKE_CXX_STANDARD 14)
4 4
5find_package(KPimKDAV2 REQUIRED) 5find_package(KPimKDAV2 REQUIRED 0.2.0)
6 6
7add_library(${PROJECT_NAME} STATIC webdav.cpp) 7add_library(${PROJECT_NAME} STATIC webdav.cpp)
8target_link_libraries(${PROJECT_NAME} Qt5::Core Qt5::Network KPim::KDAV2 sink) 8target_link_libraries(${PROJECT_NAME} Qt5::Core Qt5::Network KPim::KDAV2 sink)
diff --git a/examples/webdavcommon/webdav.cpp b/examples/webdavcommon/webdav.cpp
index 904e1e2..0dfb6c0 100644
--- a/examples/webdavcommon/webdav.cpp
+++ b/examples/webdavcommon/webdav.cpp
@@ -89,11 +89,11 @@ static KAsync::Job<T> runJob(KJob *job, const std::function<T(KJob *)> &func)
89} 89}
90 90
91WebDavSynchronizer::WebDavSynchronizer(const Sink::ResourceContext &context, 91WebDavSynchronizer::WebDavSynchronizer(const Sink::ResourceContext &context,
92 KDAV2::Protocol protocol, QByteArray collectionName, QByteArray itemName) 92 KDAV2::Protocol protocol, QByteArray mCollectionType, QByteArray mEntityType)
93 : Sink::Synchronizer(context), 93 : Sink::Synchronizer(context),
94 protocol(protocol), 94 protocol(protocol),
95 collectionName(std::move(collectionName)), 95 mCollectionType(std::move(mCollectionType)),
96 itemName(std::move(itemName)) 96 mEntityType(std::move(mEntityType))
97{ 97{
98 auto config = ResourceConfig::getConfiguration(context.instanceId()); 98 auto config = ResourceConfig::getConfiguration(context.instanceId());
99 99
@@ -111,15 +111,16 @@ QList<Sink::Synchronizer::SyncRequest> WebDavSynchronizer::getSyncRequests(const
111 // We want to synchronize everything 111 // We want to synchronize everything
112 112
113 // Item synchronization does the collections anyway 113 // Item synchronization does the collections anyway
114 // list << Synchronizer::SyncRequest{ Sink::QueryBase(collectionName) }; 114 // list << Synchronizer::SyncRequest{ Sink::QueryBase(mCollectionType) };
115 list << Synchronizer::SyncRequest{ Sink::QueryBase(itemName) }; 115 list << Synchronizer::SyncRequest{ Sink::QueryBase(mEntityType) };
116 } 116 }
117 return list; 117 return list;
118} 118}
119 119
120KAsync::Job<void> WebDavSynchronizer::synchronizeWithSource(const Sink::QueryBase &query) 120KAsync::Job<void> WebDavSynchronizer::synchronizeWithSource(const Sink::QueryBase &query)
121{ 121{
122 if (query.type() != collectionName && query.type() != itemName) { 122 if (query.type() != mCollectionType && query.type() != mEntityType) {
123 SinkWarning() << "Received synchronization reuqest with unkown type" << query;
123 return KAsync::null<void>(); 124 return KAsync::null<void>();
124 } 125 }
125 126
@@ -133,10 +134,10 @@ KAsync::Job<void> WebDavSynchronizer::synchronizeWithSource(const Sink::QueryBas
133 return collections; 134 return collections;
134 }); 135 });
135 136
136 if (query.type() == collectionName) { 137 if (query.type() == mCollectionType) {
137 // Do nothing more 138 // Do nothing more
138 return job; 139 return job;
139 } else if (query.type() == itemName) { 140 } else if (query.type() == mEntityType) {
140 auto progress = QSharedPointer<int>::create(0); 141 auto progress = QSharedPointer<int>::create(0);
141 auto total = QSharedPointer<int>::create(0); 142 auto total = QSharedPointer<int>::create(0);
142 143
@@ -156,17 +157,24 @@ KAsync::Job<void> WebDavSynchronizer::synchronizeWithSource(const Sink::QueryBas
156 return KAsync::null<void>(); 157 return KAsync::null<void>();
157 } 158 }
158 159
159 SinkTrace() << "Syncing collection:" << collectionResourceID; 160 SinkTrace() << "Syncing collection:" << collectionResourceID << collection.displayName();
160 auto itemsResourceIDs = QSharedPointer<QSet<QByteArray>>::create(); 161 auto itemsResourceIDs = QSharedPointer<QSet<QByteArray>>::create();
161 return synchronizeCollection(collection, progress, total, itemsResourceIDs) 162 return synchronizeCollection(collection, progress, total, itemsResourceIDs)
162 .then([=] { 163 .then([=] {
163 scanForRemovals(itemName, [&itemsResourceIDs](const QByteArray &remoteId) { 164 const auto collectionLocalId = collectionLocalResourceID(collection);
164 return itemsResourceIDs->contains(remoteId); 165 scanForRemovals(mEntityType,
165 }); 166 [&](const std::function<void(const QByteArray &)> &callback) {
167 //FIXME: The collection type just happens to have the same name as the parent collection property
168 const auto collectionProperty = mCollectionType;
169 store().indexLookup(mEntityType, collectionProperty, collectionLocalId, callback);
170 },
171 [&itemsResourceIDs](const QByteArray &remoteId) {
172 return itemsResourceIDs->contains(remoteId);
173 });
166 }); 174 });
167 }) 175 })
168 .then([=]() { 176 .then([=]() {
169 scanForRemovals(collectionName, [&collectionResourceIDs](const QByteArray &remoteId) { 177 scanForRemovals(mCollectionType, [&collectionResourceIDs](const QByteArray &remoteId) {
170 return collectionResourceIDs->contains(remoteId); 178 return collectionResourceIDs->contains(remoteId);
171 }); 179 });
172 }); 180 });
diff --git a/examples/webdavcommon/webdav.h b/examples/webdavcommon/webdav.h
index 813da60..af6c47e 100644
--- a/examples/webdavcommon/webdav.h
+++ b/examples/webdavcommon/webdav.h
@@ -109,8 +109,8 @@ protected:
109 109
110private: 110private:
111 KDAV2::Protocol protocol; 111 KDAV2::Protocol protocol;
112 const QByteArray collectionName; 112 const QByteArray mCollectionType;
113 const QByteArray itemName; 113 const QByteArray mEntityType;
114 114
115 QUrl mServer; 115 QUrl mServer;
116 QString mUsername; 116 QString mUsername;
diff --git a/tests/dbwriter.cpp b/tests/dbwriter.cpp
index 3045eac..a25faec 100644
--- a/tests/dbwriter.cpp
+++ b/tests/dbwriter.cpp
@@ -29,14 +29,14 @@ int main(int argc, char *argv[])
29 qWarning() << "No valid transaction"; 29 qWarning() << "No valid transaction";
30 return -1; 30 return -1;
31 } 31 }
32 transaction.openDatabase("a", nullptr, false).write(QByteArray::number(i), "a"); 32 transaction.openDatabase("a", nullptr, 0).write(QByteArray::number(i), "a");
33 transaction.openDatabase("b", nullptr, false).write(QByteArray::number(i), "b"); 33 transaction.openDatabase("b", nullptr, 0).write(QByteArray::number(i), "b");
34 transaction.openDatabase("c", nullptr, false).write(QByteArray::number(i), "c"); 34 transaction.openDatabase("c", nullptr, 0).write(QByteArray::number(i), "c");
35 transaction.openDatabase("p", nullptr, false).write(QByteArray::number(i), "c"); 35 transaction.openDatabase("p", nullptr, 0).write(QByteArray::number(i), "c");
36 transaction.openDatabase("q", nullptr, false).write(QByteArray::number(i), "c"); 36 transaction.openDatabase("q", nullptr, 0).write(QByteArray::number(i), "c");
37 if (i > (count/2)) { 37 if (i > (count/2)) {
38 for (int d = 0; d < 40; d++) { 38 for (int d = 0; d < 40; d++) {
39 transaction.openDatabase("db" + QByteArray::number(d), nullptr, false).write(QByteArray::number(i), "a"); 39 transaction.openDatabase("db" + QByteArray::number(d), nullptr, 0).write(QByteArray::number(i), "a");
40 } 40 }
41 } 41 }
42 if ((i % 1000) == 0) { 42 if ((i % 1000) == 0) {
diff --git a/tests/pipelinetest.cpp b/tests/pipelinetest.cpp
index 34ee3a5..801a9e0 100644
--- a/tests/pipelinetest.cpp
+++ b/tests/pipelinetest.cpp
@@ -32,10 +32,10 @@ static QList<Sink::Storage::Key> getKeys(const QByteArray &dbEnv, const QByteArr
32{ 32{
33 Sink::Storage::DataStore store(Sink::storageLocation(), dbEnv, Sink::Storage::DataStore::ReadOnly); 33 Sink::Storage::DataStore store(Sink::storageLocation(), dbEnv, Sink::Storage::DataStore::ReadOnly);
34 auto transaction = store.createTransaction(Sink::Storage::DataStore::ReadOnly); 34 auto transaction = store.createTransaction(Sink::Storage::DataStore::ReadOnly);
35 auto db = transaction.openDatabase(name, nullptr, false); 35 auto db = transaction.openDatabase(name, nullptr, Sink::Storage::IntegerKeys);
36 QList<Sink::Storage::Key> result; 36 QList<Sink::Storage::Key> result;
37 db.scan("", [&](const QByteArray &key, const QByteArray &value) { 37 db.scan("", [&](const QByteArray &key, const QByteArray &value) {
38 size_t revision = Sink::byteArrayToSizeT(value); 38 size_t revision = Sink::byteArrayToSizeT(key);
39 result << Sink::Storage::Key(Sink::Storage::Identifier::fromDisplayByteArray( 39 result << Sink::Storage::Key(Sink::Storage::Identifier::fromDisplayByteArray(
40 Sink::Storage::DataStore::getUidFromRevision(transaction, revision)), 40 Sink::Storage::DataStore::getUidFromRevision(transaction, revision)),
41 revision); 41 revision);
@@ -48,7 +48,7 @@ static QByteArray getEntity(const QByteArray &dbEnv, const QByteArray &name, con
48{ 48{
49 Sink::Storage::DataStore store(Sink::storageLocation(), dbEnv, Sink::Storage::DataStore::ReadOnly); 49 Sink::Storage::DataStore store(Sink::storageLocation(), dbEnv, Sink::Storage::DataStore::ReadOnly);
50 auto transaction = store.createTransaction(Sink::Storage::DataStore::ReadOnly); 50 auto transaction = store.createTransaction(Sink::Storage::DataStore::ReadOnly);
51 auto db = transaction.openDatabase(name, nullptr, false); 51 auto db = transaction.openDatabase(name, nullptr, Sink::Storage::IntegerKeys);
52 QByteArray result; 52 QByteArray result;
53 db.scan(key.revision().toSizeT(), [&](size_t rev, const QByteArray &value) { 53 db.scan(key.revision().toSizeT(), [&](size_t rev, const QByteArray &value) {
54 result = value; 54 result = value;