diff options
Diffstat (limited to 'mailnews/mime/src/mimeobj.cpp')
-rw-r--r-- | mailnews/mime/src/mimeobj.cpp | 327 |
1 files changed, 327 insertions, 0 deletions
diff --git a/mailnews/mime/src/mimeobj.cpp b/mailnews/mime/src/mimeobj.cpp new file mode 100644 index 000000000..26eb618ce --- /dev/null +++ b/mailnews/mime/src/mimeobj.cpp @@ -0,0 +1,327 @@ +/* -*- 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/. + * This Original Code has been modified by IBM Corporation. Modifications made by IBM + * described herein are Copyright (c) International Business Machines Corporation, 2000. + * Modifications to Mozilla code or documentation identified per MPL Section 3.3 + * + * Date Modified by Description of modification + * 04/20/2000 IBM Corp. OS/2 VisualAge build. + */ + +#include "mimeobj.h" +#include "prmem.h" +#include "plstr.h" +#include "prio.h" +#include "mimebuf.h" +#include "prlog.h" +#include "nsMimeTypes.h" +#include "nsMimeStringResources.h" +#include "nsMsgUtils.h" +#include "mimemsg.h" +#include "mimemapl.h" + +/* Way to destroy any notions of modularity or class hierarchy, Terry! */ +# include "mimetpla.h" +# include "mimethtm.h" +# include "mimecont.h" + +MimeDefClass (MimeObject, MimeObjectClass, mimeObjectClass, NULL); + +static int MimeObject_initialize (MimeObject *); +static void MimeObject_finalize (MimeObject *); +static int MimeObject_parse_begin (MimeObject *); +static int MimeObject_parse_buffer (const char *, int32_t, MimeObject *); +static int MimeObject_parse_line (const char *, int32_t, MimeObject *); +static int MimeObject_parse_eof (MimeObject *, bool); +static int MimeObject_parse_end (MimeObject *, bool); +static bool MimeObject_displayable_inline_p (MimeObjectClass *clazz, + MimeHeaders *hdrs); + +#if defined(DEBUG) && defined(XP_UNIX) +static int MimeObject_debug_print (MimeObject *, PRFileDesc *, int32_t depth); +#endif + +static int +MimeObjectClassInitialize(MimeObjectClass *clazz) +{ + NS_ASSERTION(!clazz->class_initialized, "class shouldn't already be initialized"); + clazz->initialize = MimeObject_initialize; + clazz->finalize = MimeObject_finalize; + clazz->parse_begin = MimeObject_parse_begin; + clazz->parse_buffer = MimeObject_parse_buffer; + clazz->parse_line = MimeObject_parse_line; + clazz->parse_eof = MimeObject_parse_eof; + clazz->parse_end = MimeObject_parse_end; + clazz->displayable_inline_p = MimeObject_displayable_inline_p; + +#if defined(DEBUG) && defined(XP_UNIX) + clazz->debug_print = MimeObject_debug_print; +#endif + return 0; +} + +static int +MimeObject_initialize (MimeObject *obj) +{ + /* This is an abstract class; it shouldn't be directly instantiated. */ + NS_ASSERTION(obj->clazz != &mimeObjectClass, "should directly instantiate abstract class"); + + /* Set up the content-type and encoding. */ + if (!obj->content_type && obj->headers) + obj->content_type = MimeHeaders_get (obj->headers, HEADER_CONTENT_TYPE, + true, false); + if (!obj->encoding && obj->headers) + obj->encoding = MimeHeaders_get (obj->headers, + HEADER_CONTENT_TRANSFER_ENCODING, + true, false); + + /* Special case to normalize some types and encodings to a canonical form. + (These are nonstandard types/encodings which have been seen to appear in + multiple forms; we normalize them so that things like looking up icons + and extensions has consistent behavior for the receiver, regardless of + the "alias" type that the sender used.) + */ + if (!obj->content_type || !*(obj->content_type)) + ; + else if (!PL_strcasecmp(obj->content_type, APPLICATION_UUENCODE2) || + !PL_strcasecmp(obj->content_type, APPLICATION_UUENCODE3) || + !PL_strcasecmp(obj->content_type, APPLICATION_UUENCODE4)) + { + PR_Free(obj->content_type); + obj->content_type = strdup(APPLICATION_UUENCODE); + } + else if (!PL_strcasecmp(obj->content_type, IMAGE_XBM2) || + !PL_strcasecmp(obj->content_type, IMAGE_XBM3)) + { + PR_Free(obj->content_type); + obj->content_type = strdup(IMAGE_XBM); + } + else { + // MIME-types are case-insenitive, but let's make it lower case internally + // to avoid some hassle later down the road. + nsAutoCString lowerCaseContentType; + ToLowerCase(nsDependentCString(obj->content_type), lowerCaseContentType); + PR_Free(obj->content_type); + obj->content_type = ToNewCString(lowerCaseContentType); + } + + if (!obj->encoding) + ; + else if (!PL_strcasecmp(obj->encoding, ENCODING_UUENCODE2) || + !PL_strcasecmp(obj->encoding, ENCODING_UUENCODE3) || + !PL_strcasecmp(obj->encoding, ENCODING_UUENCODE4)) + { + PR_Free(obj->encoding); + obj->encoding = strdup(ENCODING_UUENCODE); + } + else if (!PL_strcasecmp(obj->encoding, ENCODING_COMPRESS2)) + { + PR_Free(obj->encoding); + obj->encoding = strdup(ENCODING_COMPRESS); + } + else if (!PL_strcasecmp(obj->encoding, ENCODING_GZIP2)) + { + PR_Free(obj->encoding); + obj->encoding = strdup(ENCODING_GZIP); + } + + return 0; +} + +static void +MimeObject_finalize (MimeObject *obj) +{ + obj->clazz->parse_eof (obj, false); + obj->clazz->parse_end (obj, false); + + if (obj->headers) + { + MimeHeaders_free(obj->headers); + obj->headers = 0; + } + + /* Should have been freed by parse_eof, but just in case... */ + NS_ASSERTION(!obj->ibuffer, "buffer not freed"); + NS_ASSERTION(!obj->obuffer, "buffer not freed"); + PR_FREEIF (obj->ibuffer); + PR_FREEIF (obj->obuffer); + + PR_FREEIF(obj->content_type); + PR_FREEIF(obj->encoding); + + if (obj->options && obj->options->state) + { + delete obj->options->state; + obj->options->state = nullptr; + } +} + +static int +MimeObject_parse_begin (MimeObject *obj) +{ + NS_ASSERTION (!obj->closed_p, "object shouldn't be already closed"); + + /* If we haven't set up the state object yet, then this should be + the outermost object... */ + if (obj->options && !obj->options->state) + { + NS_ASSERTION(!obj->headers, "headers should be null"); /* should be the outermost object. */ + + obj->options->state = new MimeParseStateObject; + if (!obj->options->state) return MIME_OUT_OF_MEMORY; + obj->options->state->root = obj; + obj->options->state->separator_suppressed_p = true; /* no first sep */ + const char *delParts = PL_strcasestr(obj->options->url, "&del="); + const char *detachLocations = PL_strcasestr(obj->options->url, "&detachTo="); + if (delParts) + { + const char *delEnd = PL_strcasestr(delParts + 1, "&"); + if (!delEnd) + delEnd = delParts + strlen(delParts); + ParseString(Substring(delParts + 5, delEnd), ',', obj->options->state->partsToStrip); + } + if (detachLocations) + { + detachLocations += 10; // advance past "&detachTo=" + ParseString(nsDependentCString(detachLocations), ',', obj->options->state->detachToFiles); + } + } + + /* Decide whether this object should be output or not... */ + if (!obj->options || obj->options->no_output_p || !obj->options->output_fn + /* if we are decomposing the message in files and processing a multipart object, + we must not output it without parsing it first */ + || (obj->options->decompose_file_p && obj->options->decompose_file_output_fn && + mime_typep(obj, (MimeObjectClass*) &mimeMultipartClass)) + ) + obj->output_p = false; + else if (!obj->options->part_to_load) + obj->output_p = true; + else + { + char *id = mime_part_address(obj); + if (!id) return MIME_OUT_OF_MEMORY; + + // We need to check if a part is the subpart of the part to load. + // If so and this is a raw or body display output operation, then + // we should mark the part for subsequent output. + + // First, check for an exact match + obj->output_p = !strcmp(id, obj->options->part_to_load); + if (!obj->output_p && (obj->options->format_out == nsMimeOutput::nsMimeMessageRaw || + obj->options->format_out == nsMimeOutput::nsMimeMessageBodyDisplay || + obj->options->format_out == nsMimeOutput::nsMimeMessageAttach)) + { + // Then, check for subpart + unsigned int partlen = strlen(obj->options->part_to_load); + obj->output_p = (strlen(id) >= partlen + 2) && (id[partlen] == '.') && + !strncmp(id, obj->options->part_to_load, partlen); + } + + PR_Free(id); + } + + // If we've decided not to output this part, we also shouldn't be showing it + // as an attachment. + obj->dontShowAsAttachment = !obj->output_p; + + return 0; +} + +static int +MimeObject_parse_buffer (const char *buffer, int32_t size, MimeObject *obj) +{ + NS_ASSERTION(!obj->closed_p, "object shouldn't be closed"); + if (obj->closed_p) return -1; + + return mime_LineBuffer (buffer, size, + &obj->ibuffer, &obj->ibuffer_size, &obj->ibuffer_fp, + true, + ((int (*) (char *, int32_t, void *)) + /* This cast is to turn void into MimeObject */ + obj->clazz->parse_line), + obj); +} + +static int +MimeObject_parse_line (const char *line, int32_t length, MimeObject *obj) +{ + NS_ERROR("shouldn't call this method"); + return -1; +} + +static int +MimeObject_parse_eof (MimeObject *obj, bool abort_p) +{ + if (obj->closed_p) return 0; + NS_ASSERTION(!obj->parsed_p, "obj already parsed"); + + /* If there is still data in the ibuffer, that means that the last line of + this part didn't end in a newline; so push it out anyway (this means that + the parse_line method will be called with a string with no trailing + newline, which isn't the usual case.) + */ + if (!abort_p && + obj->ibuffer_fp > 0) + { + int status = obj->clazz->parse_line (obj->ibuffer, obj->ibuffer_fp, obj); + obj->ibuffer_fp = 0; + if (status < 0) + { + obj->closed_p = true; + return status; + } + } + + obj->closed_p = true; + return 0; +} + +static int +MimeObject_parse_end (MimeObject *obj, bool abort_p) +{ + if (obj->parsed_p) + { + NS_ASSERTION(obj->closed_p, "object should be closed"); + return 0; + } + + /* We won't be needing these buffers any more; nuke 'em. */ + PR_FREEIF(obj->ibuffer); + obj->ibuffer_fp = 0; + obj->ibuffer_size = 0; + PR_FREEIF(obj->obuffer); + obj->obuffer_fp = 0; + obj->obuffer_size = 0; + + obj->parsed_p = true; + return 0; +} + +static bool +MimeObject_displayable_inline_p (MimeObjectClass *clazz, MimeHeaders *hdrs) +{ + NS_ERROR("shouldn't call this method"); + return false; +} + +#if defined(DEBUG) && defined(XP_UNIX) +static int +MimeObject_debug_print (MimeObject *obj, PRFileDesc *stream, int32_t depth) +{ + int i; + char *addr = mime_part_address(obj); + for (i=0; i < depth; i++) + PR_Write(stream, " ", 2); +/* + fprintf(stream, "<%s %s 0x%08X>\n", obj->clazz->class_name, + addr ? addr : "???", + (uint32_t) obj); +*/ + PR_FREEIF(addr); + return 0; +} +#endif |