Back to index

lightning-sunbird  0.9+nobinonly
mimeobj.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
00002  *
00003  * ***** BEGIN LICENSE BLOCK *****
00004  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00005  *
00006  * The contents of this file are subject to the Mozilla Public License Version
00007  * 1.1 (the "License"); you may not use this file except in compliance with
00008  * the License. You may obtain a copy of the License at
00009  * http://www.mozilla.org/MPL/
00010  *
00011  * Software distributed under the License is distributed on an "AS IS" basis,
00012  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00013  * for the specific language governing rights and limitations under the
00014  * License.
00015  *
00016  * The Original Code is mozilla.org code.
00017  *
00018  * The Initial Developer of the Original Code is
00019  * Netscape Communications Corporation.
00020  * Portions created by the Initial Developer are Copyright (C) 1998
00021  * the Initial Developer. All Rights Reserved.
00022  *
00023  * Contributor(s):
00024  *
00025  * Alternatively, the contents of this file may be used under the terms of
00026  * either of the GNU General Public License Version 2 or later (the "GPL"),
00027  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00028  * in which case the provisions of the GPL or the LGPL are applicable instead
00029  * of those above. If you wish to allow use of your version of this file only
00030  * under the terms of either the GPL or the LGPL, and not to allow others to
00031  * use your version of this file under the terms of the MPL, indicate your
00032  * decision by deleting the provisions above and replace them with the notice
00033  * and other provisions required by the GPL or the LGPL. If you do not delete
00034  * the provisions above, a recipient may use your version of this file under
00035  * the terms of any one of the MPL, the GPL or the LGPL.
00036  *
00037  * ***** END LICENSE BLOCK *****
00038  * This Original Code has been modified by IBM Corporation. Modifications made by IBM 
00039  * described herein are Copyright (c) International Business Machines Corporation, 2000.
00040  * Modifications to Mozilla code or documentation identified per MPL Section 3.3
00041  *
00042  * Date             Modified by     Description of modification
00043  * 04/20/2000       IBM Corp.      OS/2 VisualAge build.
00044  */
00045 
00046 #include "mimeobj.h"
00047 #include "prmem.h"
00048 #include "plstr.h"
00049 #include "prio.h"
00050 #include "mimebuf.h"
00051 #include "prlog.h"
00052 #include "nsMimeTypes.h"
00053 #include "nsCRT.h"
00054 #include "nsMimeStringResources.h"
00055 #include "mimemsg.h"
00056 #include "mimemapl.h"
00057 
00058 /* Way to destroy any notions of modularity or class hierarchy, Terry! */
00059 # include "mimetpla.h"
00060 # include "mimethtm.h"
00061 # include "mimecont.h"
00062 
00063 MimeDefClass (MimeObject, MimeObjectClass, mimeObjectClass, NULL);
00064 
00065 static int MimeObject_initialize (MimeObject *);
00066 static void MimeObject_finalize (MimeObject *);
00067 static int MimeObject_parse_begin (MimeObject *);
00068 static int MimeObject_parse_buffer (const char *, PRInt32, MimeObject *);
00069 static int MimeObject_parse_line (char *, PRInt32, MimeObject *);
00070 static int MimeObject_parse_eof (MimeObject *, PRBool);
00071 static int MimeObject_parse_end (MimeObject *, PRBool);
00072 static PRBool MimeObject_displayable_inline_p (MimeObjectClass *clazz,
00073                                                                                     MimeHeaders *hdrs);
00074 
00075 #if defined(DEBUG) && defined(XP_UNIX)
00076 static int MimeObject_debug_print (MimeObject *, PRFileDesc *, PRInt32 depth);
00077 #endif
00078 
00079 static int
00080 MimeObjectClassInitialize(MimeObjectClass *clazz)
00081 {
00082   NS_ASSERTION(!clazz->class_initialized, "class shouldn't already be initialized");
00083   clazz->initialize   = MimeObject_initialize;
00084   clazz->finalize     = MimeObject_finalize;
00085   clazz->parse_begin  = MimeObject_parse_begin;
00086   clazz->parse_buffer = MimeObject_parse_buffer;
00087   clazz->parse_line   = MimeObject_parse_line;
00088   clazz->parse_eof    = MimeObject_parse_eof;
00089   clazz->parse_end    = MimeObject_parse_end;
00090   clazz->displayable_inline_p = MimeObject_displayable_inline_p;
00091 
00092 #if defined(DEBUG) && defined(XP_UNIX)
00093   clazz->debug_print  = MimeObject_debug_print;
00094 #endif
00095   return 0;
00096 }
00097 
00098 
00099 static int
00100 MimeObject_initialize (MimeObject *obj)
00101 {
00102   /* This is an abstract class; it shouldn't be directly instantiated. */
00103   NS_ASSERTION(obj->clazz != &mimeObjectClass, "should directly instantiate abstract class");
00104 
00105   /* Set up the content-type and encoding. */
00106   if (!obj->content_type && obj->headers)
00107        obj->content_type = MimeHeaders_get (obj->headers, HEADER_CONTENT_TYPE,
00108                                                                        PR_TRUE, PR_FALSE);
00109   if (!obj->encoding && obj->headers)
00110        obj->encoding = MimeHeaders_get (obj->headers,
00111                                                                 HEADER_CONTENT_TRANSFER_ENCODING,
00112                                                                 PR_TRUE, PR_FALSE);
00113 
00114 
00115   /* Special case to normalize some types and encodings to a canonical form.
00116         (These are nonstandard types/encodings which have been seen to appear in
00117         multiple forms; we normalize them so that things like looking up icons
00118         and extensions has consistent behavior for the receiver, regardless of
00119         the "alias" type that the sender used.)
00120    */
00121   if (!obj->content_type)
00122        ;
00123   else if (!nsCRT::strcasecmp(obj->content_type, APPLICATION_UUENCODE2) ||
00124                  !nsCRT::strcasecmp(obj->content_type, APPLICATION_UUENCODE3) ||
00125                  !nsCRT::strcasecmp(obj->content_type, APPLICATION_UUENCODE4))
00126        {
00127          PR_Free(obj->content_type);
00128          obj->content_type = nsCRT::strdup(APPLICATION_UUENCODE);
00129        }
00130   else if (!nsCRT::strcasecmp(obj->content_type, IMAGE_XBM2) ||
00131                  !nsCRT::strcasecmp(obj->content_type, IMAGE_XBM3))
00132        {
00133          PR_Free(obj->content_type);
00134          obj->content_type = nsCRT::strdup(IMAGE_XBM);
00135        }
00136 
00137   if (!obj->encoding)
00138        ;
00139   else if (!nsCRT::strcasecmp(obj->encoding, ENCODING_UUENCODE2) ||
00140                  !nsCRT::strcasecmp(obj->encoding, ENCODING_UUENCODE3) ||
00141                  !nsCRT::strcasecmp(obj->encoding, ENCODING_UUENCODE4))
00142        {
00143          PR_Free(obj->encoding);
00144          obj->encoding = nsCRT::strdup(ENCODING_UUENCODE);
00145        }
00146   else if (!nsCRT::strcasecmp(obj->encoding, ENCODING_COMPRESS2))
00147        {
00148          PR_Free(obj->encoding);
00149          obj->encoding = nsCRT::strdup(ENCODING_COMPRESS);
00150        }
00151   else if (!nsCRT::strcasecmp(obj->encoding, ENCODING_GZIP2))
00152        {
00153          PR_Free(obj->encoding);
00154          obj->encoding = nsCRT::strdup(ENCODING_GZIP);
00155        }
00156 
00157 
00158   return 0;
00159 }
00160 
00161 static void
00162 MimeObject_finalize (MimeObject *obj)
00163 {
00164   obj->clazz->parse_eof (obj, PR_FALSE);
00165   obj->clazz->parse_end (obj, PR_FALSE);
00166 
00167   if (obj->headers)
00168        {
00169          MimeHeaders_free(obj->headers);
00170          obj->headers = 0;
00171        }
00172 
00173   /* Should have been freed by parse_eof, but just in case... */
00174   NS_ASSERTION(!obj->ibuffer, "buffer not freed");
00175   NS_ASSERTION(!obj->obuffer, "buffer not freed");
00176   PR_FREEIF (obj->ibuffer);
00177   PR_FREEIF (obj->obuffer);
00178 
00179   PR_FREEIF(obj->content_type);
00180   PR_FREEIF(obj->encoding);
00181 
00182   if (obj->options && obj->options->state)
00183        {
00184          PR_Free(obj->options->state);
00185          obj->options->state = 0;
00186        }
00187 }
00188 
00189 
00190 static int
00191 MimeObject_parse_begin (MimeObject *obj)
00192 {
00193   NS_ASSERTION (!obj->closed_p, "object shouldn't be already closed");
00194 
00195   /* If we haven't set up the state object yet, then this should be
00196         the outermost object... */
00197   if (obj->options && !obj->options->state)
00198   {
00199     NS_ASSERTION(!obj->headers, "headers should be null");  /* should be the outermost object. */
00200 
00201     obj->options->state = new MimeParseStateObject;
00202     if (!obj->options->state) return MIME_OUT_OF_MEMORY;
00203     obj->options->state->root = obj;
00204     obj->options->state->separator_suppressed_p = PR_TRUE; /* no first sep */
00205     const char *delParts = PL_strcasestr(obj->options->url, "&del=");
00206     const char *detachLocations = PL_strcasestr(obj->options->url, "&detachTo=");
00207     if (delParts)
00208     {
00209       const char *delEnd = PL_strcasestr(delParts + 1, "&");
00210       if (!delEnd)
00211         delEnd = delParts + strlen(delParts);
00212       nsCAutoString partsToDel(Substring(delParts + 5, delEnd)); 
00213       obj->options->state->partsToStrip.ParseString(partsToDel.get(), ",");
00214     }
00215     if (detachLocations)
00216     {
00217       detachLocations += 10; // advance past "&detachTo="
00218       obj->options->state->detachToFiles.ParseString(detachLocations, ",");
00219     }
00220   }
00221 
00222   /* Decide whether this object should be output or not... */
00223   if (!obj->options || !obj->options->output_fn
00224     /* if we are decomposing the message in files and processing a multipart object,
00225        we must not output it without parsing it first */
00226      || (obj->options->decompose_file_p && obj->options->decompose_file_output_fn &&
00227            mime_typep(obj, (MimeObjectClass*) &mimeMultipartClass)) 
00228     )
00229          obj->output_p = PR_FALSE;
00230   else if (!obj->options->part_to_load)
00231          obj->output_p = PR_TRUE;
00232   else
00233        {
00234          char *id = mime_part_address(obj);
00235          if (!id) return MIME_OUT_OF_MEMORY;
00236 
00237       // We need to check if a part is the subpart of the part to load.
00238       // If so and this is a raw or body display output operation, then
00239       // we should mark the part for subsequent output.
00240       //
00241      
00242       // First, check for an exact match
00243       obj->output_p = !strcmp(id, obj->options->part_to_load); 
00244       if (!obj->output_p && (obj->options->format_out == nsMimeOutput::nsMimeMessageRaw ||
00245              obj->options->format_out == nsMimeOutput::nsMimeMessageBodyDisplay
00246              || obj->options->format_out == nsMimeOutput::nsMimeMessageAttach))
00247     {
00248         // Then, check for subpart
00249         unsigned int partlen = strlen(obj->options->part_to_load);
00250         obj->output_p = (strlen(id) >= partlen + 2) && (id[partlen] == '.') &&
00251             !strncmp(id, obj->options->part_to_load, partlen);
00252       }
00253 
00254          PR_Free(id);
00255        }
00256 
00257 /* Way to destroy any notions of modularity or class hierarchy, Terry! */
00258   if (obj->options && obj->options->nice_html_only_p) {
00259          if (!mime_subclass_p(obj->clazz,
00260                                              (MimeObjectClass*) &mimeInlineTextHTMLClass) &&
00261                 !mime_subclass_p(obj->clazz,
00262                                              (MimeObjectClass*) &mimeInlineTextPlainClass) &&
00263                 !mime_subclass_p(obj->clazz,
00264                                              (MimeObjectClass*) &mimeContainerClass)) {
00265                 obj->output_p = PR_FALSE;
00266          }
00267   }
00268 
00269   return 0;
00270 }
00271 
00272 static int
00273 MimeObject_parse_buffer (const char *buffer, PRInt32 size, MimeObject *obj)
00274 {
00275   NS_ASSERTION(!obj->closed_p, "object shouldn't be closed");
00276   if (obj->closed_p) return -1;
00277 
00278   return mime_LineBuffer (buffer, size,
00279                                            &obj->ibuffer, &obj->ibuffer_size, &obj->ibuffer_fp,
00280                                            PR_TRUE,
00281                                            ((int (*PR_CALLBACK) (char *, PRInt32, void *))
00282                                             /* This cast is to turn void into MimeObject */
00283                                             obj->clazz->parse_line),
00284                                            obj);
00285 }
00286 
00287 
00288 static int
00289 MimeObject_parse_line (char *line, PRInt32 length, MimeObject *obj)
00290 {
00291   /* This method should never be called. */
00292   NS_ASSERTION(0, "shouldn't call this method");
00293   return -1;
00294 }
00295 
00296 static int
00297 MimeObject_parse_eof (MimeObject *obj, PRBool abort_p)
00298 {
00299   if (obj->closed_p) return 0;
00300   NS_ASSERTION(!obj->parsed_p, "obj already parsed");
00301 
00302   /* If there is still data in the ibuffer, that means that the last line of
00303         this part didn't end in a newline; so push it out anyway (this means that
00304         the parse_line method will be called with a string with no trailing
00305         newline, which isn't the usual case.)
00306    */
00307   if (!abort_p &&
00308          obj->ibuffer_fp > 0)
00309        {
00310          int status = obj->clazz->parse_line (obj->ibuffer, obj->ibuffer_fp, obj);
00311          obj->ibuffer_fp = 0;
00312          if (status < 0)
00313               {
00314                 obj->closed_p = PR_TRUE;
00315                 return status;
00316               }
00317        }
00318 
00319   obj->closed_p = PR_TRUE;
00320   return 0;
00321 }
00322 
00323 
00324 static int
00325 MimeObject_parse_end (MimeObject *obj, PRBool abort_p)
00326 {
00327   if (obj->parsed_p)
00328        {
00329          NS_ASSERTION(obj->closed_p, "object should be closed");
00330          return 0;
00331        }
00332 
00333   /* We won't be needing these buffers any more; nuke 'em. */
00334   PR_FREEIF(obj->ibuffer);
00335   obj->ibuffer_fp = 0;
00336   obj->ibuffer_size = 0;
00337   PR_FREEIF(obj->obuffer);
00338   obj->obuffer_fp = 0;
00339   obj->obuffer_size = 0;
00340 
00341   obj->parsed_p = PR_TRUE;
00342   return 0;
00343 }
00344 
00345 
00346 static PRBool
00347 MimeObject_displayable_inline_p (MimeObjectClass *clazz, MimeHeaders *hdrs)
00348 {
00349   NS_ASSERTION(0, "shouldn't call this method");  /* This method should never be called. */
00350   return PR_FALSE;
00351 }
00352 
00353 
00354 
00355 #if defined(DEBUG) && defined(XP_UNIX)
00356 static int
00357 MimeObject_debug_print (MimeObject *obj, PRFileDesc *stream, PRInt32 depth)
00358 {
00359   int i;
00360   char *addr = mime_part_address(obj);
00361   for (i=0; i < depth; i++)
00362        PR_Write(stream, "  ", 2);
00363 /*
00364   fprintf(stream, "<%s %s 0x%08X>\n", obj->clazz->class_name,
00365                 addr ? addr : "???",
00366                 (PRUint32) obj);
00367 */
00368   PR_FREEIF(addr);
00369   return 0;
00370 }
00371 #endif