Bug 1240327, improve ability of key mailnews components to support JsAccount, r=jcranmer
☠☠ backed out by ae76d6797570 ☠ ☠
authorR Kent James <rkent@caspia.com>
Sat, 22 Aug 2015 13:40:00 -0700
changeset 18664 969a3a5cb50fff98fb5225da45e61d95e13d6671
parent 18663 cd70a2f38a732280360d7003085a847f9d72889e
child 18665 dc6dbd9cf3fced97e3187355bd954dafd7b51d13
push id1591
push userclokep@gmail.com
push dateMon, 07 Mar 2016 14:58:27 +0000
treeherdercomm-esr52@5bf8af5204f8 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjcranmer
bugs1240327
Bug 1240327, improve ability of key mailnews components to support JsAccount, r=jcranmer
mailnews/base/public/nsIMsgFolder.idl
mailnews/base/util/nsMsgDBFolder.cpp
mailnews/base/util/nsMsgDBFolder.h
mailnews/compose/public/moz.build
mailnews/compose/public/nsIMsgAttachmentHandler.idl
mailnews/compose/public/nsIMsgCompose.idl
mailnews/compose/public/nsIMsgSend.idl
mailnews/compose/src/moz.build
mailnews/compose/src/nsMsgAttachmentHandler.cpp
mailnews/compose/src/nsMsgAttachmentHandler.h
mailnews/compose/src/nsMsgCompose.cpp
mailnews/compose/src/nsMsgCompose.h
mailnews/compose/src/nsMsgSend.cpp
mailnews/compose/src/nsMsgSend.h
mailnews/imap/src/nsImapMailFolder.cpp
mailnews/imap/src/nsImapMailFolder.h
mailnews/local/src/nsLocalMailFolder.cpp
mailnews/local/src/nsLocalMailFolder.h
mailnews/news/src/nsNewsFolder.cpp
mailnews/news/src/nsNewsFolder.h
--- a/mailnews/base/public/nsIMsgFolder.idl
+++ b/mailnews/base/public/nsIMsgFolder.idl
@@ -25,17 +25,17 @@ interface nsIArray;
 interface nsIMutableArray;
 interface nsIMsgPluggableStore;
 
 typedef long nsMsgBiffState;
 
 // enumerated type for determining if a message has been replied to, forwarded, etc.
 typedef long nsMsgDispositionState;
 
