Back to index

lightning-sunbird  0.9+nobinonly
mimehdrs.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 #include "nsCOMPtr.h"
00038 #include "msgCore.h"
00039 #include "mimei.h"
00040 #include "prmem.h"
00041 #include "prlog.h"
00042 #include "plstr.h"
00043 #include "mimebuf.h"
00044 #include "mimemoz2.h"
00045 #include "nsIMimeEmitter.h"
00046 #include "nsCRT.h"
00047 #include "nsEscape.h"
00048 #include "nsMsgMessageFlags.h"
00049 #include "comi18n.h"
00050 #include "nsMailHeaders.h"
00051 #include "msgCore.h"
00052 #include "nsMimeStringResources.h"
00053 #include "mimemoz2.h"
00054 #include "nsMsgI18N.h"
00055 #include "mimehdrs.h"
00056 #include "nsIMIMEHeaderParam.h" 
00057 #include "nsNetCID.h"
00058 
00059 // Forward declares...
00060 PRInt32 MimeHeaders_build_heads_list(MimeHeaders *hdrs);
00061 
00062 static void
00063 MimeHeaders_convert_header_value(MimeDisplayOptions *opt, nsAFlatCString &value)
00064 {
00065   char        *converted;
00066 
00067   if (value.IsEmpty())
00068     return;
00069 
00070   if (opt && opt->rfc1522_conversion_p)
00071   {
00072     converted = MIME_DecodeMimeHeader(value.get(), opt->default_charset,
00073                                       opt->override_charset, PR_TRUE);
00074 
00075     if (converted)
00076     {
00077       value.Adopt(converted);
00078     }
00079   }
00080   else
00081   {
00082     // This behavior, though highly unusual, was carefully preserved
00083     // from the previous implementation.  It may be that this is dead
00084     // code, in which case opt->rfc1522_conversion_p is no longer
00085     // needed.
00086     value.Truncate();
00087   }
00088 }
00089 
00090 
00091 MimeHeaders *
00092 MimeHeaders_new (void)
00093 {
00094   MimeHeaders *hdrs = (MimeHeaders *) PR_MALLOC(sizeof(MimeHeaders));
00095   if (!hdrs) return 0;
00096 
00097   memset(hdrs, 0, sizeof(*hdrs));
00098   hdrs->done_p = PR_FALSE;
00099 
00100   return hdrs;
00101 }
00102 
00103 void
00104 MimeHeaders_free (MimeHeaders *hdrs)
00105 {
00106   if (!hdrs) return;
00107   PR_FREEIF(hdrs->all_headers);
00108   PR_FREEIF(hdrs->heads);
00109   PR_FREEIF(hdrs->obuffer);
00110   PR_FREEIF(hdrs->munged_subject);
00111   hdrs->obuffer_fp = 0;
00112   hdrs->obuffer_size = 0;
00113 
00114 # ifdef DEBUG__
00115   {
00116        int i, size = sizeof(*hdrs);
00117        PRUint32 *array = (PRUint32*) hdrs;
00118        for (i = 0; i < (size / sizeof(*array)); i++)
00119          array[i] = (PRUint32) 0xDEADBEEF;
00120   }
00121 # endif /* DEBUG */
00122 
00123   PR_Free(hdrs);
00124 }
00125 
00126 int
00127 MimeHeaders_parse_line (const char *buffer, PRInt32 size, MimeHeaders *hdrs)
00128 {
00129   int status = 0;
00130   int desired_size;
00131 
00132   NS_ASSERTION(hdrs, "1.22 <rhp@netscape.com> 22 Aug 1999 08:48");
00133   if (!hdrs) return -1;
00134 
00135   /* Don't try and feed me more data after having fed me a blank line... */
00136   NS_ASSERTION(!hdrs->done_p, "1.22 <rhp@netscape.com> 22 Aug 1999 08:48");
00137   if (hdrs->done_p) return -1;
00138 
00139   if (!buffer || size == 0 || *buffer == nsCRT::CR || *buffer == nsCRT::LF)
00140        {
00141          /* If this is a blank line, we're done.
00142           */
00143          hdrs->done_p = PR_TRUE;
00144          return MimeHeaders_build_heads_list(hdrs);
00145        }
00146 
00147   /* Tack this data on to the end of our copy.
00148    */
00149   desired_size = hdrs->all_headers_fp + size + 1;
00150   if (desired_size >= hdrs->all_headers_size)
00151        {
00152          status = mime_GrowBuffer (desired_size, sizeof(char), 255,
00153                                                     &hdrs->all_headers, &hdrs->all_headers_size);
00154          if (status < 0) return status;
00155        }
00156   memcpy(hdrs->all_headers+hdrs->all_headers_fp, buffer, size);
00157   hdrs->all_headers_fp += size;
00158 
00159   return 0;
00160 }
00161 
00162 MimeHeaders *
00163 MimeHeaders_copy (MimeHeaders *hdrs)
00164 {
00165   MimeHeaders *hdrs2;
00166   if (!hdrs) return 0;
00167 
00168   hdrs2 = (MimeHeaders *) PR_MALLOC(sizeof(*hdrs));
00169   if (!hdrs2) return 0;
00170   memset(hdrs2, 0, sizeof(*hdrs2));
00171 
00172   if (hdrs->all_headers)
00173        {
00174          hdrs2->all_headers = (char *) PR_MALLOC(hdrs->all_headers_fp);
00175          if (!hdrs2->all_headers)
00176               {
00177                 PR_Free(hdrs2);
00178                 return 0;
00179               }
00180          memcpy(hdrs2->all_headers, hdrs->all_headers, hdrs->all_headers_fp);
00181 
00182          hdrs2->all_headers_fp   = hdrs->all_headers_fp;
00183          hdrs2->all_headers_size = hdrs->all_headers_fp;
00184        }
00185 
00186   hdrs2->done_p = hdrs->done_p;
00187 
00188   if (hdrs->heads)
00189        {
00190          int i;
00191          hdrs2->heads = (char **) PR_MALLOC(hdrs->heads_size
00192                                                                       * sizeof(*hdrs->heads));
00193          if (!hdrs2->heads)
00194               {
00195                 PR_FREEIF(hdrs2->all_headers);
00196                 PR_Free(hdrs2);
00197                 return 0;
00198               }
00199          hdrs2->heads_size = hdrs->heads_size;
00200          for (i = 0; i < hdrs->heads_size; i++)
00201               {
00202                 hdrs2->heads[i] = (hdrs2->all_headers +
00203                                                   (hdrs->heads[i] - hdrs->all_headers));
00204               }
00205        }
00206   return hdrs2;
00207 }
00208 
00209 int
00210 MimeHeaders_build_heads_list(MimeHeaders *hdrs)
00211 {
00212   char *s;
00213   char *end;
00214   int i;
00215   NS_ASSERTION(hdrs, "1.1 <rhp@netscape.com> 19 Mar 1999 12:00");
00216   if (!hdrs) return -1;
00217 
00218   NS_ASSERTION(hdrs->done_p && !hdrs->heads, "1.1 <rhp@netscape.com> 19 Mar 1999 12:00");
00219   if (!hdrs->done_p || hdrs->heads)
00220        return -1;
00221 
00222   if (hdrs->all_headers_fp == 0)
00223        {
00224          /* Must not have been any headers (we got the blank line right away.) */
00225          PR_FREEIF (hdrs->all_headers);
00226          hdrs->all_headers_size = 0;
00227          return 0;
00228        }
00229 
00230   /* At this point, we might as well realloc all_headers back down to the
00231         minimum size it must be (it could be up to 1k bigger.)  But don't
00232         bother if we're only off by a tiny bit. */
00233   NS_ASSERTION(hdrs->all_headers_fp <= hdrs->all_headers_size, "1.1 <rhp@netscape.com> 19 Mar 1999 12:00");
00234   if (hdrs->all_headers_fp + 60 <= hdrs->all_headers_size)
00235        {
00236          char *ls = (char *)PR_Realloc(hdrs->all_headers, hdrs->all_headers_fp);
00237          if (ls) /* can this ever fail?  we're making it smaller... */
00238               {
00239                 hdrs->all_headers = ls;  /* in case it got relocated */
00240                 hdrs->all_headers_size = hdrs->all_headers_fp;
00241               }
00242        }
00243 
00244 
00245   /* First go through and count up the number of headers in the block.
00246    */
00247   end = hdrs->all_headers + hdrs->all_headers_fp;
00248   for (s = hdrs->all_headers; s <= end-1; s++)
00249        {
00250          if (s <= (end-1) && s[0] == nsCRT::CR && s[1] == nsCRT::LF) /* CRLF -> LF */
00251               s++;
00252 
00253          if ((s[0] == nsCRT::CR || s[0] == nsCRT::LF) &&                     /* we're at a newline, and */
00254                 (s >= (end-1) ||                                      /* we're at EOF, or */
00255                  !(s[1] == ' ' || s[1] == '\t')))              /* next char is nonwhite */
00256               hdrs->heads_size++;
00257        }
00258          
00259   /* Now allocate storage for the pointers to each of those headers.
00260    */
00261   hdrs->heads = (char **) PR_MALLOC((hdrs->heads_size + 1) * sizeof(char *));
00262   if (!hdrs->heads)
00263        return MIME_OUT_OF_MEMORY;
00264   memset(hdrs->heads, 0, (hdrs->heads_size + 1) * sizeof(char *));
00265 
00266 
00267   /* Now make another pass through the headers, and this time, record the
00268         starting position of each header.
00269    */
00270 
00271   i = 0;
00272   hdrs->heads[i++] = hdrs->all_headers;
00273   s = hdrs->all_headers;
00274 
00275   while (s <= end)
00276        {
00277        SEARCH_NEWLINE:
00278          while (s <= end-1 && *s != nsCRT::CR && *s != nsCRT::LF)
00279               s++;
00280 
00281          if (s+1 >= end)
00282               break;
00283 
00284          /* If "\r\n " or "\r\n\t" is next, that doesn't terminate the header. */
00285          else if (s+2 < end &&
00286                         (s[0] == nsCRT::CR  && s[1] == nsCRT::LF) &&
00287                         (s[2] == ' ' || s[2] == '\t'))
00288               {
00289                 s += 3;
00290                 goto SEARCH_NEWLINE;
00291               }
00292          /* If "\r " or "\r\t" or "\n " or "\n\t" is next, that doesn't terminate
00293                the header either. */
00294          else if ((s[0] == nsCRT::CR  || s[0] == nsCRT::LF) &&
00295                         (s[1] == ' ' || s[1] == '\t'))
00296               {
00297                 s += 2;
00298                 goto SEARCH_NEWLINE;
00299               }
00300 
00301          /* At this point, `s' points before a header-terminating newline.
00302                Move past that newline, and store that new position in `heads'.
00303           */
00304          if (*s == nsCRT::CR) s++;
00305          if (*s == nsCRT::LF) s++;
00306 
00307          if (s < end)
00308               {
00309                 NS_ASSERTION(! (i > hdrs->heads_size), "1.1 <rhp@netscape.com> 19 Mar 1999 12:00");
00310                 if (i > hdrs->heads_size) return -1;
00311                 hdrs->heads[i++] = s;
00312               }
00313        }
00314 
00315   return 0;
00316 }
00317 
00318 char *
00319 MimeHeaders_get (MimeHeaders *hdrs, const char *header_name,
00320                              PRBool strip_p, PRBool all_p)
00321 {
00322   int i;
00323   int name_length;
00324   char *result = 0;
00325 
00326 /*  PR_ASSERT(hdrs); cause delete message problem in WinFE */
00327   if (!hdrs) return 0;
00328   NS_ASSERTION(header_name, "1.1 <rhp@netscape.com> 19 Mar 1999 12:00");
00329   if (!header_name) return 0;
00330 
00331   /* Specifying strip_p and all_p at the same time doesn't make sense... */
00332   NS_ASSERTION(!(strip_p && all_p), "1.1 <rhp@netscape.com> 19 Mar 1999 12:00");
00333 
00334   /* One shouldn't be trying to read headers when one hasn't finished
00335         parsing them yet... but this can happen if the message ended
00336         prematurely, and has no body at all (as opposed to a null body,
00337         which is more normal.)   So, if we try to read from the headers,
00338         let's assume that the headers are now finished.  If they aren't
00339         in fact finished, then a later attempt to write to them will assert.
00340    */
00341   if (!hdrs->done_p)
00342        {
00343          int status;
00344          hdrs->done_p = PR_TRUE;
00345          status = MimeHeaders_build_heads_list(hdrs);
00346          if (status < 0) return 0;
00347        }
00348 
00349   if (!hdrs->heads)    /* Must not have been any headers. */
00350        {
00351          NS_ASSERTION(hdrs->all_headers_fp == 0, "1.1 <rhp@netscape.com> 19 Mar 1999 12:00");
00352          return 0;
00353        }
00354 
00355   name_length = strlen(header_name);
00356 
00357   for (i = 0; i < hdrs->heads_size; i++)
00358        {
00359          char *head = hdrs->heads[i];
00360          char *end = (i == hdrs->heads_size-1
00361                                ? hdrs->all_headers + hdrs->all_headers_fp
00362                                : hdrs->heads[i+1]);
00363          char *colon, *ocolon;
00364 
00365          NS_ASSERTION(head, "1.1 <rhp@netscape.com> 19 Mar 1999 12:00");
00366          if (!head) continue;
00367 
00368          /* Quick hack to skip over BSD Mailbox delimiter. */
00369          if (i == 0 && head[0] == 'F' && !strncmp(head, "From ", 5))
00370               continue;
00371 
00372          /* Find the colon. */
00373          for (colon = head; colon < end; colon++)
00374               if (*colon == ':') break;
00375 
00376          if (colon >= end) continue;
00377 
00378          /* Back up over whitespace before the colon. */
00379          ocolon = colon;
00380          for (; colon > head && nsCRT::IsAsciiSpace(colon[-1]); colon--)
00381               ;
00382 
00383          /* If the strings aren't the same length, it doesn't match. */
00384          if (name_length != colon - head )
00385               continue;
00386 
00387          /* If the strings differ, it doesn't match. */
00388          if (nsCRT::strncasecmp(header_name, head, name_length))
00389               continue;
00390 
00391          /* Otherwise, we've got a match. */
00392          {
00393               char *contents = ocolon + 1;
00394               char *s;
00395 
00396               /* Skip over whitespace after colon. */
00397               while (contents <= end && nsCRT::IsAsciiSpace(*contents))
00398                 contents++;
00399 
00400               /* If we're supposed to strip at the frist token, pull `end' back to
00401                  the first whitespace or ';' after the first token.
00402                */
00403               if (strip_p)
00404                 {
00405                      for (s = contents;
00406                              s <= end && *s != ';' && *s != ',' && !nsCRT::IsAsciiSpace(*s);
00407                              s++)
00408                        ;
00409                      end = s;
00410                 }
00411 
00412               /* Now allocate some storage.
00413                  If `result' already has a value, enlarge it.
00414                  Otherwise, just allocate a block.
00415                  `s' gets set to the place where the new data goes.
00416                */
00417               if (!result)
00418                 {
00419                      result = (char *) PR_MALLOC(end - contents + 1);
00420                      if (!result)
00421                        return 0;
00422                      s = result;
00423                 }
00424               else
00425                 {
00426                      PRInt32 L = strlen(result);
00427                      s = (char *) PR_Realloc(result, (L + (end - contents + 10)));
00428                      if (!s)
00429                        {
00430                             PR_Free(result);
00431                             return 0;
00432                        }
00433                      result = s;
00434                      s = result + L;
00435 
00436                      /* Since we are tacking more data onto the end of the header
00437                         field, we must make it be a well-formed continuation line,
00438                           by separating the old and new data with CR-LF-TAB.
00439                       */
00440                      *s++ = ',';                        /* #### only do this for addr headers? */
00441                      *s++ = MSG_LINEBREAK[0];
00442 # if (MSG_LINEBREAK_LEN == 2)
00443                      *s++ = MSG_LINEBREAK[1];
00444 # endif
00445                      *s++ = '\t';
00446                 }
00447 
00448               /* Take off trailing whitespace... */
00449               while (end > contents && nsCRT::IsAsciiSpace(end[-1]))
00450                 end--;
00451 
00452               if (end > contents)
00453                 {
00454                   /* Now copy the header's contents in...
00455                    */
00456                   memcpy(s, contents, end - contents);
00457                   s[end - contents] = 0;
00458                 }
00459               else
00460                 {
00461                   s[0] = 0;
00462                 }
00463 
00464               /* If we only wanted the first occurence of this header, we're done. */
00465               if (!all_p) break;
00466          }
00467        }
00468 
00469   if (result && !*result)  /* empty string */
00470        {
00471          PR_Free(result);
00472          return 0;
00473        }
00474 
00475   return result;
00476 }
00477 
00478 char *
00479 MimeHeaders_get_parameter (const char *header_value, const char *parm_name, 
00480                            char **charset, char **language)
00481 {
00482   if (!header_value || !parm_name || !*header_value || !*parm_name)
00483     return nsnull;
00484 
00485   nsresult rv;
00486   nsCOMPtr <nsIMIMEHeaderParam> mimehdrpar = 
00487     do_GetService(NS_MIMEHEADERPARAM_CONTRACTID, &rv);
00488 
00489   if (NS_FAILED(rv))
00490     return nsnull;
00491 
00492   nsXPIDLCString result;
00493   rv = mimehdrpar->GetParameterInternal(header_value, parm_name, charset, 
00494                                         language, getter_Copies(result));
00495   return NS_SUCCEEDED(rv) ? PL_strdup(result.get()) : nsnull; 
00496 }
00497 
00498 #define MimeHeaders_write(OPT,DATA,LENGTH) \
00499        MimeOptions_write((OPT), (DATA), (LENGTH), PR_TRUE);
00500 
00501 
00502 #define MimeHeaders_grow_obuffer(hdrs, desired_size) \
00503   ((((long) (desired_size)) >= ((long) (hdrs)->obuffer_size)) ? \
00504    mime_GrowBuffer ((desired_size), sizeof(char), 255, \
00505                                &(hdrs)->obuffer, &(hdrs)->obuffer_size) \
00506    : 0)
00507 
00508 int
00509 MimeHeaders_write_all_headers (MimeHeaders *hdrs, MimeDisplayOptions *opt, PRBool attachment)
00510 {
00511   int status = 0;
00512   int i;
00513   PRBool wrote_any_p = PR_FALSE;
00514 
00515   NS_ASSERTION(hdrs, "1.1 <rhp@netscape.com> 19 Mar 1999 12:00");
00516   if (!hdrs) 
00517     return -1;
00518 
00519   /* One shouldn't be trying to read headers when one hasn't finished
00520      parsing them yet... but this can happen if the message ended
00521      prematurely, and has no body at all (as opposed to a null body,
00522      which is more normal.)   So, if we try to read from the headers,
00523      let's assume that the headers are now finished.  If they aren't
00524      in fact finished, then a later attempt to write to them will assert.
00525    */
00526   if (!hdrs->done_p)
00527   {
00528     hdrs->done_p = PR_TRUE;
00529     status = MimeHeaders_build_heads_list(hdrs);
00530     if (status < 0) return 0;
00531   }
00532 
00533   char *charset = nsnull;
00534   if (opt->format_out == nsMimeOutput::nsMimeMessageSaveAs)
00535   {
00536     if (opt->override_charset)
00537       charset = PL_strdup(opt->default_charset);
00538     else
00539     {
00540       char *contentType = MimeHeaders_get(hdrs, HEADER_CONTENT_TYPE, PR_FALSE, PR_FALSE);
00541       if (contentType)
00542         charset = MimeHeaders_get_parameter(contentType, HEADER_PARM_CHARSET, nsnull, nsnull);
00543       PR_FREEIF(contentType);
00544     }
00545   }
00546 
00547   for (i = 0; i < hdrs->heads_size; i++)
00548   {
00549     char *head = hdrs->heads[i];
00550     char *end = (i == hdrs->heads_size-1
00551                       ? hdrs->all_headers + hdrs->all_headers_fp
00552                       : hdrs->heads[i+1]);
00553     char *colon, *ocolon;
00554     char *contents = end;
00555     
00556     /* Hack for BSD Mailbox delimiter. */
00557     if (i == 0 && head[0] == 'F' && !strncmp(head, "From ", 5))
00558     {
00559       /* For now, we don't really want this header to be output so
00560          we are going to just continue */
00561       continue;
00562       /* colon = head + 4; contents = colon + 1; */
00563     }
00564     else
00565     {
00566       /* Find the colon. */
00567       for (colon = head; colon < end && *colon != ':'; colon++)
00568         ;
00569         
00570         /* Back up over whitespace before the colon. */
00571         ocolon = colon;
00572         for (; colon > head && nsCRT::IsAsciiSpace(colon[-1]); colon--)
00573           ;
00574         
00575         contents = ocolon + 1;
00576     }
00577     
00578     /* Skip over whitespace after colon. */
00579     while (contents < end && nsCRT::IsAsciiSpace(*contents))
00580       contents++;
00581     
00582     /* Take off trailing whitespace... */
00583     while (end > contents && nsCRT::IsAsciiSpace(end[-1]))
00584       end--;
00585     
00586     nsCAutoString name(Substring(head, colon));
00587     nsCAutoString hdr_value;
00588 
00589     if ( (end - contents) > 0 )
00590     {
00591       hdr_value = Substring(contents, end);
00592     }
00593     
00594     MimeHeaders_convert_header_value(opt, hdr_value);
00595     // if we're saving as html, we need to convert headers from utf8 to message charset, if any
00596     if (opt->format_out == nsMimeOutput::nsMimeMessageSaveAs && charset)
00597     {
00598       nsCAutoString convertedStr;
00599       if (NS_SUCCEEDED(ConvertFromUnicode(charset, NS_ConvertUTF8toUTF16(hdr_value),
00600                        convertedStr)))
00601       {
00602         hdr_value = convertedStr;
00603       }
00604     }
00605 
00606     if (attachment)
00607       status = mimeEmitterAddAttachmentField(opt, name.get(), hdr_value.get());
00608     else
00609       status = mimeEmitterAddHeaderField(opt, name.get(), hdr_value.get());
00610     
00611     if (status < 0) return status;
00612     if (!wrote_any_p) 
00613       wrote_any_p = (status > 0);
00614   }
00615   mimeEmitterAddAllHeaders(opt, hdrs->all_headers, hdrs->all_headers_fp);
00616   PR_FREEIF(charset);
00617 
00618   return 1;
00619 }
00620 
00621 #ifdef MOZ_SECURITY
00622 HG99401
00623 #endif /* MOZ_SECURITY */
00624 
00625 /* Strip CR+LF runs within (original).
00626    Since the string at (original) can only shrink,
00627    this conversion is done in place. (original)
00628    is returned. */
00629 extern "C" char *
00630 MIME_StripContinuations(char *original)
00631 {
00632        char *p1, *p2;
00633 
00634        /* If we were given a null string, return it as is */
00635        if (!original) return NULL;
00636 
00637        /* Start source and dest pointers at the beginning */
00638        p1 = p2 = original;
00639 
00640        while(*p2)
00641        {
00642               /* p2 runs ahead at (CR and/or LF) */
00643               if ((p2[0] == nsCRT::CR) || (p2[0] == nsCRT::LF))
00644               {
00645             p2++;
00646               } else {
00647             *p1++ = *p2++;
00648         }
00649        }
00650        *p1 = '\0';
00651 
00652        return original;
00653 }
00654 
00655 extern PRInt16 INTL_DefaultMailToWinCharSetID(PRInt16 csid);
00656 
00657 /* Given text purporting to be a qtext header value, strip backslashes that
00658        may be escaping other chars in the string. */
00659 char *
00660 mime_decode_filename(char *name, const char *charset,
00661                      MimeDisplayOptions *opt)
00662 {
00663   nsresult rv;
00664   nsCOMPtr <nsIMIMEHeaderParam> mimehdrpar = 
00665     do_GetService(NS_MIMEHEADERPARAM_CONTRACTID, &rv);
00666 
00667   if (NS_FAILED(rv))
00668     return nsnull;
00669   nsCAutoString result;
00670   rv = mimehdrpar->DecodeParameter(nsDependentCString(name), charset,
00671                                    opt->default_charset,
00672                                    opt->override_charset, result);
00673   return NS_SUCCEEDED(rv) ? PL_strdup(result.get()) : nsnull; 
00674 }
00675 
00676 /* Pull the name out of some header or another.  Order is:
00677    Content-Disposition: XXX; filename=NAME (RFC 1521/1806)
00678    Content-Type: XXX; name=NAME (RFC 1341)
00679    Content-Name: NAME (no RFC, but seen to occur)
00680    X-Sun-Data-Name: NAME (no RFC, but used by MailTool)
00681  */
00682 char *
00683 MimeHeaders_get_name(MimeHeaders *hdrs, MimeDisplayOptions *opt)
00684 {
00685   char *s = 0, *name = 0, *cvt = 0;
00686   char *charset = nsnull; // for RFC2231 support
00687 
00688   s = MimeHeaders_get(hdrs, HEADER_CONTENT_DISPOSITION, PR_FALSE, PR_FALSE);
00689   if (s)
00690   {
00691     name = MimeHeaders_get_parameter(s, HEADER_PARM_FILENAME, &charset, NULL);
00692     PR_Free(s);
00693   }
00694 
00695   if (! name)
00696   {
00697     s = MimeHeaders_get(hdrs, HEADER_CONTENT_TYPE, PR_FALSE, PR_FALSE);
00698     if (s)
00699     {
00700       nsMemory::Free(charset);
00701 
00702       name = MimeHeaders_get_parameter(s, HEADER_PARM_NAME, &charset, NULL);
00703       PR_Free(s);
00704     }
00705   }
00706 
00707   if (! name)
00708     name = MimeHeaders_get (hdrs, HEADER_CONTENT_NAME, PR_FALSE, PR_FALSE);
00709   
00710   if (! name)
00711     name = MimeHeaders_get (hdrs, HEADER_X_SUN_DATA_NAME, PR_FALSE, PR_FALSE);
00712 
00713   if (name)
00714   {
00715     /* First remove continuation delimiters (CR+LF+space), then
00716        remove escape ('\\') characters, then attempt to decode
00717        mime-2 encoded-words. The latter two are done in 
00718        mime_decode_filename. 
00719     */
00720     MIME_StripContinuations(name);
00721 
00722     /* Argh. What we should do if we want to be robust is to decode qtext
00723        in all appropriate headers. Unfortunately, that would be too scary
00724        at this juncture. So just decode qtext/mime2 here. */
00725     cvt = mime_decode_filename(name, charset, opt);
00726 
00727     nsMemory::Free(charset);
00728 
00729     if (cvt && cvt != name)
00730     {
00731       PR_Free(name);
00732       name = cvt;
00733     }
00734   }
00735 
00736   return name;
00737 }
00738 
00739 #ifdef XP_UNIX
00740 /* This piece of junk is so that I can use BBDB with Mozilla.
00741    = Put bbdb-srv.perl on your path.
00742    = Put bbdb-srv.el on your lisp path.
00743    = Make sure gnudoit (comes with xemacs) is on your path.
00744    = Put (gnuserv-start) in ~/.emacs
00745    = setenv NS_MSG_DISPLAY_HOOK bbdb-srv.perl
00746  */
00747 void
00748 MimeHeaders_do_unix_display_hook_hack(MimeHeaders *hdrs)
00749 {
00750   static char *cmd = 0;
00751   if (!cmd)
00752   {
00753   /* The first time we're invoked, look up the command in the
00754     environment.  Use "" as the `no command' tag. */
00755     cmd = getenv("NS_MSG_DISPLAY_HOOK");
00756     if (!cmd)
00757       cmd = "";
00758     else
00759       cmd = nsCRT::strdup(cmd);
00760   }
00761   
00762   /* Invoke "cmd" at the end of a pipe, and give it the headers on stdin.
00763         The command is expected to be safe from hostile input!!
00764   */
00765   if (cmd && *cmd)
00766   {
00767     FILE *fp = popen(cmd, "w");
00768     if (fp)
00769     {
00770       fwrite(hdrs->all_headers, 1, hdrs->all_headers_fp, fp);
00771       pclose(fp);
00772     }
00773   }
00774 }
00775 #endif /* XP_UNIX */
00776 
00777 static void
00778 MimeHeaders_compact (MimeHeaders *hdrs)
00779 {
00780   NS_ASSERTION(hdrs, "1.22 <rhp@netscape.com> 22 Aug 1999 08:48");
00781   if (!hdrs) return;
00782 
00783   PR_FREEIF(hdrs->obuffer);
00784   hdrs->obuffer_fp = 0;
00785   hdrs->obuffer_size = 0;
00786 
00787   /* These really shouldn't have gotten out of whack again. */
00788   NS_ASSERTION(hdrs->all_headers_fp <= hdrs->all_headers_size &&
00789             hdrs->all_headers_fp + 100 > hdrs->all_headers_size, "1.22 <rhp@netscape.com> 22 Aug 1999 08:48");
00790 }
00791 
00792 /* Writes the headers as text/plain.
00793    This writes out a blank line after the headers, unless
00794    dont_write_content_type is true, in which case the header-block
00795    is not closed off, and none of the Content- headers are written.
00796  */
00797 int
00798 MimeHeaders_write_raw_headers (MimeHeaders *hdrs, MimeDisplayOptions *opt,
00799                                                     PRBool dont_write_content_type)
00800 {
00801   int status;
00802 
00803   if (hdrs && !hdrs->done_p)
00804        {
00805          hdrs->done_p = PR_TRUE;
00806          status = MimeHeaders_build_heads_list(hdrs);
00807          if (status < 0) return 0;
00808        }
00809 
00810   if (!dont_write_content_type)
00811        {
00812          char nl[] = MSG_LINEBREAK;
00813          if (hdrs)
00814               {
00815                 status = MimeHeaders_write(opt, hdrs->all_headers,
00816                                                                 hdrs->all_headers_fp);
00817                 if (status < 0) return status;
00818               }
00819          status = MimeHeaders_write(opt, nl, strlen(nl));
00820          if (status < 0) return status;
00821        }
00822   else if (hdrs)
00823        {
00824          PRInt32 i;
00825          for (i = 0; i < hdrs->heads_size; i++)
00826               {
00827                 char *head = hdrs->heads[i];
00828                 char *end = (i == hdrs->heads_size-1
00829                                       ? hdrs->all_headers + hdrs->all_headers_fp
00830                                       : hdrs->heads[i+1]);
00831 
00832                 NS_ASSERTION(head, "1.22 <rhp@netscape.com> 22 Aug 1999 08:48");
00833                 if (!head) continue;
00834 
00835                 /* Don't write out any Content- header. */
00836                 if (!nsCRT::strncasecmp(head, "Content-", 8))
00837                      continue;
00838 
00839                 /* Write out this (possibly multi-line) header. */
00840                 status = MimeHeaders_write(opt, head, end - head);
00841                 if (status < 0) return status;
00842               }
00843        }
00844 
00845   if (hdrs)
00846        MimeHeaders_compact (hdrs);
00847 
00848   return 0;
00849 }
00850 
00851 // XXX Fix this XXX //
00852 char *
00853 MimeHeaders_open_crypto_stamp(void)
00854 {
00855   return nsnull;
00856 }
00857 
00858 char *
00859 MimeHeaders_finish_open_crypto_stamp(void)
00860 {
00861   return nsnull;
00862 }
00863 
00864 char *
00865 MimeHeaders_close_crypto_stamp(void)
00866 {
00867   return nsnull;
00868 }
00869 
00870 char *
00871 MimeHeaders_make_crypto_stamp(PRBool encrypted_p,
00872                               PRBool signed_p,
00873                               PRBool good_p,
00874                               PRBool unverified_p,
00875                               PRBool close_parent_stamp_p,
00876                               const char *stamp_url)
00877 {
00878   return nsnull;
00879 }