summaryrefslogtreecommitdiffstats
path: root/comm/mailnews/mime/src/mimei.h
blob: d3a068422461eb284eb166ff37beb1bf32c40746 (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
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
/* -*- 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/. */

#ifndef _MIMEI_H_
#define _MIMEI_H_

/*
  This module, libmime, implements a general-purpose MIME parser.
  One of the methods provided by this parser is the ability to emit
  an HTML representation of it.

  All Mozilla-specific code is (and should remain) isolated in the
  file mimemoz.c.  Generally, if the code involves images, netlib
  streams it should be in mimemoz.c instead of in the main body of
  the MIME parser.

  The parser is object-oriented and fully buzzword-compliant.
  There is a class for each MIME type, and each class is responsible
  for parsing itself, and/or handing the input data off to one of its
  child objects.

  The class hierarchy is:

     MimeObject (abstract)
      |
      +--- MimeContainer (abstract)
      |     |
      |     +--- MimeMultipart (abstract)
      |     |     |
      |     |     +--- MimeMultipartMixed
      |     |     |
      |     |     +--- MimeMultipartDigest
      |     |     |
      |     |     +--- MimeMultipartParallel
      |     |     |
      |     |     +--- MimeMultipartAlternative
      |     |     |
      |     |     +--- MimeMultipartRelated
      |     |     |
      |     |     +--- MimeMultipartAppleDouble
      |     |     |
      |     |     +--- MimeSunAttachment
      |     |     |
      |     |     \--- MimeMultipartSigned (abstract)
      |     |          |
      |     |          \--- MimeMultipartSignedCMS
      |     |
      |     +--- MimeEncrypted (abstract)
      |     |     |
      |     |     \--- MimeEncryptedPKCS7
      |     |
      |     +--- MimeXlateed (abstract)
      |     |     |
      |     |     \--- MimeXlateed
      |     |
      |     +--- MimeMessage
      |     |
      |     \--- MimeUntypedText
      |
      +--- MimeLeaf (abstract)
      |     |
      |     +--- MimeInlineText (abstract)
      |     |     |
      |     |     +--- MimeInlineTextPlain
      |     |     |     |
      |     |     |     \--- MimeInlineTextHTMLAsPlaintext
      |     |     |
      |     |     +--- MimeInlineTextPlainFlowed
      |     |     |
      |     |     +--- MimeInlineTextHTML
      |     |     |     |
      |     |     |     +--- MimeInlineTextHTMLParsed
      |     |     |     |
      |     |     |     \--- MimeInlineTextHTMLSanitized
      |     |     |
      |     |     +--- MimeInlineTextRichtext
      |     |     |     |
      |     |     |     \--- MimeInlineTextEnriched
      |     |    |
      |     |    +--- MimeInlineTextVCard
      |     |
      |     +--- MimeInlineImage
      |     |
      |     \--- MimeExternalObject
      |
      \--- MimeExternalBody


  =========================================================================
  The definition of these classes is somewhat idiosyncratic, since I defined
  my own small object system, instead of giving the C++ virus another foothold.
  (I would have liked to have written this in Java, but our runtime isn't
  quite ready for prime time yet.)

  There is one header file and one source file for each class (for example,
  the MimeInlineText class is defined in "mimetext.h" and "mimetext.c".)
  Each header file follows the following boiler-plate form:

  TYPEDEFS: these come first to avoid circular dependencies.

      typedef struct FoobarClass FoobarClass;
      typedef struct Foobar      Foobar;

  CLASS DECLARATION:
  This structure defines the callback routines and other per-class data
  of the class defined in this module.

      struct FoobarClass {
        ParentClass superclass;
        ...any callbacks or class-variables...
      };

  CLASS DEFINITION:
  This variable holds an instance of the one-and-only class record; the
  various instances of this class point to this object.  (One interrogates
  the type of an instance by comparing the value of its class pointer with
  the address of this variable.)

      extern FoobarClass foobarClass;

  INSTANCE DECLARATION:
  This structure defines the per-instance data of an object, and a pointer
  to the corresponding class record.

      struct Foobar {
        Parent parent;
        ...any instance variables...
      };

  Then, in the corresponding .c file, the following structure is used:

  CLASS DEFINITION:
  First we pull in the appropriate include file (which includes all necessary
  include files for the parent classes) and then we define the class object
  using the MimeDefClass macro:

      #include "foobar.h"
      #define MIME_SUPERCLASS parentlClass
      MimeDefClass(Foobar, FoobarClass, foobarClass, &MIME_SUPERCLASS);

  The definition of MIME_SUPERCLASS is just to move most of the knowledge of the
  exact class hierarchy up to the file's header, instead of it being scattered
  through the various methods; see below.

  METHOD DECLARATIONS:
  We will be putting function pointers into the class object, so we declare
  them here.  They can generally all be static, since nobody outside of this
  file needs to reference them by name; all references to these routines should
  be through the class object.

      extern int FoobarMethod(Foobar *);
      ...etc...

  CLASS INITIALIZATION FUNCTION:
  The MimeDefClass macro expects us to define a function which will finish up
  any initialization of the class object that needs to happen before the first
  time it is instantiated.  Its name must be of the form "<class>Initialize",
  and it should initialize the various method slots in the class as
  appropriate.  Any methods or class variables which this class does not wish
  to override will be automatically inherited from the parent class (by virtue
  of its class-initialization function having been run first.)  Each class
  object will only be initialized once.

      static int
      FoobarClassInitialize(FoobarClass *class)
      {
        clazz->method = FoobarMethod.
        ...etc...
      }

  METHOD DEFINITIONS:
  Next come the definitions of the methods we referred to in the class-init
  function.  The way to access earlier methods (methods defined on the
  superclass) is to simply extract them from the superclass's object.
  But note that you CANNOT get at methods by indirecting through
  object->clazz->superclass: that will only work to one level, and will
  go into a loop if some subclass tries to continue on this method.

  The easiest way to do this is to make use of the MIME_SUPERCLASS macro that
  was defined at the top of the file, as shown below.  The alternative to that
  involves typing the literal name of the direct superclass of the class
  defined in this file, which will be a maintenance headache if the class
  hierarchy changes.  If you use the MIME_SUPERCLASS idiom, then a textual
  change is required in only one place if this class's superclass changes.

      static void
      Foobar_finalize (MimeObject *object)
      {
        ((MimeObjectClass*)&MIME_SUPERCLASS)->finalize(object);  //  RIGHT
        parentClass.whatnot.object.finalize(object);             //  (works...)
        object->clazz->superclass->finalize(object);             //  WRONG!!
      }

  If you write a libmime content type handler, libmime might create several
  instances of your class at once and call e.g. the same finalize code for
  3 different objects in a row.
 */

#include "mimehdrs.h"
#include "nsTArray.h"

typedef struct MimeObject MimeObject;
typedef struct MimeObjectClass MimeObjectClass;

/* (I don't pretend to understand this.) */
#define cpp_stringify_noop_helper(x) #x
#define cpp_stringify(x) cpp_stringify_noop_helper(x)

#define MimeObjectClassInitializer(ITYPE, CSUPER)                \
  cpp_stringify(ITYPE), sizeof(ITYPE), (MimeObjectClass*)CSUPER, \
      (int (*)(MimeObjectClass*))ITYPE##ClassInitialize, 0

/* Macro used for setting up class definitions.
 */
#define MimeDefClass(ITYPE, CTYPE, CVAR, CSUPER)    \
  static int ITYPE##ClassInitialize(ITYPE##Class*); \
  ITYPE##Class CVAR = {ITYPE##ClassInitializer(ITYPE, CSUPER)}

/* Creates a new (subclass of) MimeObject of the given class, with the
   given headers (which are copied.)
 */
extern MimeObject* mime_new(MimeObjectClass* clazz, MimeHeaders* hdrs,
                            const char* override_content_type);

/* Destroys a MimeObject (or subclass) and all data associated with it.
 */
extern "C" void mime_free(MimeObject* object);

/* Given a content-type string, finds and returns an appropriate subclass
   of MimeObject.  A class object is returned.  If `exact_match_p' is true,
   then only fully-known types will be returned; that is, if it is true,
   then "text/x-unknown" will return MimeInlineTextPlainType, but if it is
   false, it will return NULL.
 */
extern MimeObjectClass* mime_find_class(const char* content_type,
                                        MimeHeaders* hdrs,
                                        MimeDisplayOptions* opts,
                                        bool exact_match_p);

/** Given a content-type string, creates and returns an appropriate subclass
 * of MimeObject.  The headers (from which the content-type was presumably
 * extracted) are copied. forceInline is set to true when the caller wants
 * the function to ignore opts->show_attachment_inline_p and force inline
 * display, e.g., mimemalt wants the body part to be shown inline.
 */
extern MimeObject* mime_create(const char* content_type, MimeHeaders* hdrs,
                               MimeDisplayOptions* opts,
                               bool forceInline = false);

/* Querying the type hierarchy */
extern bool mime_subclass_p(MimeObjectClass* child, MimeObjectClass* parent);
extern bool mime_typep(MimeObject* obj, MimeObjectClass* clazz);

/* Returns a string describing the location of the part (like "2.5.3").
   This is not a full URL, just a part-number.
 */
extern char* mime_part_address(MimeObject* obj);

/* Returns a string describing the location of the *IMAP* part (like "2.5.3").
   This is not a full URL, just a part-number.
   This part is explicitly passed in the X-Mozilla-IMAP-Part header.
   Return value must be freed by the caller.
 */
extern char* mime_imap_part_address(MimeObject* obj);

extern char* mime_external_attachment_url(MimeObject* obj);

/* Puts a part-number into a URL.  If append_p is true, then the part number
   is appended to any existing part-number already in that URL; otherwise,
   it replaces it.
 */
extern char* mime_set_url_part(const char* url, const char* part,
                               bool append_p);

/*
  cut the part of url for display a attachment as a email.
*/
extern char* mime_get_base_url(const char* url);

/* Puts an *IMAP* part-number into a URL.
 */
extern char* mime_set_url_imap_part(const char* url, const char* part,
                                    const char* libmimepart);

/* Given a part ID, looks through the MimeObject tree for a sub-part whose ID
   number matches, and returns the MimeObject (else NULL.)
   (part is not a URL -- it's of the form "1.3.5".)
 */
extern MimeObject* mime_address_to_part(const char* part, MimeObject* obj);

/* Given a part ID, looks through the MimeObject tree for a sub-part whose ID
   number matches; if one is found, returns the Content-Name of that part.
   Else returns NULL.  (part is not a URL -- it's of the form "1.3.5".)
 */
extern char* mime_find_suggested_name_of_part(const char* part,
                                              MimeObject* obj);

/* Given a part ID, looks through the MimeObject tree for a sub-part whose ID
   number matches; if one is found, returns the Content-Name of that part.
   Else returns NULL.  (part is not a URL -- it's of the form "1.3.5".)
 */
extern char* mime_find_content_type_of_part(const char* part, MimeObject* obj);

/* Parse the various "?" options off the URL and into the options struct.
 */
extern int mime_parse_url_options(const char* url, MimeDisplayOptions*);

#ifdef ENABLE_SMIME

/* Asks whether the given object is one of the cryptographically signed
   or encrypted objects that we know about.  (MimeMessageClass uses this
   to decide if the headers need to be presented differently.)
 */
extern bool mime_crypto_object_p(MimeHeaders*, bool clearsigned_counts,
                                 MimeDisplayOptions*);

/* Tells whether the given MimeObject is a message which has been encrypted
   or signed.  (Helper for MIME_GetMessageCryptoState()).
 */
extern void mime_get_crypto_state(MimeObject* obj, bool* signed_p,
                                  bool* encrypted_p, bool* signed_ok,
                                  bool* encrypted_ok);

/* How the crypto code tells the MimeMessage object what the crypto stamp
   on it says. */
extern void mime_set_crypto_stamp(MimeObject* obj, bool signed_p,
                                  bool encrypted_p);
#endif  // ENABLE_SMIME

class MimeParseStateObject {
 public:
  MimeParseStateObject() {
    root = 0;
    separator_queued_p = false;
    separator_suppressed_p = false;
    first_part_written_p = false;
    post_header_html_run_p = false;
    first_data_written_p = false;
    strippingPart = false;
  }
  MimeObject* root; /* The outermost parser object. */

  bool separator_queued_p; /* Whether a separator should be written out
                  before the next text is written (this lets
                  us write separators lazily, so that one
                  doesn't appear at the end, and so that more
                  than one don't appear in a row.) */

  bool separator_suppressed_p; /* Whether the currently-queued separator
                   should not be printed; this is a kludge to
                   prevent seps from being printed just after
                   a header block... */

  bool first_part_written_p; /* State used for the `Show Attachments As
                  Links' kludge. */

  bool post_header_html_run_p; /* Whether we've run the
                   options->generate_post_header_html_fn */

  bool first_data_written_p; /* State used for Mozilla lazy-stream-
                  creation evilness. */

  nsTArray<nsCString>
      partsToStrip; /* if we're stripping parts, what parts to strip */
  nsTArray<nsCString> detachToFiles; /* if we're detaching parts, where each
                                        part was detached to */
  bool strippingPart;
  nsCString detachedFilePath; /* if we've detached this part, filepath of
                                 detached part */
};

/* Some output-generation utility functions...
 */
extern int MimeObject_output_init(MimeObject* obj, const char* content_type);

/* The `user_visible_p' argument says whether the output that has just been
   written will cause characters or images to show up on the screen, that
   is, it should be false if the stuff being written is merely structural
   HTML or whitespace ("<P>", "</TABLE>", etc.)  This information is used
   when making the decision of whether a separating <HR> is needed.
 */
extern int MimeObject_write(MimeObject*, const char* data, int32_t length,
                            bool user_visible_p);
extern int MimeOptions_write(MimeHeaders*, MimeDisplayOptions*,
                             const char* data, int32_t length,
                             bool user_visible_p);

/* Writes out the right kind of HR (or rather, queues it for writing.) */
extern int MimeObject_write_separator(MimeObject*);

extern bool MimeObjectIsMessageBody(MimeObject* obj);

struct MimeDisplayData { /* This struct is what we hang off of
                            (context)->mime_data, to remember info
                            about the last MIME object we've
                            parsed and displayed.  See
                            MimeGuessURLContentName() below.
                          */
  MimeObject* last_parsed_object;
  char* last_parsed_url;
};

#endif /* _MIMEI_H_ */