-[scriptable, uuid(E6CC0770-D0D8-4E67-8A2E-02C82C32C99A)]
+[scriptable, uuid(5d253ba2-42aa-43a7-b584-0059855ababf)]
 interface nsIMsgFolder : nsISupports {
 
   const nsMsgBiffState nsMsgBiffState_NewMail = 0; // User has new mail waiting.
   const nsMsgBiffState nsMsgBiffState_NoMail =  1; // No new mail is waiting.
   const nsMsgBiffState nsMsgBiffState_Unknown = 2; // We dunno whether there is new mail.
 
   /// Returns an enumerator containing the messages within the current database.
   readonly attribute nsISimpleEnumerator messages;
@@ -826,9 +826,15 @@ interface nsIMsgFolder : nsISupports {
    */
   boolean getForcePropertyEmpty(in string propertyName);
 
   /**
    * Pluggable store for this folder. Currently, this will always be the same
    * as the pluggable store for the server.
    */
   readonly attribute nsIMsgPluggableStore msgStore;
+
+  /**
+   * Protocol type, i.e. "pop3", "imap", "nntp", "none", etc
+   * used to construct URLs for this account type.
+   */
+  readonly attribute ACString incomingServerType;
 };
--- a/mailnews/base/util/nsMsgDBFolder.cpp
+++ b/mailnews/base/util/nsMsgDBFolder.cpp
@@ -5936,16 +5936,24 @@ NS_IMETHODIMP nsMsgDBFolder::OrProcessin
 NS_IMETHODIMP nsMsgDBFolder::AndProcessingFlags(nsMsgKey aKey, uint32_t mask)
 {
   for (uint32_t i = 0; i < nsMsgProcessingFlags::NumberOfFlags; i++)
     if (!(mProcessingFlag[i].bit & mask) && mProcessingFlag[i].keys)
       mProcessingFlag[i].keys->Remove(aKey);
   return NS_OK;
 }
 
+// Each implementation must provide an override of this, connecting the folder
+// type to the corresponding incoming server type.
+NS_IMETHODIMP nsMsgDBFolder::GetIncomingServerType(nsACString& aIncomingServerType)
+{
+  NS_ASSERTION(false, "subclasses need to override this");
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
 void nsMsgDBFolder::ClearProcessingFlags()
 {
   for (uint32_t i = 0; i < nsMsgProcessingFlags::NumberOfFlags; i++)
   {
     // There is no clear method so we need to delete and re-create.
     delete mProcessingFlag[i].keys;
     mProcessingFlag[i].keys = nsMsgKeySetU::Create();
   }
--- a/mailnews/base/util/nsMsgDBFolder.h
+++ b/mailnews/base/util/nsMsgDBFolder.h
@@ -80,22 +80,16 @@ public:
   nsresult CreateDirectoryForFolder(nsIFile **result);
   nsresult CreateBackupDirectory(nsIFile **result);
   nsresult GetBackupSummaryFile(nsIFile **result, const nsACString& newName);
   nsresult GetMsgPreviewTextFromStream(nsIMsgDBHdr *msgHdr, nsIInputStream *stream);
   nsresult HandleAutoCompactEvent(nsIMsgWindow *aMsgWindow);
 protected:
   virtual ~nsMsgDBFolder();
   
-  // this is a little helper function that is not part of the public interface. 
-  // we use it to get the IID of the incoming server for the derived folder.
-  // w/out a function like this we would have to implement GetServer in each
-  // derived folder class.
-  virtual void GetIncomingServerType(nsCString& serverType) = 0;
-
   virtual nsresult CreateBaseMessageURI(const nsACString& aURI);
 
   void compressQuotesInMsgSnippet(const nsString& aMessageText, nsAString& aCompressedQuotesStr);
   void decodeMsgSnippet(const nsACString& aEncodingType, bool aIsComplete, nsCString& aMsgSnippet);
 
   // helper routine to parse the URI and update member variables
   nsresult parseURI(bool needServer=false);
   nsresult GetBaseStringBundle(nsIStringBundle **aBundle);
--- a/mailnews/compose/public/moz.build
+++ b/mailnews/compose/public/moz.build
@@ -1,15 +1,16 @@
 # vim: set filetype=python:
 # 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/.
 
 XPIDL_SOURCES += [
     'nsIMsgAttachment.idl',
+    'nsIMsgAttachmentHandler.idl',
     'nsIMsgCompFields.idl',
     'nsIMsgCompose.idl',
     'nsIMsgComposeParams.idl',
     'nsIMsgComposeProgressParams.idl',
     'nsIMsgComposeSecure.idl',
     'nsIMsgComposeService.idl',
     'nsIMsgCompUtils.idl',
     'nsIMsgQuote.idl',
new file mode 100644
--- /dev/null
+++ b/mailnews/compose/public/nsIMsgAttachmentHandler.idl
@@ -0,0 +1,45 @@
+/* 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 "nsISupports.idl"
+interface nsIFile;
+
+// This interface provides minimal XPCONNECT access to objects of type
+// nsMsgAttachmentHandler. This is primarily for use with new account
+// types and JsAccount, so this is probably not the interface that you
+// want if you are working with standard account types.
+
+[scriptable, uuid(1731283c-60fe-4102-a804-622a84cc1a08)]
+interface nsIMsgAttachmentHandler : nsISupports
+{
+  /// The real type, once we know it.
+  readonly attribute ACString type;
+
+  /// URI with link to the attachment.
+  readonly attribute ACString uri;
+
+  /// The temp file to which we save it.
+  readonly attribute nsIFile tmpFile;
+
+  /// The name for the headers, if different from the URL.
+  readonly attribute AUTF8String name;
+
+  /// Size of the attachment, in bytes.
+  readonly attribute unsigned long size;
+
+  /// This is for multipart/related Content-ID's.
+  readonly attribute ACString contentId;
+
+  /// True if this should be sent as a link to a file.
+  readonly attribute boolean sendViaCloud;
+
+  /// Name of the character set for the attachment.
+  readonly attribute ACString charset;
+
+  /// The encoding, once we've decided.
+  readonly attribute ACString encoding;
+
+  /// Whether the attachment has been encoded, for example to base64.
+  readonly attribute boolean alreadyEncoded;
+};
--- a/mailnews/compose/public/nsIMsgCompose.idl
+++ b/mailnews/compose/public/nsIMsgCompose.idl
@@ -93,17 +93,17 @@ native nsString(nsString);
 
 /* recycling listener interface */
 [scriptable, uuid(0b28cc56-1dd2-11b2-bbe4-99e6a314f8ba)]
 interface nsIMsgComposeRecyclingListener : nsISupports {
   void onClose();
   void onReopen(in nsIMsgComposeParams params);
 };
 
-[scriptable, uuid(44596460-2de4-11e4-8c21-0800200c9a66)]
+[scriptable, uuid(d06ca5af-66b5-4a08-961f-5b47e88cee98)]
 interface nsIMsgCompose : nsIMsgSendListener {
 
   /**
    * Initializes the msg compose object.
    *
    * @param aParams   An nsIMsgComposeParams object containing the initial
    *                  details for the compose.
    * @param aWindow   The optional window associated with this compose object.
@@ -121,16 +121,29 @@ interface nsIMsgCompose : nsIMsgSendList
   void RegisterStateListener(in nsIMsgComposeStateListener stateListener);
 
   /* ... */
   void UnregisterStateListener(in nsIMsgComposeStateListener stateListener);
 
   /* ... */
   void SendMsg(in MSG_DeliverMode deliverMode, in nsIMsgIdentity identity, in string accountKey, in nsIMsgWindow aMsgWindow, in nsIMsgProgress progress);
 
+  /**
+   * After all Compose preparations are complete, send the prepared message to
+   * the server. This exists primarily to allow an override of the sending to
+   * use a non-SMTP method for send.
+   *
+   * @param deliverMode One of the nsIMsgCompDeliverMode values.
+   * @param identity The message identity.
+   * @param accountKey The message account key.
+   */
+  void sendMsgToServer(in MSG_DeliverMode deliverMode,
+                       in nsIMsgIdentity identity,
+                       in string accountKey);
+
   /* ... */
   void CloseWindow(in boolean reclycleIt);
 
   /* ... */
   void abort();
     
   /* ... */
   void quoteMessage(in string msgURI);
@@ -173,18 +186,21 @@ interface nsIMsgCompose : nsIMsgSendList
    * if it is different the SendMsg version will overwrite this identity.
    */
   attribute nsIMsgIdentity identity;
 
   /* Check if the composing mail headers (and identity) can be converted to a mail charset.
   */
   boolean checkCharsetConversion(in nsIMsgIdentity identity, out string fallbackCharset);
 
-  /* the message send object */
-  readonly attribute nsIMsgSend messageSend;
+  /* The message send object. This is created by default to be the SMTP server
+   * in sendMsgToServer, but if that method is overridden, set the actual
+   * value used here.
+   */
+  attribute nsIMsgSend messageSend;
 
   /*
    * Clear the messageSend object to break any circular references
    */
    void clearMessageSend();
 
   /* ... */
   attribute nsIEditor editor;
@@ -205,16 +221,20 @@ interface nsIMsgCompose : nsIMsgSendList
   readonly attribute long wrapLength;
 
   /* by reading this value, you can determine if yes or not the message has been mofified
      by the user. When you set this value to false, you reset the modification count
      of the body to 0 (clean).
   */
   attribute boolean bodyModified;
 
+  /* The body string is stored as a byte string in comp fields, but is converted to
+   * UTF16 when fetched by GetBody(). Fetch the body without conversion.
+   */
+  readonly attribute ACString bodyRaw;
 
   /**
    *  Init the editor THIS USED TO BE [noscript]
    *  Now, this is called after editor is created,
    *  which is triggered by loading startup url from JS.
    *  The completion of document loading is detected by observing 
    *  the "obs_documentCreated" command
    */
@@ -277,18 +297,21 @@ interface nsIMsgCompose : nsIMsgSendList
   attribute boolean insertingQuotedContent;
 
   /* for easier use of nsIMsgSendListener */
   void addMsgSendListener(in nsIMsgSendListener sendListener);
 
   /* for easier use of nsIMsgSendListener */
   void removeMsgSendListener(in nsIMsgSendListener sendListener);
 
+  // Access during mail-set-sender observer if needed, see nsIMsgCompDeliverMode.
+  readonly attribute MSG_DeliverMode deliverMode;
+
 };
 
 /* send listener interface */
-[uuid(ACC72780-2CEA-11D5-9DAA-BACDEAC1EEFC)]
+[scriptable, uuid(ad6ee068-b225-47f9-a50e-8e48440282ca)]
 interface nsIMsgComposeSendListener : nsISupports {
 
   void setMsgCompose(in nsIMsgCompose msgCompose);
   void setDeliverMode(in MSG_DeliverMode deliverMode);
  
 };
--- a/mailnews/compose/public/nsIMsgSend.idl
+++ b/mailnews/compose/public/nsIMsgSend.idl
@@ -29,16 +29,17 @@ interface nsIMsgDBHdr;
 interface nsIMsgHdr;
 interface nsIFile;
 interface nsIOutputStream;
 interface nsIMsgComposeSecure;
 interface nsIMsgStatusFeedback;
 interface nsIEditor;
 interface nsIArray;
 interface nsISupportsArray;
+interface nsIMsgAttachmentHandler;
 
 typedef long nsMsgDeliverMode;
 
 [scriptable, uuid(c658cd1f-dc4a-43c0-911c-c6d3e569ca7e)]
 interface nsIMsgAttachmentData : nsISupports
 {
   /// The URL to attach.
   attribute nsIURI url;
@@ -146,17 +147,17 @@ interface nsIMsgEmbeddedImageData : nsIS
 class nsMsgAttachmentHandler;
 #include "nsAutoPtr.h"
 #include "nsTArray.h"
 %}
 
 [ptr] native nsMsgAttachedFile(nsMsgAttachedFile);
 [ptr] native nsMsgAttachmentHandlerArray(nsTArray<RefPtr<nsMsgAttachmentHandler>>);
 
-[scriptable, uuid(3fa45021-8174-478f-8c69-f3a8dc3f49fc)]
+[scriptable, uuid(adcea7be-0585-4f43-ab97-f2436ea5e002)]
 interface nsIMsgSend : nsISupports
 {
   //
   // This is the primary interface for creating and sending RFC822 messages
   // in the new architecture. Currently, this method supports many arguments
   // that change the behavior of the operation. This will change in time to 
   // be separate calls that will be more singluar in nature.
   //
@@ -364,9 +365,41 @@ interface nsIMsgSend : nsISupports
 
     nsIOutputStream getOutputStream();
 
     attribute nsIRequest runningRequest;
 
     attribute nsresult status;
 
     attribute nsIMsgComposeSecure cryptoclosure;
+
+    /// Access the local copy of the composition fields.
+    readonly attribute nsIMsgCompFields sendCompFields;
+
+    /// The message body.
+    readonly attribute AString sendBody;
+
+    /// The type of the message body (typically text/plain or text/html).
+    readonly attribute ACString sendBodyType;
+
+    /// The identity to use to send the message.
+    readonly attribute nsIMsgIdentity identity;
+
+    /**
+     * Get a handler for an attachment by its index.
+     * The lifetime of the attachment is dependent on the existence
+     * of the underlying send object, so do not hold onto these
+     * attachment handlers.
+     *
+     * @param index  Index used to specify a particular attachment.
+     *
+     * @return       Attachment handler with information about the attachment.
+     */
+    nsIMsgAttachmentHandler getAttachment(in unsigned long index);
+
+    /// The folder name to which the message will be saved,
+    /// used by error reporting.
+    attribute AString savedToFolderName;
+
+    /// Should we deliver this message (versus saving as a file)?
+    attribute boolean dontDeliver;
+
 };
--- a/mailnews/compose/src/moz.build
+++ b/mailnews/compose/src/moz.build
@@ -1,15 +1,19 @@
 # vim: set filetype=python:
 # 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/.
 
 EXPORTS += [
     'nsComposeStrings.h',
+    'nsMsgAttachmentHandler.h',
+    'nsMsgCompFields.h',
+    'nsMsgCompose.h',
+    'nsMsgSend.h',
 ]
 
 SOURCES += [
     'nsComposeStrings.cpp',
     'nsMsgAttachment.cpp',
     'nsMsgAttachmentHandler.cpp',
     'nsMsgCompFields.cpp',
     'nsMsgCompose.cpp',
--- a/mailnews/compose/src/nsMsgAttachmentHandler.cpp
+++ b/mailnews/compose/src/nsMsgAttachmentHandler.cpp
@@ -149,16 +149,96 @@ nsMsgAttachmentHandler::~nsMsgAttachment
     mTmpFile->Remove(false);
 
   if (mOutFile)
     mOutFile->Close();
 
   CleanupTempFile();
 }
 
+NS_IMPL_ISUPPORTS(nsMsgAttachmentHandler, nsIMsgAttachmentHandler)
+
+// nsIMsgAttachmentHandler implementation.
+
+NS_IMETHODIMP nsMsgAttachmentHandler::GetType(nsACString& aType)
+{
+  aType.Assign(m_type);
+  return NS_OK;
+}
+
+NS_IMETHODIMP nsMsgAttachmentHandler::GetUri(nsACString& aUri)
+{
+  nsAutoCString turl;
+  if (!mURL)
+  {
+    if (!m_uri.IsEmpty())
+      turl = m_uri;
+  }
+  else
+    mURL->GetSpec(turl);
+  aUri.Assign(turl);
+  return NS_OK;
+}
+
+NS_IMETHODIMP nsMsgAttachmentHandler::GetTmpFile(nsIFile **aTmpFile)
+{
+  NS_ENSURE_ARG_POINTER(aTmpFile);
+  if (!mTmpFile)
+    return NS_ERROR_FAILURE;
+  NS_ADDREF(*aTmpFile = mTmpFile);
+  return NS_OK;
+}
+
+NS_IMETHODIMP nsMsgAttachmentHandler::GetName(nsACString& aName)
+{
+  aName.Assign(m_realName);
+  return NS_OK;
+}
+
+NS_IMETHODIMP nsMsgAttachmentHandler::GetSize(uint32_t *aSize)
+{
+  NS_ENSURE_ARG_POINTER(aSize);
+  *aSize = m_size;
+  return NS_OK;
+}
+
+NS_IMETHODIMP nsMsgAttachmentHandler::GetContentId(nsACString& aContentId)
+{
+  aContentId.Assign(m_contentId);
+  return NS_OK;
+}
+
+NS_IMETHODIMP nsMsgAttachmentHandler::GetSendViaCloud(bool* aSendViaCloud)
+{
+  NS_ENSURE_ARG_POINTER(aSendViaCloud);
+  *aSendViaCloud = mSendViaCloud;
+  return NS_OK;
+}
+
+NS_IMETHODIMP nsMsgAttachmentHandler::GetCharset(nsACString& aCharset)
+{
+  aCharset.Assign(m_charset);
+  return NS_OK;
+}
+
+NS_IMETHODIMP nsMsgAttachmentHandler::GetEncoding(nsACString& aEncoding)
+{
+  aEncoding.Assign(m_encoding);
+  return NS_OK;
+}
+
+NS_IMETHODIMP nsMsgAttachmentHandler::GetAlreadyEncoded(bool* aAlreadyEncoded)
+{
+  NS_ENSURE_ARG_POINTER(aAlreadyEncoded);
+  *aAlreadyEncoded = m_already_encoded_p;
+  return NS_OK;
+}
+
+// Local methods.
+
 void
 nsMsgAttachmentHandler::CleanupTempFile()
 {
 #ifdef XP_MACOSX
   if (mEncodedWorkingFile) {
     mEncodedWorkingFile->Remove(false);
     mEncodedWorkingFile = nullptr;
   }
--- a/mailnews/compose/src/nsMsgAttachmentHandler.h
+++ b/mailnews/compose/src/nsMsgAttachmentHandler.h
@@ -9,16 +9,17 @@
 #include "nsIURL.h"
 #include "nsMsgCompFields.h"
 #include "nsIMsgStatusFeedback.h"
 #include "nsIChannel.h"
 #include "nsIMsgSend.h"
 #include "nsIFileStreams.h"
 #include "nsIStreamConverter.h"
 #include "nsAutoPtr.h"
+#include "nsIMsgAttachmentHandler.h"
 
 #ifdef XP_MACOSX
 
 #include "nsMsgAppleDouble.h"
 #include "nsILocalFileMac.h"
 
 class AppleDoubleEncodeObject
 {
@@ -56,22 +57,24 @@ namespace mailnews {
 class MimeEncoder;
 }
 }
 
 //
 // This is a class that deals with processing remote attachments. It implements
 // an nsIStreamListener interface to deal with incoming data
 //
-class nsMsgAttachmentHandler
+class nsMsgAttachmentHandler : public nsIMsgAttachmentHandler
 {
-  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(nsMsgAttachmentHandler)
 
   typedef mozilla::mailnews::MimeEncoder MimeEncoder;
 public:
+  NS_DECL_THREADSAFE_ISUPPORTS
+  NS_DECL_NSIMSGATTACHMENTHANDLER
+
   nsMsgAttachmentHandler();
 public:
   nsresult              SnarfAttachment(nsMsgCompFields *compFields);
   nsresult              PickEncoding(const char *charset, nsIMsgSend* mime_delivery_state);
   nsresult              PickCharset();
   void                  AnalyzeSnarfedFile ();      // Analyze a previously-snarfed file.
                                                     // (Currently only used for plaintext
                                                     // converted from HTML.) 
@@ -80,17 +83,17 @@ public:
   
   // if there's an intermediate temp file left, takes care to remove it from disk.
   //
   // NOTE: this takes care of the mEncodedWorkingFile temp file, but not mTmpFile which seems
   // to be used by lots of other classes at the moment.
   void                  CleanupTempFile();
 
 private:
-  ~nsMsgAttachmentHandler();
+  virtual ~nsMsgAttachmentHandler();
 
   // use when a message (e.g. original message in a reply) is attached as a rfc822 attachment.
   nsresult              SnarfMsgAttachment(nsMsgCompFields *compFields);
   bool                  UseUUEncode_p(void);
   void                  AnalyzeDataChunk (const char *chunk, int32_t chunkSize);
   nsresult              LoadDataFromFile(nsIFile *file, nsString &sigData, bool charsetConversion); //A similar function already exist in nsMsgCompose!
 #ifdef XP_MACOSX
   nsresult              ConvertToAppleEncoding(const nsCString &aFileSpecURI, 
--- a/mailnews/compose/src/nsMsgCompose.cpp
+++ b/mailnews/compose/src/nsMsgCompose.cpp
@@ -73,16 +73,17 @@
 #include "nsIMsgWindow.h"
 #include "nsITextToSubURI.h"
 #include "nsIAbManager.h"
 #include "nsCRT.h"
 #include "mozilla/Services.h"
 #include "mozilla/mailnews/MimeHeaderParser.h"
 #include "nsISelection.h"
 #include "nsJSEnvironment.h"
+#include "nsIObserverService.h"
 
 using namespace mozilla::mailnews;
 
 static nsresult GetReplyHeaderInfo(int32_t* reply_header_type,
                                    nsString& reply_header_locale,
                                    nsString& reply_header_authorwrote,
                                    nsString& reply_header_ondateauthorwrote,
                                    nsString& reply_header_authorwroteondate,
@@ -1033,18 +1034,19 @@ NS_IMETHODIMP nsMsgCompose::AddMsgSendLi
 }
 
 NS_IMETHODIMP nsMsgCompose::RemoveMsgSendListener( nsIMsgSendListener *aMsgSendListener )
 {
   NS_ENSURE_ARG_POINTER(aMsgSendListener);
   return mExternalSendListeners.RemoveElement(aMsgSendListener) ? NS_OK : NS_ERROR_FAILURE;
 }
 
-nsresult nsMsgCompose::_SendMsg(MSG_DeliverMode deliverMode, nsIMsgIdentity *identity,
-                                const char *accountKey)
+NS_IMETHODIMP
+nsMsgCompose::SendMsgToServer(MSG_DeliverMode deliverMode, nsIMsgIdentity *identity,
+                              const char *accountKey)
 {
   nsresult rv = NS_OK;
 
   // clear saved message id if sending, so we don't send out the same message-id.
   if (deliverMode == nsIMsgCompDeliverMode::Now ||
       deliverMode == nsIMsgCompDeliverMode::Later ||
       deliverMode == nsIMsgCompDeliverMode::Background)
     m_compFields->SetMessageId("");
@@ -1064,17 +1066,34 @@ nsresult nsMsgCompose::_SendMsg(MSG_Deli
     if (!pFrom || !*pFrom)
     {
       nsCString sender;
       MakeMimeAddress(NS_ConvertUTF16toUTF8(fullName), email, sender);
       m_compFields->SetFrom(sender.IsEmpty() ? email.get() : sender.get());
     }
 
     m_compFields->SetOrganization(organization);
-    mMsgSend = do_CreateInstance(NS_MSGSEND_CONTRACTID);
+
+    // We need an nsIMsgSend instance to send the message. Allow extensions
+    // to override the default SMTP sender by observing mail-set-sender.
+    mMsgSend = nullptr;
+    mDeliverMode = deliverMode;  // save for possible access by observer;
+
+    nsCOMPtr<nsIObserverService> observerService =
+      mozilla::services::GetObserverService();
+    if (observerService)
+    {
+      observerService->NotifyObservers(
+        NS_ISUPPORTS_CAST(nsIMsgCompose*, this),
+        "mail-set-sender",
+        NS_ConvertUTF8toUTF16(nsDependentCString(accountKey)).get());
+    }
+    if (!mMsgSend)
+      mMsgSend = do_CreateInstance(NS_MSGSEND_CONTRACTID);
+
     if (mMsgSend)
     {
       nsCString bodyString(m_compFields->GetBody());
 
       // Create the listener for the send operation...
       nsCOMPtr<nsIMsgComposeSendListener> composeSendListener = do_CreateInstance(NS_MSGCOMPOSESENDLISTENER_CONTRACTID);
       if (!composeSendListener)
         return NS_ERROR_OUT_OF_MEMORY;
@@ -1315,17 +1334,17 @@ NS_IMETHODIMP nsMsgCompose::SendMsg(MSG_
               m_compFields->AddAttachment(attachment);
           }
       }
   }
 
   // Save the identity being sent for later use.
   m_identity = identity;
 
-  rv = _SendMsg(deliverMode, identity, accountKey);
+  rv = SendMsgToServer(deliverMode, identity, accountKey);
   if (NS_FAILED(rv))
   {
     nsCOMPtr<nsIMsgSendReport> sendReport;
     if (mMsgSend)
       mMsgSend->GetSendReport(getter_AddRefs(sendReport));
     if (sendReport)
     {
       nsresult theError;
@@ -1562,16 +1581,22 @@ NS_IMETHODIMP nsMsgCompose::InitEditor(n
   {
     NotifyStateListeners(nsIMsgComposeNotificationType::ComposeFieldsReady, NS_OK);
     nsresult rv = BuildBodyMessageAndSignature();
     NotifyStateListeners(nsIMsgComposeNotificationType::ComposeBodyReady, NS_OK);
     return rv;
   }
 }
 
+NS_IMETHODIMP nsMsgCompose::GetBodyRaw(nsACString& aBodyRaw)
+{
+  aBodyRaw.Assign((char *)m_compFields->GetBody());
+  return NS_OK;
+}
+
 nsresult nsMsgCompose::GetBodyModified(bool * modified)
 {
   nsresult rv;
 
   if (! modified)
     return NS_ERROR_NULL_POINTER;
 
   *modified = true;
@@ -2110,16 +2135,22 @@ NS_IMETHODIMP nsMsgCompose::GetProgress(
 NS_IMETHODIMP nsMsgCompose::GetMessageSend(nsIMsgSend **_retval)
 {
   NS_ENSURE_ARG_POINTER(_retval);
   *_retval = mMsgSend;
   NS_IF_ADDREF(*_retval);
   return NS_OK;
 }
 
+NS_IMETHODIMP nsMsgCompose::SetMessageSend(nsIMsgSend* aMsgSend)
+{
+  mMsgSend = aMsgSend;
+  return NS_OK;
+}
+
 NS_IMETHODIMP nsMsgCompose::ClearMessageSend()
 {
   mMsgSend = nullptr;
   return NS_OK;
 }
 
 NS_IMETHODIMP nsMsgCompose::SetCiteReference(nsString citeReference)
 {
@@ -5469,16 +5500,23 @@ NS_IMETHODIMP nsMsgCompose::CheckCharset
   // headers can be converted to the appropriate charset, but we don't support
   // encoding headers to non-UTF-8, so this is now moot.
   if (fallbackCharset)
     *fallbackCharset = nullptr;
   *_retval = true;
   return NS_OK;
 }
 
+NS_IMETHODIMP nsMsgCompose::GetDeliverMode(MSG_DeliverMode* aDeliverMode)
+{
+  NS_ENSURE_ARG_POINTER(aDeliverMode);
+  *aDeliverMode = mDeliverMode;
+  return NS_OK;
+}
+
 nsMsgMailList::nsMsgMailList(nsIAbDirectory* directory) :
   mDirectory(directory)
 {
   mDirectory->GetDirName(mName);
   mDirectory->GetDescription(mDescription);
 
   if (mDescription.IsEmpty())
     mDescription = mName;
--- a/mailnews/compose/src/nsMsgCompose.h
+++ b/mailnews/compose/src/nsMsgCompose.h
@@ -40,17 +40,17 @@ class nsMsgCompose : public nsIMsgCompos
 	NS_DECL_THREADSAFE_ISUPPORTS
 
 	/*** nsIMsgCompose pure virtual functions */
 	NS_DECL_NSIMSGCOMPOSE
 
   /* nsIMsgSendListener interface */
   NS_DECL_NSIMSGSENDLISTENER
 
-private:
+protected:
 	virtual ~nsMsgCompose();
 
  // Deal with quoting issues...
 	nsresult                      QuoteOriginalMessage(); // New template
   nsresult                      SetQuotingToFollow(bool aVal);
   nsresult                      ConvertHTMLToText(nsIFile *aSigFile, nsString &aSigData);
   nsresult                      ConvertTextToHTML(nsIFile *aSigFile, nsString &aSigData);
   bool                          IsEmbeddedObjectSafe(const char * originalScheme,
@@ -71,18 +71,17 @@ private:
                                                  bool aAllowUTF16 = true);
 
   bool                          CheckIncludeSignaturePrefs(nsIMsgIdentity *identity);
   //m_folderName to store the value of the saved drafts folder.
   nsCString                     m_folderName;
   void InsertDivWrappedTextAtSelection(const nsAString &aText,
                                        const nsAString &classStr);
 
- private:
-  nsresult _SendMsg(MSG_DeliverMode deliverMode, nsIMsgIdentity *identity, const char *accountKey);
+ protected:
   nsresult CreateMessage(const char * originalMsgURI, MSG_ComposeType type, nsIMsgCompFields* compFields);
   void CleanUpRecipients(nsString& recipients);
   nsresult GetABDirectories(const nsACString& aDirUri,
                             nsCOMArray<nsIAbDirectory> &aDirArray);
   nsresult BuildMailListArray(nsIAbDirectory* parentDir,
                               nsTArray<nsMsgMailList>& array);
   nsresult TagConvertible(nsIDOMNode *node,  int32_t *_retval);
   nsresult _BodyConvertible(nsIDOMNode *node, int32_t *_retval);
@@ -127,17 +126,18 @@ private:
 
   nsCString                                 mSmtpPassword;
   nsCString                                 mHtmlToQuote;
 
   nsTObserverArray<nsCOMPtr<nsIMsgComposeStateListener> > mStateListeners;
   nsTObserverArray<nsCOMPtr<nsIMsgSendListener> > mExternalSendListeners;
     
   bool                                      mInsertingQuotedContent;
-    
+  MSG_DeliverMode                           mDeliverMode;  // nsIMsgCompDeliverMode long.
+
   friend class QuotingOutputStreamListener;
 	friend class nsMsgComposeSendListener;
 };
 
 ////////////////////////////////////////////////////////////////////////////////////
 // THIS IS THE CLASS THAT IS THE STREAM Listener OF THE HTML OUPUT
 // FROM LIBMIME. THIS IS FOR QUOTING
 ////////////////////////////////////////////////////////////////////////////////////
--- a/mailnews/compose/src/nsMsgSend.cpp
+++ b/mailnews/compose/src/nsMsgSend.cpp
@@ -74,16 +74,17 @@
 #include "nsMsgUtils.h"
 #include "nsIArray.h"
 #include "nsArrayUtils.h"
 #include "mozilla/Services.h"
 #include "mozilla/mailnews/MimeEncoder.h"
 #include "mozilla/mailnews/MimeHeaderParser.h"
 #include "nsIMutableArray.h"
 #include "nsIMsgFilterService.h"
+#include "nsIMsgProtocolInfo.h"
 
 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"
@@ -198,20 +199,20 @@ static nsresult StripOutGroupNames(char 
 
 
 // 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)
 
@@ -224,40 +225,41 @@ MsgDeliveryListener::MsgDeliveryListener
 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)
+NS_IMPL_ISUPPORTS(nsMsgComposeAndSend, nsIMsgSend, nsIMsgOperationListener,
+                  nsISupportsWeakReference)
 
 nsMsgComposeAndSend::nsMsgComposeAndSend() :
     m_messageKey(nsMsgKey_None)
 {
   mGUINotificationEnabled = true;
   mAbortInProcess = false;
   mMultipartRelatedAttachmentCount = -1;
   mSendMailAlso = false;
@@ -1785,21 +1787,39 @@ nsMsgComposeAndSend::ProcessMultipartRel
       // 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))
+            (NS_SUCCEEDED(uri->SchemeIs("imap", &match)) && match))
           (*aMailboxCount)++;
         else if ((NS_SUCCEEDED(uri->SchemeIs("news", &match)) && match) ||
-                (NS_SUCCEEDED(uri->SchemeIs("snews", &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);
     }
 
@@ -2175,19 +2195,24 @@ nsMsgComposeAndSend::AddCompFieldRemoteA
     {
       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()))
         {
-          bool isAMessageAttachment = !PL_strncasecmp(url.get(), "mailbox-message://", 18) ||
-              !PL_strncasecmp(url.get(), "imap-message://", 15) ||
-              !PL_strncasecmp(url.get(), "news-message://", 15);
+          // 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());
 
@@ -2405,29 +2430,45 @@ nsMsgComposeAndSend::HackAttachments(nsI
       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++;
-
-      if (uri)
-        msg_pick_real_name(m_attachments[i], nullptr, mCompFields->GetCharacterSet());
+      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)
   {
@@ -3130,17 +3171,17 @@ NS_IMETHODIMP nsMsgComposeAndSend::SendD
         default:
           if (aExitCode != NS_ERROR_ABORT && !NS_IS_MSG_ERROR(aExitCode))
             aExitCode = NS_ERROR_SMTP_SEND_FAILED_UNKNOWN_REASON;
           break;
       }
     }
     DeliverAsMailExit(aUrl, aExitCode);
   }
-  
+
   return aExitCode;
 }
 
 nsresult
 nsMsgComposeAndSend::DeliverMessage()
 {
   if (mSendProgress)
   {
@@ -3227,17 +3268,17 @@ nsMsgComposeAndSend::DeliverFileAsMail()
 
   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);
 
@@ -3272,31 +3313,31 @@ nsMsgComposeAndSend::DeliverFileAsMail()
 #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()), 
+      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()), 
+      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()), 
+      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...
@@ -4809,16 +4850,92 @@ NS_IMETHODIMP nsMsgComposeAndSend::GetCr
 }
 
 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));
+  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_isExternalAttachment(0),
   m_isDownloaded(false), m_hasFilename(false), m_displayableInline(false)
 {
 }
 
 nsMsgAttachmentData::~nsMsgAttachmentData()
--- a/mailnews/compose/src/nsMsgSend.h
+++ b/mailnews/compose/src/nsMsgSend.h
@@ -161,17 +161,18 @@ class nsIInterfaceRequestor;
 
 namespace mozilla {
 namespace mailnews {
 class MimeEncoder;
 }
 }
 
 class nsMsgComposeAndSend : public nsIMsgSend,
-                            public nsIMsgOperationListener
+                            public nsIMsgOperationListener,
+                            public nsSupportsWeakReference
 {
   typedef mozilla::mailnews::MimeEncoder MimeEncoder;
 public:
   //
   // Define QueryInterface, AddRef and Release for this class
   //
   NS_DECL_THREADSAFE_ISUPPORTS
   NS_DECL_NSIMSGSEND
@@ -366,17 +367,17 @@ public:
   bool                    mGUINotificationEnabled;      // Should we throw up the GUI alerts on errors?
   bool                    mAbortInProcess;              // Used by Abort to avoid reentrance.
 
   nsCOMPtr<nsIMsgComposeSecure> m_crypto_closure;
 
 protected:
   nsCOMPtr<nsIStringBundle> mComposeBundle;
   nsresult GetNotificationCallbacks(nsIInterfaceRequestor** aCallbacks);
-private:
+
   virtual ~nsMsgComposeAndSend();
   nsresult FilterSentMessage();
   nsresult MaybePerformSecondFCC(nsresult aStatus);
 
   // generates a message id for our message, if necessary
   void GenerateMessageId( );
 
   // add default custom headers to the message
--- a/mailnews/imap/src/nsImapMailFolder.cpp
+++ b/mailnews/imap/src/nsImapMailFolder.cpp
@@ -9811,16 +9811,22 @@ NS_IMETHODIMP nsImapMailFolder::GetOffli
       return rv;
     nsMsgKey newMsgKey;
     hdr->GetMessageKey(&newMsgKey);
     return offlineFolder->GetOfflineFileStream(newMsgKey, offset, size, aFileStream);
   }
   return NS_OK;
 }
 
+NS_IMETHODIMP nsImapMailFolder::GetIncomingServerType(nsACString& serverType)
+{
+  serverType.AssignLiteral("imap");
+  return NS_OK;
+}
+
 void nsImapMailFolder::DeleteStoreMessages(nsIArray* aMessages)
 {
   // Delete messages for pluggable stores that do not support compaction.
   nsCOMPtr<nsIMsgPluggableStore> offlineStore;
   (void) GetMsgStore(getter_AddRefs(offlineStore));
 
   if (offlineStore)
   {
--- a/mailnews/imap/src/nsImapMailFolder.h
+++ b/mailnews/imap/src/nsImapMailFolder.h
@@ -317,16 +317,18 @@ public:
   * the folder where the message first arrives, this method searches for the existence
   * of msg in all the folders/labels that we retrieve from X-GM-LABELS also.
   * overrides nsMsgDBFolder::GetOfflineMsgFolder()
   *  @param msgKey key  of the msg for which we are trying to get the folder;
   *  @param aMsgFolder  required folder;
   */
   NS_IMETHOD GetOfflineMsgFolder(nsMsgKey msgKey, nsIMsgFolder **aMsgFolder) override;
 
+  NS_IMETHOD GetIncomingServerType(nsACString& serverType) override;
+
   nsresult AddSubfolderWithPath(nsAString& name, nsIFile *dbPath, nsIMsgFolder **child, bool brandNew = false);
   nsresult MoveIncorporatedMessage(nsIMsgDBHdr *mailHdr,
                                   nsIMsgDatabase *sourceDB,
                                   const nsACString& destFolder,
                                   nsIMsgFilter *filter,
                                   nsIMsgWindow *msgWindow);
 
   // send notification to copy service listener.
@@ -390,17 +392,16 @@ protected:
   static bool ShouldCheckAllFolders(nsIImapIncomingServer *imapServer);
   nsresult GetServerKey(nsACString& serverKey);
   nsresult DisplayStatusMsg(nsIImapUrl *aImapUrl, const nsAString& msg);
 
   //nsresult RenameLocal(const char *newName);
   nsresult AddDirectorySeparator(nsIFile *path);
   nsresult CreateSubFolders(nsIFile *path);
   nsresult GetDatabase() override;
-  virtual void GetIncomingServerType(nsCString& serverType) override { serverType.AssignLiteral("imap");}
 
   nsresult        GetFolderOwnerUserName(nsACString& userName);
   nsIMAPNamespace *GetNamespaceForFolder();
   void            SetNamespaceForFolder(nsIMAPNamespace *ns);
 
   nsMsgIMAPFolderACL * GetFolderACL();
   nsresult CreateACLRightsStringForFolder(nsAString& rightsString);
   nsresult GetBodysToDownload(nsTArray<nsMsgKey> *keysOfMessagesToDownload);
--- a/mailnews/local/src/nsLocalMailFolder.cpp
+++ b/mailnews/local/src/nsLocalMailFolder.cpp
@@ -3079,34 +3079,34 @@ NS_IMETHODIMP nsMsgLocalMailFolder::Noti
   NotifyFolderEvent(mDeleteOrMoveMsgCompletedAtom);
   return NS_OK;
 }
 
 // TODO:  once we move certain code into the IncomingServer (search for TODO)
 // this method will go away.
 // sometimes this gets called when we don't have the server yet, so
 // that's why we're not calling GetServer()
-void
-nsMsgLocalMailFolder::GetIncomingServerType(nsCString& aServerType)
+NS_IMETHODIMP
+nsMsgLocalMailFolder::GetIncomingServerType(nsACString& aServerType)
 {
   nsresult rv;
   if (mType.IsEmpty())
   {
     nsCOMPtr<nsIURL> url = do_CreateInstance(NS_STANDARDURL_CONTRACTID, &rv);
     if (NS_FAILED(rv))
-      return;
+      return rv;
 
     rv = url->SetSpec(mURI);
     if (NS_FAILED(rv))
-      return;
+      return rv;
 
     nsCOMPtr<nsIMsgAccountManager> accountManager =
              do_GetService(NS_MSGACCOUNTMANAGER_CONTRACTID, &rv);
     if (NS_FAILED(rv))
-      return;
+      return rv;
 
     nsCOMPtr<nsIMsgIncomingServer> server;
     // try "none" first
     url->SetScheme(NS_LITERAL_CSTRING("none"));
     rv = accountManager->FindServerByURI(url, false, getter_AddRefs(server));
     if (NS_SUCCEEDED(rv) && server)
       mType.AssignLiteral("none");
     else
@@ -3132,16 +3132,17 @@ nsMsgLocalMailFolder::GetIncomingServerT
           if (NS_SUCCEEDED(rv) && server)
             mType.AssignLiteral("movemail");
 #endif /* HAVE_MOVEMAIL */
         }
       }
     }
   }
   aServerType = mType;
+  return NS_OK;
 }
 
 nsresult nsMsgLocalMailFolder::CreateBaseMessageURI(const nsACString& aURI)
 {
   return nsCreateLocalBaseMessageURI(aURI, mBaseMessageURI);
 }
 
 NS_IMETHODIMP
--- a/mailnews/local/src/nsLocalMailFolder.h
+++ b/mailnews/local/src/nsLocalMailFolder.h
@@ -170,16 +170,17 @@ public:
 
   // Used when headers_only is TRUE
   NS_IMETHOD DownloadMessagesForOffline(nsIArray *aMessages, nsIMsgWindow *aWindow) override;
   NS_IMETHOD FetchMsgPreviewText(nsMsgKey *aKeysToFetch, uint32_t aNumKeys,
                                                  bool aLocalOnly, nsIUrlListener *aUrlListener, 
                                                  bool *aAsyncResults) override;
   NS_IMETHOD AddKeywordsToMessages(nsIArray *aMessages, const nsACString& aKeywords) override;
   NS_IMETHOD RemoveKeywordsFromMessages(nsIArray *aMessages, const nsACString& aKeywords) override;
+  NS_IMETHOD GetIncomingServerType(nsACString& serverType) override;
 
 protected:
   virtual ~nsMsgLocalMailFolder();
   nsresult CreateChildFromURI(const nsCString &uri, nsIMsgFolder **folder) override;
   nsresult CopyFolderAcrossServer(nsIMsgFolder *srcFolder, nsIMsgWindow *msgWindow,nsIMsgCopyServiceListener* listener);
 
   nsresult CreateSubFolders(nsIFile *path);
   nsresult GetTrashFolder(nsIMsgFolder** trashFolder);
@@ -217,17 +218,16 @@ protected:
                              bool isMove,
                              int64_t totalMsgSize);
 
   // copy multiple messages at a time from this folder
   nsresult CopyMessagesTo(nsIArray *messages, nsTArray<nsMsgKey> &keyArray,
                                        nsIMsgWindow *aMsgWindow,
                                        nsIMsgFolder *dstFolder,
                                        bool isMove);
-  virtual void GetIncomingServerType(nsCString& serverType) override;
   nsresult InitCopyState(nsISupports* aSupport, nsIArray* messages,
                          bool isMove, nsIMsgCopyServiceListener* listener, nsIMsgWindow *msgWindow, bool isMoveFolder, bool allowUndo);
   nsresult InitCopyMsgHdrAndFileStream();
   // preserve message metadata when moving or copying messages
   void CopyPropertiesToMsgHdr(nsIMsgDBHdr *destHdr, nsIMsgDBHdr *srcHdr, bool isMove);
   virtual nsresult CreateBaseMessageURI(const nsACString& aURI) override;
   nsresult ChangeKeywordForMessages(nsIArray *aMessages, const nsACString& aKeyword, bool add);
   bool GetDeleteFromServerOnMove();
--- a/mailnews/news/src/nsNewsFolder.cpp
+++ b/mailnews/news/src/nsNewsFolder.cpp
@@ -1884,8 +1884,16 @@ nsMsgNewsFolder::OnStopRunningUrl(nsIURI
  if (m_tempMessageStream)
   {
     m_tempMessageStream->Close();
     m_tempMessageStream = nullptr;
   }
   m_downloadingMultipleMessages = false;
   return nsMsgDBFolder::OnStopRunningUrl(aUrl, aExitCode);
 }
+
+NS_IMETHODIMP
+nsMsgNewsFolder::GetIncomingServerType(nsACString& serverType)
+{
+  serverType.AssignLiteral("nntp");
+  return NS_OK;
+}
+
--- a/mailnews/news/src/nsNewsFolder.h
+++ b/mailnews/news/src/nsNewsFolder.h
@@ -85,16 +85,17 @@ public:
 
   NS_IMETHOD GetFilterList(nsIMsgWindow *aMsgWindow,
                            nsIMsgFilterList **aFilterList) override;
   NS_IMETHOD GetEditableFilterList(nsIMsgWindow *aMsgWindow,
                                    nsIMsgFilterList **aFilterList) override;
   NS_IMETHOD SetFilterList(nsIMsgFilterList *aFilterList) override;
   NS_IMETHOD SetEditableFilterList(nsIMsgFilterList *aFilterList) override;
   NS_IMETHOD ApplyRetentionSettings() override;
+  NS_IMETHOD GetIncomingServerType(nsACString& serverType) override;
 
 protected:
   virtual ~nsMsgNewsFolder();
   // helper routine to parse the URI and update member variables
   nsresult AbbreviatePrettyName(nsAString& prettyName, int32_t fullwords);
   nsresult ParseFolder(nsIFile *path);
   nsresult CreateSubFolders(nsIFile *path);
   nsresult AddDirectorySeparator(nsIFile *path);
@@ -104,20 +105,16 @@ protected:
 
   nsresult LoadNewsrcFileAndCreateNewsgroups();
   int32_t RememberLine(const nsACString& line);
   nsresult RememberUnsubscribedGroup(const nsACString& newsgroup, const nsACString& setStr);
   nsresult ForgetLine(void);
   nsresult GetNewsMessages(nsIMsgWindow *aMsgWindow, bool getOld, nsIUrlListener *aListener);
 
   int32_t HandleNewsrcLine(const char * line, uint32_t line_size);
-  virtual void GetIncomingServerType(nsCString& serverType) override
-  {
-    serverType.AssignLiteral("nntp");
-  }
   virtual nsresult CreateBaseMessageURI(const nsACString& aURI) override;
 
 protected:
   int64_t mExpungedBytes;
   bool mGettingNews;
   bool mInitialized;
   bool m_downloadMessageForOfflineUse;
   bool m_downloadingMultipleMessages;