diff options
-rw-r--r-- | CMakeLists.txt | 2 | ||||
-rw-r--r-- | common/datastorequery.cpp | 35 | ||||
-rw-r--r-- | common/mail/threadindexer.cpp | 5 | ||||
-rw-r--r-- | examples/imapresource/imapserverproxy.cpp | 35 | ||||
-rw-r--r-- | examples/imapresource/imapserverproxy.h | 1 |
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) | |||
3 | cmake_policy(SET CMP0048 NEW) | 3 | cmake_policy(SET CMP0048 NEW) |
4 | cmake_policy(SET CMP0028 NEW) | 4 | cmake_policy(SET CMP0028 NEW) |
5 | 5 | ||
6 | project(sink VERSION 0.4.0) | 6 | project(sink VERSION 0.5) |
7 | 7 | ||
8 | option(BUILD_MAILDIR "BUILD_MAILDIR" ON) | 8 | option(BUILD_MAILDIR "BUILD_MAILDIR" ON) |
9 | option(BUILD_DAV "BUILD_DAV" ON) | 9 | option(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 | ||
483 | KAsync::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 | |||
482 | KAsync::Job<void> ImapServerProxy::fetchFolders(std::function<void(const Folder &)> callback) | 499 | KAsync::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 | ||
296 | private: | 296 | private: |
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); |