/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- * * The contents of this file are subject to the Netscape Public * License Version 1.1 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.mozilla.org/NPL/ * * Software distributed under the License is distributed on an "AS * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or * implied. See the License for the specific language governing * rights and limitations under the License. * * The Original Code is mozilla.org code. * * The Initial Developer of the Original Code is Netscape * Communications Corporation. Portions created by Netscape are * Copyright (C) 1998 Netscape Communications Corporation. All * Rights Reserved. * * Contributor(s): */ /* mimetric.c --- definition of the MimeInlineTextRichtext class (see mimei.h) Created: Jamie Zawinski , 15-May-96. */ #include "rosetta.h" #include "mimetric.h" #define MIME_SUPERCLASS mimeInlineTextClass MimeDefClass(MimeInlineTextRichtext, MimeInlineTextRichtextClass, mimeInlineTextRichtextClass, &MIME_SUPERCLASS); static int MimeInlineTextRichtext_parse_line (char *, int32, MimeObject *); static int MimeInlineTextRichtext_parse_begin (MimeObject *); static int MimeInlineTextRichtext_parse_eof (MimeObject *, XP_Bool); static int MimeInlineTextRichtextClassInitialize(MimeInlineTextRichtextClass *class) { MimeObjectClass *oclass = (MimeObjectClass *) class; XP_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 (char *line, int32 length, int (*output_fn) (char *buf, int32 size, void *closure), void *closure, char **obufferP, uint32 *obuffer_sizeP, XP_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; int desired_size; desired_size = length * 4; if (desired_size >= *obuffer_sizeP) status = XP_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 (!XP_IS_SPACE (*this_start)) break; if (this_start >= line + length) /* blank line */ { XP_STRCPY (*obufferP, "
"); return output_fn (*obufferP, XP_STRLEN(*obufferP), closure); } } out = *obufferP; *out = 0; data_end = line + length; last_end = line; this_start = last_end; this_end = this_start; 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 && !XP_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) { XP_MEMCPY (out, last_end, this_start - last_end); out += this_start - last_end; *out = 0; } if (this_start >= data_end) break; else if (*this_start == '&') { XP_STRCPY (out, "&"); out += XP_STRLEN (out); } else if (*this_start == '>') { XP_STRCPY (out, ">"); out += XP_STRLEN (out); } else if (enriched_p && this_start < data_end + 1 && this_start[0] == '<' && this_start[1] == '<') { XP_STRCPY (out, "<"); out += XP_STRLEN (out); } else if (this_start != this_end) { /* Push out this ID. */ const char *old = this_start + 1; char *tag_open = 0; char *tag_close = 0; if (*old == '/') { /* This is */ old++; } switch (*old) { case 'b': case 'B': if (!strncasecomp ("BIGGER>", old, 7)) tag_open = "", tag_close = ""; else if (!strncasecomp ("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 (!strncasecomp ("BOLD>", old, 5)) tag_open = "", tag_close = ""; break; case 'c': case 'C': if (!strncasecomp ("CENTER>", old, 7)) tag_open = "
", tag_close = "
"; else if (!enriched_p && !strncasecomp ("COMMENT>", old, 8)) tag_open = ""; break; case 'e': case 'E': if (!strncasecomp ("EXCERPT>", old, 8)) tag_open = "
", tag_close = "
"; break; case 'f': case 'F': if (!strncasecomp ("FIXED>", old, 6)) tag_open = "", tag_close = ""; else if (enriched_p && !strncasecomp ("FLUSHBOTH>", old, 10)) tag_open = "

", tag_close = "

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

", tag_close = "

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

", tag_close = "

"; else if (!enriched_p && !strncasecomp ("FOOTING>", old, 8)) tag_open = "
", tag_close = "
"; break; case 'h': case 'H': if (!enriched_p && !strncasecomp ("HEADING>", old, 8)) tag_open = "
", tag_close = "
"; break; case 'i': case 'I': if (!strncasecomp ("INDENT>", old, 7)) tag_open = "
    ", tag_close = "
