summaryrefslogtreecommitdiffstats
path: root/examples/davresource/davresource.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'examples/davresource/davresource.cpp')
-rw-r--r--examples/davresource/davresource.cpp402
1 files changed, 65 insertions, 337 deletions
diff --git a/examples/davresource/davresource.cpp b/examples/davresource/davresource.cpp
index de4c0b0..50471ed 100644
--- a/examples/davresource/davresource.cpp
+++ b/examples/davresource/davresource.cpp
@@ -21,10 +21,8 @@
21 21
22#include "facade.h" 22#include "facade.h"
23#include "resourceconfig.h" 23#include "resourceconfig.h"
24#include "index.h"
25#include "log.h" 24#include "log.h"
26#include "definitions.h" 25#include "definitions.h"
27#include "inspection.h"
28#include "synchronizer.h" 26#include "synchronizer.h"
29#include "inspector.h" 27#include "inspector.h"
30 28
@@ -40,181 +38,14 @@
40#include <KDAV/DavItemFetchJob> 38#include <KDAV/DavItemFetchJob>
41#include <KDAV/EtagCache> 39#include <KDAV/EtagCache>
42 40
43#include <QDir>
44#include <QDirIterator>
45
46//This is the resources entity type, and not the domain type 41//This is the resources entity type, and not the domain type
47#define ENTITY_TYPE_CONTACT "contact" 42#define ENTITY_TYPE_CONTACT "contact"
48#define ENTITY_TYPE_ADDRESSBOOK "folder" 43#define ENTITY_TYPE_ADDRESSBOOK "addressbook"
49 44
50SINK_DEBUG_AREA("davresource") 45SINK_DEBUG_AREA("davresource")
51 46
52using namespace Sink; 47using namespace Sink;
53 48
54/*static QString getFilePathFromMimeMessagePath(const QString &mimeMessagePath)
55{
56 auto parts = mimeMessagePath.split('/');
57 const auto key = parts.takeLast();
58 const auto path = parts.join("/") + "/cur/";
59
60 QDir dir(path);
61 const QFileInfoList list = dir.entryInfoList(QStringList() << (key+"*"), QDir::Files);
62 if (list.size() != 1) {
63 SinkWarning() << "Failed to find message " << mimeMessagePath;
64 SinkWarning() << "Failed to find message " << path;
65 return QString();
66 }
67 return list.first().filePath();
68}
69
70class MaildirMailPropertyExtractor : public MailPropertyExtractor
71{
72protected:
73 virtual QString getFilePathFromMimeMessagePath(const QString &mimeMessagePath) const Q_DECL_OVERRIDE
74 {
75 return ::getFilePathFromMimeMessagePath(mimeMessagePath);
76 }
77};
78
79class MaildirMimeMessageMover : public Sink::Preprocessor
80{
81public:
82 MaildirMimeMessageMover(const QByteArray &resourceInstanceIdentifier, const QString &maildirPath) : mResourceInstanceIdentifier(resourceInstanceIdentifier), mMaildirPath(maildirPath) {}
83
84 QString getPath(const QByteArray &folderIdentifier)
85 {
86 if (folderIdentifier.isEmpty()) {
87 return mMaildirPath;
88 }
89 QString folderPath;
90 const auto folder = entityStore().readLatest<ApplicationDomain::Folder>(folderIdentifier);
91 if (mMaildirPath.endsWith(folder.getName())) {
92 folderPath = mMaildirPath;
93 } else {
94 auto folderName = folder.getName();
95 //FIXME handle non toplevel folders
96 folderPath = mMaildirPath + "/" + folderName;
97 }
98 return folderPath;
99 }
100
101 QString moveMessage(const QString &oldPath, const QByteArray &folder)
102 {
103 if (oldPath.startsWith(Sink::temporaryFileLocation())) {
104 const auto path = getPath(folder);
105 KPIM::Contactdir maildir(path, false);
106 if (!maildir.isValid(true)) {
107 SinkWarning() << "Maildir is not existing: " << path;
108 }
109 auto identifier = maildir.addEntryFromPath(oldPath);
110 return path + "/" + identifier;
111 } else {
112 //Handle moves
113 const auto path = getPath(folder);
114 KPIM::Contactdir maildir(path, false);
115 if (!maildir.isValid(true)) {
116 SinkWarning() << "Maildir is not existing: " << path;
117 }
118 auto oldIdentifier = KPIM::Contactdir::getKeyFromFile(oldPath);
119 auto pathParts = oldPath.split('/');
120 pathParts.takeLast();
121 auto oldDirectory = pathParts.join('/');
122 if (oldDirectory == path) {
123 return oldPath;
124 }
125 KPIM::Contactdir oldMaildir(oldDirectory, false);
126 if (!oldMaildir.isValid(false)) {
127 SinkWarning() << "Maildir is not existing: " << path;
128 }
129 auto identifier = oldMaildir.moveEntryTo(oldIdentifier, maildir);
130 return path + "/" + identifier;
131 }
132 }
133
134 void newEntity(Sink::ApplicationDomain::ApplicationDomainType &newEntity) Q_DECL_OVERRIDE
135 {
136 auto mail = newEntity.cast<ApplicationDomain::Contact>();
137 const auto mimeMessage = mail.getMimeMessagePath();
138 if (!mimeMessage.isNull()) {
139 const auto path = moveMessage(mimeMessage, mail.getFolder());
140 auto blob = ApplicationDomain::BLOB{path};
141 blob.isExternal = false;
142 mail.setProperty(ApplicationDomain::Contact::MimeMessage::name, QVariant::fromValue(blob));
143 }
144 }
145
146 void modifiedEntity(const Sink::ApplicationDomain::ApplicationDomainType &oldEntity, Sink::ApplicationDomain::ApplicationDomainType &newEntity) Q_DECL_OVERRIDE
147 {
148 auto newMail = newEntity.cast<ApplicationDomain::Contact>();
149 const ApplicationDomain::Contact oldMail{oldEntity};
150 const auto mimeMessage = newMail.getMimeMessagePath();
151 const auto newFolder = newMail.getFolder();
152 const bool mimeMessageChanged = !mimeMessage.isNull() && mimeMessage != oldMail.getMimeMessagePath();
153 const bool folderChanged = !newFolder.isNull() && newFolder != oldMail.getFolder();
154 if (mimeMessageChanged || folderChanged) {
155 SinkTrace() << "Moving mime message: " << mimeMessageChanged << folderChanged;
156 auto newPath = moveMessage(mimeMessage, newMail.getFolder());
157 if (newPath != oldMail.getMimeMessagePath()) {
158 const auto oldPath = getFilePathFromMimeMessagePath(oldMail.getMimeMessagePath());
159 auto blob = ApplicationDomain::BLOB{newPath};
160 blob.isExternal = false;
161 newMail.setProperty(ApplicationDomain::Contact::MimeMessage::name, QVariant::fromValue(blob));
162 //Remove the olde mime message if there is a new one
163 QFile::remove(oldPath);
164 }
165 }
166
167 auto mimeMessagePath = newMail.getMimeMessagePath();
168 const auto maildirPath = getPath(newMail.getFolder());
169 KPIM::Contactdir maildir(maildirPath, false);
170 const auto file = getFilePathFromMimeMessagePath(mimeMessagePath);
171 QString identifier = KPIM::Contactdir::getKeyFromFile(file);
172
173 //get flags from
174 KPIM::Contactdir::Flags flags;
175 if (!newMail.getUnread()) {
176 flags |= KPIM::Contactdir::Seen;
177 }
178 if (newMail.getImportant()) {
179 flags |= KPIM::Contactdir::Flagged;
180 }
181
182 maildir.changeEntryFlags(identifier, flags);
183 }
184
185 void deletedEntity(const Sink::ApplicationDomain::ApplicationDomainType &oldEntity) Q_DECL_OVERRIDE
186 {
187 const ApplicationDomain::Contact oldMail{oldEntity};
188 const auto filePath = getFilePathFromMimeMessagePath(oldMail.getMimeMessagePath());
189 QFile::remove(filePath);
190 }
191 QByteArray mResourceInstanceIdentifier;
192 QString mMaildirPath;
193};
194
195class FolderPreprocessor : public Sink::Preprocessor
196{
197public:
198 FolderPreprocessor(const QString maildirPath) : mMaildirPath(maildirPath) {}
199
200 void newEntity(Sink::ApplicationDomain::ApplicationDomainType &newEntity) Q_DECL_OVERRIDE
201 {
202 auto folderName = Sink::ApplicationDomain::Folder{newEntity}.getName();
203 const auto path = mMaildirPath + "/" + folderName;
204 KPIM::Contactdir maildir(path, false);
205 maildir.create();
206 }
207
208 void modifiedEntity(const Sink::ApplicationDomain::ApplicationDomainType &oldEntity, Sink::ApplicationDomain::ApplicationDomainType &newEntity) Q_DECL_OVERRIDE
209 {
210 }
211
212 void deletedEntity(const Sink::ApplicationDomain::ApplicationDomainType &oldEntity) Q_DECL_OVERRIDE
213 {
214 }
215 QString mMaildirPath;
216};*/
217
218static KAsync::Job<void> runJob(KJob *job) 49static KAsync::Job<void> runJob(KJob *job)
219{ 50{
220 return KAsync::start<void>([job](KAsync::Future<void> &future) { 51 return KAsync::start<void>([job](KAsync::Future<void> &future) {
@@ -240,33 +71,33 @@ public:
240 71
241 } 72 }
242 73
243 QByteArray createAddressbook(const QString &folderName, const QString &folderPath, const QString &parentFolderRid, const QByteArray &icon) 74 QByteArray createAddressbook(const QString &addressbookName, const QString &addressbookPath, const QString &parentAddressbookRid)
244 { 75 {
245 SinkTrace() << "Creating addressbook: " << folderName << parentFolderRid; 76 SinkTrace() << "Creating addressbook: " << addressbookName << parentAddressbookRid;
246 const auto remoteId = folderPath.toUtf8(); 77 const auto remoteId = addressbookPath.toUtf8();
247 const auto bufferType = ENTITY_TYPE_ADDRESSBOOK; 78 const auto bufferType = ENTITY_TYPE_ADDRESSBOOK;
248 Sink::ApplicationDomain::Folder folder; 79 Sink::ApplicationDomain::Addressbook addressbook;
249 folder.setName(folderName); 80 addressbook.setName(addressbookName);
250 folder.setIcon(icon);
251 QHash<QByteArray, Query::Comparator> mergeCriteria; 81 QHash<QByteArray, Query::Comparator> mergeCriteria;
252 82
253 if (!parentFolderRid.isEmpty()) { 83 if (!parentAddressbookRid.isEmpty()) {
254 folder.setParent(syncStore().resolveRemoteId(ENTITY_TYPE_ADDRESSBOOK, parentFolderRid.toUtf8())); 84 addressbook.setParent(syncStore().resolveRemoteId(ENTITY_TYPE_ADDRESSBOOK, parentAddressbookRid.toUtf8()));
255 } 85 }
256 createOrModify(bufferType, remoteId, folder, mergeCriteria); 86 createOrModify(bufferType, remoteId, addressbook, mergeCriteria);
257 return remoteId; 87 return remoteId;
258 } 88 }
259 89
260 void synchronizeAddressbooks(const KDAV::DavCollection::List &folderList) 90 void synchronizeAddressbooks(const KDAV::DavCollection::List &addressbookList)
261 { 91 {
262 const QByteArray bufferType = ENTITY_TYPE_ADDRESSBOOK; 92 const QByteArray bufferType = ENTITY_TYPE_ADDRESSBOOK;
263 SinkTrace() << "Found addressbooks " << folderList.size(); 93 SinkTrace() << "Found addressbooks " << addressbookList.size();
264 94
265 QVector<QByteArray> ridList; 95 QVector<QByteArray> ridList;
266 for(const auto &f : folderList) { 96 for(const auto &f : addressbookList) {
267 const auto &rid = f.url().toDisplayString(); 97 const auto &rid = getRid(f);
268 ridList.append(rid.toUtf8()); 98 SinkTrace() << "Found addressbook:" << rid;
269 createAddressbook(f.displayName(), rid, "", "addressbook"); 99 ridList.append(rid);
100 createAddressbook(f.displayName(), rid, "");
270 } 101 }
271 102
272 scanForRemovals(bufferType, 103 scanForRemovals(bufferType,
@@ -284,54 +115,73 @@ public:
284 list << Synchronizer::SyncRequest{query}; 115 list << Synchronizer::SyncRequest{query};
285 } else { 116 } else {
286 //We want to synchronize everything 117 //We want to synchronize everything
118 list << Synchronizer::SyncRequest{Sink::QueryBase(ApplicationDomain::getTypeName<ApplicationDomain::Addressbook>())};
287 list << Synchronizer::SyncRequest{Sink::QueryBase(ApplicationDomain::getTypeName<ApplicationDomain::Contact>())}; 119 list << Synchronizer::SyncRequest{Sink::QueryBase(ApplicationDomain::getTypeName<ApplicationDomain::Contact>())};
288 } 120 }
289 return list; 121 return list;
290 } 122 }
291 123
124 static QByteArray getRid(const KDAV::DavItem &item)
125 {
126 return item.url().toDisplayString().toUtf8();
127 }
128
129 static QByteArray getRid(const KDAV::DavCollection &item)
130 {
131 return item.url().toDisplayString().toUtf8();
132 }
133
292 KAsync::Job<void> synchronizeWithSource(const Sink::QueryBase &query) Q_DECL_OVERRIDE 134 KAsync::Job<void> synchronizeWithSource(const Sink::QueryBase &query) Q_DECL_OVERRIDE
293 { 135 {
294 if (query.type() == ApplicationDomain::getTypeName<ApplicationDomain::Folder>()) { 136 if (query.type() == ApplicationDomain::getTypeName<ApplicationDomain::Addressbook>()) {
137 SinkLogCtx(mLogCtx) << "Synchronizing addressbooks:" << mResourceUrl.url();
295 auto collectionsFetchJob = new KDAV::DavCollectionsFetchJob(mResourceUrl); 138 auto collectionsFetchJob = new KDAV::DavCollectionsFetchJob(mResourceUrl);
296 auto job = runJob(collectionsFetchJob).then<void>([this, collectionsFetchJob] { 139 auto job = runJob(collectionsFetchJob).then([this, collectionsFetchJob] (const KAsync::Error &error) {
297 synchronizeAddressbooks(collectionsFetchJob ->collections()); 140 if (error) {
141 SinkWarningCtx(mLogCtx) << "Failed to synchronize addressbooks." << collectionsFetchJob->errorString();
142 } else {
143 synchronizeAddressbooks(collectionsFetchJob ->collections());
144 }
298 }); 145 });
299 return job; 146 return job;
300 } else if (query.type() == ApplicationDomain::getTypeName<ApplicationDomain::Contact>()) { 147 } else if (query.type() == ApplicationDomain::getTypeName<ApplicationDomain::Contact>()) {
148 SinkLogCtx(mLogCtx) << "Synchronizing contacts.";
301 auto ridList = QSharedPointer<QByteArrayList>::create(); 149 auto ridList = QSharedPointer<QByteArrayList>::create();
302 auto collectionsFetchJob = new KDAV::DavCollectionsFetchJob(mResourceUrl); 150 auto collectionsFetchJob = new KDAV::DavCollectionsFetchJob(mResourceUrl);
303 auto job = runJob(collectionsFetchJob).then<KDAV::DavCollection::List>([this, collectionsFetchJob] { 151 auto job = runJob(collectionsFetchJob).then([this, collectionsFetchJob] {
304 synchronizeAddressbooks(collectionsFetchJob ->collections()); 152 synchronizeAddressbooks(collectionsFetchJob ->collections());
305 return collectionsFetchJob->collections(); 153 return collectionsFetchJob->collections();
306 }) 154 })
307 .serialEach<void>([this, ridList](const KDAV::DavCollection &collection) { 155 .serialEach([this, ridList](const KDAV::DavCollection &collection) {
308 auto collId = collection.url().toDisplayString().toLatin1(); 156 auto collId = getRid(collection);
157 const auto addressbookLocalId = syncStore().resolveRemoteId(ENTITY_TYPE_ADDRESSBOOK, collId);
309 auto ctag = collection.CTag().toLatin1(); 158 auto ctag = collection.CTag().toLatin1();
310 if (ctag != syncStore().readValue(collId + "_ctagXX")) { 159 if (ctag != syncStore().readValue(collId + "_ctagXX")) {
311 SinkTrace() << "Syncing " << collId; 160 SinkTraceCtx(mLogCtx) << "Syncing " << collId;
312 auto cache = std::shared_ptr<KDAV::EtagCache>(new KDAV::EtagCache()); 161 auto cache = std::shared_ptr<KDAV::EtagCache>(new KDAV::EtagCache());
313 auto davItemsListJob = new KDAV::DavItemsListJob(collection.url(), cache); 162 auto davItemsListJob = new KDAV::DavItemsListJob(collection.url(), cache);
314 const QByteArray bufferType = ENTITY_TYPE_CONTACT; 163 const QByteArray bufferType = ENTITY_TYPE_CONTACT;
315 QHash<QByteArray, Query::Comparator> mergeCriteria; 164 QHash<QByteArray, Query::Comparator> mergeCriteria;
316 auto colljob = runJob(davItemsListJob).then<KDAV::DavItem::List>([davItemsListJob] { 165 auto colljob = runJob(davItemsListJob).then([davItemsListJob] {
317 return KAsync::value(davItemsListJob->items()); 166 return KAsync::value(davItemsListJob->items());
318 }) 167 })
319 .serialEach<QByteArray>([this, ridList, bufferType, mergeCriteria] (const KDAV::DavItem &item) { 168 .serialEach([=] (const KDAV::DavItem &item) {
320 QByteArray rid = item.url().toDisplayString().toUtf8(); 169 QByteArray rid = getRid(item);
321 if (item.etag().toLatin1() != syncStore().readValue(rid + "_etag")){ 170 if (item.etag().toLatin1() != syncStore().readValue(rid + "_etag")){
322 SinkTrace() << "Updating " << rid; 171 SinkTrace() << "Updating " << rid;
323 auto davItemFetchJob = new KDAV::DavItemFetchJob(item); 172 auto davItemFetchJob = new KDAV::DavItemFetchJob(item);
324 auto itemjob = runJob(davItemFetchJob) 173 auto itemjob = runJob(davItemFetchJob)
325 .then<KDAV::DavItem>([this, davItemFetchJob, bufferType, mergeCriteria] { 174 .then([=] {
326 const auto item = davItemFetchJob->item(); 175 const auto item = davItemFetchJob->item();
327 const auto rid = item.url().toDisplayString().toUtf8(); 176 const auto rid = getRid(item);
328 Sink::ApplicationDomain::Contact contact; 177 Sink::ApplicationDomain::Contact contact;
329 contact.setVcard(item.data()); 178 contact.setVcard(item.data());
179 contact.setAddressbook(addressbookLocalId);
330 createOrModify(bufferType, rid, contact, mergeCriteria); 180 createOrModify(bufferType, rid, contact, mergeCriteria);
331 return item; 181 return item;
332 }) 182 })
333 .then<QByteArray>([this, ridList] (const KDAV::DavItem &item) { 183 .then([this, ridList] (const KDAV::DavItem &item) {
334 const auto rid = item.url().toDisplayString().toUtf8(); 184 const auto rid = getRid(item);
335 syncStore().writeValue(rid + "_etag", item.etag().toLatin1()); 185 syncStore().writeValue(rid + "_etag", item.etag().toLatin1());
336 ridList->append(rid); 186 ridList->append(rid);
337 return rid; 187 return rid;
@@ -342,11 +192,12 @@ public:
342 return KAsync::value(rid); 192 return KAsync::value(rid);
343 } 193 }
344 }) 194 })
345 .then<void>([this, collId, ctag] () { 195 .then([this, collId, ctag] () {
346 syncStore().writeValue(collId + "_ctag", ctag); 196 syncStore().writeValue(collId + "_ctag", ctag);
347 }); 197 });
348 return colljob; 198 return colljob;
349 } else { 199 } else {
200 SinkTraceCtx(mLogCtx) << "Collection unchanged: " << ctag;
350 // for(const auto &item : addressbook) { 201 // for(const auto &item : addressbook) {
351 // ridList->append(rid); 202 // ridList->append(rid);
352 // } 203 // }
@@ -367,43 +218,11 @@ public:
367 218
368KAsync::Job<QByteArray> replay(const ApplicationDomain::Contact &contact, Sink::Operation operation, const QByteArray &oldRemoteId, const QList<QByteArray> &changedProperties) Q_DECL_OVERRIDE 219KAsync::Job<QByteArray> replay(const ApplicationDomain::Contact &contact, Sink::Operation operation, const QByteArray &oldRemoteId, const QList<QByteArray> &changedProperties) Q_DECL_OVERRIDE
369 { 220 {
370 /*
371 if (operation == Sink::Operation_Creation) {
372 const auto remoteId = getFilePathFromMimeMessagePath(mail.getMimeMessagePath());
373 SinkTrace() << "Contact created: " << remoteId;
374 return KAsync::value(remoteId.toUtf8());
375 } else if (operation == Sink::Operation_Removal) {
376 SinkTrace() << "Removing a contact " << oldRemoteId;
377 return KAsync::null<QByteArray>();
378 } else if (operation == Sink::Operation_Modification) {
379 SinkTrace() << "Modifying a contact: " << oldRemoteId;
380 const auto remoteId = getFilePathFromMimeMessagePath(mail.getMimeMessagePath());
381 return KAsync::value(remoteId.toUtf8());
382 }*/
383 return KAsync::null<QByteArray>(); 221 return KAsync::null<QByteArray>();
384 } 222 }
385 223
386 KAsync::Job<QByteArray> replay(const ApplicationDomain::Folder &folder, Sink::Operation operation, const QByteArray &oldRemoteId, const QList<QByteArray> &changedProperties) Q_DECL_OVERRIDE 224 KAsync::Job<QByteArray> replay(const ApplicationDomain::Addressbook &addressbook, Sink::Operation operation, const QByteArray &oldRemoteId, const QList<QByteArray> &changedProperties) Q_DECL_OVERRIDE
387 { 225 {
388 /*
389 if (operation == Sink::Operation_Creation) {
390 auto folderName = folder.getName();
391 //FIXME handle non toplevel folders
392 auto path = mMaildirPath + "/" + folderName;
393 SinkTrace() << "Creating a new folder: " << path;
394 KPIM::Contactdir maildir(path, false);
395 maildir.create();
396 return KAsync::value(path.toUtf8());
397 } else if (operation == Sink::Operation_Removal) {
398 const auto path = oldRemoteId;
399 SinkTrace() << "Removing a folder: " << path;
400 KPIM::Contactdir maildir(path, false);
401 maildir.remove();
402 return KAsync::null<QByteArray>();
403 } else if (operation == Sink::Operation_Modification) {
404 SinkWarning() << "Folder modifications are not implemented";
405 return KAsync::value(oldRemoteId);
406 }*/
407 return KAsync::null<QByteArray>(); 226 return KAsync::null<QByteArray>();
408 } 227 }
409 228
@@ -411,109 +230,17 @@ public:
411 KDAV::DavUrl mResourceUrl; 230 KDAV::DavUrl mResourceUrl;
412}; 231};
413 232
414/*
415class MaildirInspector : public Sink::Inspector {
416public:
417 MaildirInspector(const Sink::ResourceContext &resourceContext)
418 : Sink::Inspector(resourceContext)
419 {
420
421 }
422protected:
423
424 KAsync::Job<void> inspect(int inspectionType, const QByteArray &inspectionId, const QByteArray &domainType, const QByteArray &entityId, const QByteArray &property, const QVariant &expectedValue) Q_DECL_OVERRIDE {
425 auto synchronizationStore = QSharedPointer<Sink::Storage::DataStore>::create(Sink::storageLocation(), mResourceContext.instanceId() + ".synchronization", Sink::Storage::DataStore::ReadOnly);
426 auto synchronizationTransaction = synchronizationStore->createTransaction(Sink::Storage::DataStore::ReadOnly);
427
428 auto mainStore = QSharedPointer<Sink::Storage::DataStore>::create(Sink::storageLocation(), mResourceContext.instanceId(), Sink::Storage::DataStore::ReadOnly);
429 auto transaction = mainStore->createTransaction(Sink::Storage::DataStore::ReadOnly);
430
431 Sink::Storage::EntityStore entityStore(mResourceContext, {"maildirresource"});
432 auto syncStore = QSharedPointer<SynchronizerStore>::create(synchronizationTransaction);
433
434 SinkTrace() << "Inspecting " << inspectionType << domainType << entityId << property << expectedValue;
435
436 if (domainType == ENTITY_TYPE_MAIL) {
437 auto mail = entityStore.readLatest<Sink::ApplicationDomain::Contact>(entityId);
438 const auto filePath = getFilePathFromMimeMessagePath(mail.getMimeMessagePath());
439
440 if (inspectionType == Sink::ResourceControl::Inspection::PropertyInspectionType) {
441 if (property == "unread") {
442 const auto flags = KPIM::Contactdir::readEntryFlags(filePath.split('/').last());
443 if (expectedValue.toBool() && (flags & KPIM::Contactdir::Seen)) {
444 return KAsync::error<void>(1, "Expected unread but couldn't find it.");
445 }
446 if (!expectedValue.toBool() && !(flags & KPIM::Contactdir::Seen)) {
447 return KAsync::error<void>(1, "Expected read but couldn't find it.");
448 }
449 return KAsync::null<void>();
450 }
451 if (property == "subject") {
452 KMime::Message *msg = new KMime::Message;
453 msg->setHead(KMime::CRLFtoLF(KPIM::Contactdir::readEntryHeadersFromFile(filePath)));
454 msg->parse();
455
456 if (msg->subject(true)->asUnicodeString() != expectedValue.toString()) {
457 return KAsync::error<void>(1, "Subject not as expected: " + msg->subject(true)->asUnicodeString());
458 }
459 return KAsync::null<void>();
460 }
461 }
462 if (inspectionType == Sink::ResourceControl::Inspection::ExistenceInspectionType) {
463 if (QFileInfo(filePath).exists() != expectedValue.toBool()) {
464 return KAsync::error<void>(1, "Wrong file existence: " + filePath);
465 }
466 }
467 }
468 if (domainType == ENTITY_TYPE_FOLDER) {
469 const auto remoteId = syncStore->resolveLocalId(ENTITY_TYPE_FOLDER, entityId);
470 auto folder = entityStore.readLatest<Sink::ApplicationDomain::Folder>(entityId);
471
472 if (inspectionType == Sink::ResourceControl::Inspection::CacheIntegrityInspectionType) {
473 SinkTrace() << "Inspecting cache integrity" << remoteId;
474 if (!QDir(remoteId).exists()) {
475 return KAsync::error<void>(1, "The directory is not existing: " + remoteId);
476 }
477
478 int expectedCount = 0;
479 Index index("mail.index.folder", transaction);
480 index.lookup(entityId, [&](const QByteArray &sinkId) {
481 expectedCount++;
482 },
483 [&](const Index::Error &error) {
484 SinkWarning() << "Error in index: " << error.message << property;
485 });
486
487 QDir dir(remoteId + "/cur");
488 const QFileInfoList list = dir.entryInfoList(QDir::Files);
489 if (list.size() != expectedCount) {
490 for (const auto &fileInfo : list) {
491 SinkWarning() << "Found in cache: " << fileInfo.fileName();
492 }
493 return KAsync::error<void>(1, QString("Wrong number of files; found %1 instead of %2.").arg(list.size()).arg(expectedCount));
494 }
495 }
496 if (inspectionType == Sink::ResourceControl::Inspection::ExistenceInspectionType) {
497 if (!remoteId.endsWith(folder.getName().toUtf8())) {
498 return KAsync::error<void>(1, "Wrong folder name: " + remoteId);
499 }
500 //TODO we shouldn't use the remoteId here to figure out the path, it could be gone/changed already
501 if (QDir(remoteId).exists() != expectedValue.toBool()) {
502 return KAsync::error<void>(1, "Wrong folder existence: " + remoteId);
503 }
504 }
505
506 }
507 return KAsync::null<void>();
508 }
509};*/
510
511 233
512DavResource::DavResource(const Sink::ResourceContext &resourceContext) 234DavResource::DavResource(const Sink::ResourceContext &resourceContext)
513 : Sink::GenericResource(resourceContext) 235 : Sink::GenericResource(resourceContext)
514{ 236{
237 /*
238 * Fork KIO slaves (used in kdav), instead of starting them via klauncher.
239 * Otherwise we have yet another runtime dependency that will i.e. not work in the docker container.
240 */
241 qputenv("KDE_FORK_SLAVES", "TRUE");
515 auto config = ResourceConfig::getConfiguration(resourceContext.instanceId()); 242 auto config = ResourceConfig::getConfiguration(resourceContext.instanceId());
516 auto resourceUrl = QUrl::fromUserInput(config.value("resourceUrl").toString()); 243 auto resourceUrl = QUrl::fromUserInput(config.value("server").toString());
517 resourceUrl.setUserName(config.value("username").toString()); 244 resourceUrl.setUserName(config.value("username").toString());
518 resourceUrl.setPassword(config.value("password").toString()); 245 resourceUrl.setPassword(config.value("password").toString());
519 246
@@ -522,7 +249,6 @@ DavResource::DavResource(const Sink::ResourceContext &resourceContext)
522 auto synchronizer = QSharedPointer<ContactSynchronizer>::create(resourceContext); 249 auto synchronizer = QSharedPointer<ContactSynchronizer>::create(resourceContext);
523 synchronizer->mResourceUrl = mResourceUrl; 250 synchronizer->mResourceUrl = mResourceUrl;
524 setupSynchronizer(synchronizer); 251 setupSynchronizer(synchronizer);
525 //setupInspector(QSharedPointer<MaildirInspector>::create(resourceContext));
526 252
527 setupPreprocessors(ENTITY_TYPE_CONTACT, QVector<Sink::Preprocessor*>() << new ContactPropertyExtractor); 253 setupPreprocessors(ENTITY_TYPE_CONTACT, QVector<Sink::Preprocessor*>() << new ContactPropertyExtractor);
528} 254}
@@ -530,7 +256,9 @@ DavResource::DavResource(const Sink::ResourceContext &resourceContext)
530 256
531DavResourceFactory::DavResourceFactory(QObject *parent) 257DavResourceFactory::DavResourceFactory(QObject *parent)
532 : Sink::ResourceFactory(parent, 258 : Sink::ResourceFactory(parent,
533 {"-folder.rename"} 259 {Sink::ApplicationDomain::ResourceCapabilities::Contact::contact,
260 Sink::ApplicationDomain::ResourceCapabilities::Contact::addressbook,
261 }
534 ) 262 )
535{ 263{
536} 264}
@@ -542,14 +270,14 @@ Sink::Resource *DavResourceFactory::createResource(const ResourceContext &contex
542 270
543void DavResourceFactory::registerFacades(const QByteArray &name, Sink::FacadeFactory &factory) 271void DavResourceFactory::registerFacades(const QByteArray &name, Sink::FacadeFactory &factory)
544{ 272{
545 factory.registerFacade<Sink::ApplicationDomain::Contact, DavResourceContactFacade>(name); 273 factory.registerFacade<ApplicationDomain::Contact, DefaultFacade<ApplicationDomain::Contact>>(name);
546 factory.registerFacade<Sink::ApplicationDomain::Folder, DavResourceFolderFacade>(name); 274 factory.registerFacade<ApplicationDomain::Addressbook, DefaultFacade<ApplicationDomain::Contact>>(name);
547} 275}
548 276
549void DavResourceFactory::registerAdaptorFactories(const QByteArray &name, Sink::AdaptorFactoryRegistry &registry) 277void DavResourceFactory::registerAdaptorFactories(const QByteArray &name, Sink::AdaptorFactoryRegistry &registry)
550{ 278{
551 registry.registerFactory<Sink::ApplicationDomain::Contact, ContactAdaptorFactory>(name); 279 registry.registerFactory<ApplicationDomain::Contact, DefaultAdaptorFactory<ApplicationDomain::Contact>>(name);
552 registry.registerFactory<Sink::ApplicationDomain::Folder, AddressbookAdaptorFactory>(name); 280 registry.registerFactory<ApplicationDomain::Addressbook, DefaultAdaptorFactory<ApplicationDomain::Addressbook>>(name);
553} 281}
554 282
555void DavResourceFactory::removeDataFromDisk(const QByteArray &instanceIdentifier) 283void DavResourceFactory::removeDataFromDisk(const QByteArray &instanceIdentifier)