diff options
Diffstat (limited to 'examples/imapresource/imapresource.cpp')
-rw-r--r-- | examples/imapresource/imapresource.cpp | 128 |
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 @@ | |||
56 | using namespace Imap; | 58 | using namespace Imap; |
57 | using namespace Sink; | 59 | using namespace Sink; |
58 | 60 | ||
61 | static QHash<QByteArray, QString> specialPurposeFolders() | ||
62 | { | ||
63 | QHash<QByteArray, QString> hash; | ||
64 | //FIXME localize | ||
65 | hash.insert("drafts", "Drafts"); | ||
66 | return hash; | ||
67 | } | ||
68 | |||
69 | static 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 | ||
79 | static QHash<QByteArray, QString> sSpecialPurposeFolders = specialPurposeFolders(); | ||
80 | //Lowercase-name, specialpurpose | ||
81 | static QHash<QString, QByteArray> sSpecialPurposeNames = specialPurposeNames(); | ||
82 | |||
83 | class DraftsProcessor : public Sink::Preprocessor | ||
84 | { | ||
85 | public: | ||
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 | |||
59 | class MailPropertyExtractor : public Sink::Preprocessor | 132 | class MailPropertyExtractor : public Sink::Preprocessor |
60 | { | 133 | { |
61 | public: | 134 | public: |
@@ -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 | ||
106 | static qint64 uidFromMailRid(const QByteArray &remoteId) | 175 | static 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 | ||