"; else if (!strncasecomp ("INDENTRIGHT>", old, 12)) tag_open = 0, tag_close = 0; /* else if (!enriched_p && !strncasecomp ("ISO-8859-", old, 9)) tag_open = 0, tag_close = 0; */ else if (!strncasecomp ("ITALIC>", old, 7)) tag_open = "", tag_close = ""; break; case 'l': case 'L': if (!enriched_p && !strncasecomp ("LT>", old, 3)) tag_open = "<", tag_close = 0; break; case 'n': case 'N': if (!enriched_p && !strncasecomp ("NL>", old, 3)) tag_open = "
", tag_close = 0; if (enriched_p && !strncasecomp ("NOFILL>", old, 7)) tag_open = "", tag_close = ""; /* else if (!enriched_p && !strncasecomp ("NO-OP>", old, 6)) tag_open = 0, tag_close = 0; */ /* else if (!enriched_p && !strncasecomp ("NP>", old, 3)) tag_open = 0, tag_close = 0; */ break; case 'o': case 'O': if (!enriched_p && !strncasecomp ("OUTDENT>", old, 8)) tag_open = 0, tag_close = 0; else if (!enriched_p && !strncasecomp ("OUTDENTRIGHT>", old, 13)) tag_open = 0, tag_close = 0; break; case 'p': case 'P': if (enriched_p && !strncasecomp ("PARAM>", old, 6)) tag_open = ""; else if (!enriched_p && !strncasecomp ("PARAGRAPH>", old, 10)) tag_open = "

", tag_close = 0; break; case 's': case 'S': if (!enriched_p && !strncasecomp ("SAMEPAGE>", old, 9)) tag_open = 0, tag_close = 0; else if (!enriched_p && !strncasecomp ("SIGNATURE>", old, 10)) tag_open = "", tag_close = ""; else if (!strncasecomp ("SMALLER>", old, 8)) tag_open = "", tag_close = ""; else if (!enriched_p && !strncasecomp ("SUBSCRIPT>", old, 10)) tag_open = "", tag_close = ""; else if (!enriched_p && !strncasecomp ("SUPERSCRIPT>", old, 12)) tag_open = "", tag_close = ""; break; case 'u': case 'U': if (!strncasecomp ("UNDERLINE>", old, 10)) tag_open = "", tag_close = ""; /* else if (!enriched_p && !strncasecomp ("US-ASCII>", old, 10)) tag_open = 0, tag_close = 0; */ break; case 'v': case 'V': if (enriched_p && !strncasecomp ("VERBATIM>", old, 9)) tag_open = "

", tag_close = "
"; break; } if (this_start[1] == '/') { if (tag_close) XP_STRCPY (out, tag_close); out += XP_STRLEN (out); } else { if (tag_open) XP_STRCPY (out, tag_open); out += XP_STRLEN (out); } } /* now go around again */ last_end = this_end; this_start = last_end; } *out = 0; return output_fn (*obufferP, out - *obufferP, closure); } static int MimeInlineTextRichtext_parse_line (char *line, int32 length, MimeObject *obj) { XP_Bool enriched_p = (((MimeInlineTextRichtextClass *) obj->class) ->enriched_p); return MimeRichtextConvert (line, length, obj->options->output_fn, obj->options->stream_closure, &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... */ } /* This method is largely the same as that of MimeInlineTextHTML; maybe that means that MimeInlineTextRichtext and MimeInlineTextEnriched should share a common parent with it which is not also shared by MimeInlineTextPlain? */ static int MimeInlineTextRichtext_parse_eof (MimeObject *obj, XP_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; if (obj->options && obj->options->write_html_p && obj->options->set_html_state_fn) { return obj->options->set_html_state_fn(obj->options->stream_closure, FALSE, /* layer_encapulate_p */ FALSE, /* start_p */ abort_p); } return 0; }