1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* This Source Code Form is subject to the terms of the Mozilla Public 3 * License, v. 2.0. If a copy of the MPL was not distributed with this 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 5 6 /* 7 nsImapBodyShell and associated classes 8 */ 9 10 #ifndef IMAPBODY_H 11 #define IMAPBODY_H 12 13 #include "mozilla/Attributes.h" 14 #include "nsImapCore.h" 15 #include "nsString.h" 16 #include "nsRefPtrHashtable.h" 17 #include "nsTArray.h" 18 19 class nsImapProtocol; 20 21 typedef enum _nsIMAPBodypartType { 22 IMAP_BODY_MESSAGE_RFC822, 23 IMAP_BODY_MESSAGE_HEADER, 24 IMAP_BODY_LEAF, 25 IMAP_BODY_MULTIPART 26 } nsIMAPBodypartType; 27 28 class nsImapBodyShell; 29 class nsIMAPBodypartMessage; 30 31 class nsIMAPBodypart { 32 public: 33 // Construction GetIsValid()34 virtual bool GetIsValid() { return m_isValid; } 35 virtual void SetIsValid(bool valid); 36 virtual nsIMAPBodypartType GetType() = 0; 37 38 // Generation 39 // Generates an HTML representation of this part. Returns content length 40 // generated, -1 if failed. Generate(nsImapBodyShell * aShell,bool,bool)41 virtual int32_t Generate(nsImapBodyShell* aShell, bool /*stream*/, 42 bool /* prefetch */) { 43 return -1; 44 } 45 virtual void AdoptPartDataBuffer( 46 char* buf); // Adopts storage for part data buffer. If NULL, sets 47 // isValid to false. 48 virtual void AdoptHeaderDataBuffer( 49 char* buf); // Adopts storage for header data buffer. If NULL, sets 50 // isValid to false. ShouldFetchInline(nsImapBodyShell * aShell)51 virtual bool ShouldFetchInline(nsImapBodyShell* aShell) { 52 return true; 53 } // returns true if this part should be fetched inline for generation. PreflightCheckAllInline(nsImapBodyShell * aShell)54 virtual bool PreflightCheckAllInline(nsImapBodyShell* aShell) { return true; } 55 56 virtual bool ShouldExplicitlyFetchInline(); 57 virtual bool ShouldExplicitlyNotFetchInline(); IsLastTextPart(const char * partNumberString)58 virtual bool IsLastTextPart(const char* partNumberString) { return true; } 59 60 protected: 61 // If stream is false, simply returns the content length that will be 62 // generated the body of the part itself 63 virtual int32_t GeneratePart(nsImapBodyShell* aShell, bool stream, 64 bool prefetch); 65 // the MIME headers of the part 66 virtual int32_t GenerateMIMEHeader(nsImapBodyShell* aShell, bool stream, 67 bool prefetch); 68 // Generates the MIME boundary wrapper for this part. 69 virtual int32_t GenerateBoundary(nsImapBodyShell* aShell, bool stream, 70 bool prefetch, bool lastBoundary); 71 // lastBoundary indicates whether or not this should be the boundary for the 72 // final MIME part of the multipart message. 73 // Generates (possibly empty) filling for a part that won't be filled in 74 // inline. 75 virtual int32_t GenerateEmptyFilling(nsImapBodyShell* aShell, bool stream, 76 bool prefetch); 77 78 // Part Numbers / Hierarchy 79 public: GetPartNumberString()80 virtual char* GetPartNumberString() { return m_partNumberString; } 81 virtual nsIMAPBodypart* FindPartWithNumber( 82 const char* partNum); // Returns the part object with the given number GetParentPart()83 virtual nsIMAPBodypart* GetParentPart() { 84 return m_parentPart; 85 } // Returns the parent of this part. 86 // We will define a part of type message/rfc822 to be the 87 // parent of its body and header. 88 // A multipart is a parent of its child parts. 89 // All other leafs do not have children. 90 91 // Other / Helpers 92 public: 93 virtual ~nsIMAPBodypart(); GetnsIMAPBodypartMessage()94 virtual nsIMAPBodypartMessage* GetnsIMAPBodypartMessage() { return NULL; } 95 GetBodyType()96 const char* GetBodyType() { return m_bodyType; } GetBodySubType()97 const char* GetBodySubType() { return m_bodySubType; } SetBoundaryData(char * boundaryData)98 void SetBoundaryData(char* boundaryData) { m_boundaryData = boundaryData; } 99 100 protected: 101 virtual void QueuePrefetchMIMEHeader(nsImapBodyShell* aShell); 102 // virtual void PrefetchMIMEHeader(); // Initiates a prefetch for the MIME 103 // header of this part. 104 nsIMAPBodypart(char* partNumber, nsIMAPBodypart* parentPart); 105 106 protected: 107 bool m_isValid; // If this part is valid. 108 char* m_partNumberString; // string representation of this part's 109 // full-hierarchy number. Define 0 to be the 110 // top-level message 111 char* m_partData; // data for this part. NULL if not filled in yet. 112 char* m_headerData; // data for this part's MIME header. NULL if not filled 113 // in yet. 114 char* m_boundaryData; // MIME boundary for this part 115 int32_t m_partLength; 116 int32_t m_contentLength; // Total content length which will be Generate()'d. 117 // -1 if not filled in yet. 118 nsIMAPBodypart* m_parentPart; // Parent of this part 119 120 // Fields - Filled in from parsed BODYSTRUCTURE response (as well as others) 121 char* m_contentType; // constructed from m_bodyType and m_bodySubType 122 char* m_bodyType; 123 char* m_bodySubType; 124 char* m_bodyID; 125 char* m_bodyDescription; 126 char* m_bodyEncoding; 127 // we ignore extension data for now 128 }; 129 130 // Message headers 131 // A special type of nsIMAPBodypart 132 // These may be headers for the top-level message, 133 // or any body part of type message/rfc822. 134 class nsIMAPMessageHeaders : public nsIMAPBodypart { 135 public: 136 nsIMAPMessageHeaders(char* partNum, nsIMAPBodypart* parentPart); 137 virtual nsIMAPBodypartType GetType() override; 138 // Generates an HTML representation of this part. Returns content length 139 // generated, -1 if failed. 140 virtual int32_t Generate(nsImapBodyShell* aShell, bool stream, 141 bool prefetch) override; 142 virtual bool ShouldFetchInline(nsImapBodyShell* aShell) override; 143 virtual void QueuePrefetchMessageHeaders(nsImapBodyShell* aShell); 144 }; 145 146 class nsIMAPBodypartMultipart : public nsIMAPBodypart { 147 public: 148 nsIMAPBodypartMultipart(char* partNum, nsIMAPBodypart* parentPart); 149 virtual nsIMAPBodypartType GetType() override; 150 virtual ~nsIMAPBodypartMultipart(); 151 virtual bool ShouldFetchInline(nsImapBodyShell* aShell) override; 152 virtual bool PreflightCheckAllInline(nsImapBodyShell* aShell) override; 153 // Generates an HTML representation of this part. Returns content length 154 // generated, -1 if failed. 155 virtual int32_t Generate(nsImapBodyShell* aShell, bool stream, 156 bool prefetch) override; 157 // Returns the part object with the given number 158 virtual nsIMAPBodypart* FindPartWithNumber(const char* partNum) override; 159 virtual bool IsLastTextPart(const char* partNumberString) override; AppendPart(nsIMAPBodypart * part)160 void AppendPart(nsIMAPBodypart* part) { m_partList->AppendElement(part); } 161 void SetBodySubType(char* bodySubType); 162 163 protected: 164 nsTArray<nsIMAPBodypart*>* 165 m_partList; // An ordered list of top-level body parts for this shell 166 }; 167 168 // The name "leaf" is somewhat misleading, since a part of type message/rfc822 169 // is technically a leaf, even though it can contain other parts within it. 170 class nsIMAPBodypartLeaf : public nsIMAPBodypart { 171 public: 172 nsIMAPBodypartLeaf(char* partNum, nsIMAPBodypart* parentPart, char* bodyType, 173 char* bodySubType, char* bodyID, char* bodyDescription, 174 char* bodyEncoding, int32_t partLength, 175 bool preferPlainText); 176 virtual nsIMAPBodypartType GetType() override; 177 // Generates an HTML representation of this part. Returns content length 178 // generated, -1 if failed. 179 virtual int32_t Generate(nsImapBodyShell* aShell, bool stream, 180 bool prefetch) override; 181 // returns true if this part should be fetched inline for generation. 182 virtual bool ShouldFetchInline(nsImapBodyShell* aShell) override; 183 virtual bool PreflightCheckAllInline(nsImapBodyShell* aShell) override; 184 185 private: 186 bool mPreferPlainText; 187 }; 188 189 class nsIMAPBodypartMessage : public nsIMAPBodypartLeaf { 190 public: 191 nsIMAPBodypartMessage(char* partNum, nsIMAPBodypart* parentPart, 192 bool topLevelMessage, char* bodyType, char* bodySubType, 193 char* bodyID, char* bodyDescription, char* bodyEncoding, 194 int32_t partLength, bool preferPlainText); 195 void SetBody(nsIMAPBodypart* body); 196 virtual nsIMAPBodypartType GetType() override; 197 virtual ~nsIMAPBodypartMessage(); 198 virtual int32_t Generate(nsImapBodyShell* aShell, bool stream, 199 bool prefetch) override; 200 virtual bool ShouldFetchInline(nsImapBodyShell* aShell) override; 201 virtual bool PreflightCheckAllInline(nsImapBodyShell* aShell) override; 202 // Returns the part object with the given number 203 virtual nsIMAPBodypart* FindPartWithNumber(const char* partNum) override; 204 void AdoptMessageHeaders( 205 char* headers); // Fills in buffer (and adopts storage) for header object 206 // partNum specifies the message part number to which the 207 // headers correspond. NULL indicates the top-level 208 // message GetnsIMAPBodypartMessage()209 virtual nsIMAPBodypartMessage* GetnsIMAPBodypartMessage() override { 210 return this; 211 } GetIsTopLevelMessage()212 virtual bool GetIsTopLevelMessage() { return m_topLevelMessage; } 213 214 protected: 215 nsIMAPMessageHeaders* m_headers; // Every body shell should have headers 216 nsIMAPBodypart* m_body; 217 bool m_topLevelMessage; // Whether or not this is the top-level message 218 }; 219 220 // MessagePartID and an array of them are used for pipelining prefetches. 221 222 class nsIMAPMessagePartID { 223 public: 224 nsIMAPMessagePartID(nsIMAPeFetchFields fields, const char* partNumberString); GetFields()225 nsIMAPeFetchFields GetFields() { return m_fields; } GetPartNumberString()226 const char* GetPartNumberString() { return m_partNumberString; } 227 228 protected: 229 const char* m_partNumberString; 230 nsIMAPeFetchFields m_fields; 231 }; 232 233 // We will refer to a Body "Shell" as a hierarchical object representation of a 234 // parsed BODYSTRUCTURE response. A shell contains representations of Shell 235 // "Parts." A Body Shell can undergo essentially two operations: Construction 236 // and Generation. Shell Construction occurs from a parsed a BODYSTRUCTURE 237 // response, split into empty parts. Shell Generation generates a "MIME Shell" 238 // of the message and streams it to libmime for display. The MIME Shell has 239 // selected (inline) parts filled in, and leaves all others for on-demand 240 // retrieval through explicit part fetches. 241 242 class nsImapBodyShell : public nsISupports { 243 public: 244 NS_DECL_THREADSAFE_ISUPPORTS 245 nsImapBodyShell(nsImapProtocol* protocolConnection, 246 nsIMAPBodypartMessage* message, uint32_t UID, 247 uint32_t UIDValidity, const char* folderName); 248 // To be used after a shell is uncached SetConnection(nsImapProtocol * con)249 void SetConnection(nsImapProtocol* con) { m_protocolConnection = con; } GetIsValid()250 virtual bool GetIsValid() { return m_isValid; } 251 virtual void SetIsValid(bool valid); 252 253 // Prefetch 254 // Adds a message body part to the queue to be prefetched 255 // in a single, pipelined command 256 void AddPrefetchToQueue(nsIMAPeFetchFields, const char* partNum); 257 // Runs a single pipelined command which fetches all of the 258 // elements in the prefetch queue 259 void FlushPrefetchQueue(); 260 // Fills in buffer (and adopts storage) for header object 261 // partNum specifies the message part number to which the 262 // headers correspond. NULL indicates the top-level message 263 void AdoptMessageHeaders(char* headers, const char* partNum); 264 // Fills in buffer (and adopts storage) for MIME headers in appropriate 265 // object. If object can't be found, sets isValid to false. 266 void AdoptMimeHeader(const char* partNum, char* mimeHeader); 267 268 // Generation 269 // Streams out an HTML representation of this IMAP message, going along and 270 // fetching parts it thinks it needs, and leaving empty shells for the parts 271 // it doesn't. 272 // Returns number of bytes generated, or -1 if invalid. 273 // If partNum is not NULL, then this works to generates a MIME part that 274 // hasn't been downloaded yet and leaves out all other parts. By default, to 275 // generate a normal message, partNum should be NULL. 276 virtual int32_t Generate(char* partNum); 277 278 // Returns TRUE if the user has the pref "Show Attachments Inline" set. 279 // Returns FALSE if the setting is "Show Attachments as Links" 280 virtual bool GetShowAttachmentsInline(); 281 // Returns true if all parts are inline, false otherwise. Does not generate 282 // anything. 283 bool PreflightCheckAllInline(); 284 285 // Helpers GetConnection()286 nsImapProtocol* GetConnection() { return m_protocolConnection; } 287 bool GetPseudoInterrupted(); 288 bool DeathSignalReceived(); GetUID()289 nsCString& GetUID() { return m_UID; } GetUID_validity()290 nsCString& GetUID_validity() { return m_UID_validity; } GetFolderName()291 const char* GetFolderName() { return m_folderName; } GetGeneratingPart()292 char* GetGeneratingPart() { return m_generatingPart; } 293 // Returns true if this is in the process of being generated, 294 // so we don't re-enter IsBeingGenerated()295 bool IsBeingGenerated() { return m_isBeingGenerated; } IsShellCached()296 bool IsShellCached() { return m_cached; } SetIsCached(bool isCached)297 void SetIsCached(bool isCached) { m_cached = isCached; } GetGeneratingWholeMessage()298 bool GetGeneratingWholeMessage() { return m_generatingWholeMessage; } GetContentModified()299 IMAP_ContentModifiedType GetContentModified() { return m_contentModified; } SetContentModified(IMAP_ContentModifiedType modType)300 void SetContentModified(IMAP_ContentModifiedType modType) { 301 m_contentModified = modType; 302 } 303 304 protected: 305 virtual ~nsImapBodyShell(); 306 307 nsIMAPBodypartMessage* m_message; 308 309 nsTArray<nsIMAPMessagePartID> 310 m_prefetchQueue; // Array of pipelined part prefetches. 311 312 bool m_isValid; 313 nsImapProtocol* m_protocolConnection; // Connection, for filling in parts 314 nsCString m_UID; // UID of this message 315 nsCString m_UID_validity; // appended UID and UID-validity of this message 316 char* m_folderName; // folder that contains this message 317 char* m_generatingPart; // If a specific part is being generated, this is it. 318 // Otherwise, NULL. 319 bool m_isBeingGenerated; // true if this body shell is in the process of 320 // being generated 321 bool m_gotAttachmentPref; // Whether or not m_showAttachmentsInline has been 322 // initialized 323 bool m_showAttachmentsInline; // Whether or not we should display attachment 324 // inline 325 bool m_cached; // Whether or not this shell is cached 326 bool m_generatingWholeMessage; // whether or not we are generating the whole 327 // (non-MPOD) message Set to false if we are 328 // generating by parts 329 // under what conditions the content has been modified. 330 // Either IMAP_CONTENT_MODIFIED_VIEW_INLINE or 331 // IMAP_CONTENT_MODIFIED_VIEW_AS_LINKS 332 IMAP_ContentModifiedType m_contentModified; 333 }; 334 335 // This class caches shells, so we don't have to always go and re-fetch them. 336 // This does not cache any of the filled-in inline parts; those are cached 337 // individually in the libnet memory cache. (ugh, how will we do that?) Since 338 // we'll only be retrieving shells for messages over a given size, and since the 339 // shells themselves won't be very large, this cache will not grow very big 340 // (relatively) and should handle most common usage scenarios. 341 342 // A body cache is associated with a given host, spanning folders, so 343 // it uses both UID and UIDVALIDITY . 344 345 class nsImapBodyShellCache { 346 public: 347 static nsImapBodyShellCache* Create(); 348 virtual ~nsImapBodyShellCache(); 349 350 // Adds shell to cache, possibly ejecting 351 // another entry based on scheme in EjectEntry(). 352 bool AddShellToCache(nsImapBodyShell* shell); 353 // Looks up a shell in the cache given the message's UID. 354 nsImapBodyShell* FindShellForUID(nsCString& UID, const char* mailboxName, 355 IMAP_ContentModifiedType modType); 356 void Clear(); 357 358 protected: 359 nsImapBodyShellCache(); 360 // Chooses an entry to eject; deletes that entry; and ejects it from the 361 // cache, clearing up a new space. Returns true if it found an entry 362 // to eject, false otherwise. 363 bool EjectEntry(); GetSize()364 uint32_t GetSize() { return m_shellList->Length(); } GetMaxSize()365 uint32_t GetMaxSize() { return 20; } 366 nsTArray<nsImapBodyShell*>* m_shellList; // For maintenance 367 // For quick lookup based on UID 368 nsRefPtrHashtable<nsCStringHashKey, nsImapBodyShell> m_shellHash; 369 }; 370 371 #endif // IMAPBODY_H 372