Back to index

lightning-sunbird  0.9+nobinonly
mimesun.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either of the GNU General Public License Version 2 or later (the "GPL"),
00026  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 #include "mimesun.h"
00039 #include "prmem.h"
00040 #include "plstr.h"
00041 #include "prlog.h"
00042 #include "nsMimeTypes.h"
00043 #include "msgCore.h"
00044 #include "nsMimeStringResources.h"
00045 
00046 #define MIME_SUPERCLASS mimeMultipartClass
00047 MimeDefClass(MimeSunAttachment, MimeSunAttachmentClass,
00048                       mimeSunAttachmentClass, &MIME_SUPERCLASS);
00049 
00050 static MimeMultipartBoundaryType MimeSunAttachment_check_boundary(MimeObject *,
00051                                                                                                                   const char *,
00052                                                                                                                   PRInt32);
00053 static int MimeSunAttachment_create_child(MimeObject *);
00054 static int MimeSunAttachment_parse_child_line (MimeObject *, char *, PRInt32,
00055                                                                                 PRBool);
00056 static int MimeSunAttachment_parse_begin (MimeObject *);
00057 static int MimeSunAttachment_parse_eof (MimeObject *, PRBool);
00058 
00059 static int
00060 MimeSunAttachmentClassInitialize(MimeSunAttachmentClass *clazz)
00061 {
00062   MimeObjectClass    *oclass = (MimeObjectClass *)    clazz;
00063   MimeMultipartClass *mclass = (MimeMultipartClass *) clazz;
00064 
00065   PR_ASSERT(!oclass->class_initialized);
00066   oclass->parse_begin      = MimeSunAttachment_parse_begin;
00067   oclass->parse_eof        = MimeSunAttachment_parse_eof;
00068   mclass->check_boundary   = MimeSunAttachment_check_boundary;
00069   mclass->create_child     = MimeSunAttachment_create_child;
00070   mclass->parse_child_line = MimeSunAttachment_parse_child_line;
00071   return 0;
00072 }
00073 
00074 
00075 static int
00076 MimeSunAttachment_parse_begin (MimeObject *obj)
00077 {
00078   int status = ((MimeObjectClass*)&MIME_SUPERCLASS)->parse_begin(obj);
00079   if (status < 0) return status;
00080 
00081   /* Sun messages always have separators at the beginning. */
00082   return MimeObject_write_separator(obj);
00083 }
00084 
00085 static int
00086 MimeSunAttachment_parse_eof (MimeObject *obj, PRBool abort_p)
00087 {
00088   int status = 0;
00089 
00090   status = ((MimeObjectClass*)&MIME_SUPERCLASS)->parse_eof(obj, abort_p);
00091   if (status < 0) return status;
00092 
00093   /* Sun messages always have separators at the end. */
00094   if (!abort_p)
00095        {
00096          status = MimeObject_write_separator(obj);
00097          if (status < 0) return status;
00098        }
00099 
00100   return 0;
00101 }
00102 
00103 
00104 static MimeMultipartBoundaryType
00105 MimeSunAttachment_check_boundary(MimeObject *obj, const char *line,
00106                                                          PRInt32 length)
00107 {
00108   /* ten dashes */
00109 
00110   if (line &&
00111          line[0] == '-' && line[1] == '-' && line[2] == '-' && line[3] == '-' &&
00112          line[4] == '-' && line[5] == '-' && line[6] == '-' && line[7] == '-' &&
00113          line[8] == '-' && line[9] == '-' &&
00114          (line[10] == nsCRT::CR || line[10] == nsCRT::LF))
00115        return MimeMultipartBoundaryTypeSeparator;
00116   else
00117        return MimeMultipartBoundaryTypeNone;
00118 }
00119 
00120 
00121 static int
00122 MimeSunAttachment_create_child(MimeObject *obj)
00123 {
00124   MimeMultipart *mult = (MimeMultipart *) obj;
00125   int status = 0;
00126 
00127   char *sun_data_type = 0;
00128   const char *mime_ct = 0, *sun_enc_info = 0, *mime_cte = 0;
00129   char *mime_ct2 = 0;    /* sometimes we need to copy; this is for freeing. */
00130   MimeObject *child = 0;
00131 
00132   mult->state = MimeMultipartPartLine;
00133 
00134   sun_data_type = (mult->hdrs
00135                                ? MimeHeaders_get (mult->hdrs, HEADER_X_SUN_DATA_TYPE,
00136                                                                  PR_TRUE, PR_FALSE)
00137                                : 0);
00138   if (sun_data_type)
00139        {
00140          int i;
00141          static const struct { const char *in, *out; } sun_types[] = {
00142 
00143               /* Convert recognised Sun types to the corresponding MIME types,
00144                  and convert unrecognized ones based on the file extension and
00145                  the mime.types file.
00146 
00147                  These are the magic types used by MailTool that I can determine.
00148                  The only actual written spec I've found only listed the first few.
00149                  The rest were found by inspection (both of real-world messages,
00150                  and by running `strings' on the MailTool binary, and on the file
00151                  /usr/openwin/lib/cetables/cetables (the "Class Engine", Sun's
00152                  equivalent to .mailcap and mime.types.)
00153                */
00154               { "default",                       TEXT_PLAIN },
00155               { "default-doc",                   TEXT_PLAIN },
00156               { "text",                                 TEXT_PLAIN },
00157               { "scribe",                               TEXT_PLAIN },
00158               { "sgml",                                 TEXT_PLAIN },
00159               { "tex",                                  TEXT_PLAIN },
00160               { "troff",                                TEXT_PLAIN },
00161               { "c-file",                               TEXT_PLAIN },
00162               { "h-file",                               TEXT_PLAIN },
00163               { "readme-file",                   TEXT_PLAIN },
00164               { "shell-script",                  TEXT_PLAIN },
00165               { "cshell-script",                 TEXT_PLAIN },
00166               { "makefile",                      TEXT_PLAIN },
00167               { "hidden-docs",                   TEXT_PLAIN },
00168               { "message",                       MESSAGE_RFC822 },
00169               { "mail-message",                  MESSAGE_RFC822 },
00170               { "mail-file",                            TEXT_PLAIN },
00171               { "gif-file",                      IMAGE_GIF },
00172               { "jpeg-file",                            IMAGE_JPG },
00173               { "ppm-file",                      IMAGE_PPM },
00174               { "pgm-file",                      "image/x-portable-graymap" },
00175               { "pbm-file",                      "image/x-portable-bitmap" },
00176               { "xpm-file",                      "image/x-xpixmap" },
00177               { "ilbm-file",                            "image/ilbm" },
00178               { "tiff-file",                            "image/tiff" },
00179               { "photocd-file",                  "image/x-photo-cd" },
00180               { "sun-raster",                           "image/x-sun-raster" },
00181               { "audio-file",                           AUDIO_BASIC },
00182               { "postscript",                           APPLICATION_POSTSCRIPT },
00183               { "postscript-file",        APPLICATION_POSTSCRIPT },
00184               { "framemaker-document",    "application/x-framemaker" },
00185               { "sundraw-document",              "application/x-sun-draw" },
00186               { "sunpaint-document",             "application/x-sun-paint" },
00187               { "sunwrite-document",             "application/x-sun-write" },
00188               { "islanddraw-document",    "application/x-island-draw" },
00189               { "islandpaint-document",   "application/x-island-paint" },
00190               { "islandwrite-document",   "application/x-island-write" },
00191               { "sun-executable",                APPLICATION_OCTET_STREAM },
00192               { "default-app",                   APPLICATION_OCTET_STREAM },
00193               { 0, 0 }};
00194          for (i = 0; sun_types[i].in; i++)
00195               if (!nsCRT::strcasecmp(sun_data_type, sun_types[i].in))
00196                 {
00197                      mime_ct = sun_types[i].out;
00198                      break;
00199                 }
00200        }
00201 
00202   /* If we didn't find a type, look at the extension on the file name.
00203    */
00204   if (!mime_ct &&
00205          obj->options &&
00206          obj->options->file_type_fn)
00207        {
00208          char *name = MimeHeaders_get_name(mult->hdrs, obj->options);
00209          if (name)
00210               {
00211                 mime_ct2 = obj->options->file_type_fn(name,
00212                                                                                  obj->options->stream_closure);
00213                 mime_ct = mime_ct2;
00214                 PR_Free(name);
00215                 if (!mime_ct2 || !nsCRT::strcasecmp (mime_ct2, UNKNOWN_CONTENT_TYPE))
00216                      {
00217                        PR_FREEIF(mime_ct2);
00218                        mime_ct = APPLICATION_OCTET_STREAM;
00219                      }
00220               }
00221        }
00222   if (!mime_ct)
00223        mime_ct = APPLICATION_OCTET_STREAM;
00224 
00225   PR_FREEIF(sun_data_type);
00226 
00227 
00228   /* Convert recognised Sun encodings to the corresponding MIME encodings.
00229         However, if the X-Sun-Encoding-Info field contains more than one
00230         encoding (that is, contains a comma) then assign it the encoding of
00231         the *rightmost* element in the list; and change its Content-Type to
00232         application/octet-stream.  Examples:
00233 
00234              Sun Type:                    Translates To:
00235         ==================            ====================
00236         type:     TEXT                type:     text/plain
00237         encoding: COMPRESS            encoding: x-compress
00238 
00239         type:     POSTSCRIPT          type:     application/x-compress
00240         encoding: COMPRESS,UUENCODE   encoding: x-uuencode
00241 
00242         type:     TEXT                type:     application/octet-stream
00243         encoding: UNKNOWN,UUENCODE    encoding: x-uuencode
00244    */
00245 
00246   sun_data_type = (mult->hdrs
00247                                ? MimeHeaders_get (mult->hdrs, HEADER_X_SUN_ENCODING_INFO,
00248                                                                  PR_FALSE,PR_FALSE)
00249                                : 0);
00250   sun_enc_info = sun_data_type;
00251 
00252 
00253   /* this "adpcm-compress" pseudo-encoding is some random junk that
00254         MailTool adds to the encoding description of .AU files: we can
00255         ignore it if it is the leftmost element of the encoding field.
00256         (It looks like it's created via `audioconvert -f g721'.  Why?
00257         Who knows.)
00258    */
00259   if (sun_enc_info && !nsCRT::strncasecmp (sun_enc_info, "adpcm-compress", 14))
00260        {
00261          sun_enc_info += 14;
00262          while (nsCRT::IsAsciiSpace(*sun_enc_info) || *sun_enc_info == ',')
00263               sun_enc_info++;
00264        }
00265 
00266   /* Extract the last element of the encoding field, changing the content
00267         type if necessary (as described above.)
00268    */
00269   if (sun_enc_info && *sun_enc_info)
00270        {
00271          const char *prev;
00272          const char *end = PL_strrchr(sun_enc_info, ',');
00273          if (end)
00274               {
00275                 const char *start = sun_enc_info;
00276                 sun_enc_info = end + 1;
00277                 while (nsCRT::IsAsciiSpace(*sun_enc_info))
00278                      sun_enc_info++;
00279                 for (prev = end-1; prev > start && *prev != ','; prev--)
00280                      ;
00281                 if (*prev == ',') prev++;
00282 
00283                 if (!nsCRT::strncasecmp (prev, "uuencode", end-prev))
00284                      mime_ct = APPLICATION_UUENCODE;
00285                 else if (!nsCRT::strncasecmp (prev, "gzip", end-prev))
00286                      mime_ct = APPLICATION_GZIP;
00287                 else if (!nsCRT::strncasecmp (prev, "compress", end-prev))
00288                      mime_ct = APPLICATION_COMPRESS;
00289                 else if (!nsCRT::strncasecmp (prev, "default-compress", end-prev))
00290                      mime_ct = APPLICATION_COMPRESS;
00291                 else
00292                      mime_ct = APPLICATION_OCTET_STREAM;
00293               }
00294        }
00295 
00296   /* Convert the remaining Sun encoding to a MIME encoding.
00297         If it isn't known, change the content-type instead.
00298    */
00299   if (!sun_enc_info || !*sun_enc_info)
00300        ;
00301   else if (!nsCRT::strcasecmp(sun_enc_info,"compress")) mime_cte = ENCODING_COMPRESS;
00302   else if (!nsCRT::strcasecmp(sun_enc_info,"uuencode")) mime_cte = ENCODING_UUENCODE;
00303   else if (!nsCRT::strcasecmp(sun_enc_info,"gzip"))       mime_cte = ENCODING_GZIP;
00304   else                                                                mime_ct = APPLICATION_OCTET_STREAM;
00305 
00306   PR_FREEIF(sun_data_type);
00307 
00308 
00309   /* Now that we know its type and encoding, create a MimeObject to represent
00310         this part.
00311    */
00312   child = mime_create(mime_ct, mult->hdrs, obj->options);
00313   if (!child)
00314        {
00315          status = MIME_OUT_OF_MEMORY;
00316          goto FAIL;
00317        }
00318 
00319   /* Fake out the child's content-type and encoding (it probably doesn't have
00320         one right now, because the X-Sun- headers aren't generally recognised by
00321         the rest of this library.)
00322    */
00323   PR_FREEIF(child->content_type);
00324   PR_FREEIF(child->encoding);
00325   PR_ASSERT(mime_ct);
00326   child->content_type = (mime_ct  ? nsCRT::strdup(mime_ct)  : 0);
00327   child->encoding     = (mime_cte ? nsCRT::strdup(mime_cte) : 0);
00328 
00329   status = ((MimeContainerClass *) obj->clazz)->add_child(obj, child);
00330   if (status < 0)
00331        {
00332          mime_free(child);
00333          child = 0;
00334          goto FAIL;
00335        }
00336 
00337   /* Sun attachments always have separators between parts. */
00338   status = MimeObject_write_separator(obj);
00339   if (status < 0) goto FAIL;
00340 
00341   /* And now that we've added this new object to our list of
00342         children, start its parser going. */
00343   status = child->clazz->parse_begin(child);
00344   if (status < 0) goto FAIL;
00345 
00346  FAIL:
00347   PR_FREEIF(mime_ct2);
00348   PR_FREEIF(sun_data_type);
00349   return status;
00350 }
00351 
00352 
00353 static int
00354 MimeSunAttachment_parse_child_line (MimeObject *obj, char *line, PRInt32 length,
00355                                                                PRBool first_line_p)
00356 {
00357   MimeContainer *cont = (MimeContainer *) obj;
00358   MimeObject *kid;
00359 
00360   /* This is simpler than MimeMultipart->parse_child_line in that it doesn't
00361         play games about body parts without trailing newlines.
00362    */
00363 
00364   PR_ASSERT(cont->nchildren > 0);
00365   if (cont->nchildren <= 0)
00366        return -1;
00367 
00368   kid = cont->children[cont->nchildren-1];
00369   PR_ASSERT(kid);
00370   if (!kid) return -1;
00371 
00372   return kid->clazz->parse_buffer (line, length, kid);
00373 }