home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / lib / libmime / mimemalt.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  9.9 KB  |  327 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. /* mimemalt.c --- definition of the MimeMultipartAlternative class (see mimei.h)
  20.    Created: Jamie Zawinski <jwz@netscape.com>, 15-May-96.
  21.  */
  22.  
  23. #include "mimemalt.h"
  24.  
  25. #define MIME_SUPERCLASS mimeMultipartClass
  26. MimeDefClass(MimeMultipartAlternative, MimeMultipartAlternativeClass,
  27.              mimeMultipartAlternativeClass, &MIME_SUPERCLASS);
  28.  
  29. static int MimeMultipartAlternative_initialize (MimeObject *);
  30. static void MimeMultipartAlternative_finalize (MimeObject *);
  31. static int MimeMultipartAlternative_parse_eof (MimeObject *, XP_Bool);
  32. static int MimeMultipartAlternative_create_child(MimeObject *);
  33. static int MimeMultipartAlternative_parse_child_line (MimeObject *, char *,
  34.                                                       int32, XP_Bool);
  35. static int MimeMultipartAlternative_close_child(MimeObject *);
  36.  
  37. static XP_Bool MimeMultipartAlternative_display_part_p(MimeObject *self,
  38.                                                        MimeHeaders *sub_hdrs);
  39. static int MimeMultipartAlternative_discard_cached_part(MimeObject *);
  40. static int MimeMultipartAlternative_display_cached_part(MimeObject *);
  41.  
  42. static int
  43. MimeMultipartAlternativeClassInitialize(MimeMultipartAlternativeClass *class)
  44. {
  45.   MimeObjectClass    *oclass = (MimeObjectClass *)    class;
  46.   MimeMultipartClass *mclass = (MimeMultipartClass *) class;
  47.   XP_ASSERT(!oclass->class_initialized);
  48.   oclass->initialize       = MimeMultipartAlternative_initialize;
  49.   oclass->finalize         = MimeMultipartAlternative_finalize;
  50.   oclass->parse_eof        = MimeMultipartAlternative_parse_eof;
  51.   mclass->create_child     = MimeMultipartAlternative_create_child;
  52.   mclass->parse_child_line = MimeMultipartAlternative_parse_child_line;
  53.   mclass->close_child      = MimeMultipartAlternative_close_child;
  54.   return 0;
  55. }
  56.  
  57.  
  58. static int
  59. MimeMultipartAlternative_initialize (MimeObject *obj)
  60. {
  61.   MimeMultipartAlternative *malt = (MimeMultipartAlternative *) obj;
  62.  
  63.   XP_ASSERT(!malt->part_buffer);
  64.   malt->part_buffer = MimePartBufferCreate();
  65.   if (!malt->part_buffer)
  66.     return MK_OUT_OF_MEMORY;
  67.  
  68.   return ((MimeObjectClass*)&MIME_SUPERCLASS)->initialize(obj);
  69. }
  70.  
  71. static void
  72. MimeMultipartAlternative_cleanup(MimeObject *obj)
  73. {
  74.   MimeMultipartAlternative *malt = (MimeMultipartAlternative *) obj;
  75.   if (malt->buffered_hdrs)
  76.     {
  77.       MimeHeaders_free(malt->buffered_hdrs);
  78.       malt->buffered_hdrs = 0;
  79.     }
  80.   if (malt->part_buffer)
  81.     {
  82.       MimePartBufferDestroy(malt->part_buffer);
  83.       malt->part_buffer = 0;
  84.     }
  85. }
  86.  
  87.  
  88. static void
  89. MimeMultipartAlternative_finalize (MimeObject *obj)
  90. {
  91.   MimeMultipartAlternative_cleanup(obj);
  92.   ((MimeObjectClass*)&MIME_SUPERCLASS)->finalize(obj);
  93. }
  94.  
  95.  
  96. static int
  97. MimeMultipartAlternative_parse_eof (MimeObject *obj, XP_Bool abort_p)
  98. {
  99.   MimeMultipartAlternative *malt = (MimeMultipartAlternative *) obj;
  100.   int status = 0;
  101.  
  102.   if (obj->closed_p) return 0;
  103.  
  104.   status = ((MimeObjectClass*)&MIME_SUPERCLASS)->parse_eof(obj, abort_p);
  105.   if (status < 0) return status;
  106.  
  107.   /* If there's a cached part we haven't written out yet, do it now.
  108.    */
  109.   if (malt->buffered_hdrs && !abort_p)
  110.     {
  111.       status = MimeMultipartAlternative_display_cached_part(obj);
  112.       if (status < 0) return status;
  113.     }
  114.  
  115.   MimeMultipartAlternative_cleanup(obj);
  116.  
  117.   return status;
  118. }
  119.  
  120.  
  121. static int
  122. MimeMultipartAlternative_create_child(MimeObject *obj)
  123. {
  124.   MimeMultipart *mult = (MimeMultipart *) obj;
  125.   MimeMultipartAlternative *malt = (MimeMultipartAlternative *) obj;
  126.  
  127.   if (MimeMultipartAlternative_display_part_p (obj, mult->hdrs))
  128.     {
  129.       /* If this part is potentially displayable, begin populating the cache
  130.          with it.  If there's something in the cache already, discard it
  131.          first.  (Just because this part is displayable doesn't mean we will
  132.          display it -- of two consecutive displayable parts, it is the second
  133.          one that gets displayed.)
  134.        */
  135.       int status;
  136.       mult->state = MimeMultipartPartFirstLine;
  137.  
  138.       status = MimeMultipartAlternative_discard_cached_part(obj);
  139.       if (status < 0) return status;
  140.  
  141.       XP_ASSERT(!malt->buffered_hdrs);
  142.       malt->buffered_hdrs = MimeHeaders_copy(mult->hdrs);
  143.       if (!malt->buffered_hdrs) return MK_OUT_OF_MEMORY;
  144.       return 0;
  145.     }
  146.   else
  147.     {
  148.       /* If this part is not displayable, then we're done -- all that is left
  149.          to do is to flush out the part that is currently in the cache.
  150.        */
  151.       mult->state = MimeMultipartEpilogue;
  152.       return MimeMultipartAlternative_display_cached_part(obj);
  153.     }
  154. }
  155.  
  156.  
  157. static int
  158. MimeMultipartAlternative_parse_child_line (MimeObject *obj,
  159.                                            char *line, int32 length,
  160.                                            XP_Bool first_line_p)
  161. {
  162.   MimeMultipartAlternative *malt = (MimeMultipartAlternative *) obj;
  163.  
  164.   XP_ASSERT(malt->part_buffer);
  165.   if (!malt->part_buffer) return -1;
  166.  
  167.   /* Push this line into the buffer for later retrieval. */
  168.   return MimePartBufferWrite (malt->part_buffer, line, length);
  169. }
  170.  
  171.  
  172. static int
  173. MimeMultipartAlternative_close_child(MimeObject *obj)
  174. {
  175.   MimeMultipart *mult = (MimeMultipart *) obj;
  176.   MimeMultipartAlternative *malt = (MimeMultipartAlternative *) obj;
  177.  
  178.   /* XP_ASSERT(malt->part_buffer);            Some Mac brokenness trips this...
  179.   if (!malt->part_buffer) return -1; */
  180.  
  181.   if (malt->part_buffer)
  182.     MimePartBufferClose(malt->part_buffer);
  183.  
  184.   /* XP_ASSERT(mult->hdrs);                    I expect the Mac trips this too    */
  185.   if (mult->hdrs)
  186.     MimeHeaders_free(mult->hdrs);
  187.   mult->hdrs = 0;
  188.  
  189.   return 0;
  190. }
  191.  
  192.  
  193. static XP_Bool
  194. MimeMultipartAlternative_display_part_p(MimeObject *self,
  195.                                         MimeHeaders *sub_hdrs)
  196. {
  197.   char *ct = MimeHeaders_get (sub_hdrs, HEADER_CONTENT_TYPE, TRUE, FALSE);
  198.  
  199.   /* RFC 1521 says:
  200.        Receiving user agents should pick and display the last format
  201.        they are capable of displaying.  In the case where one of the
  202.        alternatives is itself of type "multipart" and contains unrecognized
  203.        sub-parts, the user agent may choose either to show that alternative,
  204.        an earlier alternative, or both.
  205.  
  206.      Ugh.  If there is a multipart subtype of alternative, we simply show
  207.      that, without descending into it to determine if any of its sub-parts
  208.      are themselves unknown.
  209.    */
  210.  
  211.   MimeObjectClass *class = mime_find_class (ct, sub_hdrs, self->options, TRUE);
  212.   XP_Bool result = (class
  213.                     ? class->displayable_inline_p(class, sub_hdrs)
  214.                     : FALSE);
  215.   FREEIF(ct);
  216.   return result;
  217. }
  218.  
  219. static int 
  220. MimeMultipartAlternative_discard_cached_part(MimeObject *obj)
  221. {
  222.   MimeMultipartAlternative *malt = (MimeMultipartAlternative *) obj;
  223.  
  224.   if (malt->buffered_hdrs)
  225.     {
  226.       MimeHeaders_free(malt->buffered_hdrs);
  227.       malt->buffered_hdrs = 0;
  228.     }
  229.   if (malt->part_buffer)
  230.     MimePartBufferReset (malt->part_buffer);
  231.  
  232.   return 0;
  233. }
  234.  
  235. static int 
  236. MimeMultipartAlternative_display_cached_part(MimeObject *obj)
  237. {
  238.   MimeMultipartAlternative *malt = (MimeMultipartAlternative *) obj;
  239.   int status;
  240.  
  241.   char *ct = (malt->buffered_hdrs
  242.               ? MimeHeaders_get (malt->buffered_hdrs, HEADER_CONTENT_TYPE,
  243.                                  TRUE, FALSE)
  244.               : 0);
  245.   const char *dct = (((MimeMultipartClass *) obj->class)->default_part_type);
  246.   MimeObject *body;
  247.   XP_Bool multipart_p;
  248.  
  249.   /* Don't pass in NULL as the content-type (this means that the
  250.      auto-uudecode-hack won't ever be done for subparts of a
  251.      multipart, but only for untyped children of message/rfc822.
  252.    */
  253.   body = mime_create(((ct && *ct) ? ct : (dct ? dct: TEXT_PLAIN)),
  254.                      malt->buffered_hdrs, obj->options);
  255.  
  256.   FREEIF(ct);
  257.   if (!body) return MK_OUT_OF_MEMORY;
  258.  
  259.   multipart_p = mime_typep(body, (MimeObjectClass *) &mimeMultipartClass);
  260.  
  261.   status = ((MimeContainerClass *) obj->class)->add_child(obj, body);
  262.   if (status < 0)
  263.     {
  264.       mime_free(body);
  265.       return status;
  266.     }
  267.  
  268. #ifdef MIME_DRAFTS
  269.   if ( obj->options && 
  270.        obj->options->decompose_file_p &&
  271.        !multipart_p &&
  272.        obj->options->decompose_file_init_fn )
  273.     {
  274.       status = obj->options->decompose_file_init_fn (
  275.                                                 obj->options->stream_closure,
  276.                                                 malt->buffered_hdrs);
  277.       if (status < 0) return status;
  278.     }
  279. #endif /* MIME_DRAFTS */
  280.  
  281.  
  282.   /* Now that we've added this new object to our list of children,
  283.      start its parser going. */
  284.   status = body->class->parse_begin(body);
  285.   if (status < 0) return status;
  286.  
  287. #ifdef MIME_DRAFTS
  288.   if ( obj->options &&
  289.        obj->options->decompose_file_p &&
  290.        !multipart_p &&
  291.        obj->options->decompose_file_output_fn )
  292.     status = MimePartBufferRead (malt->part_buffer,
  293.                                  obj->options->decompose_file_output_fn,
  294.                                  obj->options->stream_closure);
  295.   else
  296. #endif /* MIME_DRAFTS */
  297.  
  298.     status = MimePartBufferRead (malt->part_buffer,
  299.                                  /* The (int (*) ...) cast is to turn the
  300.                                     `void' argument into `MimeObject'. */
  301.                                  ((int (*) (char *, int32, void *))
  302.                                   body->class->parse_buffer),
  303.                                  body);
  304.  
  305.   if (status < 0) return status;
  306.  
  307.   MimeMultipartAlternative_cleanup(obj);
  308.  
  309.   /* Done parsing. */
  310.   status = body->class->parse_eof(body, FALSE);
  311.   if (status < 0) return status;
  312.   status = body->class->parse_end(body, FALSE);
  313.   if (status < 0) return status;
  314.  
  315. #ifdef MIME_DRAFTS
  316.   if ( obj->options &&
  317.        obj->options->decompose_file_p &&
  318.        !multipart_p &&
  319.        obj->options->decompose_file_close_fn ) {
  320.     status = obj->options->decompose_file_close_fn ( obj->options->stream_closure );
  321.     if (status < 0) return status;
  322.   }
  323. #endif /* MIME_DRAFTS */
  324.  
  325.   return 0;
  326. }
  327.