summaryrefslogtreecommitdiffstats
path: root/mailnews/compose/src/nsMsgSend.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'mailnews/compose/src/nsMsgSend.cpp')
-rw-r--r--mailnews/compose/src/nsMsgSend.cpp5218
1 files changed, 5218 insertions, 0 deletions
diff --git a/mailnews/compose/src/nsMsgSend.cpp b/mailnews/compose/src/nsMsgSend.cpp
new file mode 100644
index 000000000..c0f74e11c
--- /dev/null
+++ b/mailnews/compose/src/nsMsgSend.cpp
@@ -0,0 +1,5218 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+#include "nsMsgSend.h"
+#include "prmem.h"
+#include "nsMsgLocalFolderHdrs.h"
+#include "nsMsgSendPart.h"
+#include "nsMsgBaseCID.h"
+#include "nsMsgNewsCID.h"
+#include "nsISmtpService.h" // for actually sending the message...
+#include "nsINntpService.h" // for actually posting the message...
+#include "nsIMsgMailSession.h"
+#include "nsIMsgIdentity.h"
+#include "nsIPrefService.h"
+#include "nsIPrefBranch.h"
+#include "nsIMsgMailNewsUrl.h"
+#include "nsMsgCompUtils.h"
+#include "nsMsgI18N.h"
+#include "nsICharsetConverterManager.h"
+#include "nsIMsgSendListener.h"
+#include "nsIMsgCopyServiceListener.h"
+#include "nsIFile.h"
+#include "nsIURL.h"
+#include "nsNetUtil.h"
+#include "nsIFileURL.h"
+#include "nsMsgCopy.h"
+#include "nsUnicharUtils.h"
+#include "nsMsgPrompts.h"
+#include "nsIDOMHTMLBodyElement.h"
+#include "nsIDOMHTMLImageElement.h"
+#include "nsIDOMHTMLLinkElement.h"
+#include "nsIDOMHTMLAnchorElement.h"
+#include "nsCExternalHandlerService.h"
+#include "nsIMIMEService.h"
+#include "nsIDocument.h"
+#include "nsIDOMDocument.h"
+#include "nsMsgCompCID.h"
+#include "nsIAbAddressCollector.h"
+#include "nsAbBaseCID.h"
+#include "nsCOMPtr.h"
+#include "mozITXTToHTMLConv.h"
+#include "nsIMsgStatusFeedback.h"
+#include "nsIMsgWindow.h"
+#include "nsTextFormatter.h"
+#include "nsIPrompt.h"
+#include "nsMailHeaders.h"
+#include "nsIDocShell.h"
+#include "nsMimeTypes.h"
+#include "nsISmtpUrl.h"
+#include "nsIInterfaceRequestor.h"
+#include "nsIInterfaceRequestorUtils.h"
+#include "nsIEditorMailSupport.h"
+#include "nsIDocumentEncoder.h" // for editor output flags
+#include "nsILoadGroup.h"
+#include "nsMsgSendReport.h"
+#include "nsNetCID.h"
+#include "nsError.h"
+#include "nsMsgUtils.h"
+#include "nsIMsgMdnGenerator.h"
+#include "nsISmtpServer.h"
+#include "nsIRDFService.h"
+#include "nsRDFCID.h"
+#include "nsIMsgAccountManager.h"
+#include "nsNativeCharsetUtils.h"
+#include "nsIAbCard.h"
+#include "nsIMsgAttachment.h"
+#include "nsIMsgProgress.h"
+#include "nsIMsgMessageService.h"
+#include "nsIMsgHdr.h"
+#include "nsIMsgFolder.h"
+#include "nsComposeStrings.h"
+#include "nsStringGlue.h"
+#include "nsMsgUtils.h"
+#include "nsIArray.h"
+#include "nsArrayUtils.h"
+#include "mozilla/Services.h"
+#include "mozilla/Attributes.h"
+#include "mozilla/mailnews/MimeEncoder.h"
+#include "mozilla/mailnews/MimeHeaderParser.h"
+#include "nsIMutableArray.h"
+#include "nsIMsgFilterService.h"
+#include "nsIMsgProtocolInfo.h"
+#include "mozIDOMWindow.h"
+#include "mozilla/Preferences.h"
+
+using namespace mozilla;
+using namespace mozilla::mailnews;
+
+static NS_DEFINE_CID(kRDFServiceCID, NS_RDFSERVICE_CID);
+
+#define PREF_MAIL_SEND_STRUCT "mail.send_struct"
+#define PREF_MAIL_STRICTLY_MIME "mail.strictly_mime"
+#define PREF_MAIL_MESSAGE_WARNING_SIZE "mailnews.message_warning_size"
+#define PREF_MAIL_COLLECT_EMAIL_ADDRESS_OUTGOING "mail.collect_email_address_outgoing"
+
+#define ATTR_MOZ_DO_NOT_SEND "moz-do-not-send"
+
+enum { kDefaultMode = (PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE) };
+
+static bool mime_use_quoted_printable_p = false;
+
+//
+// Ugh, we need to do this currently to access this boolean.
+//
+bool
+UseQuotedPrintable(void)
+{
+ return mime_use_quoted_printable_p;
+}
+
+/* This function will parse a list of email addresses and groups and just
+ * return a list of email addresses (recipient)
+ *
+ * The input could be:
+ * [recipient | group] *[,recipient | group]
+ *
+ * The group syntax is:
+ * group-name:[recipient *[,recipient]];
+ *
+ * the output will be:
+ * recipient *[, recipient]
+ *
+ * As the result will always be equal or smaller than the input string,
+ * the extraction will be made in place. Don't need to create a new buffer.
+ */
+static nsresult StripOutGroupNames(char * addresses)
+{
+ char aChar;
+ char * readPtr = addresses; // current read position
+ char * writePtr = addresses; // current write position
+ char * previousSeparator = addresses; // remember last time we wrote a recipient separator
+ char * endPtr = addresses + PL_strlen(addresses);
+
+ bool quoted = false; // indicate if we are between double quote
+ bool group = false; // indicate if we found a group prefix
+ bool atFound = false; // indicate if we found an @ in the current recipient. group name should not have an @
+
+ while (readPtr < endPtr)
+ {
+ aChar = *readPtr;
+ readPtr ++;
+ switch(aChar)
+ {
+ case '\\':
+ if (*readPtr == '"') //ignore escaped quote
+ readPtr ++;
+ continue;
+
+ case '"':
+ quoted = !quoted;
+ break;
+
+ case '@':
+ if (!quoted)
+ atFound = true;
+ break;
+
+ case ':':
+ if (!quoted && !atFound)
+ {
+ // ok, we found a group name
+ // let's backup the write cursor to remove the group name
+ writePtr = previousSeparator + 1;
+ group = true;
+ continue;
+ }
+ break;
+
+ case ';':
+ if (quoted || !group)
+ break;
+ else
+ group = false;
+ //end of the group, act like a recipient separator now...
+ /* NO BREAK */
+ MOZ_FALLTHROUGH;
+ case ',':
+ if (!quoted)
+ {
+ atFound = false;
+ //let check if we already have a comma separator in the output string
+ if (writePtr > addresses && *(writePtr - 1) == ',')
+ writePtr --;
+ *writePtr = ',';
+ previousSeparator = writePtr;
+ writePtr ++;
+ continue;
+ }
+ break;
+ }
+ *writePtr = aChar;
+ writePtr ++;
+ }
+
+ if (writePtr > addresses && *(writePtr - 1) == ',')
+ writePtr --;
+ *writePtr = '\0';
+
+ return NS_OK;
+}
+
+
+// This private class just provides us an external URL listener, with callback functionality.
+
+class MsgDeliveryListener : public nsIUrlListener
+{
+public:
+ MsgDeliveryListener(nsIMsgSend *aMsgSend, bool inIsNewsDelivery);
+
+ NS_DECL_ISUPPORTS
+ NS_DECL_NSIURLLISTENER
+
+private:
+ virtual ~MsgDeliveryListener();
+ nsCOMPtr<nsIMsgSend> mMsgSend;
+ bool mIsNewsDelivery;
+};
+
+NS_IMPL_ISUPPORTS(MsgDeliveryListener, nsIUrlListener)
+
+MsgDeliveryListener::MsgDeliveryListener(nsIMsgSend *aMsgSend, bool inIsNewsDelivery)
+{
+ mMsgSend = aMsgSend;
+ mIsNewsDelivery = inIsNewsDelivery;
+}
+
+MsgDeliveryListener::~MsgDeliveryListener()
+{
+}
+
+NS_IMETHODIMP MsgDeliveryListener::OnStartRunningUrl(nsIURI *url)
+{
+ if (mMsgSend)
+ mMsgSend->NotifyListenerOnStartSending(nullptr, 0);
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP MsgDeliveryListener::OnStopRunningUrl(nsIURI *url, nsresult aExitCode)
+{
+ if (url)
+ {
+ nsCOMPtr<nsIMsgMailNewsUrl> mailUrl = do_QueryInterface(url);
+ if (mailUrl)
+ mailUrl->UnRegisterListener(this);
+ }
+
+ // Let mMsgSend sort out the OnStopSending notification - it knows more about
+ // the messages than we do.
+ if (mMsgSend)
+ mMsgSend->SendDeliveryCallback(url, mIsNewsDelivery, aExitCode);
+
+ return NS_OK;
+}
+
+
+/* the following macro actually implement addref, release and query interface for our component. */
+NS_IMPL_ISUPPORTS(nsMsgComposeAndSend, nsIMsgSend, nsIMsgOperationListener,
+ nsISupportsWeakReference)
+
+nsMsgComposeAndSend::nsMsgComposeAndSend() :
+ m_messageKey(nsMsgKey_None)
+{
+ mGUINotificationEnabled = true;
+ mAbortInProcess = false;
+ mMultipartRelatedAttachmentCount = -1;
+ mSendMailAlso = false;
+
+ m_dont_deliver_p = false;
+ m_deliver_mode = nsMsgDeliverNow;
+
+ m_pre_snarfed_attachments_p = false;
+ m_digest_p = false;
+ m_be_synchronous_p = false;
+ m_attachment1_type = 0;
+ m_attachment1_encoding = 0;
+ m_attachment1_body = 0;
+ m_attachment1_body_length = 0;
+ m_attachment_count = 0;
+ m_attachment_pending_count = 0;
+ m_status = NS_OK;
+ m_plaintext = nullptr;
+ m_related_part = nullptr;
+ m_related_body_part = nullptr;
+ mOriginalHTMLBody = nullptr;
+
+ mNeedToPerformSecondFCC = false;
+ mPerformingSecondFCC = false;
+
+ mPreloadedAttachmentCount = 0;
+ mRemoteAttachmentCount = 0;
+ mCompFieldLocalAttachments = 0;
+ mCompFieldRemoteAttachments = 0;
+ mMessageWarningSize = 0;
+
+ mSendReport = new nsMsgSendReport();
+}
+
+nsMsgComposeAndSend::~nsMsgComposeAndSend()
+{
+ PR_Free(m_attachment1_type);
+ PR_Free(m_attachment1_encoding);
+ PR_Free(m_attachment1_body);
+ PR_Free(mOriginalHTMLBody);
+
+ if (m_plaintext)
+ {
+ if (m_plaintext->mTmpFile)
+ m_plaintext->mTmpFile->Remove(false);
+
+ m_plaintext = nullptr;
+ }
+
+ if (mHTMLFile)
+ mHTMLFile->Remove(false);
+
+ if (mCopyFile)
+ mCopyFile->Remove(false);
+
+ if (mCopyFile2)
+ mCopyFile2->Remove(false);
+
+ if (mTempFile && !mReturnFile)
+ mTempFile->Remove(false);
+
+ m_attachments.Clear();
+}
+
+NS_IMETHODIMP nsMsgComposeAndSend::GetDefaultPrompt(nsIPrompt ** aPrompt)
+{
+ NS_ENSURE_ARG(aPrompt);
+ *aPrompt = nullptr;
+
+ nsresult rv = NS_OK;
+
+ if (mParentWindow)
+ {
+ rv = mParentWindow->GetPrompter(aPrompt);
+ if (NS_SUCCEEDED(rv) && *aPrompt)
+ return NS_OK;
+ }
+
+ /* If we cannot find a prompter, try the mail3Pane window */
+ nsCOMPtr<nsIMsgWindow> msgWindow;
+ nsCOMPtr <nsIMsgMailSession> mailSession (do_GetService(NS_MSGMAILSESSION_CONTRACTID));
+ if (mailSession)
+ {
+ mailSession->GetTopmostMsgWindow(getter_AddRefs(msgWindow));
+ if (msgWindow)
+ rv = msgWindow->GetPromptDialog(aPrompt);
+ }
+
+ return rv;
+}
+
+nsresult nsMsgComposeAndSend::GetNotificationCallbacks(nsIInterfaceRequestor** aCallbacks)
+{
+// TODO: stop using mail3pane window!
+ nsCOMPtr<nsIMsgWindow> msgWindow;
+ nsCOMPtr<nsIMsgMailSession> mailSession(do_GetService(NS_MSGMAILSESSION_CONTRACTID));
+ mailSession->GetTopmostMsgWindow(getter_AddRefs(msgWindow));
+ if (msgWindow) {
+ nsCOMPtr<nsIDocShell> docShell;
+ msgWindow->GetRootDocShell(getter_AddRefs(docShell));
+ nsCOMPtr<nsIInterfaceRequestor> ir(do_QueryInterface(docShell));
+ nsCOMPtr<nsIInterfaceRequestor> notificationCallbacks;
+ msgWindow->GetNotificationCallbacks(getter_AddRefs(notificationCallbacks));
+ if (notificationCallbacks) {
+ nsCOMPtr<nsIInterfaceRequestor> aggregrateIR;
+ MsgNewInterfaceRequestorAggregation(notificationCallbacks, ir, getter_AddRefs(aggregrateIR));
+ ir = aggregrateIR;
+ }
+ if (ir) {
+ NS_ADDREF(*aCallbacks = ir);
+ return NS_OK;
+ }
+ }
+ return NS_ERROR_FAILURE;
+}
+
+
+static char *mime_mailto_stream_read_buffer = 0;
+static char *mime_mailto_stream_write_buffer = 0;
+
+
+char * mime_get_stream_write_buffer(void)
+{
+ if (!mime_mailto_stream_write_buffer)
+ mime_mailto_stream_write_buffer = (char *) PR_Malloc(MIME_BUFFER_SIZE);
+ return mime_mailto_stream_write_buffer;
+}
+
+static bool isEmpty(const char* aString)
+{
+ return (!aString) || (!*aString);
+}
+
+void nsMsgComposeAndSend::GenerateMessageId()
+{
+ if (isEmpty(mCompFields->GetMessageId()))
+ {
+ if (isEmpty(mCompFields->GetTo()) &&
+ isEmpty(mCompFields->GetCc()) &&
+ isEmpty(mCompFields->GetBcc()) &&
+ !isEmpty(mCompFields->GetNewsgroups()))
+ {
+ bool generateNewsMessageId = false;
+ mUserIdentity->GetBoolAttribute("generate_news_message_id", &generateNewsMessageId);
+ if (!generateNewsMessageId)
+ return;
+ }
+
+ char* msgID = msg_generate_message_id(mUserIdentity);
+ mCompFields->SetMessageId(msgID);
+ PR_Free(msgID);
+ }
+}
+
+// Don't I18N this line...this is per the spec!
+#define MIME_MULTIPART_BLURB "This is a multi-part message in MIME format."
+
+/* All of the desired attachments have been written to individual temp files,
+ and we know what's in them. Now we need to make a final temp file of the
+ actual mail message, containing all of the other files after having been
+ encoded as appropriate.
+ */
+NS_IMETHODIMP
+nsMsgComposeAndSend::GatherMimeAttachments()
+{
+ bool shouldDeleteDeliveryState = true;
+ nsresult status;
+ uint32_t i;
+ PRFileDesc *in_file = 0;
+ char *buffer = 0;
+ nsString msg;
+ bool body_is_us_ascii = true;
+ bool isUsingQP = false;
+
+ nsMsgSendPart* toppart = nullptr; // The very top most container of the message
+ // that we are going to send.
+
+ nsMsgSendPart* mainbody = nullptr; // The leaf node that contains the text of the
+ // message we're going to contain.
+
+ nsMsgSendPart* maincontainer = nullptr; // The direct child of toppart that will
+ // contain the mainbody. If mainbody is
+ // the same as toppart, then this is
+ // also the same. But if mainbody is
+ // to end up somewhere inside of a
+ // multipart/alternative or a
+ // multipart/related, then this is that
+ // multipart object.
+
+ nsMsgSendPart* plainpart = nullptr; // If we converted HTML into plaintext,
+ // the message or child containing the plaintext
+ // goes here. (Need to use this to determine
+ // what headers to append/set to the main
+ // message body.)
+
+ uint32_t multipartRelatedCount = GetMultipartRelatedCount(); // The number of related part we will have to generate
+
+ nsCOMPtr<nsIPrompt> promptObject; // only used if we have to show an alert here....
+ GetDefaultPrompt(getter_AddRefs(promptObject));
+
+ char *hdrs = 0;
+ bool maincontainerISrelatedpart = false;
+ const char * toppart_type = nullptr;
+
+ status = m_status;
+ if (NS_FAILED(status))
+ goto FAIL;
+
+ if (!m_attachment1_type) {
+ m_attachment1_type = PL_strdup(TEXT_PLAIN);
+ if (!m_attachment1_type)
+ goto FAILMEM;
+ }
+
+ nsresult rv;
+
+ // If we have a text/html main part, and we need a plaintext attachment, then
+ // we'll do so now. This is an asynchronous thing, so we'll kick it off and
+ // count on getting back here when it finishes.
+
+ if (m_plaintext == nullptr &&
+ (mCompFields->GetForcePlainText() ||
+ mCompFields->GetUseMultipartAlternative()) &&
+ m_attachment1_body && PL_strcmp(m_attachment1_type, TEXT_HTML) == 0)
+ {
+ //
+ // If we get here, we have an HTML body, but we really need to send
+ // a text/plain message, so we will write the HTML out to a disk file,
+ // fire off another URL request for this local disk file and that will
+ // take care of the conversion...
+ //
+ rv = nsMsgCreateTempFile("nsemail.html", getter_AddRefs(mHTMLFile));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ nsCOMPtr<nsIOutputStream> tempfile;
+ rv = MsgNewBufferedFileOutputStream(getter_AddRefs(tempfile), mHTMLFile, -1, 00600);
+ if (NS_FAILED(rv))
+ {
+ if (mSendReport)
+ {
+ nsAutoString error_msg;
+ nsMsgBuildMessageWithTmpFile(mHTMLFile, error_msg);
+ mSendReport->SetMessage(nsIMsgSendReport::process_Current, error_msg.get(), false);
+ }
+ status = NS_MSG_UNABLE_TO_OPEN_TMP_FILE;
+ goto FAIL;
+ }
+
+ if (mOriginalHTMLBody)
+ {
+ uint32_t origLen = strlen(mOriginalHTMLBody);
+ uint32_t n;
+ nsresult rv = tempfile->Write(mOriginalHTMLBody, origLen, &n);
+ if (NS_FAILED(rv) || n != origLen)
+ {
+ status = NS_MSG_ERROR_WRITING_FILE;
+ goto FAIL;
+ }
+ }
+
+ if (NS_FAILED(tempfile->Flush()))
+ {
+ status = NS_MSG_ERROR_WRITING_FILE;
+ goto FAIL;
+ }
+
+ tempfile->Close();
+
+ m_plaintext = new nsMsgAttachmentHandler;
+ if (!m_plaintext)
+ goto FAILMEM;
+ m_plaintext->SetMimeDeliveryState(this);
+ m_plaintext->m_bogus_attachment = true;
+
+ nsAutoCString tempURL;
+ rv = NS_GetURLSpecFromFile(mHTMLFile, tempURL);
+ if (NS_FAILED(rv) || NS_FAILED(nsMsgNewURL(getter_AddRefs(m_plaintext->mURL), tempURL.get())))
+ {
+ m_plaintext = nullptr;
+ goto FAILMEM;
+ }
+
+ m_plaintext->m_type = TEXT_HTML;
+ m_plaintext->m_charset = mCompFields->GetCharacterSet();
+ m_plaintext->m_desiredType = TEXT_PLAIN;
+ m_attachment_pending_count ++;
+ status = m_plaintext->SnarfAttachment(mCompFields);
+ if (NS_FAILED(status))
+ goto FAIL;
+ if (m_attachment_pending_count > 0)
+ return NS_OK;
+ }
+
+ /* Kludge to avoid having to allocate memory on the toy computers... */
+ buffer = mime_get_stream_write_buffer();
+ if (! buffer)
+ goto FAILMEM;
+
+ NS_ASSERTION (m_attachment_pending_count == 0, "m_attachment_pending_count != 0");
+
+ mComposeBundle->GetStringFromName(u"assemblingMessage",
+ getter_Copies(msg));
+ SetStatusMessage( msg );
+
+ /* First, open the message file.
+ */
+ rv = nsMsgCreateTempFile("nsemail.eml", getter_AddRefs(mTempFile));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ rv = MsgNewBufferedFileOutputStream(getter_AddRefs(mOutputFile), mTempFile, -1, 00600);
+ if (NS_FAILED(rv))
+ {
+ status = NS_MSG_UNABLE_TO_OPEN_TMP_FILE;
+ if (mSendReport)
+ {
+ nsAutoString error_msg;
+ nsMsgBuildMessageWithTmpFile(mTempFile, error_msg);
+ mSendReport->SetMessage(nsIMsgSendReport::process_Current, error_msg.get(), false);
+ }
+ goto FAIL;
+ }
+
+ // generate a message id, if necessary
+ GenerateMessageId( );
+
+ mainbody = new nsMsgSendPart(this, mCompFields->GetCharacterSet());
+ if (!mainbody)
+ goto FAILMEM;
+
+ mainbody->SetMainPart(true);
+ mainbody->SetType(m_attachment1_type ? m_attachment1_type : TEXT_PLAIN);
+
+ NS_ASSERTION(mainbody->GetBuffer() == nullptr, "not-null buffer");
+ status = mainbody->SetBuffer(m_attachment1_body ? m_attachment1_body : "");
+ if (NS_FAILED(status))
+ goto FAIL;
+
+ // Determine the encoding of the main message body before we free it.
+ PR_FREEIF(m_attachment1_encoding);
+ if (m_attachment1_body)
+ mCompFields->GetBodyIsAsciiOnly(&body_is_us_ascii);
+
+ if (!mCompFields->GetForceMsgEncoding() && (body_is_us_ascii ||
+ nsMsgI18Nstateful_charset(mCompFields->GetCharacterSet()))) {
+ m_attachment1_encoding = PL_strdup (ENCODING_7BIT);
+ } else if (mime_use_quoted_printable_p) {
+ m_attachment1_encoding = PL_strdup (ENCODING_QUOTED_PRINTABLE);
+ isUsingQP = true;
+ } else {
+ m_attachment1_encoding = PL_strdup (ENCODING_8BIT);
+ }
+
+ // Make sure the lines don't get to long.
+ if (m_attachment1_body) {
+ uint32_t max_column = 0;
+ uint32_t cur_column = 0;
+ for (char* c = m_attachment1_body; *c; c++) {
+ if (*c == '\n') {
+ if (cur_column > max_column)
+ max_column = cur_column;
+ cur_column = 0;
+ } else if (*c != '\r') {
+ cur_column++;
+ }
+ }
+ // Check one last time for the last line.
+ if (cur_column > max_column)
+ max_column = cur_column;
+ if (max_column > LINELENGTH_ENCODING_THRESHOLD && !isUsingQP) {
+ // To encode "long lines" use a CTE that will transmit shorter lines.
+ // Switch to base64 if we are not already using "quoted printable".
+ PR_FREEIF(m_attachment1_encoding);
+ m_attachment1_encoding = PL_strdup (ENCODING_BASE64);
+ }
+ }
+ PR_FREEIF (m_attachment1_body);
+
+ maincontainer = mainbody;
+
+ // If we were given a pre-saved collection of HTML and contained images,
+ // then we want mainbody to point to the HTML lump therein.
+ if (m_related_part)
+ {
+ // If m_related_part is of type text/html, set both maincontainer
+ // and mainbody to point to it. If m_related_part is multipart/related,
+ // however, set mainbody to be the first child within m_related_part.
+ delete mainbody;
+
+ // No matter what, maincontainer points to the outermost related part.
+ maincontainer = m_related_part;
+ maincontainerISrelatedpart = true;
+
+ mainbody = m_related_part->GetChild(0);
+ mainbody->SetMainPart(true);
+ }
+ if (m_plaintext)
+ {
+ //
+ // OK. We have a plaintext version of the main body that we want to
+ // send instead of or with the text/html. Shove it in.
+ //
+ plainpart = new nsMsgSendPart(this, mCompFields->GetCharacterSet());
+ if (!plainpart)
+ goto FAILMEM;
+ status = plainpart->SetType(TEXT_PLAIN);
+ if (NS_FAILED(status))
+ goto FAIL;
+ status = plainpart->SetFile(m_plaintext->mTmpFile);
+ if (NS_FAILED(status))
+ goto FAIL;
+
+ m_plaintext->mMainBody = true;
+
+ // Determine Content-Transfer-Encoding for the attachments.
+ m_plaintext->PickEncoding(mCompFields->GetCharacterSet(), this);
+ const char *charset = mCompFields->GetCharacterSet();
+ hdrs = mime_generate_attachment_headers(m_plaintext->m_type.get(),
+ nullptr,
+ m_plaintext->m_encoding.get(),
+ m_plaintext->m_description.get(),
+ m_plaintext->m_xMacType.get(),
+ m_plaintext->m_xMacCreator.get(),
+ nullptr, 0,
+ m_digest_p,
+ m_plaintext,
+ charset,
+ charset,
+ body_is_us_ascii,
+ nullptr,
+ true);
+ if (!hdrs)
+ goto FAILMEM;
+ status = plainpart->SetOtherHeaders(hdrs);
+ PR_Free(hdrs);
+ hdrs = nullptr;
+ if (NS_FAILED(status))
+ goto FAIL;
+
+ if (mCompFields->GetUseMultipartAlternative())
+ {
+ nsMsgSendPart* htmlpart = maincontainer;
+ maincontainer = new nsMsgSendPart(this);
+ if (!maincontainer)
+ goto FAILMEM;
+
+ // Setup the maincontainer stuff...
+ status = maincontainer->SetType(MULTIPART_ALTERNATIVE);
+ if (NS_FAILED(status))
+ goto FAIL;
+
+ status = maincontainer->AddChild(plainpart);
+ if (NS_FAILED(status))
+ goto FAIL;
+
+ status = maincontainer->AddChild(htmlpart);
+ if (NS_FAILED(status))
+ goto FAIL;
+
+ // Create the encoder for the plaintext part here,
+ // because we aren't the main part (attachment1).
+ // (This, along with the rest of the routine, should really
+ // be restructured so that no special treatment is given to
+ // the main body text that came in. Best to put attachment1_text
+ // etc. into a nsMsgSendPart, then reshuffle the parts. Sigh.)
+ if (m_plaintext->m_encoding.LowerCaseEqualsLiteral(ENCODING_QUOTED_PRINTABLE))
+ {
+ plainpart->SetEncoder(MimeEncoder::GetQPEncoder(
+ mime_encoder_output_fn, this));
+ }
+ else if (m_plaintext->m_encoding.LowerCaseEqualsLiteral(ENCODING_BASE64))
+ {
+ plainpart->SetEncoder(MimeEncoder::GetBase64Encoder(
+ mime_encoder_output_fn, this));
+ }
+ }
+ else
+ {
+ delete maincontainer;
+ if (maincontainerISrelatedpart)
+ m_related_part = nullptr; // in that case, m_related_part == maincontainer which we have just deleted!
+ maincontainer = plainpart;
+ mainbody = maincontainer;
+ PR_FREEIF(m_attachment1_type);
+ m_attachment1_type = PL_strdup(TEXT_PLAIN);
+ if (!m_attachment1_type)
+ goto FAILMEM;
+
+ // Override attachment1_encoding here. We do this blindly since we are
+ // sending plaintext only at this point.
+ PR_FREEIF(m_attachment1_encoding);
+ m_attachment1_encoding = ToNewCString(m_plaintext->m_encoding);
+ }
+ }
+
+ // check if we need to encapsulate the message in a multipart/mixed or multipart/digest
+ if (m_attachment_count > multipartRelatedCount)
+ {
+ toppart = new nsMsgSendPart(this);
+ if (!toppart)
+ goto FAILMEM;
+
+ status = toppart->SetType(m_digest_p ? MULTIPART_DIGEST : MULTIPART_MIXED);
+ if (NS_FAILED(status))
+ goto FAIL;
+
+ status = toppart->AddChild(maincontainer);
+ if (NS_FAILED(status))
+ goto FAIL;
+ }
+ else
+ toppart = maincontainer;
+
+ // Is the top part a multipart container?
+ // can't use m_attachment_count because it's not reliable for that
+ // instead use type of main part. See bug #174396
+ toppart_type = toppart->GetType(); // GetType return directly the member variable, don't free it!
+ if (!m_crypto_closure && toppart_type && !PL_strncasecmp(toppart_type, "multipart/", 10))
+ {
+ status = toppart->SetBuffer(MIME_MULTIPART_BLURB);
+ if (NS_FAILED(status))
+ goto FAIL;
+ }
+
+ {
+ nsCOMPtr<msgIWritableStructuredHeaders> outputHeaders =
+ do_CreateInstance(NS_ISTRUCTUREDHEADERS_CONTRACTID);
+ status = mime_generate_headers(mCompFields, m_deliver_mode, outputHeaders);
+ if (NS_FAILED(status))
+ goto FAIL;
+
+ // Convert the blocks of headers into a single string for emission.
+ nsAutoCString headers;
+ outputHeaders->BuildMimeText(headers);
+
+ // If we converted HTML into plaintext, the plaintext part (plainpart)
+ // already has its content-type and content-transfer-encoding ("other")
+ // headers set.
+ //
+ // In the specific case where such a plaintext part is the top-level message
+ // part (iff an HTML message is being sent as text only and no other
+ // attachments exist) we want to preserve the original plainpart headers,
+ // since they contain accurate transfer encoding and Mac type/creator
+ // information.
+ //
+ // So, in the above case we append the main message headers, otherwise we
+ // overwrite whatever headers may have existed.
+ if (plainpart && plainpart == toppart)
+ status = toppart->AppendOtherHeaders(headers.get());
+ else
+ status = toppart->SetOtherHeaders(headers.get());
+ }
+
+ if (NS_FAILED(status))
+ goto FAIL;
+
+ // Set up the first part (user-typed.) For now, do it even if the first
+ // part is empty; we need to add things to skip it if this part is empty.
+
+ // Set up encoder for the first part (message body.)
+ //
+ NS_ASSERTION(!m_attachment1_encoder, "not-null m_attachment1_encoder");
+ if (!PL_strcasecmp(m_attachment1_encoding, ENCODING_BASE64))
+ {
+ m_attachment1_encoder = MimeEncoder::GetBase64Encoder(
+ mime_encoder_output_fn, this);
+ }
+ else if (!PL_strcasecmp(m_attachment1_encoding, ENCODING_QUOTED_PRINTABLE))
+ {
+ m_attachment1_encoder = MimeEncoder::GetQPEncoder(mime_encoder_output_fn,
+ this);
+ }
+
+ // If we converted HTML into plaintext, the plaintext part
+ // already has its type/encoding headers set. So, in the specific
+ // case where such a plaintext part is the main message body
+ // (iff an HTML message is being sent as text only)
+ // we want to avoid generating type/encoding/digest headers;
+ // in all other cases, generate such headers here.
+ //
+ // We really want to set up headers as a dictionary of some sort
+ // so that we need not worry about duplicate header lines.
+ //
+ if ((!plainpart) || (plainpart != mainbody))
+ {
+ const char *charset = mCompFields->GetCharacterSet();
+ hdrs = mime_generate_attachment_headers (m_attachment1_type,
+ nullptr,
+ m_attachment1_encoding,
+ 0, 0, 0, 0, 0,
+ m_digest_p,
+ nullptr, /* no "ma"! */
+ charset,
+ charset,
+ mCompFields->GetBodyIsAsciiOnly(),
+ nullptr,
+ true);
+ if (!hdrs)
+ goto FAILMEM;
+ status = mainbody->AppendOtherHeaders(hdrs);
+ if (NS_FAILED(status))
+ goto FAIL;
+ }
+
+ PR_FREEIF(hdrs);
+
+ mainbody->SetEncoder(m_attachment1_encoder.forget());
+
+ //
+ // Now we need to process attachments and slot them in the
+ // correct hierarchy.
+ //
+ if (m_attachment_count > 0)
+ {
+ // Kludge to avoid having to allocate memory on the toy computers...
+ if (! mime_mailto_stream_read_buffer)
+ mime_mailto_stream_read_buffer = (char *) PR_Malloc (MIME_BUFFER_SIZE);
+ buffer = mime_mailto_stream_read_buffer;
+ if (! buffer)
+ goto FAILMEM;
+
+ // Gather all of the attachments for this message that are NOT
+ // part of an enclosed MHTML message!
+ for (i = 0; i < m_attachment_count; i++)
+ {
+ nsMsgAttachmentHandler *ma = m_attachments[i];
+ if (!ma->mMHTMLPart)
+ PreProcessPart(ma, toppart);
+ }
+
+ //
+ // If we have a m_related_part as a container for children, then we have to
+ // tack on these children for the part
+ //
+ if (m_related_part)
+ {
+ for (i = 0; i < m_attachment_count; i++)
+ {
+ //
+ // look for earlier part with the same content id. If we find it,
+ // need to remember the mapping between our node index and the
+ // part num of the earlier part.
+ int32_t nodeIndex = m_attachments[i]->mNodeIndex;
+ if (nodeIndex != -1)
+ {
+ for (uint32_t j = 0; j < i; j++)
+ {
+ if (m_attachments[j]->mNodeIndex != -1 &&
+ m_attachments[j]->m_contentId.Equals(m_attachments[i]->m_contentId))
+ m_partNumbers[nodeIndex] = m_partNumbers[m_attachments[j]->mNodeIndex];
+ }
+ }
+ // rhp: This is here because we could get here after saying OK
+ // to a lot of prompts about not being able to fetch this part!
+ //
+ if (m_attachments[i]->mPartUserOmissionOverride)
+ continue;
+
+ // Now, we need to add this part to the m_related_part member so the
+ // message will be generated correctly.
+ if (m_attachments[i]->mMHTMLPart)
+ PreProcessPart(m_attachments[i], m_related_part);
+ }
+ }
+
+ }
+
+ // Tell the user we are creating the message...
+ mComposeBundle->GetStringFromName(u"creatingMailMessage",
+ getter_Copies(msg));
+ SetStatusMessage( msg );
+
+ // OK, now actually write the structure we've carefully built up.
+ status = toppart->Write();
+ if (NS_FAILED(status))
+ goto FAIL;
+
+ /* Close down encryption stream */
+ if (m_crypto_closure)
+ {
+ status = m_crypto_closure->FinishCryptoEncapsulation(false, mSendReport);
+ m_crypto_closure = nullptr;
+ if (NS_FAILED(status)) goto FAIL;
+ }
+
+ if (mOutputFile)
+ {
+ if (NS_FAILED(mOutputFile->Flush()))
+ {
+ status = NS_MSG_ERROR_WRITING_FILE;
+ goto FAIL;
+ }
+
+ mOutputFile->Close();
+ mOutputFile = nullptr;
+
+ // mTempFile is stale because we wrote to it. Get another copy to refresh.
+ nsCOMPtr<nsIFile> tempFileCopy;
+ mTempFile->Clone(getter_AddRefs(tempFileCopy));
+ mTempFile = tempFileCopy;
+ tempFileCopy = nullptr;
+ /* If we don't do this check...ZERO length files can be sent */
+ int64_t fileSize;
+ rv = mTempFile->GetFileSize(&fileSize);
+ if (NS_FAILED(rv) || fileSize == 0)
+ {
+ status = NS_MSG_ERROR_WRITING_FILE;
+ goto FAIL;
+ }
+ }
+
+ mComposeBundle->GetStringFromName(u"assemblingMessageDone",
+ getter_Copies(msg));
+ SetStatusMessage(msg);
+
+ if (m_dont_deliver_p && mListener)
+ {
+ //
+ // Need to ditch the file spec here so that we don't delete the
+ // file, since in this case, the caller wants the file
+ //
+ mReturnFile = mTempFile;
+ mTempFile = nullptr;
+ if (!mReturnFile)
+ NotifyListenerOnStopSending(nullptr, NS_ERROR_OUT_OF_MEMORY, nullptr, nullptr);
+ else
+ {
+ NotifyListenerOnStopSending(nullptr, NS_OK, nullptr, mReturnFile);
+ }
+ }
+ else
+ {
+ status = DeliverMessage();
+ if (NS_SUCCEEDED(status))
+ shouldDeleteDeliveryState = false;
+ }
+ goto FAIL;
+
+FAILMEM:
+ status = NS_ERROR_OUT_OF_MEMORY;
+
+FAIL:
+ if (toppart)
+ delete toppart;
+ toppart = nullptr;
+ mainbody = nullptr;
+ maincontainer = nullptr;
+
+ if (in_file)
+ {
+ PR_Close (in_file);
+ in_file = nullptr;
+ }
+
+ if (shouldDeleteDeliveryState)
+ {
+ if (NS_FAILED(status))
+ {
+ m_status = status;
+ nsresult ignoreMe;
+ Fail(status, nullptr, &ignoreMe);
+ }
+ }
+
+ return status;
+}
+
+int32_t
+nsMsgComposeAndSend::PreProcessPart(nsMsgAttachmentHandler *ma,
+ nsMsgSendPart *toppart) // The very top most container of the message
+{
+ nsresult status;
+ char *hdrs = 0;
+ nsMsgSendPart *part = nullptr;
+
+ // If this was one of those dead parts from a quoted web page,
+ // then just return safely.
+ //
+ if (ma->m_bogus_attachment)
+ return 0;
+
+ // If at this point we *still* don't have a content-type, then
+ // we're never going to get one.
+ if (ma->m_type.IsEmpty())
+ ma->m_type = UNKNOWN_CONTENT_TYPE;
+
+ ma->PickEncoding(mCompFields->GetCharacterSet(), this);
+ ma->PickCharset();
+
+ part = new nsMsgSendPart(this);
+ if (!part)
+ return 0;
+ status = toppart->AddChild(part);
+ // Remember the part number if it has a node index.
+ if (ma->mNodeIndex != -1)
+ m_partNumbers[ma->mNodeIndex] = part->m_partNum;
+
+ if (NS_FAILED(status))
+ return 0;
+ status = part->SetType(ma->m_type.get());
+ if (NS_FAILED(status))
+ return 0;
+
+ if (ma->mSendViaCloud)
+ ma->m_encoding = ENCODING_7BIT;
+
+ nsCString turl;
+ if (!ma->mURL)
+ {
+ if (!ma->m_uri.IsEmpty())
+ turl = ma->m_uri;
+ }
+ else {
+ status = ma->mURL->GetSpec(turl);
+ if (NS_FAILED(status))
+ return 0;
+ }
+
+ nsCString type(ma->m_type);
+ nsCString realName(ma->m_realName);
+
+ // for cloud attachments, make the part an html part with no name,
+ // so we don't show it as an attachment.
+ if (ma->mSendViaCloud)
+ {
+ type.Assign("application/octet-stream");
+ realName.Truncate();
+ }
+ hdrs = mime_generate_attachment_headers (type.get(),
+ ma->m_typeParam.get(),
+ ma->m_encoding.get(),
+ ma->m_description.get(),
+ ma->m_xMacType.get(),
+ ma->m_xMacCreator.get(),
+ realName.get(),
+ turl.get(),
+ m_digest_p,
+ ma,
+ ma->m_charset.get(), // rhp - this needs
+ // to be the charset
+ // we determine from
+ // the file or none
+ // at all!
+ mCompFields->GetCharacterSet(),
+ false, // bodyIsAsciiOnly to false
+ // for attachments
+ ma->m_contentId.get(),
+ false);
+ if (!hdrs)
+ return 0;
+
+ status = part->SetOtherHeaders(hdrs);
+ PR_FREEIF(hdrs);
+ if (ma->mSendViaCloud)
+ {
+ nsCString urlSpec;
+ status = ma->mURL->GetSpec(urlSpec);
+ if (NS_FAILED(status))
+ return 0;
+
+ // Need to add some headers so that libmime can restore the cloud info
+ // when loading a draft message.
+ nsCString draftInfo(HEADER_X_MOZILLA_CLOUD_PART": cloudFile; url=");
+ draftInfo.Append(ma->mCloudUrl.get());
+ // don't leak user file paths or account keys to recipients.
+ if (m_deliver_mode == nsMsgSaveAsDraft)
+ {
+ draftInfo.Append("; provider=");
+ draftInfo.Append(ma->mCloudProviderKey.get());
+ draftInfo.Append("; file=");
+ draftInfo.Append(urlSpec.get());
+ }
+ draftInfo.Append("; name=");
+ draftInfo.Append(ma->m_realName.get());
+ draftInfo.Append(CRLF);
+ part->AppendOtherHeaders(draftInfo.get());
+ part->SetType("application/octet-stream");
+ part->SetBuffer("");
+ }
+ if (NS_FAILED(status))
+ return 0;
+ status = part->SetFile(ma->mTmpFile);
+ if (NS_FAILED(status))
+ return 0;
+ if (ma->m_encoder)
+ {
+ part->SetEncoder(ma->m_encoder.forget());
+ }
+
+ ma->m_current_column = 0;
+
+ if (ma->m_type.LowerCaseEqualsLiteral(MESSAGE_RFC822) ||
+ ma->m_type.LowerCaseEqualsLiteral(MESSAGE_NEWS)) {
+ part->SetStripSensitiveHeaders(true);
+ }
+
+ return 1;
+}
+
+# define FROB(X) \
+ if (X && *X) \
+ { \
+ if (*recipients) PL_strcat(recipients, ","); \
+ PL_strcat(recipients, X); \
+ }
+
+nsresult nsMsgComposeAndSend::BeginCryptoEncapsulation ()
+{
+ // Try to create a secure compose object. If we can create it, then query to see
+ // if we need to use it for this send transaction.
+
+ nsresult rv = NS_OK;
+ nsCOMPtr<nsIMsgComposeSecure> secureCompose;
+ secureCompose = do_CreateInstance(NS_MSGCOMPOSESECURE_CONTRACTID, &rv);
+ // it's not an error scenario of there is secure compose
+ if (NS_FAILED(rv))
+ return NS_OK;
+
+ if (secureCompose)
+ {
+ bool requiresEncryptionWork = false;
+ secureCompose->RequiresCryptoEncapsulation(mUserIdentity, mCompFields, &requiresEncryptionWork);
+ if (requiresEncryptionWork)
+ {
+ m_crypto_closure = secureCompose;
+ // bah i'd like to move the following blurb into the implementation of BeginCryptoEncapsulation; however
+ // the apis for nsIMsgComposeField just aren't rich enough. It requires the implementor to jump through way
+ // too many string conversions....
+ char * recipients = (char *)
+ PR_MALLOC((mCompFields->GetTo() ? strlen(mCompFields->GetTo()) : 0) +
+ (mCompFields->GetCc() ? strlen(mCompFields->GetCc()) : 0) +
+ (mCompFields->GetBcc() ? strlen(mCompFields->GetBcc()) : 0) +
+ (mCompFields->GetNewsgroups() ? strlen(mCompFields->GetNewsgroups()) : 0) + 20);
+ if (!recipients) return NS_ERROR_OUT_OF_MEMORY;
+
+ *recipients = 0;
+
+ FROB(mCompFields->GetTo())
+ FROB(mCompFields->GetCc())
+ FROB(mCompFields->GetBcc())
+ FROB(mCompFields->GetNewsgroups())
+
+ // end section of code I'd like to move to the implementor.....
+ rv = m_crypto_closure->BeginCryptoEncapsulation(mOutputFile,
+ recipients,
+ mCompFields,
+ mUserIdentity,
+ mSendReport,
+ (m_deliver_mode == nsMsgSaveAsDraft));
+
+ PR_FREEIF(recipients);
+ }
+
+ }
+
+ return rv;
+}
+
+nsresult
+mime_write_message_body(nsIMsgSend *state, const char *buf, uint32_t size)
+{
+ NS_ENSURE_ARG_POINTER(state);
+
+ nsCOMPtr<nsIOutputStream> output;
+ nsCOMPtr<nsIMsgComposeSecure> crypto_closure;
+
+ state->GetOutputStream(getter_AddRefs(output));
+ if (!output)
+ return NS_MSG_ERROR_WRITING_FILE;
+
+ state->GetCryptoclosure(getter_AddRefs(crypto_closure));
+ if (crypto_closure)
+ {
+ // Copy to new null-terminated string so JS glue doesn't crash when
+ // MimeCryptoWriteBlock() is implemented in JS.
+ nsCString bufWithNull;
+ bufWithNull.Assign(buf, size);
+ return crypto_closure->MimeCryptoWriteBlock(bufWithNull.get(), size);
+ }
+
+ uint32_t n;
+ nsresult rv = output->Write(buf, size, &n);
+ if (NS_FAILED(rv) || n != size)
+ {
+ return NS_MSG_ERROR_WRITING_FILE;
+ }
+
+ return NS_OK;
+}
+
+nsresult
+mime_encoder_output_fn(const char *buf, int32_t size, void *closure)
+{
+ nsMsgComposeAndSend *state = (nsMsgComposeAndSend *) closure;
+ return mime_write_message_body (state, (char *) buf, (uint32_t)size);
+}
+
+nsresult
+nsMsgComposeAndSend::GetEmbeddedObjectInfo(nsIDOMNode *node, nsMsgAttachmentData *attachment, bool *acceptObject)
+{
+ NS_ENSURE_ARG_POINTER(node);
+ NS_ENSURE_ARG_POINTER(attachment);
+ NS_ENSURE_ARG_POINTER(acceptObject);
+
+ // GetEmbeddedObjectInfo will determine if we need to attach the source of the
+ // embedded object with the message. The decision is made automatically unless
+ // the attribute moz-do-not-send has been set to true or false.
+ nsresult rv = NS_OK;
+
+ // Reset this structure to null!
+ *acceptObject = false;
+
+ // We're only interested in body, image, link and anchors which are all
+ // elements.
+ nsCOMPtr<nsIDOMElement> domElement = do_QueryInterface(node);
+ if (!domElement)
+ return NS_OK;
+
+ bool isImage = false;
+ nsAutoString mozDoNotSendAttr;
+ domElement->GetAttribute(NS_LITERAL_STRING(ATTR_MOZ_DO_NOT_SEND), mozDoNotSendAttr);
+
+ // Only empty or moz-do-not-send="false" may be accepted later.
+ if (!(mozDoNotSendAttr.IsEmpty() || mozDoNotSendAttr.LowerCaseEqualsLiteral("false")))
+ return NS_OK;
+
+ // Now, we know the types of objects this node can be, so we will do
+ // our query interface here and see what we come up with
+ nsCOMPtr<nsIDOMHTMLBodyElement> body = (do_QueryInterface(node));
+ // XXX convert to use nsIImageLoadingContent?
+ nsCOMPtr<nsIDOMHTMLImageElement> image = (do_QueryInterface(node));
+ nsCOMPtr<nsIDOMHTMLLinkElement> link = (do_QueryInterface(node));
+ nsCOMPtr<nsIDOMHTMLAnchorElement> anchor = (do_QueryInterface(node));
+
+ // First, try to see if the body as a background image
+ if (body)
+ {
+ nsAutoString tUrl;
+ if (NS_SUCCEEDED(body->GetBackground(tUrl)))
+ {
+ nsAutoCString turlC;
+ CopyUTF16toUTF8(tUrl, turlC);
+ if (NS_FAILED(nsMsgNewURL(getter_AddRefs(attachment->m_url), turlC.get())))
+ return NS_OK;
+ }
+ isImage = true;
+ }
+ else if (image) // Is this an image?
+ {
+ nsString tUrl;
+ nsString tName;
+ nsString tDesc;
+
+ // Create the URI
+ if (NS_FAILED(image->GetSrc(tUrl)))
+ return NS_ERROR_FAILURE;
+ if (tUrl.IsEmpty())
+ return NS_OK;
+
+ nsAutoCString turlC;
+ CopyUTF16toUTF8(tUrl, turlC);
+ if (NS_FAILED(nsMsgNewURL(getter_AddRefs(attachment->m_url), turlC.get())))
+ {
+ // Well, the first time failed...which means we probably didn't get
+ // the full path name...
+ //
+ nsIDOMDocument *ownerDocument = nullptr;
+ node->GetOwnerDocument(&ownerDocument);
+ if (ownerDocument)
+ {
+ nsIDocument *doc = nullptr;
+ if (NS_FAILED(ownerDocument->QueryInterface(NS_GET_IID(nsIDocument),(void**)&doc)) || !doc)
+ return NS_ERROR_OUT_OF_MEMORY;
+
+ nsAutoCString spec;
+ nsIURI *uri = doc->GetDocumentURI();
+
+ if (!uri)
+ return NS_ERROR_OUT_OF_MEMORY;
+
+ rv = uri->GetSpec(spec);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ // Ok, now get the path to the root doc and tack on the name we
+ // got from the GetSrc() call....
+ NS_ConvertUTF8toUTF16 workURL(spec);
+
+ int32_t loc = workURL.RFindChar('/');
+ if (loc >= 0)
+ workURL.SetLength(loc+1);
+ workURL.Append(tUrl);
+ NS_ConvertUTF16toUTF8 workurlC(workURL);
+ if (NS_FAILED(nsMsgNewURL(getter_AddRefs(attachment->m_url), workurlC.get())))
+ return NS_OK; // Continue and send it without this image.
+ }
+ }
+ isImage = true;
+
+ rv = image->GetName(tName);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ LossyCopyUTF16toASCII(tName, attachment->m_realName);
+ rv = image->GetLongDesc(tDesc);
+ NS_ENSURE_SUCCESS(rv, rv);
+ attachment->m_description = NS_LossyConvertUTF16toASCII(tDesc); // XXX i18n
+ }
+ else if (link) // Is this a link?
+ {
+ nsString tUrl;
+
+ // Create the URI
+ rv = link->GetHref(tUrl);
+ NS_ENSURE_SUCCESS(rv, rv);
+ if (tUrl.IsEmpty())
+ return NS_OK;
+ nsAutoCString turlC;
+ CopyUTF16toUTF8(tUrl, turlC);
+ if (NS_FAILED(nsMsgNewURL(getter_AddRefs(attachment->m_url), turlC.get())))
+ return NS_OK;
+ }
+ else if (anchor)
+ {
+ nsString tUrl;
+ nsString tName;
+
+ // Create the URI
+ rv = anchor->GetHref(tUrl);
+ NS_ENSURE_SUCCESS(rv, rv);
+ if (tUrl.IsEmpty())
+ return NS_OK;
+ nsAutoCString turlC;
+ CopyUTF16toUTF8(tUrl, turlC);
+ // This can fail since the URL might not be recognised, for example:
+ // <a href="skype:some-name?call" title="Skype">Some Name</a>
+ if (NS_FAILED(nsMsgNewURL(getter_AddRefs(attachment->m_url), turlC.get())))
+ return NS_OK;
+ rv = anchor->GetName(tName);
+ NS_ENSURE_SUCCESS(rv, rv);
+ LossyCopyUTF16toASCII(tName, attachment->m_realName);
+ }
+ else
+ {
+ // If we get here, we got something we didn't expect!
+ // Just try to continue and send it without this thing.
+ return NS_OK;
+ }
+
+ // Before going further, check what scheme we're dealing with. Files need to
+ // be converted to data URLs during composition. "Attaching" means
+ // sending as a cid: part instead of original URL.
+ bool isHttp =
+ (NS_SUCCEEDED(attachment->m_url->SchemeIs("http", &isHttp)) && isHttp) ||
+ (NS_SUCCEEDED(attachment->m_url->SchemeIs("https", &isHttp)) && isHttp);
+ // Attach (= create cid: part) http resources if moz-do-not-send is set to
+ // "false". Special processing for images: We attach if the preference says so.
+ // Note that moz-do-not-send="true" is already processed above so the preference
+ // doesn't override this.
+ if (isHttp)
+ {
+ *acceptObject =
+ (isImage && Preferences::GetBool("mail.compose.attach_http_images", false)) ||
+ mozDoNotSendAttr.LowerCaseEqualsLiteral("false");
+ return NS_OK;
+ }
+
+ bool isData =
+ (NS_SUCCEEDED(attachment->m_url->SchemeIs("data", &isData)) && isData);
+ bool isNews =
+ (NS_SUCCEEDED(attachment->m_url->SchemeIs("news", &isNews)) && isNews) ||
+ (NS_SUCCEEDED(attachment->m_url->SchemeIs("snews", &isNews)) && isNews) ||
+ (NS_SUCCEEDED(attachment->m_url->SchemeIs("nntp", &isNews)) && isNews);
+ // Attach (= create cid: part) data resources if moz-do-not-send is not
+ // specified or set to "false".
+ if (isData || isNews)
+ {
+ *acceptObject = mozDoNotSendAttr.IsEmpty() ||
+ mozDoNotSendAttr.LowerCaseEqualsLiteral("false");
+ return NS_OK;
+ }
+
+ return NS_OK;
+}
+
+
+uint32_t
+nsMsgComposeAndSend::GetMultipartRelatedCount(bool forceToBeCalculated /*=false*/)
+{
+ nsresult rv = NS_OK;
+ uint32_t count;
+
+ if (mMultipartRelatedAttachmentCount != -1 && !forceToBeCalculated)
+ return (uint32_t)mMultipartRelatedAttachmentCount;
+
+ //First time here, let's calculate the correct number of related part we need to generate
+ mMultipartRelatedAttachmentCount = 0;
+ if (mEditor)
+ {
+ nsCOMPtr<nsIEditorMailSupport> mailEditor (do_QueryInterface(mEditor));
+ if (!mailEditor)
+ return 0;
+
+ rv = mailEditor->GetEmbeddedObjects(getter_AddRefs(mEmbeddedObjectList));
+ if (NS_FAILED(rv))
+ return 0;
+ }
+ if (!mEmbeddedObjectList)
+ return 0;
+
+ if (NS_SUCCEEDED(mEmbeddedObjectList->GetLength(&count)))
+ {
+ if (count > 0)
+ {
+ // preallocate space for part numbers
+ m_partNumbers.SetLength(count);
+ // Let parse the list to count the number of valid objects. BTW, we can remove the others from the list
+ RefPtr<nsMsgAttachmentData> attachment(new nsMsgAttachmentData);
+
+ int32_t i;
+ nsCOMPtr<nsIDOMNode> node;
+
+ for (i = count - 1, count = 0; i >= 0; i --)
+ {
+ // Reset this structure to null!
+
+ // now we need to get the element in the array and do the magic
+ // to process this element.
+ //
+ node = do_QueryElementAt(mEmbeddedObjectList, i, &rv);
+ bool acceptObject = false;
+ if (node)
+ {
+ rv = GetEmbeddedObjectInfo(node, attachment, &acceptObject);
+ }
+ else // outlook import case
+ {
+ nsCOMPtr<nsIMsgEmbeddedImageData> imageData =
+ do_QueryElementAt(mEmbeddedObjectList, i, &rv);
+ if (!imageData)
+ continue;
+ acceptObject = true;
+ }
+ if (NS_SUCCEEDED(rv) && acceptObject)
+ count ++;
+ }
+ }
+ mMultipartRelatedAttachmentCount = (int32_t)count;
+ return count;
+ }
+ else
+ return 0;
+}
+
+nsresult
+nsMsgComposeAndSend::GetBodyFromEditor()
+{
+ //
+ // Now we have to fix up and get the HTML from the editor. After we
+ // get the HTML data, we need to store it in the m_attachment_1_body
+ // member variable after doing the necessary charset conversion.
+ //
+
+ //
+ // Query the editor, get the body of HTML!
+ //
+ uint32_t flags = nsIDocumentEncoder::OutputFormatted |
+ nsIDocumentEncoder::OutputNoFormattingInPre |
+ nsIDocumentEncoder::OutputDisallowLineBreaking;
+ nsAutoString bodyStr;
+ char16_t* bodyText = nullptr;
+ nsresult rv;
+ char16_t *origHTMLBody = nullptr;
+
+ // Ok, get the body...the DOM should have been whacked with
+ // Content ID's already
+ if (mEditor)
+ mEditor->OutputToString(NS_LITERAL_STRING(TEXT_HTML), flags, bodyStr);
+ else
+ bodyStr = NS_ConvertASCIItoUTF16(m_attachment1_body);
+
+ // If we really didn't get a body, just return NS_OK
+ if (bodyStr.IsEmpty())
+ return NS_OK;
+ bodyText = ToNewUnicode(bodyStr);
+ if (!bodyText)
+ return NS_ERROR_OUT_OF_MEMORY;
+
+ // If we are forcing this to be plain text, we should not be
+ // doing this conversion.
+ bool doConversion = true;
+
+ if ( (mCompFields) && mCompFields->GetForcePlainText() )
+ doConversion = false;
+
+ if (doConversion)
+ {
+ nsCOMPtr<mozITXTToHTMLConv> conv = do_CreateInstance(MOZ_TXTTOHTMLCONV_CONTRACTID, &rv);
+
+ if (NS_SUCCEEDED(rv))
+ {
+ uint32_t whattodo = mozITXTToHTMLConv::kURLs;
+ bool enable_structs = false;
+ nsCOMPtr<nsIPrefBranch> pPrefBranch(do_GetService(NS_PREFSERVICE_CONTRACTID));
+ if (pPrefBranch)
+ {
+ rv = pPrefBranch->GetBoolPref(PREF_MAIL_SEND_STRUCT, &enable_structs);
+ if (enable_structs)
+ whattodo = whattodo | mozITXTToHTMLConv::kStructPhrase;
+ }
+
+ char16_t* wresult;
+ rv = conv->ScanHTML(bodyText, whattodo, &wresult);
+ if (NS_SUCCEEDED(rv))
+ {
+ // Save the original body for possible attachment as plain text
+ // We should have what the user typed in stored in mOriginalHTMLBody
+ origHTMLBody = bodyText;
+ bodyText = wresult;
+ }
+ }
+ }
+
+ nsCString attachment1_body;
+
+ // Convert body to mail charset
+ nsCString outCString;
+ const char *aCharset = mCompFields->GetCharacterSet();
+
+ if (aCharset && *aCharset)
+ {
+ rv = nsMsgI18NConvertFromUnicode(aCharset, nsDependentString(bodyText), outCString, false, true);
+ bool isAsciiOnly = NS_IsAscii(outCString.get()) &&
+ !nsMsgI18Nstateful_charset(mCompFields->GetCharacterSet());
+ if (mCompFields->GetForceMsgEncoding())
+ isAsciiOnly = false;
+ mCompFields->SetBodyIsAsciiOnly(isAsciiOnly);
+
+ // If the body contains characters outside the current mail charset,
+ // convert to UTF-8.
+ if (NS_ERROR_UENC_NOMAPPING == rv)
+ {
+ bool needToCheckCharset;
+ mCompFields->GetNeedToCheckCharset(&needToCheckCharset);
+ if (needToCheckCharset)
+ {
+ // Just use UTF-8 and be done with it
+ // unless disable_fallback_to_utf8 is set for this charset.
+ bool disableFallback = false;
+ nsCOMPtr<nsIPrefBranch> prefBranch (do_GetService(NS_PREFSERVICE_CONTRACTID, &rv));
+ if (prefBranch)
+ {
+ nsCString prefName("mailnews.disable_fallback_to_utf8.");
+ prefName.Append(aCharset);
+ prefBranch->GetBoolPref(prefName.get(), &disableFallback);
+ }
+ if (!disableFallback)
+ {
+ CopyUTF16toUTF8(nsDependentString(bodyText), outCString);
+ mCompFields->SetCharacterSet("UTF-8");
+ }
+ }
+ }
+
+ if (NS_SUCCEEDED(rv))
+ attachment1_body = outCString;
+
+ // If we have an origHTMLBody that is not null, this means that it is
+ // different than the bodyText because of formatting conversions. Because of
+ // this we need to do the charset conversion on this part separately
+ if (origHTMLBody)
+ {
+ nsCString newBody;
+ rv = nsMsgI18NConvertFromUnicode(aCharset,
+ nsDependentString(origHTMLBody), newBody, false, true);
+ if (NS_SUCCEEDED(rv))
+ {
+ mOriginalHTMLBody = ToNewCString(newBody);
+ }
+ }
+ else {
+ mOriginalHTMLBody = ToNewCString(attachment1_body);
+ }
+
+ NS_Free(bodyText); //Don't need it anymore
+ }
+ else
+ return NS_ERROR_FAILURE;
+
+ rv = SnarfAndCopyBody(attachment1_body, TEXT_HTML);
+
+ return rv;
+}
+
+//
+// This is the routine that does the magic of generating the body and the
+// attachments for the multipart/related email message.
+//
+typedef struct
+{
+ nsIDOMNode *node;
+ char *url;
+} domSaveStruct;
+
+nsresult
+nsMsgComposeAndSend::ProcessMultipartRelated(int32_t *aMailboxCount, int32_t *aNewsCount)
+{
+ uint32_t multipartCount = GetMultipartRelatedCount();
+ nsresult rv = NS_OK;
+ uint32_t i;
+ int32_t j = -1;
+ uint32_t k;
+ int32_t duplicateOf;
+ domSaveStruct *domSaveArray = nullptr;
+
+ if (!mEmbeddedObjectList)
+ return NS_ERROR_MIME_MPART_ATTACHMENT_ERROR;
+
+ RefPtr<nsMsgAttachmentData> attachment(new nsMsgAttachmentData);
+ int32_t locCount = -1;
+
+ if (multipartCount > 0)
+ {
+ domSaveArray = (domSaveStruct *)PR_MALLOC(sizeof(domSaveStruct) * multipartCount);
+ if (!domSaveArray)
+ return NS_ERROR_MIME_MPART_ATTACHMENT_ERROR;
+ memset(domSaveArray, 0, sizeof(domSaveStruct) * multipartCount);
+ }
+
+ nsCOMPtr<nsIDOMNode> node;
+ for (i = mPreloadedAttachmentCount; i < (mPreloadedAttachmentCount + multipartCount);)
+ {
+ // Ok, now we need to get the element in the array and do the magic
+ // to process this element.
+ //
+
+ locCount++;
+ mEmbeddedObjectList->QueryElementAt(locCount, NS_GET_IID(nsIDOMNode), getter_AddRefs(node));
+ if (node)
+ {
+ bool acceptObject = false;
+ rv = GetEmbeddedObjectInfo(node, attachment, &acceptObject);
+ NS_ENSURE_SUCCESS(rv, NS_ERROR_MIME_MPART_ATTACHMENT_ERROR);
+ if (!acceptObject)
+ continue;
+ nsString nodeValue;
+ node->GetNodeValue(nodeValue);
+ LossyCopyUTF16toASCII(nodeValue, m_attachments[i]->m_contentId);
+ }
+ else
+ {
+ nsCOMPtr<nsIMsgEmbeddedImageData> imageData = do_QueryElementAt(mEmbeddedObjectList, locCount, &rv);
+ if (!imageData)
+ return NS_ERROR_MIME_MPART_ATTACHMENT_ERROR;
+ imageData->GetUri(getter_AddRefs(attachment->m_url));
+ if (!attachment->m_url)
+ return NS_ERROR_MIME_MPART_ATTACHMENT_ERROR;
+ imageData->GetCid(m_attachments[i]->m_contentId);
+ imageData->GetName(attachment->m_realName);
+ }
+
+
+ // MUST set this to get placed in the correct part of the message
+ m_attachments[i]->mMHTMLPart = true;
+
+ m_attachments[i]->mDeleteFile = true;
+ m_attachments[i]->m_done = false;
+ m_attachments[i]->SetMimeDeliveryState(this);
+ m_attachments[i]->mNodeIndex = locCount;
+
+ j++;
+ domSaveArray[j].node = node;
+
+ // check if we have alreay attached this object, don't need to attach it twice
+ duplicateOf = -1;
+ for (k = mPreloadedAttachmentCount; k < i; k++)
+ {
+ bool isEqual = false;
+ NS_ASSERTION(attachment->m_url, "null attachment url!");
+ if (attachment->m_url)
+ (void)attachment->m_url->Equals(m_attachments[k]->mURL, &isEqual);
+ if (isEqual)
+ {
+ duplicateOf = k;
+ break;
+ }
+ }
+
+ if (duplicateOf == -1)
+ {
+ //
+ // Now we have to get all of the interesting information from
+ // the nsIDOMNode we have in hand...
+ m_attachments[i]->mURL = attachment->m_url;
+
+ m_attachments[i]->m_overrideType = attachment->m_realType;
+ m_attachments[i]->m_overrideEncoding = attachment->m_realEncoding;
+ m_attachments[i]->m_desiredType = attachment->m_desiredType;
+ m_attachments[i]->m_description = attachment->m_description;
+ m_attachments[i]->m_realName = attachment->m_realName;
+ m_attachments[i]->m_xMacType = attachment->m_xMacType;
+ m_attachments[i]->m_xMacCreator = attachment->m_xMacCreator;
+
+ m_attachments[i]->m_charset = mCompFields->GetCharacterSet();
+ m_attachments[i]->m_encoding = ENCODING_7BIT;
+
+ if (m_attachments[i]->mURL)
+ msg_pick_real_name(m_attachments[i], nullptr, mCompFields->GetCharacterSet());
+
+ if (m_attachments[i]->m_contentId.IsEmpty())
+ {
+ //
+ // Next, generate a content id for use with this part
+ //
+ nsCString email;
+ mUserIdentity->GetEmail(email);
+ m_attachments[i]->m_contentId = mime_gen_content_id(locCount+1, email.get());
+ }
+
+ //
+ // Start counting the attachments which are going to come from mail folders
+ // and from NNTP servers.
+ //
+ if (m_attachments[i]->mURL)
+ {
+ nsIURI *uri = m_attachments[i]->mURL;
+ bool match = false;
+ if ((NS_SUCCEEDED(uri->SchemeIs("mailbox", &match)) && match) ||
+ (NS_SUCCEEDED(uri->SchemeIs("imap", &match)) && match))
+ (*aMailboxCount)++;
+ else if ((NS_SUCCEEDED(uri->SchemeIs("news", &match)) && match) ||
+ (NS_SUCCEEDED(uri->SchemeIs("snews", &match)) && match))
+ (*aNewsCount)++;
+ else
+ {
+ // Additional account types need a mechanism to report that they are
+ // message protocols. If there is an nsIMsgProtocolInfo component
+ // registered for this scheme, we'll consider it a mailbox
+ // attachment.
+ nsAutoCString contractID;
+ contractID.Assign(
+ NS_LITERAL_CSTRING("@mozilla.org/messenger/protocol/info;1"));
+ nsAutoCString scheme;
+ uri->GetScheme(scheme);
+ contractID.Append(scheme);
+ nsCOMPtr<nsIMsgProtocolInfo> msgProtocolInfo =
+ do_CreateInstance(contractID.get());
+ if (msgProtocolInfo)
+ (*aMailboxCount)++;
+ }
+
+ }
+ }
+ else
+ {
+ m_attachments[i]->m_contentId = m_attachments[duplicateOf]->m_contentId;
+ m_attachments[i]->SetMimeDeliveryState(nullptr);
+ }
+
+ //
+ // Ok, while we are here, we should whack the DOM with the generated
+ // Content-ID for this object. This will be necessary for generating
+ // the HTML we need.
+ //
+ nsString domURL;
+ if (!m_attachments[duplicateOf == -1 ? i : duplicateOf]->m_contentId.IsEmpty())
+ {
+ nsString newSpec(NS_LITERAL_STRING("cid:"));
+ newSpec.AppendASCII(m_attachments[duplicateOf == -1 ? i : duplicateOf]->m_contentId.get());
+
+ // Now, we know the types of objects this node can be, so we will do
+ // our query interface here and see what we come up with
+ nsCOMPtr<nsIDOMHTMLBodyElement> body = (do_QueryInterface(domSaveArray[j].node));
+ nsCOMPtr<nsIDOMHTMLImageElement> image = (do_QueryInterface(domSaveArray[j].node));
+ nsCOMPtr<nsIDOMHTMLLinkElement> link = (do_QueryInterface(domSaveArray[j].node));
+ nsCOMPtr<nsIDOMHTMLAnchorElement> anchor = (do_QueryInterface(domSaveArray[j].node));
+
+ if (anchor)
+ {
+ anchor->GetHref(domURL);
+ anchor->SetHref(newSpec);
+ }
+ else if (link)
+ {
+ link->GetHref(domURL);
+ link->SetHref(newSpec);
+ }
+ else if (image)
+ {
+ image->GetSrc(domURL);
+ image->SetSrc(newSpec);
+ }
+ else if (body)
+ {
+ body->GetBackground(domURL);
+ body->SetBackground(newSpec);
+ }
+
+ if (!domURL.IsEmpty())
+ domSaveArray[j].url = ToNewCString(NS_LossyConvertUTF16toASCII(domURL));
+ }
+ i++;
+ }
+
+ rv = GetBodyFromEditor();
+
+ //
+ // Ok, now we need to un-whack the DOM or we have a screwed up document on
+ // Send failure.
+ //
+ for (i = 0; i < multipartCount; i++)
+ {
+ if ( (!domSaveArray[i].node) || (!domSaveArray[i].url) )
+ continue;
+
+ // Now, we know the types of objects this node can be, so we will do
+ // our query interface here and see what we come up with
+ nsCOMPtr<nsIDOMHTMLBodyElement> body = (do_QueryInterface(domSaveArray[i].node));
+ nsCOMPtr<nsIDOMHTMLImageElement> image = (do_QueryInterface(domSaveArray[i].node));
+ nsCOMPtr<nsIDOMHTMLLinkElement> link = (do_QueryInterface(domSaveArray[i].node));
+ nsCOMPtr<nsIDOMHTMLAnchorElement> anchor = (do_QueryInterface(domSaveArray[i].node));
+
+ // STRING USE WARNING: hoisting the following conversion might save code-space, since it happens along every path
+
+ if (anchor)
+ anchor->SetHref(NS_ConvertASCIItoUTF16(domSaveArray[i].url));
+ else if (link)
+ link->SetHref(NS_ConvertASCIItoUTF16(domSaveArray[i].url));
+ else if (image)
+ image->SetSrc(NS_ConvertASCIItoUTF16(domSaveArray[i].url));
+ else if (body)
+ body->SetBackground(NS_ConvertASCIItoUTF16(domSaveArray[i].url));
+
+ free(domSaveArray[i].url);
+ }
+
+ PR_FREEIF(domSaveArray);
+
+ //
+ // Now, we have to create that first child node for the multipart
+ // message that holds the body as well as the attachment handler
+ // for this body part.
+ //
+ // If we ONLY have multipart objects, then we don't need the container
+ // for the multipart section...
+ //
+ m_related_part = new nsMsgSendPart(this);
+ if (!m_related_part)
+ return NS_ERROR_OUT_OF_MEMORY;
+
+ m_related_part->SetMimeDeliveryState(this);
+ m_related_part->SetType(MULTIPART_RELATED);
+ // We are now going to use the m_related_part as a way to store the
+ // MHTML message for this email.
+ //
+ m_related_body_part = new nsMsgSendPart(this);
+ if (!m_related_body_part)
+ return NS_ERROR_OUT_OF_MEMORY;
+
+ // Set the body contents...
+ m_related_body_part->SetBuffer(m_attachment1_body);
+ m_related_body_part->SetType(m_attachment1_type);
+
+ m_related_part->AddChild(m_related_body_part);
+
+ return rv;
+}
+
+nsresult
+nsMsgComposeAndSend::CountCompFieldAttachments()
+{
+ //Reset the counters
+ mCompFieldLocalAttachments = 0;
+ mCompFieldRemoteAttachments = 0;
+
+ //Get the attachments array
+ nsCOMPtr<nsISimpleEnumerator> attachments;
+ mCompFields->GetAttachments(getter_AddRefs(attachments));
+ if (!attachments)
+ return NS_OK;
+
+ nsresult rv;
+
+ // Parse the attachments array
+ bool moreAttachments;
+ nsCString url;
+ nsCOMPtr<nsISupports> element;
+ while (NS_SUCCEEDED(attachments->HasMoreElements(&moreAttachments)) && moreAttachments) {
+ rv = attachments->GetNext(getter_AddRefs(element));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ nsCOMPtr<nsIMsgAttachment> attachment = do_QueryInterface(element, &rv);
+ if (NS_SUCCEEDED(rv) && attachment)
+ {
+ attachment->GetUrl(url);
+ if (!url.IsEmpty())
+ {
+ // Check to see if this is a file URL, if so, don't retrieve
+ // like a remote URL...
+ if (nsMsgIsLocalFile(url.get()))
+ mCompFieldLocalAttachments++;
+ else // This is a remote URL...
+ mCompFieldRemoteAttachments++;
+ }
+ }
+ }
+
+ return NS_OK;
+}
+
+//
+// Since we are at the head of the list, we start from ZERO.
+//
+nsresult
+nsMsgComposeAndSend::AddCompFieldLocalAttachments()
+{
+ // If none, just return...
+ if (mCompFieldLocalAttachments <= 0)
+ return NS_OK;
+
+ //Get the attachments array
+ nsCOMPtr<nsISimpleEnumerator> attachments;
+ mCompFields->GetAttachments(getter_AddRefs(attachments));
+ if (!attachments)
+ return NS_OK;
+
+ uint32_t newLoc = 0;
+ nsresult rv;
+ nsCString url;
+
+ //Parse the attachments array
+ bool moreAttachments;
+ nsCOMPtr<nsISupports> element;
+ while (NS_SUCCEEDED(attachments->HasMoreElements(&moreAttachments)) && moreAttachments) {
+ rv = attachments->GetNext(getter_AddRefs(element));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ nsCOMPtr<nsIMsgAttachment> attachment = do_QueryInterface(element, &rv);
+ if (NS_SUCCEEDED(rv) && attachment)
+ {
+ bool sendViaCloud = false;
+ attachment->GetSendViaCloud(&sendViaCloud);
+ m_attachments[newLoc]->mSendViaCloud = sendViaCloud;
+ attachment->GetUrl(url);
+ if (!url.IsEmpty())
+ {
+ bool sendViaCloud;
+ attachment->GetSendViaCloud(&sendViaCloud);
+ if (sendViaCloud)
+ {
+ nsCString cloudProviderKey;
+ // We'd like to output a part for the attachment, just an html part
+ // with information about how to download the attachment.
+ // m_attachments[newLoc]->m_done = true;
+ attachment->GetHtmlAnnotation(m_attachments[newLoc]->mHtmlAnnotation);
+ m_attachments[newLoc]->m_type.AssignLiteral("text/html");
+ attachment->GetCloudProviderKey(m_attachments[newLoc]->mCloudProviderKey);
+ attachment->GetContentLocation(m_attachments[newLoc]->mCloudUrl);
+ }
+ // Just look for local file:// attachments and do the right thing.
+ if (nsMsgIsLocalFile(url.get()))
+ {
+ //
+ // Now we have to setup the m_attachments entry for the file://
+ // URL that is passed in...
+ //
+ m_attachments[newLoc]->mDeleteFile = false;
+
+ nsMsgNewURL(getter_AddRefs(m_attachments[newLoc]->mURL), url.get());
+
+ if (m_attachments[newLoc]->mTmpFile)
+ {
+ if (m_attachments[newLoc]->mDeleteFile)
+ m_attachments[newLoc]->mTmpFile->Remove(false);
+ m_attachments[newLoc]->mTmpFile =nullptr;
+ }
+ nsresult rv;
+ nsCOMPtr<nsIIOService> ioService =
+ mozilla::services::GetIOService();
+ NS_ENSURE_TRUE(ioService, NS_ERROR_UNEXPECTED);
+ nsCOMPtr <nsIURI> uri;
+ rv = ioService->NewURI(url, nullptr, nullptr, getter_AddRefs(uri));
+ NS_ENSURE_SUCCESS(rv, rv);
+ nsCOMPtr <nsIFileURL> fileURL = do_QueryInterface(uri);
+ NS_ENSURE_SUCCESS(rv, rv);
+ nsCOMPtr <nsIFile> fileURLFile;
+ fileURL->GetFile(getter_AddRefs(fileURLFile));
+ m_attachments[newLoc]->mTmpFile = do_QueryInterface(fileURLFile);
+ m_attachments[newLoc]->mDeleteFile = false;
+ if (m_attachments[newLoc]->mURL)
+ {
+ nsAutoString proposedName;
+ attachment->GetName(proposedName);
+ msg_pick_real_name(m_attachments[newLoc], proposedName.get(), mCompFields->GetCharacterSet());
+ }
+
+ // Now, most importantly, we need to figure out what the content type is for
+ // this attachment...If we can't, then just make it application/octet-stream
+
+ #ifdef MAC_OSX
+ //Mac always need to snarf the file to figure out how to send it, maybe we need to use apple double...
+ // unless caller has already set the content type, in which case, trust them.
+ bool mustSnarfAttachment = true;
+ #else
+ bool mustSnarfAttachment = false;
+ #endif
+ if (sendViaCloud)
+ mustSnarfAttachment = false;
+
+ attachment->GetContentType(getter_Copies(m_attachments[newLoc]->m_type));
+ if (m_attachments[newLoc]->m_type.IsEmpty())
+ {
+ nsresult rv = NS_OK;
+ nsCOMPtr<nsIMIMEService> mimeFinder (do_GetService(NS_MIMESERVICE_CONTRACTID, &rv));
+ if (NS_SUCCEEDED(rv) && mimeFinder)
+ {
+ nsCOMPtr<nsIURL> fileUrl(do_CreateInstance(NS_STANDARDURL_CONTRACTID));
+ if (fileUrl)
+ {
+ nsAutoCString fileExt;
+ //First try using the real file name
+ rv = fileUrl->SetFileName(m_attachments[newLoc]->m_realName);
+ if (NS_SUCCEEDED(rv))
+ {
+ rv = fileUrl->GetFileExtension(fileExt);
+ if (NS_SUCCEEDED(rv) && !fileExt.IsEmpty()) {
+ nsAutoCString type;
+ mimeFinder->GetTypeFromExtension(fileExt, type);
+ #ifndef XP_MACOSX
+ if (!type.Equals("multipart/appledouble")) // can't do apple double on non-macs
+ #endif
+ m_attachments[newLoc]->m_type = type;
+ }
+ }
+
+ //Then try using the url if we still haven't figured out the content type
+ if (m_attachments[newLoc]->m_type.IsEmpty())
+ {
+ rv = fileUrl->SetSpec(url);
+ if (NS_SUCCEEDED(rv))
+ {
+ rv = fileUrl->GetFileExtension(fileExt);
+ if (NS_SUCCEEDED(rv) && !fileExt.IsEmpty()) {
+ nsAutoCString type;
+ mimeFinder->GetTypeFromExtension(fileExt, type);
+ #ifndef XP_MACOSX
+ if (!type.Equals("multipart/appledouble")) // can't do apple double on non-macs
+ #endif
+ m_attachments[newLoc]->m_type = type;
+ // rtf and vcs files may look like text to sniffers,
+ // but they're not human readable.
+ if (type.IsEmpty() && !fileExt.IsEmpty() &&
+ (MsgLowerCaseEqualsLiteral(fileExt, "rtf") ||
+ MsgLowerCaseEqualsLiteral(fileExt, "vcs")))
+ m_attachments[newLoc]->m_type = APPLICATION_OCTET_STREAM;
+ }
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ attachment->GetContentTypeParam(getter_Copies(m_attachments[newLoc]->m_typeParam));
+ mustSnarfAttachment = false;
+ }
+
+ //We need to snarf the file to figure out how to send it only if we don't have a content type...
+ if (mustSnarfAttachment || m_attachments[newLoc]->m_type.IsEmpty())
+ {
+ m_attachments[newLoc]->m_done = false;
+ m_attachments[newLoc]->SetMimeDeliveryState(this);
+ }
+ else
+ {
+ m_attachments[newLoc]->m_done = true;
+ m_attachments[newLoc]->SetMimeDeliveryState(nullptr);
+ }
+ // For local files, if they are HTML docs and we don't have a charset, we should
+ // sniff the file and see if we can figure it out.
+ if (!m_attachments[newLoc]->m_type.IsEmpty())
+ {
+ if (m_attachments[newLoc]->m_type.LowerCaseEqualsLiteral(TEXT_HTML))
+ {
+ char *tmpCharset = (char *)nsMsgI18NParseMetaCharset(m_attachments[newLoc]->mTmpFile);
+ if (tmpCharset[0] != '\0')
+ m_attachments[newLoc]->m_charset = tmpCharset;
+ }
+ }
+
+ attachment->GetMacType(getter_Copies(m_attachments[newLoc]->m_xMacType));
+ attachment->GetMacCreator(getter_Copies(m_attachments[newLoc]->m_xMacCreator));
+
+ ++newLoc;
+ }
+ }
+ }
+ }
+ return NS_OK;
+}
+
+nsresult
+nsMsgComposeAndSend::AddCompFieldRemoteAttachments(uint32_t aStartLocation,
+ int32_t *aMailboxCount,
+ int32_t *aNewsCount)
+{
+ // If none, just return...
+ if (mCompFieldRemoteAttachments <= 0)
+ return NS_OK;
+
+ //Get the attachments array
+ nsCOMPtr<nsISimpleEnumerator> attachments;
+ mCompFields->GetAttachments(getter_AddRefs(attachments));
+ if (!attachments)
+ return NS_OK;
+
+ uint32_t newLoc = aStartLocation;
+
+ nsresult rv;
+ bool moreAttachments;
+ nsCString url;
+ nsCOMPtr<nsISupports> element;
+ while (NS_SUCCEEDED(attachments->HasMoreElements(&moreAttachments)) && moreAttachments) {
+ rv = attachments->GetNext(getter_AddRefs(element));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ nsCOMPtr<nsIMsgAttachment> attachment = do_QueryInterface(element, &rv);
+ if (NS_SUCCEEDED(rv) && attachment)
+ {
+ attachment->GetUrl(url);
+ if (!url.IsEmpty())
+ {
+ // Just look for files that are NOT local file attachments and do
+ // the right thing.
+ if (! nsMsgIsLocalFile(url.get()))
+ {
+ // Check for message attachment, see nsMsgMailNewsUrl::GetIsMessageUri.
+ nsCOMPtr<nsIURI> nsiuri = do_CreateInstance(NS_STANDARDURL_CONTRACTID);
+ NS_ENSURE_STATE(nsiuri);
+ nsiuri->SetSpec(url);
+ nsAutoCString scheme;
+ nsiuri->GetScheme(scheme);
+ bool isAMessageAttachment =
+ StringEndsWith(scheme, NS_LITERAL_CSTRING("-message"));
+
+ m_attachments[newLoc]->mDeleteFile = true;
+ m_attachments[newLoc]->m_done = false;
+ m_attachments[newLoc]->SetMimeDeliveryState(this);
+
+ if (!isAMessageAttachment)
+ nsMsgNewURL(getter_AddRefs(m_attachments[newLoc]->mURL), url.get());
+
+ m_attachments[newLoc]->m_encoding = ENCODING_7BIT;
+
+ attachment->GetMacType(getter_Copies(m_attachments[newLoc]->m_xMacType));
+ attachment->GetMacCreator(getter_Copies(m_attachments[newLoc]->m_xMacCreator));
+
+ /* Count up attachments which are going to come from mail folders
+ and from NNTP servers. */
+ bool do_add_attachment = false;
+ if (isAMessageAttachment)
+ {
+ do_add_attachment = true;
+ if (!PL_strncasecmp(url.get(), "news-message://", 15))
+ (*aNewsCount)++;
+ else
+ (*aMailboxCount)++;
+
+ m_attachments[newLoc]->m_uri = url;
+ m_attachments[newLoc]->mURL = nullptr;
+ }
+ else
+ do_add_attachment = (nullptr != m_attachments[newLoc]->mURL);
+ m_attachments[newLoc]->mSendViaCloud = false;
+ if (do_add_attachment)
+ {
+ nsAutoString proposedName;
+ attachment->GetName(proposedName);
+ msg_pick_real_name(m_attachments[newLoc], proposedName.get(), mCompFields->GetCharacterSet());
+ ++newLoc;
+ }
+ }
+ }
+ }
+ }
+ return NS_OK;
+}
+
+nsresult
+nsMsgComposeAndSend::HackAttachments(nsIArray *attachments,
+ nsIArray *preloadedAttachments)
+{
+ //
+ // First, count the total number of attachments we are going to process
+ // for this operation! This is a little more complicated than you might
+ // think because we have a few ways to specify attachments. Via the nsMsgAttachmentData
+ // as well as the composition fields.
+ //
+ CountCompFieldAttachments();
+
+ // Count the preloaded attachments!
+ mPreloadedAttachmentCount = 0;
+
+ // For now, manually add the local attachments in the comp field!
+ mPreloadedAttachmentCount += mCompFieldLocalAttachments;
+ uint32_t numAttachments = 0, numPreloadedAttachments = 0;
+ if (attachments)
+ attachments->GetLength(&numAttachments);
+ if (preloadedAttachments)
+ preloadedAttachments->GetLength(&numPreloadedAttachments);
+ mPreloadedAttachmentCount += numPreloadedAttachments;
+
+ // Count the attachments we have to go retrieve! Keep in mind, that these
+ // will be APPENDED to the current list of URL's that we have gathered if
+ // this is a multpart/related send operation
+ mRemoteAttachmentCount = GetMultipartRelatedCount();
+
+ // For now, manually add the remote attachments in the comp field!
+ mRemoteAttachmentCount += mCompFieldRemoteAttachments;
+
+ mRemoteAttachmentCount += numAttachments;
+
+ m_attachment_count = mPreloadedAttachmentCount + mRemoteAttachmentCount;
+
+ uint32_t i; // counter for location in attachment array...
+ // Now create the array of attachment handlers...
+ for (i = 0; i < m_attachment_count; i++) {
+ RefPtr<nsMsgAttachmentHandler> handler = new nsMsgAttachmentHandler;
+ m_attachments.AppendElement(handler);
+ }
+
+ //
+ // First, we need to attach the files that are defined in the comp fields...
+ if (NS_FAILED(AddCompFieldLocalAttachments()))
+ return NS_ERROR_INVALID_ARG;
+
+ // Now handle the preloaded attachments...
+ if (numPreloadedAttachments > 0)
+ {
+ // These are attachments which have already been downloaded to tmp files.
+ // We merely need to point the internal attachment data at those tmp
+ // files.
+ m_pre_snarfed_attachments_p = true;
+
+ for (i = mCompFieldLocalAttachments; i < mPreloadedAttachmentCount; i++)
+ {
+ nsCOMPtr<nsIMsgAttachedFile> attachedFile = do_QueryElementAt(preloadedAttachments, i);
+ if (!attachedFile)
+ continue;
+
+ /* These attachments are already "snarfed". */
+ m_attachments[i]->mDeleteFile = false;
+ m_attachments[i]->SetMimeDeliveryState(nullptr);
+ m_attachments[i]->m_done = true;
+
+ attachedFile->GetOrigUrl(getter_AddRefs(m_attachments[i]->mURL));
+
+ attachedFile->GetType(m_attachments[i]->m_type);
+
+ // Set it to the compose fields for a default...
+ m_attachments[i]->m_charset = mCompFields->GetCharacterSet();
+
+ // If we still don't have a content type, we should really try sniff one out!
+ if (m_attachments[i]->m_type.IsEmpty())
+ m_attachments[i]->PickEncoding(mCompFields->GetCharacterSet(), this);
+
+ // For local files, if they are HTML docs and we don't have a charset, we should
+ // sniff the file and see if we can figure it out.
+ if (!m_attachments[i]->m_type.IsEmpty())
+ {
+ nsCOMPtr<nsIFile> tmpFile;
+ attachedFile->GetTmpFile(getter_AddRefs(tmpFile));
+ if (m_attachments[i]->m_type.LowerCaseEqualsLiteral(TEXT_HTML) && tmpFile)
+ {
+ char *tmpCharset = (char *)nsMsgI18NParseMetaCharset(tmpFile);
+ if (tmpCharset[0] != '\0')
+ m_attachments[i]->m_charset = tmpCharset;
+ }
+ }
+
+ attachedFile->GetDescription(m_attachments[i]->m_description);
+ attachedFile->GetRealName(m_attachments[i]->m_realName);
+ attachedFile->GetXMacType(m_attachments[i]->m_xMacType);
+ attachedFile->GetXMacCreator(m_attachments[i]->m_xMacCreator);
+ attachedFile->GetEncoding(m_attachments[i]->m_encoding);
+
+ if (m_attachments[i]->mTmpFile)
+ {
+ if (m_attachments[i]->mDeleteFile)
+ m_attachments[i]->mTmpFile->Remove(false);
+ m_attachments[i]->mTmpFile = nullptr;
+ }
+ attachedFile->GetTmpFile(getter_AddRefs(m_attachments[i]->mTmpFile));
+
+ attachedFile->GetSize(&m_attachments[i]->m_size);
+ attachedFile->GetUnprintableCount(&m_attachments[i]->m_unprintable_count);
+ attachedFile->GetHighbitCount(&m_attachments[i]->m_highbit_count);
+ attachedFile->GetCtlCount(&m_attachments[i]->m_ctl_count);
+ attachedFile->GetNullCount(&m_attachments[i]->m_null_count);
+ attachedFile->GetMaxLineLength(&m_attachments[i]->m_max_column);
+
+ /* If the attachment has an encoding, and it's not one of
+ the "null" encodings, then keep it. */
+ if (!m_attachments[i]->m_encoding.IsEmpty() &&
+ !m_attachments[i]->m_encoding.LowerCaseEqualsLiteral(ENCODING_7BIT) &&
+ !m_attachments[i]->m_encoding.LowerCaseEqualsLiteral(ENCODING_8BIT) &&
+ !m_attachments[i]->m_encoding.LowerCaseEqualsLiteral(ENCODING_BINARY))
+ m_attachments[i]->m_already_encoded_p = true;
+
+ if (m_attachments[i]->mURL)
+ msg_pick_real_name(m_attachments[i], nullptr, mCompFields->GetCharacterSet());
+ }
+ }
+
+ // First, handle the multipart related attachments if any...
+ //
+ int32_t mailbox_count = 0, news_count = 0;
+ int32_t multipartRelatedCount = GetMultipartRelatedCount();
+
+ if (multipartRelatedCount > 0)
+ {
+ nsresult rv = ProcessMultipartRelated(&mailbox_count, &news_count);
+ if (NS_FAILED(rv))
+ {
+ // The destructor will take care of the m_attachment array
+ return rv;
+ }
+ }
+
+ //
+ // Now add the comp field remote attachments...
+ //
+ if (NS_FAILED( AddCompFieldRemoteAttachments( (mPreloadedAttachmentCount + multipartRelatedCount),
+ &mailbox_count, &news_count) ))
+ return NS_ERROR_INVALID_ARG;
+
+ //
+ // Now deal remote attachments and attach multipart/related attachments (url's and such..)
+ // first!
+ //
+ if (attachments)
+ {
+ int32_t locCount = -1;
+
+ for (i = (mPreloadedAttachmentCount + GetMultipartRelatedCount() + mCompFieldRemoteAttachments); i < m_attachment_count; i++)
+ {
+ locCount++;
+ nsCOMPtr<nsIMsgAttachmentData> attachment(do_QueryElementAt(attachments, i));
+ if (!attachment)
+ continue;
+ m_attachments[i]->mDeleteFile = true;
+ m_attachments[i]->m_done = false;
+ m_attachments[i]->SetMimeDeliveryState(this);
+
+ attachment->GetUrl(getter_AddRefs(m_attachments[i]->mURL));
+
+ attachment->GetRealType(m_attachments[i]->m_overrideType);
+ m_attachments[i]->m_charset = mCompFields->GetCharacterSet();
+ attachment->GetRealEncoding(m_attachments[i]->m_overrideEncoding);
+ attachment->GetDesiredType(m_attachments[i]->m_desiredType);
+ attachment->GetDescription(m_attachments[i]->m_description);
+ attachment->GetRealName(m_attachments[i]->m_realName);
+ attachment->GetXMacType(m_attachments[i]->m_xMacType);
+ attachment->GetXMacCreator(m_attachments[i]->m_xMacCreator);
+ m_attachments[i]->m_encoding = ENCODING_7BIT;
+
+ // real name is set in the case of vcard so don't change it. XXX STILL NEEDED?
+ // m_attachments[i]->m_real_name = 0;
+
+ /* Count up attachments which are going to come from mail folders
+ and from NNTP servers. */
+ if (m_attachments[i]->mURL)
+ {
+ nsIURI *uri = m_attachments[i]->mURL;
+ bool match = false;
+ if ((NS_SUCCEEDED(uri->SchemeIs("mailbox", &match)) && match) ||
+ (NS_SUCCEEDED(uri->SchemeIs("imap", &match)) && match))
+ mailbox_count++;
+ else if ((NS_SUCCEEDED(uri->SchemeIs("news", &match)) && match) ||
+ (NS_SUCCEEDED(uri->SchemeIs("snews", &match)) && match))
+ news_count++;
+ else
+ {
+ // Additional account types need a mechanism to report that they are
+ // message protocols. If there is an nsIMsgProtocolInfo component
+ // registered for this scheme, we'll consider it a mailbox
+ // attachment.
+ nsAutoCString contractID;
+ contractID.Assign(
+ NS_LITERAL_CSTRING("@mozilla.org/messenger/protocol/info;1"));
+ nsAutoCString scheme;
+ uri->GetScheme(scheme);
+ contractID.Append(scheme);
+ nsCOMPtr<nsIMsgProtocolInfo> msgProtocolInfo =
+ do_CreateInstance(contractID.get());
+ if (msgProtocolInfo)
+ mailbox_count++;
+ }
+ if (uri)
+ msg_pick_real_name(m_attachments[i], nullptr, mCompFields->GetCharacterSet());
+ }
+ }
+ }
+
+ bool needToCallGatherMimeAttachments = true;
+
+ if (m_attachment_count > 0)
+ {
+ // If there is more than one mailbox URL, or more than one NNTP url,
+ // do the load in serial rather than parallel, for efficiency.
+ if (mailbox_count > 1 || news_count > 1)
+ m_be_synchronous_p = true;
+
+ m_attachment_pending_count = m_attachment_count;
+
+ // Start the URL attachments loading (eventually, an exit routine will
+ // call the done_callback).
+
+ for (i = 0; i < m_attachment_count; i++)
+ {
+ if (m_attachments[i]->m_done || m_attachments[i]->mSendViaCloud)
+ {
+ m_attachment_pending_count--;
+ continue;
+ }
+
+ //
+ // IF we get here and the URL is NULL, just dec the pending count and move on!!!
+ //
+ if ( (!m_attachments[i]->mURL) && (!m_attachments[i]->m_uri.Length()) )
+ {
+ m_attachments[i]->m_bogus_attachment = true;
+ m_attachments[i]->m_done = true;
+ m_attachments[i]->SetMimeDeliveryState(nullptr);
+ m_attachment_pending_count--;
+ continue;
+ }
+
+ //
+ // This only returns a failure code if NET_GetURL was not called
+ // (and thus no exit routine was or will be called.)
+ //
+
+ // Display some feedback to user...
+ nsString msg;
+ nsAutoString attachmentFileName;
+ NS_ConvertUTF8toUTF16 params(m_attachments[i]->m_realName);
+ const char16_t *formatParams[1];
+ if (!params.IsEmpty()) {
+ formatParams[0] = params.get();
+ } else if (m_attachments[i]->mURL) {
+ nsCString asciiSpec;
+ m_attachments[i]->mURL->GetAsciiSpec(asciiSpec);
+ attachmentFileName.AssignASCII(asciiSpec.get());
+ formatParams[0] = attachmentFileName.get();
+ }
+ mComposeBundle->FormatStringFromName(u"gatheringAttachment",
+ formatParams, 1, getter_Copies(msg));
+
+ if (!msg.IsEmpty())
+ {
+ SetStatusMessage(msg);
+ }
+
+ /* As SnarfAttachment will call GatherMimeAttachments when it will be done (this is an async process),
+ we need to avoid to call it ourself.
+ */
+ needToCallGatherMimeAttachments = false;
+
+ nsresult status = m_attachments[i]->SnarfAttachment(mCompFields);
+ if (NS_FAILED(status))
+ {
+ nsString errorMsg;
+ nsresult rv = ConvertToUnicode(nsMsgI18NFileSystemCharset(), m_attachments[i]->m_realName, attachmentFileName);
+ if (attachmentFileName.IsEmpty() && m_attachments[i]->mURL) {
+ nsCString asciiSpec;
+ m_attachments[i]->mURL->GetAsciiSpec(asciiSpec);
+ attachmentFileName.AssignASCII(asciiSpec.get());
+ rv = NS_OK;
+ }
+ if (NS_SUCCEEDED(rv))
+ {
+ nsCOMPtr<nsIStringBundle> bundle;
+ const char16_t *params[] = { attachmentFileName.get() };
+ mComposeBundle->FormatStringFromName(u"errorAttachingFile",
+ params, 1,
+ getter_Copies(errorMsg));
+ mSendReport->SetMessage(nsIMsgSendReport::process_Current, errorMsg.get(), false);
+ mSendReport->SetError(nsIMsgSendReport::process_Current,
+ NS_MSG_ERROR_ATTACHING_FILE,
+ false);
+ }
+ return NS_MSG_ERROR_ATTACHING_FILE;
+ }
+ if (m_be_synchronous_p)
+ break;
+ }
+ }
+
+ // If no attachments - finish now (this will call the done_callback).
+ if (needToCallGatherMimeAttachments)
+ return GatherMimeAttachments();
+
+ return NS_OK;
+}
+
+nsresult
+nsMsgComposeAndSend::InitCompositionFields(nsMsgCompFields *fields,
+ const nsACString &aOriginalMsgURI,
+ MSG_ComposeType aType)
+{
+ nsresult rv = NS_OK;
+ const char *pStr = nullptr;
+
+ mCompFields = new nsMsgCompFields();
+ if (!mCompFields)
+ return NS_ERROR_OUT_OF_MEMORY;
+
+ const char *cset = fields->GetCharacterSet();
+ // Make sure charset is sane...
+ if (!cset || !*cset)
+ {
+ mCompFields->SetCharacterSet("UTF-8");
+ }
+ else
+ {
+ mCompFields->SetCharacterSet(fields->GetCharacterSet());
+ }
+
+ // Now, we will look for a URI defined as the default FCC pref. If this is set,
+ // then SetFcc will use this value. The FCC field is a URI for the server that
+ // will hold the "Sent" folder...the
+ //
+ // First, look at what was passed in via the "fields" structure...if that was
+ // set then use it, otherwise, fall back to what is set in the prefs...
+ //
+ // But even before that, pay attention to the new OVERRIDE pref that will cancel
+ // any and all copy operations!
+ //
+ bool doFcc = true;
+ rv = mUserIdentity->GetDoFcc(&doFcc);
+ if (!doFcc)
+ {
+ // If the identity pref "fcc" is set to false, then we will not do
+ // any FCC operation!
+ mCompFields->SetFcc("");
+ }
+ else
+ {
+ bool useDefaultFCC = true;
+ const char *fieldsFCC = fields->GetFcc();
+ if (fieldsFCC && *fieldsFCC)
+ {
+ if (PL_strcasecmp(fieldsFCC, "nocopy://") == 0)
+ {
+ useDefaultFCC = false;
+ mCompFields->SetFcc("");
+ }
+ else
+ {
+ nsCOMPtr<nsIMsgFolder> folder;
+ GetExistingFolder(nsDependentCString(fieldsFCC), getter_AddRefs(folder));
+ if (folder)
+ {
+ useDefaultFCC = false;
+ mCompFields->SetFcc(mime_fix_header(fieldsFCC));
+ }
+ }
+ }
+
+ // We use default FCC setting if it's not set or was set to an invalid folder.
+ if (useDefaultFCC)
+ {
+ // Only check whether the user wants the message in the original message
+ // folder if the msgcomptype is some kind of a reply.
+ if (!aOriginalMsgURI.IsEmpty() && (
+ aType == nsIMsgCompType::Reply ||
+ aType == nsIMsgCompType::ReplyAll ||
+ aType == nsIMsgCompType::ReplyToGroup ||
+ aType == nsIMsgCompType::ReplyToSender ||
+ aType == nsIMsgCompType::ReplyToSenderAndGroup ||
+ aType == nsIMsgCompType::ReplyWithTemplate )
+ )
+ {
+ nsCOMPtr <nsIMsgAccountManager> accountManager =
+ do_GetService(NS_MSGACCOUNTMANAGER_CONTRACTID, &rv);
+ if (NS_SUCCEEDED(rv))
+ {
+ nsCOMPtr <nsIMsgDBHdr> msgHdr;
+ rv = GetMsgDBHdrFromURI(PromiseFlatCString(aOriginalMsgURI).get(),
+ getter_AddRefs(msgHdr));
+ if (NS_SUCCEEDED(rv))
+ {
+ nsCOMPtr <nsIMsgFolder> folder;
+ msgHdr->GetFolder(getter_AddRefs(folder));
+ if (NS_SUCCEEDED(rv))
+ {
+ bool canFileMessages;
+ rv = folder->GetCanFileMessages(&canFileMessages);
+ if (NS_SUCCEEDED(rv) && canFileMessages)
+ {
+ nsCOMPtr <nsIMsgIncomingServer> incomingServer;
+ rv = folder->GetServer(getter_AddRefs(incomingServer));
+ if (NS_SUCCEEDED(rv))
+ {
+ nsCString incomingServerType;
+ rv = incomingServer->GetCharValue("type", incomingServerType);
+ // Exclude RSS accounts, as they falsely report
+ // 'canFileMessages' = true
+ if (NS_SUCCEEDED(rv) && !incomingServerType.Equals("rss"))
+ {
+ bool fccReplyFollowsParent;
+ rv = mUserIdentity->GetFccReplyFollowsParent(
+ &fccReplyFollowsParent);
+ if (NS_SUCCEEDED(rv) && fccReplyFollowsParent)
+ {
+ nsCString folderURI;
+ rv = folder->GetURI(folderURI);
+ if (NS_SUCCEEDED(rv))
+ {
+ mCompFields->SetFcc(folderURI.get());
+ useDefaultFCC = false;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (useDefaultFCC)
+ {
+ nsCString uri;
+ GetFolderURIFromUserPrefs(nsMsgDeliverNow, mUserIdentity, uri);
+ mCompFields->SetFcc(MsgLowerCaseEqualsLiteral(uri, "nocopy://") ? "" : uri.get());
+ }
+ }
+ }
+
+ //
+ // Deal with an additional FCC operation for this email.
+ //
+ const char *fieldsFCC2 = fields->GetFcc2();
+ if ( (fieldsFCC2) && (*fieldsFCC2) )
+ {
+ if (PL_strcasecmp(fieldsFCC2, "nocopy://") == 0)
+ {
+ mCompFields->SetFcc2("");
+ mNeedToPerformSecondFCC = false;
+ }
+ else
+ {
+ mCompFields->SetFcc2(fieldsFCC2);
+ mNeedToPerformSecondFCC = true;
+ }
+ }
+
+ // Copy the main bodies of headers over.
+ rv = mCompFields->AddAllHeaders(fields);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ nsCOMPtr<nsISimpleEnumerator> srcAttachments;
+ fields->GetAttachments(getter_AddRefs(srcAttachments));
+ if (srcAttachments)
+ {
+ bool moreAttachments;
+ nsCOMPtr<nsISupports> element;
+ while (NS_SUCCEEDED(srcAttachments->HasMoreElements(&moreAttachments)) && moreAttachments) {
+ rv = srcAttachments->GetNext(getter_AddRefs(element));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ nsCOMPtr<nsIMsgAttachment> attachment = do_QueryInterface(element, &rv);
+ NS_ENSURE_SUCCESS(rv, rv);
+ mCompFields->AddAttachment(attachment);
+ }
+ }
+
+ AddDefaultCustomHeaders();
+
+ AddMailFollowupToHeader();
+ AddMailReplyToHeader();
+
+ if (aType == nsIMsgCompType::ForwardInline ||
+ aType == nsIMsgCompType::ForwardAsAttachment)
+ AddXForwardedMessageIdHeader();
+
+ pStr = fields->GetPriority();
+ if (pStr)
+ mCompFields->SetPriority((char *) pStr);
+
+ mCompFields->SetAttachVCard(fields->GetAttachVCard());
+ mCompFields->SetForcePlainText(fields->GetForcePlainText());
+ mCompFields->SetUseMultipartAlternative(fields->GetUseMultipartAlternative());
+ int32_t receiptType = nsIMsgMdnGenerator::eDntType;
+ fields->GetReceiptHeaderType(&receiptType);
+
+ mCompFields->SetReturnReceipt(fields->GetReturnReceipt());
+ mCompFields->SetAttachmentReminder(fields->GetAttachmentReminder());
+ mCompFields->SetDeliveryFormat(fields->GetDeliveryFormat());
+ mCompFields->SetContentLanguage(fields->GetContentLanguage());
+ mCompFields->SetReceiptHeaderType(receiptType);
+
+ mCompFields->SetDSN(fields->GetDSN());
+
+ mCompFields->SetBodyIsAsciiOnly(fields->GetBodyIsAsciiOnly());
+ mCompFields->SetForceMsgEncoding(fields->GetForceMsgEncoding());
+
+ nsCOMPtr<nsISupports> secInfo;
+ fields->GetSecurityInfo(getter_AddRefs(secInfo));
+
+ mCompFields->SetSecurityInfo(secInfo);
+
+ bool needToCheckCharset;
+ fields->GetNeedToCheckCharset(&needToCheckCharset);
+ mCompFields->SetNeedToCheckCharset(needToCheckCharset);
+
+ if ( m_deliver_mode != nsMsgSaveAsDraft && m_deliver_mode != nsMsgSaveAsTemplate )
+ {
+ // Check the fields for legitimacy...
+ return mime_sanity_check_fields (
+ mCompFields->GetFrom(), mCompFields->GetReplyTo(),
+ mCompFields->GetTo(), mCompFields->GetCc(),
+ mCompFields->GetBcc(), mCompFields->GetFcc(),
+ mCompFields->GetNewsgroups(), mCompFields->GetFollowupTo(),
+ mCompFields->GetSubject(), mCompFields->GetReferences(),
+ mCompFields->GetOrganization(), "");
+ }
+ return NS_OK;
+}
+
+// Add default headers to outgoing messages see Bug #61520
+// mail.identity.<id#>.headers pref is a comma separated value of pref names
+// containging headers to add headers are stored in
+// mail.identity.<id#>.header.<header name> grab all the headers, mime encode
+// them and add them to the other custom headers.
+nsresult
+nsMsgComposeAndSend::AddDefaultCustomHeaders() {
+ nsCString headersList;
+ // get names of prefs containing headers to add
+ nsresult rv = mUserIdentity->GetCharAttribute("headers", headersList);
+ if (NS_SUCCEEDED(rv) && !headersList.IsEmpty()) {
+ int32_t start = 0;
+ int32_t end = 0;
+ int32_t len = 0;
+ while (end != -1) {
+ end = headersList.FindChar(',', start);
+ if (end == -1) {
+ len = headersList.Length() - start;
+ } else {
+ len = end - start;
+ }
+ // grab the name of the current header pref
+ nsAutoCString headerName("header.");
+ headerName.Append(Substring(headersList, start, len));
+ start = end + 1;
+
+ nsCString headerVal;
+ rv = mUserIdentity->GetCharAttribute(headerName.get(), headerVal);
+ if (NS_SUCCEEDED(rv)) {
+ int32_t colonIdx = headerVal.FindChar(':');
+ if (colonIdx > 0) { // check that the header is *most likely* valid.
+ nsCString name(Substring(headerVal, 0, colonIdx));
+ mCompFields->SetRawHeader(name.get(),
+ Substring(headerVal, colonIdx + 1), nullptr);
+ }
+ }
+ }
+ }
+ return rv;
+}
+
+// Add Mail-Followup-To header
+// See bug #204339 and http://cr.yp.to/proto/replyto.html for details
+nsresult
+nsMsgComposeAndSend::AddMailFollowupToHeader() {
+ nsresult rv;
+
+ // If there's already a Mail-Followup-To header, don't need to do anything.
+ nsAutoCString mftHeader;
+ mCompFields->GetRawHeader(HEADER_MAIL_FOLLOWUP_TO, mftHeader);
+ if (!mftHeader.IsEmpty())
+ {
+ return NS_OK;
+ }
+
+ // Get list of subscribed mailing lists
+ nsAutoCString mailing_lists;
+ rv = mUserIdentity->GetCharAttribute("subscribed_mailing_lists", mailing_lists);
+ // Stop here if this list is missing or empty
+ if (NS_FAILED(rv) || mailing_lists.IsEmpty())
+ return NS_OK;
+
+ // Get a list of all recipients excluding bcc
+ nsDependentCString to(mCompFields->GetTo());
+ nsDependentCString cc(mCompFields->GetCc());
+ nsAutoCString recipients;
+
+ if (to.IsEmpty() && cc.IsEmpty())
+ // We have bcc recipients only, so we don't add the Mail-Followup-To header
+ return NS_OK;
+
+ if (!to.IsEmpty() && cc.IsEmpty())
+ recipients = to;
+ else if (to.IsEmpty() && !cc.IsEmpty())
+ recipients = cc;
+ else
+ {
+ recipients.Assign(to);
+ recipients.AppendLiteral(", ");
+ recipients.Append(cc);
+ }
+
+ // Remove duplicate addresses in recipients
+ nsAutoCString recipients_no_dups;
+ RemoveDuplicateAddresses(recipients, EmptyCString(), recipients_no_dups);
+
+ // Remove subscribed mailing lists from recipients...
+ nsAutoCString recipients_without_mailing_lists;
+ RemoveDuplicateAddresses(recipients_no_dups, mailing_lists,
+ recipients_without_mailing_lists);
+
+ // ... If the result is equal to the input, we don't write to a subscribed
+ // mailing list and therefore we don't add Mail-Followup-To
+ if (recipients_no_dups == recipients_without_mailing_lists)
+ return NS_OK;
+
+ // Set Mail-Followup-To
+ return mCompFields->SetRawHeader(HEADER_MAIL_FOLLOWUP_TO, recipients,
+ mCompFields->GetCharacterSet());
+}
+
+// Add Mail-Reply-To header
+// See bug #204339 and http://cr.yp.to/proto/replyto.html for details
+nsresult
+nsMsgComposeAndSend::AddMailReplyToHeader() {
+ nsresult rv;
+
+ // If there's already a Mail-Reply-To header, don't need to do anything.
+ nsAutoCString mrtHeader;
+ mCompFields->GetRawHeader(HEADER_MAIL_REPLY_TO, mrtHeader);
+ if (!mrtHeader.IsEmpty())
+ return NS_OK;
+
+ // Get list of reply-to mangling mailing lists
+ nsAutoCString mailing_lists;
+ rv = mUserIdentity->GetCharAttribute("replyto_mangling_mailing_lists", mailing_lists);
+ // Stop here if this list is missing or empty
+ if (NS_FAILED(rv) || mailing_lists.IsEmpty())
+ return NS_OK;
+
+ // MRT will be set if the recipients of the message contains at least one
+ // of the addresses in mailing_lists or if mailing_lists has '*' as first
+ // character. The latter case gives the user an easy way to always set
+ // the MRT header. Notice that this behaviour wouldn't make sense for MFT
+ // in AddMailFollowupToHeader() above.
+
+ if (mailing_lists[0] != '*') {
+ // Get a list of all recipients excluding bcc
+ nsDependentCString to(mCompFields->GetTo());
+ nsDependentCString cc(mCompFields->GetCc());
+ nsAutoCString recipients;
+
+ if (to.IsEmpty() && cc.IsEmpty())
+ // We have bcc recipients only, so we don't add the Mail-Reply-To header
+ return NS_OK;
+
+ if (!to.IsEmpty() && cc.IsEmpty())
+ recipients = to;
+ else if (to.IsEmpty() && !cc.IsEmpty())
+ recipients = cc;
+ else
+ {
+ recipients.Assign(to);
+ recipients.AppendLiteral(", ");
+ recipients.Append(cc);
+ }
+
+ // Remove duplicate addresses in recipients
+ nsAutoCString recipients_no_dups;
+ RemoveDuplicateAddresses(recipients, EmptyCString(), recipients_no_dups);
+
+ // Remove reply-to mangling mailing lists from recipients...
+ nsAutoCString recipients_without_mailing_lists;
+ RemoveDuplicateAddresses(recipients_no_dups, mailing_lists,
+ recipients_without_mailing_lists);
+
+ // ... If the result is equal to the input, none of the recipients
+ // occure in the MRT addresses and therefore we stop here.
+ if (recipients_no_dups == recipients_without_mailing_lists)
+ return NS_OK;
+ }
+
+ // Set Mail-Reply-To
+ nsAutoCString replyTo, mailReplyTo;
+ replyTo = mCompFields->GetReplyTo();
+ if (replyTo.IsEmpty())
+ mailReplyTo = mCompFields->GetFrom();
+ else
+ mailReplyTo = replyTo;
+
+ mCompFields->SetRawHeader(HEADER_MAIL_REPLY_TO, mailReplyTo,
+ mCompFields->GetCharacterSet());
+ return NS_OK;
+}
+
+nsresult
+nsMsgComposeAndSend::AddXForwardedMessageIdHeader() {
+ return mCompFields->SetRawHeader("X-Forwarded-Message-Id",
+ nsDependentCString(mCompFields->GetReferences()), nullptr);
+}
+
+nsresult
+nsMsgComposeAndSend::SnarfAndCopyBody(const nsACString &attachment1_body,
+ const char *attachment1_type)
+{
+ //
+ // If we are here, then just process the body from what was
+ // passed in the attachment1_body field.
+ //
+ // strip out whitespaces from the end of body ONLY.
+ nsAutoCString body(attachment1_body);
+ body.Trim(" ", false, true);
+
+ if (body.Length() > 0)
+ {
+ m_attachment1_body = ToNewCString(body);
+ if (!m_attachment1_body) {
+ return NS_ERROR_OUT_OF_MEMORY;
+ }
+ m_attachment1_body_length = body.Length();
+ }
+
+ PR_FREEIF(m_attachment1_type);
+ m_attachment1_type = PL_strdup (attachment1_type);
+ PR_FREEIF(m_attachment1_encoding);
+ m_attachment1_encoding = PL_strdup (ENCODING_8BIT);
+ return NS_OK;
+}
+
+nsresult
+nsMsgComposeAndSend::Init(
+ nsIMsgIdentity *aUserIdentity,
+ const char *aAccountKey,
+ nsMsgCompFields *fields,
+ nsIFile *sendFile,
+ bool digest_p,
+ bool dont_deliver_p,
+ nsMsgDeliverMode mode,
+ nsIMsgDBHdr *msgToReplace,
+ const char *attachment1_type,
+ const nsACString &attachment1_body,
+ nsIArray *attachments,
+ nsIArray *preloaded_attachments,
+ const char *password,
+ const nsACString &aOriginalMsgURI,
+ MSG_ComposeType aType)
+{
+ nsresult rv = NS_OK;
+
+ //Let make sure we retreive the correct number of related parts. It may have changed since last time
+ GetMultipartRelatedCount(true);
+
+ nsString msg;
+ if (!mComposeBundle)
+ {
+ nsCOMPtr<nsIStringBundleService> bundleService =
+ mozilla::services::GetStringBundleService();
+ NS_ENSURE_TRUE(bundleService, NS_ERROR_UNEXPECTED);
+ nsCOMPtr<nsIStringBundle> bundle;
+ rv = bundleService->CreateBundle("chrome://messenger/locale/messengercompose/composeMsgs.properties", getter_AddRefs(mComposeBundle));
+ NS_ENSURE_SUCCESS(rv, rv);
+ }
+
+ // Tell the user we are assembling the message...
+ mComposeBundle->GetStringFromName(u"assemblingMailInformation", getter_Copies(msg));
+ SetStatusMessage(msg);
+ if (mSendReport)
+ mSendReport->SetCurrentProcess(nsIMsgSendReport::process_BuildMessage);
+
+ //
+ // The Init() method should initialize a send operation for full
+ // blown create and send operations as well as just the "send a file"
+ // operations.
+ //
+ m_dont_deliver_p = dont_deliver_p;
+ m_deliver_mode = mode;
+ mMsgToReplace = msgToReplace;
+
+ mUserIdentity = aUserIdentity;
+ mAccountKey = aAccountKey;
+ NS_ASSERTION(mUserIdentity, "Got null identity!\n");
+ if (!mUserIdentity) return NS_ERROR_UNEXPECTED;
+
+ //
+ // First sanity check the composition fields parameter and
+ // see if we should continue
+ //
+ if (!fields)
+ return NS_ERROR_OUT_OF_MEMORY;
+
+ m_digest_p = digest_p;
+
+ //
+ // Needed for mime encoding!
+ //
+ bool strictly_mime = true;
+ nsCOMPtr<nsIPrefBranch> pPrefBranch(do_GetService(NS_PREFSERVICE_CONTRACTID));
+ if (pPrefBranch)
+ {
+ rv = pPrefBranch->GetBoolPref(PREF_MAIL_STRICTLY_MIME, &strictly_mime);
+ rv = pPrefBranch->GetIntPref(PREF_MAIL_MESSAGE_WARNING_SIZE, (int32_t *) &mMessageWarningSize);
+ }
+
+ nsCOMPtr<nsIMsgComposeSecure> secureCompose
+ = do_CreateInstance(NS_MSGCOMPOSESECURE_CONTRACTID, &rv);
+ // It's not an error scenario if there is no secure compose.
+ // The S/MIME extension may be unavailable.
+ if (NS_SUCCEEDED(rv) && secureCompose)
+ {
+ bool requiresEncryptionWork = false;
+ rv = secureCompose->RequiresCryptoEncapsulation(aUserIdentity, fields,
+ &requiresEncryptionWork);
+ NS_ENSURE_SUCCESS(rv, rv);
+ if (requiresEncryptionWork)
+ {
+ strictly_mime = true;
+ // RFC2633 3.1.3 doesn't require multipart/signed entities to have
+ // transfer encoding applied for ascii, but do it anyway to make sure
+ // the content (e.g. line endings) isn't mangled along the way.
+ fields->SetForceMsgEncoding(true);
+ }
+ }
+
+ nsMsgMIMESetConformToStandard(strictly_mime);
+ mime_use_quoted_printable_p = strictly_mime;
+
+ rv = InitCompositionFields(fields, aOriginalMsgURI, aType);
+ if (NS_FAILED(rv))
+ return rv;
+
+ //
+ // At this point, if we are only creating this object to do
+ // send operations on externally created RFC822 disk files,
+ // make sure we have setup the appropriate nsIFile and
+ // move on with life.
+ //
+ //
+ // First check to see if we are doing a send operation on an external file
+ // or creating the file itself.
+ //
+ if (sendFile)
+ {
+ mTempFile = sendFile;
+ return NS_OK;
+ }
+
+ // Ok, now watch me pull a rabbit out of my hat....what we need
+ // to do here is figure out what the body will be. If this is a
+ // MHTML request, then we need to do some processing of the document
+ // and figure out what we need to package along with this message
+ // to send. See ProcessMultipartRelated() for further details.
+ //
+
+ //
+ // If we don't have an editor, then we won't be doing multipart related processing
+ // for the body, so make a copy of the one passed in.
+ //
+ if (!mEditor)
+ {
+ SnarfAndCopyBody(attachment1_body, attachment1_type);
+ mOriginalHTMLBody = ToNewCString(attachment1_body);
+ }
+ else if (GetMultipartRelatedCount() == 0) // Only do this if there are not embedded objects
+ {
+ rv = GetBodyFromEditor();
+ if (NS_FAILED(rv))
+ return rv;
+ }
+
+ mSmtpPassword = password;
+
+ return HackAttachments(attachments, preloaded_attachments);
+}
+
+NS_IMETHODIMP nsMsgComposeAndSend::SendDeliveryCallback(nsIURI *aUrl, bool inIsNewsDelivery, nsresult aExitCode)
+{
+ if (inIsNewsDelivery)
+ {
+ if (NS_FAILED(aExitCode))
+ if (aExitCode != NS_ERROR_ABORT && !NS_IS_MSG_ERROR(aExitCode))
+ aExitCode = NS_ERROR_POST_FAILED;
+
+ DeliverAsNewsExit(aUrl, aExitCode);
+ }
+ else
+ {
+ if (NS_FAILED(aExitCode))
+ {
+#ifdef __GNUC__
+// Temporary workaroung until bug 783526 is fixed.
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wswitch"
+#endif
+ switch (aExitCode)
+ {
+ case NS_ERROR_UNKNOWN_HOST:
+ case NS_ERROR_UNKNOWN_PROXY_HOST:
+ aExitCode = NS_ERROR_SMTP_SEND_FAILED_UNKNOWN_SERVER;
+ break;
+ case NS_ERROR_CONNECTION_REFUSED:
+ case NS_ERROR_PROXY_CONNECTION_REFUSED:
+ aExitCode = NS_ERROR_SMTP_SEND_FAILED_REFUSED;
+ break;
+ case NS_ERROR_NET_INTERRUPT:
+ aExitCode = NS_ERROR_SMTP_SEND_FAILED_INTERRUPTED;
+ break;
+ case NS_ERROR_NET_TIMEOUT:
+ case NS_ERROR_NET_RESET:
+ aExitCode = NS_ERROR_SMTP_SEND_FAILED_TIMEOUT;
+ break;
+ case NS_ERROR_SMTP_PASSWORD_UNDEFINED:
+ // nothing to do, just keep the code
+ break;
+ default:
+ if (aExitCode != NS_ERROR_ABORT && !NS_IS_MSG_ERROR(aExitCode))
+ aExitCode = NS_ERROR_SMTP_SEND_FAILED_UNKNOWN_REASON;
+ break;
+ }
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
+ }
+ DeliverAsMailExit(aUrl, aExitCode);
+ }
+
+ return aExitCode;
+}
+
+nsresult
+nsMsgComposeAndSend::DeliverMessage()
+{
+ if (mSendProgress)
+ {
+ bool canceled = false;
+ mSendProgress->GetProcessCanceledByUser(&canceled);
+ if (canceled)
+ return NS_ERROR_ABORT;
+ }
+
+ bool mail_p = ((mCompFields->GetTo() && *mCompFields->GetTo()) ||
+ (mCompFields->GetCc() && *mCompFields->GetCc()) ||
+ (mCompFields->GetBcc() && *mCompFields->GetBcc()));
+ bool news_p = mCompFields->GetNewsgroups() && *(mCompFields->GetNewsgroups());
+ NS_ASSERTION(!( m_deliver_mode != nsMsgSaveAsDraft && m_deliver_mode != nsMsgSaveAsTemplate) || (mail_p || news_p), "message without destination");
+ if (m_deliver_mode == nsMsgQueueForLater ||
+ m_deliver_mode == nsMsgDeliverBackground ||
+ m_deliver_mode == nsMsgSaveAsDraft ||
+ m_deliver_mode == nsMsgSaveAsTemplate)
+ return SendToMagicFolder(m_deliver_mode);
+
+ //
+ // Ok, we are about to send the file that we have built up...but what
+ // if this is a mongo email...we should have a way to warn the user that
+ // they are about to do something they may not want to do.
+ //
+ int64_t fileSize;
+ nsresult rv = mTempFile->GetFileSize(&fileSize);
+ if (NS_FAILED(rv))
+ return NS_ERROR_FAILURE;
+
+ if ((mMessageWarningSize > 0) && (fileSize > mMessageWarningSize) && (mGUINotificationEnabled))
+ {
+ bool abortTheSend = false;
+ nsString msg;
+ nsAutoString formattedFileSize;
+ FormatFileSize(fileSize, true, formattedFileSize);
+ const char16_t* params[] = { formattedFileSize.get() };
+ mComposeBundle->FormatStringFromName(u"largeMessageSendWarning",
+ params, 1, getter_Copies(msg));
+
+ if (!msg.IsEmpty())
+ {
+ nsCOMPtr<nsIPrompt> prompt;
+ GetDefaultPrompt(getter_AddRefs(prompt));
+ nsMsgAskBooleanQuestionByString(prompt, msg.get(), &abortTheSend);
+ if (!abortTheSend)
+ {
+ nsresult ignoreMe;
+ Fail(NS_ERROR_BUT_DONT_SHOW_ALERT, msg.get(), &ignoreMe);
+ return NS_ERROR_FAILURE;
+ }
+ }
+ }
+
+ if (news_p)
+ {
+ if (mail_p)
+ mSendMailAlso = true;
+
+ return DeliverFileAsNews(); /* will call DeliverFileAsMail if it needs to */
+ }
+ else if (mail_p)
+ return DeliverFileAsMail();
+ else
+ return NS_ERROR_UNEXPECTED;
+ return NS_OK;
+}
+
+
+nsresult
+nsMsgComposeAndSend::DeliverFileAsMail()
+{
+ char *buf, *buf2;
+ buf = (char *) PR_Malloc ((mCompFields->GetTo() ? PL_strlen (mCompFields->GetTo()) + 10 : 0) +
+ (mCompFields->GetCc() ? PL_strlen (mCompFields->GetCc()) + 10 : 0) +
+ (mCompFields->GetBcc() ? PL_strlen (mCompFields->GetBcc()) + 10 : 0) +
+ 10);
+
+ if (mSendReport)
+ mSendReport->SetCurrentProcess(nsIMsgSendReport::process_SMTP);
+
+ nsCOMPtr<nsIPrompt> promptObject;
+ GetDefaultPrompt(getter_AddRefs(promptObject));
+
+ if (!buf)
+ {
+ nsresult ignoreMe;
+ Fail(NS_ERROR_OUT_OF_MEMORY, nullptr, &ignoreMe);
+ NotifyListenerOnStopSending(nullptr, NS_ERROR_OUT_OF_MEMORY, nullptr, nullptr);
+ return NS_ERROR_OUT_OF_MEMORY;
+ }
+
+ bool collectOutgoingAddresses = true;
+ nsCOMPtr<nsIPrefBranch> pPrefBranch(do_GetService(NS_PREFSERVICE_CONTRACTID));
+ if (pPrefBranch)
+ pPrefBranch->GetBoolPref(PREF_MAIL_COLLECT_EMAIL_ADDRESS_OUTGOING, &collectOutgoingAddresses);
+
+ nsCOMPtr<nsIAbAddressCollector> addressCollector =
+ do_GetService(NS_ABADDRESSCOLLECTOR_CONTRACTID);
+
+ bool collectAddresses = (collectOutgoingAddresses && addressCollector);
+ uint32_t sendFormat = nsIAbPreferMailFormat::unknown;
+
+ // this code is not ready yet
+ // see bug #44494 for more details
+ // so for now, just pass in nsIAbPreferMailFormat::unknown
+ // which will have no effect on the "prefers" attribute in the ab
+#if 0
+ bool forcePlainText = mCompFields->GetForcePlainText();
+ bool useMultipartAlternative = mCompFields->GetUseMultipartAlternative();
+ // see GenericSendMessage() in MsgComposeCommands.js for the reverse logic
+ // if we choose to send both (html and plain) remember html.
+ if (forcePlainText && !useMultipartAlternative)
+ {
+ // for now, don't remember the "plaintext" decision.
+ // we could get in here because while sending html mail
+ // the body was "convertible", but that doesn't mean
+ // we intended to force plain text here.
+ // so for now, use "unknown" which will have no effect on the
+ // "prefers" attribute in the ab.
+ // see bug #245520 for more details
+ // sendFormat = nsIAbPreferMailFormat::plaintext;
+ sendFormat = nsIAbPreferMailFormat::unknown;
+ }
+ else if (!forcePlainText)
+ sendFormat = nsIAbPreferMailFormat::html;
+ else
+ NS_ERROR("unknown send format, should not happen");
+#endif
+
+ PL_strcpy (buf, "");
+ buf2 = buf + PL_strlen (buf);
+ if (mCompFields->GetTo() && *mCompFields->GetTo())
+ {
+ PL_strcat (buf2, mCompFields->GetTo());
+ if (addressCollector)
+ addressCollector->CollectAddress(nsCString(mCompFields->GetTo()),
+ collectAddresses /* create card if one doesn't exist */, sendFormat);
+ }
+ if (mCompFields->GetCc() && *mCompFields->GetCc()) {
+ if (*buf2) PL_strcat (buf2, ",");
+ PL_strcat (buf2, mCompFields->GetCc());
+ if (addressCollector)
+ addressCollector->CollectAddress(nsCString(mCompFields->GetCc()),
+ collectAddresses /* create card if one doesn't exist */, sendFormat);
+ }
+ if (mCompFields->GetBcc() && *mCompFields->GetBcc()) {
+ if (*buf2) PL_strcat (buf2, ",");
+ PL_strcat (buf2, mCompFields->GetBcc());
+ if (addressCollector)
+ addressCollector->CollectAddress(nsCString(mCompFields->GetBcc()),
+ collectAddresses /* create card if one doesn't exist */, sendFormat);
+ }
+
+ // We need undo groups to keep only the addresses
+ nsresult rv = StripOutGroupNames(buf);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ // Ok, now MIME II encode this to prevent 8bit problems...
+ char *convbuf = nsMsgI18NEncodeMimePartIIStr(buf, true,
+ mCompFields->GetCharacterSet(), 0, nsMsgMIMEGetConformToStandard());
+ if (convbuf)
+ {
+ // MIME-PartII conversion
+ PR_FREEIF(buf);
+ buf = convbuf;
+ }
+
+ nsCString escaped_buf;
+ MsgEscapeString(nsDependentCString(buf), nsINetUtil::ESCAPE_URL_PATH, escaped_buf);
+
+ if (!escaped_buf.IsEmpty())
+ {
+ NS_Free(buf);
+ buf = ToNewCString(escaped_buf);
+ }
+
+ nsCOMPtr<nsISmtpService> smtpService(do_GetService(NS_SMTPSERVICE_CONTRACTID, &rv));
+ if (NS_SUCCEEDED(rv) && smtpService)
+ {
+ MsgDeliveryListener *deliveryListener = new MsgDeliveryListener(this, false);
+ if (!deliveryListener)
+ return NS_ERROR_OUT_OF_MEMORY;
+
+ // we used to get the prompt from the compose window and we'd pass that in
+ // to the smtp protocol as the prompt to use. But when you send a message,
+ // we dismiss the compose window.....so you are parenting off of a window that
+ // isn't there. To have it work correctly I think we want the alert dialogs to be modal
+ // to the top most mail window...after all, that's where we are going to be sending status
+ // update information too....
+
+ nsCOMPtr<nsIInterfaceRequestor> callbacks;
+ GetNotificationCallbacks(getter_AddRefs(callbacks));
+
+ // Tell the user we are sending the message!
+ nsString msg;
+ mComposeBundle->GetStringFromName(u"sendingMessage", getter_Copies(msg));
+ SetStatusMessage(msg);
+ nsCOMPtr<nsIMsgStatusFeedback> msgStatus (do_QueryInterface(mSendProgress));
+ // if the sendProgress isn't set, let's use the member variable.
+ if (!msgStatus)
+ msgStatus = do_QueryInterface(mStatusFeedback);
+
+ nsCOMPtr<nsIURI> runningUrl;
+ rv = smtpService->SendMailMessage(mTempFile, buf, mUserIdentity,
+ mSmtpPassword.get(), deliveryListener, msgStatus,
+ callbacks, mCompFields->GetDSN(),
+ getter_AddRefs(runningUrl),
+ getter_AddRefs(mRunningRequest));
+ // set envid on the returned URL
+ if (NS_SUCCEEDED(rv))
+ {
+ nsCOMPtr<nsISmtpUrl> smtpUrl(do_QueryInterface(runningUrl, &rv));
+ if (NS_SUCCEEDED(rv))
+ smtpUrl->SetDsnEnvid(nsDependentCString(mCompFields->GetMessageId()));
+ }
+ }
+
+ PR_FREEIF(buf); // free the buf because we are done with it....
+ return rv;
+}
+
+nsresult
+nsMsgComposeAndSend::DeliverFileAsNews()
+{
+ nsresult rv = NS_OK;
+ if (!(mCompFields->GetNewsgroups()))
+ return rv;
+
+ if (mSendReport)
+ mSendReport->SetCurrentProcess(nsIMsgSendReport::process_NNTP);
+
+ nsCOMPtr<nsIPrompt> promptObject;
+ GetDefaultPrompt(getter_AddRefs(promptObject));
+
+ nsCOMPtr<nsINntpService> nntpService(do_GetService(NS_NNTPSERVICE_CONTRACTID, &rv));
+
+ if (NS_SUCCEEDED(rv) && nntpService)
+ {
+ MsgDeliveryListener *deliveryListener = new MsgDeliveryListener(this, true);
+ if (!deliveryListener)
+ return NS_ERROR_OUT_OF_MEMORY;
+
+ // Tell the user we are posting the message!
+ nsString msg;
+ mComposeBundle->GetStringFromName(u"postingMessage",
+ getter_Copies(msg));
+ SetStatusMessage(msg);
+
+ nsCOMPtr <nsIMsgMailSession> mailSession = do_GetService(NS_MSGMAILSESSION_CONTRACTID, &rv);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ // JFD TODO: we should use GetDefaultPrompt instead
+ nsCOMPtr<nsIMsgWindow> msgWindow;
+ rv = mailSession->GetTopmostMsgWindow(getter_AddRefs(msgWindow));
+ // see bug #163139
+ // we might not have a msg window if only the compose window is open.
+ if(NS_FAILED(rv))
+ msgWindow = nullptr;
+
+ rv = nntpService->PostMessage(mTempFile, mCompFields->GetNewsgroups(), mAccountKey.get(),
+ deliveryListener, msgWindow, nullptr);
+ if (NS_FAILED(rv)) return rv;
+ }
+
+ return rv;
+}
+
+NS_IMETHODIMP
+nsMsgComposeAndSend::Fail(nsresult aFailureCode, const char16_t *aErrorMsg,
+ nsresult *aResult)
+{
+ NS_ENSURE_ARG_POINTER(aResult);
+ *aResult = aFailureCode;
+
+ if (NS_FAILED(aFailureCode))
+ {
+ nsCOMPtr<nsIPrompt> prompt;
+ GetDefaultPrompt(getter_AddRefs(prompt));
+
+ if (mSendReport)
+ {
+ int32_t process;
+ if (NS_SUCCEEDED(mSendReport->GetCurrentProcess(&process)) && process == nsIMsgSendReport::process_Current)
+ {
+ // currentProcess isn't set yet, so we need another value.
+ mSendReport->SetCurrentProcess(nsIMsgSendReport::process_BuildMessage);
+ }
+ mSendReport->SetError(nsIMsgSendReport::process_Current, aFailureCode, false);
+ mSendReport->SetMessage(nsIMsgSendReport::process_Current, aErrorMsg, false);
+ mSendReport->DisplayReport(prompt, true, true, aResult);
+ }
+ else
+ {
+ if (aFailureCode != NS_ERROR_BUT_DONT_SHOW_ALERT)
+ nsMsgDisplayMessageByName(prompt, u"sendFailed");
+ }
+ }
+
+ if (NS_SUCCEEDED(m_status))
+ m_status = NS_ERROR_BUT_DONT_SHOW_ALERT;
+
+ //Stop any pending process...
+ Abort();
+
+ return NS_OK;
+}
+
+nsresult
+nsMsgComposeAndSend::FormatStringWithSMTPHostNameByName(const char16_t* aMsgName, char16_t **aString)
+{
+ NS_ENSURE_ARG(aString);
+
+ nsresult rv;
+ nsCOMPtr<nsISmtpService> smtpService(do_GetService(NS_SMTPSERVICE_CONTRACTID, &rv));
+ NS_ENSURE_SUCCESS(rv,rv);
+
+ // Get the smtp hostname and format the string.
+ nsCString smtpHostName;
+ nsCOMPtr<nsISmtpServer> smtpServer;
+ rv = smtpService->GetServerByIdentity(mUserIdentity, getter_AddRefs(smtpServer));
+ if (NS_SUCCEEDED(rv))
+ smtpServer->GetHostname(smtpHostName);
+
+ nsAutoString hostStr;
+ CopyASCIItoUTF16(smtpHostName, hostStr);
+ const char16_t *params[] = { hostStr.get() };
+ if (NS_SUCCEEDED(rv))
+ mComposeBundle->FormatStringFromName(aMsgName, params, 1, aString);
+ return rv;
+}
+
+void
+nsMsgComposeAndSend::DoDeliveryExitProcessing(nsIURI * aUri, nsresult aExitCode, bool aCheckForMail)
+{
+ // If we fail on the news delivery, no sense in going on so just notify
+ // the user and exit.
+ if (NS_FAILED(aExitCode))
+ {
+ const char16_t* exitString = errorStringNameForErrorCode(aExitCode);
+ nsString eMsg;
+ if (aExitCode == NS_ERROR_SMTP_SEND_FAILED_UNKNOWN_SERVER ||
+ aExitCode == NS_ERROR_SMTP_SEND_FAILED_UNKNOWN_REASON ||
+ aExitCode == NS_ERROR_SMTP_SEND_FAILED_REFUSED ||
+ aExitCode == NS_ERROR_SMTP_SEND_FAILED_INTERRUPTED ||
+ aExitCode == NS_ERROR_SMTP_SEND_FAILED_TIMEOUT ||
+ aExitCode == NS_ERROR_SMTP_PASSWORD_UNDEFINED ||
+ aExitCode == NS_ERROR_SMTP_AUTH_FAILURE ||
+ aExitCode == NS_ERROR_SMTP_AUTH_GSSAPI ||
+ aExitCode == NS_ERROR_SMTP_AUTH_MECH_NOT_SUPPORTED ||
+ aExitCode == NS_ERROR_SMTP_AUTH_NOT_SUPPORTED ||
+ aExitCode == NS_ERROR_SMTP_AUTH_CHANGE_ENCRYPT_TO_PLAIN_NO_SSL ||
+ aExitCode == NS_ERROR_SMTP_AUTH_CHANGE_ENCRYPT_TO_PLAIN_SSL ||
+ aExitCode == NS_ERROR_SMTP_AUTH_CHANGE_PLAIN_TO_ENCRYPT ||
+ aExitCode == NS_ERROR_STARTTLS_FAILED_EHLO_STARTTLS) {
+ FormatStringWithSMTPHostNameByName(exitString, getter_Copies(eMsg));
+ } else {
+ mComposeBundle->GetStringFromName(exitString, getter_Copies(eMsg));
+ }
+
+ Fail(aExitCode, eMsg.get(), &aExitCode);
+ NotifyListenerOnStopSending(nullptr, aExitCode, nullptr, nullptr);
+ return;
+ }
+
+ if (aCheckForMail)
+ {
+ if ((mCompFields->GetTo() && *mCompFields->GetTo()) ||
+ (mCompFields->GetCc() && *mCompFields->GetCc()) ||
+ (mCompFields->GetBcc() && *mCompFields->GetBcc()))
+ {
+ // If we're sending this news message to mail as well, start it now.
+ // Completion and further errors will be handled there.
+ DeliverFileAsMail();
+ return;
+ }
+ }
+
+ //
+ // Tell the listeners that we are done with the sending operation...
+ //
+ NotifyListenerOnStopSending(mCompFields->GetMessageId(),
+ aExitCode,
+ nullptr,
+ nullptr);
+
+ // If we hit here, we are done with delivery!
+ //
+ // Just call the DoFCC() method and if that fails, then we should just
+ // cleanup and get out. If DoFCC "succeeds", then all that means is the
+ // async copy operation has been started and we will be notified later
+ // when it is done. DON'T cleanup until the copy is complete and don't
+ // notify the listeners with OnStop() until we are done.
+ //
+ // For now, we don't need to do anything here, but the code will stay this
+ // way until later...
+ //
+
+ DoFcc();
+}
+
+NS_IMETHODIMP
+nsMsgComposeAndSend::DeliverAsMailExit(nsIURI *aUrl, nsresult aExitCode)
+{
+ DoDeliveryExitProcessing(aUrl, aExitCode, false);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsMsgComposeAndSend::DeliverAsNewsExit(nsIURI *aUrl, nsresult aExitCode)
+{
+ DoDeliveryExitProcessing(aUrl, aExitCode, mSendMailAlso);
+ return NS_OK;
+}
+
+bool nsMsgComposeAndSend::CanSaveMessagesToFolder(const char *folderURL)
+{
+ nsresult rv;
+ nsCOMPtr<nsIRDFService> rdf(do_GetService("@mozilla.org/rdf/rdf-service;1", &rv));
+ if (NS_FAILED(rv))
+ return false;
+
+ nsCOMPtr<nsIRDFResource> resource;
+ rv = rdf->GetResource(nsDependentCString(folderURL), getter_AddRefs(resource));
+ if (NS_FAILED(rv))
+ return false;
+
+ nsCOMPtr <nsIMsgFolder> thisFolder;
+ thisFolder = do_QueryInterface(resource, &rv);
+ if (NS_FAILED(rv) || !thisFolder)
+ return false;
+
+ nsCOMPtr<nsIMsgIncomingServer> server;
+ rv = thisFolder->GetServer(getter_AddRefs(server));
+ if (NS_FAILED(rv) || !server)
+ return false;
+
+ // See if we are allowed to save/file msgs to this folder.
+ bool canSave;
+ rv = server->GetCanFileMessagesOnServer(&canSave);
+ return canSave;
+}
+
+//
+// Now, start the appropriate copy operation.
+//
+nsresult
+nsMsgComposeAndSend::DoFcc()
+{
+ //
+ // Just cleanup and return success if we're not allowed to save msgs to FCC folder.
+ //
+ const char* fcc = mCompFields->GetFcc();
+ if (!fcc || !*fcc || !CanSaveMessagesToFolder(fcc))
+ {
+
+ // It is the caller's responsibility to say we've stopped sending, so just
+ // let the listeners know we're not doing a copy.
+ NotifyListenerOnStopCopy(NS_OK); // For closure of compose window...
+ return NS_OK;
+ }
+
+ if (mSendReport)
+ mSendReport->SetCurrentProcess(nsIMsgSendReport::process_Copy);
+
+ //
+ // If we are here, then we need to save off the FCC file to save and
+ // start the copy operation. MimeDoFCC() will take care of all of this
+ // for us.
+ //
+ nsresult rv = MimeDoFCC(mTempFile,
+ nsMsgDeliverNow,
+ mCompFields->GetBcc(),
+ mCompFields->GetFcc(),
+ mCompFields->GetNewspostUrl());
+ if (NS_FAILED(rv))
+ {
+ //
+ // If we hit here, the copy operation FAILED and we should at least tell the
+ // user that it did fail but the send operation has already succeeded.
+ //
+ NotifyListenerOnStopCopy(rv);
+ }
+
+ return rv;
+}
+
+NS_IMETHODIMP
+nsMsgComposeAndSend::NotifyListenerOnStartSending(const char *aMsgID, uint32_t aMsgSize)
+{
+ if (mListener)
+ mListener->OnStartSending(aMsgID, aMsgSize);
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsMsgComposeAndSend::NotifyListenerOnProgress(const char *aMsgID, uint32_t aProgress, uint32_t aProgressMax)
+{
+ if (mListener)
+ mListener->OnProgress(aMsgID, aProgress, aProgressMax);
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsMsgComposeAndSend::NotifyListenerOnStatus(const char *aMsgID, const char16_t *aMsg)
+{
+ if (mListener)
+ mListener->OnStatus(aMsgID, aMsg);
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsMsgComposeAndSend::NotifyListenerOnStopSending(const char *aMsgID, nsresult aStatus, const char16_t *aMsg,
+ nsIFile *returnFile)
+{
+ if (mListener != nullptr)
+ mListener->OnStopSending(aMsgID, aStatus, aMsg, returnFile);
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsMsgComposeAndSend::NotifyListenerOnStartCopy()
+{
+ nsCOMPtr<nsIMsgCopyServiceListener> copyListener;
+
+ if (mListener)
+ {
+ copyListener = do_QueryInterface(mListener);
+ if (copyListener)
+ copyListener->OnStartCopy();
+ }
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsMsgComposeAndSend::NotifyListenerOnProgressCopy(uint32_t aProgress,
+ uint32_t aProgressMax)
+{
+ nsCOMPtr<nsIMsgCopyServiceListener> copyListener;
+
+ if (mListener)
+ {
+ copyListener = do_QueryInterface(mListener);
+ if (copyListener)
+ copyListener->OnProgress(aProgress, aProgressMax);
+ }
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsMsgComposeAndSend::SetMessageKey(nsMsgKey aMessageKey)
+{
+ m_messageKey = aMessageKey;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsMsgComposeAndSend::GetMessageKey(nsMsgKey *aMessageKey)
+{
+ *aMessageKey = m_messageKey;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsMsgComposeAndSend::GetFolderUri(nsACString &aFolderUri)
+{
+ aFolderUri = m_folderName;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsMsgComposeAndSend::GetPartForDomIndex(int32_t aDomIndex, nsACString &aPartNum)
+{
+ aPartNum = m_partNumbers.SafeElementAt(aDomIndex, EmptyCString());
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsMsgComposeAndSend::GetMessageId(nsACString& aMessageId)
+{
+ nsresult rv = NS_OK;
+ if (mCompFields)
+ aMessageId = mCompFields->GetMessageId();
+ else
+ rv = NS_ERROR_NULL_POINTER;
+ return rv;
+}
+
+NS_IMETHODIMP
+nsMsgComposeAndSend::NotifyListenerOnStopCopy(nsresult aStatus)
+{
+ // This is one per copy so make sure we clean this up first.
+ mCopyObj = nullptr;
+
+ // Set a status message...
+ nsString msg;
+ if (NS_SUCCEEDED(aStatus))
+ mComposeBundle->GetStringFromName(u"copyMessageComplete", getter_Copies(msg));
+ else
+ mComposeBundle->GetStringFromName(u"copyMessageFailed", getter_Copies(msg));
+
+ SetStatusMessage(msg);
+ nsCOMPtr<nsIPrompt> prompt;
+ GetDefaultPrompt(getter_AddRefs(prompt));
+
+ if (NS_FAILED(aStatus))
+ {
+ nsresult rv;
+ nsCOMPtr<nsIStringBundleService> bundleService =
+ mozilla::services::GetStringBundleService();
+ NS_ENSURE_TRUE(bundleService, NS_ERROR_UNEXPECTED);
+ nsCOMPtr<nsIStringBundle> bundle;
+ rv = bundleService->CreateBundle("chrome://messenger/locale/messengercompose/composeMsgs.properties", getter_AddRefs(bundle));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ nsString msg;
+ const char16_t *formatStrings[] = { mSavedToFolderName.get() };
+
+ rv = bundle->FormatStringFromName(u"errorSavingMsg",
+ formatStrings, 1,
+ getter_Copies(msg));
+ if (NS_SUCCEEDED(rv))
+ {
+ bool retry = false;
+ nsMsgAskBooleanQuestionByString(prompt, msg.get(), &retry, nullptr);
+ if (retry)
+ {
+ mSendProgress = nullptr; // this was cancelled, so we need to clear it.
+ return SendToMagicFolder(m_deliver_mode);
+ }
+ }
+
+ // We failed, and the user decided not to retry. So we're just going to
+ // fail out. However, give Fail a success code so that it doesn't prompt
+ // the user a second time as they already know about the failure.
+ Fail(NS_OK, nullptr, &aStatus);
+ }
+
+ if (NS_SUCCEEDED(aStatus) &&
+ !mPerformingSecondFCC && m_messageKey != nsMsgKey_None &&
+ (m_deliver_mode == nsMsgDeliverNow || m_deliver_mode == nsMsgSendUnsent))
+ {
+ nsresult rv = FilterSentMessage();
+ if (NS_FAILED(rv))
+ OnStopOperation(rv);
+ return rv;
+ }
+
+ return MaybePerformSecondFCC(aStatus);
+}
+
+nsresult
+nsMsgComposeAndSend::FilterSentMessage()
+{
+ if (mSendReport)
+ mSendReport->SetCurrentProcess(nsIMsgSendReport::process_Filter);
+
+ nsCOMPtr<nsIMsgFolder> folder;
+ nsresult rv = GetExistingFolder(m_folderName, getter_AddRefs(folder));
+ if (NS_FAILED(rv))
+ return rv;
+
+ nsCOMPtr<nsIMsgDBHdr> msgHdr;
+ rv = folder->GetMessageHeader(m_messageKey, getter_AddRefs(msgHdr));
+ if (NS_FAILED(rv))
+ return rv;
+
+ nsCOMPtr<nsIMutableArray> msgArray(do_CreateInstance(NS_ARRAY_CONTRACTID, &rv));
+ if (NS_FAILED(rv))
+ return rv;
+
+ nsCOMPtr<nsIMsgFilterService> filterSvc = do_GetService(NS_MSGFILTERSERVICE_CONTRACTID, &rv);
+ if (NS_FAILED(rv))
+ return rv;
+
+ rv = msgArray->AppendElement(msgHdr, false);
+ if (NS_FAILED(rv))
+ return rv;
+
+ nsCOMPtr<nsIMsgWindow> msgWindow;
+ if (mSendProgress)
+ mSendProgress->GetMsgWindow(getter_AddRefs(msgWindow));
+
+ return filterSvc->ApplyFilters(nsMsgFilterType::PostOutgoing, msgArray, folder, msgWindow, this);
+}
+
+NS_IMETHODIMP
+nsMsgComposeAndSend::OnStopOperation(nsresult aStatus)
+{
+ // Set a status message...
+ nsString msg;
+ if (NS_SUCCEEDED(aStatus))
+ mComposeBundle->GetStringFromName(u"filterMessageComplete", getter_Copies(msg));
+ else
+ mComposeBundle->GetStringFromName(u"filterMessageFailed", getter_Copies(msg));
+
+ SetStatusMessage(msg);
+
+ if (NS_FAILED(aStatus))
+ {
+ nsresult rv = mComposeBundle->GetStringFromName(u"errorFilteringMsg", getter_Copies(msg));
+ if (NS_SUCCEEDED(rv))
+ {
+ nsCOMPtr<nsIPrompt> prompt;
+ GetDefaultPrompt(getter_AddRefs(prompt));
+ nsMsgDisplayMessageByString(prompt, msg.get(), nullptr);
+ }
+
+ // We failed, however, give Fail a success code so that it doesn't prompt
+ // the user a second time as they already know about the failure.
+ Fail(NS_OK, nullptr, &aStatus);
+ }
+
+ return MaybePerformSecondFCC(aStatus);
+}
+
+nsresult
+nsMsgComposeAndSend::MaybePerformSecondFCC(nsresult aStatus)
+{
+ // Ok, now to support a second copy operation, we need to figure
+ // out which copy request just finished. If the user has requested
+ // a second copy operation, then we need to fire that off, but if they
+ // just wanted a single copy operation, we can tell everyone we are done
+ // and move on with life. Only do the second copy if the first one worked.
+ //
+ if ( NS_SUCCEEDED(aStatus) && (mNeedToPerformSecondFCC) )
+ {
+ if (mSendReport)
+ mSendReport->SetCurrentProcess(nsIMsgSendReport::process_FCC);
+
+ mNeedToPerformSecondFCC = false;
+ mPerformingSecondFCC = true;
+
+ const char *fcc2 = mCompFields->GetFcc2();
+ if (fcc2 && *fcc2)
+ {
+ nsresult rv = MimeDoFCC(mTempFile,
+ nsMsgDeliverNow,
+ mCompFields->GetBcc(),
+ fcc2,
+ mCompFields->GetNewspostUrl());
+ if (NS_FAILED(rv))
+ Fail(rv, nullptr, &aStatus);
+ else
+ return NS_OK;
+ }
+ }
+
+ // If we are here, its real cleanup time!
+ if (mListener)
+ {
+ nsCOMPtr<nsIMsgCopyServiceListener> copyListener =
+ do_QueryInterface(mListener);
+ if (copyListener)
+ copyListener->OnStopCopy(aStatus);
+ }
+
+ return aStatus;
+}
+
+/* This is the main driving function of this module. It generates a
+ document of type message/rfc822, which contains the stuff provided.
+ The first few arguments are the standard header fields that the
+ generated document should have.
+
+ `other_random_headers' is a string of additional headers that should
+ be inserted beyond the standard ones. If provided, it is just tacked
+ on to the end of the header block, so it should have newlines at the
+ end of each line, shouldn't have blank lines, multi-line headers
+ should be properly continued, etc.
+
+ `digest_p' says that most of the documents we are attaching are
+ themselves messages, and so we should generate a multipart/digest
+ container instead of multipart/mixed. (It's a minor difference.)
+
+ The full text of the first attachment is provided via `attachment1_type'
+ and `attachment1_body'. These may all be 0 if all attachments are
+ provided externally.
+
+ Subsequent attachments are provided as URLs to load, described in the
+ nsMsgAttachmentData structures.
+
+ If `dont_deliver_p' is false, then we actually deliver the message to the
+ SMTP and/or NNTP server, and the message_delivery_done_callback will be
+ invoked with the status.
+
+ If `dont_deliver_p' is true, then we just generate the message, we don't
+ actually deliver it, and the message_delivery_done_callback will be called
+ with the name of the generated file. The callback is responsible for both
+ freeing the file name string, and deleting the file when it is done with
+ it. If an error occurred, then `status' will be negative and
+ `error_message' may be an error message to display. If status is non-
+ negative, then `error_message' contains the file name (this is kind of
+ a kludge...)
+ */
+NS_IMETHODIMP
+nsMsgComposeAndSend::CreateAndSendMessage(
+ nsIEditor *aEditor,
+ nsIMsgIdentity *aUserIdentity,
+ const char *aAccountKey,
+ nsIMsgCompFields *fields,
+ bool digest_p,
+ bool dont_deliver_p,
+ nsMsgDeliverMode mode,
+ nsIMsgDBHdr *msgToReplace,
+ const char *attachment1_type,
+ const nsACString &attachment1_body,
+ nsIArray *attachments,
+ nsIArray *preloaded_attachments,
+ mozIDOMWindowProxy *parentWindow,
+ nsIMsgProgress *progress,
+ nsIMsgSendListener *aListener,
+ const char *password,
+ const nsACString &aOriginalMsgURI,
+ MSG_ComposeType aType
+ )
+{
+ nsresult rv;
+ /* First thing to do is to reset the send errors report */
+ mSendReport->Reset();
+ mSendReport->SetDeliveryMode(mode);
+
+ mParentWindow = do_QueryInterface(parentWindow);
+ mSendProgress = progress;
+ mListener = aListener;
+
+ // Set the editor for MHTML operations if necessary
+ if (aEditor)
+ mEditor = aEditor;
+
+ rv = Init(aUserIdentity, aAccountKey, (nsMsgCompFields *)fields, nullptr,
+ digest_p, dont_deliver_p, mode, msgToReplace,
+ attachment1_type, attachment1_body,
+ attachments, preloaded_attachments,
+ password, aOriginalMsgURI, aType);
+
+ if (NS_FAILED(rv) && mSendReport)
+ mSendReport->SetError(nsIMsgSendReport::process_Current, rv, false);
+
+ return rv;
+}
+
+NS_IMETHODIMP
+nsMsgComposeAndSend::CreateRFC822Message(
+ nsIMsgIdentity *aUserIdentity,
+ nsIMsgCompFields *aFields,
+ const char *aMsgType,
+ const nsACString &aMsgBody,
+ bool aIsDraft,
+ nsIArray *aAttachments,
+ nsIArray *aEmbeddedObjects,
+ nsIMsgSendListener *aListener
+ )
+{
+ nsresult rv;
+ nsMsgDeliverMode mode = aIsDraft ? nsIMsgSend::nsMsgSaveAsDraft :
+ nsIMsgSend::nsMsgDeliverNow;
+
+ /* First thing to do is to reset the send errors report */
+ mSendReport->Reset();
+ mSendReport->SetDeliveryMode(mode);
+
+ mParentWindow = nullptr;
+ mSendProgress = nullptr;
+ mListener = aListener;
+ mEmbeddedObjectList = aEmbeddedObjects;
+
+ rv = Init(aUserIdentity, nullptr, (nsMsgCompFields *)aFields, nullptr,
+ false, true, mode, nullptr,
+ aMsgType,
+ aMsgBody,
+ nullptr, aAttachments,
+ nullptr, EmptyCString(), nsIMsgCompType::New);
+
+ if (NS_FAILED(rv) && mSendReport)
+ mSendReport->SetError(nsIMsgSendReport::process_Current, rv, false);
+
+ return rv;
+}
+
+nsresult
+nsMsgComposeAndSend::SendMessageFile(
+ nsIMsgIdentity *aUserIndentity,
+ const char *aAccountKey,
+ nsIMsgCompFields *fields,
+ nsIFile *sendIFile,
+ bool deleteSendFileOnCompletion,
+ bool digest_p,
+ nsMsgDeliverMode mode,
+ nsIMsgDBHdr *msgToReplace,
+ nsIMsgSendListener *aListener,
+ nsIMsgStatusFeedback *aStatusFeedback,
+ const char *password
+ )
+{
+ NS_ENSURE_ARG_POINTER(fields);
+ NS_ENSURE_ARG_POINTER(sendIFile);
+
+ nsresult rv;
+
+ /* First thing to do is to reset the send errors report */
+ mSendReport->Reset();
+ mSendReport->SetDeliveryMode(mode);
+
+ mStatusFeedback = aStatusFeedback;
+ //
+ // First check to see if the external file we are sending is a valid file.
+ //
+ bool exists;
+ if (NS_FAILED(sendIFile->Exists(&exists)))
+ return NS_ERROR_INVALID_ARG;
+
+ if (!exists)
+ return NS_ERROR_INVALID_ARG;
+
+ // Setup the listener...
+ mListener = aListener;
+
+ // Should we delete the temp file when done?
+ if (!deleteSendFileOnCompletion)
+ mReturnFile = sendIFile;
+
+ rv = Init(aUserIndentity, aAccountKey, (nsMsgCompFields *)fields, sendIFile,
+ digest_p, false, mode, msgToReplace,
+ nullptr, EmptyCString(),
+ nullptr, nullptr,
+ password, EmptyCString(), nsIMsgCompType::New);
+
+ if (NS_SUCCEEDED(rv))
+ rv = DeliverMessage();
+
+ if (NS_FAILED(rv) && mSendReport)
+ mSendReport->SetError(nsIMsgSendReport::process_Current, rv, false);
+
+ return rv;
+}
+
+//
+// Send the message to the magic folder, and runs the completion/failure
+// callback.
+//
+nsresult
+nsMsgComposeAndSend::SendToMagicFolder(nsMsgDeliverMode mode)
+{
+ nsresult rv = MimeDoFCC(mTempFile,
+ mode,
+ mCompFields->GetBcc(),
+ mCompFields->GetFcc(),
+ mCompFields->GetNewspostUrl());
+ //
+ // The caller of MimeDoFCC needs to deal with failure.
+ //
+ if (NS_FAILED(rv))
+ rv = NotifyListenerOnStopCopy(rv);
+
+ return rv;
+}
+
+char*
+nsMsgGetEnvelopeLine(void)
+{
+ static char result[75] = "";
+ PRExplodedTime now;
+ char buffer[128] = "";
+
+ // Generate envelope line in format of: From - Sat Apr 18 20:01:49 1998
+ //
+ // Use PR_FormatTimeUSEnglish() to format the date in US English format,
+ // then figure out what our local GMT offset is, and append it (since
+ // PR_FormatTimeUSEnglish() can't do that.) Generate four digit years as
+ // per RFC 1123 (superceding RFC 822.)
+ //
+ PR_ExplodeTime(PR_Now(), PR_LocalTimeParameters, &now);
+ PR_FormatTimeUSEnglish(buffer, sizeof(buffer),
+ "%a %b %d %H:%M:%S %Y",
+ &now);
+
+ // This value must be in ctime() format, with English abbreviations.
+ // PL_strftime("... %c ...") is no good, because it is localized.
+ //
+ PL_strcpy(result, "From - ");
+ PL_strcpy(result + 7, buffer);
+ PL_strcpy(result + 7 + 24, CRLF);
+ return result;
+}
+
+#define ibuffer_size FILE_IO_BUFFER_SIZE
+nsresult
+nsMsgComposeAndSend::MimeDoFCC(nsIFile *input_file,
+ nsMsgDeliverMode mode,
+ const char *bcc_header,
+ const char *fcc_header,
+ const char *news_url)
+{
+ nsresult status = NS_OK;
+ char *ibuffer = nullptr;
+ uint32_t n;
+ bool folderIsLocal = true;
+ nsCString turi;
+ char16_t *printfString = nullptr;
+ nsString msg;
+ nsCOMPtr<nsIMsgFolder> folder;
+
+ // Before continuing, just check the user has not cancel the operation
+ if (mSendProgress)
+ {
+ bool canceled = false;
+ mSendProgress->GetProcessCanceledByUser(&canceled);
+ if (canceled)
+ return NS_ERROR_ABORT;
+ else
+ mSendProgress->OnProgressChange(nullptr, nullptr, 0, 0, 0, -1);
+ }
+
+ //
+ // Ok, this is here to keep track of this for 2 copy operations...
+ //
+ if (mCopyFile)
+ {
+ mCopyFile2 = mCopyFile;
+ mCopyFile = nullptr;
+ }
+
+ //
+ // Create the file that will be used for the copy service!
+ //
+ nsresult rv = nsMsgCreateTempFile("nscopy.tmp", getter_AddRefs(mCopyFile));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ nsCOMPtr<nsIOutputStream> tempOutfile;
+ rv = MsgNewBufferedFileOutputStream(getter_AddRefs(tempOutfile), mCopyFile, -1, 00600);
+ if (NS_FAILED(rv))
+ {
+ if (mSendReport)
+ {
+ nsAutoString error_msg;
+ nsMsgBuildMessageWithTmpFile(mCopyFile, error_msg);
+ mSendReport->SetMessage(nsIMsgSendReport::process_Current, error_msg.get(), false);
+ }
+ status = NS_MSG_UNABLE_TO_OPEN_TMP_FILE;
+
+ mCopyFile = nullptr;
+ return status;
+ }
+
+ //
+ // Get our files ready...
+ //
+ nsCOMPtr<nsIInputStream> inputFile;
+ rv = NS_NewLocalFileInputStream(getter_AddRefs(inputFile), input_file);
+ if (NS_FAILED(rv))
+ {
+ if (mSendReport)
+ {
+ nsAutoString error_msg;
+ nsMsgBuildMessageWithFile(input_file, error_msg);
+ mSendReport->SetMessage(nsIMsgSendReport::process_Current, error_msg.get(), false);
+ }
+ status = NS_MSG_UNABLE_TO_OPEN_FILE;
+ goto FAIL;
+ }
+
+ // now the buffers...
+ ibuffer = (char *) PR_Malloc(ibuffer_size);
+ if (!ibuffer)
+ {
+ status = NS_ERROR_OUT_OF_MEMORY;
+ goto FAIL;
+ }
+
+ //
+ // First, we we need to put a Berkeley "From - " delimiter at the head of
+ // the file for parsing...
+ //
+
+ if (fcc_header && *fcc_header)
+ GetExistingFolder(nsDependentCString(fcc_header), getter_AddRefs(folder));
+
+ if ((mode == nsMsgDeliverNow || mode == nsMsgSendUnsent) && folder)
+ turi = fcc_header;
+ else
+ GetFolderURIFromUserPrefs(mode, mUserIdentity, turi);
+ status = MessageFolderIsLocal(mUserIdentity, mode, turi.get(), &folderIsLocal);
+ if (NS_FAILED(status))
+ goto FAIL;
+
+ // Tell the user we are copying the message...
+ mComposeBundle->GetStringFromName(u"copyMessageStart",
+ getter_Copies(msg));
+ if (!msg.IsEmpty())
+ {
+ nsCOMPtr<nsIRDFService> rdfService = do_GetService(kRDFServiceCID);
+ if (rdfService)
+ {
+ nsCOMPtr<nsIRDFResource> res;
+ rdfService->GetResource(turi, getter_AddRefs(res));
+ nsCOMPtr<nsIMsgFolder> folder = do_QueryInterface(res);
+ if (folder)
+ folder->GetName(mSavedToFolderName);
+ }
+ if (!mSavedToFolderName.IsEmpty())
+ printfString = nsTextFormatter::smprintf(msg.get(), mSavedToFolderName.get());
+ else
+ printfString = nsTextFormatter::smprintf(msg.get(), "?");
+ if (printfString)
+ {
+ SetStatusMessage(nsDependentString(printfString));
+ PR_Free(printfString);
+ }
+ }
+
+ if (folderIsLocal)
+ {
+ char *envelopeLine = nsMsgGetEnvelopeLine();
+ uint32_t len = PL_strlen(envelopeLine);
+
+ rv = tempOutfile->Write(envelopeLine, len, &n);
+ if (NS_FAILED(rv) || n != len)
+ {
+ status = NS_ERROR_FAILURE;
+ goto FAIL;
+ }
+ }
+
+ //
+ // Write out an X-Mozilla-Status header.
+ //
+ // This is required for the queue file, so that we can overwrite it once
+ // the messages have been delivered, and so that the nsMsgMessageFlags::Queued bit
+ // is set.
+ //
+ // For FCC files, we don't necessarily need one, but we might as well put
+ // one in so that it's marked as read already.
+ //
+ //
+ // Need to add these lines for POP3 ONLY! IMAP servers will handle
+ // this status information for summary file regeneration for us.
+ if ((mode == nsMsgQueueForLater || mode == nsMsgSaveAsDraft ||
+ mode == nsMsgSaveAsTemplate || mode == nsMsgDeliverNow ||
+ mode == nsMsgSendUnsent || mode == nsMsgDeliverBackground) &&
+ folderIsLocal)
+ {
+ char *buf = 0;
+ uint16_t flags = 0;
+
+ // for save as draft and send later, we want to leave the message as unread.
+ // See Bug #198087
+ // Messages sent with mode nsMsgDeliverBackground must not have the Queued
+ // flag sent so that they get picked up by the background send function.
+ if (mode == nsMsgQueueForLater)
+ flags |= nsMsgMessageFlags::Queued;
+ else if (mode != nsMsgSaveAsDraft && mode != nsMsgDeliverBackground)
+ flags |= nsMsgMessageFlags::Read;
+ buf = PR_smprintf(X_MOZILLA_STATUS_FORMAT CRLF, flags);
+ if (buf)
+ {
+ uint32_t len = PL_strlen(buf);
+ rv = tempOutfile->Write(buf, len, &n);
+ PR_Free(buf);
+ if (NS_FAILED(rv) || n != len)
+ {
+ status = NS_ERROR_FAILURE;
+ goto FAIL;
+ }
+ }
+
+ uint32_t flags2 = 0;
+ if (mode == nsMsgSaveAsTemplate)
+ flags2 |= nsMsgMessageFlags::Template;
+ if (mode == nsMsgDeliverNow || mode == nsMsgSendUnsent)
+ {
+ flags2 &= ~nsMsgMessageFlags::MDNReportNeeded;
+ flags2 |= nsMsgMessageFlags::MDNReportSent;
+ }
+ buf = PR_smprintf(X_MOZILLA_STATUS2_FORMAT CRLF, flags2);
+ if (buf)
+ {
+ uint32_t len = PL_strlen(buf);
+ rv = tempOutfile->Write(buf, len, &n);
+ PR_Free(buf);
+ if (NS_FAILED(rv) || n != len)
+ {
+ status = NS_ERROR_FAILURE;
+ goto FAIL;
+ }
+ }
+ tempOutfile->Write(X_MOZILLA_KEYWORDS, sizeof(X_MOZILLA_KEYWORDS) - 1, &n);
+ }
+
+ // Write out the FCC and BCC headers.
+ // When writing to the Queue file, we *must* write the FCC and BCC
+ // headers, or else that information would be lost. Because, when actually
+ // delivering the message (with "deliver now") we do FCC/BCC right away;
+ // but when queueing for later delivery, we do FCC/BCC at delivery-time.
+ //
+ // The question remains of whether FCC and BCC should be written into normal
+ // BCC folders (like the Sent Mail folder.)
+ //
+ // For FCC, there seems no point to do that; it's not information that one
+ // would want to refer back to.
+ //
+ // For BCC, the question isn't as clear. On the one hand, if I send someone
+ // a BCC'ed copy of the message, and save a copy of it for myself (with FCC)
+ // I might want to be able to look at that message later and see the list of
+ // people to whom I had BCC'ed it.
+ //
+ // On the other hand, the contents of the BCC header is sensitive
+ // information, and should perhaps not be stored at all.
+ //
+ // Thus the consultation of the #define SAVE_BCC_IN_FCC_FILE.
+ //
+ // (Note that, if there is a BCC header present in a message in some random
+ // folder, and that message is forwarded to someone, then the attachment
+ // code will strip out the BCC header before forwarding it.)
+ //
+ if ((mode == nsMsgQueueForLater || mode == nsMsgDeliverBackground ||
+ mode == nsMsgSaveAsDraft || mode == nsMsgSaveAsTemplate) &&
+ fcc_header && *fcc_header)
+ {
+ int32_t L = PL_strlen(fcc_header) + 20;
+ char *buf = (char *) PR_Malloc (L);
+ if (!buf)
+ {
+ status = NS_ERROR_OUT_OF_MEMORY;
+ goto FAIL;
+ }
+
+ PR_snprintf(buf, L-1, "FCC: %s" CRLF, fcc_header);
+
+ uint32_t len = PL_strlen(buf);
+ rv = tempOutfile->Write(buf, len, &n);
+ if (NS_FAILED(rv) || n != len)
+ {
+ status = NS_ERROR_FAILURE;
+ goto FAIL;
+ }
+ }
+
+ //
+ // Ok, now I want to get the identity key and write it out if this is for a
+ // nsMsgQueueForLater operation!
+ //
+ if ((nsMsgQueueForLater == mode || nsMsgSaveAsDraft == mode ||
+ nsMsgDeliverBackground == mode || nsMsgSaveAsTemplate == mode) &&
+ mUserIdentity)
+ {
+ char *buf = nullptr;
+ nsCString key;
+
+ if (NS_SUCCEEDED(mUserIdentity->GetKey(key)) && !key.IsEmpty())
+ {
+ buf = PR_smprintf(HEADER_X_MOZILLA_IDENTITY_KEY ": %s" CRLF, key.get());
+ if (buf)
+ {
+ uint32_t len = strlen(buf);
+ rv = tempOutfile->Write(buf, len, &n);
+ PR_Free(buf);
+ if (NS_FAILED(rv) || n != len)
+ {
+ status = NS_ERROR_FAILURE;
+ goto FAIL;
+ }
+ }
+ }
+
+ if (!mAccountKey.IsEmpty())
+ {
+ buf = PR_smprintf(HEADER_X_MOZILLA_ACCOUNT_KEY ": %s" CRLF, mAccountKey.get());
+ if (buf)
+ {
+ uint32_t len = strlen(buf);
+ rv = tempOutfile->Write(buf, len, &n);
+ PR_Free(buf);
+ if (NS_FAILED(rv) || n != len)
+ {
+ status = NS_ERROR_FAILURE;
+ goto FAIL;
+ }
+ }
+ }
+ }
+
+ if (bcc_header && *bcc_header
+#ifndef SAVE_BCC_IN_FCC_FILE
+ && (mode == MSG_QueueForLater || mode == MSG_SaveAsDraft ||
+ mode == MSG_SaveAsTemplate)
+#endif
+ )
+ {
+ char *convBcc;
+ convBcc = nsMsgI18NEncodeMimePartIIStr(bcc_header, true,
+ mCompFields->GetCharacterSet(), sizeof("BCC: "),
+ nsMsgMIMEGetConformToStandard());
+
+ int32_t L = strlen(convBcc ? convBcc : bcc_header) + 20;
+ char *buf = (char *) PR_Malloc (L);
+ if (!buf)
+ {
+ status = NS_ERROR_OUT_OF_MEMORY;
+ goto FAIL;
+ }
+
+ PR_snprintf(buf, L-1, "BCC: %s" CRLF, convBcc ? convBcc : bcc_header);
+ uint32_t len = strlen(buf);
+ rv = tempOutfile->Write(buf, len, &n);
+ PR_Free(buf);
+ PR_Free(convBcc);
+ if (NS_FAILED(rv) || n != len)
+ {
+ status = NS_ERROR_FAILURE;
+ goto FAIL;
+ }
+ }
+
+ //
+ // Write out the X-Mozilla-News-Host header.
+ // This is done only when writing to the queue file, not the FCC file.
+ // We need this to complement the "Newsgroups" header for the case of
+ // queueing a message for a non-default news host.
+ //
+ // Convert a URL like "snews://host:123/" to the form "host:123/secure"
+ // or "news://user@host:222" to simply "host:222".
+ //
+ if ((mode == nsMsgQueueForLater || mode == nsMsgSaveAsDraft ||
+ mode == nsMsgSaveAsTemplate || mode == nsMsgDeliverBackground) &&
+ news_url && *news_url)
+ {
+ bool secure_p = (news_url[0] == 's' || news_url[0] == 'S');
+ char *orig_hap = nsMsgParseURLHost (news_url);
+ char *host_and_port = orig_hap;
+ if (host_and_port)
+ {
+ // There may be authinfo at the front of the host - it could be of
+ // the form "user:password@host:port", so take off everything before
+ // the first at-sign. We don't want to store authinfo in the queue
+ // folder, I guess, but would want it to be re-prompted-for at
+ // delivery-time.
+ //
+ char *at = PL_strchr (host_and_port, '@');
+ if (at)
+ host_and_port = at + 1;
+ }
+
+ if ((host_and_port && *host_and_port) || !secure_p)
+ {
+ char *line = PR_smprintf(X_MOZILLA_NEWSHOST ": %s%s" CRLF,
+ host_and_port ? host_and_port : "",
+ secure_p ? "/secure" : "");
+ PR_FREEIF(orig_hap);
+ if (!line)
+ {
+ status = NS_ERROR_OUT_OF_MEMORY;
+ goto FAIL;
+ }
+
+ uint32_t len = PL_strlen(line);
+ rv = tempOutfile->Write(line, len, &n);
+ PR_Free(line);
+ if (NS_FAILED(rv) || n != len)
+ {
+ status = NS_ERROR_FAILURE;
+ goto FAIL;
+ }
+ }
+
+ PR_Free(orig_hap);
+ }
+
+ //
+ // Read from the message file, and write to the FCC or Queue file.
+ // There are two tricky parts: the first is that the message file
+ // uses CRLF, and the FCC file should use LINEBREAK. The second
+ // is that the message file may have lines beginning with "From "
+ // but the FCC file must have those lines mangled.
+ //
+ // It's unfortunate that we end up writing the FCC file a line
+ // at a time, but it's the easiest way...
+ //
+ uint64_t available;
+ rv = inputFile->Available(&available);
+ NS_ENSURE_SUCCESS(rv, rv);
+ while (available > 0)
+ {
+ // check *ibuffer in case that ibuffer isn't big enough
+ uint32_t readCount;
+ rv = inputFile->Read(ibuffer, ibuffer_size, &readCount);
+ if (NS_FAILED(rv) || readCount == 0 || *ibuffer == 0)
+ {
+ status = NS_ERROR_FAILURE;
+ goto FAIL;
+ }
+
+ rv = tempOutfile->Write(ibuffer, readCount, &n);
+ if (NS_FAILED(rv) || n != readCount) // write failed
+ {
+ status = NS_MSG_ERROR_WRITING_FILE;
+ goto FAIL;
+ }
+
+ rv = inputFile->Available(&available);
+ NS_ENSURE_SUCCESS(rv, rv);
+ }
+
+FAIL:
+ PR_Free(ibuffer);
+
+ if (NS_FAILED(tempOutfile->Flush()))
+ status = NS_MSG_ERROR_WRITING_FILE;
+
+ tempOutfile->Close();
+
+ if (inputFile)
+ inputFile->Close();
+
+
+ // here we should clone mCopyFile, since it has changed on disk.
+ nsCOMPtr <nsIFile> clonedFile;
+ mCopyFile->Clone(getter_AddRefs(clonedFile));
+ mCopyFile = clonedFile;
+
+ // When we get here, we have to see if we have been successful so far.
+ // If we have, then we should start up the async copy service operation.
+ // If we weren't successful, then we should just return the error and
+ // bail out.
+ if (NS_SUCCEEDED(status))
+ {
+ // If we are here, time to start the async copy service operation!
+ status = StartMessageCopyOperation(mCopyFile, mode, turi);
+ }
+ return status;
+}
+
+//
+// This is pretty much a wrapper to the functionality that lives in the
+// nsMsgCopy class
+//
+nsresult
+nsMsgComposeAndSend::StartMessageCopyOperation(nsIFile *aFile,
+ nsMsgDeliverMode mode,
+ const nsCString& dest_uri)
+{
+ mCopyObj = new nsMsgCopy();
+ if (!mCopyObj)
+ return NS_ERROR_OUT_OF_MEMORY;
+
+ //
+ // Actually, we need to pick up the proper folder from the prefs and not
+ // default to the default "Flagged" folder choices
+ //
+ nsresult rv;
+ if (!dest_uri.IsEmpty())
+ m_folderName = dest_uri;
+ else
+ GetFolderURIFromUserPrefs(mode, mUserIdentity, m_folderName);
+
+ if (mListener)
+ mListener->OnGetDraftFolderURI(m_folderName.get());
+
+ rv = mCopyObj->StartCopyOperation(mUserIdentity, aFile, mode,
+ this, m_folderName.get(), mMsgToReplace);
+ return rv;
+}
+
+//I'm getting this each time without holding onto the feedback so that 3 pane windows can be closed
+//without any chance of crashing due to holding onto a deleted feedback.
+nsresult
+nsMsgComposeAndSend::SetStatusMessage(const nsString &aMsgString)
+{
+ if (mSendProgress)
+ mSendProgress->OnStatusChange(nullptr, nullptr, NS_OK, aMsgString.get());
+ return NS_OK;
+}
+
+// For GUI notification...
+nsresult
+nsMsgComposeAndSend::SetGUINotificationState(bool aEnableFlag)
+{
+ mGUINotificationEnabled = aEnableFlag;
+ return NS_OK;
+}
+
+/* readonly attribute nsIMsgSendReport sendReport; */
+NS_IMETHODIMP
+nsMsgComposeAndSend::GetSendReport(nsIMsgSendReport * *aSendReport)
+{
+ NS_ENSURE_ARG_POINTER(aSendReport);
+ NS_IF_ADDREF(*aSendReport = mSendReport);
+ return NS_OK;
+}
+
+nsresult nsMsgComposeAndSend::Abort()
+{
+ uint32_t i;
+ nsresult rv;
+
+ if (mAbortInProcess)
+ return NS_OK;
+
+ mAbortInProcess = true;
+
+ if (m_plaintext)
+ rv = m_plaintext->Abort();
+
+ for (i = 0; i < m_attachment_count; i ++)
+ {
+ nsMsgAttachmentHandler *ma = m_attachments[i];
+ if (ma)
+ rv = ma->Abort();
+ }
+
+ /* stop the current running url */
+ if (mRunningRequest)
+ {
+ mRunningRequest->Cancel(NS_ERROR_ABORT);
+ mRunningRequest = nullptr;
+ }
+
+ if (mCopyObj)
+ {
+ nsCOMPtr<nsIMsgCopyService> copyService = do_GetService(NS_MSGCOPYSERVICE_CONTRACTID, &rv);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ copyService->NotifyCompletion(mCopyFile, mCopyObj->mDstFolder, NS_ERROR_ABORT);
+ }
+ mAbortInProcess = false;
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsMsgComposeAndSend::GetProcessAttachmentsSynchronously(bool *_retval)
+{
+ NS_ENSURE_ARG(_retval);
+ *_retval = m_be_synchronous_p;
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsMsgComposeAndSend::GetAttachmentHandlers(nsTArray<RefPtr<nsMsgAttachmentHandler>> **_retval)
+{
+ NS_ENSURE_ARG(_retval);
+ *_retval = &m_attachments;
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsMsgComposeAndSend::GetAttachmentCount(uint32_t *aAttachmentCount)
+{
+ NS_ENSURE_ARG(aAttachmentCount);
+ *aAttachmentCount = m_attachment_count;
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsMsgComposeAndSend::GetPendingAttachmentCount(uint32_t *aPendingAttachmentCount)
+{
+ NS_ENSURE_ARG(aPendingAttachmentCount);
+ *aPendingAttachmentCount = m_attachment_pending_count;
+ return NS_OK;
+}
+NS_IMETHODIMP nsMsgComposeAndSend::SetPendingAttachmentCount(uint32_t aPendingAttachmentCount)
+{
+ m_attachment_pending_count = aPendingAttachmentCount;
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsMsgComposeAndSend::GetDeliveryMode(nsMsgDeliverMode *aDeliveryMode)
+{
+ NS_ENSURE_ARG(aDeliveryMode);
+ *aDeliveryMode = m_deliver_mode;
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsMsgComposeAndSend::GetProgress(nsIMsgProgress **_retval)
+{
+ NS_ENSURE_ARG(_retval);
+ NS_IF_ADDREF(*_retval = mSendProgress);
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsMsgComposeAndSend::GetOutputStream(nsIOutputStream **_retval)
+{
+ NS_ENSURE_ARG(_retval);
+ NS_IF_ADDREF(*_retval = mOutputFile);
+ return NS_OK;
+}
+
+
+/* [noscript] attribute nsIURI runningURL; */
+NS_IMETHODIMP nsMsgComposeAndSend::GetRunningRequest(nsIRequest **request)
+{
+ NS_ENSURE_ARG(request);
+ NS_IF_ADDREF(*request = mRunningRequest);
+ return NS_OK;
+}
+NS_IMETHODIMP nsMsgComposeAndSend::SetRunningRequest(nsIRequest *request)
+{
+ mRunningRequest = request;
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsMsgComposeAndSend::GetStatus(nsresult *aStatus)
+{
+ NS_ENSURE_ARG(aStatus);
+ *aStatus = m_status;
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsMsgComposeAndSend::SetStatus(nsresult aStatus)
+{
+ m_status = aStatus;
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsMsgComposeAndSend::GetCryptoclosure(nsIMsgComposeSecure ** aCryptoclosure)
+{
+ NS_ENSURE_ARG(aCryptoclosure);
+ NS_IF_ADDREF(*aCryptoclosure = m_crypto_closure);
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsMsgComposeAndSend::SetCryptoclosure(nsIMsgComposeSecure * aCryptoclosure)
+{
+ m_crypto_closure = aCryptoclosure;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsMsgComposeAndSend::GetSendCompFields(nsIMsgCompFields** aCompFields)
+{
+ NS_ENSURE_ARG_POINTER(aCompFields);
+ nsCOMPtr<nsIMsgCompFields> qiCompFields(mCompFields);
+ NS_ENSURE_STATE(qiCompFields);
+ qiCompFields.forget(aCompFields);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsMsgComposeAndSend::GetSendBody(nsAString& aBody)
+{
+ nsCString charSet;
+ if (mCompFields)
+ mCompFields->GetCharacterSet(getter_Copies(charSet));
+ if (!m_attachment1_body) {
+ aBody.Truncate();
+ return NS_OK;
+ }
+ return ConvertToUnicode(charSet.get(), m_attachment1_body, aBody);
+}
+
+NS_IMETHODIMP
+nsMsgComposeAndSend::GetSendBodyType(nsACString& aBodyType)
+{
+ if (m_attachment1_type && *m_attachment1_type)
+ aBodyType.Assign(nsDependentCString(m_attachment1_type));
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsMsgComposeAndSend::GetIdentity(nsIMsgIdentity **aIdentity)
+{
+ NS_ENSURE_ARG_POINTER(aIdentity);
+ *aIdentity = mUserIdentity;
+ NS_IF_ADDREF(*aIdentity);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsMsgComposeAndSend::GetAttachment(uint32_t aIndex,
+ nsIMsgAttachmentHandler **aAttachment)
+{
+ NS_ENSURE_ARG_POINTER(aAttachment);
+ if (aIndex >= m_attachment_count)
+ return NS_ERROR_ILLEGAL_VALUE;
+ *aAttachment = m_attachments[aIndex];
+ NS_IF_ADDREF(*aAttachment);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsMsgComposeAndSend::SetSavedToFolderName(const nsAString& aName)
+{
+ mSavedToFolderName.Assign(aName);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsMsgComposeAndSend::GetSavedToFolderName(nsAString& aName)
+{
+ aName.Assign(mSavedToFolderName);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsMsgComposeAndSend::SetDontDeliver(bool aDontDeliver)
+{
+ m_dont_deliver_p = aDontDeliver;
+ return NS_OK;
+}
+NS_IMETHODIMP
+nsMsgComposeAndSend::GetDontDeliver(bool *aDontDeliver)
+{
+ NS_ENSURE_ARG_POINTER(aDontDeliver);
+ *aDontDeliver = m_dont_deliver_p;
+ return NS_OK;
+}
+
+NS_IMPL_ISUPPORTS(nsMsgAttachmentData, nsIMsgAttachmentData)
+
+nsMsgAttachmentData::nsMsgAttachmentData() : m_size(0), m_sizeExternalStr("-1"),
+ m_isExternalAttachment(false), m_isExternalLinkAttachment(false),
+ m_isDownloaded(false), m_hasFilename(false), m_displayableInline(false)
+{
+}
+
+nsMsgAttachmentData::~nsMsgAttachmentData()
+{
+}
+
+NS_IMETHODIMP nsMsgAttachmentData::GetUrl(nsIURI **aUrl)
+{
+ NS_ENSURE_ARG_POINTER(aUrl);
+ NS_IF_ADDREF(*aUrl = m_url);
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsMsgAttachmentData::SetUrl(nsIURI *aUrl)
+{
+ m_url = aUrl;
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsMsgAttachmentData::GetDesiredType(nsACString &aDesiredType)
+{
+ aDesiredType = m_desiredType;
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsMsgAttachmentData::SetDesiredType(const nsACString &aDesiredType)
+{
+ m_desiredType = aDesiredType;
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsMsgAttachmentData::GetRealType(nsACString &aRealType)
+{
+ aRealType = m_realType;
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsMsgAttachmentData::SetRealType(const nsACString &aRealType)
+{
+ m_realType = aRealType;
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsMsgAttachmentData::GetRealEncoding(nsACString &aRealEncoding)
+{
+ aRealEncoding = m_realEncoding;
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsMsgAttachmentData::SetRealEncoding(const nsACString &aRealEncoding)
+{
+ m_realEncoding = aRealEncoding;
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsMsgAttachmentData::GetRealName(nsACString &aRealName)
+{
+ aRealName = m_realName;
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsMsgAttachmentData::SetRealName(const nsACString &aRealName)
+{
+ m_realName = aRealName;
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsMsgAttachmentData::GetDescription(nsACString &aDescription)
+{
+ aDescription = m_description;
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsMsgAttachmentData::SetDescription(const nsACString &aDescription)
+{
+ m_description = aDescription;
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsMsgAttachmentData::GetXMacType(nsACString & aXMacType)
+{
+ aXMacType = m_xMacType;
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsMsgAttachmentData::SetXMacType(const nsACString & aXMacType)
+{
+ m_xMacType = aXMacType;
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsMsgAttachmentData::GetXMacCreator(nsACString & aXMacCreator)
+{
+ aXMacCreator = m_xMacCreator;
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsMsgAttachmentData::SetXMacCreator(const nsACString & aXMacCreator)
+{
+ m_xMacCreator = aXMacCreator;
+ return NS_OK;
+}
+
+NS_IMPL_ISUPPORTS(nsMsgAttachedFile, nsIMsgAttachedFile)
+
+nsMsgAttachedFile::nsMsgAttachedFile() : m_size(0), m_unprintableCount(0),
+ m_highbitCount(0), m_ctlCount(0), m_nullCount(0), m_maxLineLength(0)
+{
+}
+
+nsMsgAttachedFile::~nsMsgAttachedFile()
+{
+}
+
+NS_IMETHODIMP nsMsgAttachedFile::GetOrigUrl(nsIURI **aOrigUrl)
+{
+ NS_ENSURE_ARG_POINTER(aOrigUrl);
+ NS_IF_ADDREF(*aOrigUrl = m_origUrl);
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsMsgAttachedFile::SetOrigUrl(nsIURI *aOrigUrl)
+{
+ m_origUrl = aOrigUrl;
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsMsgAttachedFile::GetTmpFile(nsIFile **aTmpFile)
+{
+ NS_ENSURE_ARG_POINTER(aTmpFile);
+ NS_IF_ADDREF(*aTmpFile = m_tmpFile);
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsMsgAttachedFile::SetTmpFile(nsIFile *aTmpFile)
+{
+ m_tmpFile = aTmpFile;
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsMsgAttachedFile::GetType(nsACString &aType)
+{
+ aType = m_type;
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsMsgAttachedFile::SetType(const nsACString &aType)
+{
+ m_type = aType;
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsMsgAttachedFile::GetEncoding(nsACString &aEncoding)
+{
+ aEncoding = m_encoding;
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsMsgAttachedFile::SetEncoding(const nsACString &aEncoding)
+{
+ m_encoding = aEncoding;
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsMsgAttachedFile::GetDescription(nsACString &aDescription)
+{
+ aDescription = m_description;
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsMsgAttachedFile::SetDescription(const nsACString &aDescription)
+{
+ m_description = aDescription;
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsMsgAttachedFile::GetCloudPartInfo(nsACString &aCloudPartInfo)
+{
+ aCloudPartInfo = m_cloudPartInfo;
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsMsgAttachedFile::SetCloudPartInfo(const nsACString &aCloudPartInfo)
+{
+ m_cloudPartInfo = aCloudPartInfo;
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsMsgAttachedFile::GetXMacType(nsACString & aXMacType)
+{
+ aXMacType = m_xMacType;
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsMsgAttachedFile::SetXMacType(const nsACString & aXMacType)
+{
+ m_xMacType = aXMacType;
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsMsgAttachedFile::GetXMacCreator(nsACString & aXMacCreator)
+{
+ aXMacCreator = m_xMacCreator;
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsMsgAttachedFile::SetXMacCreator(const nsACString & aXMacCreator)
+{
+ m_xMacCreator = aXMacCreator;
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsMsgAttachedFile::GetRealName(nsACString & aRealName)
+{
+ aRealName = m_realName;
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsMsgAttachedFile::SetRealName(const nsACString & aRealName)
+{
+ m_realName = aRealName;
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsMsgAttachedFile::GetSize(uint32_t *aSize)
+{
+ NS_ENSURE_ARG_POINTER(aSize);
+ *aSize = m_size;
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsMsgAttachedFile::SetSize(uint32_t aSize)
+{
+ m_size = aSize;
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsMsgAttachedFile::GetUnprintableCount(uint32_t *aUnprintableCount)
+{
+ NS_ENSURE_ARG_POINTER(aUnprintableCount);
+ *aUnprintableCount = m_unprintableCount;
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsMsgAttachedFile::SetUnprintableCount(uint32_t aUnprintableCount)
+{
+ m_unprintableCount = aUnprintableCount;
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsMsgAttachedFile::GetHighbitCount(uint32_t *aHighbitCount)
+{
+ NS_ENSURE_ARG_POINTER(aHighbitCount);
+ *aHighbitCount = m_highbitCount;
+ return NS_OK;
+}
+NS_IMETHODIMP nsMsgAttachedFile::SetHighbitCount(uint32_t aHighbitCount)
+{
+ m_highbitCount = aHighbitCount;
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsMsgAttachedFile::GetCtlCount(uint32_t *aCtlCount)
+{
+ NS_ENSURE_ARG_POINTER(aCtlCount);
+ *aCtlCount = m_ctlCount;
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsMsgAttachedFile::SetCtlCount(uint32_t aCtlCount)
+{
+ m_ctlCount = aCtlCount;
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsMsgAttachedFile::GetNullCount(uint32_t *aNullCount)
+{
+ NS_ENSURE_ARG_POINTER(aNullCount);
+ *aNullCount = m_nullCount;
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsMsgAttachedFile::SetNullCount(uint32_t aNullCount)
+{
+ m_nullCount = aNullCount;
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsMsgAttachedFile::GetMaxLineLength(uint32_t *aMaxLineLength)
+{
+ NS_ENSURE_ARG_POINTER(aMaxLineLength);
+ *aMaxLineLength = m_maxLineLength;
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsMsgAttachedFile::SetMaxLineLength(uint32_t aMaxLineLength)
+{
+ m_maxLineLength = aMaxLineLength;
+ return NS_OK;
+}