home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / lib / libmime / mimetric.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  11.3 KB  |  359 lines

  1. /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  2.  *
  3.  * The contents of this file are subject to the Netscape Public License
  4.  * Version 1.0 (the "NPL"); you may not use this file except in
  5.  * compliance with the NPL.  You may obtain a copy of the NPL at
  6.  * http://www.mozilla.org/NPL/
  7.  *
  8.  * Software distributed under the NPL is distributed on an "AS IS" basis,
  9.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
  10.  * for the specific language governing rights and limitations under the
  11.  * NPL.
  12.  *
  13.  * The Initial Developer of this code under the NPL is Netscape
  14.  * Communications Corporation.  Portions created by Netscape are
  15.  * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
  16.  * Reserved.
  17.  */
  18.  
  19. /* mimetric.c --- definition of the MimeInlineTextRichtext class (see mimei.h)
  20.    Created: Jamie Zawinski <jwz@netscape.com>, 15-May-96.
  21.  */
  22.  
  23. #include "mimetric.h"
  24.  
  25. #define MIME_SUPERCLASS mimeInlineTextClass
  26. MimeDefClass(MimeInlineTextRichtext, MimeInlineTextRichtextClass,
  27.              mimeInlineTextRichtextClass, &MIME_SUPERCLASS);
  28.  
  29. static int MimeInlineTextRichtext_parse_line (char *, int32, MimeObject *);
  30. static int MimeInlineTextRichtext_parse_begin (MimeObject *);
  31. static int MimeInlineTextRichtext_parse_eof (MimeObject *, XP_Bool);
  32.  
  33. static int
  34. MimeInlineTextRichtextClassInitialize(MimeInlineTextRichtextClass *class)
  35. {
  36.   MimeObjectClass *oclass = (MimeObjectClass *) class;
  37.   XP_ASSERT(!oclass->class_initialized);
  38.   oclass->parse_begin = MimeInlineTextRichtext_parse_begin;
  39.   oclass->parse_line  = MimeInlineTextRichtext_parse_line;
  40.   oclass->parse_eof   = MimeInlineTextRichtext_parse_eof;
  41.   return 0;
  42. }
  43.  
  44. /* This function has this clunky interface because it needs to be called
  45.    from outside this module (no MimeObject, etc.)
  46.  */
  47. int
  48. MimeRichtextConvert (char *line, int32 length,
  49.                      int (*output_fn) (char *buf, int32 size, void *closure),
  50.                      void *closure,
  51.                      char **obufferP,
  52.                      int32 *obuffer_sizeP,
  53.                      XP_Bool enriched_p)
  54. {
  55.   /* RFC 1341 (the original MIME spec) defined text/richtext.
  56.      RFC 1563 superceded text/richtext with text/enriched.
  57.      The changes from text/richtext to text/enriched are:
  58.       - CRLF semantics are different
  59.       - << maps to <
  60.       - These tags were added:
  61.          <VERBATIM>, <NOFILL>, <PARAM>, <FLUSHBOTH>
  62.       - These tags were removed:
  63.          <COMMENT>, <OUTDENT>, <OUTDENTRIGHT>, <SAMEPAGE>, <SUBSCRIPT>,
  64.          <SUPERSCRIPT>, <HEADING>, <FOOTING>, <PARAGRAPH>, <SIGNATURE>,
  65.          <LT>, <NL>, <NP>
  66.      This method implements them both.
  67.  
  68.      draft-resnick-text-enriched-03.txt is a proposed update to 1563.
  69.       - These tags were added:
  70.         <FONTFAMILY>, <COLOR>, <PARAINDENT>, <LANG>.
  71.         However, all of these rely on the magic <PARAM> tag, which we
  72.         don't implement, so we're ignoring all of these.
  73.      Interesting fact: it's by Peter W. Resnick from Qualcomm (Eudora).
  74.      And it also says "It is fully expected that other text formatting
  75.      standards like HTML and SGML will supplant text/enriched in
  76.      Internet mail."
  77.    */
  78.   int status = 0;
  79.   char *out;
  80.   const char *data_end;
  81.   const char *last_end;
  82.   const char *this_start;
  83.   const char *this_end;
  84.   int desired_size;
  85.  
  86.   desired_size = length * 4;
  87.   if (desired_size >= *obuffer_sizeP)
  88.     status = msg_GrowBuffer (desired_size, sizeof(char), 1024,
  89.                              obufferP, obuffer_sizeP);
  90.   if (status < 0) return status;
  91.  
  92.   if (enriched_p)
  93.     {
  94.       for (this_start = line; this_start < line + length; this_start++)
  95.         if (!XP_IS_SPACE (*this_start)) break;
  96.       if (this_start >= line + length) /* blank line */
  97.         {
  98.           XP_STRCPY (*obufferP, "<BR>");
  99.           return output_fn (*obufferP, XP_STRLEN(*obufferP), closure);
  100.         }
  101.     }
  102.  
  103.   out = *obufferP;
  104.   *out = 0;
  105.  
  106.   data_end = line + length;
  107.   last_end = line;
  108.   this_start = last_end;
  109.   this_end = this_start;
  110.   while (this_end < data_end)
  111.     {
  112.       /* Skip forward to next special character. */
  113.       while (this_start < data_end &&
  114.              *this_start != '<' && *this_start != '>' &&
  115.              *this_start != '&')
  116.         this_start++;
  117.  
  118.       this_end = this_start;
  119.  
  120.       /* Skip to the end of the tag. */
  121.       if (this_start < data_end && *this_start == '<')
  122.         {
  123.           this_end++;
  124.           while (this_end < data_end &&
  125.                  !XP_IS_SPACE (*this_end) &&
  126.                  *this_end != '<' && *this_end != '>' &&
  127.                  *this_end != '&')
  128.             this_end++;
  129.         }
  130.  
  131.       this_end++;
  132.  
  133.       /* Push out the text preceeding the tag. */
  134.       if (last_end && last_end != this_start)
  135.         {
  136.           XP_MEMCPY (out, last_end, this_start - last_end);
  137.           out += this_start - last_end;
  138.           *out = 0;
  139.         }
  140.  
  141.       if (this_start >= data_end)
  142.         break;
  143.       else if (*this_start == '&')
  144.         {
  145.           XP_STRCPY (out, "&"); out += XP_STRLEN (out);
  146.         }
  147.       else if (*this_start == '>')
  148.         {
  149.           XP_STRCPY (out, ">"); out += XP_STRLEN (out);
  150.         }
  151.       else if (enriched_p &&
  152.                this_start < data_end + 1 &&
  153.                this_start[0] == '<' &&
  154.                this_start[1] == '<')
  155.         {
  156.           XP_STRCPY (out, "<"); out += XP_STRLEN (out);
  157.         }
  158.       else if (this_start != this_end)
  159.         {
  160.           /* Push out this ID. */
  161.           const char *old = this_start + 1;
  162.           char *tag_open  = 0;
  163.           char *tag_close = 0;
  164.           if (*old == '/')
  165.             {
  166.               /* This is </tag> */
  167.               old++;
  168.             }
  169.  
  170.           switch (*old)
  171.             {
  172.             case 'b': case 'B':
  173.               if (!strncasecomp ("BIGGER>", old, 7))
  174.                 tag_open = "<FONT SIZE=\"+1\">", tag_close = "</FONT>";
  175.               else if (!strncasecomp ("BLINK>", old, 5))
  176.                 /* Of course, both text/richtext and text/enriched must be
  177.                    enhanced *somehow*...  Or else what would people think. */
  178.                 tag_open = "<BLINK>", tag_close = "</BLINK>";
  179.               else if (!strncasecomp ("BOLD>", old, 5))
  180.                 tag_open = "<B>", tag_close = "</B>";
  181.               break;
  182.             case 'c': case 'C':
  183.               if (!strncasecomp ("CENTER>", old, 7))
  184.                 tag_open = "<CENTER>", tag_close = "</CENTER>";
  185.               else if (!enriched_p &&
  186.                        !strncasecomp ("COMMENT>", old, 8))
  187.                 tag_open = "<!-- ", tag_close = " -->";
  188.               break;
  189.             case 'e': case 'E':
  190.               if (!strncasecomp ("EXCERPT>", old, 8))
  191.                 tag_open = "<BLOCKQUOTE>", tag_close = "</BLOCKQUOTE>";
  192.               break;
  193.             case 'f': case 'F':
  194.               if (!strncasecomp ("FIXED>", old, 6))
  195.                 tag_open = "<TT>", tag_close = "</TT>";
  196.               else if (enriched_p &&
  197.                        !strncasecomp ("FLUSHBOTH>", old, 10))
  198.                 tag_open = "<P ALIGN=LEFT>", tag_close = "</P>";
  199.               else if (!strncasecomp ("FLUSHLEFT>", old, 10))
  200.                 tag_open = "<P ALIGN=LEFT>", tag_close = "</P>";
  201.               else if (!strncasecomp ("FLUSHRIGHT>", old, 11))
  202.                 tag_open = "<P ALIGN=RIGHT>", tag_close = "</P>";
  203.               else if (!enriched_p &&
  204.                        !strncasecomp ("FOOTING>", old, 8))
  205.                 tag_open = "<H6>", tag_close = "</H6>";
  206.               break;
  207.             case 'h': case 'H':
  208.               if (!enriched_p &&
  209.                   !strncasecomp ("HEADING>", old, 8))
  210.                 tag_open = "<H6>", tag_close = "</H6>";
  211.               break;
  212.             case 'i': case 'I':
  213.               if (!strncasecomp ("INDENT>", old, 7))
  214.                 tag_open = "<UL>", tag_close = "</UL>";
  215.               else if (!strncasecomp ("INDENTRIGHT>", old, 12))
  216.                 tag_open = 0, tag_close = 0;
  217. /*              else if (!enriched_p &&
  218.                        !strncasecomp ("ISO-8859-", old, 9))
  219.                 tag_open = 0, tag_close = 0; */
  220.               else if (!strncasecomp ("ITALIC>", old, 7))
  221.                 tag_open = "<I>", tag_close = "</I>";
  222.               break;
  223.             case 'l': case 'L':
  224.               if (!enriched_p &&
  225.                   !strncasecomp ("LT>", old, 3))
  226.                 tag_open = "<", tag_close = 0;
  227.               break;
  228.             case 'n': case 'N':
  229.               if (!enriched_p &&
  230.                   !strncasecomp ("NL>", old, 3))
  231.                 tag_open = "<BR>", tag_close = 0;
  232.               if (enriched_p &&
  233.                   !strncasecomp ("NOFILL>", old, 7))
  234.                 tag_open = "<NOBR>", tag_close = "</NOBR>";
  235. /*              else if (!enriched_p &&
  236.                        !strncasecomp ("NO-OP>", old, 6))
  237.                 tag_open = 0, tag_close = 0; */
  238. /*              else if (!enriched_p &&
  239.                        !strncasecomp ("NP>", old, 3))
  240.                 tag_open = 0, tag_close = 0; */
  241.               break;
  242.             case 'o': case 'O':
  243.               if (!enriched_p &&
  244.                   !strncasecomp ("OUTDENT>", old, 8))
  245.                 tag_open = 0, tag_close = 0;
  246.               else if (!enriched_p &&
  247.                        !strncasecomp ("OUTDENTRIGHT>", old, 13))
  248.                 tag_open = 0, tag_close = 0;
  249.               break;
  250.             case 'p': case 'P':
  251.               if (enriched_p &&
  252.                   !strncasecomp ("PARAM>", old, 6))
  253.                 tag_open = "<!-- ", tag_close = " -->";
  254.               else if (!enriched_p &&
  255.                        !strncasecomp ("PARAGRAPH>", old, 10))
  256.                 tag_open = "<P>", tag_close = 0;
  257.               break;
  258.             case 's': case 'S':
  259.               if (!enriched_p &&
  260.                   !strncasecomp ("SAMEPAGE>", old, 9))
  261.                 tag_open = 0, tag_close = 0;
  262.               else if (!enriched_p &&
  263.                        !strncasecomp ("SIGNATURE>", old, 10))
  264.                 tag_open = "<I><FONT SIZE=\"-1\">", tag_close = "</FONT></I>";
  265.               else if (!strncasecomp ("SMALLER>", old, 8))
  266.                 tag_open = "<FONT SIZE=\"-1\">", tag_close = "</FONT>";
  267.               else if (!enriched_p &&
  268.                        !strncasecomp ("SUBSCRIPT>", old, 10))
  269.                 tag_open = "<SUB>", tag_close = "</SUB>";
  270.               else if (!enriched_p &&
  271.                        !strncasecomp ("SUPERSCRIPT>", old, 12))
  272.                 tag_open = "<SUP>", tag_close = "</SUP>";
  273.               break;
  274.             case 'u': case 'U':
  275.               if (!strncasecomp ("UNDERLINE>", old, 10))
  276.                 tag_open = "<U>", tag_close = "</U>";
  277. /*              else if (!enriched_p &&
  278.                        !strncasecomp ("US-ASCII>", old, 10))
  279.                 tag_open = 0, tag_close = 0; */
  280.               break;
  281.             case 'v': case 'V':
  282.               if (enriched_p &&
  283.                   !strncasecomp ("VERBATIM>", old, 9))
  284.                 tag_open = "<PRE>", tag_close = "</PRE>";
  285.               break;
  286.             }
  287.  
  288.           if (this_start[1] == '/')
  289.             {
  290.               if (tag_close) XP_STRCPY (out, tag_close);
  291.               out += XP_STRLEN (out);
  292.             }
  293.           else
  294.             {
  295.               if (tag_open) XP_STRCPY (out, tag_open);
  296.               out += XP_STRLEN (out);
  297.             }
  298.         }
  299.  
  300.       /* now go around again */
  301.       last_end = this_end;
  302.       this_start = last_end;
  303.     }
  304.   *out = 0;
  305.  
  306.   return output_fn (*obufferP, out - *obufferP, closure);
  307. }
  308.  
  309.  
  310. static int
  311. MimeInlineTextRichtext_parse_line (char *line, int32 length, MimeObject *obj)
  312. {
  313.   XP_Bool enriched_p = (((MimeInlineTextRichtextClass *) obj->class)
  314.                         ->enriched_p);
  315.  
  316.   return MimeRichtextConvert (line, length,
  317.                               obj->options->output_fn,
  318.                               obj->options->stream_closure,
  319.                               &obj->obuffer, &obj->obuffer_size,
  320.                               enriched_p);
  321. }
  322.  
  323.  
  324. static int
  325. MimeInlineTextRichtext_parse_begin (MimeObject *obj)
  326. {
  327.   int status = ((MimeObjectClass*)&MIME_SUPERCLASS)->parse_begin(obj);
  328.   char s[] = "";
  329.   if (status < 0) return status;
  330.   return MimeObject_write(obj, s, 0, TRUE); /* force out any separators... */
  331. }
  332.  
  333.  
  334. /* This method is largely the same as that of MimeInlineTextHTML; maybe that
  335.    means that MimeInlineTextRichtext and MimeInlineTextEnriched should share
  336.    a common parent with it which is not also shared by MimeInlineTextPlain?
  337.  */
  338. static int
  339. MimeInlineTextRichtext_parse_eof (MimeObject *obj, XP_Bool abort_p)
  340. {
  341.   int status;
  342.   if (obj->closed_p) return 0;
  343.  
  344.   /* Run parent method first, to flush out any buffered data. */
  345.   status = ((MimeObjectClass*)&MIME_SUPERCLASS)->parse_eof(obj, abort_p);
  346.   if (status < 0) return status;
  347.  
  348.   if (obj->options &&
  349.       obj->options->write_html_p &&
  350.       obj->options->set_html_state_fn)
  351.     {
  352.       return obj->options->set_html_state_fn(obj->options->stream_closure,
  353.                                                  FALSE, /* layer_encapulate_p */
  354.                                                  FALSE, /* start_p */
  355.                                                  abort_p);
  356.     }
  357.   return 0;
  358. }
  359.