summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--common/domain/applicationdomaintype.h8
-rw-r--r--common/mailpreprocessor.cpp46
-rw-r--r--common/mailpreprocessor.h13
-rw-r--r--common/storage/entitystore.cpp51
-rw-r--r--common/storage/entitystore.h1
-rw-r--r--examples/dummyresource/resourcefactory.cpp2
-rw-r--r--examples/imapresource/imapresource.cpp2
-rw-r--r--examples/maildirresource/maildirresource.cpp14
-rw-r--r--examples/mailtransportresource/mailtransportresource.cpp2
9 files changed, 74 insertions, 65 deletions
diff --git a/common/domain/applicationdomaintype.h b/common/domain/applicationdomaintype.h
index 7c3800d..1848224 100644
--- a/common/domain/applicationdomaintype.h
+++ b/common/domain/applicationdomaintype.h
@@ -99,7 +99,15 @@ struct SINK_EXPORT Progress {
99}; 99};
100 100
101struct BLOB { 101struct BLOB {
102 BLOB() = default;
103 BLOB(const BLOB &) = default;
104 BLOB(const QString &id) : value(id) {};
105 ~BLOB() = default;
106 bool operator==(const BLOB &other) const {
107 return value == other.value && isExternal == other.isExternal;
108 }
102 QString value; 109 QString value;
110 bool isExternal = true;
103}; 111};
104 112
105/** 113/**
diff --git a/common/mailpreprocessor.cpp b/common/mailpreprocessor.cpp
index 575ff4b..bde8a64 100644
--- a/common/mailpreprocessor.cpp
+++ b/common/mailpreprocessor.cpp
@@ -152,49 +152,3 @@ void MailPropertyExtractor::modifiedEntity(const Sink::ApplicationDomain::Mail &
152 } 152 }
153} 153}
154 154
155
156MimeMessageMover::MimeMessageMover() : Sink::EntityPreprocessor<ApplicationDomain::Mail>()
157{
158}
159
160QString MimeMessageMover::moveMessage(const QString &oldPath, const Sink::ApplicationDomain::Mail &mail)
161{
162 const auto directory = Sink::resourceStorageLocation(resourceInstanceIdentifier());
163 const auto filePath = directory + "/" + mail.identifier();
164 if (oldPath != filePath) {
165 if (!QDir().mkpath(directory)) {
166 SinkWarning() << "Failed to create the directory: " << directory;
167 }
168 QFile::remove(filePath);
169 QFile origFile(oldPath);
170 if (!origFile.open(QIODevice::ReadWrite)) {
171 SinkWarning() << "Failed to open the original file with write rights: " << origFile.errorString();
172 }
173 if (!origFile.rename(filePath)) {
174 SinkWarning() << "Failed to move the file from: " << oldPath << " to " << filePath << ". " << origFile.errorString();
175 }
176 origFile.close();
177 return filePath;
178 }
179 return oldPath;
180}
181
182void MimeMessageMover::newEntity(Sink::ApplicationDomain::Mail &mail)
183{
184 if (!mail.getMimeMessagePath().isEmpty()) {
185 mail.setMimeMessagePath(moveMessage(mail.getMimeMessagePath(), mail));
186 }
187}
188
189void MimeMessageMover::modifiedEntity(const Sink::ApplicationDomain::Mail &oldMail, Sink::ApplicationDomain::Mail &newMail)
190{
191 if (!newMail.getMimeMessagePath().isEmpty()) {
192 newMail.setMimeMessagePath(moveMessage(newMail.getMimeMessagePath(), newMail));
193 }
194}
195
196void MimeMessageMover::deletedEntity(const Sink::ApplicationDomain::Mail &mail)
197{
198 QFile::remove(mail.getMimeMessagePath());
199}
200
diff --git a/common/mailpreprocessor.h b/common/mailpreprocessor.h
index f979f22..a24a8d3 100644
--- a/common/mailpreprocessor.h
+++ b/common/mailpreprocessor.h
@@ -30,16 +30,3 @@ protected:
30 virtual QString getFilePathFromMimeMessagePath(const QString &) const; 30 virtual QString getFilePathFromMimeMessagePath(const QString &) const;
31}; 31};
32 32
33class SINK_EXPORT MimeMessageMover : public Sink::EntityPreprocessor<Sink::ApplicationDomain::Mail>
34{
35public:
36 MimeMessageMover();
37 virtual ~MimeMessageMover(){}
38
39 void newEntity(Sink::ApplicationDomain::Mail &mail) Q_DECL_OVERRIDE;
40 void modifiedEntity(const Sink::ApplicationDomain::Mail &oldMail, Sink::ApplicationDomain::Mail &newMail) Q_DECL_OVERRIDE;
41 void deletedEntity(const Sink::ApplicationDomain::Mail &mail) Q_DECL_OVERRIDE;
42
43private:
44 QString moveMessage(const QString &oldPath, const Sink::ApplicationDomain::Mail &mail);
45};
diff --git a/common/storage/entitystore.cpp b/common/storage/entitystore.cpp
index 999bb2c..d8b1121 100644
--- a/common/storage/entitystore.cpp
+++ b/common/storage/entitystore.cpp
@@ -19,6 +19,9 @@
19 */ 19 */
20#include "entitystore.h" 20#include "entitystore.h"
21 21
22#include <QDir>
23#include <QFile>
24
22#include "entitybuffer.h" 25#include "entitybuffer.h"
23#include "log.h" 26#include "log.h"
24#include "typeindex.h" 27#include "typeindex.h"
@@ -90,6 +93,11 @@ public:
90 return ApplicationDomain::ApplicationDomainType{resourceContext.instanceId(), uid, revision, adaptor}; 93 return ApplicationDomain::ApplicationDomainType{resourceContext.instanceId(), uid, revision, adaptor};
91 } 94 }
92 95
96 QString entityBlobStoragePath(const QByteArray &id)
97 {
98 return Sink::resourceStorageLocation(resourceContext.instanceId()) + "/blob/" + id;
99 }
100
93}; 101};
94 102
95EntityStore::EntityStore(const ResourceContext &context) 103EntityStore::EntityStore(const ResourceContext &context)
@@ -120,6 +128,38 @@ void EntityStore::abortTransaction()
120 d->transaction = Storage::DataStore::Transaction(); 128 d->transaction = Storage::DataStore::Transaction();
121} 129}
122 130
131void EntityStore::copyBlobs(ApplicationDomain::ApplicationDomainType &entity, qint64 newRevision)
132{
133 const auto directory = d->entityBlobStoragePath(entity.identifier());
134 if (!QDir().mkpath(directory)) {
135 SinkWarning() << "Failed to create the directory: " << directory;
136 }
137
138 for (const auto &property : entity.changedProperties()) {
139 const auto value = entity.getProperty(property);
140 if (value.canConvert<ApplicationDomain::BLOB>()) {
141 const auto blob = value.value<ApplicationDomain::BLOB>();
142 bool blobIsExternal = blob.isExternal;
143 //Any blob that is not part of the storage yet has to be moved there.
144 if (blob.isExternal) {
145 auto oldPath = blob.value;
146 auto filePath = directory + QString("/%1%2.blob").arg(QString::number(newRevision)).arg(QString::fromLatin1(property));
147 //In case we hit the same revision again due to a rollback.
148 QFile::remove(filePath);
149 QFile origFile(oldPath);
150 if (!origFile.open(QIODevice::ReadWrite)) {
151 SinkWarning() << "Failed to open the original file with write rights: " << origFile.errorString();
152 }
153 if (!origFile.rename(filePath)) {
154 SinkWarning() << "Failed to move the file from: " << oldPath << " to " << filePath << ". " << origFile.errorString();
155 }
156 origFile.close();
157 entity.setProperty(property, QVariant::fromValue(ApplicationDomain::BLOB{filePath}));
158 }
159 }
160 }
161}
162
123bool EntityStore::add(const QByteArray &type, const ApplicationDomain::ApplicationDomainType &entity_, bool replayToSource, const PreprocessCreation &preprocess) 163bool EntityStore::add(const QByteArray &type, const ApplicationDomain::ApplicationDomainType &entity_, bool replayToSource, const PreprocessCreation &preprocess)
124{ 164{
125 if (entity_.identifier().isEmpty()) { 165 if (entity_.identifier().isEmpty()) {
@@ -138,6 +178,8 @@ bool EntityStore::add(const QByteArray &type, const ApplicationDomain::Applicati
138 //The maxRevision may have changed meanwhile if the entity created sub-entities 178 //The maxRevision may have changed meanwhile if the entity created sub-entities
139 const qint64 newRevision = maxRevision() + 1; 179 const qint64 newRevision = maxRevision() + 1;
140 180
181 copyBlobs(entity, newRevision);
182
141 // Add metadata buffer 183 // Add metadata buffer
142 flatbuffers::FlatBufferBuilder metadataFbb; 184 flatbuffers::FlatBufferBuilder metadataFbb;
143 auto metadataBuilder = MetadataBuilder(metadataFbb); 185 auto metadataBuilder = MetadataBuilder(metadataFbb);
@@ -192,6 +234,8 @@ bool EntityStore::modify(const QByteArray &type, const ApplicationDomain::Applic
192 234
193 const qint64 newRevision = DataStore::maxRevision(d->transaction) + 1; 235 const qint64 newRevision = DataStore::maxRevision(d->transaction) + 1;
194 236
237 copyBlobs(newEntity, newRevision);
238
195 // Add metadata buffer 239 // Add metadata buffer
196 flatbuffers::FlatBufferBuilder metadataFbb; 240 flatbuffers::FlatBufferBuilder metadataFbb;
197 { 241 {
@@ -297,6 +341,13 @@ void EntityStore::cleanupRevision(qint64 revision)
297 DataStore::removeRevision(d->transaction, rev); 341 DataStore::removeRevision(d->transaction, rev);
298 DataStore::mainDatabase(d->transaction, bufferType).remove(key); 342 DataStore::mainDatabase(d->transaction, bufferType).remove(key);
299 } 343 }
344 if (metadata->operation() == Operation_Removal) {
345 const auto directory = d->entityBlobStoragePath(uid);
346 QDir dir(directory);
347 if (!dir.removeRecursively()) {
348 SinkError() << "Failed to cleanup: " << directory;
349 }
350 }
300 } 351 }
301 352
302 return true; 353 return true;
diff --git a/common/storage/entitystore.h b/common/storage/entitystore.h
index 06ca8c4..c626ebc 100644
--- a/common/storage/entitystore.h
+++ b/common/storage/entitystore.h
@@ -110,6 +110,7 @@ public:
110 qint64 maxRevision(); 110 qint64 maxRevision();
111 111
112private: 112private:
113 void copyBlobs(ApplicationDomain::ApplicationDomainType &entity, qint64 newRevision);
113 class Private; 114 class Private;
114 const QSharedPointer<Private> d; 115 const QSharedPointer<Private> d;
115}; 116};
diff --git a/examples/dummyresource/resourcefactory.cpp b/examples/dummyresource/resourcefactory.cpp
index 07021b9..03238ef 100644
--- a/examples/dummyresource/resourcefactory.cpp
+++ b/examples/dummyresource/resourcefactory.cpp
@@ -163,7 +163,7 @@ DummyResource::DummyResource(const Sink::ResourceContext &resourceContext, const
163 setupSynchronizer(QSharedPointer<DummySynchronizer>::create(resourceContext)); 163 setupSynchronizer(QSharedPointer<DummySynchronizer>::create(resourceContext));
164 setupInspector(QSharedPointer<DummyInspector>::create(resourceContext)); 164 setupInspector(QSharedPointer<DummyInspector>::create(resourceContext));
165 setupPreprocessors(ENTITY_TYPE_MAIL, 165 setupPreprocessors(ENTITY_TYPE_MAIL,
166 QVector<Sink::Preprocessor*>() << new MailPropertyExtractor << new MimeMessageMover << new SpecialPurposeProcessor{resourceContext.resourceType, resourceContext.instanceId()}); 166 QVector<Sink::Preprocessor*>() << new MailPropertyExtractor << new SpecialPurposeProcessor{resourceContext.resourceType, resourceContext.instanceId()});
167 setupPreprocessors(ENTITY_TYPE_FOLDER, 167 setupPreprocessors(ENTITY_TYPE_FOLDER,
168 QVector<Sink::Preprocessor*>()); 168 QVector<Sink::Preprocessor*>());
169 setupPreprocessors(ENTITY_TYPE_EVENT, 169 setupPreprocessors(ENTITY_TYPE_EVENT,
diff --git a/examples/imapresource/imapresource.cpp b/examples/imapresource/imapresource.cpp
index 238fb0c..252b910 100644
--- a/examples/imapresource/imapresource.cpp
+++ b/examples/imapresource/imapresource.cpp
@@ -737,7 +737,7 @@ ImapResource::ImapResource(const ResourceContext &resourceContext)
737 inspector->mPassword = password; 737 inspector->mPassword = password;
738 setupInspector(inspector); 738 setupInspector(inspector);
739 739
740 setupPreprocessors(ENTITY_TYPE_MAIL, QVector<Sink::Preprocessor*>() << new SpecialPurposeProcessor(resourceContext.resourceType, resourceContext.instanceId()) << new MimeMessageMover << new MailPropertyExtractor); 740 setupPreprocessors(ENTITY_TYPE_MAIL, QVector<Sink::Preprocessor*>() << new SpecialPurposeProcessor(resourceContext.resourceType, resourceContext.instanceId()) << new MailPropertyExtractor);
741 setupPreprocessors(ENTITY_TYPE_FOLDER, QVector<Sink::Preprocessor*>()); 741 setupPreprocessors(ENTITY_TYPE_FOLDER, QVector<Sink::Preprocessor*>());
742} 742}
743 743
diff --git a/examples/maildirresource/maildirresource.cpp b/examples/maildirresource/maildirresource.cpp
index a05afc6..6a03263 100644
--- a/examples/maildirresource/maildirresource.cpp
+++ b/examples/maildirresource/maildirresource.cpp
@@ -132,7 +132,10 @@ public:
132 auto mail = newEntity.cast<ApplicationDomain::Mail>(); 132 auto mail = newEntity.cast<ApplicationDomain::Mail>();
133 const auto mimeMessage = mail.getMimeMessagePath(); 133 const auto mimeMessage = mail.getMimeMessagePath();
134 if (!mimeMessage.isNull()) { 134 if (!mimeMessage.isNull()) {
135 mail.setMimeMessagePath(moveMessage(mimeMessage, mail.getFolder())); 135 const auto path = moveMessage(mimeMessage, mail.getFolder());
136 auto blob = ApplicationDomain::BLOB{path};
137 blob.isExternal = false;
138 mail.setProperty(ApplicationDomain::Mail::MimeMessage::name, QVariant::fromValue(blob));
136 } 139 }
137 } 140 }
138 141
@@ -149,7 +152,9 @@ public:
149 auto newPath = moveMessage(mimeMessage, newMail.getFolder()); 152 auto newPath = moveMessage(mimeMessage, newMail.getFolder());
150 if (newPath != oldMail.getMimeMessagePath()) { 153 if (newPath != oldMail.getMimeMessagePath()) {
151 const auto oldPath = getFilePathFromMimeMessagePath(oldMail.getMimeMessagePath()); 154 const auto oldPath = getFilePathFromMimeMessagePath(oldMail.getMimeMessagePath());
152 newMail.setMimeMessagePath(newPath); 155 auto blob = ApplicationDomain::BLOB{newPath};
156 blob.isExternal = false;
157 newMail.setProperty(ApplicationDomain::Mail::MimeMessage::name, QVariant::fromValue(blob));
153 //Remove the olde mime message if there is a new one 158 //Remove the olde mime message if there is a new one
154 QFile::remove(oldPath); 159 QFile::remove(oldPath);
155 } 160 }
@@ -323,7 +328,10 @@ public:
323 Sink::ApplicationDomain::Mail mail; 328 Sink::ApplicationDomain::Mail mail;
324 mail.setFolder(folderLocalId); 329 mail.setFolder(folderLocalId);
325 //We only store the directory path + key, so we facade can add the changing bits (flags) 330 //We only store the directory path + key, so we facade can add the changing bits (flags)
326 mail.setMimeMessagePath(KPIM::Maildir::getDirectoryFromFile(filePath) + maildirKey); 331 auto path = KPIM::Maildir::getDirectoryFromFile(filePath) + maildirKey;
332 auto blob = ApplicationDomain::BLOB{path};
333 blob.isExternal = false;
334 mail.setProperty(ApplicationDomain::Mail::MimeMessage::name, QVariant::fromValue(blob));
327 mail.setUnread(!flags.testFlag(KPIM::Maildir::Seen)); 335 mail.setUnread(!flags.testFlag(KPIM::Maildir::Seen));
328 mail.setImportant(flags.testFlag(KPIM::Maildir::Flagged)); 336 mail.setImportant(flags.testFlag(KPIM::Maildir::Flagged));
329 337
diff --git a/examples/mailtransportresource/mailtransportresource.cpp b/examples/mailtransportresource/mailtransportresource.cpp
index 08a8748..b7ee77a 100644
--- a/examples/mailtransportresource/mailtransportresource.cpp
+++ b/examples/mailtransportresource/mailtransportresource.cpp
@@ -182,7 +182,7 @@ MailtransportResource::MailtransportResource(const Sink::ResourceContext &resour
182 setupSynchronizer(synchronizer); 182 setupSynchronizer(synchronizer);
183 setupInspector(QSharedPointer<MailtransportInspector>::create(resourceContext)); 183 setupInspector(QSharedPointer<MailtransportInspector>::create(resourceContext));
184 184
185 setupPreprocessors(ENTITY_TYPE_MAIL, QVector<Sink::Preprocessor*>() << new MimeMessageMover << new MailPropertyExtractor); 185 setupPreprocessors(ENTITY_TYPE_MAIL, QVector<Sink::Preprocessor*>() << new MailPropertyExtractor);
186} 186}
187 187
188MailtransportResourceFactory::MailtransportResourceFactory(QObject *parent) 188MailtransportResourceFactory::MailtransportResourceFactory(QObject *parent)