Back to index

lightning-sunbird  0.9+nobinonly
mimeebod.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  *   Pierre Phaneuf <pp@ludusdesign.com>
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 #include "nsCOMPtr.h"
00039 #include "nsIURL.h"
00040 #include "mimeebod.h"
00041 #include "prmem.h"
00042 #include "nsCRT.h"
00043 #include "plstr.h"
00044 #include "prlog.h"
00045 #include "prio.h"
00046 #include "nsFileSpec.h"
00047 #include "nsEscape.h"
00048 #include "msgCore.h"
00049 #include "nsMimeStringResources.h"
00050 #include "mimemoz2.h"
00051 
00052 #define MIME_SUPERCLASS mimeObjectClass
00053 MimeDefClass(MimeExternalBody, MimeExternalBodyClass,
00054                       mimeExternalBodyClass, &MIME_SUPERCLASS);
00055 
00056 #if defined(XP_MAC) || defined(XP_MACOSX)
00057 extern MimeObjectClass mimeMultipartAppleDoubleClass;
00058 #endif
00059 
00060 static int MimeExternalBody_initialize (MimeObject *);
00061 static void MimeExternalBody_finalize (MimeObject *);
00062 static int MimeExternalBody_parse_line (char *, PRInt32, MimeObject *);
00063 static int MimeExternalBody_parse_eof (MimeObject *, PRBool);
00064 static PRBool MimeExternalBody_displayable_inline_p (MimeObjectClass *clazz,
00065                                                                                              MimeHeaders *hdrs);
00066 
00067 #if 0
00068 #if defined(DEBUG) && defined(XP_UNIX)
00069 static int MimeExternalBody_debug_print (MimeObject *, PRFileDesc *, PRInt32);
00070 #endif
00071 #endif /* 0 */
00072 
00073 static int
00074 MimeExternalBodyClassInitialize(MimeExternalBodyClass *clazz)
00075 {
00076   MimeObjectClass *oclass = (MimeObjectClass *) clazz;
00077 
00078   NS_ASSERTION(!oclass->class_initialized, "1.1 <rhp@netscape.com> 19 Mar 1999 12:00");
00079   oclass->initialize  = MimeExternalBody_initialize;
00080   oclass->finalize    = MimeExternalBody_finalize;
00081   oclass->parse_line  = MimeExternalBody_parse_line;
00082   oclass->parse_eof  = MimeExternalBody_parse_eof;
00083   oclass->displayable_inline_p = MimeExternalBody_displayable_inline_p;
00084 
00085 #if 0
00086 #if defined(DEBUG) && defined(XP_UNIX)
00087   oclass->debug_print = MimeExternalBody_debug_print;
00088 #endif
00089 #endif /* 0 */
00090 
00091   return 0;
00092 }
00093 
00094 
00095 static int
00096 MimeExternalBody_initialize (MimeObject *object)
00097 {
00098   return ((MimeObjectClass*)&MIME_SUPERCLASS)->initialize(object);
00099 }
00100 
00101 static void
00102 MimeExternalBody_finalize (MimeObject *object)
00103 {
00104   MimeExternalBody *bod = (MimeExternalBody *) object;
00105   if (bod->hdrs)
00106        {
00107          MimeHeaders_free(bod->hdrs);
00108          bod->hdrs = 0;
00109        }
00110   PR_FREEIF(bod->body);
00111 
00112   ((MimeObjectClass*)&MIME_SUPERCLASS)->finalize(object);
00113 }
00114 
00115 static int
00116 MimeExternalBody_parse_line (char *line, PRInt32 length, MimeObject *obj)
00117 {
00118   MimeExternalBody *bod = (MimeExternalBody *) obj;
00119   int status = 0;
00120 
00121   NS_ASSERTION(line && *line, "1.1 <rhp@netscape.com> 19 Mar 1999 12:00");
00122   if (!line || !*line) return -1;
00123 
00124   if (!obj->output_p) return 0;
00125 
00126   /* If we're supposed to write this object, but aren't supposed to convert
00127         it to HTML, simply pass it through unaltered. */
00128   if (obj->options &&
00129          !obj->options->write_html_p &&
00130          obj->options->output_fn)
00131        return MimeObject_write(obj, line, length, PR_TRUE);
00132 
00133 
00134   /* If we already have a `body' then we're done parsing headers, and all
00135         subsequent lines get tacked onto the body. */
00136   if (bod->body)
00137        {
00138          int L = strlen(bod->body);
00139          char *new_str = (char *)PR_Realloc(bod->body, L + length + 1);
00140          if (!new_str) return MIME_OUT_OF_MEMORY;
00141          bod->body = new_str;
00142          memcpy(bod->body + L, line, length);
00143          bod->body[L + length] = 0;
00144          return 0;
00145        }
00146 
00147   /* Otherwise we don't yet have a body, which means we're not done parsing
00148         our headers.
00149    */
00150   if (!bod->hdrs)
00151        {
00152          bod->hdrs = MimeHeaders_new();
00153          if (!bod->hdrs) return MIME_OUT_OF_MEMORY;
00154        }
00155 
00156   status = MimeHeaders_parse_line(line, length, bod->hdrs);
00157   if (status < 0) return status;
00158 
00159   /* If this line is blank, we're now done parsing headers, and should
00160         create a dummy body to show that.  Gag.
00161    */
00162   if (*line == nsCRT::CR || *line == nsCRT::LF)
00163        {
00164          bod->body = nsCRT::strdup("");
00165          if (!bod->body) return MIME_OUT_OF_MEMORY;
00166        }
00167 
00168   return 0;
00169 }
00170 
00171 
00172 char *
00173 MimeExternalBody_make_url(const char *ct,
00174                                             const char *at, const char *lexp, const char *size,
00175                                             const char *perm, const char *dir, const char *mode,
00176                                             const char *name, const char *url, const char *site,
00177                                             const char *svr, const char *subj, const char *body)
00178 {
00179   char *s;
00180   PRUint32 slen;
00181   if (!at)
00182     {
00183          return 0;
00184     }
00185   else if (!nsCRT::strcasecmp(at, "ftp") || !nsCRT::strcasecmp(at, "anon-ftp"))
00186        {
00187          if (!site || !name)
00188               return 0;
00189       slen = strlen(name) + strlen(site) + (dir ? strlen(dir) : 0) + 20;
00190       s = (char *) PR_MALLOC(slen);
00191       if (!s) return 0;
00192       PL_strncpyz(s, "ftp://", slen);
00193       PL_strcatn(s, slen, site);
00194       PL_strcatn(s, slen, "/");
00195       if (dir) PL_strcatn(s, slen, (dir[0] == '/' ? dir+1 : dir));
00196       if (s[strlen(s)-1] != '/')
00197         PL_strcatn(s, slen, "/");
00198       PL_strcatn(s, slen, name);
00199          return s;
00200        }
00201   else if (!nsCRT::strcasecmp(at, "local-file") || !nsCRT::strcasecmp(at, "afs"))
00202        {
00203          char *s2;
00204          if (!name)
00205               return 0;
00206 
00207 #ifdef XP_UNIX
00208          if (!nsCRT::strcasecmp(at, "afs"))   /* only if there is a /afs/ directory */
00209               {
00210       nsFileSpec    fs("/afs/.");
00211       
00212       if  (!fs.Exists())
00213         return 0;
00214               }
00215 #else  /* !XP_UNIX */
00216          return 0;                                      /* never, if not Unix. */
00217 #endif /* !XP_UNIX */
00218 
00219       slen = strlen(name)*3 + 20;
00220       s = (char *) PR_MALLOC(slen);
00221       if (!s) return 0;
00222       PL_strncpyz(s, "file:", slen);
00223 
00224          s2 = nsEscape(name, url_Path);
00225          if (s2)
00226          {
00227              PL_strcatn(s, slen, s2);
00228              nsCRT::free(s2);
00229          }
00230          return s;
00231        }
00232   else if (!nsCRT::strcasecmp(at, "mail-server"))
00233        {
00234          char *s2;
00235          if (!svr)
00236               return 0;
00237       slen = strlen(svr)*4 +   // XXX: why 4x? %xx escaping should only be 3x
00238              (subj ? strlen(subj)*4 : 0) +
00239              (body? strlen(body)*4 : 0) + 25;
00240       s = (char *) PR_MALLOC(slen);
00241       if (!s) return 0;
00242       PL_strncpyz(s, "mailto:", slen);
00243 
00244          s2 = nsEscape(svr, url_XAlphas);
00245          if (s2)
00246          {
00247              PL_strcatn(s, slen, s2);
00248              nsCRT::free(s2);
00249          }
00250 
00251          if (subj)
00252               {
00253                 s2 = nsEscape(subj, url_XAlphas);
00254                 PL_strcatn(s, slen, "?subject=");
00255                 if (s2)
00256                 {
00257                     PL_strcatn(s, slen, s2);
00258                     nsCRT::free(s2);
00259                 }
00260               }
00261          if (body)
00262               {
00263                 s2 = nsEscape(body, url_XAlphas);
00264                 PL_strcatn(s, slen, (subj ? "&body=" : "?body="));
00265                 if (s2)
00266                 {
00267                     PL_strcatn(s, slen, s2);
00268                     nsCRT::free(s2);
00269                 }
00270               }
00271          return s;
00272        }
00273   else if (!nsCRT::strcasecmp(at, "url"))     /* RFC 2017 */
00274        {
00275          if (url)
00276               return nsCRT::strdup(url);            /* it's already quoted and everything */
00277          else
00278               return 0;
00279        }
00280   else
00281        return 0;
00282 }
00283 
00284 #ifdef XP_MAC
00285 #ifdef DEBUG
00286 #pragma global_optimizer on
00287 #pragma optimization_level 1
00288 #endif /* DEBUG */
00289 #endif /* XP_MAC */
00290 
00291 static int
00292 MimeExternalBody_parse_eof (MimeObject *obj, PRBool abort_p)
00293 {
00294   int status = 0;
00295   MimeExternalBody *bod = (MimeExternalBody *) obj;
00296 
00297   if (obj->closed_p) return 0;
00298 
00299   /* Run parent method first, to flush out any buffered data. */
00300   status = ((MimeObjectClass*)&MIME_SUPERCLASS)->parse_eof(obj, abort_p);
00301   if (status < 0) return status;
00302 
00303 #if defined(XP_MAC) || defined(XP_MACOSX)
00304   if (obj->parent && mime_typep(obj->parent, 
00305          (MimeObjectClass*) &mimeMultipartAppleDoubleClass))
00306          goto done;
00307 #endif /* XP_MAC */
00308 
00309   if (!abort_p &&
00310          obj->output_p &&
00311          obj->options &&
00312          obj->options->write_html_p)
00313        {
00314          PRBool all_headers_p = obj->options->headers == MimeHeadersAll;
00315          MimeDisplayOptions *newopt = obj->options;  /* copy it */
00316 
00317          char *ct = MimeHeaders_get(obj->headers, HEADER_CONTENT_TYPE,
00318                                                          PR_FALSE, PR_FALSE);
00319          char *at, *lexp, *size, *perm;
00320          char *url, *dir, *mode, *name, *site, *svr, *subj;
00321          char *h = 0, *lname = 0, *lurl = 0, *body = 0;
00322          MimeHeaders *hdrs = 0;
00323 
00324          if (!ct) return MIME_OUT_OF_MEMORY;
00325 
00326          at   = MimeHeaders_get_parameter(ct, "access-type", NULL, NULL);
00327          lexp  = MimeHeaders_get_parameter(ct, "expiration", NULL, NULL);
00328          size = MimeHeaders_get_parameter(ct, "size", NULL, NULL);
00329          perm = MimeHeaders_get_parameter(ct, "permission", NULL, NULL);
00330          dir  = MimeHeaders_get_parameter(ct, "directory", NULL, NULL);
00331          mode = MimeHeaders_get_parameter(ct, "mode", NULL, NULL);
00332          name = MimeHeaders_get_parameter(ct, "name", NULL, NULL);
00333          site = MimeHeaders_get_parameter(ct, "site", NULL, NULL);
00334          svr  = MimeHeaders_get_parameter(ct, "server", NULL, NULL);
00335          subj = MimeHeaders_get_parameter(ct, "subject", NULL, NULL);
00336          url  = MimeHeaders_get_parameter(ct, "url", NULL, NULL);
00337          PR_FREEIF(ct);
00338 
00339          /* the *internal* content-type */
00340          ct = MimeHeaders_get(bod->hdrs, HEADER_CONTENT_TYPE,
00341                                              PR_TRUE, PR_FALSE);
00342 
00343       PRUint32 hlen = ((at ? strlen(at) : 0) +
00344                       (lexp ? strlen(lexp) : 0) +
00345                       (size ? strlen(size) : 0) +
00346                       (perm ? strlen(perm) : 0) +
00347                       (dir ? strlen(dir) : 0) +
00348                       (mode ? strlen(mode) : 0) +
00349                       (name ? strlen(name) : 0) +
00350                       (site ? strlen(site) : 0) +
00351                       (svr ? strlen(svr) : 0) +
00352                       (subj ? strlen(subj) : 0) +
00353                       (ct ? strlen(ct) : 0) +
00354                       (url ? strlen(url) : 0) + 100);
00355       h = (char *) PR_MALLOC(hlen);
00356          if (!h)
00357               {
00358                 status = MIME_OUT_OF_MEMORY;
00359                 goto FAIL;
00360               }
00361 
00362          /* If there's a URL parameter, remove all whitespace from it.
00363                (The URL parameter to one of these headers is stored with
00364                lines broken every 40 characters or less; it's assumed that
00365                all significant whitespace was URL-hex-encoded, and all the
00366                rest of it was inserted just to keep the lines short.)
00367           */
00368          if (url)
00369               {
00370                 char *in, *out;
00371                 for (in = url, out = url; *in; in++)
00372                      if (!nsCRT::IsAsciiSpace(*in))
00373                        *out++ = *in;
00374                 *out = 0;
00375               }
00376 
00377          hdrs = MimeHeaders_new();
00378          if (!hdrs)
00379               {
00380                 status = MIME_OUT_OF_MEMORY;
00381                 goto FAIL;
00382               }
00383 
00384 # define FROB(STR,VAR) \
00385          if (VAR) \
00386               { \
00387                 PL_strncpyz(h, STR ": ", hlen); \
00388                 PL_strcatn(h, hlen, VAR); \
00389                 PL_strcatn(h, hlen, MSG_LINEBREAK); \
00390                 status = MimeHeaders_parse_line(h, strlen(h), hdrs); \
00391                 if (status < 0) goto FAIL; \
00392               }
00393          FROB("Access-Type",       at);
00394          FROB("URL",               url);
00395          FROB("Site",                     site);
00396          FROB("Server",            svr);
00397          FROB("Directory",         dir);
00398          FROB("Name",                     name);
00399       FROB("Type",                 ct);
00400          FROB("Size",                     size);
00401          FROB("Mode",                     mode);
00402          FROB("Permission", perm);
00403          FROB("Expiration", lexp);
00404          FROB("Subject",           subj);
00405 # undef FROB
00406          PL_strncpyz(h, MSG_LINEBREAK, hlen);
00407          status = MimeHeaders_parse_line(h, strlen(h), hdrs);
00408          if (status < 0) goto FAIL;
00409 
00410          lurl = MimeExternalBody_make_url(ct, at, lexp, size, perm, dir, mode,
00411                                                                   name, url, site, svr, subj, bod->body);
00412          if (lurl)
00413               {
00414                 lname = MimeGetStringByID(MIME_MSG_LINK_TO_DOCUMENT);
00415               }
00416          else
00417               {
00418                 lname = MimeGetStringByID(MIME_MSG_DOCUMENT_INFO);
00419                 all_headers_p = PR_TRUE;
00420               }
00421               
00422          all_headers_p = PR_TRUE;  /* #### just do this all the time? */
00423 
00424          if (bod->body && all_headers_p)
00425               {
00426                 char *s = bod->body;
00427                 while (nsCRT::IsAsciiSpace(*s)) s++;
00428                 if (*s)
00429                      {
00430                        char *s2;
00431                        const char *pre = "<P><PRE>";
00432                        const char *suf = "</PRE>";
00433                        PRInt32 i;
00434                        for(i = strlen(s)-1; i >= 0 && nsCRT::IsAsciiSpace(s[i]); i--)
00435                             s[i] = 0;
00436                        s2 = nsEscapeHTML(s);
00437                        if (!s2) goto FAIL;
00438                        body = (char *) PR_MALLOC(strlen(pre) + strlen(s2) +
00439                                                                   strlen(suf) + 1);
00440                        if (!body)
00441                             {
00442                               nsCRT::free(s2);
00443                               goto FAIL;
00444                             }
00445                        PL_strcpy(body, pre);
00446                        PL_strcat(body, s2);
00447                        PL_strcat(body, suf);
00448                      }
00449               }
00450 
00451          newopt->fancy_headers_p = PR_TRUE;
00452          newopt->headers = (all_headers_p ? MimeHeadersAll : MimeHeadersSome);
00453 
00454        FAIL:
00455          if (hdrs)
00456               MimeHeaders_free(hdrs);
00457          PR_FREEIF(h);
00458          PR_FREEIF(lname);
00459          PR_FREEIF(lurl);
00460          PR_FREEIF(body);
00461          PR_FREEIF(ct);
00462          PR_FREEIF(at);
00463          PR_FREEIF(lexp);
00464          PR_FREEIF(size);
00465          PR_FREEIF(perm);
00466          PR_FREEIF(dir);
00467          PR_FREEIF(mode);
00468          PR_FREEIF(name);
00469          PR_FREEIF(url);
00470          PR_FREEIF(site);
00471          PR_FREEIF(svr);
00472          PR_FREEIF(subj);
00473        }
00474 
00475 #if defined(XP_MAC) || defined(XP_MACOSX)
00476 done:
00477 #endif /* XP_MAC */
00478 
00479   return status;
00480 }
00481 
00482 #ifdef XP_MAC
00483 #ifdef DEBUG
00484 #pragma global_optimizer reset
00485 #endif /* DEBUG */
00486 #endif /* XP_MAC */
00487 
00488 #if 0
00489 #if defined(DEBUG) && defined(XP_UNIX)
00490 static int
00491 MimeExternalBody_debug_print (MimeObject *obj, PRFileDesc *stream, PRInt32 depth)
00492 {
00493   MimeExternalBody *bod = (MimeExternalBody *) obj;
00494   int i;
00495   char *ct, *ct2;
00496   char *addr = mime_part_address(obj);
00497 
00498   if (obj->headers)
00499        ct = MimeHeaders_get (obj->headers, HEADER_CONTENT_TYPE, PR_FALSE, PR_FALSE);
00500   if (bod->hdrs)
00501        ct2 = MimeHeaders_get (bod->hdrs, HEADER_CONTENT_TYPE, PR_FALSE, PR_FALSE);
00502 
00503   for (i=0; i < depth; i++)
00504        PR_Write(stream, "  ", 2);
00505 /***
00506   fprintf(stream,
00507                 "<%s %s\n"
00508                 "\tcontent-type: %s\n"
00509                 "\tcontent-type: %s\n"
00510                 "\tBody:%s\n\t0x%08X>\n\n",
00511                 obj->clazz->class_name,
00512                 addr ? addr : "???",
00513                 ct ? ct : "<none>",
00514                 ct2 ? ct2 : "<none>",
00515                 bod->body ? bod->body : "<none>",
00516                 (PRUint32) obj);
00517 ***/
00518   PR_FREEIF(addr);
00519   PR_FREEIF(ct);
00520   PR_FREEIF(ct2);
00521   return 0;
00522 }
00523 #endif
00524 #endif /* 0 */
00525 
00526 static PRBool
00527 MimeExternalBody_displayable_inline_p (MimeObjectClass *clazz,
00528                                                                   MimeHeaders *hdrs)
00529 {
00530   char *ct = MimeHeaders_get (hdrs, HEADER_CONTENT_TYPE, PR_FALSE, PR_FALSE);
00531   char *at = MimeHeaders_get_parameter(ct, "access-type", NULL, NULL);
00532   PRBool inline_p = PR_FALSE;
00533 
00534   if (!at)
00535        ;
00536   else if (!nsCRT::strcasecmp(at, "ftp") ||
00537                  !nsCRT::strcasecmp(at, "anon-ftp") ||
00538                  !nsCRT::strcasecmp(at, "local-file") ||
00539                  !nsCRT::strcasecmp(at, "mail-server") ||
00540                  !nsCRT::strcasecmp(at, "url"))
00541        inline_p = PR_TRUE;
00542 #ifdef XP_UNIX
00543   else if (!nsCRT::strcasecmp(at, "afs"))   /* only if there is a /afs/ directory */
00544        {
00545     nsFileSpec    fs("/afs/.");
00546     if  (!fs.Exists())
00547       return 0;
00548 
00549     inline_p = PR_TRUE;
00550        }
00551 #endif /* XP_UNIX */
00552 
00553   PR_FREEIF(ct);
00554   PR_FREEIF(at);
00555   return inline_p;
00556 }