summaryrefslogtreecommitdiffstats
path: root/examples
diff options
context:
space:
mode:
Diffstat (limited to 'examples')
-rw-r--r--examples/dummyresource/resourcefactory.cpp44
-rw-r--r--examples/dummyresource/resourcefactory.h1
-rw-r--r--examples/imapresource/imapresource.cpp306
-rw-r--r--examples/imapresource/imapresource.h7
-rw-r--r--examples/maildirresource/maildirresource.cpp185
-rw-r--r--examples/maildirresource/maildirresource.h3
-rw-r--r--examples/mailtransportresource/mailtransportresource.cpp48
-rw-r--r--examples/mailtransportresource/mailtransportresource.h2
8 files changed, 318 insertions, 278 deletions
diff --git a/examples/dummyresource/resourcefactory.cpp b/examples/dummyresource/resourcefactory.cpp
index f5ab2d9..8e81c79 100644
--- a/examples/dummyresource/resourcefactory.cpp
+++ b/examples/dummyresource/resourcefactory.cpp
@@ -37,6 +37,7 @@
37#include "facadefactory.h" 37#include "facadefactory.h"
38#include "adaptorfactoryregistry.h" 38#include "adaptorfactoryregistry.h"
39#include "synchronizer.h" 39#include "synchronizer.h"
40#include "inspector.h"
40#include "mailpreprocessor.h" 41#include "mailpreprocessor.h"
41#include "remoteidmap.h" 42#include "remoteidmap.h"
42#include <QDate> 43#include <QDate>
@@ -130,10 +131,36 @@ class DummySynchronizer : public Sink::Synchronizer {
130 131
131}; 132};
132 133
134class DummyInspector : public Sink::Inspector {
135public:
136 DummyInspector(const Sink::ResourceContext &resourceContext)
137 : Sink::Inspector(resourceContext)
138 {
139
140 }
141
142protected:
143 KAsync::Job<void> inspect(int inspectionType, const QByteArray &inspectionId, const QByteArray &domainType, const QByteArray &entityId, const QByteArray &property, const QVariant &expectedValue) Q_DECL_OVERRIDE
144 {
145 SinkTrace() << "Inspecting " << inspectionType << domainType << entityId << property << expectedValue;
146 if (property == "testInspection") {
147 if (expectedValue.toBool()) {
148 //Success
149 return KAsync::null<void>();
150 } else {
151 //Failure
152 return KAsync::error<void>(1, "Failed.");
153 }
154 }
155 return KAsync::null<void>();
156 }
157};
158
133DummyResource::DummyResource(const Sink::ResourceContext &resourceContext, const QSharedPointer<Sink::Pipeline> &pipeline) 159DummyResource::DummyResource(const Sink::ResourceContext &resourceContext, const QSharedPointer<Sink::Pipeline> &pipeline)
134 : Sink::GenericResource(resourceContext, pipeline) 160 : Sink::GenericResource(resourceContext, pipeline)
135{ 161{
136 setupSynchronizer(QSharedPointer<DummySynchronizer>::create(resourceContext)); 162 setupSynchronizer(QSharedPointer<DummySynchronizer>::create(resourceContext));
163 setupInspector(QSharedPointer<DummyInspector>::create(resourceContext));
137 setupPreprocessors(ENTITY_TYPE_MAIL, 164 setupPreprocessors(ENTITY_TYPE_MAIL,
138 QVector<Sink::Preprocessor*>() << new MailPropertyExtractor); 165 QVector<Sink::Preprocessor*>() << new MailPropertyExtractor);
139 setupPreprocessors(ENTITY_TYPE_FOLDER, 166 setupPreprocessors(ENTITY_TYPE_FOLDER,
@@ -159,23 +186,6 @@ KAsync::Job<void> DummyResource::synchronizeWithSource(const Sink::QueryBase &qu
159 return GenericResource::synchronizeWithSource(query); 186 return GenericResource::synchronizeWithSource(query);
160} 187}
161 188
162KAsync::Job<void> DummyResource::inspect(int inspectionType, const QByteArray &inspectionId, const QByteArray &domainType, const QByteArray &entityId, const QByteArray &property, const QVariant &expectedValue)
163{
164
165 SinkTrace() << "Inspecting " << inspectionType << domainType << entityId << property << expectedValue;
166 if (property == "testInspection") {
167 if (expectedValue.toBool()) {
168 //Success
169 return KAsync::null<void>();
170 } else {
171 //Failure
172 return KAsync::error<void>(1, "Failed.");
173 }
174 }
175 return KAsync::null<void>();
176}
177
178
179DummyResourceFactory::DummyResourceFactory(QObject *parent) 189DummyResourceFactory::DummyResourceFactory(QObject *parent)
180 : Sink::ResourceFactory(parent) 190 : Sink::ResourceFactory(parent)
181{ 191{
diff --git a/examples/dummyresource/resourcefactory.h b/examples/dummyresource/resourcefactory.h
index 8ef27a6..2eb7558 100644
--- a/examples/dummyresource/resourcefactory.h
+++ b/examples/dummyresource/resourcefactory.h
@@ -33,7 +33,6 @@ public:
33 virtual ~DummyResource(); 33 virtual ~DummyResource();
34 34
35 KAsync::Job<void> synchronizeWithSource(const Sink::QueryBase &) Q_DECL_OVERRIDE; 35 KAsync::Job<void> synchronizeWithSource(const Sink::QueryBase &) Q_DECL_OVERRIDE;
36 KAsync::Job<void> inspect(int inspectionType, const QByteArray &inspectionId, const QByteArray &domainType, const QByteArray &entityId, const QByteArray &property, const QVariant &expectedValue) Q_DECL_OVERRIDE;
37}; 36};
38 37
39class DummyResourceFactory : public Sink::ResourceFactory 38class DummyResourceFactory : public Sink::ResourceFactory
diff --git a/examples/imapresource/imapresource.cpp b/examples/imapresource/imapresource.cpp
index 2aa5a2c..40fa75f 100644
--- a/examples/imapresource/imapresource.cpp
+++ b/examples/imapresource/imapresource.cpp
@@ -27,6 +27,7 @@
27#include "definitions.h" 27#include "definitions.h"
28#include "inspection.h" 28#include "inspection.h"
29#include "synchronizer.h" 29#include "synchronizer.h"
30#include "inspector.h"
30#include "remoteidmap.h" 31#include "remoteidmap.h"
31#include "query.h" 32#include "query.h"
32 33
@@ -553,169 +554,192 @@ public:
553 QByteArray mResourceInstanceIdentifier; 554 QByteArray mResourceInstanceIdentifier;
554}; 555};
555 556
556ImapResource::ImapResource(const ResourceContext &resourceContext) 557class ImapInspector : public Sink::Inspector {
557 : Sink::GenericResource(resourceContext) 558public:
558{ 559 ImapInspector(const Sink::ResourceContext &resourceContext)
559 auto config = ResourceConfig::getConfiguration(resourceContext.instanceId()); 560 : Sink::Inspector(resourceContext)
560 mServer = config.value("server").toString(); 561 {
561 mPort = config.value("port").toInt();
562 mUser = config.value("username").toString();
563 mPassword = config.value("password").toString();
564 if (mServer.startsWith("imap")) {
565 mServer.remove("imap://");
566 mServer.remove("imaps://");
567 }
568 if (mServer.contains(':')) {
569 auto list = mServer.split(':');
570 mServer = list.at(0);
571 mPort = list.at(1).toInt();
572 }
573
574 auto synchronizer = QSharedPointer<ImapSynchronizer>::create(resourceContext);
575 synchronizer->mServer = mServer;
576 synchronizer->mPort = mPort;
577 synchronizer->mUser = mUser;
578 synchronizer->mPassword = mPassword;
579 setupSynchronizer(synchronizer);
580
581 setupPreprocessors(ENTITY_TYPE_MAIL, QVector<Sink::Preprocessor*>() << new SpecialPurposeProcessor(resourceContext.resourceType, resourceContext.instanceId()) << new MimeMessageMover << new MailPropertyExtractor);
582 setupPreprocessors(ENTITY_TYPE_FOLDER, QVector<Sink::Preprocessor*>());
583}
584 562
585KAsync::Job<void> ImapResource::inspect(int inspectionType, const QByteArray &inspectionId, const QByteArray &domainType, const QByteArray &entityId, const QByteArray &property, const QVariant &expectedValue) 563 }
586{
587 auto synchronizationStore = QSharedPointer<Sink::Storage::DataStore>::create(Sink::storageLocation(), mResourceContext.instanceId() + ".synchronization", Sink::Storage::DataStore::ReadOnly);
588 auto synchronizationTransaction = synchronizationStore->createTransaction(Sink::Storage::DataStore::ReadOnly);
589 564
590 auto mainStore = QSharedPointer<Sink::Storage::DataStore>::create(Sink::storageLocation(), mResourceContext.instanceId(), Sink::Storage::DataStore::ReadOnly); 565protected:
591 auto transaction = mainStore->createTransaction(Sink::Storage::DataStore::ReadOnly); 566 KAsync::Job<void> inspect(int inspectionType, const QByteArray &inspectionId, const QByteArray &domainType, const QByteArray &entityId, const QByteArray &property, const QVariant &expectedValue) Q_DECL_OVERRIDE {
567 auto synchronizationStore = QSharedPointer<Sink::Storage::DataStore>::create(Sink::storageLocation(), mResourceContext.instanceId() + ".synchronization", Sink::Storage::DataStore::ReadOnly);
568 auto synchronizationTransaction = synchronizationStore->createTransaction(Sink::Storage::DataStore::ReadOnly);
592 569
593 Sink::Storage::EntityStore entityStore(mResourceContext); 570 auto mainStore = QSharedPointer<Sink::Storage::DataStore>::create(Sink::storageLocation(), mResourceContext.instanceId(), Sink::Storage::DataStore::ReadOnly);
594 auto syncStore = QSharedPointer<Sink::RemoteIdMap>::create(synchronizationTransaction); 571 auto transaction = mainStore->createTransaction(Sink::Storage::DataStore::ReadOnly);
595 572
596 SinkTrace() << "Inspecting " << inspectionType << domainType << entityId << property << expectedValue; 573 Sink::Storage::EntityStore entityStore(mResourceContext);
574 auto syncStore = QSharedPointer<Sink::RemoteIdMap>::create(synchronizationTransaction);
597 575
598 if (domainType == ENTITY_TYPE_MAIL) { 576 SinkTrace() << "Inspecting " << inspectionType << domainType << entityId << property << expectedValue;
599 const auto mail = entityStore.readLatest<Sink::ApplicationDomain::Mail>(entityId);
600 const auto folder = entityStore.readLatest<Sink::ApplicationDomain::Folder>(mail.getFolder());
601 const auto folderRemoteId = syncStore->resolveLocalId(ENTITY_TYPE_FOLDER, mail.getFolder());
602 const auto mailRemoteId = syncStore->resolveLocalId(ENTITY_TYPE_MAIL, mail.identifier());
603 if (mailRemoteId.isEmpty() || folderRemoteId.isEmpty()) {
604 SinkWarning() << "Missing remote id for folder or mail. " << mailRemoteId << folderRemoteId;
605 return KAsync::error<void>();
606 }
607 const auto uid = uidFromMailRid(mailRemoteId);
608 SinkTrace() << "Mail remote id: " << folderRemoteId << mailRemoteId << mail.identifier() << folder.identifier();
609 577
610 KIMAP2::ImapSet set; 578 if (domainType == ENTITY_TYPE_MAIL) {
611 set.add(uid); 579 const auto mail = entityStore.readLatest<Sink::ApplicationDomain::Mail>(entityId);
612 if (set.isEmpty()) { 580 const auto folder = entityStore.readLatest<Sink::ApplicationDomain::Folder>(mail.getFolder());
613 return KAsync::error<void>(1, "Couldn't determine uid of mail."); 581 const auto folderRemoteId = syncStore->resolveLocalId(ENTITY_TYPE_FOLDER, mail.getFolder());
614 } 582 const auto mailRemoteId = syncStore->resolveLocalId(ENTITY_TYPE_MAIL, mail.identifier());
615 KIMAP2::FetchJob::FetchScope scope; 583 if (mailRemoteId.isEmpty() || folderRemoteId.isEmpty()) {
616 scope.mode = KIMAP2::FetchJob::FetchScope::Full; 584 SinkWarning() << "Missing remote id for folder or mail. " << mailRemoteId << folderRemoteId;
617 auto imap = QSharedPointer<ImapServerProxy>::create(mServer, mPort); 585 return KAsync::error<void>();
618 auto messageByUid = QSharedPointer<QHash<qint64, Imap::Message>>::create();
619 SinkTrace() << "Connecting to:" << mServer << mPort;
620 SinkTrace() << "as:" << mUser;
621 auto inspectionJob = imap->login(mUser, mPassword)
622 .then<Imap::SelectResult>(imap->select(folderRemoteId))
623 .syncThen<void, Imap::SelectResult>([](Imap::SelectResult){})
624 .then<void>(imap->fetch(set, scope, [imap, messageByUid](const Imap::Message &message) {
625 messageByUid->insert(message.uid, message);
626 }));
627
628 if (inspectionType == Sink::ResourceControl::Inspection::PropertyInspectionType) {
629 if (property == "unread") {
630 return inspectionJob.then<void>([=]() {
631 auto msg = messageByUid->value(uid);
632 if (expectedValue.toBool() && msg.flags.contains(Imap::Flags::Seen)) {
633 return KAsync::error<void>(1, "Expected unread but couldn't find it.");
634 }
635 if (!expectedValue.toBool() && !msg.flags.contains(Imap::Flags::Seen)) {
636 return KAsync::error<void>(1, "Expected read but couldn't find it.");
637 }
638 return KAsync::null<void>();
639 });
640 }
641 if (property == "subject") {
642 return inspectionJob.then<void>([=]() {
643 auto msg = messageByUid->value(uid);
644 if (msg.msg->subject(true)->asUnicodeString() != expectedValue.toString()) {
645 return KAsync::error<void>(1, "Subject not as expected: " + msg.msg->subject(true)->asUnicodeString());
646 }
647 return KAsync::null<void>();
648 });
649 } 586 }
650 } 587 const auto uid = uidFromMailRid(mailRemoteId);
651 if (inspectionType == Sink::ResourceControl::Inspection::ExistenceInspectionType) { 588 SinkTrace() << "Mail remote id: " << folderRemoteId << mailRemoteId << mail.identifier() << folder.identifier();
652 return inspectionJob.then<void>([=]() {
653 if (!messageByUid->contains(uid)) {
654 SinkWarning() << "Existing messages are: " << messageByUid->keys();
655 SinkWarning() << "We're looking for: " << uid;
656 return KAsync::error<void>(1, "Couldn't find message: " + mailRemoteId);
657 }
658 return KAsync::null<void>();
659 });
660 }
661 }
662 if (domainType == ENTITY_TYPE_FOLDER) {
663 const auto remoteId = syncStore->resolveLocalId(ENTITY_TYPE_FOLDER, entityId);
664 const auto folder = entityStore.readLatest<Sink::ApplicationDomain::Folder>(entityId);
665
666 if (inspectionType == Sink::ResourceControl::Inspection::CacheIntegrityInspectionType) {
667 SinkLog() << "Inspecting cache integrity" << remoteId;
668 589
669 int expectedCount = 0; 590 KIMAP2::ImapSet set;
670 Index index("mail.index.folder", transaction); 591 set.add(uid);
671 index.lookup(entityId, [&](const QByteArray &sinkId) { 592 if (set.isEmpty()) {
672 expectedCount++; 593 return KAsync::error<void>(1, "Couldn't determine uid of mail.");
673 }, 594 }
674 [&](const Index::Error &error) {
675 SinkWarning() << "Error in index: " << error.message << property;
676 });
677
678 auto set = KIMAP2::ImapSet::fromImapSequenceSet("1:*");
679 KIMAP2::FetchJob::FetchScope scope; 595 KIMAP2::FetchJob::FetchScope scope;
680 scope.mode = KIMAP2::FetchJob::FetchScope::Headers; 596 scope.mode = KIMAP2::FetchJob::FetchScope::Full;
681 auto imap = QSharedPointer<ImapServerProxy>::create(mServer, mPort); 597 auto imap = QSharedPointer<ImapServerProxy>::create(mServer, mPort);
682 auto messageByUid = QSharedPointer<QHash<qint64, Imap::Message>>::create(); 598 auto messageByUid = QSharedPointer<QHash<qint64, Imap::Message>>::create();
683 return imap->login(mUser, mPassword) 599 SinkTrace() << "Connecting to:" << mServer << mPort;
684 .then<void>(imap->select(remoteId).syncThen<void>([](){})) 600 SinkTrace() << "as:" << mUser;
685 .then<void>(imap->fetch(set, scope, [=](const Imap::Message message) { 601 auto inspectionJob = imap->login(mUser, mPassword)
602 .then<Imap::SelectResult>(imap->select(folderRemoteId))
603 .syncThen<void, Imap::SelectResult>([](Imap::SelectResult){})
604 .then<void>(imap->fetch(set, scope, [imap, messageByUid](const Imap::Message &message) {
686 messageByUid->insert(message.uid, message); 605 messageByUid->insert(message.uid, message);
687 })) 606 }));
688 .then<void>([imap, messageByUid, expectedCount]() { 607
689 if (messageByUid->size() != expectedCount) { 608 if (inspectionType == Sink::ResourceControl::Inspection::PropertyInspectionType) {
690 return KAsync::error<void>(1, QString("Wrong number of messages on the server; found %1 instead of %2.").arg(messageByUid->size()).arg(expectedCount)); 609 if (property == "unread") {
610 return inspectionJob.then<void>([=]() {
611 auto msg = messageByUid->value(uid);
612 if (expectedValue.toBool() && msg.flags.contains(Imap::Flags::Seen)) {
613 return KAsync::error<void>(1, "Expected unread but couldn't find it.");
614 }
615 if (!expectedValue.toBool() && !msg.flags.contains(Imap::Flags::Seen)) {
616 return KAsync::error<void>(1, "Expected read but couldn't find it.");
617 }
618 return KAsync::null<void>();
619 });
620 }
621 if (property == "subject") {
622 return inspectionJob.then<void>([=]() {
623 auto msg = messageByUid->value(uid);
624 if (msg.msg->subject(true)->asUnicodeString() != expectedValue.toString()) {
625 return KAsync::error<void>(1, "Subject not as expected: " + msg.msg->subject(true)->asUnicodeString());
626 }
627 return KAsync::null<void>();
628 });
629 }
630 }
631 if (inspectionType == Sink::ResourceControl::Inspection::ExistenceInspectionType) {
632 return inspectionJob.then<void>([=]() {
633 if (!messageByUid->contains(uid)) {
634 SinkWarning() << "Existing messages are: " << messageByUid->keys();
635 SinkWarning() << "We're looking for: " << uid;
636 return KAsync::error<void>(1, "Couldn't find message: " + mailRemoteId);
691 } 637 }
692 return KAsync::null<void>(); 638 return KAsync::null<void>();
693 }); 639 });
640 }
694 } 641 }
695 if (inspectionType == Sink::ResourceControl::Inspection::ExistenceInspectionType) { 642 if (domainType == ENTITY_TYPE_FOLDER) {
696 auto folderByPath = QSharedPointer<QSet<QString>>::create(); 643 const auto remoteId = syncStore->resolveLocalId(ENTITY_TYPE_FOLDER, entityId);
697 auto folderByName = QSharedPointer<QSet<QString>>::create(); 644 const auto folder = entityStore.readLatest<Sink::ApplicationDomain::Folder>(entityId);
698 645
699 auto imap = QSharedPointer<ImapServerProxy>::create(mServer, mPort); 646 if (inspectionType == Sink::ResourceControl::Inspection::CacheIntegrityInspectionType) {
700 auto inspectionJob = imap->login(mUser, mPassword) 647 SinkLog() << "Inspecting cache integrity" << remoteId;
701 .then<void>(imap->fetchFolders([=](const Imap::Folder &f) { 648
702 *folderByPath << f.normalizedPath(); 649 int expectedCount = 0;
703 *folderByName << f.name(); 650 Index index("mail.index.folder", transaction);
704 })) 651 index.lookup(entityId, [&](const QByteArray &sinkId) {
705 .then<void>([this, folderByName, folderByPath, folder, remoteId, imap]() { 652 expectedCount++;
706 if (!folderByName->contains(folder.getName())) { 653 },
707 SinkWarning() << "Existing folders are: " << *folderByPath; 654 [&](const Index::Error &error) {
708 SinkWarning() << "We're looking for: " << folder.getName(); 655 SinkWarning() << "Error in index: " << error.message << property;
709 return KAsync::error<void>(1, "Wrong folder name: " + remoteId);
710 }
711 return KAsync::null<void>();
712 }); 656 });
713 657
714 return inspectionJob; 658 auto set = KIMAP2::ImapSet::fromImapSequenceSet("1:*");
659 KIMAP2::FetchJob::FetchScope scope;
660 scope.mode = KIMAP2::FetchJob::FetchScope::Headers;
661 auto imap = QSharedPointer<ImapServerProxy>::create(mServer, mPort);
662 auto messageByUid = QSharedPointer<QHash<qint64, Imap::Message>>::create();
663 return imap->login(mUser, mPassword)
664 .then<void>(imap->select(remoteId).syncThen<void>([](){}))
665 .then<void>(imap->fetch(set, scope, [=](const Imap::Message message) {
666 messageByUid->insert(message.uid, message);
667 }))
668 .then<void>([imap, messageByUid, expectedCount]() {
669 if (messageByUid->size() != expectedCount) {
670 return KAsync::error<void>(1, QString("Wrong number of messages on the server; found %1 instead of %2.").arg(messageByUid->size()).arg(expectedCount));
671 }
672 return KAsync::null<void>();
673 });
674 }
675 if (inspectionType == Sink::ResourceControl::Inspection::ExistenceInspectionType) {
676 auto folderByPath = QSharedPointer<QSet<QString>>::create();
677 auto folderByName = QSharedPointer<QSet<QString>>::create();
678
679 auto imap = QSharedPointer<ImapServerProxy>::create(mServer, mPort);
680 auto inspectionJob = imap->login(mUser, mPassword)
681 .then<void>(imap->fetchFolders([=](const Imap::Folder &f) {
682 *folderByPath << f.normalizedPath();
683 *folderByName << f.name();
684 }))
685 .then<void>([this, folderByName, folderByPath, folder, remoteId, imap]() {
686 if (!folderByName->contains(folder.getName())) {
687 SinkWarning() << "Existing folders are: " << *folderByPath;
688 SinkWarning() << "We're looking for: " << folder.getName();
689 return KAsync::error<void>(1, "Wrong folder name: " + remoteId);
690 }
691 return KAsync::null<void>();
692 });
693
694 return inspectionJob;
695 }
696
715 } 697 }
698 return KAsync::null<void>();
699 }
700
701public:
702 QString mServer;
703 int mPort;
704 QString mUser;
705 QString mPassword;
706};
707
716 708
709ImapResource::ImapResource(const ResourceContext &resourceContext)
710 : Sink::GenericResource(resourceContext)
711{
712 auto config = ResourceConfig::getConfiguration(resourceContext.instanceId());
713 auto server = config.value("server").toString();
714 auto port = config.value("port").toInt();
715 auto user = config.value("username").toString();
716 auto password = config.value("password").toString();
717 if (server.startsWith("imap")) {
718 server.remove("imap://");
719 server.remove("imaps://");
720 }
721 if (server.contains(':')) {
722 auto list = server.split(':');
723 server = list.at(0);
724 port = list.at(1).toInt();
717 } 725 }
718 return KAsync::null<void>(); 726
727 auto synchronizer = QSharedPointer<ImapSynchronizer>::create(resourceContext);
728 synchronizer->mServer = server;
729 synchronizer->mPort = port;
730 synchronizer->mUser = user;
731 synchronizer->mPassword = password;
732 setupSynchronizer(synchronizer);
733
734 auto inspector = QSharedPointer<ImapInspector>::create(resourceContext);
735 inspector->mServer = server;
736 inspector->mPort = port;
737 inspector->mUser = user;
738 inspector->mPassword = password;
739 setupInspector(inspector);
740
741 setupPreprocessors(ENTITY_TYPE_MAIL, QVector<Sink::Preprocessor*>() << new SpecialPurposeProcessor(resourceContext.resourceType, resourceContext.instanceId()) << new MimeMessageMover << new MailPropertyExtractor);
742 setupPreprocessors(ENTITY_TYPE_FOLDER, QVector<Sink::Preprocessor*>());
719} 743}
720 744
721ImapResourceFactory::ImapResourceFactory(QObject *parent) 745ImapResourceFactory::ImapResourceFactory(QObject *parent)
diff --git a/examples/imapresource/imapresource.h b/examples/imapresource/imapresource.h
index d345d64..aeb1200 100644
--- a/examples/imapresource/imapresource.h
+++ b/examples/imapresource/imapresource.h
@@ -40,13 +40,6 @@ class ImapResource : public Sink::GenericResource
40{ 40{
41public: 41public:
42 ImapResource(const Sink::ResourceContext &resourceContext); 42 ImapResource(const Sink::ResourceContext &resourceContext);
43 KAsync::Job<void> inspect(int inspectionType, const QByteArray &inspectionId, const QByteArray &domainType, const QByteArray &entityId, const QByteArray &property, const QVariant &expectedValue) Q_DECL_OVERRIDE;
44
45private:
46 QString mServer;
47 int mPort;
48 QString mUser;
49 QString mPassword;
50}; 43};
51 44
52class ImapResourceFactory : public Sink::ResourceFactory 45class ImapResourceFactory : public Sink::ResourceFactory
diff --git a/examples/maildirresource/maildirresource.cpp b/examples/maildirresource/maildirresource.cpp
index ee84bde..2b19789 100644
--- a/examples/maildirresource/maildirresource.cpp
+++ b/examples/maildirresource/maildirresource.cpp
@@ -27,6 +27,7 @@
27#include "libmaildir/maildir.h" 27#include "libmaildir/maildir.h"
28#include "inspection.h" 28#include "inspection.h"
29#include "synchronizer.h" 29#include "synchronizer.h"
30#include "inspector.h"
30 31
31#include "facadefactory.h" 32#include "facadefactory.h"
32#include "adaptorfactoryregistry.h" 33#include "adaptorfactoryregistry.h"
@@ -425,6 +426,102 @@ public:
425 QString mMaildirPath; 426 QString mMaildirPath;
426}; 427};
427 428
429class MaildirInspector : public Sink::Inspector {
430public:
431 MaildirInspector(const Sink::ResourceContext &resourceContext)
432 : Sink::Inspector(resourceContext)
433 {
434
435 }
436protected:
437
438 KAsync::Job<void> inspect(int inspectionType, const QByteArray &inspectionId, const QByteArray &domainType, const QByteArray &entityId, const QByteArray &property, const QVariant &expectedValue) Q_DECL_OVERRIDE {
439 auto synchronizationStore = QSharedPointer<Sink::Storage::DataStore>::create(Sink::storageLocation(), mResourceContext.instanceId() + ".synchronization", Sink::Storage::DataStore::ReadOnly);
440 auto synchronizationTransaction = synchronizationStore->createTransaction(Sink::Storage::DataStore::ReadOnly);
441
442 auto mainStore = QSharedPointer<Sink::Storage::DataStore>::create(Sink::storageLocation(), mResourceContext.instanceId(), Sink::Storage::DataStore::ReadOnly);
443 auto transaction = mainStore->createTransaction(Sink::Storage::DataStore::ReadOnly);
444
445 Sink::Storage::EntityStore entityStore(mResourceContext);
446 auto syncStore = QSharedPointer<RemoteIdMap>::create(synchronizationTransaction);
447
448 SinkTrace() << "Inspecting " << inspectionType << domainType << entityId << property << expectedValue;
449
450 if (domainType == ENTITY_TYPE_MAIL) {
451 auto mail = entityStore.readLatest<Sink::ApplicationDomain::Mail>(entityId);
452 const auto filePath = getFilePathFromMimeMessagePath(mail.getMimeMessagePath());
453
454 if (inspectionType == Sink::ResourceControl::Inspection::PropertyInspectionType) {
455 if (property == "unread") {
456 const auto flags = KPIM::Maildir::readEntryFlags(filePath.split('/').last());
457 if (expectedValue.toBool() && (flags & KPIM::Maildir::Seen)) {
458 return KAsync::error<void>(1, "Expected unread but couldn't find it.");
459 }
460 if (!expectedValue.toBool() && !(flags & KPIM::Maildir::Seen)) {
461 return KAsync::error<void>(1, "Expected read but couldn't find it.");
462 }
463 return KAsync::null<void>();
464 }
465 if (property == "subject") {
466 KMime::Message *msg = new KMime::Message;
467 msg->setHead(KMime::CRLFtoLF(KPIM::Maildir::readEntryHeadersFromFile(filePath)));
468 msg->parse();
469
470 if (msg->subject(true)->asUnicodeString() != expectedValue.toString()) {
471 return KAsync::error<void>(1, "Subject not as expected: " + msg->subject(true)->asUnicodeString());
472 }
473 return KAsync::null<void>();
474 }
475 }
476 if (inspectionType == Sink::ResourceControl::Inspection::ExistenceInspectionType) {
477 if (QFileInfo(filePath).exists() != expectedValue.toBool()) {
478 return KAsync::error<void>(1, "Wrong file existence: " + filePath);
479 }
480 }
481 }
482 if (domainType == ENTITY_TYPE_FOLDER) {
483 const auto remoteId = syncStore->resolveLocalId(ENTITY_TYPE_FOLDER, entityId);
484 auto folder = entityStore.readLatest<Sink::ApplicationDomain::Folder>(entityId);
485
486 if (inspectionType == Sink::ResourceControl::Inspection::CacheIntegrityInspectionType) {
487 SinkTrace() << "Inspecting cache integrity" << remoteId;
488 if (!QDir(remoteId).exists()) {
489 return KAsync::error<void>(1, "The directory is not existing: " + remoteId);
490 }
491
492 int expectedCount = 0;
493 Index index("mail.index.folder", transaction);
494 index.lookup(entityId, [&](const QByteArray &sinkId) {
495 expectedCount++;
496 },
497 [&](const Index::Error &error) {
498 SinkWarning() << "Error in index: " << error.message << property;
499 });
500
501 QDir dir(remoteId + "/cur");
502 const QFileInfoList list = dir.entryInfoList(QDir::Files);
503 if (list.size() != expectedCount) {
504 for (const auto &fileInfo : list) {
505 SinkWarning() << "Found in cache: " << fileInfo.fileName();
506 }
507 return KAsync::error<void>(1, QString("Wrong number of files; found %1 instead of %2.").arg(list.size()).arg(expectedCount));
508 }
509 }
510 if (inspectionType == Sink::ResourceControl::Inspection::ExistenceInspectionType) {
511 if (!remoteId.endsWith(folder.getName().toUtf8())) {
512 return KAsync::error<void>(1, "Wrong folder name: " + remoteId);
513 }
514 //TODO we shouldn't use the remoteId here to figure out the path, it could be gone/changed already
515 if (QDir(remoteId).exists() != expectedValue.toBool()) {
516 return KAsync::error<void>(1, "Wrong folder existence: " + remoteId);
517 }
518 }
519
520 }
521 return KAsync::null<void>();
522 }
523};
524
428 525
429MaildirResource::MaildirResource(const Sink::ResourceContext &resourceContext) 526MaildirResource::MaildirResource(const Sink::ResourceContext &resourceContext)
430 : Sink::GenericResource(resourceContext) 527 : Sink::GenericResource(resourceContext)
@@ -439,6 +536,7 @@ MaildirResource::MaildirResource(const Sink::ResourceContext &resourceContext)
439 auto synchronizer = QSharedPointer<MaildirSynchronizer>::create(resourceContext); 536 auto synchronizer = QSharedPointer<MaildirSynchronizer>::create(resourceContext);
440 synchronizer->mMaildirPath = mMaildirPath; 537 synchronizer->mMaildirPath = mMaildirPath;
441 setupSynchronizer(synchronizer); 538 setupSynchronizer(synchronizer);
539 setupInspector(QSharedPointer<MaildirInspector>::create(resourceContext));
442 540
443 setupPreprocessors(ENTITY_TYPE_MAIL, QVector<Sink::Preprocessor*>() << new SpecialPurposeProcessor(resourceContext.resourceType, resourceContext.instanceId()) << new MaildirMimeMessageMover(resourceContext.instanceId(), mMaildirPath) << new MaildirMailPropertyExtractor); 541 setupPreprocessors(ENTITY_TYPE_MAIL, QVector<Sink::Preprocessor*>() << new SpecialPurposeProcessor(resourceContext.resourceType, resourceContext.instanceId()) << new MaildirMimeMessageMover(resourceContext.instanceId(), mMaildirPath) << new MaildirMailPropertyExtractor);
444 setupPreprocessors(ENTITY_TYPE_FOLDER, QVector<Sink::Preprocessor*>() << new FolderPreprocessor(mMaildirPath)); 542 setupPreprocessors(ENTITY_TYPE_FOLDER, QVector<Sink::Preprocessor*>() << new FolderPreprocessor(mMaildirPath));
@@ -458,93 +556,6 @@ MaildirResource::MaildirResource(const Sink::ResourceContext &resourceContext)
458 synchronizer->commit(); 556 synchronizer->commit();
459} 557}
460 558
461KAsync::Job<void> MaildirResource::inspect(int inspectionType, const QByteArray &inspectionId, const QByteArray &domainType, const QByteArray &entityId, const QByteArray &property, const QVariant &expectedValue)
462{
463 auto synchronizationStore = QSharedPointer<Sink::Storage::DataStore>::create(Sink::storageLocation(), mResourceContext.instanceId() + ".synchronization", Sink::Storage::DataStore::ReadOnly);
464 auto synchronizationTransaction = synchronizationStore->createTransaction(Sink::Storage::DataStore::ReadOnly);
465
466 auto mainStore = QSharedPointer<Sink::Storage::DataStore>::create(Sink::storageLocation(), mResourceContext.instanceId(), Sink::Storage::DataStore::ReadOnly);
467 auto transaction = mainStore->createTransaction(Sink::Storage::DataStore::ReadOnly);
468
469 Sink::Storage::EntityStore entityStore(mResourceContext);
470 auto syncStore = QSharedPointer<RemoteIdMap>::create(synchronizationTransaction);
471
472 SinkTrace() << "Inspecting " << inspectionType << domainType << entityId << property << expectedValue;
473
474 if (domainType == ENTITY_TYPE_MAIL) {
475 auto mail = entityStore.readLatest<Sink::ApplicationDomain::Mail>(entityId);
476 const auto filePath = getFilePathFromMimeMessagePath(mail.getMimeMessagePath());
477
478 if (inspectionType == Sink::ResourceControl::Inspection::PropertyInspectionType) {
479 if (property == "unread") {
480 const auto flags = KPIM::Maildir::readEntryFlags(filePath.split('/').last());
481 if (expectedValue.toBool() && (flags & KPIM::Maildir::Seen)) {
482 return KAsync::error<void>(1, "Expected unread but couldn't find it.");
483 }
484 if (!expectedValue.toBool() && !(flags & KPIM::Maildir::Seen)) {
485 return KAsync::error<void>(1, "Expected read but couldn't find it.");
486 }
487 return KAsync::null<void>();
488 }
489 if (property == "subject") {
490 KMime::Message *msg = new KMime::Message;
491 msg->setHead(KMime::CRLFtoLF(KPIM::Maildir::readEntryHeadersFromFile(filePath)));
492 msg->parse();
493
494 if (msg->subject(true)->asUnicodeString() != expectedValue.toString()) {
495 return KAsync::error<void>(1, "Subject not as expected: " + msg->subject(true)->asUnicodeString());
496 }
497 return KAsync::null<void>();
498 }
499 }
500 if (inspectionType == Sink::ResourceControl::Inspection::ExistenceInspectionType) {
501 if (QFileInfo(filePath).exists() != expectedValue.toBool()) {
502 return KAsync::error<void>(1, "Wrong file existence: " + filePath);
503 }
504 }
505 }
506 if (domainType == ENTITY_TYPE_FOLDER) {
507 const auto remoteId = syncStore->resolveLocalId(ENTITY_TYPE_FOLDER, entityId);
508 auto folder = entityStore.readLatest<Sink::ApplicationDomain::Folder>(entityId);
509
510 if (inspectionType == Sink::ResourceControl::Inspection::CacheIntegrityInspectionType) {
511 SinkTrace() << "Inspecting cache integrity" << remoteId;
512 if (!QDir(remoteId).exists()) {
513 return KAsync::error<void>(1, "The directory is not existing: " + remoteId);
514 }
515
516 int expectedCount = 0;
517 Index index("mail.index.folder", transaction);
518 index.lookup(entityId, [&](const QByteArray &sinkId) {
519 expectedCount++;
520 },
521 [&](const Index::Error &error) {
522 SinkWarning() << "Error in index: " << error.message << property;
523 });
524
525 QDir dir(remoteId + "/cur");
526 const QFileInfoList list = dir.entryInfoList(QDir::Files);
527 if (list.size() != expectedCount) {
528 for (const auto &fileInfo : list) {
529 SinkWarning() << "Found in cache: " << fileInfo.fileName();
530 }
531 return KAsync::error<void>(1, QString("Wrong number of files; found %1 instead of %2.").arg(list.size()).arg(expectedCount));
532 }
533 }
534 if (inspectionType == Sink::ResourceControl::Inspection::ExistenceInspectionType) {
535 if (!remoteId.endsWith(folder.getName().toUtf8())) {
536 return KAsync::error<void>(1, "Wrong folder name: " + remoteId);
537 }
538 //TODO we shouldn't use the remoteId here to figure out the path, it could be gone/changed already
539 if (QDir(remoteId).exists() != expectedValue.toBool()) {
540 return KAsync::error<void>(1, "Wrong folder existence: " + remoteId);
541 }
542 }
543
544 }
545 return KAsync::null<void>();
546}
547
548 559
549MaildirResourceFactory::MaildirResourceFactory(QObject *parent) 560MaildirResourceFactory::MaildirResourceFactory(QObject *parent)
550 : Sink::ResourceFactory(parent) 561 : Sink::ResourceFactory(parent)
diff --git a/examples/maildirresource/maildirresource.h b/examples/maildirresource/maildirresource.h
index 4eb2042..61fe438 100644
--- a/examples/maildirresource/maildirresource.h
+++ b/examples/maildirresource/maildirresource.h
@@ -43,9 +43,8 @@ class MaildirResource : public Sink::GenericResource
43{ 43{
44public: 44public:
45 MaildirResource(const Sink::ResourceContext &resourceContext); 45 MaildirResource(const Sink::ResourceContext &resourceContext);
46 KAsync::Job<void> inspect(int inspectionType, const QByteArray &inspectionId, const QByteArray &domainType, const QByteArray &entityId, const QByteArray &property, const QVariant &expectedValue) Q_DECL_OVERRIDE;
47private:
48 46
47private:
49 QStringList listAvailableFolders(); 48 QStringList listAvailableFolders();
50 QString mMaildirPath; 49 QString mMaildirPath;
51 QString mDraftsFolder; 50 QString mDraftsFolder;
diff --git a/examples/mailtransportresource/mailtransportresource.cpp b/examples/mailtransportresource/mailtransportresource.cpp
index c135de9..524b411 100644
--- a/examples/mailtransportresource/mailtransportresource.cpp
+++ b/examples/mailtransportresource/mailtransportresource.cpp
@@ -22,7 +22,7 @@
22#include "facadefactory.h" 22#include "facadefactory.h"
23#include "resourceconfig.h" 23#include "resourceconfig.h"
24#include "definitions.h" 24#include "definitions.h"
25#include "domainadaptor.h" 25#include "inspector.h"
26#include <QDir> 26#include <QDir>
27#include <QFileInfo> 27#include <QFileInfo>
28#include <QSettings> 28#include <QSettings>
@@ -124,6 +124,31 @@ public:
124 MailtransportResource::Settings mSettings; 124 MailtransportResource::Settings mSettings;
125}; 125};
126 126
127class MailtransportInspector : public Sink::Inspector {
128public:
129 MailtransportInspector(const Sink::ResourceContext &resourceContext)
130 : Sink::Inspector(resourceContext)
131 {
132
133 }
134
135protected:
136 KAsync::Job<void> inspect(int inspectionType, const QByteArray &inspectionId, const QByteArray &domainType, const QByteArray &entityId, const QByteArray &property, const QVariant &expectedValue) Q_DECL_OVERRIDE
137 {
138 if (domainType == ENTITY_TYPE_MAIL) {
139 if (inspectionType == Sink::ResourceControl::Inspection::ExistenceInspectionType) {
140 auto path = resourceStorageLocation(mResourceContext.instanceId()) + "/test/" + entityId;
141 if (QFileInfo::exists(path)) {
142 return KAsync::null<void>();
143 }
144 return KAsync::error<void>(1, "Couldn't find message: " + path);
145 }
146 }
147 return KAsync::null<void>();
148 }
149};
150
151
127MailtransportResource::MailtransportResource(const Sink::ResourceContext &resourceContext) 152MailtransportResource::MailtransportResource(const Sink::ResourceContext &resourceContext)
128 : Sink::GenericResource(resourceContext) 153 : Sink::GenericResource(resourceContext)
129{ 154{
@@ -138,30 +163,11 @@ MailtransportResource::MailtransportResource(const Sink::ResourceContext &resour
138 auto synchronizer = QSharedPointer<MailtransportSynchronizer>::create(resourceContext); 163 auto synchronizer = QSharedPointer<MailtransportSynchronizer>::create(resourceContext);
139 synchronizer->mSettings = mSettings; 164 synchronizer->mSettings = mSettings;
140 setupSynchronizer(synchronizer); 165 setupSynchronizer(synchronizer);
166 setupInspector(QSharedPointer<MailtransportInspector>::create(resourceContext));
141 167
142 setupPreprocessors(ENTITY_TYPE_MAIL, QVector<Sink::Preprocessor*>() << new MimeMessageMover << new MailPropertyExtractor); 168 setupPreprocessors(ENTITY_TYPE_MAIL, QVector<Sink::Preprocessor*>() << new MimeMessageMover << new MailPropertyExtractor);
143} 169}
144 170
145void MailtransportResource::removeFromDisk(const QByteArray &instanceIdentifier)
146{
147 GenericResource::removeFromDisk(instanceIdentifier);
148 Sink::Storage::DataStore(Sink::storageLocation(), instanceIdentifier + ".synchronization", Sink::Storage::DataStore::ReadWrite).removeFromDisk();
149}
150
151KAsync::Job<void> MailtransportResource::inspect(int inspectionType, const QByteArray &inspectionId, const QByteArray &domainType, const QByteArray &entityId, const QByteArray &property, const QVariant &expectedValue)
152{
153 if (domainType == ENTITY_TYPE_MAIL) {
154 if (inspectionType == Sink::ResourceControl::Inspection::ExistenceInspectionType) {
155 auto path = resourceStorageLocation(mResourceContext.instanceId()) + "/test/" + entityId;
156 if (QFileInfo::exists(path)) {
157 return KAsync::null<void>();
158 }
159 return KAsync::error<void>(1, "Couldn't find message: " + path);
160 }
161 }
162 return KAsync::null<void>();
163}
164
165MailtransportResourceFactory::MailtransportResourceFactory(QObject *parent) 171MailtransportResourceFactory::MailtransportResourceFactory(QObject *parent)
166 : Sink::ResourceFactory(parent) 172 : Sink::ResourceFactory(parent)
167{ 173{
diff --git a/examples/mailtransportresource/mailtransportresource.h b/examples/mailtransportresource/mailtransportresource.h
index 95a9cd7..531fcd5 100644
--- a/examples/mailtransportresource/mailtransportresource.h
+++ b/examples/mailtransportresource/mailtransportresource.h
@@ -26,8 +26,6 @@ class MailtransportResource : public Sink::GenericResource
26{ 26{
27public: 27public:
28 MailtransportResource(const Sink::ResourceContext &resourceContext); 28 MailtransportResource(const Sink::ResourceContext &resourceContext);
29 KAsync::Job<void> inspect(int inspectionType, const QByteArray &inspectionId, const QByteArray &domainType, const QByteArray &entityId, const QByteArray &property, const QVariant &expectedValue) Q_DECL_OVERRIDE;
30 static void removeFromDisk(const QByteArray &instanceIdentifier);
31 29
32 struct Settings { 30 struct Settings {
33 QString server; 31 QString server;