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