diff options
Diffstat (limited to 'comm/mailnews/imap/src/nsImapBodyShell.h')
-rw-r--r-- | comm/mailnews/imap/src/nsImapBodyShell.h | 357 |
1 files changed, 357 insertions, 0 deletions
diff --git a/comm/mailnews/imap/src/nsImapBodyShell.h b/comm/mailnews/imap/src/nsImapBodyShell.h new file mode 100644 index 0000000000..c2ab8c5898 --- /dev/null +++ b/comm/mailnews/imap/src/nsImapBodyShell.h @@ -0,0 +1,357 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* +nsImapBodyShell and associated classes +*/ + +#ifndef IMAPBODY_H +#define IMAPBODY_H + +#include "mozilla/Attributes.h" +#include "nsImapCore.h" +#include "nsString.h" +#include "nsRefPtrHashtable.h" +#include "nsTArray.h" + +class nsImapProtocol; + +typedef enum _nsIMAPBodypartType { + IMAP_BODY_MESSAGE_RFC822, + IMAP_BODY_MESSAGE_HEADER, + IMAP_BODY_LEAF, + IMAP_BODY_MULTIPART +} nsIMAPBodypartType; + +class nsImapBodyShell; +class nsIMAPBodypartMessage; + +class nsIMAPBodypart { + public: + // Construction + virtual bool GetIsValid() { return m_isValid; } + virtual void SetIsValid(bool valid); + virtual nsIMAPBodypartType GetType() = 0; + + // Generation + // Generates an HTML representation of this part. Returns content length + // generated, -1 if failed. + virtual int32_t Generate(nsImapBodyShell* aShell, nsImapProtocol* conn, + bool /*stream*/, bool /* prefetch */) { + return -1; + } + virtual void AdoptPartDataBuffer( + char* buf); // Adopts storage for part data buffer. If NULL, sets + // isValid to false. + virtual void AdoptHeaderDataBuffer( + char* buf); // Adopts storage for header data buffer. If NULL, sets + // isValid to false. + virtual bool ShouldFetchInline(nsImapBodyShell* aShell) { + return true; + } // returns true if this part should be fetched inline for generation. + virtual bool PreflightCheckAllInline(nsImapBodyShell* aShell) { return true; } + + virtual bool ShouldExplicitlyFetchInline(); + virtual bool ShouldExplicitlyNotFetchInline(); + virtual bool IsLastTextPart(const char* partNumberString) { return true; } + + protected: + // If stream is false, simply returns the content length that will be + // generated the body of the part itself + virtual int32_t GeneratePart(nsImapBodyShell* aShell, nsImapProtocol* conn, + bool stream, bool prefetch); + // the MIME headers of the part + virtual int32_t GenerateMIMEHeader(nsImapBodyShell* aShell, + nsImapProtocol* conn, bool stream, + bool prefetch); + // Generates the MIME boundary wrapper for this part. + virtual int32_t GenerateBoundary(nsImapBodyShell* aShell, + nsImapProtocol* conn, bool stream, + bool prefetch, bool lastBoundary); + // lastBoundary indicates whether or not this should be the boundary for the + // final MIME part of the multipart message. + // Generates (possibly empty) filling for a part that won't be filled in + // inline. + virtual int32_t GenerateEmptyFilling(nsImapBodyShell* aShell, + nsImapProtocol* conn, bool stream, + bool prefetch); + + // Part Numbers / Hierarchy + public: + virtual char* GetPartNumberString() { return m_partNumberString; } + virtual nsIMAPBodypart* FindPartWithNumber( + const char* partNum); // Returns the part object with the given number + virtual nsIMAPBodypart* GetParentPart() { + return m_parentPart; + } // Returns the parent of this part. + // We will define a part of type message/rfc822 to be the + // parent of its body and header. + // A multipart is a parent of its child parts. + // All other leafs do not have children. + + // Other / Helpers + public: + virtual ~nsIMAPBodypart(); + virtual nsIMAPBodypartMessage* GetnsIMAPBodypartMessage() { return NULL; } + + const char* GetBodyType() { return m_bodyType; } + const char* GetBodySubType() { return m_bodySubType; } + void SetBoundaryData(char* boundaryData) { m_boundaryData = boundaryData; } + + protected: + virtual void QueuePrefetchMIMEHeader(nsImapBodyShell* aShell); + // virtual void PrefetchMIMEHeader(); // Initiates a prefetch for the MIME + // header of this part. + nsIMAPBodypart(char* partNumber, nsIMAPBodypart* parentPart); + + protected: + bool m_isValid; // If this part is valid. + char* m_partNumberString; // string representation of this part's + // full-hierarchy number. Define 0 to be the + // top-level message + char* m_partData; // data for this part. NULL if not filled in yet. + char* m_headerData; // data for this part's MIME header. NULL if not filled + // in yet. + char* m_boundaryData; // MIME boundary for this part + int32_t m_partLength; + int32_t m_contentLength; // Total content length which will be Generate()'d. + // -1 if not filled in yet. + nsIMAPBodypart* m_parentPart; // Parent of this part + + // Fields - Filled in from parsed BODYSTRUCTURE response (as well as others) + char* m_contentType; // constructed from m_bodyType and m_bodySubType + char* m_bodyType; + char* m_bodySubType; + char* m_bodyID; + char* m_bodyDescription; + char* m_bodyEncoding; + // we ignore extension data for now +}; + +// Message headers +// A special type of nsIMAPBodypart +// These may be headers for the top-level message, +// or any body part of type message/rfc822. +class nsIMAPMessageHeaders : public nsIMAPBodypart { + public: + nsIMAPMessageHeaders(char* partNum, nsIMAPBodypart* parentPart); + virtual nsIMAPBodypartType GetType() override; + // Generates an HTML representation of this part. Returns content length + // generated, -1 if failed. + virtual int32_t Generate(nsImapBodyShell* aShell, nsImapProtocol* conn, + bool stream, bool prefetch) override; + virtual bool ShouldFetchInline(nsImapBodyShell* aShell) override; + virtual void QueuePrefetchMessageHeaders(nsImapBodyShell* aShell); +}; + +class nsIMAPBodypartMultipart : public nsIMAPBodypart { + public: + nsIMAPBodypartMultipart(char* partNum, nsIMAPBodypart* parentPart); + virtual nsIMAPBodypartType GetType() override; + virtual ~nsIMAPBodypartMultipart(); + virtual bool ShouldFetchInline(nsImapBodyShell* aShell) override; + virtual bool PreflightCheckAllInline(nsImapBodyShell* aShell) override; + // Generates an HTML representation of this part. Returns content length + // generated, -1 if failed. + virtual int32_t Generate(nsImapBodyShell* aShell, nsImapProtocol* conn, + bool stream, bool prefetch) override; + // Returns the part object with the given number + virtual nsIMAPBodypart* FindPartWithNumber(const char* partNum) override; + virtual bool IsLastTextPart(const char* partNumberString) override; + void AppendPart(nsIMAPBodypart* part) { m_partList.AppendElement(part); } + void SetBodySubType(char* bodySubType); + + protected: + // An ordered list of top-level body parts for this shell + nsTArray<nsIMAPBodypart*> m_partList; +}; + +// The name "leaf" is somewhat misleading, since a part of type message/rfc822 +// is technically a leaf, even though it can contain other parts within it. +class nsIMAPBodypartLeaf : public nsIMAPBodypart { + public: + nsIMAPBodypartLeaf(char* partNum, nsIMAPBodypart* parentPart, char* bodyType, + char* bodySubType, char* bodyID, char* bodyDescription, + char* bodyEncoding, int32_t partLength, + bool preferPlainText); + virtual nsIMAPBodypartType GetType() override; + // Generates an HTML representation of this part. Returns content length + // generated, -1 if failed. + virtual int32_t Generate(nsImapBodyShell* aShell, nsImapProtocol* conn, + bool stream, bool prefetch) override; + // returns true if this part should be fetched inline for generation. + virtual bool ShouldFetchInline(nsImapBodyShell* aShell) override; + virtual bool PreflightCheckAllInline(nsImapBodyShell* aShell) override; + + private: + bool mPreferPlainText; +}; + +class nsIMAPBodypartMessage : public nsIMAPBodypartLeaf { + public: + nsIMAPBodypartMessage(char* partNum, nsIMAPBodypart* parentPart, + bool topLevelMessage, char* bodyType, char* bodySubType, + char* bodyID, char* bodyDescription, char* bodyEncoding, + int32_t partLength, bool preferPlainText); + void SetBody(nsIMAPBodypart* body); + virtual nsIMAPBodypartType GetType() override; + virtual ~nsIMAPBodypartMessage(); + virtual int32_t Generate(nsImapBodyShell* aShell, nsImapProtocol* conn, + bool stream, bool prefetch) override; + virtual bool ShouldFetchInline(nsImapBodyShell* aShell) override; + virtual bool PreflightCheckAllInline(nsImapBodyShell* aShell) override; + // Returns the part object with the given number + virtual nsIMAPBodypart* FindPartWithNumber(const char* partNum) override; + void AdoptMessageHeaders( + char* headers); // Fills in buffer (and adopts storage) for header object + // partNum specifies the message part number to which the + // headers correspond. NULL indicates the top-level + // message + virtual nsIMAPBodypartMessage* GetnsIMAPBodypartMessage() override { + return this; + } + virtual bool GetIsTopLevelMessage() { return m_topLevelMessage; } + + protected: + nsIMAPMessageHeaders* m_headers; // Every body shell should have headers + nsIMAPBodypart* m_body; + bool m_topLevelMessage; // Whether or not this is the top-level message +}; + +// MessagePartID and an array of them are used for pipelining prefetches. + +class nsIMAPMessagePartID { + public: + nsIMAPMessagePartID(nsIMAPeFetchFields fields, const char* partNumberString); + nsIMAPeFetchFields GetFields() { return m_fields; } + const char* GetPartNumberString() { return m_partNumberString; } + + protected: + const char* m_partNumberString; + nsIMAPeFetchFields m_fields; +}; + +// We will refer to a Body "Shell" as a hierarchical object representation of a +// parsed BODYSTRUCTURE response. A shell contains representations of Shell +// "Parts." A Body Shell can undergo essentially two operations: Construction +// and Generation. Shell Construction occurs from a parsed a BODYSTRUCTURE +// response, split into empty parts. Shell Generation generates a "MIME Shell" +// of the message and streams it to libmime for display. The MIME Shell has +// selected (inline) parts filled in, and leaves all others for on-demand +// retrieval through explicit part fetches. + +class nsImapBodyShell : public nsISupports { + public: + NS_DECL_THREADSAFE_ISUPPORTS + nsImapBodyShell(nsIMAPBodypartMessage* message, uint32_t UID, + uint32_t UIDValidity, const char* folderName, + bool showAttachmentsInline); + // To be used after a shell is uncached + bool GetIsValid() { return m_isValid; } + void SetIsValid(bool valid); + + // Prefetch + // Adds a message body part to the queue to be prefetched + // in a single, pipelined command + void AddPrefetchToQueue(nsIMAPeFetchFields, const char* partNum); + // Fills in buffer (and adopts storage) for header object + // partNum specifies the message part number to which the + // headers correspond. NULL indicates the top-level message + void AdoptMessageHeaders(char* headers, const char* partNum); + // Fills in buffer (and adopts storage) for MIME headers in appropriate + // object. If object can't be found, sets isValid to false. + void AdoptMimeHeader(const char* partNum, char* mimeHeader); + + // Generation + // Streams out an HTML representation of this IMAP message, going along and + // fetching parts it thinks it needs, and leaving empty shells for the parts + // it doesn't. + // Returns number of bytes generated, or -1 if invalid. + // If partNum is not NULL, then this works to generates a MIME part that + // hasn't been downloaded yet and leaves out all other parts. By default, to + // generate a normal message, partNum should be NULL. + int32_t Generate(nsImapProtocol* conn, char* partNum); + + // Returns TRUE if the user has the pref "Show Attachments Inline" set. + // Returns FALSE if the setting is "Show Attachments as Links" + bool GetShowAttachmentsInline(); + // Returns true if all parts are inline, false otherwise. Does not generate + // anything. + bool PreflightCheckAllInline(); + + // Helpers + nsCString& GetUID() { return m_UID; } + nsCString& GetUID_validity() { return m_UID_validity; } + nsCString const& GetFolderName() const { return m_folderName; } + char* GetGeneratingPart() { return m_generatingPart; } + // Returns true if this is in the process of being generated, + // so we don't re-enter + bool IsBeingGenerated() { return m_isBeingGenerated; } + bool IsShellCached() { return m_cached; } + void SetIsCached(bool isCached) { m_cached = isCached; } + bool GetGeneratingWholeMessage() { return m_generatingWholeMessage; } + IMAP_ContentModifiedType GetContentModified() { return m_contentModified; } + + protected: + virtual ~nsImapBodyShell(); + + nsIMAPBodypartMessage* m_message; + + // Array of pipelined part prefetches. + nsTArray<nsIMAPMessagePartID> m_prefetchQueue; + + bool m_isValid; + nsCString m_UID; // UID of this message + nsCString m_UID_validity; // appended UID and UID-validity of this message + nsCString m_folderName; // folder that contains this message + char* m_generatingPart; // If a specific part is being generated, this is it. + // Otherwise, NULL. + bool m_isBeingGenerated; // true if this body shell is in the process of + // being generated + bool m_cached; // Whether or not this shell is cached + bool m_generatingWholeMessage; // whether or not we are generating the whole + // (non-MPOD) message Set to false if we are + // generating by parts + // under what conditions the content has been modified. + // Either IMAP_CONTENT_MODIFIED_VIEW_INLINE or + // IMAP_CONTENT_MODIFIED_VIEW_AS_LINKS + IMAP_ContentModifiedType m_contentModified; +}; + +// This class caches shells, so we don't have to always go and re-fetch them. +// This does not cache any of the filled-in inline parts; those are cached +// individually in the libnet memory cache. (ugh, how will we do that?) Since +// we'll only be retrieving shells for messages over a given size, and since the +// shells themselves won't be very large, this cache will not grow very big +// (relatively) and should handle most common usage scenarios. + +// A body cache is associated with a given host, spanning folders, so +// it uses both UID and UIDVALIDITY . + +class nsImapBodyShellCache { + public: + nsImapBodyShellCache(); + + // Adds shell to cache, possibly ejecting + // another entry based on scheme in EjectEntry(). + void AddShellToCache(nsImapBodyShell* shell); + // Looks up a shell in the cache given the message's UID. + nsImapBodyShell* FindShellForUID(nsACString const& UID, + nsACString const& mailboxName, + IMAP_ContentModifiedType modType); + void Clear(); + + protected: + static constexpr int kMaxEntries = 20; + // Chooses an entry to eject; deletes that entry; and ejects it from the + // cache, clearing up a new space. + void EjectEntry(); + + nsTArray<nsImapBodyShell*> m_shellList; + // For quick lookup based on UID + nsRefPtrHashtable<nsCStringHashKey, nsImapBodyShell> m_shellHash; +}; + +#endif // IMAPBODY_H |