diff options
Diffstat (limited to 'comm/mailnews/mime/src/mimeobj.cpp')
-rw-r--r-- | comm/mailnews/mime/src/mimeobj.cpp | 301 |
1 files changed, 301 insertions, 0 deletions
diff --git a/comm/mailnews/mime/src/mimeobj.cpp b/comm/mailnews/mime/src/mimeobj.cpp new file mode 100644 index 0000000000..7ad7e290d1 --- /dev/null +++ b/comm/mailnews/mime/src/mimeobj.cpp @@ -0,0 +1,301 @@ +/* -*- Mode: C++; tab-width: 2; 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 (abort_p) { + obj->closed_p = true; + return 0; + } + 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 (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 |