summaryrefslogtreecommitdiffstats
path: root/comm/mailnews/imap/src/nsImapBodyShell.h
diff options
context:
space:
mode:
Diffstat (limited to 'comm/mailnews/imap/src/nsImapBodyShell.h')
-rw-r--r--comm/mailnews/imap/src/nsImapBodyShell.h357
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