1 /* Copyright (C) 2006 - 2014 Jan Kundrát <jkt@flaska.net> 2 3 This file is part of the Trojita Qt IMAP e-mail client, 4 http://trojita.flaska.net/ 5 6 This program is free software; you can redistribute it and/or 7 modify it under the terms of the GNU General Public License as 8 published by the Free Software Foundation; either version 2 of 9 the License or (at your option) version 3 or any later version 10 accepted by the membership of KDE e.V. (or its successor approved 11 by the membership of KDE e.V.), which shall act as a proxy 12 defined in Section 14 of version 3 of the license. 13 14 This program is distributed in the hope that it will be useful, 15 but WITHOUT ANY WARRANTY; without even the implied warranty of 16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 GNU General Public License for more details. 18 19 You should have received a copy of the GNU General Public License 20 along with this program. If not, see <http://www.gnu.org/licenses/>. 21 */ 22 23 #ifndef IMAP_MAILBOXTREE_H 24 #define IMAP_MAILBOXTREE_H 25 26 #include <memory> 27 #include <QList> 28 #include <QModelIndex> 29 #include <QPointer> 30 #include <QString> 31 #include "../Parser/Response.h" 32 #include "../Parser/Message.h" 33 #include "MailboxMetadata.h" 34 35 namespace Imap 36 { 37 38 namespace Mailbox 39 { 40 41 class Model; 42 class MailboxModel; 43 class KeepMailboxOpenTask; 44 class ListChildMailboxesTask; 45 46 class TreeItem 47 { 48 friend class Model; // for m_loading and m_fetched 49 TreeItem(const TreeItem &); // don't implement 50 void operator=(const TreeItem &); // don't implement 51 friend class DeleteMailboxTask; // for direct access to m_children 52 friend class ObtainSynchronizedMailboxTask; 53 friend class KeepMailboxOpenTask; // for direct access to m_children 54 friend class ListChildMailboxesTask; // setStatus() in case of failure 55 friend class MsgListModel; // for direct access to m_children 56 friend class ThreadingMsgListModel; // for direct access to m_children 57 friend class UpdateFlagsOfAllMessagesTask; // for direct access to m_children 58 59 protected: 60 /** @short Availability of an item */ 61 enum FetchingState { 62 NONE, /**< @short No attempt to download an item has been made yet */ 63 UNAVAILABLE, /**< @short Item isn't cached and remote requests are disabled */ 64 LOADING, /**< @short Download of an item is already scheduled */ 65 DONE /**< @short Item is available right now */ 66 }; 67 68 public: 69 typedef enum { 70 /** @short Full body of an e-mail stored on the IMAP server 71 72 This one really makes sense on a TreeItemMessage and TreeItemPart, and 73 are used 74 */ 75 /** @short The HEADER fetch modifier for the current item */ 76 OFFSET_HEADER=1, 77 /** @short The TEXT fetch modifier for the current item */ 78 OFFSET_TEXT=2, 79 /** @short The MIME fetch modifier for individual message parts 80 81 In constrast to OFFSET_HEADER and OFFSET_TEXT, this one applies 82 only to TreeItemPart, simply because using the MIME modifier on 83 a top-level message is not allowed as per RFC 3501. 84 */ 85 OFFSET_MIME=3, 86 /** @short Obtain the raw data without any kind of Content-Transfer-Encoding decoding */ 87 OFFSET_RAW_CONTENTS = 4 88 } PartModifier; 89 90 protected: 91 static const intptr_t TagMask = 0x3; 92 static const intptr_t PointerMask = ~TagMask; 93 union { 94 TreeItem *m_parent; 95 intptr_t m_parentAsBits; 96 }; 97 TreeItemChildrenList m_children; 98 accessFetchStatus()99 FetchingState accessFetchStatus() const 100 { 101 return static_cast<FetchingState>(m_parentAsBits & TagMask); 102 } setFetchStatus(const FetchingState fetchStatus)103 void setFetchStatus(const FetchingState fetchStatus) 104 { 105 m_parentAsBits = reinterpret_cast<intptr_t>(parent()) | fetchStatus; 106 } 107 public: 108 explicit TreeItem(TreeItem *parent); parent()109 TreeItem *parent() const 110 { 111 return reinterpret_cast<TreeItem *>(m_parentAsBits & PointerMask); 112 } 113 virtual int row() const; 114 115 virtual ~TreeItem(); 116 virtual unsigned int childrenCount(Model *const model); 117 virtual TreeItem *child(const int offset, Model *const model); 118 virtual TreeItemChildrenList setChildren(const TreeItemChildrenList &items); 119 virtual void fetch(Model *const model) = 0; 120 virtual unsigned int rowCount(Model *const model) = 0; 121 virtual unsigned int columnCount(); 122 virtual QVariant data(Model *const model, int role) = 0; 123 virtual bool hasChildren(Model *const model) = 0; fetched()124 virtual bool fetched() const { return accessFetchStatus() == DONE; } loading()125 virtual bool loading() const { return accessFetchStatus() == LOADING; } 126 virtual bool isUnavailable() const; 127 virtual TreeItem *specialColumnPtr(int row, int column) const; 128 virtual QModelIndex toIndex(Model *const model) const; 129 }; 130 131 class TreeItemPart; 132 class TreeItemMessage; 133 134 class TreeItemMailbox: public TreeItem 135 { 136 void operator=(const TreeItem &); // don't implement 137 MailboxMetadata m_metadata; 138 friend class Model; // needs access to maintianingTask 139 friend class MailboxModel; 140 friend class DeleteMailboxTask; // for direct access to maintainingTask 141 friend class KeepMailboxOpenTask; // needs access to maintainingTask 142 friend class SubscribeUnsubscribeTask; // needs access to m_metadata.flags 143 static QLatin1String flagNoInferiors; 144 static QLatin1String flagHasNoChildren; 145 static QLatin1String flagHasChildren; 146 public: 147 explicit TreeItemMailbox(TreeItem *parent); 148 TreeItemMailbox(TreeItem *parent, Responses::List); 149 ~TreeItemMailbox(); 150 151 static TreeItemMailbox *fromMetadata(TreeItem *parent, const MailboxMetadata &metadata); 152 153 virtual TreeItemChildrenList setChildren(const TreeItemChildrenList &items); 154 virtual void fetch(Model *const model); 155 virtual void fetchWithCacheControl(Model *const model, bool forceReload); 156 virtual unsigned int rowCount(Model *const model); 157 virtual QVariant data(Model *const model, int role); 158 virtual bool hasChildren(Model *const model); 159 virtual TreeItem *child(const int offset, Model *const model); 160 161 SyncState syncState; 162 163 /** @short Returns true if this mailbox has child mailboxes 164 165 This function might access the network if the answer can't be decided, for example on basis of mailbox flags. 166 */ 167 bool hasChildMailboxes(Model *const model); 168 /** @short Return true if the mailbox is already known to not have any child mailboxes 169 170 No network activity will be caused. If the answer is not known for sure, we return false (meaning "don't know"). 171 */ 172 bool hasNoChildMailboxesAlreadyKnown(); 173 mailbox()174 QString mailbox() const { return m_metadata.mailbox; } separator()175 QString separator() const { return m_metadata.separator; } mailboxMetadata()176 const MailboxMetadata &mailboxMetadata() const { return m_metadata; } 177 /** @short Update internal tree with the results of a FETCH response 178 179 If \a changedPart is not null, it will be updated to point to the message 180 part whose content got fetched. 181 */ 182 void handleFetchResponse(Model *const model, 183 const Responses::Fetch &response, 184 QList<TreeItemPart *> &changedParts, 185 TreeItemMessage *&changedMessage, 186 bool usingQresync); 187 void rescanForChildMailboxes(Model *const model); 188 void handleExpunge(Model *const model, const Responses::NumberResponse &resp); 189 void handleExists(Model *const model, const Responses::NumberResponse &resp); 190 void handleVanished(Model *const model, const Responses::Vanished &resp); 191 bool isSelectable() const; 192 193 void saveSyncStateAndUids(Model *model); 194 195 private: 196 TreeItemPart *partIdToPtr(Model *model, TreeItemMessage *message, const QByteArray &msgId); 197 198 /** @short ImapTask which is currently responsible for well-being of this mailbox */ 199 QPointer<KeepMailboxOpenTask> maintainingTask; 200 }; 201 202 class TreeItemMsgList: public TreeItem 203 { 204 void operator=(const TreeItem &); // don't implement 205 friend class TreeItemMailbox; 206 friend class TreeItemMessage; // for maintaining the m_unreadMessageCount 207 friend class Model; 208 friend class ObtainSynchronizedMailboxTask; 209 friend class KeepMailboxOpenTask; 210 FetchingState m_numberFetchingStatus; 211 int m_totalMessageCount; 212 int m_unreadMessageCount; 213 int m_recentMessageCount; 214 public: 215 explicit TreeItemMsgList(TreeItem *parent); 216 217 virtual void fetch(Model *const model); 218 virtual unsigned int rowCount(Model *const model); 219 virtual QVariant data(Model *const model, int role); 220 virtual bool hasChildren(Model *const model); 221 222 int totalMessageCount(Model *const model); 223 int unreadMessageCount(Model *const model); 224 int recentMessageCount(Model *const model); 225 void fetchNumbers(Model *const model); 226 void recalcVariousMessageCounts(Model *model); 227 void recalcVariousMessageCountsOnExpunge(Model *model, TreeItemMessage *expungedMessage); 228 void resetWasUnreadState(); 229 bool numbersFetched() const; 230 }; 231 232 class MessageDataPayload 233 { 234 public: 235 MessageDataPayload(); 236 237 const Message::Envelope &envelope() const; 238 void setEnvelope(const Message::Envelope &envelope); 239 const QDateTime &internalDate() const; 240 void setInternalDate(const QDateTime &internalDate); 241 quint64 size() const; 242 void setSize(const quint64 size); 243 const QList<QByteArray> &hdrReferences() const; 244 void setHdrReferences(const QList<QByteArray> &hdrReferences); 245 const QList<QUrl> &hdrListPost() const; 246 void setHdrListPost(const QList<QUrl> &hdrListPost); 247 bool hdrListPostNo() const; 248 void setHdrListPostNo(const bool hdrListPostNo); 249 const QByteArray &rememberedBodyStructure() const; 250 void setRememberedBodyStructure(const QByteArray &blob); 251 252 TreeItemPart *partHeader() const; 253 void setPartHeader(std::unique_ptr<TreeItemPart> part); 254 TreeItemPart *partText() const; 255 void setPartText(std::unique_ptr<TreeItemPart> part); 256 257 bool isComplete() const; 258 259 bool gotEnvelope() const; 260 bool gotInternalDate() const; 261 bool gotSize() const; 262 bool gotHdrReferences() const; 263 bool gotHdrListPost() const; 264 bool gotRemeberedBodyStructure() const; 265 266 private: 267 Message::Envelope m_envelope; 268 QDateTime m_internalDate; 269 quint64 m_size; 270 QList<QByteArray> m_hdrReferences; 271 QList<QUrl> m_hdrListPost; 272 QByteArray m_rememberedBodyStructure; 273 bool m_hdrListPostNo; 274 std::unique_ptr<TreeItemPart> m_partHeader; 275 std::unique_ptr<TreeItemPart> m_partText; 276 277 bool m_gotEnvelope : 1; 278 bool m_gotInternalDate : 1; 279 bool m_gotSize : 1; 280 bool m_gotBodystructure : 1; 281 bool m_gotHdrReferences : 1; 282 bool m_gotHdrListPost : 1; 283 }; 284 285 class TreeItemMessage: public TreeItem 286 { 287 void operator=(const TreeItem &); // don't implement 288 friend class TreeItemMailbox; 289 friend class TreeItemMsgList; 290 friend class Model; 291 friend class ObtainSynchronizedMailboxTask; // needs access to m_offset 292 friend class KeepMailboxOpenTask; // needs access to m_offset 293 friend class UpdateFlagsTask; // needs access to m_flags 294 friend class UpdateFlagsOfAllMessagesTask; // needs access to m_flags 295 int m_offset; 296 uint m_uid; 297 mutable MessageDataPayload *m_data; 298 QStringList m_flags; 299 bool m_flagsHandled; 300 bool m_wasUnread; 301 /** @short Set FLAGS and maintain the unread message counter */ 302 void setFlags(TreeItemMsgList *list, const QStringList &flags); 303 void processAdditionalHeaders(Model *model, const QByteArray &rawHeaders); 304 static bool hasNestedAttachments(Model *const model, TreeItemPart *part); 305 data()306 MessageDataPayload *data() const 307 { 308 return m_data ? m_data : (m_data = new MessageDataPayload()); 309 } 310 311 public: 312 explicit TreeItemMessage(TreeItem *parent); 313 ~TreeItemMessage(); 314 315 virtual int row() const; 316 virtual void fetch(Model *const model); 317 virtual unsigned int rowCount(Model *const model); 318 virtual unsigned int columnCount(); 319 virtual QVariant data(Model *const model, int role); hasChildren(Model * const model)320 virtual bool hasChildren(Model *const model) { Q_UNUSED(model); return true; } 321 virtual TreeItemChildrenList setChildren(const TreeItemChildrenList &items); 322 Message::Envelope envelope(Model *const model); 323 QDateTime internalDate(Model *const model); 324 quint64 size(Model *const model); 325 bool isMarkedAsDeleted() const; 326 bool isMarkedAsRead() const; 327 bool isMarkedAsReplied() const; 328 bool isMarkedAsForwarded() const; 329 bool isMarkedAsRecent() const; 330 bool isMarkedAsFlagged() const; 331 bool isMarkedAsJunk() const; 332 bool isMarkedAsNotJunk() const; 333 void checkFlagsReadRecent(bool &isRead, bool &isRecent) const; 334 uint uid() const; 335 virtual TreeItem *specialColumnPtr(int row, int column) const; 336 bool hasAttachments(Model *const model); 337 338 static QVariantList addresListToQVariant(const QList<Imap::Message::MailAddress> &addressList); 339 }; 340 341 class TreeItemPart: public TreeItem 342 { 343 void operator=(const TreeItem &); // don't implement 344 friend class TreeItemMailbox; // needs access to m_data 345 friend class Model; // dtto 346 QByteArray m_mimeType; 347 QByteArray m_charset; 348 QByteArray m_contentFormat; 349 QByteArray m_delSp; 350 QByteArray m_encoding; 351 QByteArray m_data; 352 QByteArray m_bodyFldId; 353 QByteArray m_bodyDisposition; 354 QString m_fileName; 355 quint64 m_octets; 356 QByteArray m_multipartRelatedStartPart; 357 Imap::Message::AbstractMessage::bodyFldParam_t m_bodyFldParam; 358 mutable TreeItemPart *m_partMime; 359 mutable TreeItemPart *m_partRaw; 360 public: 361 TreeItemPart(TreeItem *parent, const QByteArray &mimeType); 362 ~TreeItemPart(); 363 364 virtual unsigned int childrenCount(Model *const model); 365 virtual TreeItem *child(const int offset, Model *const model); 366 virtual TreeItemChildrenList setChildren(const TreeItemChildrenList &items); 367 368 virtual void fetchFromCache(Model *const model); 369 virtual void fetch(Model *const model); 370 virtual unsigned int rowCount(Model *const model); 371 virtual unsigned int columnCount(); 372 virtual QVariant data(Model *const model, int role); 373 virtual bool hasChildren(Model *const model); 374 375 virtual QByteArray partId() const; 376 377 /** @short Shall we use RFC3516 BINARY for fetching message parts or not */ 378 typedef enum { 379 /** @short Use the baseline IMAP feature, the BODY[...], from RFC 3501 */ 380 FETCH_PART_IMAP, 381 /** @short Fetch via the RFC3516's BINARY extension */ 382 FETCH_PART_BINARY 383 } PartFetchingMode; 384 385 virtual QByteArray partIdForFetch(const PartFetchingMode fetchingMode) const; 386 virtual QByteArray pathToPart() const; 387 TreeItemMessage *message() const; 388 389 /** @short Provide access to the internal buffer holding data 390 391 It is safe to access the obtained pointer as long as this object is not 392 deleted. This function violates the classic concept of object 393 encapsulation, but is really useful for the implementation of 394 Imap::Network::MsgPartNetworkReply. 395 */ 396 QByteArray *dataPtr(); mimeType()397 QByteArray mimeType() const { return m_mimeType; } charset()398 QByteArray charset() const { return m_charset; } setCharset(const QByteArray & ch)399 void setCharset(const QByteArray &ch) { m_charset = ch; } setContentFormat(const QByteArray & format)400 void setContentFormat(const QByteArray &format) { m_contentFormat = format; } setContentDelSp(const QByteArray & delSp)401 void setContentDelSp(const QByteArray &delSp) { m_delSp = delSp; } setEncoding(const QByteArray & encoding)402 void setEncoding(const QByteArray &encoding) { m_encoding = encoding; } encoding()403 QByteArray encoding() const { return m_encoding; } setBodyFldId(const QByteArray & id)404 void setBodyFldId(const QByteArray &id) { m_bodyFldId = id; } bodyFldId()405 QByteArray bodyFldId() const { return m_bodyFldId; } setBodyDisposition(const QByteArray & disposition)406 void setBodyDisposition(const QByteArray &disposition) { m_bodyDisposition = disposition; } bodyDisposition()407 QByteArray bodyDisposition() const { return m_bodyDisposition; } setFileName(const QString & name)408 void setFileName(const QString &name) { m_fileName = name; } fileName()409 QString fileName() const { return m_fileName; } setOctets(const quint64 size)410 void setOctets(const quint64 size) { m_octets = size; } 411 /** @short Return the downloadable size of the message part */ octets()412 quint64 octets() const { return m_octets; } multipartRelatedStartPart()413 QByteArray multipartRelatedStartPart() const { return m_multipartRelatedStartPart; } setMultipartRelatedStartPart(const QByteArray & start)414 void setMultipartRelatedStartPart(const QByteArray &start) { m_multipartRelatedStartPart = start; } setBodyFldParam(const Imap::Message::AbstractMessage::bodyFldParam_t & bodyFldParam)415 void setBodyFldParam(const Imap::Message::AbstractMessage::bodyFldParam_t &bodyFldParam) { m_bodyFldParam = bodyFldParam; } bodyFldParam()416 Imap::Message::AbstractMessage::bodyFldParam_t bodyFldParam() const { return m_bodyFldParam; } 417 virtual TreeItem *specialColumnPtr(int row, int column) const; 418 virtual bool isTopLevelMultiPart() const; 419 420 virtual void silentlyReleaseMemoryRecursive(); 421 protected: 422 TreeItemPart(TreeItem *parent); 423 }; 424 425 /** @short A message part with a modifier 426 427 This item hanldes fetching of message parts with an attached modifier (like TEXT, HEADER or MIME). 428 */ 429 class TreeItemModifiedPart: public TreeItemPart 430 { 431 PartModifier m_modifier; 432 public: 433 TreeItemModifiedPart(TreeItem *parent, const PartModifier kind); 434 virtual int row() const; 435 virtual unsigned int columnCount(); 436 virtual QByteArray partId() const; 437 virtual QByteArray pathToPart() const; 438 virtual TreeItem *specialColumnPtr(int row, int column) const; 439 PartModifier kind() const; 440 virtual QModelIndex toIndex(Model *const model) const; 441 virtual QByteArray partIdForFetch(const PartFetchingMode fetchingMode) const; 442 protected: 443 virtual bool isTopLevelMultiPart() const; 444 private: 445 QByteArray modifierToByteArray() const; 446 }; 447 448 /** @short Specialization of TreeItemPart for parts holding a multipart/message */ 449 class TreeItemPartMultipartMessage: public TreeItemPart 450 { 451 Message::Envelope m_envelope; 452 mutable TreeItemPart *m_partHeader; 453 mutable TreeItemPart *m_partText; 454 public: 455 TreeItemPartMultipartMessage(TreeItem *parent, const Message::Envelope &envelope); 456 virtual ~TreeItemPartMultipartMessage(); 457 virtual QVariant data(Model * const model, int role); 458 virtual TreeItem *specialColumnPtr(int row, int column) const; 459 virtual void silentlyReleaseMemoryRecursive(); 460 }; 461 462 } 463 464 } 465 466 Q_DECLARE_METATYPE(QByteArray*) 467 468 #endif // IMAP_MAILBOXTREE_H 469