Back to index

lightning-sunbird  0.9+nobinonly
nsMsgSend.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  *   Jean-Francois Ducarroz <ducarroz@netscape.com>
00024  *   Pierre Phaneuf <pp@ludusdesign.com>
00025  *
00026  * Alternatively, the contents of this file may be used under the terms of
00027  * either of the GNU General Public License Version 2 or later (the "GPL"),
00028  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00029  * in which case the provisions of the GPL or the LGPL are applicable instead
00030  * of those above. If you wish to allow use of your version of this file only
00031  * under the terms of either the GPL or the LGPL, and not to allow others to
00032  * use your version of this file under the terms of the MPL, indicate your
00033  * decision by deleting the provisions above and replace them with the notice
00034  * and other provisions required by the GPL or the LGPL. If you do not delete
00035  * the provisions above, a recipient may use your version of this file under
00036  * the terms of any one of the MPL, the GPL or the LGPL.
00037  *
00038  * ***** END LICENSE BLOCK ***** */
00039 #include "nsMsgSend.h"
00040 
00041 #include "nsCRT.h"
00042 #include "nsMsgLocalFolderHdrs.h"
00043 #include "nsMsgSendPart.h"
00044 #include "nsMsgBaseCID.h"
00045 #include "nsMsgNewsCID.h"
00046 #include "nsIMsgHeaderParser.h"
00047 #include "nsISmtpService.h"  // for actually sending the message...
00048 #include "nsINntpService.h"  // for actually posting the message...
00049 #include "nsIMsgMailSession.h"
00050 #include "nsIMsgIdentity.h"
00051 #include "nsEscape.h"
00052 #include "nsIPrefService.h"
00053 #include "nsIPrefBranch.h"
00054 #include "nsIMsgMailNewsUrl.h"
00055 #include "nsMsgDeliveryListener.h"
00056 #include "nsMsgComposeStringBundle.h"
00057 #include "nsMsgEncoders.h"
00058 #include "nsMsgCompUtils.h"
00059 #include "nsMsgI18N.h"
00060 #include "nsICharsetConverterManager.h"
00061 #include "nsIMsgSendListener.h"
00062 #include "nsIMsgCopyServiceListener.h"
00063 #include "nsIFileSpec.h"
00064 #include "nsIURL.h"
00065 #include "nsIFileURL.h"
00066 #include "nsMsgCopy.h"
00067 #include "nsXPIDLString.h"
00068 #include "nsReadableUtils.h"
00069 #include "nsUnicharUtils.h"
00070 #include "nsMsgPrompts.h"
00071 #include "nsIDOMHTMLBodyElement.h"
00072 #include "nsIDOMHTMLImageElement.h"
00073 #include "nsIDOMHTMLLinkElement.h"
00074 #include "nsIDOMHTMLAnchorElement.h"
00075 #include "nsCExternalHandlerService.h"
00076 #include "nsIMIMEService.h"
00077 #include "nsIDocument.h"
00078 #include "nsIDOMDocument.h"
00079 #include "nsMsgCompCID.h"
00080 #include "nsIFileSpec.h"
00081 #include "nsIAbAddressCollecter.h"
00082 #include "nsAbBaseCID.h"
00083 #include "nsCOMPtr.h"
00084 #include "mozITXTToHTMLConv.h"
00085 #include "nsIMsgStatusFeedback.h"
00086 #include "nsIMsgMailSession.h"
00087 #include "nsTextFormatter.h"
00088 #include "nsIPrompt.h"
00089 #include "nsMailHeaders.h"
00090 #include "nsIDocShell.h"
00091 #include "nsMimeTypes.h"
00092 #include "nsISmtpUrl.h"
00093 #include "nsIInterfaceRequestor.h"
00094 #include "nsIInterfaceRequestorUtils.h"
00095 #include "nsIEditorMailSupport.h"
00096 #include "nsIDocumentEncoder.h"    // for editor output flags
00097 #include "nsILoadGroup.h"
00098 #include "nsMsgSendReport.h"
00099 #include "nsMsgSimulateError.h"
00100 #include "nsNetCID.h"
00101 #include "nsNetError.h"
00102 #include "nsMsgUtils.h"
00103 #include "nsIMsgMdnGenerator.h"
00104 #include "nsISmtpServer.h"
00105 #include "nsIRDFService.h"
00106 #include "nsRDFCID.h"
00107 #include "nsIMsgAccountManager.h"
00108 #include "nsNativeCharsetUtils.h"
00109 #include "nsIAbCard.h"
00110 #include "nsIMsgProgress.h"
00111 #include "nsIMsgMessageService.h"
00112 #include "nsIMsgHdr.h"
00113 #include "nsIMsgFolder.h"
00114 
00115 static NS_DEFINE_CID(kRDFServiceCID, NS_RDFSERVICE_CID);
00116 
00117 #define PREF_MAIL_SEND_STRUCT "mail.send_struct"
00118 #define PREF_MAIL_STRICTLY_MIME "mail.strictly_mime"
00119 #define PREF_MAIL_MESSAGE_WARNING_SIZE "mailnews.message_warning_size"
00120 #define PREF_MAIL_COLLECT_EMAIL_ADDRESS_OUTGOING "mail.collect_email_address_outgoing"
00121 #define PREF_MAIL_DONT_ATTACH_SOURCE "mail.compose.dont_attach_source_of_local_network_links"
00122 
00123 #define ATTR_MOZ_DO_NOT_SEND "moz-do-not-send"
00124 
00125 enum  { kDefaultMode = (PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE) };
00126 
00127 #ifdef XP_MAC
00128 
00129 static char* NET_GetLocalFileFromURL(char *url)
00130 {
00131   char * finalPath;
00132   NS_ASSERTION(PL_strncasecmp(url, "file://", 7) == 0, "invalid url");
00133   finalPath = (char*)PR_Malloc(strlen(url));
00134   if (finalPath == nsnull)
00135     return nsnull;
00136   strcpy(finalPath, url+6+1);
00137   return finalPath;
00138 }
00139 
00140 static char* NET_GetURLFromLocalFile(char *filename)
00141 {
00142     /*  file:///<path>0 */
00143   char * finalPath = (char*)PR_Malloc(strlen(filename) + 8 + 1);
00144   if (finalPath == nsnull)
00145     return nsnull;
00146   finalPath[0] = 0;
00147   strcat(finalPath, "file://");
00148   strcat(finalPath, filename);
00149   return finalPath;
00150 }
00151 
00152 #endif /* XP_MAC */
00153 
00154 static PRBool mime_use_quoted_printable_p = PR_FALSE;
00155 
00156 //
00157 // Ugh, we need to do this currently to access this boolean.
00158 //
00159 PRBool
00160 UseQuotedPrintable(void)
00161 {
00162   return mime_use_quoted_printable_p;
00163 }
00164 
00165 /* This function will parse a list of email addresses and groups and just
00166  * return a list of email addresses (recipient)
00167  *
00168  * The input could be:
00169  *    [recipient | group] *[,recipient | group]
00170  *
00171  * The group syntax is:
00172  *    group-name:[recipient *[,recipient]];
00173  *
00174  * the output will be:
00175  *    recipient *[, recipient]
00176  *
00177  * As the result will always be equal or smaller than the input string,
00178  * the extraction will be made in place. Don't need to create a new buffer.
00179  */
00180 static nsresult StripOutGroupNames(char * addresses)
00181 {
00182   char aChar;
00183   char * readPtr = addresses;           // current read position
00184   char * writePtr = addresses;          // current write position
00185   char * previousSeparator = addresses; // remember last time we wrote a recipient separator
00186   char * endPtr = addresses + PL_strlen(addresses);
00187 
00188   PRBool quoted = PR_FALSE;   // indicate if we are between double quote
00189   PRBool group = PR_FALSE;   // indicate if we found a group prefix
00190   PRBool atFound = PR_FALSE;  // indicate if we found an @ in the current recipient. group name should not have an @
00191 
00192   while (readPtr < endPtr)
00193   {
00194     aChar = *readPtr;
00195     readPtr ++;
00196     switch(aChar)
00197     {
00198       case '\\':
00199         if (*readPtr == '"') //ignore escaped quote
00200           readPtr ++;
00201         continue;
00202 
00203       case '"':
00204         quoted = !quoted;
00205         break;
00206 
00207       case '@':
00208         if (!quoted)
00209           atFound = PR_TRUE;
00210         break;
00211 
00212       case ':':
00213         if (!quoted && !atFound)
00214         {
00215           // ok, we found a group name
00216           // let's backup the write cursor to remove the group name
00217           writePtr = previousSeparator + 1;
00218           group = PR_TRUE;
00219           continue;
00220         }
00221         break;
00222 
00223       case ';':
00224         if (quoted || !group)
00225           break;
00226         else
00227           group = PR_FALSE;
00228           //end of the group, act like a recipient separator now...
00229         /* NO BREAK */
00230 
00231       case ',':
00232         if (!quoted)
00233         {
00234           atFound = PR_FALSE;
00235           //let check if we already have a comma separator in the output string
00236           if (writePtr > addresses && *(writePtr - 1) == ',')
00237             writePtr --;
00238           *writePtr = ',';
00239           previousSeparator = writePtr;
00240           writePtr ++;
00241           continue;
00242         }
00243         break;
00244     }
00245     *writePtr = aChar;
00246     writePtr ++;
00247   }
00248 
00249   if (writePtr > addresses && *(writePtr - 1) == ',')
00250     writePtr --;
00251   *writePtr = '\0';
00252 
00253   return NS_OK;
00254 }
00255 
00256 /* the following macro actually implement addref, release and query interface for our component. */
00257 NS_IMPL_THREADSAFE_ISUPPORTS1(nsMsgComposeAndSend, nsIMsgSend)
00258 
00259 nsMsgComposeAndSend::nsMsgComposeAndSend() : 
00260     m_messageKey(0xffffffff)
00261 {
00262 #if defined(DEBUG_ducarroz)
00263   printf("CREATE nsMsgComposeAndSend: %x\n", this);
00264 #endif
00265   mGUINotificationEnabled = PR_TRUE;
00266   mAbortInProcess = PR_FALSE;
00267   mLastErrorReported = NS_OK;
00268   mEditor = nsnull;
00269   mMultipartRelatedAttachmentCount = -1;
00270   mCompFields = nsnull;     /* Where to send the message once it's done */
00271   mSendMailAlso = PR_FALSE;
00272   mOutputFile = nsnull;
00273 
00274   m_dont_deliver_p = PR_FALSE;
00275   m_deliver_mode = nsMsgDeliverNow;
00276 
00277   m_attachments_only_p = PR_FALSE;
00278   m_pre_snarfed_attachments_p = PR_FALSE;
00279   m_digest_p = PR_FALSE;
00280   m_be_synchronous_p = PR_FALSE;
00281   m_crypto_closure = nsnull;
00282   m_attachment1_type = 0;
00283   m_attachment1_encoding = 0;
00284   m_attachment1_encoder_data = nsnull;
00285   m_attachment1_body = 0;
00286   m_attachment1_body_length = 0;
00287   m_attachment_count = 0;
00288   m_attachment_pending_count = 0;
00289   m_attachments = nsnull;
00290   m_status = 0;
00291   m_attachments_done_callback = nsnull;
00292   m_plaintext = nsnull;
00293   m_related_part = nsnull;
00294   m_related_body_part = nsnull;
00295   mOriginalHTMLBody = nsnull;
00296 
00297   // These are for temp file creation and return
00298   mReturnFileSpec = nsnull;
00299   mTempFileSpec = nsnull;
00300   mHTMLFileSpec = nsnull;
00301   mCopyFileSpec = nsnull;
00302   mCopyFileSpec2 = nsnull;
00303   mCopyObj = nsnull;
00304   mNeedToPerformSecondFCC = PR_FALSE;
00305 
00306   mPreloadedAttachmentCount = 0;
00307   mRemoteAttachmentCount = 0;
00308   mCompFieldLocalAttachments = 0;
00309   mCompFieldRemoteAttachments = 0;
00310   mMessageWarningSize = 0;
00311   
00312   NS_NEWXPCOM(mSendReport, nsMsgSendReport);
00313 }
00314 
00315 nsMsgComposeAndSend::~nsMsgComposeAndSend()
00316 {
00317 #if defined(DEBUG_ducarroz)
00318   printf("DISPOSE nsMsgComposeAndSend: %x\n", this);
00319 #endif
00320   mSendReport = nsnull;
00321   Clear();
00322 }
00323 
00324 NS_IMETHODIMP nsMsgComposeAndSend::GetDefaultPrompt(nsIPrompt ** aPrompt)
00325 {
00326   NS_ENSURE_ARG(aPrompt);
00327   *aPrompt = nsnull;
00328   
00329   nsresult rv = NS_OK;
00330 
00331   if (mSendProgress)
00332   {
00333     rv = mSendProgress->GetPrompter(aPrompt);
00334     if (NS_SUCCEEDED(rv) && *aPrompt)
00335       return NS_OK;
00336   }
00337   
00338   if (mParentWindow)
00339   {
00340     rv = mParentWindow->GetPrompter(aPrompt);
00341     if (NS_SUCCEEDED(rv) && *aPrompt)
00342       return NS_OK;
00343   }
00344   
00345   /* If we cannot find a prompter, try the mail3Pane window */
00346   nsCOMPtr<nsIMsgWindow> msgWindow;
00347   nsCOMPtr <nsIMsgMailSession> mailSession (do_GetService(NS_MSGMAILSESSION_CONTRACTID));
00348   if (mailSession)
00349   {
00350     mailSession->GetTopmostMsgWindow(getter_AddRefs(msgWindow));
00351     if (msgWindow)
00352       rv = msgWindow->GetPromptDialog(aPrompt);
00353   }
00354   
00355   return rv;
00356 }
00357 
00358 nsresult nsMsgComposeAndSend::GetNotificationCallbacks(nsIInterfaceRequestor** aCallbacks)
00359 {
00360 // TODO: stop using mail3pane window!
00361   nsCOMPtr<nsIMsgWindow> msgWindow;
00362   nsCOMPtr<nsIMsgMailSession> mailSession(do_GetService(NS_MSGMAILSESSION_CONTRACTID));
00363   mailSession->GetTopmostMsgWindow(getter_AddRefs(msgWindow));
00364   if (msgWindow) {
00365     nsCOMPtr<nsIDocShell> docShell;
00366     msgWindow->GetRootDocShell(getter_AddRefs(docShell));
00367     nsCOMPtr<nsIInterfaceRequestor> ir(do_QueryInterface(docShell));
00368     if (ir) {
00369       *aCallbacks = ir;
00370       NS_ADDREF(*aCallbacks);
00371       return NS_OK;
00372     }
00373   }
00374   return NS_ERROR_FAILURE;  
00375 }
00376 
00377 void 
00378 nsMsgComposeAndSend::Clear()
00379 {
00380 #ifdef NS_DEBUG
00381   printf("\nTHE CLEANUP ROUTINE FOR nsMsgComposeAndSend() WAS CALLED\n");
00382 #endif
00383   PR_FREEIF (m_attachment1_type);
00384   PR_FREEIF (m_attachment1_encoding);
00385   PR_FREEIF (m_attachment1_body);
00386   PR_FREEIF (mOriginalHTMLBody);
00387 
00388   if (m_attachment1_encoder_data) 
00389   {
00390     MIME_EncoderDestroy(m_attachment1_encoder_data, PR_TRUE);
00391     m_attachment1_encoder_data = 0;
00392   }
00393 
00394   if (m_plaintext) 
00395   {
00396     if (m_plaintext->mOutFile)
00397       m_plaintext->mOutFile->Close();
00398 
00399     if (m_plaintext->mFileSpec)
00400     {
00401       m_plaintext->mFileSpec->Delete(PR_FALSE);
00402       delete m_plaintext->mFileSpec;
00403       m_plaintext->mFileSpec = nsnull;
00404     }
00405     delete m_plaintext;
00406     m_plaintext = nsnull;
00407   }
00408 
00409   if (mHTMLFileSpec) 
00410   {
00411     mHTMLFileSpec->Delete(PR_FALSE);
00412     delete mHTMLFileSpec;
00413     mHTMLFileSpec= nsnull;
00414   }
00415 
00416   if (mOutputFile) 
00417   {
00418     delete mOutputFile;
00419     mOutputFile = 0;
00420   }
00421 
00422   if (mCopyFileSpec)
00423   {
00424     nsFileSpec aFileSpec;
00425     mCopyFileSpec->GetFileSpec(&aFileSpec);
00426     if (aFileSpec.Valid())
00427       aFileSpec.Delete(PR_FALSE);
00428 
00429     // jt -- *don't* use delete someone may still holding the nsIFileSpec
00430     // pointer
00431     NS_IF_RELEASE(mCopyFileSpec);
00432   }
00433 
00434   if (mCopyFileSpec2)
00435   {
00436     nsFileSpec aFileSpec;
00437     mCopyFileSpec2->GetFileSpec(&aFileSpec);
00438     if (aFileSpec.Valid())
00439       aFileSpec.Delete(PR_FALSE);
00440 
00441     // jt -- *don't* use delete someone may still holding the nsIFileSpec
00442     // pointer
00443     NS_IF_RELEASE(mCopyFileSpec2);
00444   }
00445 
00446   if (mTempFileSpec) 
00447   {
00448     if (mReturnFileSpec == nsnull)
00449     {
00450       mTempFileSpec->Delete(PR_FALSE);
00451       delete mTempFileSpec;
00452       mTempFileSpec = nsnull;
00453     }
00454   }
00455 
00456   if (m_attachments)
00457   {
00458     PRUint32 i;
00459     for (i = 0; i < m_attachment_count; i++) 
00460     {
00461       if (m_attachments [i].m_encoder_data) 
00462       {
00463         MIME_EncoderDestroy(m_attachments[i].m_encoder_data, PR_TRUE);
00464         m_attachments [i].m_encoder_data = 0;
00465       }
00466 
00467       m_attachments[i].mURL = nsnull;
00468 
00469       // is this needed? the destructor for the attachments
00470       // should be freeing these strings.
00471       PR_FREEIF (m_attachments [i].m_type);
00472       PR_FREEIF (m_attachments [i].m_charset);
00473       PR_FREEIF (m_attachments [i].m_override_type);
00474       PR_FREEIF (m_attachments [i].m_override_encoding);
00475       PR_FREEIF (m_attachments [i].m_desired_type);
00476       PR_FREEIF (m_attachments [i].m_description);
00477       PR_FREEIF (m_attachments [i].m_x_mac_type);
00478       PR_FREEIF (m_attachments [i].m_x_mac_creator);
00479       PR_FREEIF (m_attachments [i].m_real_name);
00480       PR_FREEIF (m_attachments [i].m_encoding);
00481       PR_FREEIF (m_attachments [i].m_content_id);
00482       if (m_attachments[i].mOutFile)
00483           m_attachments[i].mOutFile->Close();
00484       if (m_attachments[i].mFileSpec) 
00485       {
00486         // Only Delete the file if this variable is set!
00487         if (m_attachments[i].mDeleteFile)
00488           m_attachments[i].mFileSpec->Delete(PR_FALSE);
00489         delete m_attachments[i].mFileSpec;
00490         m_attachments[i].mFileSpec = nsnull;
00491       }
00492 
00493 #if defined(XP_MAC) || defined(XP_MACOSX)
00494       //
00495       // remove the appledoubled intermediate file after we done all.
00496       //
00497       if (m_attachments[i].mAppleFileSpec) 
00498       {
00499         m_attachments[i].mAppleFileSpec->Delete(PR_FALSE);
00500         delete m_attachments[i].mAppleFileSpec;
00501         m_attachments[i].mAppleFileSpec = nsnull;
00502       }
00503 #endif /* XP_MAC */
00504     }
00505 
00506     delete[] m_attachments;
00507     m_attachment_count = m_attachment_pending_count = 0;
00508     m_attachments = 0;
00509   }
00510 
00511   // Cleanup listener
00512   mListener = nsnull;
00513 }
00514 
00515 static char *mime_mailto_stream_read_buffer = 0;
00516 static char *mime_mailto_stream_write_buffer = 0;
00517 
00518 
00519 char * mime_get_stream_write_buffer(void)
00520 {
00521   if (!mime_mailto_stream_write_buffer)
00522     mime_mailto_stream_write_buffer = (char *) PR_Malloc(MIME_BUFFER_SIZE);
00523   return mime_mailto_stream_write_buffer;
00524 }
00525 
00526 static PRBool isEmpty(const char* aString)
00527 {
00528   return (!aString) || (!*aString);
00529 }
00530 
00531 void nsMsgComposeAndSend::GenerateMessageId()
00532 {
00533   if (isEmpty(mCompFields->GetMessageId()))
00534   {
00535     if (isEmpty(mCompFields->GetTo()) &&
00536         isEmpty(mCompFields->GetCc()) &&
00537         isEmpty(mCompFields->GetBcc()) &&
00538         !isEmpty(mCompFields->GetNewsgroups()))
00539     {
00540       PRBool generateNewsMessageId = PR_FALSE;
00541       mUserIdentity->GetBoolAttribute("generate_news_message_id", &generateNewsMessageId);
00542       if (!generateNewsMessageId)
00543         return;
00544     }
00545 
00546     char* msgID = msg_generate_message_id(mUserIdentity);
00547     mCompFields->SetMessageId(msgID);
00548     PR_Free(msgID);
00549   }
00550 }
00551 
00552 // Don't I18N this line...this is per the spec!
00553 #define   MIME_MULTIPART_BLURB     "This is a multi-part message in MIME format."
00554 
00555 /* All of the desired attachments have been written to individual temp files,
00556    and we know what's in them.  Now we need to make a final temp file of the
00557    actual mail message, containing all of the other files after having been
00558    encoded as appropriate.
00559  */
00560 NS_IMETHODIMP 
00561 nsMsgComposeAndSend::GatherMimeAttachments()
00562 {
00563   PRBool shouldDeleteDeliveryState = PR_TRUE;
00564   PRInt32 status;
00565   PRUint32    i;
00566   char *headers = 0;
00567   PRFileDesc  *in_file = 0;
00568   PRBool multipart_p = PR_FALSE;
00569   PRBool plaintext_is_mainbody_p = PR_FALSE; // only using text converted from HTML?
00570   char *buffer = 0;
00571   char *buffer_tail = 0;
00572   nsXPIDLString msg; 
00573   PRBool tonews;
00574   PRBool body_is_us_ascii = PR_TRUE;
00575 
00576   nsMsgSendPart* toppart = nsnull;      // The very top most container of the message
00577                       // that we are going to send.
00578 
00579   nsMsgSendPart* mainbody = nsnull;     // The leaf node that contains the text of the
00580                       // message we're going to contain.
00581 
00582   nsMsgSendPart* maincontainer = nsnull;  // The direct child of toppart that will
00583                       // contain the mainbody.  If mainbody is
00584                       // the same as toppart, then this is
00585                       // also the same.  But if mainbody is
00586                       // to end up somewhere inside of a
00587                       // multipart/alternative or a
00588                       // multipart/related, then this is that
00589                       // multipart object.
00590 
00591   nsMsgSendPart* plainpart = nsnull;    // If we converted HTML into plaintext,
00592                       // the message or child containing the plaintext
00593                       // goes here. (Need to use this to determine
00594                       // what headers to append/set to the main 
00595                       // message body.)
00596 
00597   PRUint32 multipartRelatedCount = GetMultipartRelatedCount(); // The number of related part we will have to generate
00598 
00599   nsCOMPtr<nsIPrompt> promptObject; // only used if we have to show an alert here....
00600   GetDefaultPrompt(getter_AddRefs(promptObject));
00601 
00602   char *hdrs = 0;
00603   PRBool maincontainerISrelatedpart = PR_FALSE;
00604   const char * toppart_type = nsnull;
00605 
00606   // If we have any attachments, we generate multipart.
00607   multipart_p = (m_attachment_count > 0);
00608 
00609   // to news is true if we have a m_field and we have a Newsgroup and it is not empty
00610   tonews = PR_FALSE;
00611   if (mCompFields) 
00612   {
00613     const char* pstrzNewsgroup = mCompFields->GetNewsgroups();
00614     if (pstrzNewsgroup && *pstrzNewsgroup)
00615       tonews = PR_TRUE;
00616   }
00617 
00618   status = m_status;
00619   if (status < 0)
00620     goto FAIL;
00621 
00622   if (m_attachments_only_p)
00623   {
00624     /* If we get here, we should be fetching attachments only! */
00625     if (m_attachments_done_callback) 
00626     {
00627       struct nsMsgAttachedFile *attachments;
00628 
00629       NS_ASSERTION(m_attachment_count > 0, "not more attachment");
00630       if (m_attachment_count <= 0) 
00631       {
00632         m_attachments_done_callback (nsnull, nsnull, nsnull);
00633         m_attachments_done_callback = nsnull;
00634         goto FAIL;
00635       }
00636 
00637       attachments = (struct nsMsgAttachedFile *)PR_Malloc((m_attachment_count + 1) * sizeof(*attachments));
00638 
00639       if (!attachments)
00640         goto FAILMEM;
00641       memset(attachments, 0, ((m_attachment_count + 1) * sizeof(*attachments)));
00642       for (i = 0; i < m_attachment_count; i++)
00643       {
00644         nsMsgAttachmentHandler *ma = &m_attachments[i];
00645 
00646 #undef SNARF
00647 #define SNARF(x,y) do { if((y) && *(y) && !(x)) { ((x) = (y)); ((y) = 0); }} \
00648            while(0)
00649         // Rather than copying the strings and dealing with allocation
00650         // failures, we'll just "move" them into the other struct (this
00651         // should be ok since this file uses PR_FREEIF when discarding
00652         // the mime_attachment objects.) 
00653         //
00654         attachments[i].orig_url = ma->mURL;
00655         attachments[i].file_spec = ma->mFileSpec;
00656 
00657         SNARF(attachments[i].type, ma->m_type);
00658         SNARF(attachments[i].encoding, ma->m_encoding);
00659         SNARF(attachments[i].description, ma->m_description);
00660         SNARF(attachments[i].x_mac_type, ma->m_x_mac_type);
00661         SNARF(attachments[i].x_mac_creator, ma->m_x_mac_creator);
00662 
00663 #undef SNARF
00664         attachments[i].size = ma->m_size;
00665         attachments[i].unprintable_count = ma->m_unprintable_count;
00666         attachments[i].highbit_count = ma->m_highbit_count;
00667         attachments[i].ctl_count = ma->m_ctl_count;
00668         attachments[i].null_count = ma->m_null_count;
00669         attachments[i].max_line_length = ma->m_max_column;
00670 
00671         /* Doesn't really matter, but let's not lie about encoding
00672            in case it does someday. */
00673         if (attachments[i].highbit_count > 0 && attachments[i].encoding &&
00674             !PL_strcasecmp(attachments[i].encoding, ENCODING_7BIT))
00675           attachments[i].encoding = ENCODING_8BIT;
00676       }
00677 
00678       m_attachments_done_callback(nsnull, nsnull, attachments);
00679       PR_FREEIF(attachments);
00680       m_attachments_done_callback = nsnull;
00681     }
00682     goto FAIL;
00683   }
00684 
00685 
00686   /* If we get here, we're generating a message, so there shouldn't be an
00687      attachments callback. */
00688   NS_ASSERTION(!m_attachments_done_callback, "shouldn't have an attachement callback!");
00689 
00690   if (!m_attachment1_type) {
00691     m_attachment1_type = PL_strdup(TEXT_PLAIN);
00692     if (!m_attachment1_type)
00693       goto FAILMEM;
00694   }
00695 
00696   // If we have a text/html main part, and we need a plaintext attachment, then
00697   // we'll do so now.  This is an asynchronous thing, so we'll kick it off and
00698   // count on getting back here when it finishes.
00699 
00700   if (m_plaintext == nsnull &&
00701       (mCompFields->GetForcePlainText() ||
00702        mCompFields->GetUseMultipartAlternative()) &&
00703        m_attachment1_body && PL_strcmp(m_attachment1_type, TEXT_HTML) == 0)
00704   {
00705     //
00706     // If we get here, we have an HTML body, but we really need to send
00707     // a text/plain message, so we will write the HTML out to a disk file,
00708     // fire off another URL request for this local disk file and that will
00709     // take care of the conversion...
00710     //
00711     mHTMLFileSpec = nsMsgCreateTempFileSpec("nsmail.html");
00712     if (!mHTMLFileSpec)
00713       goto FAILMEM;
00714 
00715     nsOutputFileStream tempfile(*mHTMLFileSpec, kDefaultMode, 00600);
00716     if (! tempfile.is_open()) 
00717     {
00718       if (mSendReport)
00719       {
00720         nsAutoString error_msg;
00721         nsAutoString path;
00722         NS_CopyNativeToUnicode(
00723           nsDependentCString(mHTMLFileSpec->GetNativePathCString()), path);
00724         nsMsgBuildErrorMessageByID(NS_MSG_UNABLE_TO_OPEN_TMP_FILE, error_msg, &path, nsnull);
00725         mSendReport->SetMessage(nsIMsgSendReport::process_Current, error_msg.get(), PR_FALSE);
00726       }
00727       status = NS_MSG_UNABLE_TO_OPEN_TMP_FILE;
00728       goto FAIL;
00729     }
00730 
00731     if (mOriginalHTMLBody)
00732     {
00733       PRUint32    origLen = strlen(mOriginalHTMLBody);
00734       status = tempfile.write(mOriginalHTMLBody, origLen);
00735       if (status < int(origLen)) 
00736       {
00737         if (status >= 0)
00738           status = NS_MSG_ERROR_WRITING_FILE;
00739         goto FAIL;
00740       }
00741     }
00742 
00743     if (NS_FAILED(tempfile.flush()) || tempfile.failed())
00744     {
00745       status = NS_MSG_ERROR_WRITING_FILE;
00746       goto FAIL;
00747     }
00748 
00749     tempfile.close();
00750 
00751     m_plaintext = new nsMsgAttachmentHandler;
00752     if (!m_plaintext)
00753       goto FAILMEM;
00754     m_plaintext->SetMimeDeliveryState(this);
00755     m_plaintext->m_bogus_attachment = PR_TRUE;
00756 
00757     char *tempURL = nsMsgPlatformFileToURL (*mHTMLFileSpec);
00758     if (!tempURL || NS_FAILED(nsMsgNewURL(getter_AddRefs(m_plaintext->mURL), tempURL)))
00759     {
00760       delete m_plaintext;
00761       m_plaintext = nsnull;
00762       goto FAILMEM;
00763     }
00764   
00765     PR_FREEIF(tempURL);
00766 
00767     PR_FREEIF(m_plaintext->m_type);
00768     m_plaintext->m_type = PL_strdup(TEXT_HTML);
00769     PR_FREEIF(m_plaintext->m_charset);
00770     m_plaintext->m_charset = PL_strdup(mCompFields->GetCharacterSet());
00771     PR_FREEIF(m_plaintext->m_desired_type);
00772     m_plaintext->m_desired_type = PL_strdup(TEXT_PLAIN);
00773     m_attachment_pending_count ++;
00774     status = m_plaintext->SnarfAttachment(mCompFields);
00775     if (NS_FAILED(status))
00776       goto FAIL;
00777     if (m_attachment_pending_count > 0)
00778       return NS_OK;
00779   }
00780     
00781   /* Kludge to avoid having to allocate memory on the toy computers... */
00782   buffer = mime_get_stream_write_buffer();
00783   if (! buffer)
00784     goto FAILMEM;
00785 
00786   buffer_tail = buffer;
00787 
00788   NS_ASSERTION (m_attachment_pending_count == 0, "m_attachment_pending_count != 0");
00789 
00790   mComposeBundle->GetStringByID(NS_MSG_ASSEMBLING_MSG, getter_Copies(msg));
00791   SetStatusMessage( msg );
00792 
00793   /* First, open the message file.
00794   */
00795   mTempFileSpec = nsMsgCreateTempFileSpec("nsmail.eml");
00796   if (! mTempFileSpec)
00797     goto FAILMEM;
00798 
00799   mOutputFile = new nsOutputFileStream(*mTempFileSpec, kDefaultMode, 00600);
00800   if (! mOutputFile->is_open() || CHECK_SIMULATED_ERROR(SIMULATED_SEND_ERROR_4)) 
00801   {
00802     status = NS_MSG_UNABLE_TO_OPEN_TMP_FILE;
00803     if (mSendReport)
00804     {
00805       nsAutoString error_msg;
00806       nsAutoString path;
00807       NS_CopyNativeToUnicode(
00808         nsDependentCString(mTempFileSpec->GetNativePathCString()), path);
00809       nsMsgBuildErrorMessageByID(NS_MSG_UNABLE_TO_OPEN_TMP_FILE, error_msg, &path, nsnull);
00810       mSendReport->SetMessage(nsIMsgSendReport::process_Current, error_msg.get(), PR_FALSE);
00811     }
00812     goto FAIL;
00813   }
00814   
00815   // generate a message id, if necessary
00816   GenerateMessageId( );
00817 
00818   mainbody = new nsMsgSendPart(this, mCompFields->GetCharacterSet());
00819   if (!mainbody)
00820     goto FAILMEM;
00821 
00822   mainbody->SetMainPart(PR_TRUE);
00823   mainbody->SetType(m_attachment1_type ? m_attachment1_type : TEXT_PLAIN);
00824 
00825   NS_ASSERTION(mainbody->GetBuffer() == nsnull, "not-null buffer");
00826   status = mainbody->SetBuffer(m_attachment1_body ? m_attachment1_body : "");
00827   if (status < 0)
00828     goto FAIL;
00829 
00830   /*
00831     Determine the encoding of the main message body before we free it.
00832     The proper way to do this should be to test whatever text is in mainbody
00833     just before writing it out, but that will require a fix that is less safe
00834     and takes more memory. */
00835   PR_FREEIF(m_attachment1_encoding);
00836   if (m_attachment1_body)
00837     mCompFields->GetBodyIsAsciiOnly(&body_is_us_ascii);
00838 
00839   if (mCompFields->GetForceMsgEncoding())
00840     body_is_us_ascii = PR_FALSE;
00841 
00842   if (nsMsgI18Nstateful_charset(mCompFields->GetCharacterSet()) ||
00843       body_is_us_ascii)
00844     m_attachment1_encoding = PL_strdup (ENCODING_7BIT);
00845   else if (mime_use_quoted_printable_p)
00846     m_attachment1_encoding = PL_strdup (ENCODING_QUOTED_PRINTABLE);
00847   else
00848     m_attachment1_encoding = PL_strdup (ENCODING_8BIT);
00849 
00850   PR_FREEIF (m_attachment1_body);
00851 
00852   maincontainer = mainbody;
00853 
00854   // If we were given a pre-saved collection of HTML and contained images,
00855   // then we want mainbody to point to the HTML lump therein.
00856   if (m_related_part)
00857   {
00858     // If m_related_part is of type text/html, set both maincontainer
00859     // and mainbody to point to it. If m_related_part is multipart/related,
00860     // however, set mainbody to be the first child within m_related_part.
00861     delete mainbody;
00862 
00863     // No matter what, maincontainer points to the outermost related part.
00864     maincontainer = m_related_part;
00865     maincontainerISrelatedpart = PR_TRUE;
00866 
00867     mainbody = m_related_part->GetChild(0);
00868     mainbody->SetMainPart(PR_TRUE);
00869   }
00870 
00871   if (m_plaintext) 
00872   {
00873     //
00874     // OK.  We have a plaintext version of the main body that we want to
00875     // send instead of or with the text/html.  Shove it in.
00876     //
00877     plainpart = new nsMsgSendPart(this, mCompFields->GetCharacterSet());
00878     if (!plainpart)
00879       goto FAILMEM;
00880     status = plainpart->SetType(TEXT_PLAIN);
00881     if (status < 0)
00882       goto FAIL;
00883     status = plainpart->SetFile(m_plaintext->mFileSpec);
00884     if (status < 0)
00885       goto FAIL;
00886 
00887     m_plaintext->mMainBody = PR_TRUE;
00888 
00889     m_plaintext->AnalyzeSnarfedFile(); // look for 8 bit text, long lines, etc.
00890     m_plaintext->PickEncoding(mCompFields->GetCharacterSet(), this);
00891     const char *charset = mCompFields->GetCharacterSet();
00892     hdrs = mime_generate_attachment_headers(m_plaintext->m_type,
00893                         nsnull,
00894                         m_plaintext->m_encoding,
00895                         m_plaintext->m_description,
00896                         m_plaintext->m_x_mac_type,
00897                         m_plaintext->m_x_mac_creator,
00898                         nsnull, 0,
00899                         m_digest_p,
00900                         m_plaintext,
00901                         charset,
00902                         charset,
00903                         mCompFields->GetBodyIsAsciiOnly(),
00904                         nsnull,
00905                         PR_TRUE);
00906     if (!hdrs)
00907       goto FAILMEM;
00908     status = plainpart->SetOtherHeaders(hdrs);
00909     PR_Free(hdrs);
00910     hdrs = nsnull;
00911     if (status < 0)
00912       goto FAIL;
00913 
00914     if (mCompFields->GetUseMultipartAlternative()) 
00915     {
00916       nsMsgSendPart* htmlpart = maincontainer;
00917       maincontainer = new nsMsgSendPart(this);
00918       if (!maincontainer)
00919         goto FAILMEM;
00920 
00921       // Setup the maincontainer stuff...
00922       status = maincontainer->SetType(MULTIPART_ALTERNATIVE);
00923       if (status < 0)
00924         goto FAIL;
00925 
00926       status = maincontainer->AddChild(plainpart);
00927       if (status < 0)
00928         goto FAIL;
00929 
00930       status = maincontainer->AddChild(htmlpart);
00931       if (status < 0)
00932         goto FAIL;
00933 
00934       // Create the encoder for the plaintext part here,
00935       // because we aren't the main part (attachment1).
00936       // (This, along with the rest of the routine, should really
00937       // be restructured so that no special treatment is given to
00938       // the main body text that came in. Best to put attachment1_text
00939       // etc. into a nsMsgSendPart, then reshuffle the parts. Sigh.)
00940       if (!PL_strcasecmp(m_plaintext->m_encoding, ENCODING_QUOTED_PRINTABLE))
00941       {
00942         MimeEncoderData *plaintext_enc = MIME_QPEncoderInit(mime_encoder_output_fn, this);
00943         if (!plaintext_enc)
00944         {
00945           status = NS_ERROR_OUT_OF_MEMORY;
00946           goto FAIL;
00947         }
00948         plainpart->SetEncoderData(plaintext_enc);
00949       }
00950       else if (!PL_strcasecmp(m_plaintext->m_encoding, ENCODING_BASE64))
00951       {
00952         MimeEncoderData *plaintext_enc = MIME_B64EncoderInit(mime_encoder_output_fn, this);
00953         if (!plaintext_enc)
00954         {
00955           status = NS_ERROR_OUT_OF_MEMORY;
00956           goto FAIL;
00957         }
00958         plainpart->SetEncoderData(plaintext_enc);
00959       }
00960     }
00961     else 
00962     {
00963       delete maincontainer; 
00964       if (maincontainerISrelatedpart)
00965         m_related_part = nsnull; // in that case, m_related_part == maincontainer which we have just deleted!
00966       maincontainer = plainpart;
00967       mainbody = maincontainer;
00968       PR_FREEIF(m_attachment1_type);
00969       m_attachment1_type = PL_strdup(TEXT_PLAIN);
00970       if (!m_attachment1_type)
00971         goto FAILMEM;
00972 
00973       /* Override attachment1_encoding here. */
00974       PR_FREEIF(m_attachment1_encoding);
00975       m_attachment1_encoding = PL_strdup(m_plaintext->m_encoding);
00976 
00977       plaintext_is_mainbody_p = PR_TRUE; // converted plaintext is mainbody
00978     }
00979   }
00980 
00981   // check if we need to encapsulate the message in a multipart/mixed or multipart/digest
00982   if (m_attachment_count > multipartRelatedCount) 
00983   {
00984     toppart = new nsMsgSendPart(this);
00985     if (!toppart)
00986       goto FAILMEM;
00987 
00988     status = toppart->SetType(m_digest_p ? MULTIPART_DIGEST : MULTIPART_MIXED);
00989     if (status < 0)
00990       goto FAIL;
00991 
00992     status = toppart->AddChild(maincontainer);
00993     if (status < 0)
00994       goto FAIL;
00995   }
00996   else
00997     toppart = maincontainer;
00998 
00999   // Is the top part a multipart container?
01000   // can't use m_attachment_count because it's not reliable for that
01001   // instead use type of main part. See bug #174396
01002   toppart_type = toppart->GetType(); // GetType return directly the member variable, don't free it!
01003   if (!m_crypto_closure && toppart_type && !PL_strncasecmp(toppart_type, "multipart/", 10))
01004   {
01005     status = toppart->SetBuffer(MIME_MULTIPART_BLURB);
01006     if (status < 0)
01007       goto FAIL;
01008   }
01009 
01010    /* Write out the message headers.
01011    */
01012   headers = mime_generate_headers (mCompFields, mCompFields->GetCharacterSet(),
01013                                    m_deliver_mode, promptObject, &status);
01014   if (status < 0) 
01015     goto FAIL;
01016 
01017   if (!headers)
01018     goto FAILMEM;
01019 
01020   // 
01021   // If we converted HTML into plaintext, the plaintext part (plainpart)
01022   // already has its content-type and content-transfer-encoding
01023   // ("other") headers set. 
01024   // 
01025   // In the specific case where such a plaintext part is the 
01026   // top level message part (iff an HTML message is being sent
01027   // as text only and no other attachments exist) we want to 
01028   // preserve the original plainpart headers, since they
01029   // contain accurate transfer encoding and Mac type/creator 
01030   // information.
01031   // 
01032   // So, in the above case we append the main message headers, 
01033   // otherwise we overwrite whatever headers may have existed.
01034   // 
01035   /* reordering of headers will happen in nsMsgSendPart::Write */
01036   if ((plainpart) && (plainpart == toppart))
01037     status = toppart->AppendOtherHeaders(headers);
01038   else
01039     status = toppart->SetOtherHeaders(headers);
01040   PR_Free(headers);
01041   headers = nsnull;
01042   if (status < 0)
01043     goto FAIL;
01044 
01045   // Set up the first part (user-typed.)  For now, do it even if the first
01046   // part is empty; we need to add things to skip it if this part is empty.
01047 
01048   // Set up encoder for the first part (message body.)
01049   //
01050   NS_ASSERTION(!m_attachment1_encoder_data, "not-null m_attachment1_encoder_data");
01051   if (!PL_strcasecmp(m_attachment1_encoding, ENCODING_BASE64))
01052   {
01053     m_attachment1_encoder_data = MIME_B64EncoderInit(mime_encoder_output_fn, this);
01054     if (!m_attachment1_encoder_data) goto FAILMEM;
01055   }
01056   else
01057     if (!PL_strcasecmp(m_attachment1_encoding, ENCODING_QUOTED_PRINTABLE)) {
01058       m_attachment1_encoder_data =
01059       MIME_QPEncoderInit(mime_encoder_output_fn, this);
01060     }
01061 
01062   // If we converted HTML into plaintext, the plaintext part
01063   // already has its type/encoding headers set. So, in the specific
01064   // case where such a plaintext part is the main message body
01065   // (iff an HTML message is being sent as text only)
01066   // we want to avoid generating type/encoding/digest headers;
01067   // in all other cases, generate such headers here.
01068   //
01069   // We really want to set up headers as a dictionary of some sort
01070   // so that we need not worry about duplicate header lines.
01071   //
01072   if ((!plainpart) || (plainpart != mainbody))
01073   {
01074     const char *charset = mCompFields->GetCharacterSet();
01075     hdrs = mime_generate_attachment_headers (m_attachment1_type,
01076                          nsnull,
01077                          m_attachment1_encoding,
01078                          0, 0, 0, 0, 0,
01079                          m_digest_p,
01080                          nsnull, /* no "ma"! */
01081                          charset,
01082                          charset,
01083                          mCompFields->GetBodyIsAsciiOnly(),
01084                          nsnull,
01085                          PR_TRUE);
01086     if (!hdrs)
01087       goto FAILMEM;
01088     status = mainbody->AppendOtherHeaders(hdrs);
01089     if (status < 0)
01090       goto FAIL;
01091   }
01092 
01093   PR_FREEIF(hdrs);
01094 
01095   status = mainbody->SetEncoderData(m_attachment1_encoder_data);
01096   m_attachment1_encoder_data = nsnull;
01097   if (status < 0)
01098     goto FAIL;
01099 
01100   //
01101   // Now we need to process attachments and slot them in the
01102   // correct heirarchy.
01103   //
01104   if (m_attachment_count > 0)
01105   {
01106     // Kludge to avoid having to allocate memory on the toy computers...
01107     if (! mime_mailto_stream_read_buffer)
01108       mime_mailto_stream_read_buffer = (char *) PR_Malloc (MIME_BUFFER_SIZE);
01109     buffer = mime_mailto_stream_read_buffer;
01110     if (! buffer)
01111       goto FAILMEM;
01112     buffer_tail = buffer;
01113 
01114     // Gather all of the attachments for this message that are NOT
01115     // part of an enclosed MHTML message!
01116     for (i = 0; i < m_attachment_count; i++)
01117     {
01118       nsMsgAttachmentHandler *ma = &m_attachments[i];
01119       if (!ma->mMHTMLPart)
01120         PreProcessPart(ma, toppart);
01121     }
01122 
01123     // 
01124     // If we have a m_related_part as a container for children, then we have to 
01125     // tack on these children for the part
01126     //
01127     if (m_related_part)
01128     {
01129       for (i = 0; i < m_attachment_count; i++) 
01130       {
01131         //
01132         // rhp: This is here because we could get here after saying OK
01133         // to a lot of prompts about not being able to fetch this part!
01134         //
01135         if (m_attachments[i].mPartUserOmissionOverride)
01136           continue;
01137 
01138         // Now, we need to add this part to the m_related_part member so the 
01139         // message will be generated correctly.
01140         if (m_attachments[i].mMHTMLPart)
01141           PreProcessPart(&(m_attachments[i]), m_related_part);
01142       }
01143     }
01144 
01145   }
01146 
01147   // Tell the user we are creating the message...
01148   mComposeBundle->GetStringByID(NS_MSG_CREATING_MESSAGE, getter_Copies(msg));
01149   SetStatusMessage( msg );
01150 
01151   // OK, now actually write the structure we've carefully built up.
01152   status = toppart->Write();
01153   if (status < 0)
01154     goto FAIL;
01155 
01156   /* Close down encryption stream */
01157   if (m_crypto_closure)
01158        {
01159          status = m_crypto_closure->FinishCryptoEncapsulation(PR_FALSE, mSendReport);
01160          m_crypto_closure = 0;
01161          if (NS_FAILED(status)) goto FAIL;
01162        }
01163  
01164   if (mOutputFile) 
01165   {
01166     if (NS_FAILED(mOutputFile->flush()) || mOutputFile->failed()) 
01167     {
01168       status = NS_MSG_ERROR_WRITING_FILE;
01169       goto FAIL;
01170     }
01171 
01172     mOutputFile->close();
01173     delete mOutputFile;
01174     mOutputFile = nsnull;
01175 
01176     /* If we don't do this check...ZERO length files can be sent */
01177     if (mTempFileSpec->GetFileSize() == 0)
01178     {
01179      status = NS_MSG_ERROR_WRITING_FILE;
01180       goto FAIL;
01181     }
01182   }
01183 
01184   mComposeBundle->GetStringByID(NS_MSG_ASSEMB_DONE_MSG, getter_Copies(msg));
01185   SetStatusMessage( msg );
01186 
01187   if (m_dont_deliver_p && mListener)
01188   {
01189     //
01190     // Need to ditch the file spec here so that we don't delete the
01191     // file, since in this case, the caller wants the file
01192     //
01193     NS_NewFileSpecWithSpec(*mTempFileSpec, &mReturnFileSpec);
01194     delete mTempFileSpec;
01195     mTempFileSpec = nsnull;
01196     if (!mReturnFileSpec)
01197       NotifyListenerOnStopSending(nsnull, NS_ERROR_OUT_OF_MEMORY, nsnull, nsnull);
01198     else
01199       NotifyListenerOnStopSending(nsnull, NS_OK, nsnull, mReturnFileSpec);
01200   }
01201   else 
01202   {
01203     status = DeliverMessage();
01204     if (NS_SUCCEEDED(status))
01205       shouldDeleteDeliveryState = PR_FALSE;
01206   }
01207   goto FAIL;
01208 
01209 FAILMEM:
01210   status = NS_ERROR_OUT_OF_MEMORY;
01211 
01212 FAIL:
01213   if (toppart)
01214     delete toppart;
01215   toppart = nsnull;
01216   mainbody = nsnull;
01217   maincontainer = nsnull;
01218 
01219   PR_FREEIF(headers);
01220   if (in_file) 
01221   {
01222     PR_Close (in_file);
01223     in_file = nsnull;
01224   }
01225 
01226   if (shouldDeleteDeliveryState)
01227   {
01228     if (status < 0) 
01229     {
01230       m_status = status;
01231       nsresult ignoreMe;
01232       Fail (status, nsnull, &ignoreMe);
01233     }
01234   }
01235 
01236   return status;
01237 }
01238 
01239 PRInt32
01240 nsMsgComposeAndSend::PreProcessPart(nsMsgAttachmentHandler  *ma,
01241                                     nsMsgSendPart           *toppart) // The very top most container of the message
01242 {
01243   nsresult        status;
01244   char            *hdrs = 0;
01245   nsMsgSendPart   *part = nsnull;
01246 
01247   // If this was one of those dead parts from a quoted web page, 
01248   // then just return safely.
01249   //
01250   if (ma->m_bogus_attachment)
01251     return 0;
01252 
01253   // If at this point we *still* don't have a content-type, then
01254   // we're never going to get one.
01255   if (ma->m_type == nsnull) 
01256   {
01257     ma->m_type = PL_strdup(UNKNOWN_CONTENT_TYPE);
01258     if (ma->m_type == nsnull)
01259       return 0;
01260   }
01261 
01262   ma->PickEncoding (mCompFields->GetCharacterSet(), this);
01263 
01264   part = new nsMsgSendPart(this);
01265   if (!part)
01266     return 0;
01267   status = toppart->AddChild(part);
01268   if (NS_FAILED(status))
01269     return 0;
01270   status = part->SetType(ma->m_type);
01271   if (NS_FAILED(status))
01272     return 0;
01273 
01274   nsXPIDLCString turl;
01275   if (!ma->mURL)
01276     {
01277       if (ma->m_uri)
01278         turl.Adopt(nsCRT::strdup(ma->m_uri));
01279     }
01280   else
01281     ma->mURL->GetSpec(turl);
01282   hdrs = mime_generate_attachment_headers (ma->m_type,
01283                                            ma->m_type_param,
01284                                            ma->m_encoding,
01285                                            ma->m_description,
01286                                            ma->m_x_mac_type,
01287                                            ma->m_x_mac_creator,
01288                                            ma->m_real_name,
01289                                            turl,
01290                                            m_digest_p,
01291                                            ma,
01292                                            ma->m_charset, // rhp - this needs
01293                                                           // to be the charset
01294                                                           // we determine from
01295                                                           // the file or none
01296                                                           // at all! 
01297                                            mCompFields->GetCharacterSet(),
01298                                            PR_FALSE,      // bodyIsAsciiOnly to false
01299                                                           // for attachments
01300                                            ma->m_content_id,
01301                                            PR_FALSE);
01302   if (!hdrs)
01303     return 0;
01304 
01305   status = part->SetOtherHeaders(hdrs);
01306   PR_FREEIF(hdrs);
01307   if (NS_FAILED(status))
01308     return 0;
01309   status = part->SetFile(ma->mFileSpec);
01310   if (NS_FAILED(status))
01311     return 0;
01312   if (ma->m_encoder_data) 
01313   {
01314     status = part->SetEncoderData(ma->m_encoder_data);
01315     if (NS_FAILED(status))
01316       return 0;
01317     ma->m_encoder_data = nsnull;
01318   }
01319 
01320   ma->m_current_column = 0;
01321 
01322   if (ma->m_type &&
01323       (!PL_strcasecmp (ma->m_type, MESSAGE_RFC822) ||
01324       !PL_strcasecmp (ma->m_type, MESSAGE_NEWS))) {
01325     status = part->SetStripSensitiveHeaders(PR_TRUE);
01326     if (NS_FAILED(status))
01327       return 0;
01328   }
01329 
01330   return 1;
01331 }
01332 
01333 
01334 #if defined(XP_MAC) && defined(DEBUG)
01335 // Compiler runs out of registers for the debug build.
01336 #pragma global_optimizer on
01337 #pragma optimization_level 4
01338 #endif // XP_MAC && DEBUG
01339 
01340 # define FROB(X) \
01341     if (X && *X) \
01342     { \
01343       if (*recipients) PL_strcat(recipients, ","); \
01344       PL_strcat(recipients, X); \
01345     }
01346 
01347 nsresult nsMsgComposeAndSend::BeginCryptoEncapsulation ()
01348 {
01349   // Try to create a secure compose object. If we can create it, then query to see
01350   // if we need to use it for this send transaction. 
01351 
01352   nsresult rv = NS_OK;
01353   nsCOMPtr<nsIMsgComposeSecure> secureCompose;
01354   secureCompose = do_CreateInstance(NS_MSGCOMPOSESECURE_CONTRACTID, &rv);
01355   // it's not an error scenario of there is secure compose
01356   if (NS_FAILED(rv))
01357     return NS_OK;
01358 
01359   if (secureCompose)
01360   {
01361     PRBool requiresEncryptionWork = PR_FALSE;
01362     secureCompose->RequiresCryptoEncapsulation(mUserIdentity, mCompFields, &requiresEncryptionWork);
01363     if (requiresEncryptionWork)
01364     {
01365       m_crypto_closure = secureCompose;
01366       // bah i'd like to move the following blurb into the implementation of BeginCryptoEncapsulation; however
01367       // the apis for nsIMsgComposeField just aren't rich enough. It requires the implementor to jump through way
01368       // too many string conversions....
01369            char * recipients = (char *)
01370       PR_MALLOC((mCompFields->GetTo()  ? strlen(mCompFields->GetTo())  : 0) +
01371                              (mCompFields->GetCc()  ? strlen(mCompFields->GetCc())  : 0) +
01372                              (mCompFields->GetBcc() ? strlen(mCompFields->GetBcc()) : 0) +
01373                              (mCompFields->GetNewsgroups() ? strlen(mCompFields->GetNewsgroups()) : 0) + 20);
01374            if (!recipients) return NS_ERROR_OUT_OF_MEMORY;
01375 
01376       *recipients = 0;
01377 
01378            FROB(mCompFields->GetTo())
01379            FROB(mCompFields->GetCc())
01380            FROB(mCompFields->GetBcc())
01381            FROB(mCompFields->GetNewsgroups())
01382 
01383       // end section of code I'd like to move to the implementor.....
01384       rv = m_crypto_closure->BeginCryptoEncapsulation(mOutputFile,
01385                                                       recipients,
01386                                                       mCompFields,
01387                                                       mUserIdentity,
01388                                                       mSendReport,
01389                                                       (m_deliver_mode == nsMsgSaveAsDraft));
01390 
01391       PR_FREEIF(recipients);
01392     }
01393 
01394   }
01395 
01396   return rv;
01397 }
01398 
01399 #if defined(XP_MAC) && defined(DEBUG)
01400 #pragma global_optimizer reset
01401 #endif // XP_MAC && DEBUG
01402 
01403 nsresult
01404 mime_write_message_body(nsIMsgSend *state, char *buf, PRInt32 size)
01405 {
01406   NS_ENSURE_ARG_POINTER(state);
01407 
01408   nsOutputFileStream * output;
01409   nsCOMPtr<nsIMsgComposeSecure> crypto_closure;
01410 
01411   state->GetOutputStream(&output);
01412   if (!output || CHECK_SIMULATED_ERROR(SIMULATED_SEND_ERROR_9))
01413     return NS_MSG_ERROR_WRITING_FILE;
01414 
01415   state->GetCryptoclosure(getter_AddRefs(crypto_closure));
01416   if (crypto_closure)
01417   {
01418          return crypto_closure->MimeCryptoWriteBlock (buf, size);
01419        }
01420 
01421   if (PRInt32(output->write(buf, size)) < size) 
01422   {
01423     return NS_MSG_ERROR_WRITING_FILE;
01424   } 
01425   else 
01426   {
01427     return NS_OK;
01428   }
01429 }
01430 
01431 nsresult
01432 mime_encoder_output_fn(const char *buf, PRInt32 size, void *closure)
01433 {
01434   nsMsgComposeAndSend *state = (nsMsgComposeAndSend *) closure;
01435   return mime_write_message_body (state, (char *) buf, size);
01436 }
01437 
01438 nsresult
01439 nsMsgComposeAndSend::GetEmbeddedObjectInfo(nsIDOMNode *node, nsMsgAttachmentData *attachment, PRBool *acceptObject)
01440 {
01441   NS_ENSURE_ARG_POINTER(node);
01442   NS_ENSURE_ARG_POINTER(attachment);
01443   NS_ENSURE_ARG_POINTER(acceptObject);
01444 
01445 // GetEmbeddedObjectInfo will determine if we need to attach the source of the embedded object with the message
01446 // The decision is made automatically unless the attribute moz-do-not-send has been set to true or false
01447 // The default rule is that all image and anchor objects are attached as well link to a local file
01448   nsresult rv;
01449 
01450   // Reset this structure to null!
01451   memset(attachment, 0, sizeof(nsMsgAttachmentData));
01452   *acceptObject = PR_FALSE;
01453 
01454   // Check if the object has a moz-do-not-send attribute set. If it's true,
01455   // we must ignore it, if false set forceToBeAttached to be true.
01456 
01457   PRBool forceToBeAttached = PR_FALSE;
01458   nsCOMPtr<nsIDOMElement> domElement = do_QueryInterface(node);
01459   if (domElement)
01460   {
01461     nsAutoString attributeValue;
01462     if (NS_SUCCEEDED(domElement->GetAttribute(NS_LITERAL_STRING(ATTR_MOZ_DO_NOT_SEND), attributeValue)))
01463     {
01464       if (attributeValue.LowerCaseEqualsLiteral("true"))
01465         return NS_OK;
01466       if (attributeValue.LowerCaseEqualsLiteral("false"))
01467         forceToBeAttached = PR_TRUE;
01468     }
01469   }
01470     
01471   // Now, we know the types of objects this node can be, so we will do
01472   // our query interface here and see what we come up with 
01473   nsCOMPtr<nsIDOMHTMLBodyElement>     body = (do_QueryInterface(node));
01474   // XXX convert to use nsIImageLoadingContent?
01475   nsCOMPtr<nsIDOMHTMLImageElement>    image = (do_QueryInterface(node));
01476   nsCOMPtr<nsIDOMHTMLLinkElement>     link = (do_QueryInterface(node));
01477   nsCOMPtr<nsIDOMHTMLAnchorElement>   anchor = (do_QueryInterface(node));
01478     
01479   // First, try to see if the body as a background image
01480   if (body)
01481   {
01482     nsAutoString    tUrl;
01483     if (NS_SUCCEEDED(body->GetBackground(tUrl)))
01484     {
01485       nsCAutoString turlC;
01486       CopyUTF16toUTF8(tUrl, turlC);
01487       if (NS_SUCCEEDED(nsMsgNewURL(&attachment->url, turlC.get())))      
01488         NS_IF_ADDREF(attachment->url);
01489       else
01490         return NS_OK;
01491      }
01492   }
01493   else if (image)        // Is this an image?
01494   {
01495     nsString    tUrl;
01496     nsString    tName;
01497     nsString    tDesc;
01498     
01499     // Create the URI
01500     if (NS_FAILED(image->GetSrc(tUrl)))
01501       return NS_ERROR_FAILURE;
01502     nsCAutoString turlC;
01503     CopyUTF16toUTF8(tUrl, turlC);
01504     if (NS_FAILED(nsMsgNewURL(&attachment->url, turlC.get())))
01505     {
01506       // Well, the first time failed...which means we probably didn't get
01507       // the full path name...
01508       //
01509       nsIDOMDocument    *ownerDocument = nsnull;
01510       node->GetOwnerDocument(&ownerDocument);
01511       if (ownerDocument)
01512       {
01513         nsIDocument     *doc = nsnull;
01514         if (NS_FAILED(ownerDocument->QueryInterface(NS_GET_IID(nsIDocument),(void**)&doc)) || !doc)
01515           return NS_ERROR_OUT_OF_MEMORY;
01516         
01517         nsCAutoString spec;
01518         nsIURI *uri = doc->GetDocumentURI();
01519         
01520         if (!uri)
01521           return NS_ERROR_OUT_OF_MEMORY;
01522         
01523         uri->GetSpec(spec);
01524         
01525         // Ok, now get the path to the root doc and tack on the name we
01526         // got from the GetSrc() call....
01527         NS_ConvertUTF8toUTF16 workURL(spec);
01528         
01529         PRInt32 loc = workURL.RFind("/");
01530         if (loc >= 0)
01531           workURL.SetLength(loc+1);
01532         workURL.Append(tUrl);
01533         NS_ConvertUTF16toUTF8 workurlC(workURL);
01534         if (NS_FAILED(nsMsgNewURL(&attachment->url, workurlC.get())))
01535         {
01536           // rhp - just try to continue and send it without this image.
01537           return NS_OK;
01538         }
01539       }
01540     }
01541     
01542     NS_IF_ADDREF(attachment->url);
01543     
01544     rv = image->GetName(tName);
01545     NS_ENSURE_SUCCESS(rv, rv);
01546     attachment->real_name = ToNewCString(tName); // XXX i18n
01547     
01548     image->GetLongDesc(tDesc);
01549     NS_ENSURE_SUCCESS(rv, rv);
01550     attachment->description = ToNewCString(tDesc); // XXX i18n
01551     
01552   }
01553   else if (link)        // Is this a link?
01554   {
01555     nsString    tUrl;
01556     
01557     // Create the URI
01558     rv = link->GetHref(tUrl);
01559     NS_ENSURE_SUCCESS(rv, rv);
01560     nsCAutoString turlC;
01561     CopyUTF16toUTF8(tUrl, turlC);
01562     rv = nsMsgNewURL(&attachment->url, turlC.get());
01563     NS_ENSURE_SUCCESS(rv, rv);
01564     
01565     NS_IF_ADDREF(attachment->url);
01566   }
01567   else if (anchor)
01568   {
01569     nsString    tUrl;
01570     nsString    tName;
01571     
01572     // Create the URI
01573     rv = anchor->GetHref(tUrl);
01574     NS_ENSURE_SUCCESS(rv, rv);
01575     nsCAutoString turlC;
01576     CopyUTF16toUTF8(tUrl, turlC);
01577     rv = nsMsgNewURL(&attachment->url, turlC.get());
01578     NS_ENSURE_SUCCESS(rv, rv);
01579     
01580     NS_IF_ADDREF(attachment->url);
01581     
01582     rv = anchor->GetName(tName);
01583     NS_ENSURE_SUCCESS(rv, rv);
01584     attachment->real_name = ToNewCString(tName);
01585   }
01586   else
01587   {
01588     // If we get here, we got something we didn't expect!
01589     // Just try to continue and send it without this thing.
01590     return NS_OK;
01591   }
01592     
01593   //
01594   // Before going further, check if we are dealing with a local file and
01595   // if it's the case be sure the file exist!
01596   PRBool schemeIsFile = PR_FALSE;
01597   rv = attachment->url->SchemeIs("file", &schemeIsFile);
01598   if (NS_SUCCEEDED(rv) && schemeIsFile)
01599   {
01600     nsCOMPtr<nsIFileURL> fileUrl (do_QueryInterface(attachment->url));
01601     if (fileUrl)
01602     {
01603       PRBool isAValidFile = PR_FALSE;
01604 
01605       nsCOMPtr<nsIFile> aFile;
01606       rv = fileUrl->GetFile(getter_AddRefs(aFile));
01607       if (NS_SUCCEEDED(rv) && aFile)
01608       {
01609         nsCOMPtr<nsILocalFile> aLocalFile (do_QueryInterface(aFile));
01610         if (aLocalFile)
01611         {
01612           rv = aLocalFile->IsFile(&isAValidFile);
01613           if (NS_FAILED(rv))
01614             isAValidFile = PR_FALSE;
01615           else
01616           {
01617             if (anchor)
01618             {
01619               // One more test, if the anchor points to a local network server, let's check what the pref
01620               // mail.compose.dont_attach_source_of_local_network_links tells us to do.
01621               nsCAutoString urlSpec;         
01622               rv = attachment->url->GetSpec(urlSpec);
01623               if (NS_SUCCEEDED(rv))
01624                 if (StringBeginsWith(urlSpec, NS_LITERAL_CSTRING("file://///")))
01625                 {
01626                   nsCOMPtr<nsIPrefBranch> pPrefBranch(do_GetService(NS_PREFSERVICE_CONTRACTID));
01627                   if (pPrefBranch)
01628                   {
01629                     PRBool dontSend = PR_FALSE;
01630                     rv = pPrefBranch->GetBoolPref(PREF_MAIL_DONT_ATTACH_SOURCE, &dontSend);
01631                     if (dontSend)
01632                       isAValidFile = PR_FALSE;
01633                   }
01634                 }
01635             }
01636           }
01637         }
01638       }
01639       
01640       if (! isAValidFile)
01641         return NS_OK;
01642     }  
01643   }
01644   else //not a file:// url
01645   {
01646     //if this is an anchor, don't attach remote file unless we have been forced to do it
01647     if (anchor && !forceToBeAttached)
01648       return NS_OK;
01649   }
01650   
01651   *acceptObject = PR_TRUE;
01652   return NS_OK;
01653 }
01654 
01655 
01656 PRUint32
01657 nsMsgComposeAndSend::GetMultipartRelatedCount(PRBool forceToBeCalculated /*=PR_FALSE*/)
01658 {
01659   nsresult                  rv = NS_OK;
01660   PRUint32                  count;
01661 
01662   if (mMultipartRelatedAttachmentCount != -1 && !forceToBeCalculated)
01663     return (PRUint32)mMultipartRelatedAttachmentCount;
01664 
01665   //First time here, let's calculate the correct number of related part we need to generate
01666   mMultipartRelatedAttachmentCount = 0;
01667   nsCOMPtr<nsIEditorMailSupport> mailEditor (do_QueryInterface(mEditor));
01668   if (!mailEditor)
01669     return 0;
01670 
01671   rv = mailEditor->GetEmbeddedObjects(getter_AddRefs(mEmbeddedObjectList));
01672   if ((NS_FAILED(rv) || (!mEmbeddedObjectList)))
01673     return 0;
01674 
01675   if (NS_SUCCEEDED(mEmbeddedObjectList->Count(&count)))
01676   {
01677     if (count > 0)
01678     {
01679       // Let parse the list to count the number of valid objects. BTW, we can remove the others from the list
01680       nsMsgAttachmentData attachment;
01681 
01682       PRInt32 i;
01683       nsCOMPtr<nsIDOMNode> node;
01684       nsCOMPtr <nsISupports> isupp;
01685 
01686       for (i = count - 1, count = 0; i >= 0; i --)
01687       {
01688         // Reset this structure to null!
01689         memset(&attachment, 0, sizeof(nsMsgAttachmentData));
01690         
01691         // now we need to get the element in the array and do the magic
01692         // to process this element.
01693         //
01694         mEmbeddedObjectList->QueryElementAt(i, NS_GET_IID(nsIDOMNode), getter_AddRefs(node));
01695         if (!node)
01696           continue;
01697     
01698         PRBool acceptObject = PR_FALSE;
01699         rv = GetEmbeddedObjectInfo(node, &attachment, &acceptObject);
01700         if (NS_SUCCEEDED(rv) && acceptObject)
01701           count ++;
01702         else
01703           mEmbeddedObjectList->DeleteElementAt(i);
01704       }
01705     }
01706     mMultipartRelatedAttachmentCount = (PRInt32)count;
01707     return count;
01708   }
01709   else
01710     return 0;
01711 }
01712 
01713 nsresult
01714 nsMsgComposeAndSend::GetBodyFromEditor()
01715 {
01716   //
01717   // Now we have to fix up and get the HTML from the editor. After we
01718   // get the HTML data, we need to store it in the m_attachment_1_body
01719   // member variable after doing the necessary charset conversion.
01720   //
01721 
01722   // 
01723   // Query the editor, get the body of HTML!
01724   //
01725   nsString  format;
01726   format.AssignLiteral(TEXT_HTML);
01727   PRUint32  flags = nsIDocumentEncoder::OutputFormatted  | nsIDocumentEncoder::OutputNoFormattingInPre;
01728   nsAutoString bodyStr;
01729   PRUnichar* bodyText = nsnull;
01730   nsresult rv;
01731   PRUnichar *origHTMLBody = nsnull;
01732 
01733   // Ok, get the body...the DOM should have been whacked with 
01734   // Content ID's already
01735   mEditor->OutputToString(format, flags, bodyStr);
01736 
01737  //
01738   // If we really didn't get a body, just return NS_OK
01739   //
01740   if (bodyStr.IsEmpty())
01741     return NS_OK;
01742   bodyText = ToNewUnicode(bodyStr);
01743   if (!bodyText)
01744     return NS_ERROR_OUT_OF_MEMORY;
01745 
01746   // If we are forcing this to be plain text, we should not be
01747   // doing this conversion.
01748   PRBool doConversion = PR_TRUE;
01749 
01750   if ( (mCompFields) && mCompFields->GetForcePlainText() )
01751     doConversion = PR_FALSE;
01752 
01753   if (doConversion)
01754   {
01755     nsCOMPtr<mozITXTToHTMLConv> conv = do_CreateInstance(MOZ_TXTTOHTMLCONV_CONTRACTID, &rv);
01756 
01757     if (NS_SUCCEEDED(rv)) 
01758     {
01759       PRUint32 whattodo = mozITXTToHTMLConv::kURLs;
01760       PRBool enable_structs = PR_FALSE;
01761       nsCOMPtr<nsIPrefBranch> pPrefBranch(do_GetService(NS_PREFSERVICE_CONTRACTID));
01762       if (pPrefBranch)
01763       {
01764         rv = pPrefBranch->GetBoolPref(PREF_MAIL_SEND_STRUCT, &enable_structs);
01765         if (enable_structs)
01766           whattodo = whattodo | mozITXTToHTMLConv::kStructPhrase;
01767       }
01768       
01769       PRUnichar* wresult;
01770       rv = conv->ScanHTML(bodyText, whattodo, &wresult);
01771       if (NS_SUCCEEDED(rv))
01772       {
01773         // Save the original body for possible attachment as plain text
01774         // We should have what the user typed in stored in mOriginalHTMLBody
01775         origHTMLBody = bodyText;
01776         bodyText = wresult;
01777       }
01778     }
01779   }
01780   
01781   nsCString attachment1_body;
01782   // we'd better be "text/html" at this point
01783   char          *attachment1_type = TEXT_HTML;  
01784 
01785   // Convert body to mail charset
01786   nsXPIDLCString    outCString;
01787   const char  *aCharset = mCompFields->GetCharacterSet();
01788 
01789   if (aCharset && *aCharset)
01790   {
01791     // Convert to entities.
01792     // If later Editor generates entities then we can remove this.
01793     PRBool isAsciiOnly;
01794     rv = nsMsgI18NSaveAsCharset(mCompFields->GetForcePlainText() ? TEXT_PLAIN : attachment1_type, 
01795                                 aCharset, bodyText, getter_Copies(outCString), nsnull, &isAsciiOnly);
01796 
01797     if (mCompFields->GetForceMsgEncoding())
01798       isAsciiOnly = PR_FALSE;
01799 
01800     mCompFields->SetBodyIsAsciiOnly(isAsciiOnly);
01801       
01802     // body contains characters outside the current mail charset,
01803     // ask whether to convert to UTF-8 (bug 233361). do this only for text/plain
01804     if ((NS_ERROR_UENC_NOMAPPING == rv) && mCompFields->GetForcePlainText()) {
01805       // if nbsp then replace it by sp and try again
01806       PRUnichar *bodyTextPtr = bodyText;
01807       while (*bodyTextPtr) {
01808         if (0x00A0 == *bodyTextPtr)
01809           *bodyTextPtr = 0x0020;
01810         bodyTextPtr++;
01811       }
01812       
01813       nsXPIDLCString fallbackCharset;
01814       rv = nsMsgI18NSaveAsCharset(TEXT_PLAIN, aCharset, bodyText,
01815            getter_Copies(outCString), getter_Copies(fallbackCharset));
01816 
01817       if (NS_ERROR_UENC_NOMAPPING == rv) {
01818         PRBool needToCheckCharset;
01819         mCompFields->GetNeedToCheckCharset(&needToCheckCharset);
01820         if (needToCheckCharset) {
01821           nsCOMPtr<nsIPrompt> prompt;
01822           GetDefaultPrompt(getter_AddRefs(prompt));
01823           PRInt32 answer = nsMsgAskAboutUncoveredCharacters(prompt);
01824           switch (answer) {
01825             case 0 : // convert to UTF-8
01826               CopyUTF16toUTF8(bodyText, outCString);
01827               mCompFields->SetCharacterSet("UTF-8"); // tag as UTF-8
01828               break; 
01829             case 1 : // return to the editor
01830               Recycle(bodyText);
01831               return NS_ERROR_MSG_MULTILINGUAL_SEND;
01832             case 2 : // send anyway 
01833               break;
01834           }
01835         }
01836       }
01837       // re-label to the fallback charset
01838       else if (fallbackCharset)
01839         mCompFields->SetCharacterSet(fallbackCharset.get());
01840     }
01841 
01842     if (NS_SUCCEEDED(rv)) 
01843       attachment1_body = outCString;
01844 
01845     // If we have an origHTMLBody that is not null, this means that it is
01846     // different than the bodyText because of formatting conversions. Because of
01847     // this we need to do the charset conversion on this part separately
01848     if (origHTMLBody)
01849     {
01850       char      *newBody = nsnull;
01851       rv = nsMsgI18NSaveAsCharset(mCompFields->GetUseMultipartAlternative() ? TEXT_PLAIN : attachment1_type, 
01852                                   aCharset, origHTMLBody, &newBody);
01853       if (NS_SUCCEEDED(rv)) 
01854       {
01855         PR_FREEIF(origHTMLBody);
01856         origHTMLBody = (PRUnichar *)newBody;
01857       }
01858     }
01859 
01860     Recycle(bodyText);    //Don't need it anymore
01861   }
01862   else
01863     return NS_ERROR_FAILURE;
01864 
01865   // If our holder for the orignal body text is STILL null, then just 
01866   // just copy what we have as the original body text.
01867   //
01868   if (!origHTMLBody)
01869     mOriginalHTMLBody = nsCRT::strdup(attachment1_body.get());
01870   else
01871     mOriginalHTMLBody = (char *)origHTMLBody;
01872 
01873   rv = SnarfAndCopyBody(attachment1_body.get(), attachment1_body.Length(),
01874                         attachment1_type);
01875 
01876   return rv;
01877 }
01878 
01879 // for SMTP, 16k
01880 // for our internal protocol buffers, 4k
01881 // for news < 1000
01882 // so we choose the minimum, because we could be sending and posting this message.
01883 #define LINE_BREAK_MAX 990
01884 
01885 // EnsureLineBreaks() will set m_attachment1_body and m_attachment1_body_length 
01886 nsresult
01887 nsMsgComposeAndSend::EnsureLineBreaks(const char *body, PRUint32 bodyLen)
01888 {
01889   NS_ENSURE_ARG_POINTER(body);
01890 
01891   PRUint32 i;
01892   PRUint32 charsSinceLineBreak = 0;
01893   PRUint32 lastPos = 0;
01894 
01895   char *newBody = nsnull;
01896   char *newBodyPos = nsnull;
01897   
01898   // the most common way to get into the state where we have to insert
01899   // linebreaks is when we do HTML reply and we quote large <pre> blocks.
01900   // see #83381 and #84261
01901   // 
01902   // until #67334 is fixed, we'll be replacing newlines with <br>, which can lead
01903   // to large quoted <pre> blocks without linebreaks.
01904   // this hack makes it so we can at least save (as draft or template) and send or post
01905   // the message.
01906   // 
01907   // XXX TODO 
01908   // march backwards and determine the "best" place for the linebreak
01909   // for example, we don't want <a hrLINEBREAKref=""> or <bLINEBREAKr>
01910   // or "MississLINEBREAKippi" 
01911   for (i = 0; i < bodyLen-1; i++) {
01912     if (nsCRT::strncmp(body+i, NS_LINEBREAK, NS_LINEBREAK_LEN)) {
01913       charsSinceLineBreak++;
01914       if (charsSinceLineBreak == LINE_BREAK_MAX) {
01915         if (!newBody) {
01916           // in the worse case, the body will be solid, no linebreaks.
01917           // that will require us to insert a line break every LINE_BREAK_MAX bytes
01918           PRUint32 worstCaseLen = bodyLen+((bodyLen/LINE_BREAK_MAX)*NS_LINEBREAK_LEN)+1;
01919           newBody = (char *) PR_Calloc(1, worstCaseLen);
01920           if (!newBody) return NS_ERROR_OUT_OF_MEMORY;
01921           newBodyPos = newBody;
01922         }
01923 
01924         PL_strncpy(newBodyPos, body+lastPos, i - lastPos + 1);
01925         newBodyPos += i - lastPos + 1;
01926         PL_strncpy(newBodyPos, NS_LINEBREAK, NS_LINEBREAK_LEN);
01927         newBodyPos += NS_LINEBREAK_LEN;
01928 
01929         lastPos = i+1;
01930         charsSinceLineBreak = 0;
01931       }
01932     }
01933     else {
01934       // found a linebreak
01935       charsSinceLineBreak = 0;
01936     }
01937   }
01938 
01939   // if newBody is non-null is non-zero, we inserted a linebreak
01940   if (newBody) {
01941       // don't forget about part after the last linebreak we inserted
01942      PL_strncpy(newBodyPos, body+lastPos, bodyLen - lastPos);
01943 
01944      m_attachment1_body = newBody;
01945      m_attachment1_body_length = PL_strlen(newBody);  // not worstCaseLen
01946   }
01947   else {
01948      // body did not require any additional linebreaks, so just use it
01949      // body will not have any null bytes, so we can use PL_strdup
01950      m_attachment1_body = PL_strdup(body);
01951      if (!m_attachment1_body) {
01952       return NS_ERROR_OUT_OF_MEMORY;
01953      }
01954      m_attachment1_body_length = bodyLen;
01955   }
01956   return NS_OK;
01957 }
01958 
01959 //
01960 // This is the routine that does the magic of generating the body and the
01961 // attachments for the multipart/related email message.
01962 //
01963 typedef struct
01964 {
01965   nsIDOMNode    *node;
01966   char          *url;
01967 } domSaveStruct;
01968 
01969 nsresult
01970 nsMsgComposeAndSend::ProcessMultipartRelated(PRInt32 *aMailboxCount, PRInt32 *aNewsCount)
01971 {
01972   PRUint32                  multipartCount = GetMultipartRelatedCount();
01973   nsresult                  rv = NS_OK;
01974   PRUint32                  i; 
01975   PRInt32                   j = -1;
01976   PRUint32                  k;
01977   PRInt32                   duplicateOf;
01978   domSaveStruct             *domSaveArray = nsnull;
01979   
01980   // Sanity check to see if we should be here or not...if not, just return
01981   if (!mEditor)
01982     return NS_OK;
01983   
01984    if (!mEmbeddedObjectList) 
01985     return NS_ERROR_MIME_MPART_ATTACHMENT_ERROR;
01986   
01987   nsMsgAttachmentData   attachment;
01988   PRInt32               locCount = -1;
01989 
01990   if (multipartCount > 0)
01991   {
01992     domSaveArray = (domSaveStruct *)PR_MALLOC(sizeof(domSaveStruct) * multipartCount);
01993     if (!domSaveArray)
01994       return NS_ERROR_MIME_MPART_ATTACHMENT_ERROR;
01995     memset(domSaveArray, 0, sizeof(domSaveStruct) * multipartCount);
01996   }
01997 
01998   nsCOMPtr<nsIDOMNode> node;
01999   for (i = mPreloadedAttachmentCount; i < (mPreloadedAttachmentCount + multipartCount); i++)
02000   {
02001     // Reset this structure to null!
02002     memset(&attachment, 0, sizeof(nsMsgAttachmentData));
02003     
02004     // MUST set this to get placed in the correct part of the message
02005     m_attachments[i].mMHTMLPart = PR_TRUE;
02006     
02007     locCount++;
02008     m_attachments[i].mDeleteFile = PR_TRUE;
02009     m_attachments[i].m_done = PR_FALSE;
02010     m_attachments[i].SetMimeDeliveryState(this);
02011     
02012     // Ok, now we need to get the element in the array and do the magic
02013     // to process this element.
02014     //
02015     
02016     mEmbeddedObjectList->QueryElementAt(locCount, NS_GET_IID(nsIDOMNode), getter_AddRefs(node));
02017     if (!node)
02018       return NS_ERROR_MIME_MPART_ATTACHMENT_ERROR;
02019     
02020     PRBool acceptObject = PR_FALSE;
02021     rv = GetEmbeddedObjectInfo(node, &attachment, &acceptObject);
02022     NS_ENSURE_SUCCESS(rv, NS_ERROR_MIME_MPART_ATTACHMENT_ERROR);
02023 
02024     if (!acceptObject)
02025         continue;
02026    
02027     j++;
02028     domSaveArray[j].node = node;
02029     
02030     // check if we have alreay attached this object, don't need to attach it twice
02031     duplicateOf = -1;
02032     for (k = mPreloadedAttachmentCount; k < i; k++)
02033     {
02034       PRBool isEqual = PR_FALSE;
02035       (void)attachment.url->Equals(m_attachments[k].mURL, &isEqual);
02036       if (isEqual)
02037       {
02038         duplicateOf = k;
02039         break;
02040       }
02041     }
02042 
02043     if (duplicateOf == -1)
02044     {
02045       //
02046       // Now we have to get all of the interesting information from
02047       // the nsIDOMNode we have in hand...
02048       m_attachments[i].mURL = attachment.url;
02049   
02050       PR_FREEIF(m_attachments[i].m_override_type);
02051       m_attachments[i].m_override_type = PL_strdup (attachment.real_type);
02052       PR_FREEIF(m_attachments[i].m_override_encoding);
02053       m_attachments[i].m_override_encoding = PL_strdup (attachment.real_encoding);
02054       PR_FREEIF(m_attachments[i].m_desired_type);
02055       m_attachments[i].m_desired_type = PL_strdup (attachment.desired_type);
02056       PR_FREEIF(m_attachments[i].m_description);
02057       m_attachments[i].m_description = PL_strdup (attachment.description);
02058       PR_FREEIF(m_attachments[i].m_real_name);
02059       m_attachments[i].m_real_name = PL_strdup (attachment.real_name);
02060       PR_FREEIF(m_attachments[i].m_x_mac_type);
02061       m_attachments[i].m_x_mac_type = PL_strdup (attachment.x_mac_type);
02062       PR_FREEIF(m_attachments[i].m_x_mac_creator);
02063       m_attachments[i].m_x_mac_creator = PL_strdup (attachment.x_mac_creator);
02064   
02065       PR_FREEIF(m_attachments[i].m_charset);
02066       m_attachments[i].m_charset = PL_strdup (mCompFields->GetCharacterSet());
02067       PR_FREEIF(m_attachments[i].m_encoding);
02068       m_attachments[i].m_encoding = PL_strdup ("7bit");
02069   
02070       if (m_attachments[i].mURL)
02071         msg_pick_real_name(&m_attachments[i], nsnull, mCompFields->GetCharacterSet());
02072   
02073       //
02074       // Next, generate a content id for use with this part
02075       //    
02076       nsXPIDLCString email;
02077       mUserIdentity->GetEmail(getter_Copies(email));
02078       m_attachments[i].m_content_id = mime_gen_content_id(locCount+1, email.get());  
02079   
02080       if (!m_attachments[i].m_content_id)
02081         return NS_ERROR_OUT_OF_MEMORY;
02082   
02083       //
02084       // Start counting the attachments which are going to come from mail folders
02085       // and from NNTP servers.
02086       //
02087       if (m_attachments[i].mURL)
02088       {
02089         nsIURI *uri = m_attachments[i].mURL;
02090         PRBool match = PR_FALSE;
02091         if ((NS_SUCCEEDED(uri->SchemeIs("mailbox", &match)) && match) ||
02092            (NS_SUCCEEDED(uri->SchemeIs("imap", &match)) && match))
02093           (*aMailboxCount)++;
02094         else if ((NS_SUCCEEDED(uri->SchemeIs("news", &match)) && match) ||
02095                 (NS_SUCCEEDED(uri->SchemeIs("snews", &match)) && match))
02096           (*aNewsCount)++;
02097       }
02098     }
02099     
02100     // Ok, cleanup the temp structure...
02101     PR_Free(attachment.real_name);
02102     PR_Free(attachment.description);
02103     PR_Free(attachment.real_type);
02104     PR_Free(attachment.real_encoding);
02105     PR_Free(attachment.desired_type);
02106     PR_Free(attachment.x_mac_type);
02107     PR_Free(attachment.x_mac_creator); 
02108     
02109     //
02110     // Ok, while we are here, we should whack the DOM with the generated 
02111     // Content-ID for this object. This will be necessary for generating
02112     // the HTML we need.
02113     //
02114     nsString domURL;
02115     if (m_attachments[duplicateOf == -1 ? i : duplicateOf].m_content_id)  
02116     {
02117       nsString   newSpec(NS_LITERAL_STRING("cid:"));
02118       newSpec.AppendWithConversion(m_attachments[duplicateOf == -1 ? i : duplicateOf].m_content_id);
02119 
02120       // Now, we know the types of objects this node can be, so we will do
02121       // our query interface here and see what we come up with 
02122       nsCOMPtr<nsIDOMHTMLBodyElement>     body = (do_QueryInterface(domSaveArray[j].node));
02123       nsCOMPtr<nsIDOMHTMLImageElement>    image = (do_QueryInterface(domSaveArray[j].node));
02124       nsCOMPtr<nsIDOMHTMLLinkElement>     link = (do_QueryInterface(domSaveArray[j].node));
02125       nsCOMPtr<nsIDOMHTMLAnchorElement>   anchor = (do_QueryInterface(domSaveArray[j].node));
02126 
02127       if (anchor)
02128       {
02129         anchor->GetHref(domURL);
02130         anchor->SetHref(newSpec);
02131       }
02132       else if (link)
02133       {
02134         link->GetHref(domURL);
02135         link->SetHref(newSpec);
02136       }
02137       else if (image)
02138       {
02139         image->GetSrc(domURL);
02140         image->SetSrc(newSpec);
02141       }
02142       else if (body)
02143       {
02144         body->GetBackground(domURL);
02145         body->SetBackground(newSpec);
02146       }
02147 
02148       if (!domURL.IsEmpty())
02149         domSaveArray[j].url = ToNewCString(domURL);
02150     }
02151   }
02152   
02153   rv = GetBodyFromEditor();
02154 
02155   // 
02156   // Ok, now we need to un-whack the DOM or we have a screwed up document on 
02157   // Send failure.
02158   //
02159   for (i = 0; i < multipartCount; i++)
02160   {
02161     if ( (!domSaveArray[i].node) || (!domSaveArray[i].url) )
02162       continue;
02163 
02164     // Now, we know the types of objects this node can be, so we will do
02165     // our query interface here and see what we come up with 
02166     nsCOMPtr<nsIDOMHTMLBodyElement>     body = (do_QueryInterface(domSaveArray[i].node));
02167     nsCOMPtr<nsIDOMHTMLImageElement>    image = (do_QueryInterface(domSaveArray[i].node));
02168     nsCOMPtr<nsIDOMHTMLLinkElement>     link = (do_QueryInterface(domSaveArray[i].node));
02169     nsCOMPtr<nsIDOMHTMLAnchorElement>   anchor = (do_QueryInterface(domSaveArray[i].node));
02170 
02171       // STRING USE WARNING: hoisting the following conversion might save code-space, since it happens along every path
02172 
02173     if (anchor)
02174       anchor->SetHref(NS_ConvertASCIItoUCS2(domSaveArray[i].url));
02175     else if (link)
02176       link->SetHref(NS_ConvertASCIItoUCS2(domSaveArray[i].url));
02177     else if (image)
02178       image->SetSrc(NS_ConvertASCIItoUCS2(domSaveArray[i].url));
02179     else if (body)
02180       body->SetBackground(NS_ConvertASCIItoUCS2(domSaveArray[i].url));
02181 
02182     nsMemory::Free(domSaveArray[i].url);
02183   }
02184 
02185   PR_FREEIF(domSaveArray);
02186 
02187   //
02188   // Now, we have to create that first child node for the multipart
02189   // message that holds the body as well as the attachment handler
02190   // for this body part.
02191   //
02192   // If we ONLY have multipart objects, then we don't need the container
02193   // for the multipart section...
02194   //
02195   m_related_part = new nsMsgSendPart(this);
02196   if (!m_related_part)
02197     return NS_ERROR_OUT_OF_MEMORY;  
02198 
02199   m_related_part->SetMimeDeliveryState(this);
02200   m_related_part->SetType(MULTIPART_RELATED);
02201     
02202   // We are now going to use the m_related_part as a way to store the 
02203   // MHTML message for this email.
02204   //
02205   m_related_body_part = new nsMsgSendPart(this);
02206   if (!m_related_body_part)
02207     return NS_ERROR_OUT_OF_MEMORY;
02208   
02209   // Set the body contents...
02210   m_related_body_part->SetBuffer(m_attachment1_body);
02211   m_related_body_part->SetType(m_attachment1_type);
02212   
02213   m_related_part->AddChild(m_related_body_part);
02214 
02215   return rv;
02216 }
02217 
02218 nsresult
02219 nsMsgComposeAndSend::CountCompFieldAttachments()
02220 {
02221   //Reset the counters
02222   mCompFieldLocalAttachments = 0;
02223   mCompFieldRemoteAttachments = 0;
02224 
02225   //Get the attachments array
02226   nsCOMPtr<nsISupportsArray> attachmentsArray;
02227   mCompFields->GetAttachmentsArray(getter_AddRefs(attachmentsArray));
02228   if (!attachmentsArray)
02229     return NS_OK;
02230 
02231   PRUint32 i;
02232   PRUint32 attachmentCount = 0;
02233   attachmentsArray->Count(&attachmentCount);
02234   
02235   //Parse the attachments array
02236   nsCOMPtr<nsIMsgAttachment> element;
02237   nsXPIDLCString url;
02238   for (i = 0; i < attachmentCount; i ++)
02239   {
02240     attachmentsArray->QueryElementAt(i, NS_GET_IID(nsIMsgAttachment), getter_AddRefs(element));
02241     if (element)
02242     {
02243       element->GetUrl(getter_Copies(url));
02244       if (!url.IsEmpty())
02245     {
02246       // Check to see if this is a file URL, if so, don't retrieve
02247       // like a remote URL...
02248         if (nsMsgIsLocalFile(url.get()))
02249       {
02250         mCompFieldLocalAttachments++;
02251 #if defined(DEBUG_ducarroz)
02252           printf("Counting LOCAL attachment %d: %s\n", mCompFieldLocalAttachments, url.get());
02253 #endif
02254       }
02255       else    // This is a remote URL...
02256       {
02257         mCompFieldRemoteAttachments++;
02258 #if defined(DEBUG_ducarroz)
02259           printf("Counting REMOTE attachment %d: %s\n", mCompFieldRemoteAttachments, url.get());
02260 #endif
02261       }
02262     }
02263     }
02264   }
02265 
02266   return NS_OK;
02267 }
02268 
02269 // 
02270 // Since we are at the head of the list, we start from ZERO.
02271 //
02272 nsresult
02273 nsMsgComposeAndSend::AddCompFieldLocalAttachments()
02274 {
02275   // If none, just return...
02276   if (mCompFieldLocalAttachments <= 0)
02277     return NS_OK;
02278 
02279   //Get the attachments array
02280   nsCOMPtr<nsISupportsArray> attachmentsArray;
02281   mCompFields->GetAttachmentsArray(getter_AddRefs(attachmentsArray));
02282   if (!attachmentsArray)
02283     return NS_OK;
02284 
02285   PRUint32 i;
02286   PRUint32  newLoc = 0;
02287   PRUint32 attachmentCount = 0;
02288   attachmentsArray->Count(&attachmentCount);
02289   
02290   //Parse the attachments array
02291   nsCOMPtr<nsIMsgAttachment> element;
02292   nsXPIDLCString url;
02293   for (i = 0; i < attachmentCount; i ++)
02294   {
02295     attachmentsArray->QueryElementAt(i, NS_GET_IID(nsIMsgAttachment), getter_AddRefs(element));
02296     if (element)
02297     {
02298       element->GetUrl(getter_Copies(url));
02299       if (!url.IsEmpty())
02300       {
02301       // Just look for local file:// attachments and do the right thing.
02302       if (nsMsgIsLocalFile(url.get()))
02303       {
02304 #if defined(DEBUG_ducarroz)
02305         printf("Adding LOCAL attachment %d: %s\n", newLoc, url.get());
02306 #endif
02307         //
02308         // Now we have to setup the m_attachments entry for the file://
02309         // URL that is passed in...
02310         //
02311         m_attachments[newLoc].mDeleteFile = PR_FALSE;
02312 
02313         nsMsgNewURL(getter_AddRefs(m_attachments[newLoc].mURL), url.get());
02314 
02315         if (m_attachments[newLoc].mFileSpec)
02316         {
02317           if (m_attachments[newLoc].mDeleteFile)
02318             m_attachments[newLoc].mFileSpec->Delete(PR_FALSE);
02319           delete (m_attachments[newLoc].mFileSpec);
02320           m_attachments[newLoc].mFileSpec =nsnull;
02321         }
02322         if (!NS_IsNativeUTF8())
02323         {
02324           // XXX : this is really hackish. 
02325           // File URL is now in UTF-8 (bug 278161), but nsFileSpec still uses 
02326           // the native encoding.
02327           NS_UnescapeURL(url);
02328           NS_ASSERTION(IsUTF8(url), "unescaped url must be in UTF-8");
02329           nsCAutoString nativeUrl;
02330           NS_CopyUnicodeToNative(NS_ConvertUTF8toUTF16(url), nativeUrl);
02331           url.Truncate(); // NS_EscapeURL will append to |url|
02332           NS_EscapeURL(nativeUrl.get(), -1, esc_FilePath | esc_AlwaysCopy,
02333                        url);
02334         }
02335         m_attachments[newLoc].mFileSpec = new nsFileSpec(nsFileURL(url.get()));
02336         m_attachments[newLoc].mDeleteFile = PR_FALSE;
02337         if (m_attachments[newLoc].mURL)
02338         {
02339           nsAutoString proposedName;
02340           element->GetName(proposedName);
02341           msg_pick_real_name(&m_attachments[newLoc], proposedName.get(), mCompFields->GetCharacterSet());
02342         }
02343 
02344         // Now, most importantly, we need to figure out what the content type is for
02345         // this attachment...If we can't, then just make it application/octet-stream
02346         
02347 #ifdef MAC_OSX
02348         //Mac always need to snarf the file to figure out how to send it, maybe we need to use apple double...
02349         //  unless caller has already set the content type, in which case, trust them.
02350         PRBool mustSnarfAttachment = PR_TRUE;
02351 #else
02352         PRBool mustSnarfAttachment = PR_FALSE;
02353 #endif        
02354         PR_FREEIF(m_attachments[newLoc].m_type);
02355         element->GetContentType(&m_attachments[newLoc].m_type);
02356         if (!m_attachments[newLoc].m_type || !(*m_attachments[newLoc].m_type))
02357         {
02358           nsresult  rv = NS_OK;
02359           nsCOMPtr<nsIMIMEService> mimeFinder (do_GetService(NS_MIMESERVICE_CONTRACTID, &rv));
02360           if (NS_SUCCEEDED(rv) && mimeFinder) 
02361           {
02362             nsCOMPtr<nsIURL> fileUrl(do_CreateInstance(NS_STANDARDURL_CONTRACTID));
02363             if (fileUrl)
02364             {
02365               nsCAutoString fileExt;
02366               //First try using the real file name
02367               rv = fileUrl->SetFileName(nsDependentCString(m_attachments[newLoc].m_real_name));
02368               if (NS_SUCCEEDED(rv))
02369               {
02370                 rv = fileUrl->GetFileExtension(fileExt);
02371                 if (NS_SUCCEEDED(rv) && !fileExt.IsEmpty()) {
02372                   nsCAutoString type;
02373                   mimeFinder->GetTypeFromExtension(fileExt, type);
02374 #if !defined(XP_MAC) && !defined(XP_MACOSX)
02375                   if (!type.Equals("multipart/appledouble"))  // can't do apple double on non-macs
02376 #endif
02377                   m_attachments[newLoc].m_type = ToNewCString(type);
02378                 }
02379               }
02380 
02381               //Then try using the url if we still haven't figured out the content type
02382               if ((!m_attachments[newLoc].m_type) ||  (!*m_attachments[newLoc].m_type))
02383               {
02384                 rv = fileUrl->SetSpec(url);
02385                 if (NS_SUCCEEDED(rv))
02386                 {
02387                   rv = fileUrl->GetFileExtension(fileExt);
02388                   if (NS_SUCCEEDED(rv) && !fileExt.IsEmpty()) {
02389                     nsCAutoString type;
02390                     mimeFinder->GetTypeFromExtension(fileExt, type);
02391 #if !defined(XP_MAC) && !defined(XP_MACOSX)
02392                   if (!type.Equals("multipart/appledouble"))  // can't do apple double on non-macs
02393 #endif
02394                     m_attachments[newLoc].m_type = ToNewCString(type);
02395                   // rtf and vcs files may look like text to sniffers,
02396                   // but they're not human readable.
02397                   if (type.IsEmpty() && !fileExt.IsEmpty() &&
02398                        (fileExt.LowerCaseEqualsLiteral("rtf") || fileExt.LowerCaseEqualsLiteral("vcs")))
02399                     m_attachments[newLoc].m_type = PL_strdup(APPLICATION_OCTET_STREAM);
02400                   }
02401                 }
02402               }
02403             }
02404           }
02405         }
02406         else
02407         {
02408           element->GetContentTypeParam(&m_attachments[newLoc].m_type_param);
02409           mustSnarfAttachment = PR_FALSE;
02410         }
02411 
02412         //We need to snarf the file to figure out how to send it only if we don't have a content type...
02413         if (mustSnarfAttachment || (!m_attachments[newLoc].m_type) || (!*m_attachments[newLoc].m_type))
02414         {
02415           m_attachments[newLoc].m_done = PR_FALSE;
02416           m_attachments[newLoc].SetMimeDeliveryState(this);
02417         }
02418         else
02419         {
02420           m_attachments[newLoc].m_done = PR_TRUE;
02421           m_attachments[newLoc].SetMimeDeliveryState(nsnull);
02422         }
02423         // For local files, if they are HTML docs and we don't have a charset, we should
02424         // sniff the file and see if we can figure it out.
02425         if ( (m_attachments[newLoc].m_type) &&  (*m_attachments[newLoc].m_type) ) 
02426         {
02427           if (PL_strcasecmp(m_attachments[newLoc].m_type, TEXT_HTML) == 0)
02428           {
02429             char *tmpCharset = (char *)nsMsgI18NParseMetaCharset(m_attachments[newLoc].mFileSpec);
02430             if (tmpCharset[0] != '\0')
02431             {
02432               PR_FREEIF(m_attachments[newLoc].m_charset);
02433               m_attachments[newLoc].m_charset = PL_strdup(tmpCharset);
02434             }
02435           }
02436         }
02437 
02438         PR_FREEIF(m_attachments[newLoc].m_x_mac_type);
02439         element->GetMacType(&m_attachments[newLoc].m_x_mac_type);
02440         PR_FREEIF(m_attachments[newLoc].m_x_mac_creator);
02441         element->GetMacCreator(&m_attachments[newLoc].m_x_mac_creator);
02442 
02443         ++newLoc;
02444       }
02445     }
02446   }
02447   }
02448   return NS_OK;
02449 }
02450 
02451 nsresult
02452 nsMsgComposeAndSend::AddCompFieldRemoteAttachments(PRUint32   aStartLocation,
02453                                                    PRInt32    *aMailboxCount, 
02454                                                    PRInt32    *aNewsCount)
02455 {
02456   // If none, just return...
02457   if (mCompFieldRemoteAttachments <= 0)
02458     return NS_OK;
02459 
02460   //Get the attachments array
02461   nsCOMPtr<nsISupportsArray> attachmentsArray;
02462   mCompFields->GetAttachmentsArray(getter_AddRefs(attachmentsArray));
02463   if (!attachmentsArray)
02464     return NS_OK;
02465 
02466   PRUint32 i;
02467   PRUint32  newLoc = aStartLocation;
02468   PRUint32 attachmentCount = 0;
02469   attachmentsArray->Count(&attachmentCount);
02470 
02471   //Parse the attachments array
02472   nsCOMPtr<nsIMsgAttachment> element;
02473   nsXPIDLCString url;
02474   for (i = 0; i < attachmentCount; i ++)
02475   {
02476     attachmentsArray->QueryElementAt(i, NS_GET_IID(nsIMsgAttachment), getter_AddRefs(element));
02477     if (element)
02478     {
02479       element->GetUrl(getter_Copies(url));
02480       if (!url.IsEmpty())
02481       {
02482         // Just look for files that are NOT local file attachments and do 
02483         // the right thing.
02484         if (! nsMsgIsLocalFile(url.get()))
02485         {
02486 #if defined(DEBUG_ducarroz)
02487           printf("Adding REMOTE attachment %d: %s\n", newLoc, url.get());
02488 #endif
02489           PRBool isAMessageAttachment = !PL_strncasecmp(url.get(), "mailbox-message://", 18) ||
02490               !PL_strncasecmp(url.get(), "imap-message://", 15) ||
02491               !PL_strncasecmp(url.get(), "news-message://", 15);
02492 
02493           m_attachments[newLoc].mDeleteFile = PR_TRUE;
02494           m_attachments[newLoc].m_done = PR_FALSE;
02495           m_attachments[newLoc].SetMimeDeliveryState(this);
02496 
02497           if (!isAMessageAttachment)
02498             nsMsgNewURL(getter_AddRefs(m_attachments[newLoc].mURL), url.get());
02499 
02500           PR_FREEIF(m_attachments[newLoc].m_encoding);
02501           m_attachments[newLoc].m_encoding = PL_strdup ("7bit");
02502 
02503           PR_FREEIF(m_attachments[newLoc].m_x_mac_type);
02504           element->GetMacType(&m_attachments[newLoc].m_x_mac_type);
02505           PR_FREEIF(m_attachments[newLoc].m_x_mac_creator);
02506           element->GetMacCreator(&m_attachments[newLoc].m_x_mac_creator);
02507 
02508           /* Count up attachments which are going to come from mail folders
02509              and from NNTP servers. */
02510           PRBool do_add_attachment = PR_FALSE;
02511           if (isAMessageAttachment)
02512           {
02513             do_add_attachment = PR_TRUE;
02514             if (!PL_strncasecmp(url.get(), "news-message://", 15))
02515               (*aNewsCount)++;
02516             else
02517               (*aMailboxCount)++;              
02518 
02519             m_attachments[newLoc].m_uri = PL_strdup(url.get());
02520             m_attachments[newLoc].mURL = nsnull;
02521           }
02522           else
02523             do_add_attachment = (nsnull != m_attachments[newLoc].mURL);
02524 
02525           if (do_add_attachment)
02526           {
02527             nsAutoString proposedName;
02528             element->GetName(proposedName);
02529             msg_pick_real_name(&m_attachments[newLoc], proposedName.get(), mCompFields->GetCharacterSet());
02530             ++newLoc;
02531           }
02532         }
02533       }
02534     }
02535   }
02536   return NS_OK;
02537 }
02538 
02539 nsresult 
02540 nsMsgComposeAndSend::HackAttachments(const nsMsgAttachmentData *attachments,
02541                                      const nsMsgAttachedFile *preloaded_attachments)
02542 { 
02543   //
02544   // First, count the total number of attachments we are going to process
02545   // for this operation! This is a little more complicated than you might
02546   // think because we have a few ways to specify attachments. Via the nsMsgAttachmentData
02547   // as well as the composition fields.
02548   //
02549   CountCompFieldAttachments();
02550 
02551   // Count the preloaded attachments!
02552   mPreloadedAttachmentCount = 0;
02553 
02554   // For now, manually add the local attachments in the comp field!
02555   mPreloadedAttachmentCount += mCompFieldLocalAttachments;
02556 
02557   if (preloaded_attachments && preloaded_attachments[0].orig_url) 
02558   {
02559     while (preloaded_attachments[mPreloadedAttachmentCount].orig_url)
02560       mPreloadedAttachmentCount++;
02561   }
02562 
02563   // Count the attachments we have to go retrieve! Keep in mind, that these
02564   // will be APPENDED to the current list of URL's that we have gathered if
02565   // this is a multpart/related send operation
02566   mRemoteAttachmentCount = GetMultipartRelatedCount();
02567 
02568   // For now, manually add the remote attachments in the comp field!
02569   mRemoteAttachmentCount += mCompFieldRemoteAttachments;
02570 
02571   PRInt32     tCount = 0;
02572   if (attachments && attachments[0].url) 
02573   {
02574     while (attachments[tCount].url)
02575     {
02576       mRemoteAttachmentCount++;
02577       tCount++;
02578     }
02579   }
02580 
02581   m_attachment_count = mPreloadedAttachmentCount + mRemoteAttachmentCount;
02582 
02583   // Now create the array of attachment handlers...
02584   m_attachments = (nsMsgAttachmentHandler *) new nsMsgAttachmentHandler[m_attachment_count];
02585   if (! m_attachments)
02586     return NS_ERROR_OUT_OF_MEMORY;
02587 
02588   // clear this new memory...
02589   memset(m_attachments, 0, (sizeof(nsMsgAttachmentHandler) * m_attachment_count)); 
02590   PRUint32     i;    // counter for location in attachment array...
02591 
02592   //
02593   // First, we need to attach the files that are defined in the comp fields...
02594   if (NS_FAILED(AddCompFieldLocalAttachments()))
02595     return NS_ERROR_INVALID_ARG;
02596 
02597   // Now handle the preloaded attachments...
02598   if (preloaded_attachments && preloaded_attachments[0].orig_url) 
02599   {
02600     // These are attachments which have already been downloaded to tmp files.
02601     // We merely need to point the internal attachment data at those tmp
02602     // files.
02603     m_pre_snarfed_attachments_p = PR_TRUE;
02604 
02605     for (i = mCompFieldLocalAttachments; i < mPreloadedAttachmentCount; i++) 
02606     {
02607       /* These attachments are already "snarfed". */
02608       m_attachments[i].mDeleteFile = PR_FALSE;
02609       m_attachments[i].SetMimeDeliveryState(nsnull);
02610       m_attachments[i].m_done = PR_TRUE;
02611       NS_ASSERTION (preloaded_attachments[i].orig_url, "null url");
02612 
02613       m_attachments[i].mURL = preloaded_attachments[i].orig_url;
02614 
02615       PR_FREEIF(m_attachments[i].m_type);
02616       m_attachments[i].m_type = PL_strdup (preloaded_attachments[i].type);
02617 
02618       // Set it to the compose fields for a default...
02619       PR_FREEIF(m_attachments[i].m_charset);
02620       m_attachments[i].m_charset = PL_strdup (mCompFields->GetCharacterSet());
02621 
02622       // If we still don't have a content type, we should really try sniff one out!
02623       if ((!m_attachments[i].m_type) || (!*m_attachments[i].m_type))
02624       {
02625         m_attachments[i].PickEncoding(mCompFields->GetCharacterSet(), this);
02626       }
02627 
02628       // For local files, if they are HTML docs and we don't have a charset, we should
02629       // sniff the file and see if we can figure it out.
02630       if ( (m_attachments[i].m_type) &&  (*m_attachments[i].m_type) ) 
02631       {
02632         if ( (PL_strcasecmp(m_attachments[i].m_type, TEXT_HTML) == 0) && (preloaded_attachments[i].file_spec) )
02633         {
02634           char *tmpCharset = (char *)nsMsgI18NParseMetaCharset(preloaded_attachments[i].file_spec);
02635           if (tmpCharset[0] != '\0')
02636           {
02637             PR_FREEIF(m_attachments[i].m_charset);
02638             m_attachments[i].m_charset = PL_strdup(tmpCharset);
02639           }
02640         }
02641       }
02642 
02643       PR_FREEIF(m_attachments[i].m_description);
02644       m_attachments[i].m_description = PL_strdup (preloaded_attachments[i].description);
02645       PR_FREEIF(m_attachments[i].m_real_name);
02646       m_attachments[i].m_real_name = PL_strdup (preloaded_attachments[i].real_name);
02647       PR_FREEIF(m_attachments[i].m_x_mac_type);
02648       m_attachments[i].m_x_mac_type = PL_strdup (preloaded_attachments[i].x_mac_type);
02649       PR_FREEIF(m_attachments[i].m_x_mac_creator);
02650       m_attachments[i].m_x_mac_creator = PL_strdup (preloaded_attachments[i].x_mac_creator);
02651       PR_FREEIF(m_attachments[i].m_encoding);
02652       m_attachments[i].m_encoding = PL_strdup (preloaded_attachments[i].encoding);
02653 
02654       if (m_attachments[i].mFileSpec)
02655       {
02656         if (m_attachments[i].mDeleteFile)
02657           m_attachments[i].mFileSpec->Delete(PR_FALSE);
02658         delete (m_attachments[i].mFileSpec);
02659         m_attachments[i].mFileSpec=nsnull;
02660       }
02661       m_attachments[i].mFileSpec = new nsFileSpec(*(preloaded_attachments[i].file_spec));
02662 
02663       m_attachments[i].m_size = preloaded_attachments[i].size;
02664       m_attachments[i].m_unprintable_count = preloaded_attachments[i].unprintable_count;
02665       m_attachments[i].m_highbit_count = preloaded_attachments[i].highbit_count;
02666       m_attachments[i].m_ctl_count = preloaded_attachments[i].ctl_count;
02667       m_attachments[i].m_null_count = preloaded_attachments[i].null_count;
02668       m_attachments[i].m_max_column = preloaded_attachments[i].max_line_length;
02669 
02670       /* If the attachment has an encoding, and it's not one of
02671       the "null" encodings, then keep it. */
02672       if (m_attachments[i].m_encoding &&
02673           PL_strcasecmp (m_attachments[i].m_encoding, ENCODING_7BIT) &&
02674           PL_strcasecmp (m_attachments[i].m_encoding, ENCODING_8BIT) &&
02675           PL_strcasecmp (m_attachments[i].m_encoding, ENCODING_BINARY))
02676         m_attachments[i].m_already_encoded_p = PR_TRUE;
02677 
02678             if (m_attachments[i].mURL)
02679         msg_pick_real_name(&m_attachments[i], nsnull, mCompFields->GetCharacterSet());
02680     }
02681   }
02682 
02683   // First, handle the multipart related attachments if any...
02684   //
02685   PRInt32 mailbox_count = 0, news_count = 0;
02686   PRInt32 multipartRelatedCount = GetMultipartRelatedCount();
02687 
02688   if (multipartRelatedCount > 0)
02689   {
02690     nsresult rv = ProcessMultipartRelated(&mailbox_count, &news_count);
02691     if (NS_FAILED(rv))
02692     {
02693       // The destructor will take care of the m_attachment array
02694       return rv;
02695     }
02696   }
02697 
02698   //
02699   // Now add the comp field remote attachments...
02700   //
02701   if (NS_FAILED( AddCompFieldRemoteAttachments( (mPreloadedAttachmentCount + multipartRelatedCount), 
02702                                                  &mailbox_count, &news_count) ))
02703     return NS_ERROR_INVALID_ARG;
02704 
02705   //
02706   // Now deal remote attachments and attach multipart/related attachments (url's and such..)
02707   // first!
02708   //
02709   if (attachments && attachments[0].url) 
02710   {
02711     PRInt32     locCount = -1;
02712 
02713     for (i = (mPreloadedAttachmentCount + GetMultipartRelatedCount() + mCompFieldRemoteAttachments); i < m_attachment_count; i++) 
02714     {
02715       locCount++;
02716       m_attachments[i].mDeleteFile = PR_TRUE;
02717       m_attachments[i].m_done = PR_FALSE;
02718       m_attachments[i].SetMimeDeliveryState(this);
02719       NS_ASSERTION (attachments[locCount].url, "null url");
02720 
02721       m_attachments[i].mURL = attachments[locCount].url;
02722 
02723       PR_FREEIF(m_attachments[i].m_override_type);
02724       m_attachments[i].m_override_type = PL_strdup (attachments[locCount].real_type);
02725       PR_FREEIF(m_attachments[i].m_charset);
02726       m_attachments[i].m_charset = PL_strdup (mCompFields->GetCharacterSet());
02727       PR_FREEIF(m_attachments[i].m_override_encoding);
02728       m_attachments[i].m_override_encoding = PL_strdup (attachments[locCount].real_encoding);
02729       PR_FREEIF(m_attachments[i].m_desired_type);
02730       m_attachments[i].m_desired_type = PL_strdup (attachments[locCount].desired_type);
02731       PR_FREEIF(m_attachments[i].m_description);
02732       m_attachments[i].m_description = PL_strdup (attachments[locCount].description);
02733       PR_FREEIF(m_attachments[i].m_real_name);
02734       m_attachments[i].m_real_name = PL_strdup (attachments[locCount].real_name);
02735       PR_FREEIF(m_attachments[i].m_x_mac_type);
02736       m_attachments[i].m_x_mac_type = PL_strdup (attachments[locCount].x_mac_type);
02737       PR_FREEIF(m_attachments[i].m_x_mac_creator);
02738       m_attachments[i].m_x_mac_creator = PL_strdup (attachments[locCount].x_mac_creator);
02739       PR_FREEIF(m_attachments[i].m_encoding);
02740       m_attachments[i].m_encoding = PL_strdup ("7bit");
02741 
02742       // real name is set in the case of vcard so don't change it.  XXX STILL NEEDED?
02743       // m_attachments[i].m_real_name = 0;
02744 
02745       /* Count up attachments which are going to come from mail folders
02746       and from NNTP servers. */
02747          if (m_attachments[i].mURL)
02748          {
02749               nsIURI *uri = m_attachments[i].mURL;
02750               PRBool match = PR_FALSE;
02751               if ((NS_SUCCEEDED(uri->SchemeIs("mailbox", &match)) && match) ||
02752                      (NS_SUCCEEDED(uri->SchemeIs("imap", &match)) && match))
02753                 mailbox_count++;
02754               else if ((NS_SUCCEEDED(uri->SchemeIs("news", &match)) && match) ||
02755                           (NS_SUCCEEDED(uri->SchemeIs("snews", &match)) && match))
02756              news_count++;
02757 
02758            if (uri)
02759              msg_pick_real_name(&m_attachments[i], nsnull, mCompFields->GetCharacterSet());
02760       }
02761     }
02762   }
02763 
02764   PRBool needToCallGatherMimeAttachments = PR_TRUE;
02765 
02766   if (m_attachment_count > 0)
02767   {
02768     // If there is more than one mailbox URL, or more than one NNTP url,
02769     // do the load in serial rather than parallel, for efficiency.
02770     if (mailbox_count > 1 || news_count > 1)
02771       m_be_synchronous_p = PR_TRUE;
02772   
02773     m_attachment_pending_count = m_attachment_count;
02774   
02775     // Start the URL attachments loading (eventually, an exit routine will
02776     // call the done_callback).
02777   
02778     for (i = 0; i < m_attachment_count; i++) 
02779     {
02780       if (m_attachments[i].m_done)
02781       {
02782         m_attachment_pending_count--;
02783         continue;
02784       }
02785     
02786       //
02787       //  IF we get here and the URL is NULL, just dec the pending count and move on!!!
02788       //
02789       if ( (!m_attachments[i].mURL) && (!m_attachments[i].m_uri) )
02790       {
02791         m_attachments[i].m_bogus_attachment = PR_TRUE;
02792         m_attachments[i].m_done = PR_TRUE;
02793         m_attachments[i].SetMimeDeliveryState(nsnull);
02794         m_attachment_pending_count--;
02795         continue;
02796       }
02797 
02798       //
02799       // This only returns a failure code if NET_GetURL was not called
02800       // (and thus no exit routine was or will be called.) 
02801       //
02802 
02803       // Display some feedback to user...
02804       PRUnichar     *printfString = nsnull;
02805 
02806       nsXPIDLString msg; 
02807       mComposeBundle->GetStringByID(NS_MSG_GATHERING_ATTACHMENT, getter_Copies(msg));
02808 
02809       if (m_attachments[i].m_real_name)
02810         printfString = nsTextFormatter::smprintf(msg, m_attachments[i].m_real_name);
02811       else
02812         printfString = nsTextFormatter::smprintf(msg, "");
02813 
02814       if (printfString)
02815       {
02816         SetStatusMessage(printfString); 
02817         PR_Free(printfString);  
02818       }
02819       
02820       /* As SnarfAttachment will call GatherMimeAttachments when it will be done (this is an async process),
02821          we need to avoid to call it ourself.
02822       */ 
02823       needToCallGatherMimeAttachments = PR_FALSE;
02824 
02825       nsresult status = m_attachments[i].SnarfAttachment(mCompFields);
02826       if (NS_FAILED(status))
02827       {
02828         nsXPIDLString errorMsg; 
02829         nsAutoString attachmentFileName;
02830         nsresult rv = ConvertToUnicode(nsMsgI18NFileSystemCharset(), m_attachments[i].m_real_name, attachmentFileName);
02831         if (NS_SUCCEEDED(rv))
02832         {
02833           nsCOMPtr<nsIStringBundle> bundle;
02834           const PRUnichar *params[] = { attachmentFileName.get() };
02835           rv = mComposeBundle->GetBundle(getter_AddRefs(bundle));
02836           if (NS_SUCCEEDED(rv))
02837           {
02838             bundle->FormatStringFromID(NS_ERROR_GET_CODE(NS_MSG_ERROR_ATTACHING_FILE), params, 1, getter_Copies(errorMsg));
02839             mSendReport->SetMessage(nsIMsgSendReport::process_Current, errorMsg, PR_FALSE);
02840           }
02841           mSendReport->SetError(nsIMsgSendReport::process_Current, NS_MSG_ERROR_ATTACHING_FILE /* status */, PR_FALSE);
02842         }
02843         return NS_MSG_ERROR_ATTACHING_FILE;
02844       }
02845       if (m_be_synchronous_p)
02846         break;
02847     }
02848   }
02849 
02850   // If no attachments - finish now (this will call the done_callback).
02851   if (needToCallGatherMimeAttachments)
02852     return GatherMimeAttachments();
02853 
02854   return NS_OK;
02855 }
02856 
02857 int nsMsgComposeAndSend::SetMimeHeader(nsMsgCompFields::MsgHeaderID header, const char *value)
02858 {
02859   char * dupHeader = nsnull;
02860   PRInt32 ret = NS_ERROR_OUT_OF_MEMORY;
02861 
02862   switch (header)
02863   {
02864     case nsMsgCompFields::MSG_FROM_HEADER_ID :
02865     case nsMsgCompFields::MSG_TO_HEADER_ID :
02866     case nsMsgCompFields::MSG_REPLY_TO_HEADER_ID :
02867     case nsMsgCompFields::MSG_CC_HEADER_ID :
02868     case nsMsgCompFields::MSG_BCC_HEADER_ID :
02869       dupHeader = mime_fix_addr_header(value);
02870       break;
02871     
02872     case nsMsgCompFields::MSG_NEWSGROUPS_HEADER_ID :
02873     case nsMsgCompFields::MSG_FOLLOWUP_TO_HEADER_ID :
02874       dupHeader = mime_fix_news_header(value);
02875       break;
02876     
02877     case nsMsgCompFields::MSG_FCC_HEADER_ID :
02878     case nsMsgCompFields::MSG_ORGANIZATION_HEADER_ID :
02879     case nsMsgCompFields::MSG_SUBJECT_HEADER_ID :
02880     case nsMsgCompFields::MSG_REFERENCES_HEADER_ID :
02881     case nsMsgCompFields::MSG_X_TEMPLATE_HEADER_ID :
02882     case nsMsgCompFields::MSG_ATTACHMENTS_HEADER_ID :
02883       dupHeader = mime_fix_header(value);
02884       break;
02885     
02886     default : NS_ASSERTION(PR_FALSE, "invalid header"); // unhandled header - bad boy.
02887   }
02888 
02889   if (dupHeader) 
02890   {
02891     ret = mCompFields->SetAsciiHeader(header, dupHeader);
02892     PR_Free(dupHeader);
02893   }
02894   return ret;
02895 }
02896 
02897 nsresult
02898 nsMsgComposeAndSend::InitCompositionFields(nsMsgCompFields *fields,
02899                                            const nsACString &aOriginalMsgURI,
02900                                            MSG_ComposeType aType)
02901 {
02902   nsresult        rv = NS_OK;
02903   const char      *pStr = nsnull;
02904   nsMsgCompFields *tPtr = new nsMsgCompFields();
02905 
02906   if (!tPtr)
02907     return NS_ERROR_OUT_OF_MEMORY;
02908 
02909   mCompFields = do_QueryInterface( tPtr );
02910   if (!mCompFields)
02911     return NS_ERROR_OUT_OF_MEMORY;
02912 
02913   const char *cset = fields->GetCharacterSet();
02914   // Make sure charset is sane...
02915   if (!cset || !*cset)
02916   {
02917     mCompFields->SetCharacterSet("us-ascii");
02918   }
02919   else
02920   {
02921     mCompFields->SetCharacterSet(fields->GetCharacterSet());
02922   }
02923 
02924   pStr = fields->GetMessageId();
02925   if (pStr)
02926   {
02927     mCompFields->SetMessageId((char *) pStr);
02928     /* Don't bother checking for out of memory; if it fails, then we'll just
02929        let the server generate the message-id, and suffer with the
02930        possibility of duplicate messages.*/
02931   }
02932 
02933   pStr = fields->GetNewspostUrl();
02934   if (pStr && *pStr) 
02935   {
02936     mCompFields->SetNewspostUrl((char *)pStr);
02937   }
02938 
02939   // Now, we will look for a URI defined as the default FCC pref. If this is set,
02940   // then SetFcc will use this value. The FCC field is a URI for the server that 
02941   // will hold the "Sent" folder...the 
02942   //
02943   // First, look at what was passed in via the "fields" structure...if that was
02944   // set then use it, otherwise, fall back to what is set in the prefs...
02945   //
02946   // But even before that, pay attention to the new OVERRIDE pref that will cancel
02947   // any and all copy operations!
02948   //
02949   PRBool    doFcc = PR_TRUE;
02950   rv = mUserIdentity->GetDoFcc(&doFcc);
02951   if (!doFcc)
02952   {
02953     // If the identity pref "fcc" is set to false, then we will not do
02954     // any FCC operation!
02955     mCompFields->SetFcc("");
02956   }
02957   else
02958   {
02959     PRBool useDefaultFCC = PR_TRUE;
02960     const char *fieldsFCC = fields->GetFcc();
02961     if (fieldsFCC && *fieldsFCC)
02962     {
02963       if (PL_strcasecmp(fieldsFCC, "nocopy://") == 0)
02964       {
02965         useDefaultFCC = PR_FALSE;
02966         mCompFields->SetFcc("");
02967       }
02968       else
02969       {
02970         nsCOMPtr<nsIMsgFolder> folder;
02971         (void)GetExistingFolder(fieldsFCC, getter_AddRefs(folder));
02972         if (folder)
02973         {
02974           useDefaultFCC = PR_FALSE;
02975           SetMimeHeader(nsMsgCompFields::MSG_FCC_HEADER_ID, fieldsFCC); 
02976         }
02977       }
02978     }
02979     
02980     // We use default FCC setting if it's not set or was set to an invalid folder.
02981     if (useDefaultFCC)
02982     {
02983       // Only check whether the user wants the message in the original message
02984       // folder if the msgcomptype is some kind of a reply.
02985       if (!aOriginalMsgURI.IsEmpty() && (
02986             aType == nsIMsgCompType::Reply || 
02987             aType == nsIMsgCompType::ReplyAll ||
02988             aType == nsIMsgCompType::ReplyToGroup ||
02989             aType == nsIMsgCompType::ReplyToSender ||
02990             aType == nsIMsgCompType::ReplyToSenderAndGroup ||
02991             aType == nsIMsgCompType::ReplyWithTemplate )
02992          )
02993       {
02994         nsCOMPtr <nsIMsgAccountManager> accountManager =
02995             do_GetService(NS_MSGACCOUNTMANAGER_CONTRACTID, &rv); 
02996         if (NS_SUCCEEDED(rv))
02997         {
02998           nsCOMPtr <nsIMsgDBHdr> msgHdr;
02999           rv = GetMsgDBHdrFromURI(PromiseFlatCString(aOriginalMsgURI).get(),
03000                                   getter_AddRefs(msgHdr));
03001           if (NS_SUCCEEDED(rv))
03002           {
03003             nsCOMPtr <nsIMsgFolder> folder;
03004             msgHdr->GetFolder(getter_AddRefs(folder));
03005             if (NS_SUCCEEDED(rv))
03006             {
03007               PRBool canFileMessages;
03008               rv = folder->GetCanFileMessages(&canFileMessages);
03009               if (NS_SUCCEEDED(rv) && canFileMessages)
03010               {
03011                 nsCOMPtr <nsIMsgIncomingServer> incomingServer;
03012                 rv = folder->GetServer(getter_AddRefs(incomingServer));
03013                 if (NS_SUCCEEDED(rv))
03014                 {
03015                   nsXPIDLCString incomingServerType;
03016                   rv = incomingServer->GetCharValue("type",
03017                            getter_Copies(incomingServerType));
03018                   // Exclude RSS accounts, as they falsely report
03019                   // 'canFileMessages' = true
03020                   if (NS_SUCCEEDED(rv) && !incomingServerType.Equals("rss"))
03021                   {
03022                     PRBool fccReplyFollowsParent;
03023                     rv = mUserIdentity->GetFccReplyFollowsParent(
03024                              &fccReplyFollowsParent);
03025                     if (NS_SUCCEEDED(rv) && fccReplyFollowsParent)
03026                     {
03027                       nsXPIDLCString folderURI;
03028                       rv = folder->GetURI(getter_Copies(folderURI));
03029                       if (NS_SUCCEEDED(rv))
03030                       {
03031                         mCompFields->SetFcc(folderURI.get());
03032                         useDefaultFCC = PR_FALSE;
03033                       }
03034                     }
03035                   }
03036                 }
03037               }
03038             }
03039           }
03040         }
03041       }
03042 
03043       if (useDefaultFCC)
03044       {
03045         char *uri = GetFolderURIFromUserPrefs(nsMsgDeliverNow, mUserIdentity);
03046         if ( (uri) && (*uri) )
03047         {
03048           mCompFields->SetFcc(PL_strcasecmp(uri, "nocopy://") ? uri : "");
03049           PL_strfree(uri);
03050         }
03051         else
03052                                    mCompFields->SetFcc("");
03053       }
03054     }
03055   }
03056 
03057   //
03058   // Deal with an additional FCC operation for this email.
03059   //
03060   const char *fieldsFCC2 = fields->GetFcc2();
03061   if ( (fieldsFCC2) && (*fieldsFCC2) )
03062   {
03063     if (PL_strcasecmp(fieldsFCC2, "nocopy://") == 0)
03064     {
03065       mCompFields->SetFcc2("");
03066       mNeedToPerformSecondFCC = PR_FALSE;
03067     }
03068     else
03069     {
03070       mCompFields->SetFcc2(fieldsFCC2);
03071       mNeedToPerformSecondFCC = PR_TRUE;
03072     }
03073   }
03074 
03075   mCompFields->SetNewspostUrl((char *) fields->GetNewspostUrl());
03076 
03077   /* strip whitespace from and duplicate header fields. */
03078   SetMimeHeader(nsMsgCompFields::MSG_FROM_HEADER_ID, fields->GetFrom());
03079   SetMimeHeader(nsMsgCompFields::MSG_REPLY_TO_HEADER_ID, fields->GetReplyTo());
03080   SetMimeHeader(nsMsgCompFields::MSG_TO_HEADER_ID, fields->GetTo());
03081   SetMimeHeader(nsMsgCompFields::MSG_CC_HEADER_ID, fields->GetCc());
03082   SetMimeHeader(nsMsgCompFields::MSG_BCC_HEADER_ID, fields->GetBcc());
03083   SetMimeHeader(nsMsgCompFields::MSG_NEWSGROUPS_HEADER_ID, fields->GetNewsgroups());
03084   SetMimeHeader(nsMsgCompFields::MSG_FOLLOWUP_TO_HEADER_ID, fields->GetFollowupTo());
03085   SetMimeHeader(nsMsgCompFields::MSG_ORGANIZATION_HEADER_ID, fields->GetOrganization());
03086   SetMimeHeader(nsMsgCompFields::MSG_SUBJECT_HEADER_ID, fields->GetSubject());
03087   SetMimeHeader(nsMsgCompFields::MSG_REFERENCES_HEADER_ID, fields->GetReferences());
03088   SetMimeHeader(nsMsgCompFields::MSG_X_TEMPLATE_HEADER_ID, fields->GetTemplateName());
03089 
03090   nsCOMPtr<nsISupportsArray> srcAttachmentArray;
03091   fields->GetAttachmentsArray(getter_AddRefs(srcAttachmentArray));
03092   if (srcAttachmentArray)
03093   {
03094     PRUint32 i;
03095     PRUint32 attachmentCount = 0;
03096     srcAttachmentArray->Count(&attachmentCount);
03097     if (attachmentCount > 0)
03098     {
03099       nsCOMPtr<nsIMsgAttachment> element;
03100       for (i = 0; i < attachmentCount; i ++)
03101       {
03102         srcAttachmentArray->QueryElementAt(i, NS_GET_IID(nsIMsgAttachment), getter_AddRefs(element));
03103         if (element)
03104           mCompFields->AddAttachment(element);
03105       }
03106     }
03107   }
03108 
03109   pStr = fields->GetOtherRandomHeaders();
03110   if (pStr)
03111     mCompFields->SetOtherRandomHeaders((char *) pStr);
03112  
03113   AddDefaultCustomHeaders();
03114                                                             
03115   pStr = fields->GetPriority();
03116   if (pStr)
03117     mCompFields->SetPriority((char *) pStr);
03118 
03119   mCompFields->SetAttachVCard(fields->GetAttachVCard());
03120   mCompFields->SetForcePlainText(fields->GetForcePlainText());
03121   mCompFields->SetUseMultipartAlternative(fields->GetUseMultipartAlternative());
03122   PRInt32 receiptType = nsIMsgMdnGenerator::eDntType; 
03123   fields->GetReceiptHeaderType(&receiptType);
03124 
03125   mCompFields->SetReturnReceipt(fields->GetReturnReceipt());
03126   mCompFields->SetReceiptHeaderType(receiptType);
03127 
03128   mCompFields->SetUuEncodeAttachments(fields->GetUuEncodeAttachments());
03129 
03130   mCompFields->SetBodyIsAsciiOnly(fields->GetBodyIsAsciiOnly());
03131   mCompFields->SetForceMsgEncoding(fields->GetForceMsgEncoding());
03132 
03133   nsCOMPtr<nsISupports> secInfo;
03134   fields->GetSecurityInfo(getter_AddRefs(secInfo));
03135 
03136   mCompFields->SetSecurityInfo(secInfo);
03137 
03138   PRBool needToCheckCharset;
03139   fields->GetNeedToCheckCharset(&needToCheckCharset);
03140   mCompFields->SetNeedToCheckCharset(needToCheckCharset);
03141 
03142   // Check the fields for legitimacy...
03143   //
03144   if ( m_deliver_mode != nsMsgSaveAsDraft && m_deliver_mode != nsMsgSaveAsTemplate ) 
03145   {
03146     rv = mime_sanity_check_fields (mCompFields->GetFrom(), mCompFields->GetReplyTo(),
03147                     mCompFields->GetTo(), mCompFields->GetCc(),
03148                     mCompFields->GetBcc(), mCompFields->GetFcc(),
03149                     mCompFields->GetNewsgroups(), mCompFields->GetFollowupTo(),
03150                     mCompFields->GetSubject(), mCompFields->GetReferences(),
03151                     mCompFields->GetOrganization(),
03152                     mCompFields->GetOtherRandomHeaders());
03153   }
03154   
03155   return rv;
03156 }
03157 
03158 // Add default headers to outgoing messages see Bug #61520
03159 // mail.identity.<id#>.headers pref is a comma separated value of pref names
03160 // containging headers to add headers are stored in
03161 // mail.identity.<id#>.header.<header name> grab all the headers, mime encode
03162 // them and add them to the other custom headers.
03163 nsresult
03164 nsMsgComposeAndSend::AddDefaultCustomHeaders() {
03165   nsXPIDLCString headersList;
03166   // get names of prefs containing headers to add
03167   nsresult rv = mUserIdentity->GetCharAttribute("headers",
03168                                                 getter_Copies(headersList));
03169   if (NS_SUCCEEDED(rv) && !headersList.IsEmpty()) {
03170     PRInt32 start = 0;
03171     PRInt32 end = 0;
03172     PRInt32 len = 0;
03173     // preserve any custom headers that have been added through the UI
03174     nsCAutoString newHeaderVal(mCompFields->GetOtherRandomHeaders());
03175     
03176     while (end != -1) {
03177       end = headersList.FindChar(',', start);
03178       if (end == -1) {
03179         len = headersList.Length() - start;
03180       } else {
03181         len = end - start;
03182       }
03183       // grab the name of the current header pref
03184       nsCAutoString headerName(NS_LITERAL_CSTRING("header.") +
03185                                Substring(headersList, start, len));
03186       start = end + 1;
03187       
03188       nsXPIDLCString headerVal;
03189       rv = mUserIdentity->GetCharAttribute(headerName.get(),
03190                                            getter_Copies(headerVal));
03191       if (NS_SUCCEEDED(rv)) {
03192         PRInt32 colonIdx = headerVal.FindChar(':') + 1;
03193         if (colonIdx != 0) { // check that the header is *most likely* valid.
03194           char * convHeader =
03195             nsMsgI18NEncodeMimePartIIStr(headerVal.get() + colonIdx,
03196                                          PR_FALSE,
03197                                          mCompFields->GetCharacterSet(),
03198                                          colonIdx,
03199                                          PR_TRUE);
03200           if (convHeader) {
03201             newHeaderVal.Append(Substring(headerVal, 0, colonIdx));
03202             newHeaderVal.Append(convHeader);
03203             // we must terminate the header with CRLF here
03204             // as nsMsgCompUtils.cpp just calls PUSH_STRING
03205             newHeaderVal.Append("\r\n");
03206             PR_Free(convHeader);
03207           }
03208         }
03209       }
03210     }
03211     mCompFields->SetOtherRandomHeaders(newHeaderVal.get());
03212   }
03213   return rv;
03214 }
03215 
03216 
03217 nsresult
03218 nsMsgComposeAndSend::SnarfAndCopyBody(const char  *attachment1_body,
03219                                       PRUint32    attachment1_body_length,
03220                                       const char  *attachment1_type)
03221 {
03222   //
03223   // If we are here, then just process the body from what was
03224   // passed in the attachment_1_body field.
03225   //
03226   // Strip whitespace from beginning and end of body.
03227   if (attachment1_body)
03228   {
03229     // strip out whitespaces from the end of body ONLY.
03230     while (attachment1_body_length > 0 &&
03231       (attachment1_body[attachment1_body_length - 1] == ' ') )
03232     {
03233       attachment1_body_length--;
03234     }
03235 
03236     if (attachment1_body_length > 0)
03237     {
03238      // will set m_attachment1_body and m_attachment1_body_length
03239      nsresult rv = EnsureLineBreaks(attachment1_body, attachment1_body_length);
03240      NS_ENSURE_SUCCESS(rv,rv);
03241     }
03242   }
03243   
03244   PR_FREEIF(m_attachment1_type);
03245   m_attachment1_type = PL_strdup (attachment1_type);
03246   PR_FREEIF(m_attachment1_encoding);
03247   m_attachment1_encoding = PL_strdup ("8bit");
03248   return NS_OK;
03249 }
03250 
03251 nsresult
03252 nsMsgComposeAndSend::Init(
03253               nsIMsgIdentity  *aUserIdentity,
03254               const char *aAccountKey,
03255               nsMsgCompFields *fields,
03256               nsFileSpec      *sendFileSpec,
03257               PRBool digest_p,
03258               PRBool dont_deliver_p,
03259               nsMsgDeliverMode mode,
03260               nsIMsgDBHdr *msgToReplace,
03261               const char *attachment1_type,
03262               const char *attachment1_body,
03263               PRUint32 attachment1_body_length,
03264               const nsMsgAttachmentData *attachments,
03265               const nsMsgAttachedFile *preloaded_attachments,
03266               const char *password,
03267               const nsACString &aOriginalMsgURI,
03268               MSG_ComposeType aType)
03269 {
03270   nsresult      rv = NS_OK;
03271   
03272   //Reset last error
03273   mLastErrorReported = NS_OK;
03274   
03275   //Let make sure we retreive the correct number of related parts. It may have changed since last time
03276   GetMultipartRelatedCount(PR_TRUE);
03277 
03278   nsXPIDLString msg;
03279   if (!mComposeBundle)
03280     mComposeBundle = do_GetService(NS_MSG_COMPOSESTRINGSERVICE_CONTRACTID);
03281 
03282   // Tell the user we are assembling the message...
03283   mComposeBundle->GetStringByID(NS_MSG_ASSEMBLING_MESSAGE, getter_Copies(msg));
03284   SetStatusMessage( msg );
03285   if (mSendReport)
03286     mSendReport->SetCurrentProcess(nsIMsgSendReport::process_BuildMessage);
03287 
03288   RETURN_SIMULATED_ERROR(SIMULATED_SEND_ERROR_1, NS_ERROR_FAILURE);
03289 
03290   // 
03291   // The Init() method should initialize a send operation for full
03292   // blown create and send operations as well as just the "send a file"
03293   // operations. 
03294   //
03295   m_dont_deliver_p = dont_deliver_p;
03296   m_deliver_mode = mode;
03297   mMsgToReplace = msgToReplace;
03298 
03299   mUserIdentity = aUserIdentity;
03300   mAccountKey = aAccountKey;
03301   NS_ASSERTION(mUserIdentity, "Got null identity!\n");
03302   if (!mUserIdentity) return NS_ERROR_UNEXPECTED;
03303 
03304   //
03305   // First sanity check the composition fields parameter and
03306   // see if we should continue
03307   //
03308   if (!fields)
03309     return NS_ERROR_OUT_OF_MEMORY;
03310 
03311   rv = InitCompositionFields(fields, aOriginalMsgURI, aType);
03312   if (NS_FAILED(rv))
03313     return rv;
03314 
03315   //
03316   // At this point, if we are only creating this object to do
03317   // send operations on externally created RFC822 disk files, 
03318   // make sure we have setup the appropriate nsFileSpec and
03319   // move on with life.
03320   //
03321   //
03322   // First check to see if we are doing a send operation on an external file
03323   // or creating the file itself.
03324   //
03325   if (sendFileSpec)
03326   {
03327     mTempFileSpec = sendFileSpec;
03328     return NS_OK;
03329   }
03330 
03331   m_digest_p = digest_p;
03332 
03333   //
03334   // Needed for mime encoding!
03335   //
03336   PRBool strictly_mime = PR_TRUE; 
03337   nsCOMPtr<nsIPrefBranch> pPrefBranch(do_GetService(NS_PREFSERVICE_CONTRACTID));
03338   if (pPrefBranch)
03339   {
03340     rv = pPrefBranch->GetBoolPref(PREF_MAIL_STRICTLY_MIME, &strictly_mime);
03341     rv = pPrefBranch->GetIntPref(PREF_MAIL_MESSAGE_WARNING_SIZE, (PRInt32 *) &mMessageWarningSize);
03342   }
03343 
03344   if (!strictly_mime)
03345   {
03346     nsresult rv = NS_OK;
03347     nsCOMPtr<nsIMsgComposeSecure> secureCompose;
03348     secureCompose = do_CreateInstance(NS_MSGCOMPOSESECURE_CONTRACTID, &rv);
03349     if (NS_SUCCEEDED(rv) && secureCompose)
03350       secureCompose->RequiresCryptoEncapsulation(aUserIdentity, fields, &strictly_mime);
03351   }
03352 
03353   nsMsgMIMESetConformToStandard(strictly_mime);
03354   mime_use_quoted_printable_p = strictly_mime;
03355 
03356   // Ok, now watch me pull a rabbit out of my hat....what we need
03357   // to do here is figure out what the body will be. If this is a
03358   // MHTML request, then we need to do some processing of the document
03359   // and figure out what we need to package along with this message
03360   // to send. See ProcessMultipartRelated() for further details.
03361   //
03362 
03363   //
03364   // If we don't have an editor, then we won't be doing multipart related processing 
03365   // for the body, so make a copy of the one passed in.
03366   //
03367   if (!mEditor)
03368   {
03369     SnarfAndCopyBody(attachment1_body, attachment1_body_length, attachment1_type);
03370   }
03371   else if (GetMultipartRelatedCount() == 0) // Only do this if there are not embedded objects
03372   {
03373     rv = GetBodyFromEditor();
03374     if (NS_FAILED(rv))
03375       return rv;
03376   }
03377 
03378   mSmtpPassword = password;
03379 
03380   return HackAttachments(attachments, preloaded_attachments);
03381 }
03382 
03383 nsresult
03384 SendDeliveryCallback(nsIURI *aUrl, nsresult aExitCode, nsMsgDeliveryType deliveryType, nsISupports *tagData)
03385 {
03386   if (tagData)
03387   {
03388     nsCOMPtr<nsIMsgSend> msgSend = do_QueryInterface(tagData);
03389     if (!msgSend)
03390       return NS_ERROR_NULL_POINTER;
03391 
03392     if (deliveryType == nsMailDelivery)
03393     {
03394       if (NS_FAILED(aExitCode))
03395         switch (aExitCode)
03396         {
03397           case NS_ERROR_UNKNOWN_HOST:
03398           case NS_ERROR_UNKNOWN_PROXY_HOST:
03399             aExitCode = NS_ERROR_COULD_NOT_LOGIN_TO_SMTP_SERVER;
03400             break;
03401           default:
03402             if (aExitCode != NS_ERROR_ABORT && !NS_IS_MSG_ERROR(aExitCode))
03403               aExitCode = NS_ERROR_SMTP_SEND_FAILED;
03404             break;
03405         }
03406       msgSend->DeliverAsMailExit(aUrl, aExitCode);
03407     }
03408     
03409     else if (deliveryType == nsNewsDelivery)
03410     {
03411       if (NS_FAILED(aExitCode))
03412         if (aExitCode != NS_ERROR_ABORT && !NS_IS_MSG_ERROR(aExitCode))
03413           aExitCode = NS_ERROR_POST_FAILED;
03414       
03415       msgSend->DeliverAsNewsExit(aUrl, aExitCode);
03416     }
03417 
03418     msgSend->SetRunningRequest(nsnull);
03419   }
03420 
03421   return aExitCode;
03422 }
03423 
03424 nsresult
03425 nsMsgComposeAndSend::DeliverMessage()
03426 {
03427   if (mSendProgress)
03428   {
03429     PRBool canceled = PR_FALSE;
03430     mSendProgress->GetProcessCanceledByUser(&canceled);
03431     if (canceled)
03432       return NS_ERROR_ABORT;
03433   }
03434 
03435   PRBool mail_p = ((mCompFields->GetTo() && *mCompFields->GetTo()) || 
03436           (mCompFields->GetCc() && *mCompFields->GetCc()) || 
03437           (mCompFields->GetBcc() && *mCompFields->GetBcc()));
03438   PRBool news_p = mCompFields->GetNewsgroups() && *(mCompFields->GetNewsgroups());
03439   NS_ASSERTION(!( m_deliver_mode != nsMsgSaveAsDraft && m_deliver_mode != nsMsgSaveAsTemplate)  || (mail_p || news_p), "message without destination");
03440   if (m_deliver_mode == nsMsgQueueForLater) 
03441     return QueueForLater();
03442   else if (m_deliver_mode == nsMsgSaveAsDraft) 
03443     return SaveAsDraft();
03444   else if (m_deliver_mode == nsMsgSaveAsTemplate)
03445     return SaveAsTemplate();
03446 
03447   //
03448   // Ok, we are about to send the file that we have built up...but what
03449   // if this is a mongo email...we should have a way to warn the user that
03450   // they are about to do something they may not want to do.
03451   //
03452   if (((mMessageWarningSize > 0) && (mTempFileSpec->GetFileSize() > mMessageWarningSize) && (mGUINotificationEnabled)) ||
03453       CHECK_SIMULATED_ERROR(SIMULATED_SEND_ERROR_15))
03454   {
03455     PRBool abortTheSend = PR_FALSE;
03456     
03457     nsXPIDLString msg;
03458     mComposeBundle->GetStringByID(NS_MSG_LARGE_MESSAGE_WARNING, getter_Copies(msg));
03459     
03460     if (msg)
03461     {
03462       PRUnichar *printfString = nsTextFormatter::smprintf(msg, mTempFileSpec->GetFileSize());
03463 
03464       if (printfString)
03465       {
03466         nsCOMPtr<nsIPrompt> prompt;
03467         GetDefaultPrompt(getter_AddRefs(prompt));
03468 
03469         nsMsgAskBooleanQuestionByString(prompt, printfString, &abortTheSend);
03470         if (!abortTheSend)
03471         {
03472           nsresult ignoreMe;
03473           Fail(NS_ERROR_BUT_DONT_SHOW_ALERT, printfString, &ignoreMe);
03474           PR_Free(printfString);
03475           return NS_ERROR_FAILURE;
03476         }
03477         else
03478           PR_Free(printfString);
03479       }
03480 
03481     }
03482   }
03483 
03484   if (news_p) 
03485   {
03486     if (mail_p) 
03487       mSendMailAlso = PR_TRUE;
03488 
03489     return DeliverFileAsNews();   /* will call DeliverFileAsMail if it needs to */
03490   }
03491   else if (mail_p) 
03492   {
03493     return DeliverFileAsMail();
03494   }
03495   else
03496   {
03497     return NS_ERROR_UNEXPECTED;
03498   }
03499   
03500   return NS_OK;
03501 }
03502 
03503 // strip out non-printable characters 
03504 static void 
03505 strip_nonprintable(char *string) 
03506 {
03507   char *dest, *src;
03508   
03509   if ( (!string) || (!*string) ) return;
03510   dest=src=string;
03511   while (*src) 
03512   {
03513     if  ( (isprint(*src)) && (*src != ' ') )
03514     {
03515       (*dest)=(*src);
03516       src++; dest++;
03517     } 
03518     else 
03519     {
03520       src++;
03521     }
03522   }
03523 
03524   (*dest)='\0';
03525 }
03526 
03527 nsresult
03528 nsMsgComposeAndSend::DeliverFileAsMail()
03529 {
03530   char *buf, *buf2;
03531   buf = (char *) PR_Malloc ((mCompFields->GetTo() ? PL_strlen (mCompFields->GetTo())  + 10 : 0) +
03532                (mCompFields->GetCc() ? PL_strlen (mCompFields->GetCc())  + 10 : 0) +
03533                (mCompFields->GetBcc() ? PL_strlen (mCompFields->GetBcc()) + 10 : 0) +
03534                10);
03535   
03536   if (mSendReport)
03537     mSendReport->SetCurrentProcess(nsIMsgSendReport::process_SMTP);
03538 
03539   nsCOMPtr<nsIPrompt> promptObject;
03540   GetDefaultPrompt(getter_AddRefs(promptObject));
03541 
03542   if (!buf) 
03543   {
03544     nsXPIDLString eMsg; 
03545     mComposeBundle->GetStringByID(NS_ERROR_OUT_OF_MEMORY, getter_Copies(eMsg));
03546     
03547     nsresult ignoreMe;
03548     Fail(NS_ERROR_OUT_OF_MEMORY, eMsg, &ignoreMe);
03549     NotifyListenerOnStopSending(nsnull, NS_ERROR_OUT_OF_MEMORY, nsnull, nsnull);
03550     return NS_ERROR_OUT_OF_MEMORY;
03551   }
03552 
03553   PRBool collectOutgoingAddresses = PR_TRUE;
03554   nsCOMPtr<nsIPrefBranch> pPrefBranch(do_GetService(NS_PREFSERVICE_CONTRACTID));
03555   if (pPrefBranch)
03556     pPrefBranch->GetBoolPref(PREF_MAIL_COLLECT_EMAIL_ADDRESS_OUTGOING, &collectOutgoingAddresses);
03557  
03558   nsCOMPtr<nsIAbAddressCollecter> addressCollecter = 
03559            do_GetService(NS_ABADDRESSCOLLECTER_CONTRACTID);
03560 
03561   PRBool collectAddresses = (collectOutgoingAddresses && addressCollecter);
03562   PRBool forcePlainText = mCompFields->GetForcePlainText();
03563   PRBool useMultipartAlternative = mCompFields->GetUseMultipartAlternative();
03564   PRUint32 sendFormat = nsIAbPreferMailFormat::unknown;
03565 
03566   // this code is not ready yet
03567   // see bug #44494 for more details
03568   // so for now, just pass in nsIAbPreferMailFormat::unknown
03569   // which will have no effect on the "prefers" attribute in the ab
03570 #if 0
03571   // see GenericSendMessage() in MsgComposeCommands.js for the reverse logic
03572   // if we choose to send both (html and plain) remember html.
03573   if (forcePlainText && !useMultipartAlternative)
03574   {
03575     // for now, don't remember the "plaintext" decision.
03576     // we could get in here because while sending html mail
03577     // the body was "convertible", but that doesn't mean
03578     // we intended to force plain text here.
03579     // so for now, use "unknown" which will have no effect on the
03580     // "prefers" attribute in the ab.
03581     // see bug #245520 for more details
03582     // sendFormat = nsIAbPreferMailFormat::plaintext;
03583     sendFormat = nsIAbPreferMailFormat::unknown;
03584   }
03585   else if (!forcePlainText)
03586     sendFormat = nsIAbPreferMailFormat::html;
03587   else
03588     NS_ASSERTION(0,"unknown send format, should not happen");
03589 #endif
03590 
03591   PL_strcpy (buf, "");
03592   buf2 = buf + PL_strlen (buf);
03593   if (mCompFields->GetTo() && *mCompFields->GetTo())
03594   {
03595     PL_strcat (buf2, mCompFields->GetTo());
03596     if (addressCollecter)
03597       addressCollecter->CollectAddress(mCompFields->GetTo(), collectAddresses /* create card if one doesn't exist */, sendFormat);
03598   }
03599   if (mCompFields->GetCc() && *mCompFields->GetCc()) {
03600     if (*buf2) PL_strcat (buf2, ",");
03601       PL_strcat (buf2, mCompFields->GetCc());
03602     if (addressCollecter)
03603       addressCollecter->CollectAddress(mCompFields->GetCc(), collectAddresses /* create card if one doesn't exist */, sendFormat);
03604   }
03605   if (mCompFields->GetBcc() && *mCompFields->GetBcc()) {
03606     if (*buf2) PL_strcat (buf2, ",");
03607       PL_strcat (buf2, mCompFields->GetBcc());
03608     if (addressCollecter)
03609       addressCollecter->CollectAddress(mCompFields->GetBcc(), collectAddresses /* create card if one doesn't exist */, sendFormat);
03610   }
03611 
03612   // We need undo groups to keep only the addresses
03613   nsresult rv = StripOutGroupNames(buf);
03614   NS_ENSURE_SUCCESS(rv, rv);
03615 
03616   // Ok, now MIME II encode this to prevent 8bit problems...
03617   char *convbuf = nsMsgI18NEncodeMimePartIIStr(buf, PR_TRUE, 
03618             mCompFields->GetCharacterSet(), 0, nsMsgMIMEGetConformToStandard());
03619   if (convbuf) 
03620   {     
03621     // MIME-PartII conversion 
03622     PR_FREEIF(buf);
03623     buf = convbuf;
03624   }
03625 
03626   strip_nonprintable(buf);
03627 
03628   convbuf = nsEscape(buf, url_Path);
03629   if (convbuf)
03630   {
03631       nsCRT::free(buf);
03632       buf = convbuf;
03633   }
03634   
03635   nsCOMPtr<nsISmtpService> smtpService(do_GetService(NS_SMTPSERVICE_CONTRACTID, &rv));
03636   if (NS_SUCCEEDED(rv) && smtpService)
03637   {
03638     nsMsgDeliveryListener * aListener = new nsMsgDeliveryListener(SendDeliveryCallback, nsMailDelivery, this);
03639     nsCOMPtr<nsIUrlListener> uriListener = do_QueryInterface(aListener);
03640     if (!uriListener)
03641       return NS_ERROR_OUT_OF_MEMORY;
03642 
03643     // Note: Don't do a SetMsgComposeAndSendObject since we are in the same thread, and
03644     // using callbacks for notification
03645 
03646     nsCOMPtr<nsIFileSpec> aFileSpec;
03647     NS_NewFileSpecWithSpec(*mTempFileSpec, getter_AddRefs(aFileSpec));
03648 
03649     // we used to get the prompt from the compose window and we'd pass that in
03650     // to the smtp protocol as the prompt to use. But when you send a message,
03651     // we dismiss the compose window.....so you are parenting off of a window that
03652     // isn't there. To have it work correctly I think we want the alert dialogs to be modal
03653     // to the top most mail window...after all, that's where we are going to be sending status
03654     // update information too....
03655 
03656     nsCOMPtr<nsIInterfaceRequestor> callbacks;
03657     GetNotificationCallbacks(getter_AddRefs(callbacks));
03658 
03659     // Tell the user we are sending the message!
03660     nsXPIDLString msg; 
03661     mComposeBundle->GetStringByID(NS_MSG_SENDING_MESSAGE, getter_Copies(msg));
03662     SetStatusMessage( msg );
03663     nsCOMPtr<nsIMsgStatusFeedback> msgStatus (do_QueryInterface(mSendProgress));
03664     // if the sendProgress isn't set, let's use the member variable.
03665     if (!msgStatus)
03666       msgStatus = do_QueryInterface(mStatusFeedback);
03667 
03668     rv = smtpService->SendMailMessage(aFileSpec, buf, mUserIdentity,
03669                                       mSmtpPassword.get(), uriListener, msgStatus,
03670                                       callbacks, nsnull, getter_AddRefs(mRunningRequest));
03671   }
03672   
03673   PR_FREEIF(buf); // free the buf because we are done with it....
03674   return rv;
03675 }
03676 
03677 nsresult
03678 nsMsgComposeAndSend::DeliverFileAsNews()
03679 {
03680   nsresult rv = NS_OK;
03681   if (!(mCompFields->GetNewsgroups()))
03682     return rv;
03683   
03684   if (mSendReport)
03685     mSendReport->SetCurrentProcess(nsIMsgSendReport::process_NNTP);
03686   
03687   nsCOMPtr<nsIPrompt> promptObject;
03688   GetDefaultPrompt(getter_AddRefs(promptObject));
03689   
03690   nsCOMPtr<nsINntpService> nntpService(do_GetService(NS_NNTPSERVICE_CONTRACTID, &rv));
03691   
03692   if (NS_SUCCEEDED(rv) && nntpService) 
03693   {
03694     nsMsgDeliveryListener * aListener = new nsMsgDeliveryListener(SendDeliveryCallback, nsNewsDelivery, this);
03695     nsCOMPtr<nsIUrlListener> uriListener = do_QueryInterface(aListener);
03696     if (!uriListener)
03697       return NS_ERROR_OUT_OF_MEMORY;
03698     
03699     // Note: Don't do a SetMsgComposeAndSendObject since we are in the same thread, and
03700     // using callbacks for notification
03701     
03702     nsCOMPtr<nsIFileSpec>fileToPost;
03703     
03704     rv = NS_NewFileSpecWithSpec(*mTempFileSpec, getter_AddRefs(fileToPost));
03705     if (NS_FAILED(rv)) return rv;
03706     
03707     // Tell the user we are posting the message!
03708     nsXPIDLString msg; 
03709     mComposeBundle->GetStringByID(NS_MSG_POSTING_MESSAGE, getter_Copies(msg));
03710     SetStatusMessage( msg );
03711     
03712     nsCOMPtr <nsIMsgMailSession> mailSession = do_GetService(NS_MSGMAILSESSION_CONTRACTID, &rv);
03713     if (NS_FAILED(rv)) return rv;
03714     
03715     if (!mailSession) return NS_ERROR_FAILURE;
03716     
03717     // JFD TODO: we should use GetDefaultPrompt instead
03718     nsCOMPtr<nsIMsgWindow> msgWindow;
03719     rv = mailSession->GetTopmostMsgWindow(getter_AddRefs(msgWindow));
03720     // see bug #163139
03721     // we might not have a msg window if only the compose window is open.
03722     if(NS_FAILED(rv))
03723       msgWindow = nsnull;
03724 
03725     rv = nntpService->PostMessage(fileToPost, mCompFields->GetNewsgroups(), mAccountKey.get(),
03726                                   uriListener, msgWindow, nsnull);
03727     if (NS_FAILED(rv)) return rv;
03728   }
03729   
03730   return rv;
03731 }
03732 
03733 NS_IMETHODIMP 
03734 nsMsgComposeAndSend::Fail(nsresult failure_code, const PRUnichar * error_msg, nsresult *_retval)
03735 {
03736   NS_ENSURE_ARG(_retval);
03737   *_retval = failure_code;
03738   
03739   if (NS_FAILED(failure_code))
03740   {
03741     nsCOMPtr<nsIPrompt> prompt;
03742     GetDefaultPrompt(getter_AddRefs(prompt));
03743       
03744     if (mSendReport)
03745     {
03746       mSendReport->SetError(nsIMsgSendReport::process_Current, failure_code, PR_FALSE);
03747       mSendReport->SetMessage(nsIMsgSendReport::process_Current, error_msg, PR_FALSE);
03748       mSendReport->DisplayReport(prompt, PR_TRUE, PR_TRUE, _retval);
03749     }
03750     else
03751     {
03752       if (failure_code != NS_ERROR_BUT_DONT_SHOW_ALERT)
03753         nsMsgDisplayMessageByID(prompt, NS_ERROR_SEND_FAILED);
03754     }
03755   }
03756 
03757   if (m_attachments_done_callback)
03758   {
03759     /* mime_free_message_state will take care of cleaning up the
03760        attachment files and attachment structures */
03761     m_attachments_done_callback (failure_code, error_msg, nsnull);
03762     m_attachments_done_callback = nsnull;
03763   }
03764   
03765   if (m_status == NS_OK)
03766     m_status = NS_ERROR_BUT_DONT_SHOW_ALERT;
03767 
03768   //Stop any pending process...
03769   Abort();
03770   
03771   return NS_OK;
03772 }
03773 
03774 nsresult
03775 nsMsgComposeAndSend::FormatStringWithSMTPHostNameByID(PRInt32 aMsgId, PRUnichar **aString)
03776 {
03777   NS_ENSURE_ARG(aString);
03778 
03779   nsresult rv;
03780   nsCOMPtr<nsISmtpService> smtpService(do_GetService(NS_SMTPSERVICE_CONTRACTID, &rv));
03781   NS_ENSURE_SUCCESS(rv,rv);
03782 
03783   // Get the smtp hostname and format the string.
03784   nsXPIDLCString smtpHostName;
03785   nsCOMPtr<nsISmtpServer> smtpServer;
03786   rv = smtpService->GetSmtpServerByIdentity(mUserIdentity, getter_AddRefs(smtpServer));
03787   if (NS_SUCCEEDED(rv))
03788     smtpServer->GetHostname(getter_Copies(smtpHostName));
03789 
03790   nsAutoString hostStr;
03791   hostStr.AssignWithConversion(smtpHostName.get());
03792   const PRUnichar *params[] = { hostStr.get() };
03793   nsCOMPtr<nsIStringBundle> bundle;
03794   rv = mComposeBundle->GetBundle(getter_AddRefs(bundle));
03795   if (NS_SUCCEEDED(rv))
03796     bundle->FormatStringFromID(NS_ERROR_GET_CODE(aMsgId), params, 1, aString);
03797   return rv;
03798 }
03799 
03800 void
03801 nsMsgComposeAndSend::DoDeliveryExitProcessing(nsIURI * aUri, nsresult aExitCode, PRBool aCheckForMail)
03802 {  
03803   // If we fail on the news delivery, no sense in going on so just notify
03804   // the user and exit.
03805   if (NS_FAILED(aExitCode))
03806   {
03807 #ifdef NS_DEBUG
03808   printf("\nMessage Delivery Failed!\n");
03809 #endif
03810 
03811     nsXPIDLString eMsg; 
03812     if (aExitCode == NS_ERROR_SMTP_SEND_FAILED ||
03813         aExitCode == NS_ERROR_COULD_NOT_LOGIN_TO_SMTP_SERVER ||
03814         aExitCode == NS_ERROR_COULD_NOT_LOGIN_TO_SMTP_SERVER_WITH_STARTTLS1 ||
03815         aExitCode == NS_ERROR_COULD_NOT_LOGIN_TO_SMTP_SERVER_WITH_STARTTLS2)
03816       FormatStringWithSMTPHostNameByID(aExitCode, getter_Copies(eMsg));
03817     else
03818     mComposeBundle->GetStringByID(aExitCode, getter_Copies(eMsg));
03819     
03820     Fail(aExitCode, eMsg, &aExitCode);
03821     NotifyListenerOnStopSending(nsnull, aExitCode, nsnull, nsnull);
03822     return;
03823   }
03824 #ifdef NS_DEBUG
03825   else
03826     printf("\nMessage Delivery SUCCEEDED!\n");
03827 #endif
03828 
03829   if (aCheckForMail)
03830   {
03831     if ((mCompFields->GetTo() && *mCompFields->GetTo()) || 
03832         (mCompFields->GetCc() && *mCompFields->GetCc()) || 
03833         (mCompFields->GetBcc() && *mCompFields->GetBcc()))
03834     {
03835       // If we're sending this news message to mail as well, start it now.
03836       // Completion and further errors will be handled there.
03837       DeliverFileAsMail();
03838       return;
03839     }
03840   }
03841 
03842   //
03843   // Tell the listeners that we are done with the sending operation...
03844   //
03845   NotifyListenerOnStopSending(nsnull, aExitCode, nsnull, nsnull);
03846 
03847   // If we hit here, we are done with delivery!
03848   //
03849   // Just call the DoFCC() method and if that fails, then we should just 
03850   // cleanup and get out. If DoFCC "succeeds", then all that means is the
03851   // async copy operation has been started and we will be notified later 
03852   // when it is done. DON'T cleanup until the copy is complete and don't
03853   // notify the listeners with OnStop() until we are done.
03854   //
03855   // For now, we don't need to do anything here, but the code will stay this 
03856   // way until later...
03857   //
03858 
03859   nsresult retCode = DoFcc();
03860   if (NS_FAILED(retCode))
03861   {
03862 #ifdef NS_DEBUG
03863   printf("\nDoDeliveryExitProcessing(): DoFcc() call Failed!\n");
03864 #endif
03865     return;
03866   } 
03867   else
03868   {
03869     // Either we started the copy...cleanup happens later...or cleanup will
03870     // be take care of by a listener...
03871     return;
03872   }
03873 }
03874 
03875 NS_IMETHODIMP
03876 nsMsgComposeAndSend::DeliverAsMailExit(nsIURI *aUrl, nsresult aExitCode)
03877 {
03878   DoDeliveryExitProcessing(aUrl, aExitCode, PR_FALSE);
03879   return NS_OK;
03880 }
03881 
03882 NS_IMETHODIMP
03883 nsMsgComposeAndSend::DeliverAsNewsExit(nsIURI *aUrl, nsresult aExitCode)
03884 {
03885   DoDeliveryExitProcessing(aUrl, aExitCode, mSendMailAlso);
03886   return NS_OK;
03887 }
03888 
03889 PRBool nsMsgComposeAndSend::CanSaveMessagesToFolder(const char *folderURL)
03890 {
03891   nsresult rv;
03892   nsCOMPtr<nsIRDFService> rdf(do_GetService("@mozilla.org/rdf/rdf-service;1", &rv));
03893   if (NS_FAILED(rv))
03894     return PR_FALSE;
03895 
03896   nsCOMPtr<nsIRDFResource> resource;
03897   rv = rdf->GetResource(nsDependentCString(folderURL), getter_AddRefs(resource));
03898   if (NS_FAILED(rv))
03899     return PR_FALSE;
03900 
03901   nsCOMPtr <nsIMsgFolder> thisFolder;
03902   thisFolder = do_QueryInterface(resource, &rv);
03903   if (NS_FAILED(rv) || !thisFolder)
03904     return PR_FALSE;
03905 
03906   nsCOMPtr<nsIMsgIncomingServer> server;
03907   rv = thisFolder->GetServer(getter_AddRefs(server));
03908   if (NS_FAILED(rv) || !server)
03909     return PR_FALSE;
03910 
03911   // See if we are allowed to save/file msgs to this folder.
03912   PRBool canSave;
03913   rv = server->GetCanFileMessagesOnServer(&canSave);
03914   return canSave;
03915 }
03916 
03917 // 
03918 // Now, start the appropriate copy operation.
03919 //
03920 nsresult
03921 nsMsgComposeAndSend::DoFcc()
03922 {
03923   //
03924   // Just cleanup and return success if we're not allowed to save msgs to FCC folder.
03925   //
03926   if (! CanSaveMessagesToFolder(mCompFields->GetFcc()))
03927   {
03928 #ifdef NS_DEBUG
03929   printf("\nCopy operation disabled by user!\n");
03930 #endif
03931 
03932     NotifyListenerOnStopSending(nsnull, NS_OK, nsnull, nsnull);
03933     NotifyListenerOnStopCopy(NS_OK);  // For closure of compose window...
03934     return NS_OK;
03935   }
03936 
03937   if (mSendReport)
03938     mSendReport->SetCurrentProcess(nsIMsgSendReport::process_Copy);
03939 
03940   //
03941   // If we are here, then we need to save off the FCC file to save and
03942   // start the copy operation. MimeDoFCC() will take care of all of this
03943   // for us.
03944   //
03945   nsresult rv = MimeDoFCC(mTempFileSpec,
03946                           nsMsgDeliverNow,
03947                           mCompFields->GetBcc(),
03948                           mCompFields->GetFcc(), 
03949                           mCompFields->GetNewspostUrl());
03950   if (NS_FAILED(rv))
03951   {
03952     //
03953     // If we hit here, the copy operation FAILED and we should at least tell the
03954     // user that it did fail but the send operation has already succeeded.
03955     //
03956     NotifyListenerOnStopCopy(rv);
03957   }
03958 
03959   return rv;
03960 }
03961 
03962 NS_IMETHODIMP
03963 nsMsgComposeAndSend::NotifyListenerOnStartSending(const char *aMsgID, PRUint32 aMsgSize)
03964 {
03965   if (mListener)
03966     mListener->OnStartSending(aMsgID, aMsgSize);
03967 
03968   return NS_OK;
03969 }
03970 
03971 NS_IMETHODIMP
03972 nsMsgComposeAndSend::NotifyListenerOnProgress(const char *aMsgID, PRUint32 aProgress, PRUint32 aProgressMax)
03973 {
03974   if (mListener)
03975     mListener->OnProgress(aMsgID, aProgress, aProgressMax);
03976 
03977   return NS_OK;
03978 }
03979 
03980 NS_IMETHODIMP
03981 nsMsgComposeAndSend::NotifyListenerOnStatus(const char *aMsgID, const PRUnichar *aMsg)
03982 {
03983   if (mListener)
03984     mListener->OnStatus(aMsgID, aMsg);
03985 
03986   return NS_OK;
03987 }
03988 
03989 NS_IMETHODIMP
03990 nsMsgComposeAndSend::NotifyListenerOnStopSending(const char *aMsgID, nsresult aStatus, const PRUnichar *aMsg, 
03991                                                   nsIFileSpec *returnFileSpec)
03992 {
03993   if (mListener != nsnull)
03994     mListener->OnStopSending(aMsgID, aStatus, aMsg, returnFileSpec);
03995 
03996   return NS_OK;
03997 }
03998 
03999 NS_IMETHODIMP
04000 nsMsgComposeAndSend::NotifyListenerOnStartCopy()
04001 {
04002   nsCOMPtr<nsIMsgCopyServiceListener> copyListener;
04003 
04004   if (mListener)
04005   {
04006     copyListener = do_QueryInterface(mListener);
04007     if (copyListener)
04008       copyListener->OnStartCopy();      
04009   }
04010 
04011   return NS_OK;
04012 }
04013 
04014 NS_IMETHODIMP
04015 nsMsgComposeAndSend::NotifyListenerOnProgressCopy(PRUint32 aProgress,
04016                                                    PRUint32 aProgressMax)
04017 {
04018   nsCOMPtr<nsIMsgCopyServiceListener> copyListener;
04019 
04020   if (mListener)
04021   {
04022     copyListener = do_QueryInterface(mListener);
04023     if (copyListener)
04024       copyListener->OnProgress(aProgress, aProgressMax);
04025   }
04026 
04027   return NS_OK;  
04028 }
04029 
04030 NS_IMETHODIMP
04031 nsMsgComposeAndSend::SetMessageKey(PRUint32 aMessageKey)
04032 {
04033     m_messageKey = aMessageKey;
04034     return NS_OK;
04035 }
04036 
04037 NS_IMETHODIMP
04038 nsMsgComposeAndSend::GetMessageKey(PRUint32 *aMessageKey)
04039 {
04040     *aMessageKey = m_messageKey;
04041     return NS_OK;
04042 }
04043 
04044 NS_IMETHODIMP
04045 nsMsgComposeAndSend::GetMessageId(nsCString* aMessageId)
04046 {
04047   NS_ENSURE_ARG(aMessageId);
04048   
04049   if (mCompFields)
04050   {
04051     *aMessageId = mCompFields->GetMessageId();
04052     return NS_OK;
04053   }
04054   return NS_ERROR_NULL_POINTER;
04055 }
04056 
04057 NS_IMETHODIMP
04058 nsMsgComposeAndSend::NotifyListenerOnStopCopy(nsresult aStatus)
04059 {
04060   nsCOMPtr<nsIMsgCopyServiceListener> copyListener;
04061 
04062   // This is one per copy so make sure we clean this up first.
04063   if (mCopyObj)
04064   {
04065     NS_RELEASE(mCopyObj);
04066     mCopyObj = nsnull;
04067   }
04068 
04069   // Set a status message...
04070   nsXPIDLString msg;
04071 
04072   if (NS_SUCCEEDED(aStatus))
04073     mComposeBundle->GetStringByID(NS_MSG_START_COPY_MESSAGE_COMPLETE, getter_Copies(msg));
04074   else
04075     mComposeBundle->GetStringByID(NS_MSG_START_COPY_MESSAGE_FAILED, getter_Copies(msg));
04076 
04077   SetStatusMessage( msg );
04078   nsCOMPtr<nsIPrompt> prompt;
04079   GetDefaultPrompt(getter_AddRefs(prompt));
04080 
04081   if (NS_FAILED(aStatus))
04082   {
04083     PRBool retry = PR_FALSE;
04084     nsMsgAskBooleanQuestionByID(prompt, NS_MSG_ERROR_DOING_FCC, &retry, nsnull /* what title */);
04085     if (retry)
04086     {
04087       mSendProgress = nsnull; // this was cancelled, so we need to clear it.
04088       return DoFcc();
04089     }
04090 
04091   }
04092   // Ok, now to support a second copy operation, we need to figure
04093   // out which copy request just finished. If the user has requested
04094   // a second copy operation, then we need to fire that off, but if they
04095   // just wanted a single copy operation, we can tell everyone we are done
04096   // and move on with life. Only do the second copy if the first one worked.
04097   //
04098   if ( NS_SUCCEEDED(aStatus) && (mNeedToPerformSecondFCC) )
04099   {
04100     if (mSendReport)
04101       mSendReport->SetCurrentProcess(nsIMsgSendReport::process_FCC);
04102 
04103     mNeedToPerformSecondFCC = PR_FALSE;
04104 
04105     const char *fcc2 = mCompFields->GetFcc2();
04106     if (fcc2 && *fcc2)
04107     {
04108       nsresult rv = MimeDoFCC(mTempFileSpec,
04109                               nsMsgDeliverNow,
04110                               mCompFields->GetBcc(),
04111                               fcc2, 
04112                               mCompFields->GetNewspostUrl());
04113       if (NS_FAILED(rv))
04114         Fail(rv, nsnull, &aStatus);
04115       else
04116         return NS_OK;
04117     }
04118   }
04119   else if (NS_FAILED(aStatus))
04120   {
04121     //
04122     // If we hit here, the ASYNC copy operation FAILED and we should at least tell the
04123     // user that it did fail but the send operation has already succeeded. This only if
04124     // we are sending the message and not just saving it!
04125     
04126     Fail(aStatus, nsnull, &aStatus);
04127   }
04128 
04129   // If we are here, its real cleanup time! 
04130   if (mListener)
04131   {
04132     copyListener = do_QueryInterface(mListener);
04133     if (copyListener)
04134       copyListener->OnStopCopy(aStatus);
04135   }
04136 
04137   return aStatus;
04138 }
04139 
04140 /* This is the main driving function of this module.  It generates a
04141    document of type message/rfc822, which contains the stuff provided.
04142    The first few arguments are the standard header fields that the
04143    generated document should have.
04144 
04145    `other_random_headers' is a string of additional headers that should
04146    be inserted beyond the standard ones.  If provided, it is just tacked
04147    on to the end of the header block, so it should have newlines at the
04148    end of each line, shouldn't have blank lines, multi-line headers
04149    should be properly continued, etc.
04150 
04151    `digest_p' says that most of the documents we are attaching are
04152    themselves messages, and so we should generate a multipart/digest
04153    container instead of multipart/mixed.  (It's a minor difference.)
04154 
04155    The full text of the first attachment is provided via `attachment1_type',
04156    `attachment1_body' and `attachment1_body_length'.  These may all be 0
04157    if all attachments are provided externally.
04158 
04159    Subsequent attachments are provided as URLs to load, described in the
04160    nsMsgAttachmentData structures.
04161 
04162    If `dont_deliver_p' is false, then we actually deliver the message to the
04163    SMTP and/or NNTP server, and the message_delivery_done_callback will be
04164    invoked with the status.
04165 
04166    If `dont_deliver_p' is true, then we just generate the message, we don't
04167    actually deliver it, and the message_delivery_done_callback will be called
04168    with the name of the generated file.  The callback is responsible for both
04169    freeing the file name string, and deleting the file when it is done with
04170    it.  If an error occurred, then `status' will be negative and
04171    `error_message' may be an error message to display.  If status is non-
04172    negative, then `error_message' contains the file name (this is kind of
04173    a kludge...)
04174  */
04175 NS_IMETHODIMP 
04176 nsMsgComposeAndSend::CreateAndSendMessage(
04177               nsIEditor                         *aEditor,
04178               nsIMsgIdentity                    *aUserIdentity,
04179               const char                        *aAccountKey,
04180               nsIMsgCompFields                  *fields,
04181               PRBool                            digest_p,
04182               PRBool                            dont_deliver_p,
04183               nsMsgDeliverMode                  mode,
04184               nsIMsgDBHdr                       *msgToReplace,
04185               const char                        *attachment1_type,
04186               const char                        *attachment1_body,
04187               PRUint32                          attachment1_body_length,
04188               const nsMsgAttachmentData         *attachments,
04189               const nsMsgAttachedFile           *preloaded_attachments,
04190               void                              *relatedPart,
04191               nsIDOMWindowInternal              *parentWindow,
04192               nsIMsgProgress                    *progress,
04193               nsIMsgSendListener                *aListener,
04194               const char                        *password,
04195               const nsACString                  &aOriginalMsgURI,
04196               MSG_ComposeType                   aType
04197               )
04198 {
04199   nsresult      rv;
04200   
04201   
04202   /* First thing to do is to reset the send errors report */
04203   mSendReport->Reset();
04204   mSendReport->SetDeliveryMode(mode);
04205 
04206   mParentWindow = parentWindow;
04207   mSendProgress = progress;
04208   mListener = aListener;
04209 
04210   if (!attachment1_body || !*attachment1_body)
04211   {
04212     attachment1_body_length = 0;
04213     attachment1_body = (char *) nsnull;
04214   }
04215 
04216   // Set the editor for MHTML operations if necessary
04217   if (aEditor)
04218     mEditor = aEditor;
04219 
04220   rv = Init(aUserIdentity, aAccountKey, (nsMsgCompFields *)fields, nsnull,
04221           digest_p, dont_deliver_p, mode, msgToReplace,
04222           attachment1_type, attachment1_body,
04223           attachment1_body_length,
04224           attachments, preloaded_attachments,
04225           password, aOriginalMsgURI, aType);
04226 
04227   if (NS_FAILED(rv) && mSendReport)
04228     mSendReport->SetError(nsIMsgSendReport::process_Current, rv, PR_FALSE);
04229 
04230   return rv;
04231 }
04232 
04233 nsresult
04234 nsMsgComposeAndSend::SendMessageFile(
04235               nsIMsgIdentity                    *aUserIndentity,
04236               const char                        *aAccountKey,
04237               nsIMsgCompFields                  *fields,
04238               nsIFileSpec                       *sendIFileSpec,
04239               PRBool                            deleteSendFileOnCompletion,
04240               PRBool                            digest_p,
04241               nsMsgDeliverMode                  mode,
04242               nsIMsgDBHdr                       *msgToReplace,
04243               nsIMsgSendListener                *aListener,
04244               nsIMsgStatusFeedback              *aStatusFeedback,
04245               const char                        *password
04246               )
04247 {
04248   nsresult      rv;
04249 
04250   /* First thing to do is to reset the send errors report */
04251   mSendReport->Reset();
04252   mSendReport->SetDeliveryMode(mode);
04253 
04254   if (!fields)
04255     return NS_ERROR_INVALID_ARG;
04256 
04257   mStatusFeedback = aStatusFeedback;
04258   //
04259   // First check to see if the external file we are sending is a valid file.
04260   //
04261   if (!sendIFileSpec)
04262     return NS_ERROR_INVALID_ARG;
04263 
04264   PRBool valid;
04265   if (NS_FAILED(sendIFileSpec->IsValid(&valid)))
04266     return NS_ERROR_INVALID_ARG;
04267 
04268   if (!valid)
04269     return NS_ERROR_INVALID_ARG;
04270 
04271   nsFileSpec  *sendFileSpec = nsnull;
04272   nsFileSpec  tempFileSpec;
04273 
04274   if (NS_FAILED(sendIFileSpec->GetFileSpec(&tempFileSpec)))
04275     return NS_ERROR_UNEXPECTED;
04276 
04277   sendFileSpec = new nsFileSpec(tempFileSpec);
04278   if (!sendFileSpec)
04279     return NS_ERROR_OUT_OF_MEMORY;
04280 
04281   // Setup the listener...
04282   mListener = aListener;
04283 
04284   // Should we delete the temp file when done?
04285   if (!deleteSendFileOnCompletion)
04286   {
04287     NS_NewFileSpecWithSpec(*sendFileSpec, &mReturnFileSpec);
04288     if (!mReturnFileSpec)
04289       return NS_ERROR_OUT_OF_MEMORY;
04290   }
04291 
04292   rv = Init(aUserIndentity, aAccountKey, (nsMsgCompFields *)fields, sendFileSpec,
04293             digest_p, PR_FALSE, mode, msgToReplace, 
04294             nsnull, nsnull, nsnull,
04295             nsnull, nsnull,
04296             password, EmptyCString(), nsnull);
04297 
04298   if (NS_SUCCEEDED(rv))
04299     rv = DeliverMessage();
04300 
04301   if (NS_FAILED(rv) && mSendReport)
04302     mSendReport->SetError(nsIMsgSendReport::process_Current, rv, PR_FALSE);
04303 
04304   return rv;
04305 }
04306 
04307 nsMsgAttachmentData *
04308 BuildURLAttachmentData(nsIURI *url)
04309 {
04310   int                 attachCount = 2;  // one entry and one empty entry
04311   nsMsgAttachmentData *attachments = nsnull;
04312   const char          *theName = nsnull;
04313 
04314   if (!url)
04315     return nsnull;    
04316 
04317   attachments = (nsMsgAttachmentData *) PR_Malloc(sizeof(nsMsgAttachmentData) * attachCount);
04318   if (!attachments)
04319     return nsnull;
04320 
04321   // Now get a readable name...
04322   nsCAutoString spec;
04323   url->GetSpec(spec);
04324   if (!spec.IsEmpty())
04325   {
04326     theName = strrchr(spec.get(), '/');
04327   }
04328 
04329   if (!theName)
04330     theName = "Unknown"; // Don't I18N this string...should never happen...
04331   else
04332     theName++;
04333 
04334   memset(attachments, 0, sizeof(nsMsgAttachmentData) * attachCount);
04335   attachments[0].url = url; // The URL to attach. This should be 0 to signify "end of list".
04336   attachments[0].real_name = (char *)PL_strdup(theName);  // The original name of this document, which will eventually show up in the 
04337 
04338   NS_IF_ADDREF(url);
04339   return attachments;
04340 }
04341 
04342 //
04343 // Send the message to the magic folder, and runs the completion/failure
04344 // callback.
04345 //
04346 nsresult
04347 nsMsgComposeAndSend::SendToMagicFolder(nsMsgDeliverMode mode)
04348 {
04349     nsresult rv = MimeDoFCC(mTempFileSpec,
04350                             mode,
04351                             mCompFields->GetBcc(),
04352                             mCompFields->GetFcc(), 
04353                             mCompFields->GetNewspostUrl());
04354     //
04355     // The caller of MimeDoFCC needs to deal with failure.
04356     //
04357     if (NS_FAILED(rv))
04358       rv = NotifyListenerOnStopCopy(rv);
04359     
04360     return rv;
04361 }
04362 
04363 //
04364 // Queues the message for later delivery, and runs the completion/failure
04365 // callback.
04366 //
04367 nsresult
04368 nsMsgComposeAndSend::QueueForLater()
04369 {
04370   return SendToMagicFolder(nsMsgQueueForLater);
04371 }
04372 
04373 //
04374 // Save the message to the Drafts folder, and runs the completion/failure
04375 // callback.
04376 //
04377 nsresult 
04378 nsMsgComposeAndSend::SaveAsDraft()
04379 {
04380   return SendToMagicFolder(nsMsgSaveAsDraft);
04381 }
04382 
04383 //
04384 // Save the message to the Template folder, and runs the completion/failure
04385 // callback.
04386 //
04387 nsresult
04388 nsMsgComposeAndSend::SaveAsTemplate()
04389 {
04390   return SendToMagicFolder(nsMsgSaveAsTemplate);
04391 }
04392 
04393 nsresult
04394 nsMsgComposeAndSend::SaveInSentFolder()
04395 {
04396   return SendToMagicFolder(nsMsgDeliverNow);
04397 }
04398 
04399 char*
04400 nsMsgGetEnvelopeLine(void)
04401 {
04402   static char       result[75] = "";
04403   PRExplodedTime    now;
04404   char              buffer[128] = "";
04405 
04406   // Generate envelope line in format of:  From - Sat Apr 18 20:01:49 1998
04407   //
04408   // Use PR_FormatTimeUSEnglish() to format the date in US English format,
04409   // then figure out what our local GMT offset is, and append it (since
04410   // PR_FormatTimeUSEnglish() can't do that.) Generate four digit years as
04411   // per RFC 1123 (superceding RFC 822.)
04412   //
04413   PR_ExplodeTime(PR_Now(), PR_LocalTimeParameters, &now);
04414   PR_FormatTimeUSEnglish(buffer, sizeof(buffer),
04415                "%a %b %d %H:%M:%S %Y",
04416                &now);
04417   
04418   // This value must be in ctime() format, with English abbreviations.
04419   // PL_strftime("... %c ...") is no good, because it is localized.
04420   //
04421   PL_strcpy(result, "From - ");
04422   PL_strcpy(result + 7, buffer);
04423   PL_strcpy(result + 7 + 24, CRLF);
04424   return result;
04425 }
04426 
04427 nsresult 
04428 nsMsgComposeAndSend::MimeDoFCC(nsFileSpec       *input_file, 
04429                                nsMsgDeliverMode mode,
04430                                const char       *bcc_header,
04431                                const char       *fcc_header,
04432                                const char       *news_url)
04433 {
04434   nsresult      status = NS_OK;
04435   char          *ibuffer = 0;
04436   PRInt32       ibuffer_size = TEN_K;
04437   char          *obuffer = 0;
04438   PRInt32       n;
04439   char          *envelopeLine = nsMsgGetEnvelopeLine();
04440   PRBool        folderIsLocal = PR_TRUE;
04441   char          *turi = nsnull;
04442   PRUnichar     *printfString = nsnull;
04443   nsXPIDLString folderName;
04444   nsXPIDLString msg; 
04445   nsCOMPtr<nsIMsgFolder> folder;
04446 
04447   // Before continuing, just check the user has not cancel the operation
04448   if (mSendProgress)
04449   {
04450     PRBool canceled = PR_FALSE;
04451     mSendProgress->GetProcessCanceledByUser(&canceled);
04452     if (canceled)
04453       return NS_ERROR_ABORT;
04454     else
04455       mSendProgress->OnProgressChange(nsnull, nsnull, 0, 0, 0, -1);
04456   }
04457 
04458   //
04459   // Ok, this is here to keep track of this for 2 copy operations... 
04460   //
04461   if (mCopyFileSpec)
04462   {
04463     mCopyFileSpec2 = mCopyFileSpec;
04464     mCopyFileSpec = nsnull;
04465   }
04466 
04467   //
04468   // Create the file that will be used for the copy service!
04469   //
04470   nsFileSpec *tFileSpec = nsMsgCreateTempFileSpec("nscopy.tmp"); 
04471   if (!tFileSpec)
04472     return NS_ERROR_FAILURE;
04473 
04474   NS_NewFileSpecWithSpec(*tFileSpec, &mCopyFileSpec);
04475   if (!mCopyFileSpec)
04476   {
04477     delete tFileSpec;
04478     return NS_ERROR_INVALID_ARG;
04479   }
04480 
04481   nsOutputFileStream tempOutfile(*tFileSpec, PR_WRONLY | PR_CREATE_FILE, 00600);
04482   delete tFileSpec;
04483   if (! tempOutfile.is_open()) 
04484   {   
04485     if (mSendReport)
04486     {
04487       nsAutoString error_msg;
04488       nsAutoString path;
04489       NS_CopyNativeToUnicode(
04490         nsDependentCString(tFileSpec->GetNativePathCString()), path);
04491       nsMsgBuildErrorMessageByID(NS_MSG_UNABLE_TO_OPEN_TMP_FILE, error_msg, &path, nsnull);
04492       mSendReport->SetMessage(nsIMsgSendReport::process_Current, error_msg.get(), PR_FALSE);
04493     }
04494     status = NS_MSG_UNABLE_TO_OPEN_TMP_FILE;
04495 
04496     NS_RELEASE(mCopyFileSpec);
04497     return status;
04498   }
04499 
04500   //
04501   // Get our files ready...
04502   //
04503   nsInputFileStream inputFile(*input_file);
04504   if (!inputFile.is_open() || CHECK_SIMULATED_ERROR(SIMULATED_SEND_ERROR_2))
04505   {
04506     if (mSendReport)
04507     {
04508       nsAutoString error_msg;
04509       nsAutoString path;
04510       NS_CopyNativeToUnicode(
04511         nsDependentCString(input_file->GetNativePathCString()), path);
04512       nsMsgBuildErrorMessageByID(NS_MSG_UNABLE_TO_OPEN_FILE, error_msg, &path, nsnull);
04513       mSendReport->SetMessage(nsIMsgSendReport::process_Current, error_msg.get(), PR_FALSE);
04514     }
04515     status = NS_MSG_UNABLE_TO_OPEN_FILE;
04516     goto FAIL;
04517   }
04518 
04519   // now the buffers...
04520   ibuffer = nsnull;
04521   while (!ibuffer && (ibuffer_size >= 1024))
04522   {
04523     ibuffer = (char *) PR_Malloc(ibuffer_size);
04524     if (!ibuffer)
04525       ibuffer_size /= 2;
04526   }
04527 
04528   if (!ibuffer)
04529   {
04530     status = NS_ERROR_OUT_OF_MEMORY;
04531     goto FAIL;
04532   }
04533 
04534   //
04535   // First, we we need to put a Berkeley "From - " delimiter at the head of 
04536   // the file for parsing...
04537   //
04538 
04539   (void)GetExistingFolder(fcc_header, getter_AddRefs(folder));
04540   if ((mode == nsMsgDeliverNow || mode == nsMsgSendUnsent) && folder)
04541     turi = PL_strdup(fcc_header);
04542   else
04543     turi = GetFolderURIFromUserPrefs(mode, mUserIdentity);
04544   status = MessageFolderIsLocal(mUserIdentity, mode, turi, &folderIsLocal);
04545   if (NS_FAILED(status))
04546     goto FAIL;
04547 
04548   // Tell the user we are copying the message... 
04549   mComposeBundle->GetStringByID(NS_MSG_START_COPY_MESSAGE, getter_Copies(msg));
04550   if (msg)
04551   {
04552     nsCOMPtr<nsIRDFService> rdfService = do_GetService(kRDFServiceCID);
04553     if (rdfService)
04554     {
04555       nsCOMPtr<nsIRDFResource> res;
04556       rdfService->GetResource(nsDependentCString(turi), getter_AddRefs(res));
04557       nsCOMPtr<nsIMsgFolder> folder = do_QueryInterface(res);
04558       if (folder)
04559         folder->GetName(getter_Copies(folderName));
04560     }
04561     if (!folderName.IsEmpty())
04562       printfString = nsTextFormatter::smprintf(msg, folderName.get());
04563     else
04564       printfString = nsTextFormatter::smprintf(msg, "?");
04565     if (printfString)
04566     {
04567       SetStatusMessage(printfString); 
04568       PR_Free(printfString);  
04569     }
04570   }
04571 
04572   if ( (envelopeLine) && (folderIsLocal) )
04573   {
04574     PRInt32   len = PL_strlen(envelopeLine);
04575     
04576     n = tempOutfile.write(envelopeLine, len);
04577     if (n != len)
04578     {
04579       status = NS_ERROR_FAILURE;
04580       goto FAIL;
04581     }
04582   }
04583 
04584   //
04585   // Write out an X-Mozilla-Status header.
04586   //
04587   // This is required for the queue file, so that we can overwrite it once
04588   // the messages have been delivered, and so that the MSG_FLAG_QUEUED bit
04589   // is set.
04590   //
04591   // For FCC files, we don't necessarily need one, but we might as well put
04592   // one in so that it's marked as read already.
04593   //
04594   //
04595   // Need to add these lines for POP3 ONLY! IMAP servers will handle
04596   // this status information for summary file regeneration for us. 
04597   if ( (mode == nsMsgQueueForLater  || mode == nsMsgSaveAsDraft ||
04598         mode == nsMsgSaveAsTemplate || mode == nsMsgDeliverNow ||
04599         mode == nsMsgSendUnsent) && folderIsLocal)
04600   {
04601     char       *buf = 0;
04602     PRUint16   flags = 0;
04603     
04604     // for save as draft and send later, we want to leave the message as unread.
04605     // See Bug #198087
04606     if (mode == nsMsgQueueForLater)
04607       flags |= MSG_FLAG_QUEUED;
04608     else if (mode != nsMsgSaveAsDraft)
04609       flags |= MSG_FLAG_READ;
04610     buf = PR_smprintf(X_MOZILLA_STATUS_FORMAT CRLF, flags);
04611     if (buf)
04612     {
04613       PRInt32   len = PL_strlen(buf);
04614       n = tempOutfile.write(buf, len);
04615       PR_Free(buf);
04616       if (n != len)
04617       {
04618         status = NS_ERROR_FAILURE;
04619         goto FAIL;
04620       }
04621     }
04622     
04623     PRUint32 flags2 = 0;
04624     if (mode == nsMsgSaveAsTemplate)
04625       flags2 |= MSG_FLAG_TEMPLATE;
04626     if (mode == nsMsgDeliverNow || mode == nsMsgSendUnsent) 
04627     {
04628       flags2 &= ~MSG_FLAG_MDN_REPORT_NEEDED;
04629       flags2 |= MSG_FLAG_MDN_REPORT_SENT;
04630     }
04631     buf = PR_smprintf(X_MOZILLA_STATUS2_FORMAT CRLF, flags2);
04632     if (buf)
04633     {
04634       PRInt32   len = PL_strlen(buf);
04635       n = tempOutfile.write(buf, len);
04636       PR_Free(buf);
04637       if (n != len)
04638       {
04639         status = NS_ERROR_FAILURE;
04640         goto FAIL;
04641       }
04642     }
04643     n = tempOutfile.write(X_MOZILLA_KEYWORDS, sizeof(X_MOZILLA_KEYWORDS) - 1);
04644   }
04645 
04646   // Write out the FCC and BCC headers.
04647   // When writing to the Queue file, we *must* write the FCC and BCC
04648   // headers, or else that information would be lost.  Because, when actually
04649   // delivering the message (with "deliver now") we do FCC/BCC right away;
04650   // but when queueing for later delivery, we do FCC/BCC at delivery-time.
04651   //
04652   // The question remains of whether FCC and BCC should be written into normal
04653   // BCC folders (like the Sent Mail folder.)
04654   //
04655   // For FCC, there seems no point to do that; it's not information that one
04656   // would want to refer back to.
04657   //
04658   // For BCC, the question isn't as clear.  On the one hand, if I send someone
04659   // a BCC'ed copy of the message, and save a copy of it for myself (with FCC)
04660   // I might want to be able to look at that message later and see the list of
04661   // people to whom I had BCC'ed it.
04662   //
04663   // On the other hand, the contents of the BCC header is sensitive
04664   // information, and should perhaps not be stored at all.
04665   //
04666   // Thus the consultation of the #define SAVE_BCC_IN_FCC_FILE.
04667   //
04668   // (Note that, if there is a BCC header present in a message in some random
04669   // folder, and that message is forwarded to someone, then the attachment
04670   // code will strip out the BCC header before forwarding it.)
04671   //
04672   if ((mode == nsMsgQueueForLater || mode == nsMsgSaveAsDraft ||
04673        mode == nsMsgSaveAsTemplate) && fcc_header && *fcc_header)
04674   {
04675     PRInt32 L = PL_strlen(fcc_header) + 20;
04676     char  *buf = (char *) PR_Malloc (L);
04677     if (!buf)
04678     {
04679       status = NS_ERROR_OUT_OF_MEMORY;
04680       goto FAIL;
04681     }
04682 
04683     PR_snprintf(buf, L-1, "FCC: %s" CRLF, fcc_header);
04684 
04685     PRInt32   len = PL_strlen(buf);
04686     n = tempOutfile.write(buf, len);
04687     if (n != len)
04688     {
04689       status = NS_ERROR_FAILURE;
04690       goto FAIL;
04691     }
04692   }
04693 
04694   //
04695   // Ok, now I want to get the identity key and write it out if this is for a
04696   // nsMsgQueueForLater operation!
04697   //
04698   if (  (  ( nsMsgQueueForLater == mode )
04699         || ( nsMsgSaveAsDraft == mode )
04700         || ( nsMsgSaveAsTemplate == mode )
04701         )
04702      && ( mUserIdentity )
04703      )
04704   {
04705     char *buf = nsnull, *key = nsnull;
04706 
04707     if (NS_SUCCEEDED(mUserIdentity->GetKey(&key)) && (key))
04708     {
04709       buf = PR_smprintf(HEADER_X_MOZILLA_IDENTITY_KEY ": %s" CRLF, key);
04710       if (buf)
04711       {
04712         PRInt32 len = strlen(buf);
04713         n = tempOutfile.write(buf, len);
04714         PR_Free(buf);
04715         if (n != len)
04716         {
04717           status = NS_ERROR_FAILURE;
04718           goto FAIL;
04719         }
04720       }
04721     }
04722 
04723     if (!mAccountKey.IsEmpty())
04724     {
04725       buf = PR_smprintf(HEADER_X_MOZILLA_ACCOUNT_KEY ": %s" CRLF, mAccountKey.get());
04726       if (buf)
04727       {
04728         PRInt32 len = strlen(buf);
04729         n = tempOutfile.write(buf, len);
04730         PR_Free(buf);
04731         if (n != len)
04732         {
04733           status = NS_ERROR_FAILURE;
04734           goto FAIL;
04735         }
04736       }
04737     }
04738   }
04739 
04740   if (bcc_header && *bcc_header
04741 #ifndef SAVE_BCC_IN_FCC_FILE
04742       && (mode == MSG_QueueForLater || mode == MSG_SaveAsDraft ||
04743           mode == MSG_SaveAsTemplate)
04744 #endif
04745     )
04746   {
04747     char *convBcc;
04748     convBcc = nsMsgI18NEncodeMimePartIIStr(bcc_header, PR_TRUE,
04749                     mCompFields->GetCharacterSet(), sizeof("BCC: "),
04750                     nsMsgMIMEGetConformToStandard());
04751 
04752     PRInt32 L = strlen(convBcc ? convBcc : bcc_header) + 20;
04753     char *buf = (char *) PR_Malloc (L);
04754     if (!buf)
04755     {
04756       status = NS_ERROR_OUT_OF_MEMORY;
04757       goto FAIL;
04758     }
04759 
04760     PR_snprintf(buf, L-1, "BCC: %s" CRLF, convBcc ? convBcc : bcc_header);
04761     PRInt32   len = strlen(buf);
04762     n = tempOutfile.write(buf, len);
04763     PR_Free(buf);
04764     PR_Free(convBcc);
04765     if (n != len)
04766     {
04767       status = NS_ERROR_FAILURE;
04768       goto FAIL;
04769     }
04770   }
04771 
04772   //
04773   // Write out the X-Mozilla-News-Host header.
04774   // This is done only when writing to the queue file, not the FCC file.
04775   // We need this to complement the "Newsgroups" header for the case of
04776   // queueing a message for a non-default news host.
04777   //
04778   // Convert a URL like "snews://host:123/" to the form "host:123/secure"
04779   // or "news://user@host:222" to simply "host:222".
04780   //
04781   if ((mode == nsMsgQueueForLater || mode == nsMsgSaveAsDraft ||
04782        mode == nsMsgSaveAsTemplate) && news_url && *news_url)
04783   {
04784     PRBool secure_p = (news_url[0] == 's' || news_url[0] == 'S');
04785     char *orig_hap = nsMsgParseURLHost (news_url);
04786     char *host_and_port = orig_hap;
04787     if (host_and_port)
04788     {
04789       // There may be authinfo at the front of the host - it could be of
04790       // the form "user:password@host:port", so take off everything before
04791       // the first at-sign.  We don't want to store authinfo in the queue
04792       // folder, I guess, but would want it to be re-prompted-for at
04793       // delivery-time.
04794       //
04795       char *at = PL_strchr (host_and_port, '@');
04796       if (at)
04797         host_and_port = at + 1;
04798     }
04799 
04800     if ((host_and_port && *host_and_port) || !secure_p)
04801     {
04802       char *line = PR_smprintf(X_MOZILLA_NEWSHOST ": %s%s" CRLF,
04803                    host_and_port ? host_and_port : "",
04804                    secure_p ? "/secure" : "");
04805       PR_FREEIF(orig_hap);
04806       if (!line)
04807       {
04808         status = NS_ERROR_OUT_OF_MEMORY;
04809         goto FAIL;
04810       }
04811 
04812       PRInt32   len = PL_strlen(line);
04813       n = tempOutfile.write(line, len);
04814       PR_Free(line);
04815       if (n != len)
04816       {
04817         status = NS_ERROR_FAILURE;
04818         goto FAIL;
04819       }
04820     }
04821 
04822     PR_Free(orig_hap);
04823   }
04824 
04825   //
04826   // Read from the message file, and write to the FCC or Queue file.
04827   // There are two tricky parts: the first is that the message file
04828   // uses CRLF, and the FCC file should use LINEBREAK.  The second
04829   // is that the message file may have lines beginning with "From "
04830   // but the FCC file must have those lines mangled.
04831   //
04832   // It's unfortunate that we end up writing the FCC file a line
04833   // at a time, but it's the easiest way...
04834   //
04835   while (! inputFile.eof())
04836   {
04837     // check *ibuffer in case that ibuffer isn't big enough
04838     if (!inputFile.readline(ibuffer, ibuffer_size) && *ibuffer == 0)
04839     {
04840       status = NS_ERROR_FAILURE;
04841       goto FAIL;
04842     }
04843 
04844     n =  tempOutfile.write(ibuffer, PL_strlen(ibuffer));
04845     n += tempOutfile.write(CRLF, 2);
04846     if (n != (PRInt32) (PL_strlen(ibuffer) + 2)) // write failed 
04847     {
04848       status = NS_MSG_ERROR_WRITING_FILE;
04849       goto FAIL;
04850     }
04851   }
04852 
04853   //
04854   // Terminate with a final newline. 
04855   //
04856   n = tempOutfile.write(CRLF, 2);
04857   if (n != 2) // write failed 
04858   {
04859     status = NS_MSG_ERROR_WRITING_FILE;
04860     goto FAIL;
04861   }
04862 
04863 FAIL:
04864   PR_Free(ibuffer);
04865   if (obuffer != ibuffer)
04866     PR_Free(obuffer);
04867 
04868 
04869   if (tempOutfile.is_open()) 
04870   {
04871     if (NS_FAILED(tempOutfile.flush()) || tempOutfile.failed())
04872       status = NS_MSG_ERROR_WRITING_FILE;
04873 
04874     tempOutfile.close();
04875     if (mCopyFileSpec)
04876       mCopyFileSpec->CloseStream();
04877   }
04878 
04879   if (inputFile.is_open()) 
04880     inputFile.close();
04881 
04882   // 
04883   // When we get here, we have to see if we have been successful so far.
04884   // If we have, then we should start up the async copy service operation.
04885   // If we weren't successful, then we should just return the error and 
04886   // bail out.
04887   //
04888   if (NS_SUCCEEDED(status))
04889   {
04890     //
04891     // If we are here, time to start the async copy service operation!
04892     //
04893     status = StartMessageCopyOperation(mCopyFileSpec, mode, turi);
04894   }
04895   PR_Free(turi);
04896   return status;
04897 }
04898 
04899 //
04900 // This is pretty much a wrapper to the functionality that lives in the 
04901 // nsMsgCopy class
04902 //
04903 nsresult 
04904 nsMsgComposeAndSend::StartMessageCopyOperation(nsIFileSpec        *aFileSpec, 
04905                                                nsMsgDeliverMode   mode,
04906                                                char             *dest_uri)
04907 {
04908   mCopyObj = new nsMsgCopy();
04909   if (!mCopyObj)
04910     return NS_ERROR_OUT_OF_MEMORY;
04911   NS_ADDREF(mCopyObj);
04912   //
04913   // Actually, we need to pick up the proper folder from the prefs and not
04914   // default to the default "Flagged" folder choices
04915   //
04916   nsresult    rv;
04917   if (dest_uri && *dest_uri)
04918     m_folderName = dest_uri;
04919   else
04920     m_folderName = GetFolderURIFromUserPrefs(mode, mUserIdentity);
04921 
04922   if (mListener)
04923     mListener->OnGetDraftFolderURI(m_folderName.get());
04924 
04925   rv = mCopyObj->StartCopyOperation(mUserIdentity, aFileSpec, mode, 
04926                                     this, m_folderName.get(), mMsgToReplace);
04927   return rv;
04928 }
04929 
04930 //I'm getting this each time without holding onto the feedback so that 3 pane windows can be closed
04931 //without any chance of crashing due to holding onto a deleted feedback.
04932 nsresult
04933 nsMsgComposeAndSend::SetStatusMessage(const PRUnichar *aMsgString)
04934 {
04935   if (mSendProgress)
04936     mSendProgress->OnStatusChange(nsnull, nsnull, 0, aMsgString);
04937   return NS_OK;
04938 }
04939 
04940 // For GUI notification...
04941 nsresult
04942 nsMsgComposeAndSend::SetGUINotificationState(PRBool aEnableFlag)
04943 {
04944   mGUINotificationEnabled = aEnableFlag;
04945   return NS_OK;
04946 }
04947 
04948 /* readonly attribute nsIMsgSendReport sendReport; */
04949 NS_IMETHODIMP
04950 nsMsgComposeAndSend::GetSendReport(nsIMsgSendReport * *aSendReport)
04951 {
04952   NS_ENSURE_ARG_POINTER(aSendReport);
04953   NS_IF_ADDREF(*aSendReport = mSendReport);
04954   return NS_OK;
04955 }
04956 
04957 nsresult nsMsgComposeAndSend::Abort()
04958 {
04959   PRUint32 i;
04960   nsresult rv;
04961   
04962   if (mAbortInProcess)
04963     return NS_OK;
04964     
04965   mAbortInProcess = PR_TRUE;
04966       
04967   if (m_plaintext)
04968     rv = m_plaintext->Abort();
04969   
04970   if (m_attachments)
04971   {
04972     for (i = 0; i < m_attachment_count; i ++)
04973     {
04974       nsMsgAttachmentHandler *ma = &m_attachments[i];
04975       if (ma)
04976         rv = ma->Abort();
04977     }
04978   }
04979 
04980   /* stop the current running url */
04981   if (mRunningRequest)
04982   {
04983     mRunningRequest->Cancel(NS_ERROR_ABORT);
04984     mRunningRequest = nsnull;
04985   }
04986   
04987   if (mCopyObj)
04988   {
04989     nsCOMPtr<nsIMsgCopyService> copyService = do_GetService(NS_MSGCOPYSERVICE_CONTRACTID, &rv);
04990     NS_ENSURE_SUCCESS(rv, rv);
04991     copyService->NotifyCompletion(mCopyFileSpec, mCopyObj->mDstFolder, NS_ERROR_ABORT);
04992   }
04993   mAbortInProcess = PR_FALSE;
04994   return NS_OK;
04995 }
04996 
04997 NS_IMETHODIMP nsMsgComposeAndSend::GetProcessAttachmentsSynchronously(PRBool *_retval)
04998 {
04999   NS_ENSURE_ARG(_retval);
05000   *_retval = m_be_synchronous_p;
05001   return NS_OK;
05002 }
05003 
05004 NS_IMETHODIMP nsMsgComposeAndSend::GetAttachmentHandlers(nsMsgAttachmentHandler * *_retval)
05005 {
05006   NS_ENSURE_ARG(_retval);
05007   *_retval = m_attachments;
05008   return NS_OK;
05009 }
05010 
05011 NS_IMETHODIMP nsMsgComposeAndSend::GetAttachmentCount(PRUint32 *aAttachmentCount)
05012 {
05013   NS_ENSURE_ARG(aAttachmentCount);
05014   *aAttachmentCount = m_attachment_count;
05015   return NS_OK;
05016 }
05017 
05018 NS_IMETHODIMP nsMsgComposeAndSend::GetPendingAttachmentCount(PRUint32 *aPendingAttachmentCount)
05019 {
05020   NS_ENSURE_ARG(aPendingAttachmentCount);
05021   *aPendingAttachmentCount = m_attachment_pending_count;
05022   return NS_OK;
05023 }
05024 NS_IMETHODIMP nsMsgComposeAndSend::SetPendingAttachmentCount(PRUint32 aPendingAttachmentCount)
05025 {
05026   m_attachment_pending_count = aPendingAttachmentCount;
05027   return NS_OK;
05028 }
05029 
05030 NS_IMETHODIMP nsMsgComposeAndSend::GetDeliveryMode(nsMsgDeliverMode *aDeliveryMode)
05031 {
05032   NS_ENSURE_ARG(aDeliveryMode);
05033   *aDeliveryMode = m_deliver_mode;
05034   return NS_OK;
05035 }
05036 
05037 NS_IMETHODIMP nsMsgComposeAndSend::GetProgress(nsIMsgProgress **_retval)
05038 {
05039   NS_ENSURE_ARG(_retval);
05040   NS_IF_ADDREF(*_retval = mSendProgress);
05041   return NS_OK;
05042 }
05043 
05044 NS_IMETHODIMP nsMsgComposeAndSend::GetOutputStream(nsOutputFileStream * *_retval)
05045 {
05046   NS_ENSURE_ARG(_retval);
05047   *_retval = mOutputFile;
05048   return NS_OK;
05049 }
05050 
05051 
05052 /* [noscript] attribute nsIURI runningURL; */
05053 NS_IMETHODIMP nsMsgComposeAndSend::GetRunningRequest(nsIRequest **request)
05054 {
05055   NS_ENSURE_ARG(request);
05056   NS_IF_ADDREF(*request = mRunningRequest);
05057   return NS_OK;
05058 }
05059 NS_IMETHODIMP nsMsgComposeAndSend::SetRunningRequest(nsIRequest *request)
05060 {
05061   mRunningRequest = request;
05062   return NS_OK;
05063 }
05064 
05065 NS_IMETHODIMP nsMsgComposeAndSend::GetStatus(nsresult *aStatus)
05066 {
05067   NS_ENSURE_ARG(aStatus);
05068   *aStatus = m_status;
05069   return NS_OK;
05070 }
05071 
05072 NS_IMETHODIMP nsMsgComposeAndSend::SetStatus(nsresult aStatus)
05073 {
05074   m_status = aStatus;
05075   return NS_OK;
05076 }
05077 
05078 NS_IMETHODIMP nsMsgComposeAndSend::GetCryptoclosure(nsIMsgComposeSecure ** aCryptoclosure)
05079 {
05080   NS_ENSURE_ARG(aCryptoclosure);
05081   NS_IF_ADDREF(*aCryptoclosure = m_crypto_closure);
05082   return NS_OK;
05083 }
05084 
05085 NS_IMETHODIMP nsMsgComposeAndSend::SetCryptoclosure(nsIMsgComposeSecure * aCryptoclosure)
05086 {
05087   m_crypto_closure = aCryptoclosure;
05088   return NS_OK;
05089 }
05090