File indexing completed on 2024-11-24 04:44:18
0001 /* 0002 SPDX-FileCopyrightText: 2014 Christian Mollekopf <mollekopf@kolabsys.com> 0003 0004 SPDX-License-Identifier: LGPL-2.0-or-later 0005 */ 0006 0007 #include "kolabretrievetagstask.h" 0008 #include "kolabresource_debug.h" 0009 #include "kolabresource_trace.h" 0010 #include "tagchangehelper.h" 0011 0012 #include "imapflags.h" 0013 #include "pimkolab/kolabformat/kolabobject.h" 0014 #include <KIMAP/FetchJob> 0015 #include <KIMAP/SelectJob> 0016 0017 KolabRetrieveTagTask::KolabRetrieveTagTask(const ResourceStateInterface::Ptr &resource, RetrieveType type, QObject *parent) 0018 : KolabRelationResourceTask(resource, parent) 0019 , mRetrieveType(type) 0020 { 0021 } 0022 0023 void KolabRetrieveTagTask::startRelationTask(KIMAP::Session *session) 0024 { 0025 mSession = session; 0026 const QString mailBox = mailBoxForCollection(relationCollection()); 0027 0028 auto select = new KIMAP::SelectJob(session); 0029 select->setMailBox(mailBox); 0030 connect(select, &KJob::result, this, &KolabRetrieveTagTask::onFinalSelectDone); 0031 select->start(); 0032 } 0033 0034 void KolabRetrieveTagTask::onFinalSelectDone(KJob *job) 0035 { 0036 if (job->error()) { 0037 qCWarning(KOLABRESOURCE_LOG) << job->errorString(); 0038 cancelTask(job->errorString()); 0039 return; 0040 } 0041 0042 auto select = static_cast<KIMAP::SelectJob *>(job); 0043 auto fetch = new KIMAP::FetchJob(select->session()); 0044 0045 if (select->messageCount() == 0) { 0046 taskComplete(); 0047 return; 0048 } 0049 0050 KIMAP::ImapSet set; 0051 set.add(KIMAP::ImapInterval(1, 0)); 0052 fetch->setSequenceSet(set); 0053 fetch->setUidBased(false); 0054 0055 KIMAP::FetchJob::FetchScope scope; 0056 scope.parts.clear(); 0057 scope.mode = KIMAP::FetchJob::FetchScope::Full; 0058 fetch->setScope(scope); 0059 connect(fetch, &KIMAP::FetchJob::messagesAvailable, this, &KolabRetrieveTagTask::onMessagesAvailable); 0060 connect(fetch, &KJob::result, this, &KolabRetrieveTagTask::onHeadersFetchDone); 0061 fetch->start(); 0062 } 0063 0064 void KolabRetrieveTagTask::onMessagesAvailable(const QMap<qint64, KIMAP::Message> &messages) 0065 { 0066 auto fetch = static_cast<KIMAP::FetchJob *>(sender()); 0067 Q_ASSERT(fetch); 0068 0069 for (auto it = messages.cbegin(), end = messages.cend(); it != end; ++it) { 0070 if (it->flags.contains(ImapFlags::Deleted)) { 0071 continue; 0072 } 0073 const KMime::Message::Ptr msg = it->message; 0074 const Kolab::KolabObjectReader reader(msg); 0075 switch (reader.getType()) { 0076 case Kolab::RelationConfigurationObject: 0077 if (mRetrieveType == RetrieveTags && reader.isTag()) { 0078 extractTag(reader, it->uid); 0079 } else if (mRetrieveType == RetrieveRelations && reader.isRelation()) { 0080 extractRelation(reader, it->uid); 0081 } 0082 break; 0083 0084 default: 0085 break; 0086 } 0087 } 0088 } 0089 0090 Akonadi::Item KolabRetrieveTagTask::extractMember(const Kolab::RelationMember &member) 0091 { 0092 // TODO should we create a dummy item if it isn't yet available? 0093 Akonadi::Item i; 0094 if (!member.gid.isEmpty()) { 0095 // Reference by GID 0096 i.setGid(member.gid); 0097 } else { 0098 // Reference by imap uid 0099 if (member.uid < 0) { 0100 return {}; 0101 } 0102 i.setRemoteId(QString::number(member.uid)); 0103 qCDebug(KOLABRESOURCE_LOG) << "got member: " << member.uid << member.mailbox; 0104 Akonadi::Collection parent; 0105 { 0106 // The root collection is not part of the mailbox path 0107 Akonadi::Collection col; 0108 col.setRemoteId(rootRemoteId()); 0109 col.setParentCollection(Akonadi::Collection::root()); 0110 parent = col; 0111 } 0112 for (const QByteArray &part : std::as_const(member.mailbox)) { 0113 Akonadi::Collection col; 0114 col.setRemoteId(separatorCharacter() + QString::fromLatin1(part)); 0115 col.setParentCollection(parent); 0116 parent = col; 0117 } 0118 i.setParentCollection(parent); 0119 } 0120 return i; 0121 } 0122 0123 void KolabRetrieveTagTask::extractTag(const Kolab::KolabObjectReader &reader, qint64 remoteUid) 0124 { 0125 Akonadi::Tag tag = reader.getTag(); 0126 tag.setRemoteId(QByteArray::number(remoteUid)); 0127 mTags << tag; 0128 0129 qCDebug(KOLABRESOURCE_TRACE) << "Extracted tag: " << tag.gid() << " remoteId: " << remoteUid << tag.remoteId(); 0130 0131 Akonadi::Item::List members; 0132 const QStringList lstMemberUrl = reader.getTagMembers(); 0133 for (const QString &memberUrl : lstMemberUrl) { 0134 Kolab::RelationMember member = Kolab::parseMemberUrl(memberUrl); 0135 const Akonadi::Item i = extractMember(member); 0136 // TODO implement fallback to search if uid is not available 0137 if (!i.remoteId().isEmpty() || !i.gid().isEmpty()) { 0138 members << i; 0139 } else { 0140 qCWarning(KOLABRESOURCE_LOG) << "Failed to parse member: " << memberUrl; 0141 } 0142 } 0143 mTagMembers.insert(QString::fromLatin1(tag.remoteId()), members); 0144 } 0145 0146 void KolabRetrieveTagTask::extractRelation(const Kolab::KolabObjectReader &reader, qint64 remoteUid) 0147 { 0148 Akonadi::Item::List members; 0149 const QStringList lstMemberUrl = reader.getTagMembers(); 0150 for (const QString &memberUrl : lstMemberUrl) { 0151 Kolab::RelationMember member = Kolab::parseMemberUrl(memberUrl); 0152 const Akonadi::Item i = extractMember(member); 0153 // TODO implement fallback to search if uid is not available 0154 if (!i.remoteId().isEmpty() || !i.gid().isEmpty()) { 0155 members << i; 0156 } else { 0157 qCWarning(KOLABRESOURCE_LOG) << "Failed to parse member: " << memberUrl; 0158 } 0159 } 0160 if (members.size() != 2) { 0161 qCWarning(KOLABRESOURCE_LOG) << "Wrong numbers of members for a relation, expected 2: " << members.size(); 0162 return; 0163 } 0164 0165 Akonadi::Relation relation = reader.getRelation(); 0166 relation.setType(Akonadi::Relation::GENERIC); 0167 relation.setRemoteId(QByteArray::number(remoteUid)); 0168 relation.setLeft(members.at(0)); 0169 relation.setRight(members.at(1)); 0170 mRelations << relation; 0171 } 0172 0173 void KolabRetrieveTagTask::onHeadersFetchDone(KJob *job) 0174 { 0175 if (job->error()) { 0176 qCWarning(KOLABRESOURCE_LOG) << "Fetch job failed " << job->errorString(); 0177 cancelTask(job->errorString()); 0178 return; 0179 } 0180 0181 taskComplete(); 0182 } 0183 0184 void KolabRetrieveTagTask::taskComplete() 0185 { 0186 if (mRetrieveType == RetrieveTags) { 0187 qCDebug(KOLABRESOURCE_LOG) << "Fetched tags: " << mTags.size() << mTagMembers.size(); 0188 resourceState()->tagsRetrieved(mTags, mTagMembers); 0189 } else if (mRetrieveType == RetrieveRelations) { 0190 qCDebug(KOLABRESOURCE_LOG) << "Fetched relations:" << mRelations.size(); 0191 resourceState()->relationsRetrieved(mRelations); 0192 } 0193 0194 deleteLater(); 0195 } 0196 0197 #include "moc_kolabretrievetagstask.cpp"