/* -*- 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 #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: , , , - These tags were removed: , , , , , , , , , , , , This method implements them both. draft-resnick-text-enriched-03.txt is a proposed update to 1563. - These tags were added: , , , . However, all of these rely on the magic 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, "
", *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, "&", 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 */ old++; } switch (*old) { case 'b': case 'B': if (!PL_strncasecmp ("BIGGER>", old, 7)) tag_open = "", tag_close = ""; 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 = "", tag_close = ""; else if (!PL_strncasecmp ("BOLD>", old, 5)) tag_open = "", tag_close = ""; break; case 'c': case 'C': if (!PL_strncasecmp ("CENTER>", old, 7)) tag_open = "
", tag_close = "
"; else if (!enriched_p && !PL_strncasecmp ("COMMENT>", old, 8)) tag_open = ""; break; case 'e': case 'E': if (!PL_strncasecmp ("EXCERPT>", old, 8)) tag_open = "
", tag_close = "
"; break; case 'f': case 'F': if (!PL_strncasecmp ("FIXED>", old, 6)) tag_open = "", tag_close = ""; else if (enriched_p && !PL_strncasecmp ("FLUSHBOTH>", old, 10)) tag_open = "

", tag_close = "

"; else if (!PL_strncasecmp ("FLUSHLEFT>", old, 10)) tag_open = "

", tag_close = "

"; else if (!PL_strncasecmp ("FLUSHRIGHT>", old, 11)) tag_open = "

", tag_close = "

"; else if (!enriched_p && !PL_strncasecmp ("FOOTING>", old, 8)) tag_open = "
", tag_close = "
"; break; case 'h': case 'H': if (!enriched_p && !PL_strncasecmp ("HEADING>", old, 8)) tag_open = "
", tag_close = "
"; break; case 'i': case 'I': if (!PL_strncasecmp ("INDENT>", old, 7)) tag_open = "
    ", tag_close = "
"; 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 = "", tag_close = ""; 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 = "
", tag_close = 0; if (enriched_p && !PL_strncasecmp ("NOFILL>", old, 7)) tag_open = "", tag_close = ""; /* 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 = ""; else if (!enriched_p && !PL_strncasecmp ("PARAGRAPH>", old, 10)) tag_open = "

", 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 = "", tag_close = ""; else if (!PL_strncasecmp ("SMALLER>", old, 8)) tag_open = "", tag_close = ""; else if (!enriched_p && !PL_strncasecmp ("SUBSCRIPT>", old, 10)) tag_open = "", tag_close = ""; else if (!enriched_p && !PL_strncasecmp ("SUPERSCRIPT>", old, 12)) tag_open = "", tag_close = ""; break; case 'u': case 'U': if (!PL_strncasecmp ("UNDERLINE>", old, 10)) tag_open = "", tag_close = ""; /* 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 = "

", tag_close = "
"; 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; }