summaryrefslogtreecommitdiffstats
path: root/examples
diff options
context:
space:
mode:
Diffstat (limited to 'examples')
-rw-r--r--examples/client/CMakeLists.txt2
-rw-r--r--examples/client/main.cpp3
-rw-r--r--examples/dummyresource/CMakeLists.txt2
-rw-r--r--examples/dummyresource/resourcefactory.cpp10
-rw-r--r--examples/dummyresource/resourcefactory.h1
-rw-r--r--examples/maildirresource/CMakeLists.txt2
-rw-r--r--examples/maildirresource/facade.cpp30
-rw-r--r--examples/maildirresource/facade.h1
-rw-r--r--examples/maildirresource/libmaildir/maildir.cpp193
-rw-r--r--examples/maildirresource/libmaildir/maildir.h30
-rw-r--r--examples/maildirresource/maildirresource.cpp82
-rw-r--r--examples/maildirresource/maildirresource.h5
12 files changed, 249 insertions, 112 deletions
diff --git a/examples/client/CMakeLists.txt b/examples/client/CMakeLists.txt
index 85840c4..ef00368 100644
--- a/examples/client/CMakeLists.txt
+++ b/examples/client/CMakeLists.txt
@@ -3,6 +3,6 @@ project(sink_client)
3include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR}) 3include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR})
4 4
5add_executable(${PROJECT_NAME} main.cpp console.cpp) 5add_executable(${PROJECT_NAME} main.cpp console.cpp)
6target_link_libraries(${PROJECT_NAME} sinkcommon) 6target_link_libraries(${PROJECT_NAME} sink)
7qt5_use_modules(${PROJECT_NAME} Widgets Network) 7qt5_use_modules(${PROJECT_NAME} Widgets Network)
8install(TARGETS ${PROJECT_NAME} ${KDE_INSTALL_TARGETS_DEFAULT_ARGS}) 8install(TARGETS ${PROJECT_NAME} ${KDE_INSTALL_TARGETS_DEFAULT_ARGS})
diff --git a/examples/client/main.cpp b/examples/client/main.cpp
index f437c19..07e780e 100644
--- a/examples/client/main.cpp
+++ b/examples/client/main.cpp
@@ -22,7 +22,7 @@
22#include <QCommandLineOption> 22#include <QCommandLineOption>
23#include <QTime> 23#include <QTime>
24 24
25#include "common/clientapi.h" 25#include "common/store.h"
26#include "common/log.h" 26#include "common/log.h"
27 27
28#include <QWidget> 28#include <QWidget>
@@ -38,6 +38,7 @@
38 */ 38 */
39class StoreBase { 39class StoreBase {
40public: 40public:
41 virtual ~StoreBase(){};
41 virtual Sink::ApplicationDomain::ApplicationDomainType::Ptr getObject() = 0; 42 virtual Sink::ApplicationDomain::ApplicationDomainType::Ptr getObject() = 0;
42 virtual Sink::ApplicationDomain::ApplicationDomainType::Ptr getObject(const QByteArray &resourceInstanceIdentifier, const QByteArray &identifier = QByteArray()) = 0; 43 virtual Sink::ApplicationDomain::ApplicationDomainType::Ptr getObject(const QByteArray &resourceInstanceIdentifier, const QByteArray &identifier = QByteArray()) = 0;
43 virtual KAsync::Job<void> create(const Sink::ApplicationDomain::ApplicationDomainType &type) = 0; 44 virtual KAsync::Job<void> create(const Sink::ApplicationDomain::ApplicationDomainType &type) = 0;
diff --git a/examples/dummyresource/CMakeLists.txt b/examples/dummyresource/CMakeLists.txt
index 6ffac9a..6400f0c 100644
--- a/examples/dummyresource/CMakeLists.txt
+++ b/examples/dummyresource/CMakeLists.txt
@@ -7,6 +7,6 @@ include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR})
7add_library(${PROJECT_NAME} SHARED facade.cpp resourcefactory.cpp domainadaptor.cpp dummystore.cpp) 7add_library(${PROJECT_NAME} SHARED facade.cpp resourcefactory.cpp domainadaptor.cpp dummystore.cpp)
8generate_flatbuffers(${PROJECT_NAME} dummycalendar) 8generate_flatbuffers(${PROJECT_NAME} dummycalendar)
9qt5_use_modules(${PROJECT_NAME} Core Network) 9qt5_use_modules(${PROJECT_NAME} Core Network)
10target_link_libraries(${PROJECT_NAME} sinkcommon) 10target_link_libraries(${PROJECT_NAME} sink)
11 11
12install(TARGETS ${PROJECT_NAME} LIBRARY DESTINATION ${SINK_RESOURCE_PLUGINS_PATH}) 12install(TARGETS ${PROJECT_NAME} LIBRARY DESTINATION ${SINK_RESOURCE_PLUGINS_PATH})
diff --git a/examples/dummyresource/resourcefactory.cpp b/examples/dummyresource/resourcefactory.cpp
index 31633d7..48858da 100644
--- a/examples/dummyresource/resourcefactory.cpp
+++ b/examples/dummyresource/resourcefactory.cpp
@@ -95,12 +95,17 @@ Sink::ApplicationDomain::Folder::Ptr DummyResource::createFolder(const QByteArra
95 95
96void DummyResource::synchronize(const QByteArray &bufferType, const QMap<QString, QMap<QString, QVariant> > &data, Sink::Storage::Transaction &transaction, Sink::Storage::Transaction &synchronizationTransaction, DomainTypeAdaptorFactoryInterface &adaptorFactory, std::function<Sink::ApplicationDomain::ApplicationDomainType::Ptr(const QByteArray &ridBuffer, const QMap<QString, QVariant> &data, Sink::Storage::Transaction &)> createEntity) 96void DummyResource::synchronize(const QByteArray &bufferType, const QMap<QString, QMap<QString, QVariant> > &data, Sink::Storage::Transaction &transaction, Sink::Storage::Transaction &synchronizationTransaction, DomainTypeAdaptorFactoryInterface &adaptorFactory, std::function<Sink::ApplicationDomain::ApplicationDomainType::Ptr(const QByteArray &ridBuffer, const QMap<QString, QVariant> &data, Sink::Storage::Transaction &)> createEntity)
97{ 97{
98 auto time = QSharedPointer<QTime>::create();
99 time->start();
98 //TODO find items to remove 100 //TODO find items to remove
101 int count = 0;
99 for (auto it = data.constBegin(); it != data.constEnd(); it++) { 102 for (auto it = data.constBegin(); it != data.constEnd(); it++) {
103 count++;
100 const auto remoteId = it.key().toUtf8(); 104 const auto remoteId = it.key().toUtf8();
101 auto entity = createEntity(remoteId, it.value(), synchronizationTransaction); 105 auto entity = createEntity(remoteId, it.value(), synchronizationTransaction);
102 createOrModify(transaction, synchronizationTransaction, adaptorFactory, bufferType, remoteId, *entity); 106 createOrModify(transaction, synchronizationTransaction, adaptorFactory, bufferType, remoteId, *entity);
103 } 107 }
108 Trace() << "Sync of " << count << " entities of type " << bufferType << " done." << Sink::Log::TraceTime(time->elapsed());
104} 109}
105 110
106KAsync::Job<void> DummyResource::synchronizeWithSource(Sink::Storage &mainStore, Sink::Storage &synchronizationStore) 111KAsync::Job<void> DummyResource::synchronizeWithSource(Sink::Storage &mainStore, Sink::Storage &synchronizationStore)
@@ -128,6 +133,11 @@ KAsync::Job<void> DummyResource::replay(Sink::Storage &synchronizationStore, con
128 return KAsync::null<void>(); 133 return KAsync::null<void>();
129} 134}
130 135
136void DummyResource::removeDataFromDisk()
137{
138 removeFromDisk(mResourceInstanceIdentifier);
139}
140
131void DummyResource::removeFromDisk(const QByteArray &instanceIdentifier) 141void DummyResource::removeFromDisk(const QByteArray &instanceIdentifier)
132{ 142{
133 GenericResource::removeFromDisk(instanceIdentifier); 143 GenericResource::removeFromDisk(instanceIdentifier);
diff --git a/examples/dummyresource/resourcefactory.h b/examples/dummyresource/resourcefactory.h
index 240bb9f..865f6e5 100644
--- a/examples/dummyresource/resourcefactory.h
+++ b/examples/dummyresource/resourcefactory.h
@@ -39,6 +39,7 @@ public:
39 DummyResource(const QByteArray &instanceIdentifier, const QSharedPointer<Sink::Pipeline> &pipeline = QSharedPointer<Sink::Pipeline>()); 39 DummyResource(const QByteArray &instanceIdentifier, const QSharedPointer<Sink::Pipeline> &pipeline = QSharedPointer<Sink::Pipeline>());
40 KAsync::Job<void> synchronizeWithSource(Sink::Storage &mainStore, Sink::Storage &synchronizationStore) Q_DECL_OVERRIDE; 40 KAsync::Job<void> synchronizeWithSource(Sink::Storage &mainStore, Sink::Storage &synchronizationStore) Q_DECL_OVERRIDE;
41 using GenericResource::synchronizeWithSource; 41 using GenericResource::synchronizeWithSource;
42 void removeDataFromDisk() Q_DECL_OVERRIDE;
42 static void removeFromDisk(const QByteArray &instanceIdentifier); 43 static void removeFromDisk(const QByteArray &instanceIdentifier);
43 KAsync::Job<void> inspect(int inspectionType, const QByteArray &inspectionId, const QByteArray &domainType, const QByteArray &entityId, const QByteArray &property, const QVariant &expectedValue) Q_DECL_OVERRIDE; 44 KAsync::Job<void> inspect(int inspectionType, const QByteArray &inspectionId, const QByteArray &domainType, const QByteArray &entityId, const QByteArray &property, const QVariant &expectedValue) Q_DECL_OVERRIDE;
44private: 45private:
diff --git a/examples/maildirresource/CMakeLists.txt b/examples/maildirresource/CMakeLists.txt
index baacd44..efaa266 100644
--- a/examples/maildirresource/CMakeLists.txt
+++ b/examples/maildirresource/CMakeLists.txt
@@ -8,7 +8,7 @@ find_package(KF5 COMPONENTS REQUIRED Mime)
8add_library(${PROJECT_NAME} SHARED facade.cpp maildirresource.cpp domainadaptor.cpp) 8add_library(${PROJECT_NAME} SHARED facade.cpp maildirresource.cpp domainadaptor.cpp)
9# generate_flatbuffers(${PROJECT_NAME} dummycalendar) 9# generate_flatbuffers(${PROJECT_NAME} dummycalendar)
10qt5_use_modules(${PROJECT_NAME} Core Network) 10qt5_use_modules(${PROJECT_NAME} Core Network)
11target_link_libraries(${PROJECT_NAME} sinkcommon maildir KF5::Mime) 11target_link_libraries(${PROJECT_NAME} sink maildir KF5::Mime)
12 12
13install(TARGETS ${PROJECT_NAME} LIBRARY DESTINATION ${SINK_RESOURCE_PLUGINS_PATH}) 13install(TARGETS ${PROJECT_NAME} LIBRARY DESTINATION ${SINK_RESOURCE_PLUGINS_PATH})
14 14
diff --git a/examples/maildirresource/facade.cpp b/examples/maildirresource/facade.cpp
index 7178ab9..a7a0348 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 if (value.hasProperty("mimeMessage")) {
33 const auto property = value.getProperty("mimeMessage");
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 3d4630f..59e7e5c 100644
--- a/examples/maildirresource/libmaildir/maildir.cpp
+++ b/examples/maildirresource/libmaildir/maildir.cpp
@@ -142,7 +142,6 @@ public:
142 { 142 {
143 // KeyCache* keyCache = KeyCache::self(); 143 // KeyCache* keyCache = KeyCache::self();
144 // if (keyCache->isNewKey(path, key)) { 144 // if (keyCache->isNewKey(path, key)) {
145 qWarning() << path + QString::fromLatin1("/new/") + key;
146 if (QFile::exists(path + QString::fromLatin1("/new/") + key)) { 145 if (QFile::exists(path + QString::fromLatin1("/new/") + key)) {
147#ifdef DEBUG_KEYCACHE_CONSITENCY 146#ifdef DEBUG_KEYCACHE_CONSITENCY
148 if (!QFile::exists(path + QString::fromLatin1("/new/") + key)) { 147 if (!QFile::exists(path + QString::fromLatin1("/new/") + key)) {
@@ -178,6 +177,13 @@ public:
178 return realKey; 177 return realKey;
179 } 178 }
180 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
181 static QString subDirNameForFolderName(const QString &folderName) 187 static QString subDirNameForFolderName(const QString &folderName)
182 { 188 {
183 return QString::fromLatin1(".%1.directory").arg(folderName); 189 return QString::fromLatin1(".%1.directory").arg(folderName);
@@ -560,7 +566,20 @@ QDateTime Maildir::lastModified(const QString& key) const
560 return info.lastModified(); 566 return info.lastModified();
561} 567}
562 568
563QByteArray Maildir::readEntryHeadersFromFile(const QString& file) const 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
582QByteArray Maildir::readEntryHeadersFromFile(const QString& file)
564{ 583{
565 QByteArray result; 584 QByteArray result;
566 585
@@ -643,9 +662,14 @@ QString Maildir::addEntry(const QByteArray& data)
643 662
644 QFile f(key); 663 QFile f(key);
645 bool result = f.open(QIODevice::WriteOnly); 664 bool result = f.open(QIODevice::WriteOnly);
665 if (!result) {
666 qWarning() << f.errorString();
667 qWarning() << "Cannot write to mail file: " << key;
668 }
646 result = result & (f.write(data) != -1); 669 result = result & (f.write(data) != -1);
647 f.close(); 670 f.close();
648 if (!result) { 671 if (!result) {
672 qWarning() << "Cannot write to mail file: " << key;
649 // d->lastError = i18n("Cannot write to mail file %1." , key); 673 // d->lastError = i18n("Cannot write to mail file %1." , key);
650 return QString(); 674 return QString();
651 } 675 }
@@ -688,88 +712,89 @@ bool Maildir::removeEntry(const QString& key)
688 // return QFile::remove(realKey); 712 // return QFile::remove(realKey);
689} 713}
690 714
691// QString Maildir::changeEntryFlags(const QString& key, const Sink::Item::Flags& flags) 715QString Maildir::changeEntryFlags(const QString& key, const Maildir::Flags& flags)
692// { 716{
693// QString realKey(d->findRealKey(key)); 717 QString realKey(d->findRealKey(key));
694// if (realKey.isEmpty()) { 718 if (realKey.isEmpty()) {
695// qWarning() << "Maildir::changeEntryFlags unable to find: " << key; 719 qWarning() << "Maildir::changeEntryFlags unable to find: " << key;
696// d->lastError = i18n("Cannot locate mail file %1." , key); 720 // d->lastError = i18n("Cannot locate mail file %1." , key);
697// return QString(); 721 return QString();
698// } 722 }
699// 723
700// const QRegExp rx = *(statusSeparatorRx()); 724 const QRegExp rx = *(statusSeparatorRx());
701// QString finalKey = key.left(key.indexOf(rx)); 725 QString finalKey = key.left(key.indexOf(rx));
702// 726
703// QStringList mailDirFlags; 727 QStringList mailDirFlags;
704// Q_FOREACH (const Sink::Item::Flag &flag, flags) { 728 if (flags & Forwarded)
705// if (flag == Sink::MessageFlags::Forwarded) 729 mailDirFlags << QLatin1String("P");
706// mailDirFlags << QLatin1String("P"); 730 if (flags & Replied)
707// if (flag == Sink::MessageFlags::Replied) 731 mailDirFlags << QLatin1String("R");
708// mailDirFlags << QLatin1String("R"); 732 if (flags & Seen)
709// if (flag == Sink::MessageFlags::Seen) 733 mailDirFlags << QLatin1String("S");
710// mailDirFlags << QLatin1String("S"); 734 if (flags & Deleted)
711// if (flag == Sink::MessageFlags::Deleted) 735 mailDirFlags << QLatin1String("T");
712// mailDirFlags << QLatin1String("T"); 736 if (flags & Flagged)
713// if (flag == Sink::MessageFlags::Flagged) 737 mailDirFlags << QLatin1String("F");
714// mailDirFlags << QLatin1String("F"); 738
715// } 739 mailDirFlags.sort();
716// mailDirFlags.sort(); 740 if (!mailDirFlags.isEmpty()) {
717// if (!mailDirFlags.isEmpty()) { 741#ifdef Q_OS_WIN
718// #ifdef Q_OS_WIN 742 finalKey.append(QLatin1String("!2,") + mailDirFlags.join(QString()));
719// finalKey.append(QLatin1String("!2,") + mailDirFlags.join(QString())); 743#else
720// #else 744 finalKey.append(QLatin1String(":2,") + mailDirFlags.join(QString()));
721// finalKey.append(QLatin1String(":2,") + mailDirFlags.join(QString())); 745#endif
722// #endif 746 }
723// } 747
724// 748 QString newUniqueKey = finalKey; //key without path
725// QString newUniqueKey = finalKey; //key without path 749 finalKey.prepend(d->path + QString::fromLatin1("/cur/"));
726// finalKey.prepend(d->path + QString::fromLatin1("/cur/")); 750
727// 751 if (realKey == finalKey) {
728// if (realKey == finalKey) { 752 // Somehow it already is named this way (e.g. migration bug -> wrong status in sink)
729// // Somehow it already is named this way (e.g. migration bug -> wrong status in sink) 753 qWarning() << "File already named that way: " << newUniqueKey << finalKey;
730// return newUniqueKey; 754 return newUniqueKey;
731// } 755 }
732// 756
733// QFile f(realKey); 757 QFile f(realKey);
734// if (QFile::exists(finalKey)) { 758 if (QFile::exists(finalKey)) {
735// QFile destFile(finalKey); 759 QFile destFile(finalKey);
736// QByteArray destContent; 760 QByteArray destContent;
737// if (destFile.open(QIODevice::ReadOnly)) { 761 if (destFile.open(QIODevice::ReadOnly)) {
738// destContent = destFile.readAll(); 762 destContent = destFile.readAll();
739// destFile.close(); 763 destFile.close();
740// } 764 }
741// QByteArray sourceContent; 765 QByteArray sourceContent;
742// if (f.open(QIODevice::ReadOnly)) { 766 if (f.open(QIODevice::ReadOnly)) {
743// sourceContent = f.readAll(); 767 sourceContent = f.readAll();
744// f.close(); 768 f.close();
745// } 769 }
746// 770
747// if (destContent != sourceContent) { 771 if (destContent != sourceContent) {
748// QString newFinalKey = QLatin1String("1-") + newUniqueKey; 772 QString newFinalKey = QLatin1String("1-") + newUniqueKey;
749// int i = 1; 773 int i = 1;
750// while (QFile::exists(d->path + QString::fromLatin1("/cur/") + newFinalKey)) { 774 while (QFile::exists(d->path + QString::fromLatin1("/cur/") + newFinalKey)) {
751// i++; 775 i++;
752// newFinalKey = QString::number(i) + QLatin1Char('-') + newUniqueKey; 776 newFinalKey = QString::number(i) + QLatin1Char('-') + newUniqueKey;
753// } 777 }
754// finalKey = d->path + QString::fromLatin1("/cur/") + newFinalKey; 778 finalKey = d->path + QString::fromLatin1("/cur/") + newFinalKey;
755// } else { 779 } else {
756// QFile::remove(finalKey); //they are the same 780 QFile::remove(finalKey); //they are the same
757// } 781 }
758// } 782 }
759// 783
760// if (!f.rename(finalKey)) { 784 if (!f.rename(finalKey)) {
761// qWarning() << "Maildir: Failed to rename entry: " << f.fileName() << " to " << finalKey << "! Error: " << f.errorString(); 785 qWarning() << "Maildir: Failed to rename entry: " << f.fileName() << " to " << finalKey << "! Error: " << f.errorString();
762// d->lastError = i18n("Failed to update the file name %1 to %2 on the disk. The error was: %3." , f.fileName(), finalKey, f.errorString()); 786 // d->lastError = i18n("Failed to update the file name %1 to %2 on the disk. The error was: %3." , f.fileName(), finalKey, f.errorString());
763// return QString(); 787 return QString();
764// } 788 }
765// 789 qWarning() << "Renamed file: " << f.fileName() << finalKey;
766// KeyCache *keyCache = KeyCache::self(); 790
767// keyCache->removeKey(d->path, key); 791 // KeyCache *keyCache = KeyCache::self();
768// keyCache->addCurKey(d->path, newUniqueKey); 792 // keyCache->removeKey(d->path, key);
769// 793 // keyCache->addCurKey(d->path, newUniqueKey);
770// return newUniqueKey; 794
771// } 795 return newUniqueKey;
772// 796}
797
773Maildir::Flags Maildir::readEntryFlags(const QString& key) 798Maildir::Flags Maildir::readEntryFlags(const QString& key)
774{ 799{
775 Flags flags; 800 Flags flags;
diff --git a/examples/maildirresource/libmaildir/maildir.h b/examples/maildirresource/libmaildir/maildir.h
index a89a832..6c68656 100644
--- a/examples/maildirresource/libmaildir/maildir.h
+++ b/examples/maildirresource/libmaildir/maildir.h
@@ -167,13 +167,14 @@ public:
167 */ 167 */
168 QByteArray readEntry( const QString& key ) const; 168 QByteArray readEntry( const QString& key ) const;
169 169
170 enum MailFlags { 170 enum Flag {
171 Forwarded, 171 Forwarded = 0x1,
172 Replied, 172 Replied = 0x2,
173 Seen, 173 Seen = 0x4,
174 Flagged 174 Flagged = 0x8,
175 Deleted = 0x10
175 }; 176 };
176 Q_DECLARE_FLAGS(Flags, MailFlags); 177 Q_DECLARE_FLAGS(Flags, Flag);
177 178
178 /** 179 /**
179 * Return the flags encoded in the maildir file name for an entry 180 * Return the flags encoded in the maildir file name for an entry
@@ -184,7 +185,7 @@ public:
184 * Return the contents of the headers section of the file the maildir with the given @p file, that 185 * Return the contents of the headers section of the file the maildir with the given @p file, that
185 * is a full path to the file. You can get it by using findRealKey(key) . 186 * is a full path to the file. You can get it by using findRealKey(key) .
186 */ 187 */
187 QByteArray readEntryHeadersFromFile( const QString& file ) const; 188 static QByteArray readEntryHeadersFromFile( const QString& file );
188 189
189 /** 190 /**
190 * Return the contents of the headers section of the file the maildir with the given @p key. 191 * Return the contents of the headers section of the file the maildir with the given @p key.
@@ -211,7 +212,7 @@ public:
211 * Change the flags for an entry specified by @p key. Returns the new key of the entry (the key might change because 212 * Change the flags for an entry specified by @p key. Returns the new key of the entry (the key might change because
212 * flags are stored in the unique filename). 213 * flags are stored in the unique filename).
213 */ 214 */
214 // QString changeEntryFlags( const QString& key, const Sink::Item::Flags& flags ); 215 QString changeEntryFlags( const QString& key, const Flags& flags );
215 216
216 /** 217 /**
217 * Moves this maildir into @p destination. 218 * Moves this maildir into @p destination.
@@ -261,6 +262,19 @@ public:
261 querying the last error string. */ 262 querying the last error string. */
262 QString lastError() const; 263 QString lastError() const;
263 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
264private: 278private:
265 void swap( const Maildir& ); 279 void swap( const Maildir& );
266 class Private; 280 class Private;
diff --git a/examples/maildirresource/maildirresource.cpp b/examples/maildirresource/maildirresource.cpp
index 33883a7..0ddd8f8 100644
--- a/examples/maildirresource/maildirresource.cpp
+++ b/examples/maildirresource/maildirresource.cpp
@@ -46,6 +46,9 @@
46#define ENTITY_TYPE_MAIL "mail" 46#define ENTITY_TYPE_MAIL "mail"
47#define ENTITY_TYPE_FOLDER "folder" 47#define ENTITY_TYPE_FOLDER "folder"
48 48
49#undef DEBUG_AREA
50#define DEBUG_AREA "resource.maildir"
51
49MaildirResource::MaildirResource(const QByteArray &instanceIdentifier, const QSharedPointer<Sink::Pipeline> &pipeline) 52MaildirResource::MaildirResource(const QByteArray &instanceIdentifier, const QSharedPointer<Sink::Pipeline> &pipeline)
50 : Sink::GenericResource(instanceIdentifier, pipeline), 53 : Sink::GenericResource(instanceIdentifier, pipeline),
51 mMailAdaptorFactory(QSharedPointer<MaildirMailAdaptorFactory>::create()), 54 mMailAdaptorFactory(QSharedPointer<MaildirMailAdaptorFactory>::create()),
@@ -103,7 +106,7 @@ void MaildirResource::synchronizeFolders(Sink::Storage::Transaction &transaction
103 //we should rather iterate over an index that contains every uid exactly once. The remoteId index would be such an index, 106 //we should rather iterate over an index that contains every uid exactly once. The remoteId index would be such an index,
104 //but we currently fail to iterate over all entries in an index it seems. 107 //but we currently fail to iterate over all entries in an index it seems.
105 // auto remoteIds = synchronizationTransaction.openDatabase("rid.mapping." + bufferType, std::function<void(const Sink::Storage::Error &)>(), true); 108 // auto remoteIds = synchronizationTransaction.openDatabase("rid.mapping." + bufferType, std::function<void(const Sink::Storage::Error &)>(), true);
106 auto mainDatabase = transaction.openDatabase(bufferType + ".main"); 109 auto mainDatabase = Sink::Storage::mainDatabase(transaction, bufferType);
107 mainDatabase.scan("", [&](const QByteArray &key, const QByteArray &) { 110 mainDatabase.scan("", [&](const QByteArray &key, const QByteArray &) {
108 callback(key); 111 callback(key);
109 return true; 112 return true;
@@ -132,6 +135,8 @@ void MaildirResource::synchronizeFolders(Sink::Storage::Transaction &transaction
132void MaildirResource::synchronizeMails(Sink::Storage::Transaction &transaction, Sink::Storage::Transaction &synchronizationTransaction, const QString &path) 135void MaildirResource::synchronizeMails(Sink::Storage::Transaction &transaction, Sink::Storage::Transaction &synchronizationTransaction, const QString &path)
133{ 136{
134 Trace() << "Synchronizing mails" << path; 137 Trace() << "Synchronizing mails" << path;
138 auto time = QSharedPointer<QTime>::create();
139 time->start();
135 const QByteArray bufferType = ENTITY_TYPE_MAIL; 140 const QByteArray bufferType = ENTITY_TYPE_MAIL;
136 141
137 KPIM::Maildir maildir(path, true); 142 KPIM::Maildir maildir(path, true);
@@ -162,7 +167,9 @@ void MaildirResource::synchronizeMails(Sink::Storage::Transaction &transaction,
162 } 167 }
163 ); 168 );
164 169
170 int count = 0;
165 while (entryIterator->hasNext()) { 171 while (entryIterator->hasNext()) {
172 count++;
166 const QString filePath = QDir::fromNativeSeparators(entryIterator->next()); 173 const QString filePath = QDir::fromNativeSeparators(entryIterator->next());
167 const QString fileName = entryIterator->fileName(); 174 const QString fileName = entryIterator->fileName();
168 const auto remoteId = filePath.toUtf8(); 175 const auto remoteId = filePath.toUtf8();
@@ -172,6 +179,7 @@ void MaildirResource::synchronizeMails(Sink::Storage::Transaction &transaction,
172 msg->parse(); 179 msg->parse();
173 180
174 const auto flags = maildir.readEntryFlags(fileName); 181 const auto flags = maildir.readEntryFlags(fileName);
182 const auto maildirKey = maildir.getKeyFromFile(fileName);
175 183
176 Trace() << "Found a mail " << filePath << " : " << fileName << msg->subject(true)->asUnicodeString(); 184 Trace() << "Found a mail " << filePath << " : " << fileName << msg->subject(true)->asUnicodeString();
177 185
@@ -181,12 +189,16 @@ void MaildirResource::synchronizeMails(Sink::Storage::Transaction &transaction,
181 mail.setProperty("senderName", msg->from(true)->asUnicodeString()); 189 mail.setProperty("senderName", msg->from(true)->asUnicodeString());
182 mail.setProperty("date", msg->date(true)->dateTime()); 190 mail.setProperty("date", msg->date(true)->dateTime());
183 mail.setProperty("folder", folderLocalId); 191 mail.setProperty("folder", folderLocalId);
184 mail.setProperty("mimeMessage", filePath); 192 //We only store the directory path + key, so we facade can add the changing bits (flags)
193 mail.setProperty("mimeMessage", KPIM::Maildir::getDirectoryFromFile(filePath) + maildirKey);
185 mail.setProperty("unread", !flags.testFlag(KPIM::Maildir::Seen)); 194 mail.setProperty("unread", !flags.testFlag(KPIM::Maildir::Seen));
186 mail.setProperty("important", flags.testFlag(KPIM::Maildir::Flagged)); 195 mail.setProperty("important", flags.testFlag(KPIM::Maildir::Flagged));
187 196
188 createOrModify(transaction, synchronizationTransaction, *mMailAdaptorFactory, bufferType, remoteId, mail); 197 createOrModify(transaction, synchronizationTransaction, *mMailAdaptorFactory, bufferType, remoteId, mail);
189 } 198 }
199 const auto elapsed = time->elapsed();
200 Trace() << "Synchronized " << count << " mails in " << listingPath << Sink::Log::TraceTime(elapsed) << " " << elapsed/qMax(count, 1) << " [ms/mail]";
201
190} 202}
191 203
192KAsync::Job<void> MaildirResource::synchronizeWithSource(Sink::Storage &mainStore, Sink::Storage &synchronizationStore) 204KAsync::Job<void> MaildirResource::synchronizeWithSource(Sink::Storage &mainStore, Sink::Storage &synchronizationStore)
@@ -216,7 +228,7 @@ KAsync::Job<void> MaildirResource::replay(Sink::Storage &synchronizationStore, c
216 228
217 Trace() << "Replaying " << key << type; 229 Trace() << "Replaying " << key << type;
218 if (type == ENTITY_TYPE_FOLDER) { 230 if (type == ENTITY_TYPE_FOLDER) {
219 Sink::EntityBuffer buffer(value.data(), value.size()); 231 Sink::EntityBuffer buffer(value);
220 const Sink::Entity &entity = buffer.entity(); 232 const Sink::Entity &entity = buffer.entity();
221 const auto metadataBuffer = Sink::EntityBuffer::readBuffer<Sink::Metadata>(entity.metadata()); 233 const auto metadataBuffer = Sink::EntityBuffer::readBuffer<Sink::Metadata>(entity.metadata());
222 if (metadataBuffer && !metadataBuffer->replayToSource()) { 234 if (metadataBuffer && !metadataBuffer->replayToSource()) {
@@ -248,7 +260,7 @@ KAsync::Job<void> MaildirResource::replay(Sink::Storage &synchronizationStore, c
248 Warning() << "Unkown operation" << operation; 260 Warning() << "Unkown operation" << operation;
249 } 261 }
250 } else if (type == ENTITY_TYPE_MAIL) { 262 } else if (type == ENTITY_TYPE_MAIL) {
251 Sink::EntityBuffer buffer(value.data(), value.size()); 263 Sink::EntityBuffer buffer(value);
252 const Sink::Entity &entity = buffer.entity(); 264 const Sink::Entity &entity = buffer.entity();
253 const auto metadataBuffer = Sink::EntityBuffer::readBuffer<Sink::Metadata>(entity.metadata()); 265 const auto metadataBuffer = Sink::EntityBuffer::readBuffer<Sink::Metadata>(entity.metadata());
254 if (metadataBuffer && !metadataBuffer->replayToSource()) { 266 if (metadataBuffer && !metadataBuffer->replayToSource()) {
@@ -268,10 +280,19 @@ KAsync::Job<void> MaildirResource::replay(Sink::Storage &synchronizationStore, c
268 } 280 }
269 const auto parentFolderPath = parentFolderRemoteId; 281 const auto parentFolderPath = parentFolderRemoteId;
270 KPIM::Maildir maildir(parentFolderPath, false); 282 KPIM::Maildir maildir(parentFolderPath, false);
271 //FIXME assemble the MIME message 283 if (!maildir.isValid(true)) {
272 const auto id = maildir.addEntry("foobar"); 284 return KAsync::error<void>(1, "Invalid folder " + parentFolderPath);
273 Trace() << "Creating a new mail: " << id; 285 }
274 recordRemoteId(ENTITY_TYPE_MAIL, mail.identifier(), id.toUtf8(), synchronizationTransaction); 286 //FIXME move the mime message from the mimeMessage property to the proper place.
287 Trace() << "Creating a new mail.";
288 const auto remoteId = maildir.addEntry("foobar");
289 if (remoteId.isEmpty()) {
290 Warning() << "Failed to create mail: " << remoteId;
291 return KAsync::error<void>(1, "Failed to create mail.");
292 } else {
293 Trace() << "Mail created: " << remoteId;
294 recordRemoteId(ENTITY_TYPE_MAIL, mail.identifier(), remoteId.toUtf8(), synchronizationTransaction);
295 }
275 } else if (operation == Sink::Operation_Removal) { 296 } else if (operation == Sink::Operation_Removal) {
276 const auto uid = Sink::Storage::uidFromKey(key); 297 const auto uid = Sink::Storage::uidFromKey(key);
277 const auto remoteId = resolveLocalId(ENTITY_TYPE_MAIL, uid, synchronizationTransaction); 298 const auto remoteId = resolveLocalId(ENTITY_TYPE_MAIL, uid, synchronizationTransaction);
@@ -279,7 +300,26 @@ KAsync::Job<void> MaildirResource::replay(Sink::Storage &synchronizationStore, c
279 QFile::remove(remoteId); 300 QFile::remove(remoteId);
280 removeRemoteId(ENTITY_TYPE_MAIL, uid, remoteId, synchronizationTransaction); 301 removeRemoteId(ENTITY_TYPE_MAIL, uid, remoteId, synchronizationTransaction);
281 } else if (operation == Sink::Operation_Modification) { 302 } else if (operation == Sink::Operation_Modification) {
282 Warning() << "Mail modifications are not implemented"; 303 const auto uid = Sink::Storage::uidFromKey(key);
304 const auto remoteId = resolveLocalId(ENTITY_TYPE_MAIL, uid, synchronizationTransaction);
305 Trace() << "Modifying a mail: " << remoteId;
306 auto parts = remoteId.split('/');
307 const auto filename = parts.takeLast(); //filename
308 parts.removeLast(); //cur/new folder
309 auto maildirPath = parts.join('/');
310
311 KPIM::Maildir maildir(maildirPath, false);
312
313 const Sink::ApplicationDomain::Mail mail(mResourceInstanceIdentifier, Sink::Storage::uidFromKey(key), revision, mMailAdaptorFactory->createAdaptor(entity));
314
315 //get flags from
316 KPIM::Maildir::Flags flags;
317 if (!mail.getProperty("unread").toBool()) {
318 flags |= KPIM::Maildir::Seen;
319 }
320
321 auto newRemoteId = maildir.changeEntryFlags(filename, flags);
322 updateRemoteId(ENTITY_TYPE_MAIL, uid, QString(maildirPath + "/cur/" + newRemoteId).toUtf8(), synchronizationTransaction);
283 } else { 323 } else {
284 Warning() << "Unkown operation" << operation; 324 Warning() << "Unkown operation" << operation;
285 } 325 }
@@ -299,20 +339,32 @@ KAsync::Job<void> MaildirResource::inspect(int inspectionType, const QByteArray
299 auto synchronizationTransaction = synchronizationStore->createTransaction(Sink::Storage::ReadOnly); 339 auto synchronizationTransaction = synchronizationStore->createTransaction(Sink::Storage::ReadOnly);
300 Trace() << "Inspecting " << inspectionType << domainType << entityId << property << expectedValue; 340 Trace() << "Inspecting " << inspectionType << domainType << entityId << property << expectedValue;
301 if (domainType == ENTITY_TYPE_MAIL) { 341 if (domainType == ENTITY_TYPE_MAIL) {
302 if (inspectionType == Sink::Resources::Inspection::PropertyInspectionType) { 342 if (inspectionType == Sink::ResourceControl::Inspection::PropertyInspectionType) {
303 if (property == "unread") { 343 if (property == "unread") {
304 const auto remoteId = resolveLocalId(ENTITY_TYPE_MAIL, entityId, synchronizationTransaction); 344 const auto remoteId = resolveLocalId(ENTITY_TYPE_MAIL, entityId, synchronizationTransaction);
305 const auto flags = KPIM::Maildir::readEntryFlags(remoteId.split('/').last()); 345 const auto flags = KPIM::Maildir::readEntryFlags(remoteId.split('/').last());
306 if (expectedValue.toBool() && !(flags & KPIM::Maildir::Seen)) { 346 if (expectedValue.toBool() && (flags & KPIM::Maildir::Seen)) {
307 return KAsync::error<void>(1, "Expected seen but couldn't find it."); 347 return KAsync::error<void>(1, "Expected unread but couldn't find it.");
308 } 348 }
309 if (!expectedValue.toBool() && (flags & KPIM::Maildir::Seen)) { 349 if (!expectedValue.toBool() && !(flags & KPIM::Maildir::Seen)) {
310 return KAsync::error<void>(1, "Expected seen but couldn't find it."); 350 return KAsync::error<void>(1, "Expected read but couldn't find it.");
351 }
352 return KAsync::null<void>();
353 }
354 if (property == "subject") {
355 const auto remoteId = resolveLocalId(ENTITY_TYPE_MAIL, entityId, synchronizationTransaction);
356
357 KMime::Message *msg = new KMime::Message;
358 msg->setHead(KMime::CRLFtoLF(KPIM::Maildir::readEntryHeadersFromFile(remoteId)));
359 msg->parse();
360
361 if (msg->subject(true)->asUnicodeString() != expectedValue.toString()) {
362 return KAsync::error<void>(1, "Subject not as expected: " + msg->subject(true)->asUnicodeString());
311 } 363 }
312 return KAsync::null<void>(); 364 return KAsync::null<void>();
313 } 365 }
314 } 366 }
315 if (inspectionType == Sink::Resources::Inspection::ExistenceInspectionType) { 367 if (inspectionType == Sink::ResourceControl::Inspection::ExistenceInspectionType) {
316 const auto remoteId = resolveLocalId(ENTITY_TYPE_MAIL, entityId, synchronizationTransaction); 368 const auto remoteId = resolveLocalId(ENTITY_TYPE_MAIL, entityId, synchronizationTransaction);
317 if (QFileInfo(remoteId).exists() != expectedValue.toBool()) { 369 if (QFileInfo(remoteId).exists() != expectedValue.toBool()) {
318 return KAsync::error<void>(1, "Wrong file existence: " + remoteId); 370 return KAsync::error<void>(1, "Wrong file existence: " + remoteId);
diff --git a/examples/maildirresource/maildirresource.h b/examples/maildirresource/maildirresource.h
index 9af2f39..32eb88c 100644
--- a/examples/maildirresource/maildirresource.h
+++ b/examples/maildirresource/maildirresource.h
@@ -32,12 +32,15 @@ class MaildirMailAdaptorFactory;
32class MaildirFolderAdaptorFactory; 32class MaildirFolderAdaptorFactory;
33 33
34/** 34/**
35 * A maildir resource 35 * A maildir resource.
36 * 36 *
37 * Implementation details: 37 * Implementation details:
38 * The remoteid's have the following formats: 38 * The remoteid's have the following formats:
39 * files: full file path 39 * files: full file path
40 * directories: full directory path 40 * directories: full directory path
41 *
42 * The resource moves all messages from new to cur during sync and thus expectes all messages that are in the store to always reside in cur.
43 * The tmp directory is never directly used
41 */ 44 */
42class MaildirResource : public Sink::GenericResource 45class MaildirResource : public Sink::GenericResource
43{ 46{