/* -*- 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 #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: , , , - 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 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 */ old++; } switch (*old) { case 'b': case 'B': if (!PL_strncasecmp("BIGGER>", old, 7)) { tag_open = ""; tag_close = ""; } 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 = ""; 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 (!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 = ""; } 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 = ""; } 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; }