summaryrefslogtreecommitdiffstats
path: root/mailnews/mime/src/mimeebod.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'mailnews/mime/src/mimeebod.cpp')
-rw-r--r--mailnews/mime/src/mimeebod.cpp509
1 files changed, 509 insertions, 0 deletions
diff --git a/mailnews/mime/src/mimeebod.cpp b/mailnews/mime/src/mimeebod.cpp
new file mode 100644
index 000000000..2ca056feb
--- /dev/null
+++ b/mailnews/mime/src/mimeebod.cpp
@@ -0,0 +1,509 @@
+/* -*- 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/. */
+#include "nsCOMPtr.h"
+#include "nsIURL.h"
+#include "mimeebod.h"
+#include "prmem.h"
+#include "plstr.h"
+#include "prlog.h"
+#include "prio.h"
+#include "msgCore.h"
+#include "nsMimeStringResources.h"
+#include "mimemoz2.h"
+#include "nsComponentManagerUtils.h"
+#include "nsMsgUtils.h"
+#include "nsINetUtil.h"
+#include <ctype.h>
+
+#define MIME_SUPERCLASS mimeObjectClass
+MimeDefClass(MimeExternalBody, MimeExternalBodyClass,
+ mimeExternalBodyClass, &MIME_SUPERCLASS);
+
+#ifdef XP_MACOSX
+extern MimeObjectClass mimeMultipartAppleDoubleClass;
+#endif
+
+static int MimeExternalBody_initialize (MimeObject *);
+static void MimeExternalBody_finalize (MimeObject *);
+static int MimeExternalBody_parse_line (const char *, int32_t, MimeObject *);
+static int MimeExternalBody_parse_eof (MimeObject *, bool);
+static bool MimeExternalBody_displayable_inline_p (MimeObjectClass *clazz,
+ MimeHeaders *hdrs);
+
+#if 0
+#if defined(DEBUG) && defined(XP_UNIX)
+static int MimeExternalBody_debug_print (MimeObject *, PRFileDesc *, int32_t);
+#endif
+#endif /* 0 */
+
+static int
+MimeExternalBodyClassInitialize(MimeExternalBodyClass *clazz)
+{
+ MimeObjectClass *oclass = (MimeObjectClass *) clazz;
+
+ NS_ASSERTION(!oclass->class_initialized, "1.1 <rhp@netscape.com> 19 Mar 1999 12:00");
+ oclass->initialize = MimeExternalBody_initialize;
+ oclass->finalize = MimeExternalBody_finalize;
+ oclass->parse_line = MimeExternalBody_parse_line;
+ oclass->parse_eof = MimeExternalBody_parse_eof;
+ oclass->displayable_inline_p = MimeExternalBody_displayable_inline_p;
+
+#if 0
+#if defined(DEBUG) && defined(XP_UNIX)
+ oclass->debug_print = MimeExternalBody_debug_print;
+#endif
+#endif /* 0 */
+
+ return 0;
+}
+
+
+static int
+MimeExternalBody_initialize (MimeObject *object)
+{
+ return ((MimeObjectClass*)&MIME_SUPERCLASS)->initialize(object);
+}
+
+static void
+MimeExternalBody_finalize (MimeObject *object)
+{
+ MimeExternalBody *bod = (MimeExternalBody *) object;
+ if (bod->hdrs)
+ {
+ MimeHeaders_free(bod->hdrs);
+ bod->hdrs = 0;
+ }
+ PR_FREEIF(bod->body);
+
+ ((MimeObjectClass*)&MIME_SUPERCLASS)->finalize(object);
+}
+
+static int
+MimeExternalBody_parse_line (const char *line, int32_t length, MimeObject *obj)
+{
+ MimeExternalBody *bod = (MimeExternalBody *) obj;
+ int status = 0;
+
+ NS_ASSERTION(line && *line, "1.1 <rhp@netscape.com> 19 Mar 1999 12:00");
+ if (!line || !*line) return -1;
+
+ if (!obj->output_p) return 0;
+
+ /* If we're supposed to write this object, but aren't supposed to convert
+ it to HTML, simply pass it through unaltered. */
+ if (obj->options &&
+ !obj->options->write_html_p &&
+ obj->options->output_fn)
+ return MimeObject_write(obj, line, length, true);
+
+
+ /* If we already have a `body' then we're done parsing headers, and all
+ subsequent lines get tacked onto the body. */
+ if (bod->body)
+ {
+ int L = strlen(bod->body);
+ char *new_str = (char *)PR_Realloc(bod->body, L + length + 1);
+ if (!new_str) return MIME_OUT_OF_MEMORY;
+ bod->body = new_str;
+ memcpy(bod->body + L, line, length);
+ bod->body[L + length] = 0;
+ return 0;
+ }
+
+ /* Otherwise we don't yet have a body, which means we're not done parsing
+ our headers.
+ */
+ if (!bod->hdrs)
+ {
+ bod->hdrs = MimeHeaders_new();
+ if (!bod->hdrs) return MIME_OUT_OF_MEMORY;
+ }
+
+ status = MimeHeaders_parse_line(line, length, bod->hdrs);
+ if (status < 0) return status;
+
+ /* If this line is blank, we're now done parsing headers, and should
+ create a dummy body to show that. Gag.
+ */
+ if (*line == '\r' || *line == '\n')
+ {
+ bod->body = strdup("");
+ if (!bod->body) return MIME_OUT_OF_MEMORY;
+ }
+
+ return 0;
+}
+
+
+char *
+MimeExternalBody_make_url(const char *ct,
+ const char *at, const char *lexp, const char *size,
+ const char *perm, const char *dir, const char *mode,
+ const char *name, const char *url, const char *site,
+ const char *svr, const char *subj, const char *body)
+{
+ char *s;
+ uint32_t slen;
+ if (!at)
+ {
+ return 0;
+ }
+ else if (!PL_strcasecmp(at, "ftp") || !PL_strcasecmp(at, "anon-ftp"))
+ {
+ if (!site || !name)
+ return 0;
+
+ slen = strlen(name) + strlen(site) + (dir ? strlen(dir) : 0) + 20;
+ s = (char *) PR_MALLOC(slen);
+
+ if (!s) return 0;
+ PL_strncpyz(s, "ftp://", slen);
+ PL_strcatn(s, slen, site);
+ PL_strcatn(s, slen, "/");
+ if (dir) PL_strcatn(s, slen, (dir[0] == '/' ? dir+1 : dir));
+ if (s[strlen(s)-1] != '/')
+ PL_strcatn(s, slen, "/");
+ PL_strcatn(s, slen, name);
+ return s;
+ }
+ else if (!PL_strcasecmp(at, "local-file") || !PL_strcasecmp(at, "afs"))
+ {
+ if (!name)
+ return 0;
+
+#ifdef XP_UNIX
+ if (!PL_strcasecmp(at, "afs")) /* only if there is a /afs/ directory */
+ {
+ nsCOMPtr <nsIFile> fs = do_CreateInstance(NS_LOCAL_FILE_CONTRACTID);
+ bool exists = false;
+ if (fs)
+ {
+ fs->InitWithNativePath(NS_LITERAL_CSTRING("/afs/."));
+ fs->Exists(&exists);
+ }
+ if (!exists)
+ return 0;
+ }
+#else /* !XP_UNIX */
+ return 0; /* never, if not Unix. */
+#endif /* !XP_UNIX */
+
+ slen = (strlen(name) * 3 + 20);
+ s = (char *) PR_MALLOC(slen);
+ if (!s) return 0;
+ PL_strncpyz(s, "file:", slen);
+
+ nsCString s2;
+ MsgEscapeString(nsDependentCString(name), nsINetUtil::ESCAPE_URL_PATH, s2);
+ PL_strcatn(s, slen, s2.get());
+ return s;
+ }
+else if (!PL_strcasecmp(at, "mail-server"))
+{
+ if (!svr)
+ return 0;
+
+ slen = (strlen(svr)*4 + (subj ? strlen(subj)*4 : 0) +
+ (body ? strlen(body)*4 : 0) + 25); // dpv xxx: why 4x? %xx escaping should be 3x
+ s = (char *) PR_MALLOC(slen);
+ if (!s) return 0;
+ PL_strncpyz(s, "mailto:", slen);
+
+ nsCString s2;
+ MsgEscapeString(nsDependentCString(svr), nsINetUtil::ESCAPE_XALPHAS, s2);
+ PL_strcatn(s, slen, s2.get());
+
+ if (subj)
+ {
+ MsgEscapeString(nsDependentCString(subj), nsINetUtil::ESCAPE_XALPHAS, s2);
+ PL_strcatn(s, slen, "?subject=");
+ PL_strcatn(s, slen, s2.get());
+ }
+ if (body)
+ {
+ MsgEscapeString(nsDependentCString(body), nsINetUtil::ESCAPE_XALPHAS, s2);
+ PL_strcatn(s, slen, (subj ? "&body=" : "?body="));
+ PL_strcatn(s, slen, s2.get());
+ }
+ return s;
+}
+else if (!PL_strcasecmp(at, "url")) /* RFC 2017 */
+ {
+ if (url)
+ return strdup(url); /* it's already quoted and everything */
+ else
+ return 0;
+ }
+ else
+ return 0;
+}
+
+static int
+MimeExternalBody_parse_eof (MimeObject *obj, bool abort_p)
+{
+ int status = 0;
+ MimeExternalBody *bod = (MimeExternalBody *) obj;
+
+ if (obj->closed_p) return 0;
+
+ /* Run parent method first, to flush out any buffered data. */
+ status = ((MimeObjectClass*)&MIME_SUPERCLASS)->parse_eof(obj, abort_p);
+ if (status < 0) return status;
+
+#ifdef XP_MACOSX
+ if (obj->parent && mime_typep(obj->parent,
+ (MimeObjectClass*) &mimeMultipartAppleDoubleClass))
+ goto done;
+#endif /* XP_MACOSX */
+
+ if (!abort_p &&
+ obj->output_p &&
+ obj->options &&
+ obj->options->write_html_p)
+ {
+ bool all_headers_p = obj->options->headers == MimeHeadersAll;
+ MimeDisplayOptions *newopt = obj->options; /* copy it */
+
+ char *ct = MimeHeaders_get(obj->headers, HEADER_CONTENT_TYPE,
+ false, false);
+ char *at, *lexp, *size, *perm;
+ char *url, *dir, *mode, *name, *site, *svr, *subj;
+ char *h = 0, *lname = 0, *lurl = 0, *body = 0;
+ MimeHeaders *hdrs = 0;
+
+ if (!ct) return MIME_OUT_OF_MEMORY;
+
+ at = MimeHeaders_get_parameter(ct, "access-type", NULL, NULL);
+ lexp = MimeHeaders_get_parameter(ct, "expiration", NULL, NULL);
+ size = MimeHeaders_get_parameter(ct, "size", NULL, NULL);
+ perm = MimeHeaders_get_parameter(ct, "permission", NULL, NULL);
+ dir = MimeHeaders_get_parameter(ct, "directory", NULL, NULL);
+ mode = MimeHeaders_get_parameter(ct, "mode", NULL, NULL);
+ name = MimeHeaders_get_parameter(ct, "name", NULL, NULL);
+ site = MimeHeaders_get_parameter(ct, "site", NULL, NULL);
+ svr = MimeHeaders_get_parameter(ct, "server", NULL, NULL);
+ subj = MimeHeaders_get_parameter(ct, "subject", NULL, NULL);
+ url = MimeHeaders_get_parameter(ct, "url", NULL, NULL);
+ PR_FREEIF(ct);
+
+ /* the *internal* content-type */
+ ct = MimeHeaders_get(bod->hdrs, HEADER_CONTENT_TYPE,
+ true, false);
+
+ uint32_t hlen = ((at ? strlen(at) : 0) +
+ (lexp ? strlen(lexp) : 0) +
+ (size ? strlen(size) : 0) +
+ (perm ? strlen(perm) : 0) +
+ (dir ? strlen(dir) : 0) +
+ (mode ? strlen(mode) : 0) +
+ (name ? strlen(name) : 0) +
+ (site ? strlen(site) : 0) +
+ (svr ? strlen(svr) : 0) +
+ (subj ? strlen(subj) : 0) +
+ (ct ? strlen(ct) : 0) +
+ (url ? strlen(url) : 0) + 100);
+
+ h = (char *) PR_MALLOC(hlen);
+ if (!h)
+ {
+ status = MIME_OUT_OF_MEMORY;
+ goto FAIL;
+ }
+
+ /* If there's a URL parameter, remove all whitespace from it.
+ (The URL parameter to one of these headers is stored with
+ lines broken every 40 characters or less; it's assumed that
+ all significant whitespace was URL-hex-encoded, and all the
+ rest of it was inserted just to keep the lines short.)
+ */
+ if (url)
+ {
+ char *in, *out;
+ for (in = url, out = url; *in; in++)
+ if (!IS_SPACE(*in))
+ *out++ = *in;
+ *out = 0;
+ }
+
+ hdrs = MimeHeaders_new();
+ if (!hdrs)
+ {
+ status = MIME_OUT_OF_MEMORY;
+ goto FAIL;
+ }
+
+# define FROB(STR,VAR) \
+ if (VAR) \
+ { \
+ PL_strncpyz(h, STR ": ", hlen); \
+ PL_strcatn(h, hlen, VAR); \
+ PL_strcatn(h, hlen, MSG_LINEBREAK); \
+ status = MimeHeaders_parse_line(h, strlen(h), hdrs); \
+ if (status < 0) goto FAIL; \
+ }
+ FROB("Access-Type", at);
+ FROB("URL", url);
+ FROB("Site", site);
+ FROB("Server", svr);
+ FROB("Directory", dir);
+ FROB("Name", name);
+ FROB("Type", ct);
+ FROB("Size", size);
+ FROB("Mode", mode);
+ FROB("Permission", perm);
+ FROB("Expiration", lexp);
+ FROB("Subject", subj);
+# undef FROB
+ PL_strncpyz(h, MSG_LINEBREAK, hlen);
+ status = MimeHeaders_parse_line(h, strlen(h), hdrs);
+ if (status < 0) goto FAIL;
+
+ lurl = MimeExternalBody_make_url(ct, at, lexp, size, perm, dir, mode,
+ name, url, site, svr, subj, bod->body);
+ if (lurl)
+ {
+ lname = MimeGetStringByID(MIME_MSG_LINK_TO_DOCUMENT);
+ }
+ else
+ {
+ lname = MimeGetStringByID(MIME_MSG_DOCUMENT_INFO);
+ all_headers_p = true;
+ }
+
+ all_headers_p = true; /* #### just do this all the time? */
+
+ if (bod->body && all_headers_p)
+ {
+ char *s = bod->body;
+ while (IS_SPACE(*s)) s++;
+ if (*s)
+ {
+ char *s2;
+ const char *pre = "<P><PRE>";
+ const char *suf = "</PRE>";
+ int32_t i;
+ for(i = strlen(s)-1; i >= 0 && IS_SPACE(s[i]); i--)
+ s[i] = 0;
+ s2 = MsgEscapeHTML(s);
+ if (!s2) goto FAIL;
+ body = (char *) PR_MALLOC(strlen(pre) + strlen(s2) +
+ strlen(suf) + 1);
+ if (!body)
+ {
+ NS_Free(s2);
+ goto FAIL;
+ }
+ PL_strcpy(body, pre);
+ PL_strcat(body, s2);
+ PL_strcat(body, suf);
+ }
+ }
+
+ newopt->fancy_headers_p = true;
+ newopt->headers = (all_headers_p ? MimeHeadersAll : MimeHeadersSome);
+
+FAIL:
+ if (hdrs)
+ MimeHeaders_free(hdrs);
+ PR_FREEIF(h);
+ PR_FREEIF(lname);
+ PR_FREEIF(lurl);
+ PR_FREEIF(body);
+ PR_FREEIF(ct);
+ PR_FREEIF(at);
+ PR_FREEIF(lexp);
+ PR_FREEIF(size);
+ PR_FREEIF(perm);
+ PR_FREEIF(dir);
+ PR_FREEIF(mode);
+ PR_FREEIF(name);
+ PR_FREEIF(url);
+ PR_FREEIF(site);
+ PR_FREEIF(svr);
+ PR_FREEIF(subj);
+ }
+
+#ifdef XP_MACOSX
+done:
+#endif
+
+ return status;
+}
+
+#if 0
+#if defined(DEBUG) && defined(XP_UNIX)
+static int
+MimeExternalBody_debug_print (MimeObject *obj, PRFileDesc *stream, int32_t depth)
+{
+ MimeExternalBody *bod = (MimeExternalBody *) obj;
+ int i;
+ char *ct, *ct2;
+ char *addr = mime_part_address(obj);
+
+ if (obj->headers)
+ ct = MimeHeaders_get (obj->headers, HEADER_CONTENT_TYPE, false, false);
+ if (bod->hdrs)
+ ct2 = MimeHeaders_get (bod->hdrs, HEADER_CONTENT_TYPE, false, false);
+
+ for (i=0; i < depth; i++)
+ PR_Write(stream, " ", 2);
+/***
+ fprintf(stream,
+ "<%s %s\n"
+ "\tcontent-type: %s\n"
+ "\tcontent-type: %s\n"
+ "\tBody:%s\n\t0x%08X>\n\n",
+ obj->clazz->class_name,
+ addr ? addr : "???",
+ ct ? ct : "<none>",
+ ct2 ? ct2 : "<none>",
+ bod->body ? bod->body : "<none>",
+ (uint32_t) obj);
+***/
+ PR_FREEIF(addr);
+ PR_FREEIF(ct);
+ PR_FREEIF(ct2);
+ return 0;
+}
+#endif
+#endif /* 0 */
+
+static bool
+MimeExternalBody_displayable_inline_p (MimeObjectClass *clazz,
+ MimeHeaders *hdrs)
+{
+ char *ct = MimeHeaders_get (hdrs, HEADER_CONTENT_TYPE, false, false);
+ char *at = MimeHeaders_get_parameter(ct, "access-type", NULL, NULL);
+ bool inline_p = false;
+
+ if (!at)
+ ;
+ else if (!PL_strcasecmp(at, "ftp") ||
+ !PL_strcasecmp(at, "anon-ftp") ||
+ !PL_strcasecmp(at, "local-file") ||
+ !PL_strcasecmp(at, "mail-server") ||
+ !PL_strcasecmp(at, "url"))
+ inline_p = true;
+#ifdef XP_UNIX
+ else if (!PL_strcasecmp(at, "afs")) /* only if there is a /afs/ directory */
+ {
+ nsCOMPtr <nsIFile> fs = do_CreateInstance(NS_LOCAL_FILE_CONTRACTID);
+ bool exists = false;
+ if (fs)
+ {
+ fs->InitWithNativePath(NS_LITERAL_CSTRING("/afs/."));
+ fs->Exists(&exists);
+ }
+ if (!exists)
+ return 0;
+
+ inline_p = true;
+ }
+#endif /* XP_UNIX */
+
+ PR_FREEIF(ct);
+ PR_FREEIF(at);
+ return inline_p;
+}