Back to index

lightning-sunbird  0.9+nobinonly
nsMsgSendPart.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; 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 "nsMsgLocalFolderHdrs.h"
00039 #include "nsMsgSend.h"
00040 #include "nsMsgSendPart.h"
00041 #include "nsIMimeConverter.h"
00042 #include "nsFileStream.h"
00043 #include "nsCOMPtr.h"
00044 #include "nsIComponentManager.h"
00045 #include "nsMsgEncoders.h"
00046 #include "nsMsgI18N.h"
00047 #include "nsMsgCompUtils.h"
00048 #include "nsFileStream.h"
00049 #include "nsMsgMimeCID.h"
00050 #include "nsMimeTypes.h"
00051 #include "prmem.h"
00052 #include "nsMsgPrompts.h"
00053 #include "nsMsgComposeStringBundle.h"
00054 #include "nsNativeCharsetUtils.h"
00055 
00056 // defined in msgCompGlue.cpp
00057 static char *mime_mailto_stream_read_buffer = 0;
00058 
00059 PRInt32 nsMsgSendPart::M_counter = 0;
00060 
00061 nsMsgSendPart::nsMsgSendPart(nsIMsgSend* state, const char *part_charset)
00062 {
00063   m_state = nsnull;
00064 
00065   PL_strncpy(m_charset_name, (part_charset ? part_charset : "us-ascii"), sizeof(m_charset_name)-1);
00066   m_charset_name[sizeof(m_charset_name)-1] = '\0';
00067   m_children = nsnull;
00068   m_numchildren = 0;
00069   
00070   SetMimeDeliveryState(state);
00071 
00072   m_parent = nsnull;
00073   m_filespec = nsnull;
00074   m_buffer = nsnull;
00075   m_type = nsnull;
00076   m_other = nsnull;
00077   m_strip_sensitive_headers = PR_FALSE;
00078   m_encoder_data = nsnull;
00079   
00080   m_firstBlock = PR_FALSE;
00081   m_needIntlConversion = PR_FALSE;
00082   
00083   m_mainpart = PR_FALSE;
00084   m_just_hit_CR = PR_FALSE;
00085 }
00086 
00087 
00088 nsMsgSendPart::~nsMsgSendPart()
00089 {
00090   if (m_encoder_data) {
00091     MIME_EncoderDestroy(m_encoder_data, PR_FALSE);
00092     m_encoder_data = nsnull;
00093   }
00094   for (int i=0 ; i < m_numchildren; i++)
00095     delete m_children[i];
00096 
00097   delete [] m_children;
00098     PR_FREEIF(m_buffer);
00099   PR_FREEIF(m_other);
00100   if (m_filespec)
00101     delete m_filespec;
00102   PR_FREEIF(m_type);
00103 }
00104 
00105 int nsMsgSendPart::CopyString(char** dest, const char* src)
00106 {
00107   NS_ASSERTION(src, "src null");
00108   
00109   PR_FREEIF(*dest);
00110   if (!src)
00111     *dest = PL_strdup("");
00112   else
00113     *dest = PL_strdup(src);
00114   
00115   return *dest? 0 : NS_ERROR_OUT_OF_MEMORY;
00116 }
00117 
00118 
00119 int nsMsgSendPart::SetFile(nsFileSpec *filename)
00120 {
00121   m_filespec = new nsFileSpec(*filename);
00122   if (!m_filespec)
00123     return NS_ERROR_OUT_OF_MEMORY;
00124   else
00125     return NS_OK;
00126 }
00127 
00128 
00129 int nsMsgSendPart::SetBuffer(const char* buffer)
00130 {
00131   PR_FREEIF(m_buffer);
00132   return CopyString(&m_buffer, buffer);
00133 }
00134 
00135 
00136 int nsMsgSendPart::SetType(const char* type)
00137 {
00138   PR_FREEIF(m_type);
00139   m_type = PL_strdup(type);
00140   return m_type ? 0 : NS_ERROR_OUT_OF_MEMORY;
00141 }
00142 
00143 
00144 int nsMsgSendPart::SetOtherHeaders(const char* other)
00145 {
00146   return CopyString(&m_other, other);
00147 }
00148 
00149 int nsMsgSendPart::SetMimeDeliveryState(nsIMsgSend *state)
00150 {
00151   m_state = state;
00152   if (GetNumChildren() > 0)
00153   {
00154     for (int i = 0; i < GetNumChildren(); i++)
00155     {
00156       nsMsgSendPart *part = GetChild(i);
00157       if (part) 
00158         part->SetMimeDeliveryState(state);
00159     }
00160   }
00161   return 0;
00162 }
00163 
00164 int nsMsgSendPart::AppendOtherHeaders(const char* more)
00165 {
00166   if (!m_other)
00167     return SetOtherHeaders(more);
00168 
00169   if (!more || !*more)
00170     return 0;
00171 
00172   char* tmp = (char *) PR_Malloc(sizeof(char) * (PL_strlen(m_other) + PL_strlen(more) + 2));
00173   if (!tmp)
00174     return NS_ERROR_OUT_OF_MEMORY;
00175 
00176   PL_strcpy(tmp, m_other);
00177   PL_strcat(tmp, more);
00178   PR_FREEIF(m_other);
00179   m_other = tmp;
00180 
00181   return 0;
00182 }
00183 
00184 
00185 int nsMsgSendPart::SetEncoderData(MimeEncoderData* data)
00186 {
00187   m_encoder_data = data;
00188   return 0;
00189 }
00190 
00191 int nsMsgSendPart::SetMainPart(PRBool value)
00192 {
00193   m_mainpart = value;
00194   return 0;
00195 }
00196 
00197 int nsMsgSendPart::AddChild(nsMsgSendPart* child)
00198 {
00199   m_numchildren++;
00200   nsMsgSendPart** tmp = new nsMsgSendPart* [m_numchildren];
00201   if (tmp == nsnull) return NS_ERROR_OUT_OF_MEMORY;
00202   for (int i=0 ; i<m_numchildren-1 ; i++) {
00203     tmp[i] = m_children[i];
00204   }
00205   delete [] m_children;
00206   m_children = tmp;
00207   m_children[m_numchildren - 1] = child;
00208   child->m_parent = this;
00209   return 0;
00210 }
00211 
00212 nsMsgSendPart * nsMsgSendPart::DetachChild(PRInt32 whichOne)
00213 {
00214   nsMsgSendPart *returnValue = nsnull;
00215   
00216   NS_ASSERTION(whichOne >= 0 && whichOne < m_numchildren, "parameter out of range");
00217   if (whichOne >= 0 && whichOne < m_numchildren) 
00218   {
00219     returnValue = m_children[whichOne];
00220     
00221     if (m_numchildren > 1)
00222     {
00223       nsMsgSendPart** tmp = new nsMsgSendPart* [m_numchildren-1];
00224       if (tmp != nsnull) 
00225       {
00226         // move all the other kids over
00227         for (int i=0 ; i<m_numchildren-1 ; i++) 
00228         {
00229           if (i >= whichOne)
00230             tmp[i] = m_children[i+1];
00231           else
00232             tmp[i] = m_children[i];
00233         }
00234         delete [] m_children;
00235         m_children = tmp;
00236         m_numchildren--;
00237       }
00238     }
00239     else 
00240     {
00241       delete [] m_children;
00242       m_children = nsnull;
00243       m_numchildren = 0;
00244     }
00245   }
00246   
00247   if (returnValue)
00248     returnValue->m_parent = nsnull;
00249   
00250   return returnValue;
00251 }
00252 
00253 nsMsgSendPart* nsMsgSendPart::GetChild(PRInt32 which)
00254 {
00255   NS_ASSERTION(which >= 0 && which < m_numchildren, "parameter out of range");
00256   if (which >= 0 && which < m_numchildren) {
00257     return m_children[which];
00258   }
00259   return nsnull;
00260 }
00261 
00262 
00263 
00264 int nsMsgSendPart::PushBody(char* buffer, PRInt32 length)
00265 {
00266   int status = 0;
00267   char* encoded_data = buffer;
00268   
00269   if (m_encoder_data) 
00270   {
00271     status = MIME_EncoderWrite(m_encoder_data, encoded_data, length);
00272   } 
00273   else 
00274   {
00275     // Merely translate all linebreaks to CRLF.
00276     const char *in = encoded_data;
00277     const char *end = in + length;
00278     char *buffer, *out;
00279     
00280     
00281     buffer = mime_get_stream_write_buffer();
00282     if (!buffer) return NS_ERROR_OUT_OF_MEMORY;
00283     
00284     NS_ASSERTION(encoded_data != buffer, "encoded_data == buffer");
00285     out = buffer;
00286     
00287     for (; in < end; in++) {
00288       if (m_just_hit_CR) {
00289         m_just_hit_CR = PR_FALSE;
00290         if (*in == nsCRT::LF) {
00291           // The last thing we wrote was a CRLF from hitting a CR.
00292           // So, we don't want to do anything from a following LF;
00293           // we want to ignore it.
00294           continue;
00295         }
00296       }
00297       if (*in == nsCRT::CR || *in == nsCRT::LF) {
00298         /* Write out the newline. */
00299         *out++ = nsCRT::CR;
00300         *out++ = nsCRT::LF;
00301         
00302         status = mime_write_message_body(m_state, buffer,
00303           out - buffer);
00304         if (status < 0) return status;
00305         out = buffer;
00306         
00307         if (*in == nsCRT::CR) {
00308           m_just_hit_CR = PR_TRUE;
00309         }
00310         
00311         out = buffer;
00312       } else {
00313         
00314       /*  Fix for bug #95985. We can't assume that all lines are shorter
00315       than 4096 chars (MIME_BUFFER_SIZE), so we need to test
00316       for this here. sfraser.
00317         */
00318         if (out - buffer >= MIME_BUFFER_SIZE)
00319         {
00320           status = mime_write_message_body(m_state, buffer, out - buffer);
00321           if (status < 0) return status;
00322           
00323           out = buffer;
00324         }
00325         
00326         *out++ = *in;
00327       }
00328     }
00329     
00330     /* Flush the last line. */
00331     if (out > buffer) {
00332       status = mime_write_message_body(m_state, buffer, out - buffer);
00333       if (status < 0) return status;
00334       out = buffer;
00335     }
00336   }
00337   
00338   if (encoded_data && encoded_data != buffer) {
00339     PR_Free(encoded_data);
00340   }
00341   
00342   return status;
00343 }
00344 
00345 
00346 /* Partition the headers into those which apply to the message as a whole;
00347 those which apply to the message's contents; and the Content-Type header
00348 itself.  (This relies on the fact that all body-related headers begin with
00349 "Content-".)
00350 
00351   (How many header parsers are in this program now?)
00352   */
00353 static int 
00354 divide_content_headers(const char *headers,
00355                         char **message_headers,
00356                         char **content_headers,
00357                         char **content_type_header)
00358 {
00359     const char *tail;
00360     char *message_tail, *content_tail, *type_tail;
00361     int L = 0;
00362     if (headers)
00363       L = PL_strlen(headers);
00364     
00365     if (L == 0)
00366       return 0;
00367     
00368     *message_headers = (char *)PR_Malloc(L+1);
00369     if (!*message_headers)
00370       return NS_ERROR_OUT_OF_MEMORY;
00371     
00372     *content_headers = (char *)PR_Malloc(L+1);
00373     if (!*content_headers) {
00374       PR_Free(*message_headers);
00375       return NS_ERROR_OUT_OF_MEMORY;
00376     }
00377     
00378     *content_type_header = (char *)PR_Malloc(L+1);
00379     if (!*content_type_header) {
00380       PR_Free(*message_headers);
00381       PR_Free(*content_headers);
00382       return NS_ERROR_OUT_OF_MEMORY;
00383     }
00384     
00385     message_tail = *message_headers;
00386     content_tail = *content_headers;
00387     type_tail    = *content_type_header;
00388     tail = headers;
00389     
00390     while (*tail)
00391     {
00392       const char *head = tail;
00393       char **out;
00394       while(PR_TRUE) {
00395       /* Loop until we reach a newline that is not followed by whitespace.
00396         */
00397         if (tail[0] == 0 ||
00398           ((tail[0] == nsCRT::CR || tail[0] == nsCRT::LF) &&
00399           !(tail[1] == ' ' || tail[1] == '\t' || tail[1] == nsCRT::LF)))
00400         {
00401           /* Swallow the whole newline. */
00402           if (tail[0] == nsCRT::CR && tail[1] == nsCRT::LF)
00403             tail++;
00404           if (*tail)
00405             tail++;
00406           break;
00407         }
00408         tail++;
00409       }
00410       
00411       /* Decide which block this header goes into.
00412       */
00413       if (!PL_strncasecmp(head, "Content-Type:", 13))
00414         out = &type_tail;
00415       else
00416         if (!PL_strncasecmp(head, "Content-", 8))
00417           out = &content_tail;
00418         else
00419           out = &message_tail;
00420         
00421         memcpy(*out, head, (tail-head));
00422         *out += (tail-head);
00423     }
00424     
00425     *message_tail = 0;
00426     *content_tail = 0;
00427     *type_tail = 0;
00428     
00429     if (!**message_headers) {
00430       PR_Free(*message_headers);
00431       *message_headers = 0;
00432     }
00433     
00434     if (!**content_headers) {
00435       PR_Free(*content_headers);
00436       *content_headers = 0;
00437     }
00438     
00439     if (!**content_type_header) {
00440       PR_Free(*content_type_header);
00441       *content_type_header = 0;
00442     }
00443     
00444 #ifdef DEBUG
00445     // ### mwelch Because of the extreme difficulty we've had with
00446     //      duplicate part headers, I'm going to put in an
00447     //      ASSERT here which makes sure that no duplicate
00448     //      Content-Type or Content-Transfer-Encoding headers
00449     //      leave here undetected.
00450     const char* tmp;
00451     if (*content_type_header) {
00452       tmp = PL_strstr(*content_type_header, "Content-Type");
00453       if (tmp) {
00454         tmp++; // get past the first occurrence
00455         NS_ASSERTION(!PL_strstr(tmp, "Content-Type"), "Content-part already present");
00456       }
00457     }
00458     
00459     if (*content_headers) {
00460       tmp = PL_strstr(*content_headers, "Content-Transfer-Encoding");
00461       if (tmp) {
00462         tmp++; // get past the first occurrence
00463         NS_ASSERTION(!PL_strstr(tmp, "Content-Transfer-Encoding"), "Content-Transfert already present");
00464       }
00465     }
00466 #endif // DEBUG
00467     
00468     return 0;
00469 }
00470 
00471 #define     SKIP_EMPTY_PART   1966
00472 
00473 int 
00474 nsMsgSendPart::Write()
00475 {
00476   int     status = 0;
00477   char    *separator = nsnull;
00478   PRBool  needToWriteCRLFAfterEncodedBody  = PR_FALSE;
00479 
00480 #define PUSHLEN(str, length)                  \
00481   do {                            \
00482     status = mime_write_message_body(m_state, str, length); \
00483     if (status < 0) goto FAIL;                \
00484   } while (0)                         \
00485 
00486 #define PUSH(str) PUSHLEN(str, PL_strlen(str))
00487 
00488   // rhp: Suppress the output of parts that are empty!
00489   if ( (m_parent) &&
00490        (m_numchildren == 0) &&
00491        ( (!m_buffer) || (!*m_buffer) ) &&
00492        (!m_filespec) &&
00493        (!m_mainpart) )
00494     return SKIP_EMPTY_PART;
00495 
00496   if (m_mainpart && m_type && PL_strcmp(m_type, TEXT_HTML) == 0) 
00497   {     
00498     if (m_filespec) 
00499     {
00500       // The "insert HTML links" code requires a memory buffer,
00501       // so read the file into memory.
00502       NS_ASSERTION(m_buffer == nsnull, "not-null buffer");
00503       PRInt32           length = 0;
00504       
00505       if (m_filespec->Valid())
00506         length = m_filespec->GetFileSize();
00507       
00508       m_buffer = (char *) PR_Malloc(sizeof(char) * (length + 1));
00509       if (m_buffer) 
00510       {
00511         nsInputFileStream file(*m_filespec);
00512         if (file.is_open()) 
00513         {
00514           length = file.read(m_buffer, length);
00515           file.close();
00516           m_buffer[length] = '\0';
00517         }
00518         else 
00519           PR_Free(m_buffer);
00520       }
00521     }
00522   }
00523   
00524   if (m_parent && m_parent->m_type &&
00525         !PL_strcasecmp(m_parent->m_type, MULTIPART_DIGEST) &&
00526         m_type &&
00527         (!PL_strcasecmp(m_type, MESSAGE_RFC822) ||
00528         !PL_strcasecmp(m_type, MESSAGE_NEWS))) 
00529   {
00530     // If we're in a multipart/digest, and this document is of type
00531     // message/rfc822, then it's appropriate to emit no headers.
00532     //
00533   }
00534   else 
00535   {
00536     char *message_headers = 0;
00537     char *content_headers = 0;
00538     char *content_type_header = 0;
00539     status = divide_content_headers(m_other,
00540                                     &message_headers,
00541                                     &content_headers,
00542                                     &content_type_header);
00543     if (status < 0)
00544       goto FAIL;
00545     
00546       /* First, write out all of the headers that refer to the message
00547       itself (From, Subject, MIME-Version, etc.)
00548     */
00549     if (message_headers) 
00550     {
00551       PUSH(message_headers);
00552       PR_Free(message_headers);
00553       message_headers = 0;
00554     }
00555 
00556     /* Now allow the crypto library to (potentially) insert some text
00557        (it may want to wrap the body in an envelope.)           */
00558     if (!m_parent) {
00559       status = m_state->BeginCryptoEncapsulation();
00560       if (status < 0) goto FAIL;
00561     }
00562           
00563     /* Now make sure there's a Content-Type header.
00564     */
00565     if (!content_type_header) 
00566     {
00567       NS_ASSERTION(m_type && *m_type, "null ptr");
00568       PRBool needsCharset = mime_type_needs_charset(m_type ? m_type : TEXT_PLAIN);
00569       if (needsCharset) 
00570       {
00571         content_type_header = PR_smprintf("Content-Type: %s; charset=%s" CRLF,
00572                                           (m_type ? m_type : TEXT_PLAIN), m_charset_name);
00573       }
00574       else
00575         content_type_header = PR_smprintf("Content-Type: %s" CRLF,
00576                                           (m_type ? m_type : TEXT_PLAIN));
00577       if (!content_type_header) 
00578       {
00579         if (content_headers)
00580           PR_Free(content_headers);
00581         status = NS_ERROR_OUT_OF_MEMORY;
00582         goto FAIL;
00583       }
00584     }
00585     
00586     /* If this is a compound object, tack a boundary string onto the
00587     Content-Type header. this
00588     */
00589     if (m_numchildren > 0)
00590     {
00591       int L;
00592       char *ct2;
00593       NS_ASSERTION(m_type, "null ptr");
00594 
00595       if (!separator)
00596       {
00597         separator = mime_make_separator("");
00598         if (!separator)
00599         {
00600           status = NS_ERROR_OUT_OF_MEMORY;
00601           goto FAIL;
00602         }
00603       }
00604 
00605       L = PL_strlen(content_type_header);
00606       
00607       if (content_type_header[L-1] == nsCRT::LF)
00608         content_type_header[--L] = 0;
00609       if (content_type_header[L-1] == nsCRT::CR)
00610         content_type_header[--L] = 0;
00611       
00612       ct2 = PR_smprintf("%s;\r\n boundary=\"%s\"" CRLF, content_type_header, separator);
00613       PR_Free(content_type_header);
00614       if (!ct2) 
00615       {
00616         if (content_headers)
00617           PR_Free(content_headers);
00618         status = NS_ERROR_OUT_OF_MEMORY;
00619         goto FAIL;
00620       }
00621       
00622       content_type_header = ct2;
00623     }
00624     
00625     // Now write out the Content-Type header...
00626     NS_ASSERTION(content_type_header && *content_type_header, "null ptr");
00627     PUSH(content_type_header);
00628     PR_Free(content_type_header);
00629     content_type_header = 0;
00630     
00631     /* ...followed by all of the other headers that refer to the body of
00632     the message (Content-Transfer-Encoding, Content-Dispositon, etc.)
00633     */
00634     if (content_headers) 
00635     {
00636       PUSH(content_headers);
00637       PR_Free(content_headers);
00638       content_headers = 0;
00639     }
00640   }
00641 
00642   PUSH(CRLF);         // A blank line, to mark the end of headers.
00643 
00644   m_firstBlock = PR_TRUE;
00645   /* only convert if we need to tag charset */
00646   m_needIntlConversion = mime_type_needs_charset(m_type);
00647   
00648   if (m_buffer) 
00649   {
00650     status = PushBody(m_buffer, PL_strlen(m_buffer));
00651     if (status < 0)
00652       goto FAIL;
00653   }
00654   else if (m_filespec) 
00655   {
00656     nsInputFileStream   myStream(*m_filespec);
00657 
00658     if (!myStream.is_open())
00659     {
00660       // mysteriously disappearing?
00661       nsCOMPtr<nsIMsgSendReport> sendReport;
00662       m_state->GetSendReport(getter_AddRefs(sendReport));
00663       if (sendReport)
00664       {
00665         nsAutoString error_msg;
00666         nsAutoString path;
00667         NS_CopyNativeToUnicode(
00668           nsDependentCString(m_filespec->GetNativePathCString()), path);
00669         nsMsgBuildErrorMessageByID(NS_MSG_UNABLE_TO_OPEN_TMP_FILE, error_msg, &path, nsnull);
00670         sendReport->SetMessage(nsIMsgSendReport::process_Current, error_msg.get(), PR_FALSE);
00671       }
00672       status = NS_MSG_UNABLE_TO_OPEN_TMP_FILE;
00673       goto FAIL;
00674     }
00675     /* Kludge to avoid having to allocate memory on the toy computers... */
00676     if (!mime_mailto_stream_read_buffer) 
00677     {
00678       mime_mailto_stream_read_buffer = (char *) PR_Malloc(MIME_BUFFER_SIZE);
00679       if (!mime_mailto_stream_read_buffer) 
00680       {
00681         status = NS_ERROR_OUT_OF_MEMORY;
00682         goto FAIL;
00683       }
00684     }
00685 
00686     char    *buffer = mime_mailto_stream_read_buffer;
00687     if (m_strip_sensitive_headers) 
00688     {
00689       // We are attaching a message, so we should be careful to
00690       // strip out certain sensitive internal header fields.
00691       PRBool skipping = PR_FALSE;
00692 
00693       while (1) 
00694       {
00695         char *line;
00696 
00697         if (myStream.eof())
00698           line = nsnull;
00699         else
00700         {
00701           buffer[0] = '\0';
00702           myStream.readline(buffer, MIME_BUFFER_SIZE-3);
00703           line = buffer;
00704         }
00705       
00706         if (!line)
00707           break;  /* EOF */
00708         
00709         if (skipping) {
00710           if (*line == ' ' || *line == '\t')
00711             continue;
00712           else
00713             skipping = PR_FALSE;
00714         }
00715         
00716         int hdrLen = PL_strlen(buffer);
00717         if ((hdrLen < 2) || (buffer[hdrLen-2] != nsCRT::CR)) { // if the line doesn't end with CRLF,
00718           // ... make it end with CRLF.
00719           if ( (hdrLen == 0) || ((buffer[hdrLen-1] != nsCRT::CR) && (buffer[hdrLen-1] != nsCRT::LF)) )
00720             hdrLen++;
00721           buffer[hdrLen-1] = '\015';
00722           buffer[hdrLen] = '\012';
00723           buffer[hdrLen+1] = '\0';
00724         }
00725         
00726         if (!PL_strncasecmp(line, "From -", 6) ||
00727             !PL_strncasecmp(line, "BCC:", 4) ||
00728             !PL_strncasecmp(line, "FCC:", 4) ||
00729             !PL_strncasecmp(line, CONTENT_LENGTH ":", CONTENT_LENGTH_LEN+1) ||
00730             !PL_strncasecmp(line, "Lines:", 6) ||
00731             !PL_strncasecmp(line, "Status:", 7) ||
00732             !PL_strncasecmp(line, X_MOZILLA_STATUS ":", X_MOZILLA_STATUS_LEN+1) ||
00733             !PL_strncasecmp(line, X_MOZILLA_STATUS2 ":", X_MOZILLA_STATUS2_LEN+1) ||
00734             !PL_strncasecmp(line, X_MOZILLA_DRAFT_INFO ":", X_MOZILLA_DRAFT_INFO_LEN+1) ||
00735             !PL_strncasecmp(line, X_MOZILLA_NEWSHOST ":", X_MOZILLA_NEWSHOST_LEN+1) ||
00736             !PL_strncasecmp(line, X_UIDL ":", X_UIDL_LEN+1) ||
00737             !PL_strncasecmp(line, "X-VM-", 5)) /* hi Kyle */
00738         {
00739           skipping = PR_TRUE;
00740           continue;
00741         }
00742         
00743         PUSH(line);
00744         
00745         if (*line == nsCRT::CR || *line == nsCRT::LF) {
00746           break;  // Now can do normal reads for the body.
00747         }
00748       }
00749     }
00750         
00751     while (!myStream.eof()) 
00752     {
00753       if ((status = myStream.read(buffer, MIME_BUFFER_SIZE)) < 0)
00754       {  
00755         nsCOMPtr<nsIMsgSendReport> sendReport;
00756         m_state->GetSendReport(getter_AddRefs(sendReport));
00757         if (sendReport)
00758         {
00759           nsAutoString error_msg;
00760           nsAutoString path;
00761           NS_CopyNativeToUnicode(nsDependentCString(m_filespec->GetNativePathCString()), path);
00762           nsMsgBuildErrorMessageByID(NS_MSG_UNABLE_TO_OPEN_FILE, error_msg, &path, nsnull);
00763           sendReport->SetMessage(nsIMsgSendReport::process_Current, error_msg.get(), PR_FALSE);
00764           status = NS_MSG_UNABLE_TO_OPEN_FILE;
00765           goto FAIL;
00766         }
00767       }
00768       status = PushBody(buffer, status);
00769       if (status < 0)
00770         goto FAIL;
00771     }
00772   }
00773   
00774   if (m_encoder_data) 
00775   {
00776     status = MIME_EncoderDestroy(m_encoder_data, PR_FALSE);
00777     m_encoder_data = nsnull;
00778     needToWriteCRLFAfterEncodedBody = !m_parent;
00779     if (status < 0)
00780       goto FAIL;
00781   }
00782   
00783   // 
00784   // Ok, from here we loop and drive the the output of all children 
00785   // for this message.
00786   //
00787   if (m_numchildren > 0) 
00788   {
00789     PRBool  writeSeparator = PR_TRUE;
00790 
00791     for (int i = 0 ; i < m_numchildren ; i ++) 
00792     {
00793       if (writeSeparator)
00794       {
00795         PUSH(CRLF);
00796         PUSH("--");
00797 
00798         PUSH(separator);
00799         PUSH(CRLF);
00800       }
00801 
00802       status = m_children[i]->Write();
00803       if (status < 0)
00804         goto FAIL;
00805 
00806       if (status == SKIP_EMPTY_PART)
00807         writeSeparator = PR_FALSE;
00808       else
00809         writeSeparator = PR_TRUE;
00810     }
00811 
00812     PUSH(CRLF);
00813     PUSH("--");
00814     PUSH(separator);
00815     PUSH("--");
00816     PUSH(CRLF);
00817   }
00818   else if (needToWriteCRLFAfterEncodedBody)
00819     PUSH(CRLF);
00820   
00821 FAIL:
00822   PR_FREEIF(separator);
00823   return status;
00824 }
00825