summaryrefslogtreecommitdiff
path: root/mailnews/imap/src/nsIMAPBodyShell.h
blob: 1c8d58ae50dad3a47223921ede0ed75f201fa6f9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
/* -*- 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 "nsStringGlue.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, 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, bool stream, bool prefetch);
    // the MIME headers of the part
    virtual int32_t GenerateMIMEHeader(nsIMAPBodyShell *aShell, bool stream, bool prefetch); 
    // Generates the MIME boundary wrapper for this part.
    virtual int32_t GenerateBoundary(nsIMAPBodyShell *aShell, 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, 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, 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, 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:
    nsTArray<nsIMAPBodypart*>  *m_partList;  // An ordered list of top-level body parts for this shell
};


// 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, 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, 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

};


class nsIMAPMessagePartIDArray;

// 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(nsImapProtocol *protocolConnection,
                  nsIMAPBodypartMessage *message, uint32_t UID,
                  const char *folderName);
  // To be used after a shell is uncached
  void SetConnection(nsImapProtocol *con) { m_protocolConnection = con; }
  virtual bool GetIsValid() { return m_isValid; }
  virtual 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);
  // Runs a single pipelined command which fetches all of the
  // elements in the prefetch queue
  void FlushPrefetchQueue();
  // 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.
  virtual int32_t Generate(char *partNum);

  // Returns TRUE if the user has the pref "Show Attachments Inline" set.
  // Returns FALSE if the setting is "Show Attachments as Links"
  virtual bool GetShowAttachmentsInline();
  // Returns true if all parts are inline, false otherwise. Does not generate anything.
  bool PreflightCheckAllInline();

  // Helpers
  nsImapProtocol *GetConnection() { return m_protocolConnection; }
  bool GetPseudoInterrupted();
  bool DeathSignalReceived();
  nsCString &GetUID() { return m_UID; }
  const char *GetFolderName() { 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; }
  void SetContentModified(IMAP_ContentModifiedType modType) { m_contentModified = modType; }
protected:
  virtual ~nsIMAPBodyShell();

  nsIMAPBodypartMessage *m_message;

  nsIMAPMessagePartIDArray        *m_prefetchQueue; // array of pipelined part prefetches.  Ok, so it's not really a queue.

  bool                            m_isValid;
  nsImapProtocol                  *m_protocolConnection;  // Connection, for filling in parts
  nsCString                       m_UID;                  // UID of this message
  char                            *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_gotAttachmentPref;    // Whether or not m_showAttachmentsInline has been initialized 
  bool                            m_showAttachmentsInline; // Whether or not we should display attachment inline
  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.
// It should pay attention to UIDVALIDITY.

class nsIMAPBodyShellCache
{
public:
  static nsIMAPBodyShellCache *Create();
  virtual ~nsIMAPBodyShellCache();

  // Adds shell to cache, possibly ejecting
  // another entry based on scheme in EjectEntry().
  bool AddShellToCache(nsIMAPBodyShell *shell);
  // Looks up a shell in the cache given the message's UID.
  nsIMAPBodyShell *FindShellForUID(nsCString &UID, const char *mailboxName,
                                   IMAP_ContentModifiedType modType);
  void Clear();

protected:
  nsIMAPBodyShellCache();
  // Chooses an entry to eject;  deletes that entry;  and ejects it from the
  // cache, clearing up a new space.  Returns true if it found an entry
  // to eject, false otherwise.
  bool EjectEntry();
  uint32_t GetSize() { return m_shellList->Length(); }
  uint32_t GetMaxSize() { return 20; }
  nsTArray<nsIMAPBodyShell*> *m_shellList; // For maintenance
  // For quick lookup based on UID
  nsRefPtrHashtable <nsCStringHashKey, nsIMAPBodyShell> m_shellHash;
};

// MessagePartID and MessagePartIDArray 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;
};


class nsIMAPMessagePartIDArray : public nsTArray<nsIMAPMessagePartID*> {
public:
  nsIMAPMessagePartIDArray();
  ~nsIMAPMessagePartIDArray();

  void RemoveAndFreeAll();
  uint32_t GetNumParts() { return Length(); }
  nsIMAPMessagePartID *GetPart(uint32_t i)
  {
    NS_ASSERTION(i < Length(), "invalid message part #");
    return ElementAt(i);
  }
};


#endif // IMAPBODY_H