summaryrefslogtreecommitdiffstats
path: root/examples/davresource
diff options
context:
space:
mode:
authorChristian Mollekopf <chrigi_1@fastmail.fm>2017-03-09 16:14:02 +0100
committerChristian Mollekopf <chrigi_1@fastmail.fm>2017-03-09 16:14:02 +0100
commit57a88e6c1514b85d25b066059defcd62d2ccd8d6 (patch)
treead41c8e9e4e6b59329e84c2151f24ba5a22eca64 /examples/davresource
parent45aaa4a4b2a0718d6e23dd5ac8a5c594d774e949 (diff)
downloadsink-57a88e6c1514b85d25b066059defcd62d2ccd8d6.tar.gz
sink-57a88e6c1514b85d25b066059defcd62d2ccd8d6.zip
Addressbook support
Diffstat (limited to 'examples/davresource')
-rw-r--r--examples/davresource/CMakeLists.txt6
-rw-r--r--examples/davresource/davresource.cpp374
-rw-r--r--examples/davresource/facade.cpp6
-rw-r--r--examples/davresource/facade.h6
4 files changed, 50 insertions, 342 deletions
diff --git a/examples/davresource/CMakeLists.txt b/examples/davresource/CMakeLists.txt
index c7899eb..f8cbdb4 100644
--- a/examples/davresource/CMakeLists.txt
+++ b/examples/davresource/CMakeLists.txt
@@ -3,7 +3,6 @@ project(sink_resource_dav)
3add_definitions(-DQT_PLUGIN) 3add_definitions(-DQT_PLUGIN)
4include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR}) 4include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR})
5 5
6find_package(KF5 COMPONENTS REQUIRED Mime)
7find_package(KPimKDAV REQUIRED) 6find_package(KPimKDAV REQUIRED)
8 7
9add_library(${PROJECT_NAME} SHARED facade.cpp davresource.cpp domainadaptor.cpp) 8add_library(${PROJECT_NAME} SHARED facade.cpp davresource.cpp domainadaptor.cpp)
@@ -11,8 +10,3 @@ qt5_use_modules(${PROJECT_NAME} Core Network)
11target_link_libraries(${PROJECT_NAME} sink KPim::KDAV) 10target_link_libraries(${PROJECT_NAME} sink KPim::KDAV)
12 11
13install(TARGETS ${PROJECT_NAME} LIBRARY DESTINATION ${SINK_RESOURCE_PLUGINS_PATH}) 12install(TARGETS ${PROJECT_NAME} LIBRARY DESTINATION ${SINK_RESOURCE_PLUGINS_PATH})
14
15#add_definitions(-DTESTDATAPATH="${CMAKE_CURRENT_SOURCE_DIR}/tests/data")
16
17#add_subdirectory(libmaildir)
18#add_subdirectory(tests)
diff --git a/examples/davresource/davresource.cpp b/examples/davresource/davresource.cpp
index df2c4b4..3d23a04 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,21 +115,32 @@ 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
287 list << Synchronizer::SyncRequest{Sink::QueryBase(ApplicationDomain::getTypeName<ApplicationDomain::Folder>())}; 118 list << Synchronizer::SyncRequest{Sink::QueryBase(ApplicationDomain::getTypeName<ApplicationDomain::Addressbook>())};
288 list << Synchronizer::SyncRequest{Sink::QueryBase(ApplicationDomain::getTypeName<ApplicationDomain::Contact>())}; 119 list << Synchronizer::SyncRequest{Sink::QueryBase(ApplicationDomain::getTypeName<ApplicationDomain::Contact>())};
289 } 120 }
290 return list; 121 return list;
291 } 122 }
292 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
293 KAsync::Job<void> synchronizeWithSource(const Sink::QueryBase &query) Q_DECL_OVERRIDE 134 KAsync::Job<void> synchronizeWithSource(const Sink::QueryBase &query) Q_DECL_OVERRIDE
294 { 135 {
295 if (query.type() == ApplicationDomain::getTypeName<ApplicationDomain::Folder>()) { 136 if (query.type() == ApplicationDomain::getTypeName<ApplicationDomain::Addressbook>()) {
296 SinkLogCtx(mLogCtx) << "Synchronizing folders:" << mResourceUrl.url(); 137 SinkLogCtx(mLogCtx) << "Synchronizing addressbooks:" << mResourceUrl.url();
297 auto collectionsFetchJob = new KDAV::DavCollectionsFetchJob(mResourceUrl); 138 auto collectionsFetchJob = new KDAV::DavCollectionsFetchJob(mResourceUrl);
298 auto job = runJob(collectionsFetchJob).then([this, collectionsFetchJob] (const KAsync::Error &error) { 139 auto job = runJob(collectionsFetchJob).then([this, collectionsFetchJob] (const KAsync::Error &error) {
299 if (error) { 140 if (error) {
300 SinkWarningCtx(mLogCtx) << "Failed to synchronize folders." << collectionsFetchJob->errorString(); 141 SinkWarningCtx(mLogCtx) << "Failed to synchronize addressbooks." << collectionsFetchJob->errorString();
301 } else { 142 } else {
143 SinkWarningCtx(mLogCtx) << "Fetched addressbooks." << collectionsFetchJob->errorString();
302 synchronizeAddressbooks(collectionsFetchJob ->collections()); 144 synchronizeAddressbooks(collectionsFetchJob ->collections());
303 } 145 }
304 }); 146 });
@@ -312,7 +154,8 @@ public:
312 return collectionsFetchJob->collections(); 154 return collectionsFetchJob->collections();
313 }) 155 })
314 .serialEach([this, ridList](const KDAV::DavCollection &collection) { 156 .serialEach([this, ridList](const KDAV::DavCollection &collection) {
315 auto collId = collection.url().toDisplayString().toLatin1(); 157 auto collId = getRid(collection);
158 const auto addressbookLocalId = syncStore().resolveRemoteId(ENTITY_TYPE_ADDRESSBOOK, collId);
316 auto ctag = collection.CTag().toLatin1(); 159 auto ctag = collection.CTag().toLatin1();
317 if (ctag != syncStore().readValue(collId + "_ctagXX")) { 160 if (ctag != syncStore().readValue(collId + "_ctagXX")) {
318 SinkTraceCtx(mLogCtx) << "Syncing " << collId; 161 SinkTraceCtx(mLogCtx) << "Syncing " << collId;
@@ -323,22 +166,23 @@ public:
323 auto colljob = runJob(davItemsListJob).then([davItemsListJob] { 166 auto colljob = runJob(davItemsListJob).then([davItemsListJob] {
324 return KAsync::value(davItemsListJob->items()); 167 return KAsync::value(davItemsListJob->items());
325 }) 168 })
326 .serialEach([this, ridList, bufferType, mergeCriteria] (const KDAV::DavItem &item) { 169 .serialEach([=] (const KDAV::DavItem &item) {
327 QByteArray rid = item.url().toDisplayString().toUtf8(); 170 QByteArray rid = getRid(item);
328 if (item.etag().toLatin1() != syncStore().readValue(rid + "_etag")){ 171 if (item.etag().toLatin1() != syncStore().readValue(rid + "_etag")){
329 SinkTrace() << "Updating " << rid; 172 SinkTrace() << "Updating " << rid;
330 auto davItemFetchJob = new KDAV::DavItemFetchJob(item); 173 auto davItemFetchJob = new KDAV::DavItemFetchJob(item);
331 auto itemjob = runJob(davItemFetchJob) 174 auto itemjob = runJob(davItemFetchJob)
332 .then([this, davItemFetchJob, bufferType, mergeCriteria] { 175 .then([=] {
333 const auto item = davItemFetchJob->item(); 176 const auto item = davItemFetchJob->item();
334 const auto rid = item.url().toDisplayString().toUtf8(); 177 const auto rid = getRid(item);
335 Sink::ApplicationDomain::Contact contact; 178 Sink::ApplicationDomain::Contact contact;
336 contact.setVcard(item.data()); 179 contact.setVcard(item.data());
180 contact.setAddressbook(addressbookLocalId);
337 createOrModify(bufferType, rid, contact, mergeCriteria); 181 createOrModify(bufferType, rid, contact, mergeCriteria);
338 return item; 182 return item;
339 }) 183 })
340 .then([this, ridList] (const KDAV::DavItem &item) { 184 .then([this, ridList] (const KDAV::DavItem &item) {
341 const auto rid = item.url().toDisplayString().toUtf8(); 185 const auto rid = getRid(item);
342 syncStore().writeValue(rid + "_etag", item.etag().toLatin1()); 186 syncStore().writeValue(rid + "_etag", item.etag().toLatin1());
343 ridList->append(rid); 187 ridList->append(rid);
344 return rid; 188 return rid;
@@ -375,43 +219,11 @@ public:
375 219
376KAsync::Job<QByteArray> replay(const ApplicationDomain::Contact &contact, Sink::Operation operation, const QByteArray &oldRemoteId, const QList<QByteArray> &changedProperties) Q_DECL_OVERRIDE 220KAsync::Job<QByteArray> replay(const ApplicationDomain::Contact &contact, Sink::Operation operation, const QByteArray &oldRemoteId, const QList<QByteArray> &changedProperties) Q_DECL_OVERRIDE
377 { 221 {
378 /*
379 if (operation == Sink::Operation_Creation) {
380 const auto remoteId = getFilePathFromMimeMessagePath(mail.getMimeMessagePath());
381 SinkTrace() << "Contact created: " << remoteId;
382 return KAsync::value(remoteId.toUtf8());
383 } else if (operation == Sink::Operation_Removal) {
384 SinkTrace() << "Removing a contact " << oldRemoteId;
385 return KAsync::null<QByteArray>();
386 } else if (operation == Sink::Operation_Modification) {
387 SinkTrace() << "Modifying a contact: " << oldRemoteId;
388 const auto remoteId = getFilePathFromMimeMessagePath(mail.getMimeMessagePath());
389 return KAsync::value(remoteId.toUtf8());
390 }*/
391 return KAsync::null<QByteArray>(); 222 return KAsync::null<QByteArray>();
392 } 223 }
393 224
394 KAsync::Job<QByteArray> replay(const ApplicationDomain::Folder &folder, Sink::Operation operation, const QByteArray &oldRemoteId, const QList<QByteArray> &changedProperties) Q_DECL_OVERRIDE 225 KAsync::Job<QByteArray> replay(const ApplicationDomain::Addressbook &addressbook, Sink::Operation operation, const QByteArray &oldRemoteId, const QList<QByteArray> &changedProperties) Q_DECL_OVERRIDE
395 { 226 {
396 /*
397 if (operation == Sink::Operation_Creation) {
398 auto folderName = folder.getName();
399 //FIXME handle non toplevel folders
400 auto path = mMaildirPath + "/" + folderName;
401 SinkTrace() << "Creating a new folder: " << path;
402 KPIM::Contactdir maildir(path, false);
403 maildir.create();
404 return KAsync::value(path.toUtf8());
405 } else if (operation == Sink::Operation_Removal) {
406 const auto path = oldRemoteId;
407 SinkTrace() << "Removing a folder: " << path;
408 KPIM::Contactdir maildir(path, false);
409 maildir.remove();
410 return KAsync::null<QByteArray>();
411 } else if (operation == Sink::Operation_Modification) {
412 SinkWarning() << "Folder modifications are not implemented";
413 return KAsync::value(oldRemoteId);
414 }*/
415 return KAsync::null<QByteArray>(); 227 return KAsync::null<QByteArray>();
416 } 228 }
417 229
@@ -419,103 +231,6 @@ public:
419 KDAV::DavUrl mResourceUrl; 231 KDAV::DavUrl mResourceUrl;
420}; 232};
421 233
422/*
423class MaildirInspector : public Sink::Inspector {
424public:
425 MaildirInspector(const Sink::ResourceContext &resourceContext)
426 : Sink::Inspector(resourceContext)
427 {
428
429 }
430protected:
431
432 KAsync::Job<void> inspect(int inspectionType, const QByteArray &inspectionId, const QByteArray &domainType, const QByteArray &entityId, const QByteArray &property, const QVariant &expectedValue) Q_DECL_OVERRIDE {
433 auto synchronizationStore = QSharedPointer<Sink::Storage::DataStore>::create(Sink::storageLocation(), mResourceContext.instanceId() + ".synchronization", Sink::Storage::DataStore::ReadOnly);
434 auto synchronizationTransaction = synchronizationStore->createTransaction(Sink::Storage::DataStore::ReadOnly);
435
436 auto mainStore = QSharedPointer<Sink::Storage::DataStore>::create(Sink::storageLocation(), mResourceContext.instanceId(), Sink::Storage::DataStore::ReadOnly);
437 auto transaction = mainStore->createTransaction(Sink::Storage::DataStore::ReadOnly);
438
439 Sink::Storage::EntityStore entityStore(mResourceContext, {"maildirresource"});
440 auto syncStore = QSharedPointer<SynchronizerStore>::create(synchronizationTransaction);
441
442 SinkTrace() << "Inspecting " << inspectionType << domainType << entityId << property << expectedValue;
443
444 if (domainType == ENTITY_TYPE_MAIL) {
445 auto mail = entityStore.readLatest<Sink::ApplicationDomain::Contact>(entityId);
446 const auto filePath = getFilePathFromMimeMessagePath(mail.getMimeMessagePath());
447
448 if (inspectionType == Sink::ResourceControl::Inspection::PropertyInspectionType) {
449 if (property == "unread") {
450 const auto flags = KPIM::Contactdir::readEntryFlags(filePath.split('/').last());
451 if (expectedValue.toBool() && (flags & KPIM::Contactdir::Seen)) {
452 return KAsync::error<void>(1, "Expected unread but couldn't find it.");
453 }
454 if (!expectedValue.toBool() && !(flags & KPIM::Contactdir::Seen)) {
455 return KAsync::error<void>(1, "Expected read but couldn't find it.");
456 }
457 return KAsync::null<void>();
458 }
459 if (property == "subject") {
460 KMime::Message *msg = new KMime::Message;
461 msg->setHead(KMime::CRLFtoLF(KPIM::Contactdir::readEntryHeadersFromFile(filePath)));
462 msg->parse();
463
464 if (msg->subject(true)->asUnicodeString() != expectedValue.toString()) {
465 return KAsync::error<void>(1, "Subject not as expected: " + msg->subject(true)->asUnicodeString());
466 }
467 return KAsync::null<void>();
468 }
469 }
470 if (inspectionType == Sink::ResourceControl::Inspection::ExistenceInspectionType) {
471 if (QFileInfo(filePath).exists() != expectedValue.toBool()) {
472 return KAsync::error<void>(1, "Wrong file existence: " + filePath);
473 }
474 }
475 }
476 if (domainType == ENTITY_TYPE_FOLDER) {
477 const auto remoteId = syncStore->resolveLocalId(ENTITY_TYPE_FOLDER, entityId);
478 auto folder = entityStore.readLatest<Sink::ApplicationDomain::Folder>(entityId);
479
480 if (inspectionType == Sink::ResourceControl::Inspection::CacheIntegrityInspectionType) {
481 SinkTrace() << "Inspecting cache integrity" << remoteId;
482 if (!QDir(remoteId).exists()) {
483 return KAsync::error<void>(1, "The directory is not existing: " + remoteId);
484 }
485
486 int expectedCount = 0;
487 Index index("mail.index.folder", transaction);
488 index.lookup(entityId, [&](const QByteArray &sinkId) {
489 expectedCount++;
490 },
491 [&](const Index::Error &error) {
492 SinkWarning() << "Error in index: " << error.message << property;
493 });
494
495 QDir dir(remoteId + "/cur");
496 const QFileInfoList list = dir.entryInfoList(QDir::Files);
497 if (list.size() != expectedCount) {
498 for (const auto &fileInfo : list) {
499 SinkWarning() << "Found in cache: " << fileInfo.fileName();
500 }
501 return KAsync::error<void>(1, QString("Wrong number of files; found %1 instead of %2.").arg(list.size()).arg(expectedCount));
502 }
503 }
504 if (inspectionType == Sink::ResourceControl::Inspection::ExistenceInspectionType) {
505 if (!remoteId.endsWith(folder.getName().toUtf8())) {
506 return KAsync::error<void>(1, "Wrong folder name: " + remoteId);
507 }
508 //TODO we shouldn't use the remoteId here to figure out the path, it could be gone/changed already
509 if (QDir(remoteId).exists() != expectedValue.toBool()) {
510 return KAsync::error<void>(1, "Wrong folder existence: " + remoteId);
511 }
512 }
513
514 }
515 return KAsync::null<void>();
516 }
517};*/
518
519 234
520DavResource::DavResource(const Sink::ResourceContext &resourceContext) 235DavResource::DavResource(const Sink::ResourceContext &resourceContext)
521 : Sink::GenericResource(resourceContext) 236 : Sink::GenericResource(resourceContext)
@@ -530,7 +245,6 @@ DavResource::DavResource(const Sink::ResourceContext &resourceContext)
530 auto synchronizer = QSharedPointer<ContactSynchronizer>::create(resourceContext); 245 auto synchronizer = QSharedPointer<ContactSynchronizer>::create(resourceContext);
531 synchronizer->mResourceUrl = mResourceUrl; 246 synchronizer->mResourceUrl = mResourceUrl;
532 setupSynchronizer(synchronizer); 247 setupSynchronizer(synchronizer);
533 //setupInspector(QSharedPointer<MaildirInspector>::create(resourceContext));
534 248
535 setupPreprocessors(ENTITY_TYPE_CONTACT, QVector<Sink::Preprocessor*>() << new ContactPropertyExtractor); 249 setupPreprocessors(ENTITY_TYPE_CONTACT, QVector<Sink::Preprocessor*>() << new ContactPropertyExtractor);
536} 250}
@@ -539,8 +253,8 @@ DavResource::DavResource(const Sink::ResourceContext &resourceContext)
539DavResourceFactory::DavResourceFactory(QObject *parent) 253DavResourceFactory::DavResourceFactory(QObject *parent)
540 : Sink::ResourceFactory(parent, 254 : Sink::ResourceFactory(parent,
541 {Sink::ApplicationDomain::ResourceCapabilities::Contact::contact, 255 {Sink::ApplicationDomain::ResourceCapabilities::Contact::contact,
542 Sink::ApplicationDomain::ResourceCapabilities::Mail::folder, 256 Sink::ApplicationDomain::ResourceCapabilities::Contact::addressbook,
543 "-folder.rename"} 257 }
544 ) 258 )
545{ 259{
546} 260}
@@ -553,13 +267,13 @@ Sink::Resource *DavResourceFactory::createResource(const ResourceContext &contex
553void DavResourceFactory::registerFacades(const QByteArray &name, Sink::FacadeFactory &factory) 267void DavResourceFactory::registerFacades(const QByteArray &name, Sink::FacadeFactory &factory)
554{ 268{
555 factory.registerFacade<Sink::ApplicationDomain::Contact, DavResourceContactFacade>(name); 269 factory.registerFacade<Sink::ApplicationDomain::Contact, DavResourceContactFacade>(name);
556 factory.registerFacade<Sink::ApplicationDomain::Folder, DavResourceFolderFacade>(name); 270 factory.registerFacade<Sink::ApplicationDomain::Addressbook, DavResourceAddressbookFacade>(name);
557} 271}
558 272
559void DavResourceFactory::registerAdaptorFactories(const QByteArray &name, Sink::AdaptorFactoryRegistry &registry) 273void DavResourceFactory::registerAdaptorFactories(const QByteArray &name, Sink::AdaptorFactoryRegistry &registry)
560{ 274{
561 registry.registerFactory<Sink::ApplicationDomain::Contact, ContactAdaptorFactory>(name); 275 registry.registerFactory<Sink::ApplicationDomain::Contact, ContactAdaptorFactory>(name);
562 registry.registerFactory<Sink::ApplicationDomain::Folder, AddressbookAdaptorFactory>(name); 276 registry.registerFactory<Sink::ApplicationDomain::Addressbook, AddressbookAdaptorFactory>(name);
563} 277}
564 278
565void DavResourceFactory::removeDataFromDisk(const QByteArray &instanceIdentifier) 279void DavResourceFactory::removeDataFromDisk(const QByteArray &instanceIdentifier)
diff --git a/examples/davresource/facade.cpp b/examples/davresource/facade.cpp
index b56815a..8ee1b01 100644
--- a/examples/davresource/facade.cpp
+++ b/examples/davresource/facade.cpp
@@ -34,11 +34,11 @@ DavResourceContactFacade::~DavResourceContactFacade()
34} 34}
35 35
36 36
37DavResourceFolderFacade::DavResourceFolderFacade(const Sink::ResourceContext &context) 37DavResourceAddressbookFacade::DavResourceAddressbookFacade(const Sink::ResourceContext &context)
38 : Sink::GenericFacade<Sink::ApplicationDomain::Folder>(context) 38 : Sink::GenericFacade<Sink::ApplicationDomain::Addressbook>(context)
39{ 39{
40} 40}
41 41
42DavResourceFolderFacade::~DavResourceFolderFacade() 42DavResourceAddressbookFacade::~DavResourceAddressbookFacade()
43{ 43{
44} 44}
diff --git a/examples/davresource/facade.h b/examples/davresource/facade.h
index 02bd5dc..d520891 100644
--- a/examples/davresource/facade.h
+++ b/examples/davresource/facade.h
@@ -28,9 +28,9 @@ public:
28 virtual ~DavResourceContactFacade(); 28 virtual ~DavResourceContactFacade();
29}; 29};
30 30
31class DavResourceFolderFacade : public Sink::GenericFacade<Sink::ApplicationDomain::Folder> 31class DavResourceAddressbookFacade : public Sink::GenericFacade<Sink::ApplicationDomain::Addressbook>
32{ 32{
33public: 33public:
34 DavResourceFolderFacade(const Sink::ResourceContext &context); 34 DavResourceAddressbookFacade(const Sink::ResourceContext &context);
35 virtual ~DavResourceFolderFacade(); 35 virtual ~DavResourceAddressbookFacade();
36}; 36};