File indexing completed on 2024-11-24 04:44:18
0001 /* 0002 SPDX-FileCopyrightText: 2010 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com> 0003 SPDX-FileContributor: Kevin Ottens <kevin@kdab.com> 0004 0005 SPDX-FileCopyrightText: 2014 Christian Mollekopf <mollekopf@kolabsys.com> 0006 0007 SPDX-License-Identifier: LGPL-2.0-or-later 0008 */ 0009 0010 #include "kolabretrievecollectionstask.h" 0011 #include "kolabhelpers.h" 0012 #include "kolabresource_debug.h" 0013 #include "kolabresource_trace.h" 0014 0015 #include "collectionmetadatahelper.h" 0016 #include "imapaclattribute.h" 0017 #include "noinferiorsattribute.h" 0018 #include "noselectattribute.h" 0019 #include <Akonadi/CollectionAnnotationsAttribute> 0020 #include <KIMAP/GetMetaDataJob> 0021 #include <KIMAP/MyRightsJob> 0022 0023 #include <Akonadi/MessageParts> 0024 0025 #include <Akonadi/BlockAlarmsAttribute> 0026 #include <Akonadi/CachePolicy> 0027 #include <Akonadi/CollectionColorAttribute> 0028 #include <Akonadi/CollectionIdentificationAttribute> 0029 #include <Akonadi/EntityDisplayAttribute> 0030 #include <Akonadi/SpecialCollectionAttribute> 0031 #include <Akonadi/VectorHelper> 0032 0033 #include <KMime/Message> 0034 0035 #include <KLocalizedString> 0036 0037 #include <QColor> 0038 0039 static bool isNamespaceFolder(const QString &path, const QList<KIMAP::MailBoxDescriptor> &namespaces, bool matchCompletePath = false) 0040 { 0041 for (const KIMAP::MailBoxDescriptor &desc : namespaces) { 0042 if (path.startsWith(desc.name.left(desc.name.size() - 1))) { // Namespace ends with path separator and path doesn't 0043 if (!matchCompletePath || path.size() - desc.name.size() <= 1) { // We want to match only for the complete path 0044 return true; 0045 } 0046 } 0047 } 0048 return false; 0049 } 0050 0051 RetrieveMetadataJob::RetrieveMetadataJob(KIMAP::Session *session, 0052 const QStringList &mailboxes, 0053 const QStringList &serverCapabilities, 0054 const QSet<QByteArray> &requestedMetadata, 0055 const QString &separator, 0056 const QList<KIMAP::MailBoxDescriptor> &sharedNamespace, 0057 const QList<KIMAP::MailBoxDescriptor> &userNamespace, 0058 QObject *parent) 0059 : KJob(parent) 0060 , mRequestedMetadata(requestedMetadata) 0061 , mServerCapabilities(serverCapabilities) 0062 , mMailboxes(mailboxes) 0063 , mSession(session) 0064 , mSeparator(separator) 0065 , mSharedNamespace(sharedNamespace) 0066 , mUserNamespace(userNamespace) 0067 { 0068 } 0069 0070 void RetrieveMetadataJob::start() 0071 { 0072 qCDebug(KOLABRESOURCE_TRACE); 0073 // Fill the map with empty entries so we set the mimetype to mail if no metadata is retrieved 0074 for (const QString &mailbox : std::as_const(mMailboxes)) { 0075 mMetadata.insert(mailbox, QMap<QByteArray, QByteArray>()); 0076 } 0077 0078 if (mServerCapabilities.contains(QLatin1StringView("METADATA")) || mServerCapabilities.contains(QLatin1StringView("ANNOTATEMORE"))) { 0079 QSet<QString> toplevelMailboxes; 0080 for (const QString &mailbox : std::as_const(mMailboxes)) { 0081 const QStringList parts = mailbox.split(mSeparator); 0082 if (!parts.isEmpty()) { 0083 if (isNamespaceFolder(mailbox, mUserNamespace) && parts.length() >= 2) { 0084 // Other Users can be too big to request with a single command so we request Other Users/<user>/* 0085 toplevelMailboxes << parts.at(0) + mSeparator + parts.at(1) + mSeparator; 0086 } else if (!isNamespaceFolder(mailbox, mSharedNamespace)) { 0087 toplevelMailboxes << parts.first(); 0088 } 0089 } 0090 } 0091 for (const KIMAP::MailBoxDescriptor &desc : std::as_const(mSharedNamespace)) { 0092 toplevelMailboxes << desc.name; 0093 } 0094 // TODO perhaps exclude the shared and other users namespaces by listing only toplevel (with %), and then only getting metadata of the toplevel folders. 0095 for (const QString &mailbox : std::as_const(toplevelMailboxes)) { 0096 auto meta = new KIMAP::GetMetaDataJob(mSession); 0097 meta->setMailBox(mailbox + QLatin1StringView("*")); 0098 if (mServerCapabilities.contains(QLatin1StringView("METADATA"))) { 0099 meta->setServerCapability(KIMAP::MetaDataJobBase::Metadata); 0100 } else { 0101 meta->setServerCapability(KIMAP::MetaDataJobBase::Annotatemore); 0102 } 0103 meta->setDepth(KIMAP::GetMetaDataJob::AllLevels); 0104 for (const QByteArray &requestedEntry : std::as_const(mRequestedMetadata)) { 0105 meta->addRequestedEntry(requestedEntry); 0106 } 0107 connect(meta, &KJob::result, this, &RetrieveMetadataJob::onGetMetaDataDone); 0108 mJobs++; 0109 meta->start(); 0110 } 0111 } 0112 0113 // Get the ACLs from the mailbox if it's supported 0114 if (mServerCapabilities.contains(QLatin1StringView("ACL"))) { 0115 for (const QString &mailbox : std::as_const(mMailboxes)) { 0116 // "Shared Folders" is not a valid mailbox, so we have to skip the ACL request for this folder 0117 if (isNamespaceFolder(mailbox, mSharedNamespace, true)) { 0118 continue; 0119 } 0120 auto rights = new KIMAP::MyRightsJob(mSession); 0121 rights->setMailBox(mailbox); 0122 connect(rights, &KJob::result, this, &RetrieveMetadataJob::onRightsReceived); 0123 mJobs++; 0124 rights->start(); 0125 } 0126 } 0127 checkDone(); 0128 } 0129 0130 void RetrieveMetadataJob::onGetMetaDataDone(KJob *job) 0131 { 0132 mJobs--; 0133 auto meta = static_cast<KIMAP::GetMetaDataJob *>(job); 0134 if (job->error()) { 0135 qCDebug(KOLABRESOURCE_LOG) << "No metadata for for mailbox: " << meta->mailBox(); 0136 if (!isNamespaceFolder(meta->mailBox(), mSharedNamespace)) { 0137 qCWarning(KOLABRESOURCE_LOG) << "Get metadata failed: " << job->errorString(); 0138 // We ignore the error to avoid failing the complete sync. We can run into this when trying to retrieve rights for non-existing mailboxes. 0139 } 0140 checkDone(); 0141 return; 0142 } 0143 0144 const QHash<QString, QMap<QByteArray, QByteArray>> metadata = meta->allMetaDataForMailboxes(); 0145 const QStringList lstKeys = metadata.keys(); 0146 for (const QString &folder : lstKeys) { 0147 mMetadata.insert(folder, metadata.value(folder)); 0148 } 0149 checkDone(); 0150 } 0151 0152 void RetrieveMetadataJob::onRightsReceived(KJob *job) 0153 { 0154 mJobs--; 0155 auto rights = static_cast<KIMAP::MyRightsJob *>(job); 0156 if (job->error()) { 0157 qCDebug(KOLABRESOURCE_LOG) << "No rights for mailbox: " << rights->mailBox(); 0158 if (!isNamespaceFolder(rights->mailBox(), mSharedNamespace)) { 0159 qCWarning(KOLABRESOURCE_LOG) << "MyRights for mailbox" << rights->mailBox() << "failed:" << job->errorString(); 0160 // We ignore the error to avoid failing the complete sync. We can run into this when trying to retrieve rights for non-existing mailboxes. 0161 } 0162 checkDone(); 0163 return; 0164 } 0165 0166 const KIMAP::Acl::Rights imapRights = rights->rights(); 0167 mRights.insert(rights->mailBox(), imapRights); 0168 checkDone(); 0169 } 0170 0171 void RetrieveMetadataJob::checkDone() 0172 { 0173 if (!mJobs) { 0174 qCDebug(KOLABRESOURCE_TRACE) << "done"; 0175 qCDebug(KOLABRESOURCE_LOG) << "done"; 0176 emitResult(); 0177 } 0178 } 0179 0180 KolabRetrieveCollectionsTask::KolabRetrieveCollectionsTask(const ResourceStateInterface::Ptr &resource, QObject *parent) 0181 : ResourceTask(CancelIfNoSession, resource, parent) 0182 , cContentMimeTypes("CONTENTMIMETYPES") 0183 , cAccessRights("AccessRights") 0184 , cImapAcl("imapacl") 0185 , cCollectionAnnotations("collectionannotations") 0186 , cDefaultKeepLocalChanges(QSet<QByteArray>() << cContentMimeTypes << cAccessRights << cImapAcl << cCollectionAnnotations) 0187 , cDefaultMimeTypes(QStringList() << Akonadi::Collection::mimeType() << QStringLiteral("application/x-kolab-objects")) 0188 , cCollectionOnlyContentMimeTypes(QStringList() << Akonadi::Collection::mimeType()) 0189 { 0190 mRequestedMetadata << "/shared/vendor/kolab/folder-type"; 0191 mRequestedMetadata << "/private/vendor/kolab/folder-type"; 0192 mRequestedMetadata << "/shared" KOLAB_COLOR_ANNOTATION << "/private" KOLAB_COLOR_ANNOTATION; 0193 } 0194 0195 KolabRetrieveCollectionsTask::~KolabRetrieveCollectionsTask() = default; 0196 0197 void KolabRetrieveCollectionsTask::doStart(KIMAP::Session *session) 0198 { 0199 qCDebug(KOLABRESOURCE_LOG) << "Starting collection retrieval"; 0200 mTime.start(); 0201 mSession = session; 0202 0203 Akonadi::Collection root; 0204 root.setName(resourceName()); 0205 root.setRemoteId(rootRemoteId()); 0206 root.setContentMimeTypes(QStringList(Akonadi::Collection::mimeType())); 0207 root.setParentCollection(Akonadi::Collection::root()); 0208 root.addAttribute(new NoSelectAttribute(true)); 0209 root.attribute<Akonadi::EntityDisplayAttribute>(Akonadi::Collection::AddIfMissing)->setIconName(QStringLiteral("kolab")); 0210 0211 Akonadi::CachePolicy policy; 0212 policy.setInheritFromParent(false); 0213 policy.setSyncOnDemand(true); 0214 0215 QStringList localParts; 0216 localParts << QLatin1StringView(Akonadi::MessagePart::Envelope) << QLatin1StringView(Akonadi::MessagePart::Header); 0217 int cacheTimeout = 60; 0218 0219 if (isDisconnectedModeEnabled()) { 0220 // For disconnected mode we also cache the body 0221 // and we keep all data indefinitely 0222 localParts << QLatin1StringView(Akonadi::MessagePart::Body); 0223 cacheTimeout = -1; 0224 } 0225 0226 policy.setLocalParts(localParts); 0227 policy.setCacheTimeout(cacheTimeout); 0228 policy.setIntervalCheckTime(intervalCheckTime()); 0229 0230 root.setCachePolicy(policy); 0231 0232 mMailCollections.insert(QString(), root); 0233 0234 qCDebug(KOLABRESOURCE_TRACE) << "subscription enabled: " << isSubscriptionEnabled(); 0235 // jobs are serialized by the session 0236 if (isSubscriptionEnabled()) { 0237 auto fullListJob = new KIMAP::ListJob(session); 0238 fullListJob->setOption(KIMAP::ListJob::NoOption); 0239 fullListJob->setQueriedNamespaces(serverNamespaces()); 0240 connect(fullListJob, &KIMAP::ListJob::mailBoxesReceived, this, &KolabRetrieveCollectionsTask::onFullMailBoxesReceived); 0241 connect(fullListJob, &KJob::result, this, &KolabRetrieveCollectionsTask::onFullMailBoxesReceiveDone); 0242 mJobs++; 0243 fullListJob->start(); 0244 } 0245 0246 auto listJob = new KIMAP::ListJob(session); 0247 listJob->setOption(KIMAP::ListJob::IncludeUnsubscribed); 0248 listJob->setQueriedNamespaces(serverNamespaces()); 0249 connect(listJob, &KIMAP::ListJob::mailBoxesReceived, this, &KolabRetrieveCollectionsTask::onMailBoxesReceived); 0250 connect(listJob, &KJob::result, this, &KolabRetrieveCollectionsTask::onMailBoxesReceiveDone); 0251 mJobs++; 0252 listJob->start(); 0253 } 0254 0255 void KolabRetrieveCollectionsTask::onMailBoxesReceived(const QList<KIMAP::MailBoxDescriptor> &descriptors, const QList<QList<QByteArray>> &flags) 0256 { 0257 const int nbDescriptors = descriptors.size(); 0258 for (int i = 0; i < nbDescriptors; ++i) { 0259 const KIMAP::MailBoxDescriptor descriptor = descriptors[i]; 0260 createCollection(descriptor.name, flags.at(i), !isSubscriptionEnabled() || mSubscribedMailboxes.contains(descriptor.name)); 0261 } 0262 checkDone(); 0263 } 0264 0265 Akonadi::Collection KolabRetrieveCollectionsTask::getOrCreateParent(const QString &path) 0266 { 0267 if (mMailCollections.contains(path)) { 0268 return mMailCollections.value(path); 0269 } 0270 // create a dummy collection 0271 const QString separator = separatorCharacter(); 0272 const QStringList pathParts = path.split(separator); 0273 const QString pathPart = pathParts.last(); 0274 Akonadi::Collection c; 0275 c.setName(pathPart); 0276 c.setRemoteId(separator + pathPart); 0277 const QStringList parentPath = pathParts.mid(0, pathParts.size() - 1); 0278 const Akonadi::Collection parentCollection = getOrCreateParent(parentPath.join(separator)); 0279 c.setParentCollection(parentCollection); 0280 0281 c.addAttribute(new NoSelectAttribute(true)); 0282 c.setContentMimeTypes(QStringList() << Akonadi::Collection::mimeType()); 0283 c.setRights(Akonadi::Collection::ReadOnly); 0284 c.setEnabled(false); 0285 setAttributes(c, pathParts, path); 0286 0287 mMailCollections.insert(path, c); 0288 return c; 0289 } 0290 0291 void KolabRetrieveCollectionsTask::setAttributes(Akonadi::Collection &c, const QStringList &pathParts, const QString &path) 0292 { 0293 auto attr = c.attribute<Akonadi::CollectionIdentificationAttribute>(Akonadi::Collection::AddIfMissing); 0294 attr->setIdentifier(path.toLatin1()); 0295 0296 // If the folder is a other users folder block all alarms from default 0297 if (isNamespaceFolder(path, resourceState()->userNamespaces())) { 0298 auto attr = c.attribute<Akonadi::BlockAlarmsAttribute>(Akonadi::Collection::AddIfMissing); 0299 attr->blockEverything(true); 0300 } 0301 0302 // If the folder is a other users top-level folder mark it accordingly 0303 if (pathParts.size() == 1 && isNamespaceFolder(path, resourceState()->userNamespaces())) { 0304 auto attr = c.attribute<Akonadi::EntityDisplayAttribute>(Akonadi::Collection::AddIfMissing); 0305 attr->setDisplayName(i18n("Other Users")); 0306 attr->setIconName(QStringLiteral("x-mail-distribution-list")); 0307 } 0308 0309 // Mark user folders for searching 0310 if (pathParts.size() >= 2 && isNamespaceFolder(path, resourceState()->userNamespaces())) { 0311 auto attr = c.attribute<Akonadi::CollectionIdentificationAttribute>(Akonadi::Collection::AddIfMissing); 0312 if (pathParts.size() == 2) { 0313 attr->setCollectionNamespace("usertoplevel"); 0314 } else { 0315 attr->setCollectionNamespace("user"); 0316 } 0317 } 0318 0319 // If the folder is a shared folders top-level folder mark it accordingly 0320 if (pathParts.size() == 1 && isNamespaceFolder(path, resourceState()->sharedNamespaces())) { 0321 auto attr = c.attribute<Akonadi::EntityDisplayAttribute>(Akonadi::Collection::AddIfMissing); 0322 attr->setDisplayName(i18n("Shared Folders")); 0323 attr->setIconName(QStringLiteral("x-mail-distribution-list")); 0324 } 0325 0326 // Mark shared folders for searching 0327 if (pathParts.size() >= 2 && isNamespaceFolder(path, resourceState()->sharedNamespaces())) { 0328 auto attr = c.attribute<Akonadi::CollectionIdentificationAttribute>(Akonadi::Collection::AddIfMissing); 0329 attr->setCollectionNamespace("shared"); 0330 } 0331 } 0332 0333 void KolabRetrieveCollectionsTask::createCollection(const QString &mailbox, const QList<QByteArray> ¤tFlags, bool isSubscribed) 0334 { 0335 const QString separator = separatorCharacter(); 0336 Q_ASSERT(separator.size() == 1); 0337 const QString boxName = mailbox.endsWith(separator) ? mailbox.left(mailbox.size() - 1) : mailbox; 0338 const QStringList pathParts = boxName.split(separator); 0339 const QString pathPart = pathParts.last(); 0340 0341 Akonadi::Collection c; 0342 // If we had a dummy collection we need to replace it 0343 if (mMailCollections.contains(mailbox)) { 0344 c = mMailCollections.value(mailbox); 0345 } 0346 c.setName(pathPart); 0347 c.setRemoteId(separator + pathPart); 0348 const QStringList parentPath = pathParts.mid(0, pathParts.size() - 1); 0349 const Akonadi::Collection parentCollection = getOrCreateParent(parentPath.join(separator)); 0350 c.setParentCollection(parentCollection); 0351 // TODO get from ResourceState, and add KMime::Message::mimeType() for the normal imap resource by default 0352 // We add a dummy mimetype, otherwise the itemsync doesn't even work (action is disabled and resourcebase aborts the operation) 0353 c.setContentMimeTypes(cDefaultMimeTypes); 0354 c.setKeepLocalChanges(cDefaultKeepLocalChanges); 0355 0356 // assume LRS, until myrights is executed 0357 if (serverCapabilities().contains(QLatin1StringView("ACL"))) { 0358 c.setRights(Akonadi::Collection::ReadOnly); 0359 } else { 0360 c.setRights(Akonadi::Collection::AllRights); 0361 } 0362 0363 setAttributes(c, pathParts, mailbox); 0364 0365 // If the folder is the Inbox, make some special settings. 0366 if (pathParts.size() == 1 && pathPart.compare(QLatin1StringView("inbox"), Qt::CaseInsensitive) == 0) { 0367 auto attr = c.attribute<Akonadi::EntityDisplayAttribute>(Akonadi::Collection::AddIfMissing); 0368 attr->setDisplayName(i18n("Inbox")); 0369 attr->setIconName(QStringLiteral("mail-folder-inbox")); 0370 c.attribute<Akonadi::SpecialCollectionAttribute>(Akonadi::Collection::AddIfMissing)->setCollectionType("inbox"); 0371 setIdleCollection(c); 0372 } 0373 0374 // If this folder is a noselect folder, make some special settings. 0375 if (currentFlags.contains("\\noselect")) { 0376 c.addAttribute(new NoSelectAttribute(true)); 0377 c.setContentMimeTypes(cCollectionOnlyContentMimeTypes); 0378 c.setRights(Akonadi::Collection::ReadOnly); 0379 } else { 0380 // remove the noselect attribute explicitly, in case we had set it before (eg. for non-subscribed non-leaf folders) 0381 c.removeAttribute<NoSelectAttribute>(); 0382 } 0383 0384 // If this folder is a noinferiors folder, it is not allowed to create subfolders inside. 0385 if (currentFlags.contains("\\noinferiors")) { 0386 // qCDebug(KOLABRESOURCE_LOG) << "Noinferiors: " << currentPath; 0387 c.addAttribute(new NoInferiorsAttribute(true)); 0388 c.setRights(c.rights() & ~Akonadi::Collection::CanCreateCollection); 0389 } 0390 c.setEnabled(isSubscribed); 0391 0392 // qCDebug(KOLABRESOURCE_LOG) << "creating collection " << mailbox << " with parent " << parentPath; 0393 mMailCollections.insert(mailbox, c); 0394 } 0395 0396 void KolabRetrieveCollectionsTask::onMailBoxesReceiveDone(KJob *job) 0397 { 0398 qCDebug(KOLABRESOURCE_LOG) << "All mailboxes received: " << mTime.elapsed(); 0399 qCDebug(KOLABRESOURCE_LOG) << "in total: " << mMailCollections.size(); 0400 mJobs--; 0401 if (job->error()) { 0402 qCWarning(KOLABRESOURCE_LOG) << QStringLiteral("Failed to retrieve mailboxes: ") + job->errorString(); 0403 cancelTask(i18n("Collection retrieval failed")); 0404 } else { 0405 QSet<QString> mailboxes; 0406 const QStringList lstKeys = mMailCollections.keys(); 0407 for (const QString &mailbox : lstKeys) { 0408 if (!mailbox.isEmpty() && !isNamespaceFolder(mailbox, resourceState()->userNamespaces() + resourceState()->sharedNamespaces())) { 0409 mailboxes << mailbox; 0410 } 0411 } 0412 0413 // Only request metadata for subscribed Other Users Folders 0414 const QStringList metadataMailboxes = mailboxes.unite(mSubscribedMailboxes).values(); 0415 0416 auto metadata = new RetrieveMetadataJob(mSession, 0417 metadataMailboxes, 0418 serverCapabilities(), 0419 mRequestedMetadata, 0420 separatorCharacter(), 0421 resourceState()->sharedNamespaces(), 0422 resourceState()->userNamespaces(), 0423 this); 0424 connect(metadata, &KJob::result, this, &KolabRetrieveCollectionsTask::onMetadataRetrieved); 0425 mJobs++; 0426 metadata->start(); 0427 } 0428 } 0429 0430 void KolabRetrieveCollectionsTask::applyRights(const QHash<QString, KIMAP::Acl::Rights> &rights) 0431 { 0432 // qCDebug(KOLABRESOURCE_LOG) << rights; 0433 const QStringList lstKeys = rights.keys(); 0434 for (const QString &mailbox : lstKeys) { 0435 if (mMailCollections.contains(mailbox)) { 0436 const KIMAP::Acl::Rights imapRights = rights.value(mailbox); 0437 QStringList parts = mailbox.split(separatorCharacter()); 0438 parts.removeLast(); 0439 QString parentMailbox = parts.join(separatorCharacter()); 0440 0441 KIMAP::Acl::Rights parentImapRights; 0442 // If the parent folder is not existing we can't rename 0443 if (!parentMailbox.isEmpty() && rights.contains(parentMailbox)) { 0444 parentImapRights = rights.value(parentMailbox); 0445 } 0446 // qCDebug(KOLABRESOURCE_LOG) << mailbox << parentMailbox << imapRights << parentImapRights; 0447 0448 Akonadi::Collection &collection = mMailCollections[mailbox]; 0449 CollectionMetadataHelper::applyRights(collection, imapRights, parentImapRights); 0450 0451 // Store the mailbox ACLs 0452 auto aclAttribute = collection.attribute<Akonadi::ImapAclAttribute>(Akonadi::Collection::AddIfMissing); 0453 const KIMAP::Acl::Rights oldRights = aclAttribute->myRights(); 0454 if (oldRights != imapRights) { 0455 aclAttribute->setMyRights(imapRights); 0456 } 0457 } else { 0458 qCWarning(KOLABRESOURCE_LOG) << "Can't find mailbox " << mailbox; 0459 } 0460 } 0461 } 0462 0463 void KolabRetrieveCollectionsTask::applyMetadata(const QHash<QString, QMap<QByteArray, QByteArray>> &metadataMap) 0464 { 0465 // qCDebug(KOLABRESOURCE_LOG) << metadataMap; 0466 const auto keys{metadataMap.keys()}; 0467 for (const QString &mailbox : keys) { 0468 const QMap<QByteArray, QByteArray> metadata = metadataMap.value(mailbox); 0469 if (mMailCollections.contains(mailbox)) { 0470 Akonadi::Collection &collection = mMailCollections[mailbox]; 0471 // qCDebug(KOLABRESOURCE_LOG) << mailbox << metadata << type << folderType << KolabHelpers::getContentMimeTypes(folderType); 0472 collection.attribute<Akonadi::CollectionAnnotationsAttribute>(Akonadi::Collection::AddIfMissing)->setAnnotations(metadata); 0473 const QByteArray type = KolabHelpers::getFolderTypeAnnotation(metadata); 0474 const Kolab::FolderType folderType = KolabHelpers::folderTypeFromString(type); 0475 collection.setContentMimeTypes(KolabHelpers::getContentMimeTypes(folderType)); 0476 const QColor color = KolabHelpers::getFolderColor(metadata); 0477 if (color.isValid()) { 0478 collection.attribute<Akonadi::CollectionColorAttribute>(Akonadi::Collection::AddIfMissing)->setColor(color); 0479 } 0480 QSet<QByteArray> keepLocalChanges = collection.keepLocalChanges(); 0481 keepLocalChanges.remove(cContentMimeTypes); 0482 collection.setKeepLocalChanges(keepLocalChanges); 0483 } 0484 } 0485 } 0486 0487 void KolabRetrieveCollectionsTask::onMetadataRetrieved(KJob *job) 0488 { 0489 qCDebug(KOLABRESOURCE_LOG) << mTime.elapsed(); 0490 mJobs--; 0491 if (job->error()) { 0492 qCWarning(KOLABRESOURCE_LOG) << "Error while retrieving metadata, aborting collection retrieval: " << job->errorString(); 0493 cancelTask(i18n("Collection retrieval failed")); 0494 } else { 0495 auto metadata = static_cast<RetrieveMetadataJob *>(job); 0496 applyRights(metadata->mRights); 0497 applyMetadata(metadata->mMetadata); 0498 checkDone(); 0499 } 0500 } 0501 0502 void KolabRetrieveCollectionsTask::checkDone() 0503 { 0504 if (!mJobs) { 0505 collectionsRetrieved(Akonadi::valuesToVector(mMailCollections)); 0506 qCDebug(KOLABRESOURCE_LOG) << "done " << mTime.elapsed(); 0507 } 0508 } 0509 0510 void KolabRetrieveCollectionsTask::onFullMailBoxesReceived(const QList<KIMAP::MailBoxDescriptor> &descriptors, const QList<QList<QByteArray>> &flags) 0511 { 0512 Q_UNUSED(flags) 0513 for (const KIMAP::MailBoxDescriptor &descriptor : descriptors) { 0514 mSubscribedMailboxes.insert(descriptor.name); 0515 } 0516 } 0517 0518 void KolabRetrieveCollectionsTask::onFullMailBoxesReceiveDone(KJob *job) 0519 { 0520 qCDebug(KOLABRESOURCE_LOG) << "received subscribed collections " << mTime.elapsed(); 0521 mJobs--; 0522 if (job->error()) { 0523 qCWarning(KOLABRESOURCE_LOG) << QStringLiteral("Failed to retrieve subscribed collections: ") + job->errorString(); 0524 cancelTask(i18n("Collection retrieval failed")); 0525 } else { 0526 checkDone(); 0527 } 0528 } 0529 0530 #include "moc_kolabretrievecollectionstask.cpp"