summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristian Mollekopf <chrigi_1@fastmail.fm>2016-02-05 17:33:08 +0100
committerChristian Mollekopf <chrigi_1@fastmail.fm>2016-02-05 18:14:43 +0100
commit47bfba0d9152a1f7f689d7936b107b1a899a0b76 (patch)
treed3097b1da7bc87984bd7fdffbf803ed682e95fcc
parentb9a79ed514e7ab6bab0d6dedfcb9a78387d2b7c1 (diff)
downloadsink-47bfba0d9152a1f7f689d7936b107b1a899a0b76.tar.gz
sink-47bfba0d9152a1f7f689d7936b107b1a899a0b76.zip
Use property transformation for the mimeMessage
The filepath changes with every flag change. It is thus easier to only store a limited path that remains stable, and figure out the rest as the property is requested (we'll have to translate it anyways once we the file handoff protocol is implemented). The reason why we don't update the mimeMessage path on every modification is because we move the message during change replay, and not while storing the modification in the db. This would lead to the message-path on disk not correspond to what is in the db for some time.
-rw-r--r--examples/maildirresource/facade.cpp30
-rw-r--r--examples/maildirresource/facade.h1
-rw-r--r--examples/maildirresource/libmaildir/maildir.cpp20
-rw-r--r--examples/maildirresource/libmaildir/maildir.h13
-rw-r--r--examples/maildirresource/maildirresource.cpp6
-rw-r--r--tests/maildirresourcetest.cpp17
6 files changed, 83 insertions, 4 deletions
diff --git a/examples/maildirresource/facade.cpp b/examples/maildirresource/facade.cpp
index 7178ab9..a10a18b 100644
--- a/examples/maildirresource/facade.cpp
+++ b/examples/maildirresource/facade.cpp
@@ -19,17 +19,47 @@
19 19
20#include "facade.h" 20#include "facade.h"
21 21
22#include <QDir>
23#include <QFileInfo>
24
22#include "domainadaptor.h" 25#include "domainadaptor.h"
26#include "queryrunner.h"
23 27
24MaildirResourceMailFacade::MaildirResourceMailFacade(const QByteArray &instanceIdentifier) 28MaildirResourceMailFacade::MaildirResourceMailFacade(const QByteArray &instanceIdentifier)
25 : Sink::GenericFacade<Sink::ApplicationDomain::Mail>(instanceIdentifier, QSharedPointer<MaildirMailAdaptorFactory>::create()) 29 : Sink::GenericFacade<Sink::ApplicationDomain::Mail>(instanceIdentifier, QSharedPointer<MaildirMailAdaptorFactory>::create())
26{ 30{
31 mResultTransformation = [](Sink::ApplicationDomain::ApplicationDomainType &value) {
32 const auto property = value.getProperty("mimeMessage");
33 if (property.isValid()) {
34 //Transform the mime message property into the actual path on disk.
35 const auto mimeMessage = property.toString();
36 auto parts = mimeMessage.split('/');
37 auto key = parts.takeLast();
38 const auto folderPath = parts.join('/');
39 const auto path = folderPath + "/cur/";
40
41 Trace() << "Looking for mail in: " << path << key;
42 QDir dir(path);
43 const QFileInfoList list = dir.entryInfoList(QStringList() << (key+"*"), QDir::Files);
44 if (list.size() != 1) {
45 Warning() << "Failed to find message " << path << key << list.size();
46 value.setProperty("mimeMessage", QVariant());
47 } else {
48 value.setProperty("mimeMessage", list.at(0).filePath());
49 }
50 }
51 };
27} 52}
28 53
29MaildirResourceMailFacade::~MaildirResourceMailFacade() 54MaildirResourceMailFacade::~MaildirResourceMailFacade()
30{ 55{
31} 56}
32 57
58QPair<KAsync::Job<void>, Sink::ResultEmitter<Sink::ApplicationDomain::Mail::Ptr>::Ptr> MaildirResourceMailFacade::load(const Sink::Query &query)
59{
60 return Sink::GenericFacade<Sink::ApplicationDomain::Mail>::load(query);
61}
62
33 63
34MaildirResourceFolderFacade::MaildirResourceFolderFacade(const QByteArray &instanceIdentifier) 64MaildirResourceFolderFacade::MaildirResourceFolderFacade(const QByteArray &instanceIdentifier)
35 : Sink::GenericFacade<Sink::ApplicationDomain::Folder>(instanceIdentifier, QSharedPointer<MaildirFolderAdaptorFactory>::create()) 65 : Sink::GenericFacade<Sink::ApplicationDomain::Folder>(instanceIdentifier, QSharedPointer<MaildirFolderAdaptorFactory>::create())
diff --git a/examples/maildirresource/facade.h b/examples/maildirresource/facade.h
index a243b0d..38981d0 100644
--- a/examples/maildirresource/facade.h
+++ b/examples/maildirresource/facade.h
@@ -26,6 +26,7 @@ class MaildirResourceMailFacade : public Sink::GenericFacade<Sink::ApplicationDo
26public: 26public:
27 MaildirResourceMailFacade(const QByteArray &instanceIdentifier); 27 MaildirResourceMailFacade(const QByteArray &instanceIdentifier);
28 virtual ~MaildirResourceMailFacade(); 28 virtual ~MaildirResourceMailFacade();
29 QPair<KAsync::Job<void>, Sink::ResultEmitter<Sink::ApplicationDomain::Mail::Ptr>::Ptr> load(const Sink::Query &query) Q_DECL_OVERRIDE;
29}; 30};
30 31
31class MaildirResourceFolderFacade : public Sink::GenericFacade<Sink::ApplicationDomain::Folder> 32class MaildirResourceFolderFacade : public Sink::GenericFacade<Sink::ApplicationDomain::Folder>
diff --git a/examples/maildirresource/libmaildir/maildir.cpp b/examples/maildirresource/libmaildir/maildir.cpp
index 0057b26..59e7e5c 100644
--- a/examples/maildirresource/libmaildir/maildir.cpp
+++ b/examples/maildirresource/libmaildir/maildir.cpp
@@ -177,6 +177,13 @@ public:
177 return realKey; 177 return realKey;
178 } 178 }
179 179
180 static QString stripFlags(const QString& key)
181 {
182 const QRegExp rx = *(statusSeparatorRx());
183 const int index = key.indexOf(rx);
184 return key.mid(0, index);
185 }
186
180 static QString subDirNameForFolderName(const QString &folderName) 187 static QString subDirNameForFolderName(const QString &folderName)
181 { 188 {
182 return QString::fromLatin1(".%1.directory").arg(folderName); 189 return QString::fromLatin1(".%1.directory").arg(folderName);
@@ -559,6 +566,19 @@ QDateTime Maildir::lastModified(const QString& key) const
559 return info.lastModified(); 566 return info.lastModified();
560} 567}
561 568
569QString Maildir::getKeyFromFile(const QString& file)
570{
571 return Maildir::Private::stripFlags(file.split('/').last());
572}
573
574QString Maildir::getDirectoryFromFile( const QString& file )
575{
576 auto parts = file.split('/');
577 parts.removeLast(); //File
578 parts.removeLast(); //cur/new/tmp
579 return parts.join('/') + "/";
580}
581
562QByteArray Maildir::readEntryHeadersFromFile(const QString& file) 582QByteArray Maildir::readEntryHeadersFromFile(const QString& file)
563{ 583{
564 QByteArray result; 584 QByteArray result;
diff --git a/examples/maildirresource/libmaildir/maildir.h b/examples/maildirresource/libmaildir/maildir.h
index 5936515..6c68656 100644
--- a/examples/maildirresource/libmaildir/maildir.h
+++ b/examples/maildirresource/libmaildir/maildir.h
@@ -262,6 +262,19 @@ public:
262 querying the last error string. */ 262 querying the last error string. */
263 QString lastError() const; 263 QString lastError() const;
264 264
265 /**
266 * Returns the key from the file identified by the full path @param file.
267 */
268 static QString getKeyFromFile( const QString& file );
269
270 /**
271 * Returns the directory from a file.
272 *
273 * Strips key and new/cur/tmp.
274 * The returned path is ended with a trailing slash.
275 */
276 static QString getDirectoryFromFile( const QString& file );
277
265private: 278private:
266 void swap( const Maildir& ); 279 void swap( const Maildir& );
267 class Private; 280 class Private;
diff --git a/examples/maildirresource/maildirresource.cpp b/examples/maildirresource/maildirresource.cpp
index 87623ca..d5cc24b 100644
--- a/examples/maildirresource/maildirresource.cpp
+++ b/examples/maildirresource/maildirresource.cpp
@@ -175,6 +175,7 @@ void MaildirResource::synchronizeMails(Sink::Storage::Transaction &transaction,
175 msg->parse(); 175 msg->parse();
176 176
177 const auto flags = maildir.readEntryFlags(fileName); 177 const auto flags = maildir.readEntryFlags(fileName);
178 const auto maildirKey = maildir.getKeyFromFile(fileName);
178 179
179 Trace() << "Found a mail " << filePath << " : " << fileName << msg->subject(true)->asUnicodeString(); 180 Trace() << "Found a mail " << filePath << " : " << fileName << msg->subject(true)->asUnicodeString();
180 181
@@ -184,7 +185,8 @@ void MaildirResource::synchronizeMails(Sink::Storage::Transaction &transaction,
184 mail.setProperty("senderName", msg->from(true)->asUnicodeString()); 185 mail.setProperty("senderName", msg->from(true)->asUnicodeString());
185 mail.setProperty("date", msg->date(true)->dateTime()); 186 mail.setProperty("date", msg->date(true)->dateTime());
186 mail.setProperty("folder", folderLocalId); 187 mail.setProperty("folder", folderLocalId);
187 mail.setProperty("mimeMessage", filePath); 188 //We only store the directory path + key, so we facade can add the changing bits (flags)
189 mail.setProperty("mimeMessage", KPIM::Maildir::getDirectoryFromFile(filePath) + maildirKey);
188 mail.setProperty("unread", !flags.testFlag(KPIM::Maildir::Seen)); 190 mail.setProperty("unread", !flags.testFlag(KPIM::Maildir::Seen));
189 mail.setProperty("important", flags.testFlag(KPIM::Maildir::Flagged)); 191 mail.setProperty("important", flags.testFlag(KPIM::Maildir::Flagged));
190 192
@@ -274,7 +276,7 @@ KAsync::Job<void> MaildirResource::replay(Sink::Storage &synchronizationStore, c
274 if (!maildir.isValid(true)) { 276 if (!maildir.isValid(true)) {
275 return KAsync::error<void>(1, "Invalid folder " + parentFolderPath); 277 return KAsync::error<void>(1, "Invalid folder " + parentFolderPath);
276 } 278 }
277 //FIXME assemble the MIME message 279 //FIXME move the mime message from the mimeMessage property to the proper place.
278 Trace() << "Creating a new mail."; 280 Trace() << "Creating a new mail.";
279 const auto remoteId = maildir.addEntry("foobar"); 281 const auto remoteId = maildir.addEntry("foobar");
280 if (remoteId.isEmpty()) { 282 if (remoteId.isEmpty()) {
diff --git a/tests/maildirresourcetest.cpp b/tests/maildirresourcetest.cpp
index 7cdfc36..e502d10 100644
--- a/tests/maildirresourcetest.cpp
+++ b/tests/maildirresourcetest.cpp
@@ -158,6 +158,9 @@ private Q_SLOTS:
158 QVERIFY(!mail->getProperty("subject").toString().isEmpty()); 158 QVERIFY(!mail->getProperty("subject").toString().isEmpty());
159 QVERIFY(!mail->getProperty("mimeMessage").toString().isEmpty()); 159 QVERIFY(!mail->getProperty("mimeMessage").toString().isEmpty());
160 QVERIFY(mail->getProperty("date").toDateTime().isValid()); 160 QVERIFY(mail->getProperty("date").toDateTime().isValid());
161
162 QFileInfo info(mail->getProperty("mimeMessage").toString());
163 QVERIFY(info.exists());
161 } 164 }
162 165
163 166
@@ -368,10 +371,11 @@ private Q_SLOTS:
368 result.waitForFinished(); 371 result.waitForFinished();
369 QVERIFY(!result.errorCode()); 372 QVERIFY(!result.errorCode());
370 373
374 //Verify that we can still query for all relevant information
371 auto result2 = Store::fetchAll<Mail>( 375 auto result2 = Store::fetchAll<Mail>(
372 Query::ResourceFilter("org.kde.maildir.instance1") + Query::PropertyFilter("folder", f) + Query::RequestedProperties(QByteArrayList() << "folder" << "subject") 376 Query::ResourceFilter("org.kde.maildir.instance1") + Query::PropertyFilter("folder", f) + Query::RequestedProperties(QByteArrayList() << "folder" << "subject" << "mimeMessage" << "unread")
373 ) 377 )
374 .then<void, KAsync::Job<void>, QList<Mail::Ptr> >([query](const QList<Mail::Ptr> &mails) { 378 .then<void, KAsync::Job<void>, QList<Mail::Ptr> >([](const QList<Mail::Ptr> &mails) {
375 //Can't use QCOMPARE because it tries to return FIXME Implement ASYNCCOMPARE 379 //Can't use QCOMPARE because it tries to return FIXME Implement ASYNCCOMPARE
376 if (mails.size() != 1) { 380 if (mails.size() != 1) {
377 qWarning() << "Wrong number of mails"; 381 qWarning() << "Wrong number of mails";
@@ -382,6 +386,15 @@ private Q_SLOTS:
382 qWarning() << "Wrong subject"; 386 qWarning() << "Wrong subject";
383 return KAsync::error<void>(1, "Wrong subject."); 387 return KAsync::error<void>(1, "Wrong subject.");
384 } 388 }
389 if (mail->getProperty("unread").toBool() != true) {
390 qWarning() << "Not unread";
391 return KAsync::error<void>(1, "Not unread.");
392 }
393 QFileInfo info(mail->getProperty("mimeMessage").toString());
394 if (!info.exists()) {
395 qWarning() << "Wrong subject";
396 return KAsync::error<void>(1, "Can't find mime message.");
397 }
385 return KAsync::null<void>(); 398 return KAsync::null<void>();
386 }) 399 })
387 .exec(); 400 .exec();