diff options
Diffstat (limited to '')
-rw-r--r-- | comm/mailnews/mime/src/mimetric.cpp | 356 |
1 files changed, 356 insertions, 0 deletions
diff --git a/comm/mailnews/mime/src/mimetric.cpp b/comm/mailnews/mime/src/mimetric.cpp new file mode 100644 index 0000000000..79eedea75d --- /dev/null +++ b/comm/mailnews/mime/src/mimetric.cpp @@ -0,0 +1,356 @@ +/* -*- 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/. */ +#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 superseded 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 preceding 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, "&", outlen); + addedlen = strlen(out); + outlen -= addedlen; + out += addedlen; + } else if (*this_start == '>') { + PL_strncpyz(out, ">", 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, "<", 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, 6)) + // 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=JUSTIFY>"; + 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 (!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 = "<"; + 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>"; + } + 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>"; + } + 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; +} |