summaryrefslogtreecommitdiffstats
path: root/comm/mailnews/mime/src/mimeobj.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'comm/mailnews/mime/src/mimeobj.cpp')
-rw-r--r--comm/mailnews/mime/src/mimeobj.cpp301
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