summaryrefslogtreecommitdiffstats
path: root/examples/imapresource/imapresource.cpp
diff options
context:
space:
mode:
authorChristian Mollekopf <chrigi_1@fastmail.fm>2016-11-28 19:33:01 +0100
committerChristian Mollekopf <chrigi_1@fastmail.fm>2016-11-28 19:33:01 +0100
commit938554f267193b652478fc12343819fa45d76034 (patch)
tree1c027f97f3209571740377f1d4b7e6721d8de777 /examples/imapresource/imapresource.cpp
parent885f185f55249a2e97e9c7c238f89a5d0d99d1df (diff)
downloadsink-938554f267193b652478fc12343819fa45d76034.tar.gz
sink-938554f267193b652478fc12343819fa45d76034.zip
Moved inspection commands to a separate inspector.
Diffstat (limited to 'examples/imapresource/imapresource.cpp')
-rw-r--r--examples/imapresource/imapresource.cpp306
1 files changed, 165 insertions, 141 deletions
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)