home *** CD-ROM | disk | FTP | other *** search
- /* -*- 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.0 (the "NPL"); you may not use this file except in
- * compliance with the NPL. You may obtain a copy of the NPL at
- * http://www.mozilla.org/NPL/
- *
- * Software distributed under the NPL is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
- * for the specific language governing rights and limitations under the
- * NPL.
- *
- * The Initial Developer of this code under the NPL is Netscape
- * Communications Corporation. Portions created by Netscape are
- * Copyright (C) 1998 Netscape Communications Corporation. All Rights
- * Reserved.
- */
-
- /* mimetric.c --- definition of the MimeInlineTextRichtext class (see mimei.h)
- Created: Jamie Zawinski <jwz@netscape.com>, 15-May-96.
- */
-
- #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,
- int32 *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:
- <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;
- int desired_size;
-
- desired_size = length * 4;
- if (desired_size >= *obuffer_sizeP)
- status = msg_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, "<BR>");
- 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 </tag> */
- old++;
- }
-
- switch (*old)
- {
- case 'b': case 'B':
- if (!strncasecomp ("BIGGER>", old, 7))
- tag_open = "<FONT SIZE=\"+1\">", tag_close = "</FONT>";
- 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 = "<BLINK>", tag_close = "</BLINK>";
- else if (!strncasecomp ("BOLD>", old, 5))
- tag_open = "<B>", tag_close = "</B>";
- break;
- case 'c': case 'C':
- if (!strncasecomp ("CENTER>", old, 7))
- tag_open = "<CENTER>", tag_close = "</CENTER>";
- else if (!enriched_p &&
- !strncasecomp ("COMMENT>", old, 8))
- tag_open = "<!-- ", tag_close = " -->";
- break;
- case 'e': case 'E':
- if (!strncasecomp ("EXCERPT>", old, 8))
- tag_open = "<BLOCKQUOTE>", tag_close = "</BLOCKQUOTE>";
- break;
- case 'f': case 'F':
- if (!strncasecomp ("FIXED>", old, 6))
- tag_open = "<TT>", tag_close = "</TT>";
- else if (enriched_p &&
- !strncasecomp ("FLUSHBOTH>", old, 10))
- tag_open = "<P ALIGN=LEFT>", tag_close = "</P>";
- else if (!strncasecomp ("FLUSHLEFT>", old, 10))
- tag_open = "<P ALIGN=LEFT>", tag_close = "</P>";
- else if (!strncasecomp ("FLUSHRIGHT>", old, 11))
- tag_open = "<P ALIGN=RIGHT>", tag_close = "</P>";
- else if (!enriched_p &&
- !strncasecomp ("FOOTING>", old, 8))
- tag_open = "<H6>", tag_close = "</H6>";
- break;
- case 'h': case 'H':
- if (!enriched_p &&
- !strncasecomp ("HEADING>", old, 8))
- tag_open = "<H6>", tag_close = "</H6>";
- break;
- case 'i': case 'I':
- if (!strncasecomp ("INDENT>", old, 7))
- tag_open = "<UL>", tag_close = "</UL>";
- 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 = "<I>", tag_close = "</I>";
- 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 = "<BR>", tag_close = 0;
- if (enriched_p &&
- !strncasecomp ("NOFILL>", old, 7))
- tag_open = "<NOBR>", tag_close = "</NOBR>";
- /* 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 = "<!-- ", tag_close = " -->";
- else if (!enriched_p &&
- !strncasecomp ("PARAGRAPH>", old, 10))
- tag_open = "<P>", 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 = "<I><FONT SIZE=\"-1\">", tag_close = "</FONT></I>";
- else if (!strncasecomp ("SMALLER>", old, 8))
- tag_open = "<FONT SIZE=\"-1\">", tag_close = "</FONT>";
- else if (!enriched_p &&
- !strncasecomp ("SUBSCRIPT>", old, 10))
- tag_open = "<SUB>", tag_close = "</SUB>";
- else if (!enriched_p &&
- !strncasecomp ("SUPERSCRIPT>", old, 12))
- tag_open = "<SUP>", tag_close = "</SUP>";
- break;
- case 'u': case 'U':
- if (!strncasecomp ("UNDERLINE>", old, 10))
- tag_open = "<U>", tag_close = "</U>";
- /* 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 = "<PRE>", tag_close = "</PRE>";
- 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;
- }
-