summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt2
-rw-r--r--common/datastorequery.cpp35
-rw-r--r--common/mail/threadindexer.cpp5
-rw-r--r--examples/imapresource/imapserverproxy.cpp35
-rw-r--r--examples/imapresource/imapserverproxy.h1
5 files changed, 58 insertions, 20 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 210774f..d5729da 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -3,7 +3,7 @@ cmake_minimum_required(VERSION 3.0)
3cmake_policy(SET CMP0048 NEW) 3cmake_policy(SET CMP0048 NEW)
4cmake_policy(SET CMP0028 NEW) 4cmake_policy(SET CMP0028 NEW)
5 5
6project(sink VERSION 0.4.0) 6project(sink VERSION 0.5)
7 7
8option(BUILD_MAILDIR "BUILD_MAILDIR" ON) 8option(BUILD_MAILDIR "BUILD_MAILDIR" ON)
9option(BUILD_DAV "BUILD_DAV" ON) 9option(BUILD_DAV "BUILD_DAV" ON)
diff --git a/common/datastorequery.cpp b/common/datastorequery.cpp
index 4c95606..ad21910 100644
--- a/common/datastorequery.cpp
+++ b/common/datastorequery.cpp
@@ -524,6 +524,7 @@ void DataStoreQuery::setupQuery(const Sink::QueryBase &query_)
524{ 524{
525 auto query = query_; 525 auto query = query_;
526 auto baseFilters = query.getBaseFilters(); 526 auto baseFilters = query.getBaseFilters();
527 //Resolve any subqueries we have
527 for (const auto &k : baseFilters.keys()) { 528 for (const auto &k : baseFilters.keys()) {
528 const auto comparator = baseFilters.value(k); 529 const auto comparator = baseFilters.value(k);
529 if (comparator.value.canConvert<Query>()) { 530 if (comparator.value.canConvert<Query>()) {
@@ -534,26 +535,26 @@ void DataStoreQuery::setupQuery(const Sink::QueryBase &query_)
534 } 535 }
535 query.setBaseFilters(baseFilters); 536 query.setBaseFilters(baseFilters);
536 537
537 FilterBase::Ptr baseSet;
538 QSet<QByteArray> remainingFilters = query.getBaseFilters().keys().toSet();
539 QByteArray appliedSorting; 538 QByteArray appliedSorting;
540 if (!query.ids().isEmpty()) { 539
541 mSource = Source::Ptr::create(query.ids().toVector(), this); 540 //Determine initial set
542 baseSet = mSource; 541 mSource = [&]() {
543 } else { 542 if (!query.ids().isEmpty()) {
544 QSet<QByteArray> appliedFilters; 543 //We have a set of ids as a starting point
545 544 return Source::Ptr::create(query.ids().toVector(), this);
546 auto resultSet = mStore.indexLookup(mType, query, appliedFilters, appliedSorting);
547 remainingFilters = remainingFilters - appliedFilters;
548
549 // We do a full scan if there were no indexes available to create the initial set.
550 if (appliedFilters.isEmpty()) {
551 mSource = Source::Ptr::create(mStore.fullScan(mType), this);
552 } else { 545 } else {
553 mSource = Source::Ptr::create(resultSet, this); 546 QSet<QByteArray> appliedFilters;
547 auto resultSet = mStore.indexLookup(mType, query, appliedFilters, appliedSorting);
548 if (!appliedFilters.isEmpty()) {
549 //We have an index lookup as starting point
550 return Source::Ptr::create(resultSet, this);
551 }
552 // We do a full scan if there were no indexes available to create the initial set (this is going to be expensive for large sets).
553 return Source::Ptr::create(mStore.fullScan(mType), this);
554 } 554 }
555 baseSet = mSource; 555 }();
556 } 556
557 FilterBase::Ptr baseSet = mSource;
557 if (!query.getBaseFilters().isEmpty()) { 558 if (!query.getBaseFilters().isEmpty()) {
558 auto filter = Filter::Ptr::create(baseSet, this); 559 auto filter = Filter::Ptr::create(baseSet, this);
559 //For incremental queries the remaining filters are not sufficient 560 //For incremental queries the remaining filters are not sufficient
diff --git a/common/mail/threadindexer.cpp b/common/mail/threadindexer.cpp
index 1401fc8..68f7af7 100644
--- a/common/mail/threadindexer.cpp
+++ b/common/mail/threadindexer.cpp
@@ -46,6 +46,11 @@ void ThreadIndexer::updateThreadingIndex(const QByteArray &identifier, const App
46 if (!parentThread.isEmpty()) { 46 if (!parentThread.isEmpty()) {
47 auto childThreadId = thread.first(); 47 auto childThreadId = thread.first();
48 auto parentThreadId = parentThread.first(); 48 auto parentThreadId = parentThread.first();
49 //Can happen if the message is already available locally.
50 if (childThreadId == parentThreadId) {
51 //Nothing to do
52 return;
53 }
49 SinkTrace() << "Merging child thread: " << childThreadId << " into parent thread: " << parentThreadId; 54 SinkTrace() << "Merging child thread: " << childThreadId << " into parent thread: " << parentThreadId;
50 55
51 //Ensure this mail ends up in the correct thread 56 //Ensure this mail ends up in the correct thread
diff --git a/examples/imapresource/imapserverproxy.cpp b/examples/imapresource/imapserverproxy.cpp
index 5c2e07c..16887b1 100644
--- a/examples/imapresource/imapserverproxy.cpp
+++ b/examples/imapresource/imapserverproxy.cpp
@@ -31,6 +31,7 @@
31#include <KIMAP2/ExpungeJob> 31#include <KIMAP2/ExpungeJob>
32#include <KIMAP2/CapabilitiesJob> 32#include <KIMAP2/CapabilitiesJob>
33#include <KIMAP2/SearchJob> 33#include <KIMAP2/SearchJob>
34#include <KIMAP2/GetMetaDataJob>
34 35
35#include <KCoreAddons/KJob> 36#include <KCoreAddons/KJob>
36 37
@@ -479,14 +480,33 @@ static void reportFolder(const Folder &f, QSharedPointer<QSet<QString>> reported
479 } 480 }
480} 481}
481 482
483KAsync::Job<void> ImapServerProxy::getMetaData(std::function<void(const QHash<QString, QMap<QByteArray, QByteArray> > &metadata)> callback)
484{
485 if (!mCapabilities.contains("METADATA")) {
486 return KAsync::null();
487 }
488 KIMAP2::GetMetaDataJob *meta = new KIMAP2::GetMetaDataJob(mSession);
489 meta->setMailBox(QLatin1String("*"));
490 meta->setServerCapability( KIMAP2::MetaDataJobBase::Metadata );
491 meta->setDepth(KIMAP2::GetMetaDataJob::AllLevels);
492 meta->addRequestedEntry("/shared/vendor/kolab/folder-type");
493 meta->addRequestedEntry("/private/vendor/kolab/folder-type");
494 return runJob(meta).then<void>([callback, meta] () {
495 callback(meta->allMetaDataForMailboxes());
496 });
497}
498
482KAsync::Job<void> ImapServerProxy::fetchFolders(std::function<void(const Folder &)> callback) 499KAsync::Job<void> ImapServerProxy::fetchFolders(std::function<void(const Folder &)> callback)
483{ 500{
484 SinkTrace() << "Fetching folders"; 501 SinkTrace() << "Fetching folders";
485 auto subscribedList = QSharedPointer<QSet<QString>>::create() ; 502 auto subscribedList = QSharedPointer<QSet<QString>>::create() ;
486 auto reportedList = QSharedPointer<QSet<QString>>::create() ; 503 auto reportedList = QSharedPointer<QSet<QString>>::create() ;
487 return list(KIMAP2::ListJob::NoOption, [=](const KIMAP2::MailBoxDescriptor &mailbox, const QList<QByteArray> &){ 504 auto metaData = QSharedPointer<QHash<QString, QMap<QByteArray, QByteArray>>>::create() ;
505 return getMetaData([=] (const QHash<QString, QMap<QByteArray, QByteArray>> &m) {
506 *metaData = m;
507 }).then(list(KIMAP2::ListJob::NoOption, [=](const KIMAP2::MailBoxDescriptor &mailbox, const QList<QByteArray> &){
488 *subscribedList << mailbox.name; 508 *subscribedList << mailbox.name;
489 }).then(list(KIMAP2::ListJob::IncludeUnsubscribed, [=](const KIMAP2::MailBoxDescriptor &mailbox, const QList<QByteArray> &flags) { 509 })).then(list(KIMAP2::ListJob::IncludeUnsubscribed, [=](const KIMAP2::MailBoxDescriptor &mailbox, const QList<QByteArray> &flags) {
490 bool noselect = caseInsensitiveContains(FolderFlags::Noselect, flags); 510 bool noselect = caseInsensitiveContains(FolderFlags::Noselect, flags);
491 bool subscribed = subscribedList->contains(mailbox.name); 511 bool subscribed = subscribedList->contains(mailbox.name);
492 if (isGmail()) { 512 if (isGmail()) {
@@ -502,6 +522,17 @@ KAsync::Job<void> ImapServerProxy::fetchFolders(std::function<void(const Folder
502 } 522 }
503 } 523 }
504 SinkLog() << "Found mailbox: " << mailbox.name << flags << FolderFlags::Noselect << noselect << " sub: " << subscribed; 524 SinkLog() << "Found mailbox: " << mailbox.name << flags << FolderFlags::Noselect << noselect << " sub: " << subscribed;
525 //Ignore all non-mail folders
526 if (metaData->contains(mailbox.name)) {
527 auto m = metaData->value(mailbox.name);
528 auto sharedType = m.value("/shared/vendor/kolab/folder-type");
529 auto privateType = m.value("/private/vendor/kolab/folder-type");
530 auto type = !privateType.isEmpty() ? privateType : sharedType;
531 if (!type.isEmpty() && !type.contains("mail")) {
532 SinkLog() << "Skipping due to folder type: " << type;
533 return;
534 }
535 }
505 auto ns = getNamespace(mailbox.name); 536 auto ns = getNamespace(mailbox.name);
506 auto folder = Folder{mailbox.name, ns, mailbox.separator, noselect, subscribed, flags}; 537 auto folder = Folder{mailbox.name, ns, mailbox.separator, noselect, subscribed, flags};
507 538
diff --git a/examples/imapresource/imapserverproxy.h b/examples/imapresource/imapserverproxy.h
index f9b854b..86e3378 100644
--- a/examples/imapresource/imapserverproxy.h
+++ b/examples/imapresource/imapserverproxy.h
@@ -294,6 +294,7 @@ public:
294 KAsync::Job<QVector<qint64>> fetchUids(const Folder &folder); 294 KAsync::Job<QVector<qint64>> fetchUids(const Folder &folder);
295 295
296private: 296private:
297 KAsync::Job<void> getMetaData(std::function<void(const QHash<QString, QMap<QByteArray, QByteArray> > &metadata)> callback);
297 bool isGmail() const; 298 bool isGmail() const;
298 299
299 QString getNamespace(const QString &name); 300 QString getNamespace(const QString &name);