summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristian Mollekopf <chrigi_1@fastmail.fm>2016-06-23 17:05:47 +0200
committerChristian Mollekopf <chrigi_1@fastmail.fm>2016-06-25 23:34:51 +0200
commitb29a17465d1e52bd7dd5c57f08e7af53e915eee6 (patch)
treeab618b5f0a1c89ba1332723b5ebad03bce92fb2c
parent2ce8dcf40f22dd4e9cf4a6b1c8f5386993ebba6e (diff)
downloadsink-b29a17465d1e52bd7dd5c57f08e7af53e915eee6.tar.gz
sink-b29a17465d1e52bd7dd5c57f08e7af53e915eee6.zip
Share special purpose preprocessor implementation.
-rw-r--r--common/CMakeLists.txt1
-rw-r--r--common/specialpurposepreprocessor.cpp88
-rw-r--r--common/specialpurposepreprocessor.h43
-rw-r--r--examples/imapresource/imapresource.cpp88
4 files changed, 137 insertions, 83 deletions
diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt
index 3083a2e..5eb15ba 100644
--- a/common/CMakeLists.txt
+++ b/common/CMakeLists.txt
@@ -74,6 +74,7 @@ set(command_SRCS
74 sourcewriteback.cpp 74 sourcewriteback.cpp
75 entityreader.cpp 75 entityreader.cpp
76 mailpreprocessor.cpp 76 mailpreprocessor.cpp
77 specialpurposepreprocessor.cpp
77 ${storage_SRCS}) 78 ${storage_SRCS})
78 79
79add_library(${PROJECT_NAME} SHARED ${command_SRCS}) 80add_library(${PROJECT_NAME} SHARED ${command_SRCS})
diff --git a/common/specialpurposepreprocessor.cpp b/common/specialpurposepreprocessor.cpp
new file mode 100644
index 0000000..2892105
--- /dev/null
+++ b/common/specialpurposepreprocessor.cpp
@@ -0,0 +1,88 @@
1#include "specialpurposepreprocessor.h"
2#include "entityreader.h"
3#include "query.h"
4#include "applicationdomaintype.h"
5
6using namespace Sink;
7
8static QHash<QByteArray, QString> specialPurposeFolders()
9{
10 QHash<QByteArray, QString> hash;
11 //FIXME localize
12 hash.insert("drafts", "Drafts");
13 hash.insert("trash", "Trash");
14 return hash;
15}
16
17static QHash<QString, QByteArray> specialPurposeNames()
18{
19 QHash<QString, QByteArray> hash;
20 for (const auto &value : specialPurposeFolders().values()) {
21 hash.insert(value.toLower(), specialPurposeFolders().key(value));
22 }
23 return hash;
24}
25
26//specialpurpose, name
27static QHash<QByteArray, QString> sSpecialPurposeFolders = specialPurposeFolders();
28//Lowercase-name, specialpurpose
29static QHash<QString, QByteArray> sSpecialPurposeNames = specialPurposeNames();
30
31namespace SpecialPurpose {
32bool isSpecialPurposeFolderName(const QString &name)
33{
34 return sSpecialPurposeNames.contains(name.toLower());
35}
36
37QByteArray getSpecialPurposeType(const QString &name)
38{
39 return sSpecialPurposeNames.value(name.toLower());
40}
41}
42
43SpecialPurposeProcessor::SpecialPurposeProcessor(const QByteArray &resourceType, const QByteArray &resourceInstanceIdentifier) : mResourceType(resourceType), mResourceInstanceIdentifier(resourceInstanceIdentifier) {}
44
45QByteArray SpecialPurposeProcessor::ensureFolder(Sink::Storage::Transaction &transaction, const QByteArray &specialPurpose)
46{
47 if (!mSpecialPurposeFolders.contains(specialPurpose)) {
48 //Try to find an existing drafts folder
49 Sink::EntityReader<ApplicationDomain::Folder> reader(mResourceType, mResourceInstanceIdentifier, transaction);
50 reader.query(Sink::Query().filter<ApplicationDomain::Folder::SpecialPurpose>(Query::Comparator(specialPurpose, Query::Comparator::Contains)),
51 [this, specialPurpose](const ApplicationDomain::Folder &f) -> bool{
52 mSpecialPurposeFolders.insert(specialPurpose, f.identifier());
53 return false;
54 });
55 if (!mSpecialPurposeFolders.contains(specialPurpose)) {
56 Trace() << "Failed to find a drafts folder, creating a new one";
57 auto folder = ApplicationDomain::Folder::create(mResourceInstanceIdentifier);
58 folder.setSpecialPurpose(QByteArrayList() << specialPurpose);
59 folder.setName(sSpecialPurposeFolders.value(specialPurpose));
60 folder.setIcon("folder");
61 //This processes the pipeline synchronously
62 createEntity(folder);
63 mSpecialPurposeFolders.insert(specialPurpose, folder.identifier());
64 }
65 }
66 return mSpecialPurposeFolders.value(specialPurpose);
67}
68
69void SpecialPurposeProcessor::moveToFolder(Sink::ApplicationDomain::BufferAdaptor &newEntity, Sink::Storage::Transaction &transaction)
70{
71 if (newEntity.getProperty("trash").toBool()) {
72 newEntity.setProperty("folder", ensureFolder(transaction, "trash"));
73 return;
74 }
75 if (newEntity.getProperty("draft").toBool()) {
76 newEntity.setProperty("folder", ensureFolder(transaction, "drafts"));
77 }
78}
79
80void SpecialPurposeProcessor::newEntity(const QByteArray &uid, qint64 revision, Sink::ApplicationDomain::BufferAdaptor &newEntity, Sink::Storage::Transaction &transaction)
81{
82 moveToFolder(newEntity, transaction);
83}
84
85void SpecialPurposeProcessor::modifiedEntity(const QByteArray &uid, qint64 revision, const Sink::ApplicationDomain::BufferAdaptor &oldEntity, Sink::ApplicationDomain::BufferAdaptor &newEntity, Sink::Storage::Transaction &transaction)
86{
87 moveToFolder(newEntity, transaction);
88}
diff --git a/common/specialpurposepreprocessor.h b/common/specialpurposepreprocessor.h
new file mode 100644
index 0000000..a33701b
--- /dev/null
+++ b/common/specialpurposepreprocessor.h
@@ -0,0 +1,43 @@
1/*
2 * Copyright (C) 2015 Christian Mollekopf <chrigi_1@fastmail.fm>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the
16 * Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19#include "sink_export.h"
20
21#include "pipeline.h"
22
23namespace SpecialPurpose {
24 bool SINK_EXPORT isSpecialPurposeFolderName(const QString &name);
25 QByteArray SINK_EXPORT getSpecialPurposeType(const QString &name);
26}
27
28class SINK_EXPORT SpecialPurposeProcessor : public Sink::Preprocessor
29{
30public:
31 SpecialPurposeProcessor(const QByteArray &resourceType, const QByteArray &resourceInstanceIdentifier);
32
33 QByteArray ensureFolder(Sink::Storage::Transaction &transaction, const QByteArray &specialPurpose);
34
35 void moveToFolder(Sink::ApplicationDomain::BufferAdaptor &newEntity, Sink::Storage::Transaction &transaction);
36
37 void newEntity(const QByteArray &uid, qint64 revision, Sink::ApplicationDomain::BufferAdaptor &newEntity, Sink::Storage::Transaction &transaction) Q_DECL_OVERRIDE;
38 void modifiedEntity(const QByteArray &uid, qint64 revision, const Sink::ApplicationDomain::BufferAdaptor &oldEntity, Sink::ApplicationDomain::BufferAdaptor &newEntity, Sink::Storage::Transaction &transaction) Q_DECL_OVERRIDE;
39
40 QHash<QByteArray, QByteArray> mSpecialPurposeFolders;
41 QByteArray mResourceType;
42 QByteArray mResourceInstanceIdentifier;
43};
diff --git a/examples/imapresource/imapresource.cpp b/examples/imapresource/imapresource.cpp
index 18747bf..605dbc2 100644
--- a/examples/imapresource/imapresource.cpp
+++ b/examples/imapresource/imapresource.cpp
@@ -48,6 +48,7 @@
48#include "imapserverproxy.h" 48#include "imapserverproxy.h"
49#include "entityreader.h" 49#include "entityreader.h"
50#include "mailpreprocessor.h" 50#include "mailpreprocessor.h"
51#include "specialpurposepreprocessor.h"
51 52
52//This is the resources entity type, and not the domain type 53//This is the resources entity type, and not the domain type
53#define ENTITY_TYPE_MAIL "mail" 54#define ENTITY_TYPE_MAIL "mail"
@@ -59,85 +60,6 @@
59using namespace Imap; 60using namespace Imap;
60using namespace Sink; 61using namespace Sink;
61 62
62static QHash<QByteArray, QString> specialPurposeFolders()
63{
64 QHash<QByteArray, QString> hash;
65 //FIXME localize
66 hash.insert("drafts", "Drafts");
67 hash.insert("trash", "Trash");
68 return hash;
69}
70
71static QHash<QString, QByteArray> specialPurposeNames()
72{
73 QHash<QString, QByteArray> hash;
74 for (const auto &value : specialPurposeFolders().values()) {
75 hash.insert(value.toLower(), specialPurposeFolders().key(value));
76 }
77 return hash;
78}
79
80//specialpurpose, name
81static QHash<QByteArray, QString> sSpecialPurposeFolders = specialPurposeFolders();
82//Lowercase-name, specialpurpose
83static QHash<QString, QByteArray> sSpecialPurposeNames = specialPurposeNames();
84
85class SpecialPurposeProcessor : public Sink::Preprocessor
86{
87public:
88 SpecialPurposeProcessor(const QByteArray &resourceType, const QByteArray &resourceInstanceIdentifier) : mResourceType(resourceType), mResourceInstanceIdentifier(resourceInstanceIdentifier) {}
89
90 QByteArray ensureFolder(Sink::Storage::Transaction &transaction, const QByteArray &specialPurpose)
91 {
92 if (!mSpecialPurposeFolders.contains(specialPurpose)) {
93 //Try to find an existing drafts folder
94 Sink::EntityReader<ApplicationDomain::Folder> reader(mResourceType, mResourceInstanceIdentifier, transaction);
95 reader.query(Sink::Query().filter<ApplicationDomain::Folder::SpecialPurpose>(Query::Comparator("drafts", Query::Comparator::Contains)),
96 [this, specialPurpose](const ApplicationDomain::Folder &f) -> bool{
97 mSpecialPurposeFolders.insert(specialPurpose, f.identifier());
98 return false;
99 });
100 if (!mSpecialPurposeFolders.contains(specialPurpose)) {
101 Trace() << "Failed to find a drafts folder, creating a new one";
102 auto folder = ApplicationDomain::Folder::create(mResourceInstanceIdentifier);
103 folder.setSpecialPurpose(QByteArrayList() << specialPurpose);
104 folder.setName(sSpecialPurposeFolders.value(specialPurpose));
105 folder.setIcon("folder");
106 //This processes the pipeline synchronously
107 createEntity(folder);
108 mSpecialPurposeFolders.insert(specialPurpose, folder.identifier());
109 }
110 }
111 return mSpecialPurposeFolders.value(specialPurpose);
112 }
113
114 void moveToFolder(Sink::ApplicationDomain::BufferAdaptor &newEntity, Sink::Storage::Transaction &transaction)
115 {
116 if (newEntity.getProperty("trash").toBool()) {
117 newEntity.setProperty("folder", ensureFolder(transaction, "trash"));
118 return;
119 }
120 if (newEntity.getProperty("draft").toBool()) {
121 newEntity.setProperty("folder", ensureFolder(transaction, "drafts"));
122 }
123 }
124
125 void newEntity(const QByteArray &uid, qint64 revision, Sink::ApplicationDomain::BufferAdaptor &newEntity, Sink::Storage::Transaction &transaction) Q_DECL_OVERRIDE
126 {
127 moveToFolder(newEntity, transaction);
128 }
129
130 void modifiedEntity(const QByteArray &uid, qint64 revision, const Sink::ApplicationDomain::BufferAdaptor &oldEntity, Sink::ApplicationDomain::BufferAdaptor &newEntity, Sink::Storage::Transaction &transaction) Q_DECL_OVERRIDE
131 {
132 moveToFolder(newEntity, transaction);
133 }
134
135 QHash<QByteArray, QByteArray> mSpecialPurposeFolders;
136 QByteArray mResourceType;
137 QByteArray mResourceInstanceIdentifier;
138};
139
140
141static qint64 uidFromMailRid(const QByteArray &remoteId) 63static qint64 uidFromMailRid(const QByteArray &remoteId)
142{ 64{
143 auto ridParts = remoteId.split(':'); 65 auto ridParts = remoteId.split(':');
@@ -180,8 +102,8 @@ public:
180 folder.setProperty(ApplicationDomain::Folder::Name::name, folderName); 102 folder.setProperty(ApplicationDomain::Folder::Name::name, folderName);
181 folder.setProperty(ApplicationDomain::Folder::Icon::name, icon); 103 folder.setProperty(ApplicationDomain::Folder::Icon::name, icon);
182 QHash<QByteArray, Query::Comparator> mergeCriteria; 104 QHash<QByteArray, Query::Comparator> mergeCriteria;
183 if (sSpecialPurposeNames.contains(folderName.toLower())) { 105 if (SpecialPurpose::isSpecialPurposeFolderName(folderName)) {
184 auto type = sSpecialPurposeNames.value(folderName.toLower()); 106 auto type = SpecialPurpose::getSpecialPurposeType(folderName);
185 folder.setProperty(ApplicationDomain::Folder::SpecialPurpose::name, QVariant::fromValue(QByteArrayList() << type)); 107 folder.setProperty(ApplicationDomain::Folder::SpecialPurpose::name, QVariant::fromValue(QByteArrayList() << type));
186 mergeCriteria.insert(ApplicationDomain::Folder::SpecialPurpose::name, Query::Comparator(type, Query::Comparator::Contains)); 108 mergeCriteria.insert(ApplicationDomain::Folder::SpecialPurpose::name, Query::Comparator(type, Query::Comparator::Contains));
187 } 109 }
@@ -481,8 +403,8 @@ public:
481 auto mergeJob = imap->login(mUser, mPassword) 403 auto mergeJob = imap->login(mUser, mPassword)
482 .then<void>(imap->fetchFolders([=](const QVector<Imap::Folder> &folders) { 404 .then<void>(imap->fetchFolders([=](const QVector<Imap::Folder> &folders) {
483 for (const auto &f : folders) { 405 for (const auto &f : folders) {
484 if (sSpecialPurposeNames.contains(f.pathParts.last().toLower())) { 406 if (SpecialPurpose::isSpecialPurposeFolderName(f.pathParts.last())) {
485 specialPurposeFolders->insert(sSpecialPurposeNames.value(f.pathParts.last().toLower()), f.path); 407 specialPurposeFolders->insert(SpecialPurpose::getSpecialPurposeType(f.pathParts.last()), f.path);
486 }; 408 };
487 } 409 }
488 })) 410 }))