File indexing completed on 2024-09-22 04:52:43
0001 /* Copyright (C) 2006 - 2014 Jan Kundrát <jkt@flaska.net> 0002 0003 This file is part of the Trojita Qt IMAP e-mail client, 0004 http://trojita.flaska.net/ 0005 0006 This program is free software; you can redistribute it and/or 0007 modify it under the terms of the GNU General Public License as 0008 published by the Free Software Foundation; either version 2 of 0009 the License or (at your option) version 3 or any later version 0010 accepted by the membership of KDE e.V. (or its successor approved 0011 by the membership of KDE e.V.), which shall act as a proxy 0012 defined in Section 14 of version 3 of the license. 0013 0014 This program is distributed in the hope that it will be useful, 0015 but WITHOUT ANY WARRANTY; without even the implied warranty of 0016 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 0017 GNU General Public License for more details. 0018 0019 You should have received a copy of the GNU General Public License 0020 along with this program. If not, see <http://www.gnu.org/licenses/>. 0021 */ 0022 0023 #ifndef IMAP_MAILBOXTREE_H 0024 #define IMAP_MAILBOXTREE_H 0025 0026 #include <memory> 0027 #include <QList> 0028 #include <QModelIndex> 0029 #include <QPointer> 0030 #include <QString> 0031 #include "../Parser/Response.h" 0032 #include "../Parser/Message.h" 0033 #include "MailboxMetadata.h" 0034 0035 namespace Imap 0036 { 0037 0038 namespace Mailbox 0039 { 0040 0041 class Model; 0042 class MailboxModel; 0043 class KeepMailboxOpenTask; 0044 class ListChildMailboxesTask; 0045 0046 class TreeItem 0047 { 0048 friend class Model; // for m_loading and m_fetched 0049 TreeItem(const TreeItem &); // don't implement 0050 void operator=(const TreeItem &); // don't implement 0051 friend class DeleteMailboxTask; // for direct access to m_children 0052 friend class ObtainSynchronizedMailboxTask; 0053 friend class KeepMailboxOpenTask; // for direct access to m_children 0054 friend class ListChildMailboxesTask; // setStatus() in case of failure 0055 friend class MsgListModel; // for direct access to m_children 0056 friend class ThreadingMsgListModel; // for direct access to m_children 0057 friend class UpdateFlagsOfAllMessagesTask; // for direct access to m_children 0058 friend class FetchMsgPartTask; // for direct access to m_children 0059 0060 protected: 0061 /** @short Availability of an item */ 0062 enum FetchingState { 0063 NONE, /**< @short No attempt to download an item has been made yet */ 0064 UNAVAILABLE, /**< @short Item isn't cached and remote requests are disabled */ 0065 LOADING, /**< @short Download of an item is already scheduled */ 0066 DONE /**< @short Item is available right now */ 0067 }; 0068 0069 public: 0070 typedef enum { 0071 /** @short Full body of an e-mail stored on the IMAP server 0072 0073 This one really makes sense on a TreeItemMessage and TreeItemPart, and 0074 are used 0075 */ 0076 /** @short The HEADER fetch modifier for the current item */ 0077 OFFSET_HEADER=1, 0078 /** @short The TEXT fetch modifier for the current item */ 0079 OFFSET_TEXT=2, 0080 /** @short The MIME fetch modifier for individual message parts 0081 0082 In constrast to OFFSET_HEADER and OFFSET_TEXT, this one applies 0083 only to TreeItemPart, simply because using the MIME modifier on 0084 a top-level message is not allowed as per RFC 3501. 0085 */ 0086 OFFSET_MIME=3, 0087 /** @short Obtain the raw data without any kind of Content-Transfer-Encoding decoding */ 0088 OFFSET_RAW_CONTENTS = 4 0089 } PartModifier; 0090 0091 protected: 0092 static const intptr_t TagMask = 0x3; 0093 static const intptr_t PointerMask = ~TagMask; 0094 union { 0095 TreeItem *m_parent; 0096 intptr_t m_parentAsBits; 0097 }; 0098 TreeItemChildrenList m_children; 0099 0100 FetchingState accessFetchStatus() const 0101 { 0102 return static_cast<FetchingState>(m_parentAsBits & TagMask); 0103 } 0104 void setFetchStatus(const FetchingState fetchStatus) 0105 { 0106 m_parentAsBits = reinterpret_cast<intptr_t>(parent()) | fetchStatus; 0107 } 0108 public: 0109 explicit TreeItem(TreeItem *parent); 0110 TreeItem *parent() const 0111 { 0112 return reinterpret_cast<TreeItem *>(m_parentAsBits & PointerMask); 0113 } 0114 virtual int row() const; 0115 0116 virtual ~TreeItem(); 0117 virtual unsigned int childrenCount(Model *const model); 0118 virtual TreeItem *child(const int offset, Model *const model); 0119 virtual TreeItemChildrenList setChildren(const TreeItemChildrenList &items); 0120 virtual void fetch(Model *const model) = 0; 0121 virtual unsigned int rowCount(Model *const model) = 0; 0122 virtual unsigned int columnCount(); 0123 virtual QVariant data(Model *const model, int role) = 0; 0124 virtual bool hasChildren(Model *const model) = 0; 0125 virtual bool fetched() const { return accessFetchStatus() == DONE; } 0126 virtual bool loading() const { return accessFetchStatus() == LOADING; } 0127 virtual bool isUnavailable() const; 0128 virtual TreeItem *specialColumnPtr(int row, int column) const; 0129 virtual QModelIndex toIndex(Model *const model) const; 0130 }; 0131 0132 class TreeItemPart; 0133 class TreeItemMessage; 0134 0135 class TreeItemMailbox: public TreeItem 0136 { 0137 void operator=(const TreeItem &); // don't implement 0138 MailboxMetadata m_metadata; 0139 friend class Model; // needs access to maintianingTask 0140 friend class MailboxModel; 0141 friend class DeleteMailboxTask; // for direct access to maintainingTask 0142 friend class KeepMailboxOpenTask; // needs access to maintainingTask 0143 friend class SubscribeUnsubscribeTask; // needs access to m_metadata.flags 0144 friend class FetchMsgPartTask; // needs access to partIdToPtr() 0145 static QLatin1String flagNoInferiors; 0146 static QLatin1String flagHasNoChildren; 0147 static QLatin1String flagHasChildren; 0148 public: 0149 explicit TreeItemMailbox(TreeItem *parent); 0150 TreeItemMailbox(TreeItem *parent, Responses::List); 0151 ~TreeItemMailbox(); 0152 0153 static TreeItemMailbox *fromMetadata(TreeItem *parent, const MailboxMetadata &metadata); 0154 0155 TreeItemChildrenList setChildren(const TreeItemChildrenList &items) override; 0156 void fetch(Model *const model) override; 0157 virtual void fetchWithCacheControl(Model *const model, bool forceReload); 0158 unsigned int rowCount(Model *const model) override; 0159 QVariant data(Model *const model, int role) override; 0160 bool hasChildren(Model *const model) override; 0161 TreeItem *child(const int offset, Model *const model) override; 0162 0163 SyncState syncState; 0164 0165 /** @short Returns true if this mailbox has child mailboxes 0166 0167 This function might access the network if the answer can't be decided, for example on basis of mailbox flags. 0168 */ 0169 bool hasChildMailboxes(Model *const model); 0170 /** @short Return true if the mailbox is already known to not have any child mailboxes 0171 0172 No network activity will be caused. If the answer is not known for sure, we return false (meaning "don't know"). 0173 */ 0174 bool hasNoChildMailboxesAlreadyKnown(); 0175 0176 QString mailbox() const { return m_metadata.mailbox; } 0177 QString separator() const { return m_metadata.separator; } 0178 const MailboxMetadata &mailboxMetadata() const { return m_metadata; } 0179 /** @short Update internal tree with the results of a FETCH response 0180 0181 If \a changedPart is not null, it will be updated to point to the message 0182 part whose content got fetched. 0183 */ 0184 void handleFetchResponse(Model *const model, 0185 const Responses::Fetch &response, 0186 QList<TreeItemPart *> &changedParts, 0187 TreeItemMessage *&changedMessage, 0188 bool usingQresync); 0189 void rescanForChildMailboxes(Model *const model); 0190 void handleExpunge(Model *const model, const Responses::NumberResponse &resp); 0191 void handleExists(Model *const model, const Responses::NumberResponse &resp); 0192 void handleVanished(Model *const model, const Responses::Vanished &resp); 0193 bool isSelectable() const; 0194 0195 void saveSyncStateAndUids(Model *model); 0196 0197 private: 0198 TreeItemPart *partIdToPtr(Model *model, TreeItemMessage *message, const QByteArray &msgId); 0199 0200 /** @short ImapTask which is currently responsible for well-being of this mailbox */ 0201 QPointer<KeepMailboxOpenTask> maintainingTask; 0202 }; 0203 0204 class TreeItemMsgList: public TreeItem 0205 { 0206 void operator=(const TreeItem &); // don't implement 0207 friend class TreeItemMailbox; 0208 friend class TreeItemMessage; // for maintaining the m_unreadMessageCount 0209 friend class Model; 0210 friend class ObtainSynchronizedMailboxTask; 0211 friend class KeepMailboxOpenTask; 0212 FetchingState m_numberFetchingStatus; 0213 int m_totalMessageCount; 0214 int m_unreadMessageCount; 0215 int m_recentMessageCount; 0216 public: 0217 explicit TreeItemMsgList(TreeItem *parent); 0218 0219 void fetch(Model *const model) override; 0220 unsigned int rowCount(Model *const model) override; 0221 QVariant data(Model *const model, int role) override; 0222 bool hasChildren(Model *const model) override; 0223 0224 int totalMessageCount(Model *const model); 0225 int unreadMessageCount(Model *const model); 0226 int recentMessageCount(Model *const model); 0227 void fetchNumbers(Model *const model); 0228 void recalcVariousMessageCounts(Model *model); 0229 void recalcVariousMessageCountsOnExpunge(Model *model, TreeItemMessage *expungedMessage); 0230 void resetWasUnreadState(); 0231 bool numbersFetched() const; 0232 }; 0233 0234 class MessageDataPayload 0235 { 0236 public: 0237 MessageDataPayload(); 0238 0239 const Message::Envelope &envelope() const; 0240 void setEnvelope(const Message::Envelope &envelope); 0241 const QDateTime &internalDate() const; 0242 void setInternalDate(const QDateTime &internalDate); 0243 quint64 size() const; 0244 void setSize(const quint64 size); 0245 const QList<QByteArray> &hdrReferences() const; 0246 void setHdrReferences(const QList<QByteArray> &hdrReferences); 0247 const QList<QUrl> &hdrListPost() const; 0248 void setHdrListPost(const QList<QUrl> &hdrListPost); 0249 bool hdrListPostNo() const; 0250 void setHdrListPostNo(const bool hdrListPostNo); 0251 const QByteArray &rememberedBodyStructure() const; 0252 void setRememberedBodyStructure(const QByteArray &blob); 0253 0254 TreeItemPart *partHeader() const; 0255 void setPartHeader(std::unique_ptr<TreeItemPart> part); 0256 TreeItemPart *partText() const; 0257 void setPartText(std::unique_ptr<TreeItemPart> part); 0258 0259 bool isComplete() const; 0260 0261 bool gotEnvelope() const; 0262 bool gotInternalDate() const; 0263 bool gotSize() const; 0264 bool gotHdrReferences() const; 0265 bool gotHdrListPost() const; 0266 bool gotRemeberedBodyStructure() const; 0267 0268 private: 0269 Message::Envelope m_envelope; 0270 QDateTime m_internalDate; 0271 quint64 m_size; 0272 QList<QByteArray> m_hdrReferences; 0273 QList<QUrl> m_hdrListPost; 0274 QByteArray m_rememberedBodyStructure; 0275 bool m_hdrListPostNo; 0276 std::unique_ptr<TreeItemPart> m_partHeader; 0277 std::unique_ptr<TreeItemPart> m_partText; 0278 0279 bool m_gotEnvelope : 1; 0280 bool m_gotInternalDate : 1; 0281 bool m_gotSize : 1; 0282 bool m_gotBodystructure : 1; 0283 bool m_gotHdrReferences : 1; 0284 bool m_gotHdrListPost : 1; 0285 }; 0286 0287 class TreeItemMessage: public TreeItem 0288 { 0289 void operator=(const TreeItem &); // don't implement 0290 friend class TreeItemMailbox; 0291 friend class TreeItemMsgList; 0292 friend class Model; 0293 friend class ObtainSynchronizedMailboxTask; // needs access to m_offset 0294 friend class KeepMailboxOpenTask; // needs access to m_offset 0295 friend class ThreadingMsgListModel; // needs access to m_flags 0296 friend class UpdateFlagsTask; // needs access to m_flags 0297 friend class UpdateFlagsOfAllMessagesTask; // needs access to m_flags 0298 int m_offset; 0299 uint m_uid; 0300 mutable MessageDataPayload *m_data; 0301 QStringList m_flags; 0302 bool m_flagsHandled; 0303 bool m_wasUnread; 0304 /** @short Set FLAGS and maintain the unread message counter */ 0305 void setFlags(TreeItemMsgList *list, const QStringList &flags); 0306 void processAdditionalHeaders(Model *model, const QByteArray &rawHeaders); 0307 static bool hasNestedAttachments(Model *const model, TreeItemPart *part); 0308 0309 MessageDataPayload *data() const 0310 { 0311 return m_data ? m_data : (m_data = new MessageDataPayload()); 0312 } 0313 0314 public: 0315 explicit TreeItemMessage(TreeItem *parent); 0316 ~TreeItemMessage(); 0317 0318 int row() const override; 0319 void fetch(Model *const model) override; 0320 unsigned int rowCount(Model *const model) override; 0321 unsigned int columnCount() override; 0322 QVariant data(Model *const model, int role) override; 0323 bool hasChildren(Model *const model) override { Q_UNUSED(model); return true; } 0324 TreeItemChildrenList setChildren(const TreeItemChildrenList &items) override; 0325 Message::Envelope envelope(Model *const model); 0326 QDateTime internalDate(Model *const model); 0327 quint64 size(Model *const model); 0328 bool isMarkedAsDeleted() const; 0329 bool isMarkedAsRead() const; 0330 bool isMarkedAsReplied() const; 0331 bool isMarkedAsForwarded() const; 0332 bool isMarkedAsRecent() const; 0333 bool isMarkedAsFlagged() const; 0334 bool isMarkedAsJunk() const; 0335 bool isMarkedAsNotJunk() const; 0336 void checkFlagsReadRecent(bool &isRead, bool &isRecent) const; 0337 uint uid() const; 0338 TreeItem *specialColumnPtr(int row, int column) const override; 0339 bool hasAttachments(Model *const model); 0340 0341 static QVariantList addresListToQVariant(const QList<Imap::Message::MailAddress> &addressList); 0342 }; 0343 0344 class TreeItemPart: public TreeItem 0345 { 0346 void operator=(const TreeItem &); // don't implement 0347 friend class TreeItemMailbox; // needs access to m_data 0348 friend class Model; // dtto 0349 friend class FetchMsgPartTask; // needs m_binaryCTEFailed 0350 QByteArray m_mimeType; 0351 QByteArray m_charset; 0352 QByteArray m_contentFormat; 0353 QByteArray m_delSp; 0354 QByteArray m_transferEncoding; 0355 QByteArray m_data; 0356 QByteArray m_bodyFldId; 0357 QByteArray m_bodyDisposition; 0358 QString m_fileName; 0359 quint64 m_octets; 0360 QByteArray m_multipartRelatedStartPart; 0361 Imap::Message::AbstractMessage::bodyFldParam_t m_bodyFldParam; 0362 mutable TreeItemPart *m_partMime; 0363 mutable TreeItemPart *m_partRaw; 0364 bool m_binaryCTEFailed; 0365 public: 0366 TreeItemPart(TreeItem *parent, const QByteArray &mimeType); 0367 ~TreeItemPart(); 0368 0369 unsigned int childrenCount(Model *const model) override; 0370 TreeItem *child(const int offset, Model *const model) override; 0371 TreeItemChildrenList setChildren(const TreeItemChildrenList &items) override; 0372 0373 virtual void fetchFromCache(Model *const model); 0374 void fetch(Model *const model) override; 0375 unsigned int rowCount(Model *const model) override; 0376 unsigned int columnCount() override; 0377 QVariant data(Model *const model, int role) override; 0378 bool hasChildren(Model *const model) override; 0379 0380 virtual QByteArray partId() const; 0381 0382 /** @short Shall we use RFC3516 BINARY for fetching message parts or not */ 0383 typedef enum { 0384 /** @short Use the baseline IMAP feature, the BODY[...], from RFC 3501 */ 0385 FETCH_PART_IMAP, 0386 /** @short Fetch via the RFC3516's BINARY extension */ 0387 FETCH_PART_BINARY 0388 } PartFetchingMode; 0389 0390 virtual QByteArray partIdForFetch(const PartFetchingMode fetchingMode) const; 0391 virtual QByteArray pathToPart() const; 0392 TreeItemMessage *message() const; 0393 0394 /** @short Provide access to the internal buffer holding data 0395 0396 It is safe to access the obtained pointer as long as this object is not 0397 deleted. This function violates the classic concept of object 0398 encapsulation, but is really useful for the implementation of 0399 Imap::Network::MsgPartNetworkReply. 0400 */ 0401 QByteArray *dataPtr(); 0402 QByteArray mimeType() const { return m_mimeType; } 0403 QByteArray charset() const { return m_charset; } 0404 void setCharset(const QByteArray &ch) { m_charset = ch; } 0405 void setContentFormat(const QByteArray &format) { m_contentFormat = format; } 0406 void setContentDelSp(const QByteArray &delSp) { m_delSp = delSp; } 0407 void setTransferEncoding(const QByteArray &transferEncoding) { m_transferEncoding = transferEncoding; } 0408 QByteArray transferEncoding() const { return m_transferEncoding; } 0409 void setBodyFldId(const QByteArray &id) { m_bodyFldId = id; } 0410 QByteArray bodyFldId() const { return m_bodyFldId; } 0411 void setBodyDisposition(const QByteArray &disposition) { m_bodyDisposition = disposition; } 0412 QByteArray bodyDisposition() const { return m_bodyDisposition; } 0413 void setFileName(const QString &name) { m_fileName = name; } 0414 QString fileName() const { return m_fileName; } 0415 void setOctets(const quint64 size) { m_octets = size; } 0416 /** @short Return the downloadable size of the message part */ 0417 quint64 octets() const { return m_octets; } 0418 QByteArray multipartRelatedStartPart() const { return m_multipartRelatedStartPart; } 0419 void setMultipartRelatedStartPart(const QByteArray &start) { m_multipartRelatedStartPart = start; } 0420 void setBodyFldParam(const Imap::Message::AbstractMessage::bodyFldParam_t &bodyFldParam) { m_bodyFldParam = bodyFldParam; } 0421 Imap::Message::AbstractMessage::bodyFldParam_t bodyFldParam() const { return m_bodyFldParam; } 0422 TreeItem *specialColumnPtr(int row, int column) const override; 0423 virtual bool isTopLevelMultiPart() const; 0424 0425 virtual void silentlyReleaseMemoryRecursive(); 0426 protected: 0427 TreeItemPart(TreeItem *parent); 0428 }; 0429 0430 /** @short A message part with a modifier 0431 0432 This item hanldes fetching of message parts with an attached modifier (like TEXT, HEADER or MIME). 0433 */ 0434 class TreeItemModifiedPart: public TreeItemPart 0435 { 0436 PartModifier m_modifier; 0437 public: 0438 TreeItemModifiedPart(TreeItem *parent, const PartModifier kind); 0439 int row() const override; 0440 unsigned int columnCount() override; 0441 QByteArray partId() const override; 0442 QByteArray pathToPart() const override; 0443 TreeItem *specialColumnPtr(int row, int column) const override; 0444 PartModifier kind() const; 0445 QModelIndex toIndex(Model *const model) const override; 0446 QByteArray partIdForFetch(const PartFetchingMode fetchingMode) const override; 0447 protected: 0448 bool isTopLevelMultiPart() const override; 0449 private: 0450 QByteArray modifierToByteArray() const; 0451 }; 0452 0453 /** @short Specialization of TreeItemPart for parts holding a multipart/message */ 0454 class TreeItemPartMultipartMessage: public TreeItemPart 0455 { 0456 Message::Envelope m_envelope; 0457 mutable std::unique_ptr<TreeItemPart> m_partHeader; 0458 mutable std::unique_ptr<TreeItemPart> m_partText; 0459 public: 0460 TreeItemPartMultipartMessage(TreeItem *parent, const Message::Envelope &envelope); 0461 virtual ~TreeItemPartMultipartMessage(); 0462 QVariant data(Model * const model, int role) override; 0463 TreeItem *specialColumnPtr(int row, int column) const override; 0464 void silentlyReleaseMemoryRecursive() override; 0465 }; 0466 0467 } 0468 0469 } 0470 0471 Q_DECLARE_METATYPE(QByteArray*) 0472 0473 #endif // IMAP_MAILBOXTREE_H