home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / lib / libmime / mimetext.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  10.0 KB  |  306 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. /* mimetext.c --- definition of the MimeInlineText class (see mimei.h)
  20.    Created: Jamie Zawinski <jwz@netscape.com>, 15-May-96.
  21.  */
  22.  
  23. #include "mimetext.h"
  24. #include "libi18n.h"
  25.  
  26. #define MIME_SUPERCLASS mimeLeafClass
  27. MimeDefClass(MimeInlineText, MimeInlineTextClass, mimeInlineTextClass,
  28.              &MIME_SUPERCLASS);
  29.  
  30. static int MimeInlineText_initialize (MimeObject *);
  31. static void MimeInlineText_finalize (MimeObject *);
  32. static int MimeInlineText_rot13_line (MimeObject *, char *line, int32 length);
  33. static int MimeInlineText_parse_eof (MimeObject *obj, XP_Bool abort_p);
  34. static int MimeInlineText_parse_end  (MimeObject *, XP_Bool);
  35. static int MimeInlineText_parse_decoded_buffer (char *, int32, MimeObject *);
  36. static int MimeInlineText_rotate_convert_and_parse_line(char *, int32,
  37.                                                         MimeObject *);
  38.  
  39. static int
  40. MimeInlineTextClassInitialize(MimeInlineTextClass *class)
  41. {
  42.   MimeObjectClass *oclass = (MimeObjectClass *) class;
  43.   MimeLeafClass   *lclass = (MimeLeafClass *) class;
  44.   XP_ASSERT(!oclass->class_initialized);
  45.   oclass->initialize           = MimeInlineText_initialize;
  46.   oclass->finalize             = MimeInlineText_finalize;
  47.   oclass->parse_eof               = MimeInlineText_parse_eof;
  48.   oclass->parse_end            = MimeInlineText_parse_end;
  49.   class->rot13_line            = MimeInlineText_rot13_line;
  50.   lclass->parse_decoded_buffer = MimeInlineText_parse_decoded_buffer;
  51.   return 0;
  52. }
  53.  
  54. static int
  55. MimeInlineText_initialize (MimeObject *obj)
  56. {
  57.   MimeInlineText *text = (MimeInlineText *) obj;
  58.  
  59.   /* This is an abstract class; it shouldn't be directly instanciated. */
  60.   XP_ASSERT(obj->class != (MimeObjectClass *) &mimeInlineTextClass);
  61.  
  62.   /* Figure out an appropriate charset for this object.
  63.    */
  64.   if (!text->charset && obj->headers)
  65.     {
  66.       if (obj->options && obj->options->override_charset)
  67.         {
  68.           text->charset = XP_STRDUP(obj->options->override_charset);
  69.         }
  70.       else
  71.         {
  72.           char *ct = MimeHeaders_get (obj->headers, HEADER_CONTENT_TYPE,
  73.                                       FALSE, FALSE);
  74.           if (ct)
  75.             {
  76.               text->charset = MimeHeaders_get_parameter (ct, "charset");
  77.               XP_FREE(ct);
  78.             }
  79.  
  80.           if (!text->charset)
  81.             {
  82.               /* If we didn't find "Content-Type: ...; charset=XX" then look
  83.                  for "X-Sun-Charset: XX" instead.  (Maybe this should be done
  84.                  in MimeSunAttachmentClass, but it's harder there than here.)
  85.                */
  86.               text->charset = MimeHeaders_get (obj->headers,
  87.                                                HEADER_X_SUN_CHARSET,
  88.                                                FALSE, FALSE);
  89.             }
  90.  
  91.           if (!text->charset)
  92.             {
  93.               if (obj->options && obj->options->default_charset)
  94.                 text->charset = XP_STRDUP(obj->options->default_charset);
  95.               /* Do not label US-ASCII if the app default charset is multibyte.
  96.                  Perhaps US-ASCII label should be removed for all cases.
  97.                */
  98.               else if (MULTIBYTE & INTL_DefaultDocCharSetID(0))
  99.                   ;
  100.               else
  101.                 text->charset = XP_STRDUP("US-ASCII");
  102.             }
  103.         }
  104.     }
  105.  
  106.   return ((MimeObjectClass*)&MIME_SUPERCLASS)->initialize(obj);
  107. }
  108.  
  109.  
  110. static void
  111. MimeInlineText_finalize (MimeObject *obj)
  112. {
  113.   MimeInlineText *text = (MimeInlineText *) obj;
  114.  
  115.   obj->class->parse_eof (obj, FALSE);
  116.   obj->class->parse_end (obj, FALSE);
  117.  
  118.   FREEIF(text->charset);
  119.  
  120.   /* Should have been freed by parse_eof, but just in case... */
  121.   XP_ASSERT(!text->cbuffer);
  122.   FREEIF (text->cbuffer);
  123.  
  124.   ((MimeObjectClass*)&MIME_SUPERCLASS)->finalize (obj);
  125. }
  126.  
  127.  
  128. static int
  129. MimeInlineText_parse_eof (MimeObject *obj, XP_Bool abort_p)
  130. {
  131.   if (obj->closed_p) return 0;
  132.   XP_ASSERT(!obj->parsed_p);
  133.  
  134.   /* If there is still data in the ibuffer, that means that the last line of
  135.      this part didn't end in a newline; so push it out anyway (this means that
  136.      the parse_line method will be called with a string with no trailing
  137.      newline, which isn't the usual case.)  We do this here, rather than in 
  138.      MimeObject_parse_eof, because MimeObject likes to shove things through
  139.      parse_line, and we have to shove it through the magic rotating-and-converting
  140.      code.  So, we do that and digest the buffer before MimeObject has a chance
  141.      to do the wrong thing.  See bug #26276 for more painful details.
  142.    */
  143.   if (!abort_p &&
  144.       obj->ibuffer_fp > 0)
  145.     {
  146.       int status = MimeInlineText_rotate_convert_and_parse_line (obj->ibuffer,
  147.                                                                    obj->ibuffer_fp,
  148.                                                                    obj);
  149.       obj->ibuffer_fp = 0;
  150.       if (status < 0)
  151.         {
  152.           obj->closed_p = TRUE;
  153.           return status;
  154.         }
  155.     }
  156.   return ((MimeObjectClass*)&MIME_SUPERCLASS)->parse_eof (obj, abort_p);
  157. }
  158.  
  159. static int
  160. MimeInlineText_parse_end (MimeObject *obj, XP_Bool abort_p)
  161. {
  162.   MimeInlineText *text = (MimeInlineText *) obj;
  163.  
  164.   if (obj->parsed_p)
  165.     {
  166.       XP_ASSERT(obj->closed_p);
  167.       return 0;
  168.     }
  169.  
  170.   /* We won't be needing this buffer any more; nuke it. */
  171.   FREEIF(text->cbuffer);
  172.   text->cbuffer_size = 0;
  173.  
  174.   return ((MimeObjectClass*)&MIME_SUPERCLASS)->parse_end (obj, abort_p);
  175. }
  176.  
  177.  
  178. /* This maps A-M to N-Z and N-Z to A-M.  All other characters are left alone.
  179.    (Comments in GNUS imply that for Japanese, one should rotate by 47?)
  180.  */
  181. static const unsigned char MimeInlineText_rot13_table[256] = {
  182.   0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
  183.   21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39,
  184.   40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58,
  185.   59, 60, 61, 62, 63, 64, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90,
  186.   65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 91, 92, 93, 94, 95, 96,
  187.   110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 97, 98,
  188.   99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 123, 124, 125, 126,
  189.   127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141,
  190.   142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156,
  191.   157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171,
  192.   172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186,
  193.   187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201,
  194.   202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216,
  195.   217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231,
  196.   232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246,
  197.   247, 248, 249, 250, 251, 252, 253, 254, 255 };
  198.  
  199. static int
  200. MimeInlineText_rot13_line (MimeObject *obj, char *line, int32 length)
  201. {
  202.   unsigned char *s, *end;
  203.   XP_ASSERT(line);
  204.   if (!line) return -1;
  205.   s = (unsigned char *) line;
  206.   end = s + length;
  207.   while (s < end)
  208.     {
  209.       *s = MimeInlineText_rot13_table[*s];
  210.       s++;
  211.     }
  212.   return 0;
  213. }
  214.  
  215.  
  216. static int
  217. MimeInlineText_parse_decoded_buffer (char *buf, int32 size, MimeObject *obj)
  218. {
  219.   XP_ASSERT(!obj->closed_p);
  220.   if (obj->closed_p) return -1;
  221.  
  222.   /* MimeLeaf takes care of this. */
  223.   XP_ASSERT(obj->output_p && obj->options && obj->options->output_fn);
  224.   if (!obj->options) return -1;
  225.  
  226.   /* If we're supposed to write this object, but aren't supposed to convert
  227.      it to HTML, simply pass it through unaltered. */
  228.   if (!obj->options->write_html_p)
  229.     return MimeObject_write(obj, buf, size, TRUE);
  230.  
  231.   /* This is just like the parse_decoded_buffer method we inherit from the
  232.      MimeLeaf class, except that we line-buffer to our own wrapper on the
  233.      `parse_line' method instead of calling the `parse_line' method directly.
  234.    */
  235.   return msg_LineBuffer (buf, size,
  236.                          &obj->ibuffer, &obj->ibuffer_size, &obj->ibuffer_fp,
  237.                          TRUE,
  238.                          ((int (*) (char *, int32, void *))
  239.                           /* This cast is to turn void into MimeObject */
  240.                           MimeInlineText_rotate_convert_and_parse_line),
  241.                          obj);
  242. }
  243.  
  244.  
  245. #define MimeInlineText_grow_cbuffer(text, desired_size) \
  246.   (((desired_size) >= (text)->cbuffer_size) ? \
  247.    msg_GrowBuffer ((desired_size), sizeof(char), 100, \
  248.                    &(text)->cbuffer, &(text)->cbuffer_size) \
  249.    : 0)
  250.  
  251.  
  252. static int
  253. MimeInlineText_rotate_convert_and_parse_line(char *line, int32 length,
  254.                                              MimeObject *obj)
  255. {
  256.   int status;
  257.   MimeInlineText *text = (MimeInlineText *) obj;
  258.   MimeInlineTextClass *textc = (MimeInlineTextClass *) obj->class;
  259.   char *converted = 0;
  260.  
  261.   XP_ASSERT(!obj->closed_p);
  262.   if (obj->closed_p) return -1;
  263.  
  264.   /* Rotate the line, if desired (this happens on the raw data, before any
  265.      charset conversion.) */
  266.   if (obj->options && obj->options->rot13_p)
  267.     {
  268.       status = textc->rot13_line(obj, line, length);
  269.       if (status < 0) return status;
  270.     }
  271.  
  272.   /* Now convert to the canonical charset, if desired.
  273.    */
  274.   if (obj->options && obj->options->charset_conversion_fn)
  275.     {
  276.       int32 converted_len = 0;
  277.       const char *output_charset = (obj->options->override_charset
  278.                                     ? obj->options->override_charset
  279.                                     : obj->options->default_charset);
  280.  
  281.       status = obj->options->charset_conversion_fn(line, length,
  282.                                                    text->charset,
  283.                                                    output_charset,
  284.                                                    &converted,
  285.                                                    &converted_len,
  286.                                                  obj->options->stream_closure);
  287.       if (status < 0)
  288.         {
  289.           FREEIF(converted);
  290.           return status;
  291.         }
  292.  
  293.       if (converted)
  294.         {
  295.           line = converted;
  296.           length = converted_len;
  297.         }
  298.     }
  299.  
  300.   /* Now that the line has been converted, call the subclass's parse_line
  301.      method with the decoded data. */
  302.   status = obj->class->parse_line(line, length, obj);
  303.   FREEIF(converted);
  304.   return status;
  305. }
  306.