summaryrefslogtreecommitdiff
path: root/mailnews/mime/src/mimetric.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'mailnews/mime/src/mimetric.cpp')
-rw-r--r--mailnews/mime/src/mimetric.cpp353
1 files changed, 353 insertions, 0 deletions
diff --git a/mailnews/mime/src/mimetric.cpp b/mailnews/mime/src/mimetric.cpp
new file mode 100644
index 0000000000..95e08ac9b0
--- /dev/null
+++ b/mailnews/mime/src/mimetric.cpp
@@ -0,0 +1,353 @@
+/* -*- 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 "mimetric.h"
+#include "mimebuf.h"
+#include "prmem.h"
+#include "plstr.h"
+#include "prlog.h"
+#include "msgCore.h"
+#include <ctype.h>
+
+#define MIME_SUPERCLASS mimeInlineTextClass
+MimeDefClass(MimeInlineTextRichtext, MimeInlineTextRichtextClass,
+ mimeInlineTextRichtextClass, &MIME_SUPERCLASS);
+
+static int MimeInlineTextRichtext_parse_line (const char *, int32_t, MimeObject *);
+static int MimeInlineTextRichtext_parse_begin (MimeObject *);
+static int MimeInlineTextRichtext_parse_eof (MimeObject *, bool);
+
+static int
+MimeInlineTextRichtextClassInitialize(MimeInlineTextRichtextClass *clazz)
+{
+ MimeObjectClass *oclass = (MimeObjectClass *) clazz;
+ PR_ASSERT(!oclass->class_initialized);
+ oclass->parse_begin = MimeInlineTextRichtext_parse_begin;
+ oclass->parse_line = MimeInlineTextRichtext_parse_line;
+ oclass->parse_eof = MimeInlineTextRichtext_parse_eof;
+ return 0;
+}
+
+/* This function has this clunky interface because it needs to be called
+ from outside this module (no MimeObject, etc.)
+ */
+int
+MimeRichtextConvert (const char *line, int32_t length,
+ MimeObject *obj,
+ char **obufferP,
+ int32_t *obuffer_sizeP,
+ bool enriched_p)
+{
+ /* RFC 1341 (the original MIME spec) defined text/richtext.
+ RFC 1563 superceded text/richtext with text/enriched.
+ The changes from text/richtext to text/enriched are:
+ - CRLF semantics are different
+ - << maps to <
+ - These tags were added:
+ <VERBATIM>, <NOFILL>, <PARAM>, <FLUSHBOTH>
+ - These tags were removed:
+ <COMMENT>, <OUTDENT>, <OUTDENTRIGHT>, <SAMEPAGE>, <SUBSCRIPT>,
+ <SUPERSCRIPT>, <HEADING>, <FOOTING>, <PARAGRAPH>, <SIGNATURE>,
+ <LT>, <NL>, <NP>
+ This method implements them both.
+
+ draft-resnick-text-enriched-03.txt is a proposed update to 1563.
+ - These tags were added:
+ <FONTFAMILY>, <COLOR>, <PARAINDENT>, <LANG>.
+ However, all of these rely on the magic <PARAM> tag, which we
+ don't implement, so we're ignoring all of these.
+ Interesting fact: it's by Peter W. Resnick from Qualcomm (Eudora).
+ And it also says "It is fully expected that other text formatting
+ standards like HTML and SGML will supplant text/enriched in
+ Internet mail."
+ */
+ int status = 0;
+ char *out;
+ const char *data_end;
+ const char *last_end;
+ const char *this_start;
+ const char *this_end;
+ unsigned int desired_size;
+
+ // The code below must never expand the input by more than 5x;
+ // if it does, the desired_size multiplier (5) below must be changed too
+#define BGROWTH 5
+ if ( (uint32_t)length >= ( (uint32_t) 0xfffffffe)/BGROWTH )
+ return -1;
+ desired_size = (length * BGROWTH) + 1;
+#undef BGROWTH
+ if (desired_size >= (uint32_t) *obuffer_sizeP)
+ status = mime_GrowBuffer (desired_size, sizeof(char), 1024,
+ obufferP, obuffer_sizeP);
+ if (status < 0) return status;
+
+ if (enriched_p)
+ {
+ for (this_start = line; this_start < line + length; this_start++)
+ if (!IS_SPACE (*this_start)) break;
+ if (this_start >= line + length) /* blank line */
+ {
+ PL_strncpyz (*obufferP, "<BR>", *obuffer_sizeP);
+ return MimeObject_write(obj, *obufferP, strlen(*obufferP), true);
+ }
+ }
+
+ uint32_t outlen = (uint32_t) *obuffer_sizeP;
+ out = *obufferP;
+ *out = 0;
+
+ data_end = line + length;
+ last_end = line;
+ this_start = last_end;
+ this_end = this_start;
+ uint32_t addedlen = 0;
+ while (this_end < data_end)
+ {
+ /* Skip forward to next special character. */
+ while (this_start < data_end &&
+ *this_start != '<' && *this_start != '>' &&
+ *this_start != '&')
+ this_start++;
+
+ this_end = this_start;
+
+ /* Skip to the end of the tag. */
+ if (this_start < data_end && *this_start == '<')
+ {
+ this_end++;
+ while (this_end < data_end &&
+ !IS_SPACE(*this_end) &&
+ *this_end != '<' && *this_end != '>' &&
+ *this_end != '&')
+ this_end++;
+ }
+
+ this_end++;
+
+ /* Push out the text preceeding the tag. */
+ if (last_end && last_end != this_start)
+ {
+ memcpy (out, last_end, this_start - last_end);
+ out += this_start - last_end;
+ *out = 0;
+ outlen -= (this_start - last_end);
+ }
+
+ if (this_start >= data_end)
+ break;
+ else if (*this_start == '&')
+ {
+ PL_strncpyz (out, "&amp;", outlen);
+ addedlen = strlen(out);
+ outlen -= addedlen;
+ out += addedlen;
+ }
+ else if (*this_start == '>')
+ {
+ PL_strncpyz (out, "&gt;", outlen);
+ addedlen = strlen(out);
+ outlen -= addedlen;
+ out += addedlen;
+ }
+ else if (enriched_p &&
+ this_start < data_end + 1 &&
+ this_start[0] == '<' &&
+ this_start[1] == '<')
+ {
+ PL_strncpyz (out, "&lt;", outlen);
+ addedlen = strlen(out);
+ outlen -= addedlen;
+ out += addedlen;
+ }
+ else if (this_start != this_end)
+ {
+ /* Push out this ID. */
+ const char *old = this_start + 1;
+ const char *tag_open = 0;
+ const char *tag_close = 0;
+ if (*old == '/')
+ {
+ /* This is </tag> */
+ old++;
+ }
+
+ switch (*old)
+ {
+ case 'b': case 'B':
+ if (!PL_strncasecmp ("BIGGER>", old, 7))
+ tag_open = "<FONT SIZE=\"+1\">", tag_close = "</FONT>";
+ else if (!PL_strncasecmp ("BLINK>", old, 5))
+ /* Of course, both text/richtext and text/enriched must be
+ enhanced *somehow*... Or else what would people think. */
+ tag_open = "<BLINK>", tag_close = "</BLINK>";
+ else if (!PL_strncasecmp ("BOLD>", old, 5))
+ tag_open = "<B>", tag_close = "</B>";
+ break;
+ case 'c': case 'C':
+ if (!PL_strncasecmp ("CENTER>", old, 7))
+ tag_open = "<CENTER>", tag_close = "</CENTER>";
+ else if (!enriched_p &&
+ !PL_strncasecmp ("COMMENT>", old, 8))
+ tag_open = "<!-- ", tag_close = " -->";
+ break;
+ case 'e': case 'E':
+ if (!PL_strncasecmp ("EXCERPT>", old, 8))
+ tag_open = "<BLOCKQUOTE>", tag_close = "</BLOCKQUOTE>";
+ break;
+ case 'f': case 'F':
+ if (!PL_strncasecmp ("FIXED>", old, 6))
+ tag_open = "<TT>", tag_close = "</TT>";
+ else if (enriched_p &&
+ !PL_strncasecmp ("FLUSHBOTH>", old, 10))
+ tag_open = "<P ALIGN=LEFT>", tag_close = "</P>";
+ else if (!PL_strncasecmp ("FLUSHLEFT>", old, 10))
+ tag_open = "<P ALIGN=LEFT>", tag_close = "</P>";
+ else if (!PL_strncasecmp ("FLUSHRIGHT>", old, 11))
+ tag_open = "<P ALIGN=RIGHT>", tag_close = "</P>";
+ else if (!enriched_p &&
+ !PL_strncasecmp ("FOOTING>", old, 8))
+ tag_open = "<H6>", tag_close = "</H6>";
+ break;
+ case 'h': case 'H':
+ if (!enriched_p &&
+ !PL_strncasecmp ("HEADING>", old, 8))
+ tag_open = "<H6>", tag_close = "</H6>";
+ break;
+ case 'i': case 'I':
+ if (!PL_strncasecmp ("INDENT>", old, 7))
+ tag_open = "<UL>", tag_close = "</UL>";
+ else if (!PL_strncasecmp ("INDENTRIGHT>", old, 12))
+ tag_open = 0, tag_close = 0;
+/* else if (!enriched_p &&
+ !PL_strncasecmp ("ISO-8859-", old, 9))
+ tag_open = 0, tag_close = 0; */
+ else if (!PL_strncasecmp ("ITALIC>", old, 7))
+ tag_open = "<I>", tag_close = "</I>";
+ break;
+ case 'l': case 'L':
+ if (!enriched_p &&
+ !PL_strncasecmp ("LT>", old, 3))
+ tag_open = "&lt;", tag_close = 0;
+ break;
+ case 'n': case 'N':
+ if (!enriched_p &&
+ !PL_strncasecmp ("NL>", old, 3))
+ tag_open = "<BR>", tag_close = 0;
+ if (enriched_p &&
+ !PL_strncasecmp ("NOFILL>", old, 7))
+ tag_open = "<NOBR>", tag_close = "</NOBR>";
+/* else if (!enriched_p &&
+ !PL_strncasecmp ("NO-OP>", old, 6))
+ tag_open = 0, tag_close = 0; */
+/* else if (!enriched_p &&
+ !PL_strncasecmp ("NP>", old, 3))
+ tag_open = 0, tag_close = 0; */
+ break;
+ case 'o': case 'O':
+ if (!enriched_p &&
+ !PL_strncasecmp ("OUTDENT>", old, 8))
+ tag_open = 0, tag_close = 0;
+ else if (!enriched_p &&
+ !PL_strncasecmp ("OUTDENTRIGHT>", old, 13))
+ tag_open = 0, tag_close = 0;
+ break;
+ case 'p': case 'P':
+ if (enriched_p &&
+ !PL_strncasecmp ("PARAM>", old, 6))
+ tag_open = "<!-- ", tag_close = " -->";
+ else if (!enriched_p &&
+ !PL_strncasecmp ("PARAGRAPH>", old, 10))
+ tag_open = "<P>", tag_close = 0;
+ break;
+ case 's': case 'S':
+ if (!enriched_p &&
+ !PL_strncasecmp ("SAMEPAGE>", old, 9))
+ tag_open = 0, tag_close = 0;
+ else if (!enriched_p &&
+ !PL_strncasecmp ("SIGNATURE>", old, 10))
+ tag_open = "<I><FONT SIZE=\"-1\">", tag_close = "</FONT></I>";
+ else if (!PL_strncasecmp ("SMALLER>", old, 8))
+ tag_open = "<FONT SIZE=\"-1\">", tag_close = "</FONT>";
+ else if (!enriched_p &&
+ !PL_strncasecmp ("SUBSCRIPT>", old, 10))
+ tag_open = "<SUB>", tag_close = "</SUB>";
+ else if (!enriched_p &&
+ !PL_strncasecmp ("SUPERSCRIPT>", old, 12))
+ tag_open = "<SUP>", tag_close = "</SUP>";
+ break;
+ case 'u': case 'U':
+ if (!PL_strncasecmp ("UNDERLINE>", old, 10))
+ tag_open = "<U>", tag_close = "</U>";
+/* else if (!enriched_p &&
+ !PL_strncasecmp ("US-ASCII>", old, 10))
+ tag_open = 0, tag_close = 0; */
+ break;
+ case 'v': case 'V':
+ if (enriched_p &&
+ !PL_strncasecmp ("VERBATIM>", old, 9))
+ tag_open = "<PRE>", tag_close = "</PRE>";
+ break;
+ }
+
+ if (this_start[1] == '/')
+ {
+ if (tag_close) PL_strncpyz (out, tag_close, outlen);
+ addedlen = strlen (out);
+ outlen -= addedlen;
+ out += addedlen;
+ }
+ else
+ {
+ if (tag_open) PL_strncpyz (out, tag_open, outlen);
+ addedlen = strlen (out);
+ outlen -= addedlen;
+ out += addedlen;
+ }
+ }
+
+ /* now go around again */
+ last_end = this_end;
+ this_start = last_end;
+ }
+ *out = 0;
+
+ return MimeObject_write(obj, *obufferP, out - *obufferP, true);
+}
+
+
+static int
+MimeInlineTextRichtext_parse_line (const char *line, int32_t length, MimeObject *obj)
+{
+ bool enriched_p = (((MimeInlineTextRichtextClass *) obj->clazz)
+ ->enriched_p);
+
+ return MimeRichtextConvert (line, length,
+ obj,
+ &obj->obuffer, &obj->obuffer_size,
+ enriched_p);
+}
+
+
+static int
+MimeInlineTextRichtext_parse_begin (MimeObject *obj)
+{
+ int status = ((MimeObjectClass*)&MIME_SUPERCLASS)->parse_begin(obj);
+ char s[] = "";
+ if (status < 0) return status;
+ return MimeObject_write(obj, s, 0, true); /* force out any separators... */
+}
+
+
+static int
+MimeInlineTextRichtext_parse_eof (MimeObject *obj, bool abort_p)
+{
+ int status;
+ 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;
+
+ return 0;
+}