summaryrefslogtreecommitdiffstats
path: root/examples/imapresource/imapresource.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'examples/imapresource/imapresource.cpp')
-rw-r--r--examples/imapresource/imapresource.cpp128
1 files changed, 118 insertions, 10 deletions
diff --git a/examples/imapresource/imapresource.cpp b/examples/imapresource/imapresource.cpp
index fee479a..ac75432 100644
--- a/examples/imapresource/imapresource.cpp
+++ b/examples/imapresource/imapresource.cpp
@@ -39,12 +39,14 @@
39#include "sourcewriteback.h" 39#include "sourcewriteback.h"
40#include "entitystore.h" 40#include "entitystore.h"
41#include "remoteidmap.h" 41#include "remoteidmap.h"
42#include "query.h"
42#include <QDate> 43#include <QDate>
43#include <QUuid> 44#include <QUuid>
44#include <QDir> 45#include <QDir>
45#include <QDirIterator> 46#include <QDirIterator>
46 47
47#include "imapserverproxy.h" 48#include "imapserverproxy.h"
49#include "entityreader.h"
48 50
49//This is the resources entity type, and not the domain type 51//This is the resources entity type, and not the domain type
50#define ENTITY_TYPE_MAIL "mail" 52#define ENTITY_TYPE_MAIL "mail"
@@ -56,6 +58,77 @@
56using namespace Imap; 58using namespace Imap;
57using namespace Sink; 59using namespace Sink;
58 60
61static QHash<QByteArray, QString> specialPurposeFolders()
62{
63 QHash<QByteArray, QString> hash;
64 //FIXME localize
65 hash.insert("drafts", "Drafts");
66 return hash;
67}
68
69static QHash<QString, QByteArray> specialPurposeNames()
70{
71 QHash<QString, QByteArray> hash;
72 for (const auto &value : specialPurposeFolders().values()) {
73 hash.insert(value.toLower(), specialPurposeFolders().key(value));
74 }
75 return hash;
76}
77
78//specialpurpose, name
79static QHash<QByteArray, QString> sSpecialPurposeFolders = specialPurposeFolders();
80//Lowercase-name, specialpurpose
81static QHash<QString, QByteArray> sSpecialPurposeNames = specialPurposeNames();
82
83class DraftsProcessor : public Sink::Preprocessor
84{
85public:
86 DraftsProcessor() {}
87
88 QByteArray ensureDraftsFolder(Sink::Storage::Transaction &transaction)
89 {
90 if (mDraftsFolder.isEmpty()) {
91 //Try to find an existing drafts folder
92 Sink::EntityReader<ApplicationDomain::Folder> reader(mResourceInstanceIdentifier, mResourceType, transaction);
93 reader.query(Sink::Query().filter<ApplicationDomain::Folder::SpecialPurpose>(Query::Comparator("drafts", Query::Comparator::Contains)),
94 [this](const ApplicationDomain::Folder &f) -> bool{
95 mDraftsFolder = f.identifier();
96 return false;
97 });
98 if (mDraftsFolder.isEmpty()) {
99 Trace() << "Failed to find a drafts folder, creating a new one";
100 auto folder = ApplicationDomain::Folder::create(mResourceInstanceIdentifier);
101 folder.setSpecialPurpose(QByteArrayList() << "drafts");
102 folder.setName(sSpecialPurposeFolders.value("drafts"));
103 folder.setIcon("folder");
104 //This processes the pipeline synchronously
105 createEntity(folder);
106 mDraftsFolder = folder.identifier();
107 }
108 }
109 return mDraftsFolder;
110 }
111
112 void newEntity(const QByteArray &uid, qint64 revision, Sink::ApplicationDomain::BufferAdaptor &newEntity, Sink::Storage::Transaction &transaction) Q_DECL_OVERRIDE
113 {
114 if (newEntity.getProperty("draft").toBool()) {
115 newEntity.setProperty("folder", ensureDraftsFolder(transaction));
116 }
117 }
118
119 void modifiedEntity(const QByteArray &uid, qint64 revision, const Sink::ApplicationDomain::BufferAdaptor &oldEntity, Sink::ApplicationDomain::BufferAdaptor &newEntity,
120 Sink::Storage::Transaction &transaction) Q_DECL_OVERRIDE
121 {
122 if (newEntity.getProperty("draft").toBool()) {
123 newEntity.setProperty("folder", ensureDraftsFolder(transaction));
124 }
125 }
126
127 QByteArray mDraftsFolder;
128 QByteArray mResourceInstanceIdentifier;
129 QByteArray mResourceType;
130};
131
59class MailPropertyExtractor : public Sink::Preprocessor 132class MailPropertyExtractor : public Sink::Preprocessor
60{ 133{
61public: 134public:
@@ -97,10 +170,6 @@ public:
97 updatedIndexedProperties(newEntity); 170 updatedIndexedProperties(newEntity);
98 } 171 }
99 172
100 void deletedEntity(const QByteArray &uid, qint64 revision, const Sink::ApplicationDomain::BufferAdaptor &oldEntity, Sink::Storage::Transaction &transaction) Q_DECL_OVERRIDE
101 {
102 }
103
104}; 173};
105 174
106static qint64 uidFromMailRid(const QByteArray &remoteId) 175static qint64 uidFromMailRid(const QByteArray &remoteId)
@@ -142,13 +211,19 @@ public:
142 const auto remoteId = folderPath.toUtf8(); 211 const auto remoteId = folderPath.toUtf8();
143 const auto bufferType = ENTITY_TYPE_FOLDER; 212 const auto bufferType = ENTITY_TYPE_FOLDER;
144 Sink::ApplicationDomain::Folder folder; 213 Sink::ApplicationDomain::Folder folder;
145 folder.setProperty("name", folderName); 214 folder.setProperty(ApplicationDomain::Folder::Name::name, folderName);
146 folder.setProperty("icon", icon); 215 folder.setProperty(ApplicationDomain::Folder::Icon::name, icon);
216 QHash<QByteArray, Query::Comparator> mergeCriteria;
217 if (sSpecialPurposeNames.contains(folderName.toLower())) {
218 auto type = sSpecialPurposeNames.value(folderName.toLower());
219 folder.setProperty(ApplicationDomain::Folder::SpecialPurpose::name, QVariant::fromValue(QByteArrayList() << type));
220 mergeCriteria.insert(ApplicationDomain::Folder::SpecialPurpose::name, Query::Comparator(type, Query::Comparator::Contains));
221 }
147 222
148 if (!parentFolderRid.isEmpty()) { 223 if (!parentFolderRid.isEmpty()) {
149 folder.setProperty("parent", syncStore().resolveRemoteId(ENTITY_TYPE_FOLDER, parentFolderRid.toUtf8())); 224 folder.setProperty("parent", syncStore().resolveRemoteId(ENTITY_TYPE_FOLDER, parentFolderRid.toUtf8()));
150 } 225 }
151 createOrModify(bufferType, remoteId, folder); 226 createOrModify(bufferType, remoteId, folder, mergeCriteria);
152 return remoteId; 227 return remoteId;
153 } 228 }
154 229
@@ -434,14 +509,47 @@ public:
434 } 509 }
435 Trace() << "Creating a new folder: " << parentFolder << folder.getName(); 510 Trace() << "Creating a new folder: " << parentFolder << folder.getName();
436 auto rid = QSharedPointer<QByteArray>::create(); 511 auto rid = QSharedPointer<QByteArray>::create();
437 return login.then<QString>(imap->createSubfolder(parentFolder, folder.getName())) 512 auto createFolder = login.then<QString>(imap->createSubfolder(parentFolder, folder.getName()))
438 .then<void, QString>([imap, rid](const QString &createdFolder) { 513 .then<void, QString>([imap, rid](const QString &createdFolder) {
439 Trace() << "Finished creating a new folder: " << createdFolder; 514 Trace() << "Finished creating a new folder: " << createdFolder;
440 *rid = createdFolder.toUtf8(); 515 *rid = createdFolder.toUtf8();
441 }) 516 });
517 if (folder.getSpecialPurpose().isEmpty()) {
518 return createFolder
519 .then<QByteArray>([rid](){
520 return *rid;
521 });
522 } else { //We try to merge special purpose folders first
523 auto specialPurposeFolders = QSharedPointer<QHash<QByteArray, QString>>::create();
524 auto mergeJob = imap->login(mUser, mPassword)
525 .then<void>(imap->fetchFolders([=](const QVector<Imap::Folder> &folders) {
526 for (const auto &f : folders) {
527 if (sSpecialPurposeNames.contains(f.pathParts.last().toLower())) {
528 specialPurposeFolders->insert(sSpecialPurposeNames.value(f.pathParts.last().toLower()), f.path);
529 };
530 }
531 }))
532 .then<void, KAsync::Job<void>>([specialPurposeFolders, folder, imap, parentFolder, rid]() -> KAsync::Job<void> {
533 for (const auto &purpose : folder.getSpecialPurpose()) {
534 if (specialPurposeFolders->contains(purpose)) {
535 auto f = specialPurposeFolders->value(purpose);
536 Trace() << "Merging specialpurpose folder with: " << f << " with purpose: " << purpose;
537 *rid = f.toUtf8();
538 return KAsync::null<void>();
539 }
540 Trace() << "No match found for merging, creating a new folder";
541 return imap->createSubfolder(parentFolder, folder.getName())
542 .then<void, QString>([imap, rid](const QString &createdFolder) {
543 Trace() << "Finished creating a new folder: " << createdFolder;
544 *rid = createdFolder.toUtf8();
545 });
546
547 })
442 .then<QByteArray>([rid](){ 548 .then<QByteArray>([rid](){
443 return *rid; 549 return *rid;
444 }); 550 });
551 return mergeJob;
552 }
445 } else if (operation == Sink::Operation_Removal) { 553 } else if (operation == Sink::Operation_Removal) {
446 Trace() << "Removing a folder: " << oldRemoteId; 554 Trace() << "Removing a folder: " << oldRemoteId;
447 return login.then<void>(imap->remove(oldRemoteId)) 555 return login.then<void>(imap->remove(oldRemoteId))
@@ -495,7 +603,7 @@ ImapResource::ImapResource(const QByteArray &instanceIdentifier, const QSharedPo
495 changereplay->mPassword = mPassword; 603 changereplay->mPassword = mPassword;
496 setupChangereplay(changereplay); 604 setupChangereplay(changereplay);
497 605
498 setupPreprocessors(ENTITY_TYPE_MAIL, QVector<Sink::Preprocessor*>() << new MailPropertyExtractor << new DefaultIndexUpdater<Sink::ApplicationDomain::Mail>); 606 setupPreprocessors(ENTITY_TYPE_MAIL, QVector<Sink::Preprocessor*>() << new DraftsProcessor << new MailPropertyExtractor << new DefaultIndexUpdater<Sink::ApplicationDomain::Mail>);
499 setupPreprocessors(ENTITY_TYPE_FOLDER, QVector<Sink::Preprocessor*>() << new DefaultIndexUpdater<Sink::ApplicationDomain::Folder>); 607 setupPreprocessors(ENTITY_TYPE_FOLDER, QVector<Sink::Preprocessor*>() << new DefaultIndexUpdater<Sink::ApplicationDomain::Folder>);
500} 608}
501 609