add forward inline filter action, r=rkent, sr=standard8, bug 312025
authorDavid Bienvenu <bienvenu@nventure.com>
Wed, 20 Jan 2010 14:15:44 -0800
changeset 4731 b80ba3cbee79c2cee3ad4063b5696215ea473adb
parent 4730 d48a8dbd8fcc8c4a0a6b59634bdbb56262242cd4
child 4732 28ce2a63f2077aa0e056561cd71ae516e9cf0af4
push idunknown
push userunknown
push dateunknown
reviewersrkent, standard8, bug
bugs312025
add forward inline filter action, r=rkent, sr=standard8, bug 312025
mailnews/base/search/src/nsMsgFilterService.cpp
mailnews/compose/public/nsIMsgComposeService.idl
mailnews/compose/src/nsMsgComposeService.cpp
mailnews/compose/src/nsMsgComposeService.h
mailnews/imap/src/nsImapMailFolder.cpp
mailnews/local/src/nsParseMailbox.cpp
mailnews/mime/public/nsIMimeStreamConverter.idl
mailnews/mime/src/mimedrft.cpp
mailnews/mime/src/mimemoz2.h
mailnews/mime/src/nsStreamConverter.cpp
mailnews/mime/src/nsStreamConverter.h
--- a/mailnews/base/search/src/nsMsgFilterService.cpp
+++ b/mailnews/base/search/src/nsMsgFilterService.cpp
@@ -664,33 +664,32 @@ nsresult nsMsgFilterAfterTheFact::ApplyF
         junkScoreStr.AppendInt(junkScore);
         m_curFolder->SetJunkScoreForMessages(m_searchHitHdrs, junkScoreStr);
         break;
       }
       case nsMsgFilterAction::Forward:
         {
           nsCString forwardTo;
           filterAction->GetStrValue(forwardTo);
-          nsCOMPtr <nsIMsgIncomingServer> server;
+          nsCOMPtr<nsIMsgIncomingServer> server;
           rv = m_curFolder->GetServer(getter_AddRefs(server));
           NS_ENSURE_SUCCESS(rv, rv);
           if (!forwardTo.IsEmpty())
           {
-            nsCOMPtr <nsIMsgComposeService> compService = do_GetService (NS_MSGCOMPOSESERVICE_CONTRACTID) ;
-            if (compService)
+            nsCOMPtr<nsIMsgComposeService> compService = 
+              do_GetService(NS_MSGCOMPOSESERVICE_CONTRACTID, &rv);
+            NS_ENSURE_SUCCESS(rv, rv);
+            for (PRUint32 msgIndex = 0; msgIndex < m_searchHits.Length(); msgIndex++)
             {
-              for (PRUint32 msgIndex = 0; msgIndex < m_searchHits.Length(); msgIndex++)
-              {
-                nsCOMPtr <nsIMsgDBHdr> msgHdr;
-                m_searchHitHdrs->QueryElementAt(msgIndex, NS_GET_IID(nsIMsgDBHdr), getter_AddRefs(msgHdr));
-                if (msgHdr)
-                {
-                  rv = compService->ForwardMessage(NS_ConvertASCIItoUTF16(forwardTo), msgHdr, m_msgWindow, server);
-                }
-              }
+              nsCOMPtr<nsIMsgDBHdr> msgHdr(do_QueryElementAt(m_searchHitHdrs,
+                                           msgIndex));
+              if (msgHdr)
+                rv = compService->ForwardMessage(NS_ConvertASCIItoUTF16(forwardTo),
+                                                 msgHdr, m_msgWindow, server,
+                                                 nsIMsgComposeService::kForwardAsDefault);
             }
           }
         }
         break;
       case nsMsgFilterAction::Reply:
         {
           nsCString replyTemplateUri;
           filterAction->GetStrValue(replyTemplateUri);
--- a/mailnews/compose/public/nsIMsgComposeService.idl
+++ b/mailnews/compose/public/nsIMsgComposeService.idl
@@ -42,17 +42,17 @@
 
 interface nsIURI;
 interface nsIDOMWindowInternal;
 interface nsIMsgWindow;
 interface nsIMsgIdentity;
 interface nsIMsgIncomingServer;
 interface nsIMsgDBHdr;
 
-[scriptable, uuid(ce5f77c8-f278-4ec7-b8dd-ea9dc84af137)]
+[scriptable, uuid(dbf4b3a7-dc38-4362-a620-ff5d22b3777c)]
 interface nsIMsgComposeService : nsISupports {
 
   /* we need a msg window because when we forward inline we may need progress */
   void OpenComposeWindow(in string msgComposeWindowURL,
                          in nsIMsgDBHdr msgHdr,
                          in string originalMsgURI,
                          in MSG_ComposeType type, 
                          in MSG_ComposeFormat format,
@@ -92,24 +92,38 @@ interface nsIMsgComposeService : nsISupp
 
   /** 
    * given a mailto url, parse the attributes and turn them into a nsIMsgComposeParams object
    * @return nsIMsgComposeParams which corresponds to the passed in mailto url
    */
   nsIMsgComposeParams getParamsForMailto(in nsIURI aURI); 
 
   /**
+   * @{
+   * These constants control how to forward messages in forwardMessage.
+   * kForwardAsDefault uses value of pref "mail.forward_message_mode".
+   */
+  const unsigned long kForwardAsDefault = 0;
+  const unsigned long kForwardAsAttachment = 1;
+  const unsigned long kForwardInline = 2;
+  /** @} */
+
+  /**
    * Allow filters to automatically forward a message to the given address(es).
    * @param forwardTo the address(es) to forward to
    * @param msgHdr the header of the message being replied to
    * @param msgWindow message window to use
    * @param server server to use for determining which account to send from
+   * @param aForwardType - How to forward the message one of 3 values:
+   *                       kForwardAsDefault, kForwardInline, or
+   *                       kForwardAsAttachment.
    */
   void forwardMessage(in AString forwardTo, in nsIMsgDBHdr msgHdr,
-                      in nsIMsgWindow msgWindow, in nsIMsgIncomingServer server);
+                      in nsIMsgWindow msgWindow, in nsIMsgIncomingServer server,
+                      in unsigned long aForwardType);
 
   /**
    * Allow filters to automatically reply to a message. The reply message is
    * based on the given template.
    * @param msgHdr the header of the message being replied to
    * @param templateUri uri of the template to base ther reply on
    * @param msgWindow message window to use
    * @param server server to use for determining which account to send from
--- a/mailnews/compose/src/nsMsgComposeService.cpp
+++ b/mailnews/compose/src/nsMsgComposeService.cpp
@@ -563,17 +563,18 @@ nsMsgComposeService::OpenComposeWindow(c
     nsCAutoString uriToOpen(originalMsgURI);
     uriToOpen += (uriToOpen.FindChar('?') == kNotFound) ? "?" : "&";
     uriToOpen.Append("fetchCompleteMessage=true");
     if (type == nsIMsgCompType::Redirect)
       uriToOpen.Append("&redirect=true");
 
     return LoadDraftOrTemplate(uriToOpen, type == nsIMsgCompType::ForwardInline || type == nsIMsgCompType::Draft ?
                                nsMimeOutput::nsMimeMessageDraftOrTemplate : nsMimeOutput::nsMimeMessageEditorTemplate,
-                               identity, originalMsgURI, origMsgHdr, type == nsIMsgCompType::ForwardInline, format, aMsgWindow);
+                               identity, originalMsgURI, origMsgHdr, type == nsIMsgCompType::ForwardInline,
+                               format == nsIMsgCompFormat::OppositeOfDefault, aMsgWindow);
   }
 
   nsCOMPtr<nsIMsgComposeParams> pMsgComposeParams (do_CreateInstance(NS_MSGCOMPOSEPARAMS_CONTRACTID, &rv));
   if (NS_SUCCEEDED(rv) && pMsgComposeParams)
   {
     nsCOMPtr<nsIMsgCompFields> pMsgCompFields (do_CreateInstance(NS_MSGCOMPFIELDS_CONTRACTID, &rv));
     if (NS_SUCCEEDED(rv) && pMsgCompFields)
     {
@@ -1207,66 +1208,83 @@ NS_IMETHODIMP nsMsgComposeService::Reply
   if (!folder)
     return NS_ERROR_NULL_POINTER;
 
   // We're sending a new message. Conceptually it's a reply though, so mark the
   // original message as replied.
   return folder->AddMessageDispositionState(aMsgHdr, nsIMsgFolder::nsMsgDispositionState_Replied);
 }
 
-NS_IMETHODIMP nsMsgComposeService::ForwardMessage(const nsAString &forwardTo, nsIMsgDBHdr *aMsgHdr,
-                                             nsIMsgWindow *aMsgWindow, nsIMsgIncomingServer *aServer)
+NS_IMETHODIMP
+nsMsgComposeService::ForwardMessage(const nsAString &forwardTo,
+                                    nsIMsgDBHdr *aMsgHdr,
+                                    nsIMsgWindow *aMsgWindow,
+                                    nsIMsgIncomingServer *aServer,
+                                    PRUint32 aForwardType)
 {
   NS_ENSURE_ARG_POINTER(aMsgHdr);
 
   nsresult rv;
+  if (aForwardType == nsIMsgComposeService::kForwardAsDefault)
+  {
+    PRInt32 forwardPref = 0;
+    nsCOMPtr<nsIPrefBranch> prefBranch(do_GetService(NS_PREFSERVICE_CONTRACTID, &rv));
+    NS_ENSURE_SUCCESS(rv, rv);
+    prefBranch->GetIntPref("mail.forward_message_mode", &forwardPref);
+    // 0=default as attachment 2=forward as inline with attachments,
+    // (obsolete 4.x value)1=forward as quoted (mapped to 2 in mozilla)
+    aForwardType = forwardPref == 0 ? nsIMsgComposeService::kForwardAsAttachment :
+                                      nsIMsgComposeService::kForwardInline;
+  }
+  nsCString msgUri;
+
+  nsCOMPtr<nsIMsgFolder> folder;
+  aMsgHdr->GetFolder(getter_AddRefs(folder));
+  if (!folder)
+    return NS_ERROR_NULL_POINTER;
+  folder->GetUriForMsg(aMsgHdr, msgUri);
+
+  // get the MsgIdentity for the above key using AccountManager
+  nsCOMPtr<nsIMsgAccountManager> accountManager = 
+    do_GetService (NS_MSGACCOUNTMANAGER_CONTRACTID, &rv);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  nsCOMPtr<nsIMsgAccount> account;
+  nsCOMPtr<nsIMsgIdentity> identity;
+
+  rv = accountManager->FindAccountForServer(aServer, getter_AddRefs(account));
+  NS_ENSURE_SUCCESS(rv, rv);
+  rv = account->GetDefaultIdentity(getter_AddRefs(identity));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  if (aForwardType == nsIMsgComposeService::kForwardInline)
+    return RunMessageThroughMimeDraft(msgUri,
+                                      nsMimeOutput::nsMimeMessageDraftOrTemplate,
+                                      identity,
+                                      msgUri.get(), aMsgHdr,
+                                      PR_TRUE, forwardTo,
+                                      PR_FALSE, aMsgWindow);
+
   nsCOMPtr<nsIDOMWindowInternal> parentWindow;
   if (aMsgWindow)
   {
     nsCOMPtr<nsIDocShell> docShell;
     rv = aMsgWindow->GetRootDocShell(getter_AddRefs(docShell));
     NS_ENSURE_SUCCESS(rv, rv);
     parentWindow = do_GetInterface(docShell);
     NS_ENSURE_TRUE(parentWindow, NS_ERROR_FAILURE);
   }
-  if ( NS_FAILED(rv) ) return rv ;
-  // get the MsgIdentity for the above key using AccountManager
-  nsCOMPtr <nsIMsgAccountManager> accountManager = do_GetService (NS_MSGACCOUNTMANAGER_CONTRACTID) ;
-  if (NS_FAILED(rv) || (!accountManager) ) return rv ;
-
-  nsCOMPtr <nsIMsgAccount> account;
-  nsCOMPtr <nsIMsgIdentity> identity;
-
-  rv = accountManager->FindAccountForServer(aServer, getter_AddRefs(account));
-  NS_ENSURE_SUCCESS(rv, rv);
-  account->GetDefaultIdentity(getter_AddRefs(identity));
-  NS_ENSURE_SUCCESS(rv, rv);
-
   // create the compose params object
   nsCOMPtr<nsIMsgComposeParams> pMsgComposeParams (do_CreateInstance(NS_MSGCOMPOSEPARAMS_CONTRACTID, &rv));
-  if (NS_FAILED(rv) || (!pMsgComposeParams) ) return rv ;
-  nsCOMPtr<nsIMsgCompFields> compFields = do_CreateInstance(NS_MSGCOMPFIELDS_CONTRACTID, &rv) ;
+  NS_ENSURE_SUCCESS(rv, rv);
+  nsCOMPtr<nsIMsgCompFields> compFields = do_CreateInstance(NS_MSGCOMPFIELDS_CONTRACTID, &rv);
 
   compFields->SetTo(forwardTo);
-  nsCString msgUri;
-  PRInt32 forwardType = 0;
-
-  nsCOMPtr<nsIPrefBranch> prefBranch(do_GetService(NS_PREFSERVICE_CONTRACTID));
-  if (prefBranch)
-    prefBranch->GetIntPref("mail.forward_message_mode", &forwardType);
-
-  nsCOMPtr<nsIMsgFolder> folder;
-  aMsgHdr->GetFolder(getter_AddRefs(folder));
-  if (!folder)
-    return NS_ERROR_NULL_POINTER;
-  folder->GetUriForMsg(aMsgHdr, msgUri);
   // populate the compose params
-  // right now, forward inline won't work, since that requires opening a compose window,
-  // and would require major whackage of the compose code.
-  pMsgComposeParams->SetType(/* forwardType ? nsIMsgCompType::ForwardInline : */nsIMsgCompType::ForwardAsAttachment);
+  pMsgComposeParams->SetType(nsIMsgCompType::ForwardAsAttachment);
   pMsgComposeParams->SetFormat(nsIMsgCompFormat::Default);
   pMsgComposeParams->SetIdentity(identity);
   pMsgComposeParams->SetComposeFields(compFields);
   pMsgComposeParams->SetOriginalMsgURI(msgUri.get());
   // create the nsIMsgCompose object to send the object
   nsCOMPtr<nsIMsgCompose> pMsgCompose (do_CreateInstance(NS_MSGCOMPOSE_CONTRACTID, &rv));
   NS_ENSURE_SUCCESS(rv,rv);
 
@@ -1512,33 +1530,76 @@ nsMsgComposeService::GetMsgComposeForWin
  * LoadDraftOrTemplate
  *   Helper routine used to run msgURI through libmime in order to fetch the contents for a
  *   draft or template.
  */
 nsresult
 nsMsgComposeService::LoadDraftOrTemplate(const nsACString& aMsgURI, nsMimeOutputType aOutType,
                                          nsIMsgIdentity * aIdentity, const char * aOriginalMsgURI,
                                          nsIMsgDBHdr * aOrigMsgHdr,
-                                         PRBool aAddInlineHeaders,
-                                         MSG_ComposeFormat format,
+                                         PRBool aForwardInline,
+                                         PRBool overrideComposeFormat,
                                          nsIMsgWindow *aMsgWindow)
 {
-  nsresult rv;
+  return RunMessageThroughMimeDraft(aMsgURI, aOutType, aIdentity,
+                                    aOriginalMsgURI, aOrigMsgHdr,
+                                    aForwardInline, EmptyString(),
+                                    overrideComposeFormat, aMsgWindow);
+}
+
+/**
+ * Run the aMsgURI message through libmime. We set various attributes of the 
+ * nsIMimeStreamConverter so mimedrft.cpp will know what to do with the message
+ * when its done streaming. Usually that will be opening a compose window
+ * with the contents of the message, but if forwardTo is non-empty, mimedrft.cpp
+ * will forward the contents directly.
+ *
+ * @param aMsgURI URI to stream, which is the msgUri + any extra terms, e.g.,
+ *                "redirect=true".
+ * @param aOutType  nsMimeOutput::nsMimeMessageDraftOrTemplate or
+ *                  nsMimeOutput::nsMimeMessageEditorTemplate
+ * @param aIdentity identity to use for the new message
+ * @param aOriginalMsgURI msgURI w/o any extra terms
+ * @param aOrigMsgHdr nsIMsgDBHdr corresponding to aOriginalMsgURI
+ * @param aForwardInline true if doing a forward inline
+ * @param aForwardTo  e-mail address to forward msg to. This is used for
+ *                     forward inline message filter actions.
+ * @param aOverrideComposeFormat True if the user had shift key down when
+                                 doing a command that opens the compose window,
+ *                               which means we switch the compose window used
+ *                               from the default.
+ * @param aMsgWindow msgWindow to pass into DisplayMessage.
+ */
+nsresult
+nsMsgComposeService::RunMessageThroughMimeDraft(
+            const nsACString& aMsgURI, nsMimeOutputType aOutType,
+            nsIMsgIdentity * aIdentity, const char * aOriginalMsgURI,
+            nsIMsgDBHdr * aOrigMsgHdr,
+            PRBool aForwardInline,
+            const nsAString &aForwardTo,
+            PRBool aOverrideComposeFormat,
+            nsIMsgWindow *aMsgWindow)
+{
   nsCOMPtr <nsIMsgMessageService> messageService;
-  rv = GetMessageServiceFromURI(aMsgURI, getter_AddRefs(messageService));
+  nsresult rv = GetMessageServiceFromURI(aMsgURI, getter_AddRefs(messageService));
   NS_ENSURE_SUCCESS(rv, rv);
 
-  // Now, we can create a mime parser (nsIStreamConverter)!
+  // Create a mime parser (nsIMimeStreamConverter)to do the conversion.
   nsCOMPtr<nsIMimeStreamConverter> mimeConverter =
     do_CreateInstance(NS_MAILNEWS_MIME_STREAM_CONVERTER_CONTRACTID, &rv);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  mimeConverter->SetMimeOutputType(aOutType);  // Set the type of output for libmime
-  mimeConverter->SetForwardInline(aAddInlineHeaders);
-  mimeConverter->SetOverrideComposeFormat(format == nsIMsgCompFormat::OppositeOfDefault);
+  mimeConverter->SetMimeOutputType(aOutType); // Set the type of output for libmime
+  mimeConverter->SetForwardInline(aForwardInline);
+  if (!aForwardTo.IsEmpty())
+  {
+    mimeConverter->SetForwardInlineFilter(PR_TRUE);
+    mimeConverter->SetForwardToAddress(aForwardTo);
+  }
+  mimeConverter->SetOverrideComposeFormat(aOverrideComposeFormat);
   mimeConverter->SetIdentity(aIdentity);
   mimeConverter->SetOriginalMsgURI(aOriginalMsgURI);
   mimeConverter->SetOrigMsgHdr(aOrigMsgHdr);
 
   nsCOMPtr<nsIURI> url;
   PRBool fileUrl = StringBeginsWith(aMsgURI, NS_LITERAL_CSTRING("file:"));
   if (fileUrl || nsDependentCString(aMsgURI).Find("&type=application/x-message-display") >= 0)
     rv = NS_NewURI(getter_AddRefs(url), aMsgURI);
--- a/mailnews/compose/src/nsMsgComposeService.h
+++ b/mailnews/compose/src/nsMsgComposeService.h
@@ -95,20 +95,30 @@ private:
 
   PRInt32 mMaxRecycledWindows;
   nsMsgCachedWindowInfo *mCachedWindows;
   
   void CloseHiddenCachedWindow(nsIDOMWindowInternal *domWindow);
 
   nsresult LoadDraftOrTemplate(const nsACString& aMsgURI, nsMimeOutputType aOutType, 
                                nsIMsgIdentity * aIdentity, const char * aOriginalMsgURI, 
-                               nsIMsgDBHdr * aOrigMsgHdr, PRBool aAddInlineHeaders,
+                               nsIMsgDBHdr * aOrigMsgHdr, PRBool aForwardInline,
                                MSG_ComposeFormat format,
                                nsIMsgWindow *aMsgWindow);
 
+  nsresult RunMessageThroughMimeDraft(const nsACString& aMsgURI,
+                                      nsMimeOutputType aOutType,
+                                      nsIMsgIdentity * aIdentity,
+                                      const char * aOriginalMsgURI,
+                                      nsIMsgDBHdr * aOrigMsgHdr,
+                                      PRBool aForwardInline,
+                                      const nsAString &forwardTo,
+                                      PRBool overrideComposeFormat,
+                                      nsIMsgWindow *aMsgWindow);
+
   nsresult ShowCachedComposeWindow(nsIDOMWindowInternal *aComposeWindow, PRBool aShow);
 
   // hash table mapping dom windows to nsIMsgCompose objects
   nsInterfaceHashtable<nsISupportsHashKey, nsIWeakReference> mOpenComposeWindows;
 
   // When doing a reply and the settings are enabled, get the HTML of the selected text
   // in the original message window so that it can be quoted instead of the entire message.
   nsresult GetOrigWindowSelection(MSG_ComposeType type, nsIMsgWindow *aMsgWindow, nsACString& aSelHTML);
--- a/mailnews/imap/src/nsImapMailFolder.cpp
+++ b/mailnews/imap/src/nsImapMailFolder.cpp
@@ -3611,24 +3611,27 @@ NS_IMETHODIMP nsImapMailFolder::ApplyFil
             }
           }
         }
         break;
       case nsMsgFilterAction::Forward:
         {
           nsCString forwardTo;
           filterAction->GetStrValue(forwardTo);
-          nsCOMPtr <nsIMsgIncomingServer> server;
+          nsCOMPtr<nsIMsgIncomingServer> server;
           rv = GetServer(getter_AddRefs(server));
           NS_ENSURE_SUCCESS(rv, rv);
           if (!forwardTo.IsEmpty())
           {
-            nsCOMPtr <nsIMsgComposeService> compService = do_GetService (NS_MSGCOMPOSESERVICE_CONTRACTID) ;
-            if (compService)
-              rv = compService->ForwardMessage(NS_ConvertASCIItoUTF16(forwardTo), msgHdr, msgWindow, server);
+            nsCOMPtr<nsIMsgComposeService> compService =
+              do_GetService (NS_MSGCOMPOSESERVICE_CONTRACTID, &rv);
+            NS_ENSURE_SUCCESS(rv, rv);
+            rv = compService->ForwardMessage(NS_ConvertASCIItoUTF16(forwardTo),
+                                             msgHdr, msgWindow, server,
+                                             nsIMsgComposeService::kForwardAsDefault);
           }
         }
         break;
 
       case nsMsgFilterAction::Reply:
         {
           nsCString replyTemplateUri;
           filterAction->GetStrValue(replyTemplateUri);
--- a/mailnews/local/src/nsParseMailbox.cpp
+++ b/mailnews/local/src/nsParseMailbox.cpp
@@ -2268,19 +2268,22 @@ nsresult nsParseNewMailState::ApplyForwa
   {
     if (!m_forwardTo[i]->IsEmpty())
     {
       nsAutoString forwardStr;
       CopyASCIItoUTF16(*(m_forwardTo[i]), forwardStr);
       rv = m_rootFolder->GetServer(getter_AddRefs(server));
       NS_ENSURE_SUCCESS(rv, rv);
       {
-        nsCOMPtr <nsIMsgComposeService> compService = do_GetService (NS_MSGCOMPOSESERVICE_CONTRACTID) ;
-        if (compService)
-          rv = compService->ForwardMessage(forwardStr, m_msgToForwardOrReply, msgWindow, server);
+        nsCOMPtr<nsIMsgComposeService> compService =
+          do_GetService (NS_MSGCOMPOSESERVICE_CONTRACTID, &rv);
+        NS_ENSURE_SUCCESS(rv, rv);
+        rv = compService->ForwardMessage(forwardStr, m_msgToForwardOrReply,
+                                         msgWindow, server,
+                                         nsIMsgComposeService::kForwardAsDefault);
       }
     }
   }
   m_forwardTo.Clear();
 
   for (i = 0; i < m_replyTemplateUri.Count(); i++)
   {
     if (!m_replyTemplateUri[i]->IsEmpty())
--- a/mailnews/mime/public/nsIMimeStreamConverter.idl
+++ b/mailnews/mime/public/nsIMimeStreamConverter.idl
@@ -70,17 +70,17 @@ interface nsIMimeStreamConverterListener
       void onHeadersReady(in nsIMimeHeaders headers);
 };
 
 /**
  * This interface contains mailnews mime specific information for stream
  * converters. Most of the code is just stuff that has been moved out
  * of nsIStreamConverter.idl to make it more generic.
  */
-[scriptable, uuid(ed861e40-6901-4bb0-b9ec-7a8e7a79bb0e)]
+[scriptable, uuid(d894c833-29c5-495b-880c-9a9f847bfdc9)]
 interface nsIMimeStreamConverter : nsISupports {
 
   /**
    * Set the desired mime output type on the converer.
    */
   void SetMimeOutputType(in nsMimeOutputType aType);
 
   void GetMimeOutputType(out nsMimeOutputType aOutFormat);
@@ -92,21 +92,31 @@ interface nsIMimeStreamConverter : nsISu
   void SetStreamURI(in nsIURI aURI);
 
   /**
    * Used to extract headers while parsing a message.
    */
   void SetMimeHeadersListener(in nsIMimeStreamConverterListener listener, in nsMimeOutputType aType);
 
   /**
-   * This is used for forward inline.
+   * This is used for forward inline, both as a filter action, and from the UI.
    */
-  attribute PRBool forwardInline;
+  attribute boolean forwardInline;
 
   /**
+   * This is used for a forward inline filter action. When streaming is done,
+   * we won't open a compose window with the editor contents.
+   */
+  attribute boolean forwardInlineFilter;
+
+  /**
+   * Address for the forward inline filter to forward the message to.
+   */
+  attribute AString forwardToAddress;
+  /**
    * Use the opposite compose format, used for forward inline.
    */
   attribute PRBool overrideComposeFormat;
 
   /**
    * This is used for OpenDraft, OpenEditorTemplate and Forward inline (which use OpenDraft)
    */
   attribute nsIMsgIdentity identity;
--- a/mailnews/mime/src/mimedrft.cpp
+++ b/mailnews/mime/src/mimedrft.cpp
@@ -176,32 +176,30 @@ mime_dump_attachments ( nsMsgAttachmentD
     printf("Mac Type          : %s\n", tmp->x_mac_type ? tmp->x_mac_type : "nsnull");
     printf("Mac Creator       : %s\n", tmp->x_mac_creator ? tmp->x_mac_creator : "nsnull");
     i++;
     tmp++;
   }
 }
 #endif
 
-nsresult
-CreateTheComposeWindow(nsIMsgCompFields *   compFields,
-                       nsMsgAttachmentData *attachmentList,
-                       MSG_ComposeType      composeType,
-                       MSG_ComposeFormat    composeFormat,
-                       nsIMsgIdentity *     identity,
-                       const char *         originalMsgURI,
-                       nsIMsgDBHdr *        origMsgHdr
-                       )
+nsresult CreateComposeParams(nsCOMPtr<nsIMsgComposeParams> &pMsgComposeParams,
+                             nsIMsgCompFields * compFields,
+                             nsMsgAttachmentData *attachmentList,
+                             MSG_ComposeType composeType,
+                             MSG_ComposeFormat composeFormat,
+                             nsIMsgIdentity * identity,
+                             const char *originalMsgURI,
+                             nsIMsgDBHdr *origMsgHdr)
 {
-  nsresult            rv;
-
 #ifdef NS_DEBUG
   mime_dump_attachments ( attachmentList );
 #endif
 
+  nsresult rv;
   nsMsgAttachmentData *curAttachment = attachmentList;
   if (curAttachment)
   {
     nsCAutoString spec;
 
     while (curAttachment && curAttachment->real_name) //JFD: Why do we check for real_name?
     {
       rv = curAttachment->url->GetSpec(spec);
@@ -222,49 +220,101 @@ CreateTheComposeWindow(nsIMsgCompFields 
           attachment->SetMacCreator(curAttachment->x_mac_creator);
           compFields->AddAttachment(attachment);
         }
       }
       curAttachment++;
     }
   }
 
-  nsCOMPtr<nsIMsgComposeService> msgComposeService =
-           do_GetService(kCMsgComposeServiceCID, &rv);
-  if ((NS_FAILED(rv)) || (!msgComposeService))
-    return rv;
-
   MSG_ComposeFormat format = composeFormat; // Format to actually use.
   if (identity && composeType == nsIMsgCompType::ForwardInline)
   {
     PRBool composeHtml = PR_FALSE;
     identity->GetComposeHtml(&composeHtml);
     if (composeHtml)
       format = (composeFormat == nsIMsgCompFormat::OppositeOfDefault) ?
                  nsIMsgCompFormat::PlainText : nsIMsgCompFormat::HTML;
     else
       format = (composeFormat == nsIMsgCompFormat::OppositeOfDefault) ?
                  nsIMsgCompFormat::HTML : nsIMsgCompFormat::PlainText;
   }
 
-  nsCOMPtr<nsIMsgComposeParams> pMsgComposeParams (do_CreateInstance(NS_MSGCOMPOSEPARAMS_CONTRACTID, &rv));
-  if (NS_SUCCEEDED(rv) && pMsgComposeParams)
-  {
-    pMsgComposeParams->SetType(composeType);
-    pMsgComposeParams->SetFormat(format);
-    pMsgComposeParams->SetIdentity(identity);
-    pMsgComposeParams->SetComposeFields(compFields);
-    if (originalMsgURI)
-      pMsgComposeParams->SetOriginalMsgURI(originalMsgURI);
-    if (origMsgHdr)
-      pMsgComposeParams->SetOrigMsgHdr(origMsgHdr);
+  pMsgComposeParams = do_CreateInstance(NS_MSGCOMPOSEPARAMS_CONTRACTID, &rv);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  pMsgComposeParams->SetType(composeType);
+  pMsgComposeParams->SetFormat(format);
+  pMsgComposeParams->SetIdentity(identity);
+  pMsgComposeParams->SetComposeFields(compFields);
+  if (originalMsgURI)
+    pMsgComposeParams->SetOriginalMsgURI(originalMsgURI);
+  if (origMsgHdr)
+    pMsgComposeParams->SetOrigMsgHdr(origMsgHdr);
+  return NS_OK;
+}
+
+nsresult
+CreateTheComposeWindow(nsIMsgCompFields *   compFields,
+                       nsMsgAttachmentData *attachmentList,
+                       MSG_ComposeType      composeType,
+                       MSG_ComposeFormat    composeFormat,
+                       nsIMsgIdentity *     identity,
+                       const char *         originalMsgURI,
+                       nsIMsgDBHdr *        origMsgHdr
+                       )
+{
+  nsCOMPtr<nsIMsgComposeParams> pMsgComposeParams;
+  nsresult rv = CreateComposeParams(pMsgComposeParams, compFields,
+                       attachmentList,
+                       composeType,
+                       composeFormat,
+                       identity,
+                       originalMsgURI,
+                       origMsgHdr);
+  NS_ENSURE_SUCCESS(rv, rv);
 
-    rv = msgComposeService->OpenComposeWindowWithParams(nsnull /* default chrome */, pMsgComposeParams);
-  }
-  return rv;
+  nsCOMPtr<nsIMsgComposeService> msgComposeService =
+           do_GetService(kCMsgComposeServiceCID, &rv);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  return msgComposeService->OpenComposeWindowWithParams(nsnull /* default chrome */, pMsgComposeParams);
+}
+
+nsresult
+SendTheMessage(nsIMsgCompFields *   compFields,
+               nsMsgAttachmentData *attachmentList,
+               MSG_ComposeType      composeType,
+               MSG_ComposeFormat    composeFormat,
+               nsIMsgIdentity *     identity,
+               const char *         originalMsgURI,
+               nsIMsgDBHdr *        origMsgHdr)
+{
+  nsCOMPtr<nsIMsgComposeParams> pMsgComposeParams;
+  nsresult rv = CreateComposeParams(pMsgComposeParams, compFields,
+                       attachmentList,
+                       composeType,
+                       composeFormat,
+                       identity,
+                       originalMsgURI,
+                       origMsgHdr);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  nsCOMPtr<nsIMsgComposeService> msgComposeService =
+           do_GetService(kCMsgComposeServiceCID, &rv);
+  NS_ENSURE_SUCCESS(rv, rv);
+  // create the nsIMsgCompose object to send the object
+  nsCOMPtr<nsIMsgCompose> pMsgCompose (do_CreateInstance(NS_MSGCOMPOSE_CONTRACTID, &rv));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  /** initialize nsIMsgCompose, Send the message, wait for send completion response **/
+  rv = pMsgCompose->Initialize(nsnull, pMsgComposeParams) ;
+  NS_ENSURE_SUCCESS(rv,rv);
+
+  return pMsgCompose->SendMsg(nsIMsgSend::nsMsgDeliverNow, identity, nsnull, nsnull, nsnull) ;
 }
 
 nsresult
 CreateCompositionFields(const char        *from,
                         const char        *reply_to,
                         const char        *to,
                         const char        *cc,
                         const char        *bcc,
@@ -1458,24 +1508,25 @@ mime_parse_stream_complete (nsMIMESessio
               char *escapedBody = MsgEscapeHTML(body);
               if (escapedBody)
               {
                 PR_Free(body);
                 body = escapedBody;
                 bodyLen = strlen(body);
               }
 
-              PRUint32 newbodylen = bodyLen + 12; //+11 chars for <pre> & </pre> tags
+               //+13 chars for <pre> & </pre> tags and CRLF
+              PRUint32 newbodylen = bodyLen + 14;
               char* newbody = (char *)PR_MALLOC (newbodylen);
               if (newbody)
               {
                 *newbody = 0;
                 PL_strcatn(newbody, newbodylen, "<PRE>");
                 PL_strcatn(newbody, newbodylen, body);
-                PL_strcatn(newbody, newbodylen, "</PRE>");
+                PL_strcatn(newbody, newbodylen, "</PRE>"CRLF);
                 PR_Free(body);
                 body = newbody;
               }
             }
             // Body is now HTML, set the format too (so headers are inserted in
             // correct format).
             composeFormat = nsIMsgCompFormat::HTML;
           }
@@ -1524,17 +1575,25 @@ mime_parse_stream_complete (nsMIMESessio
       else
       {
         if (mdd->forwardInline)
         {
           if (convertToPlainText)
             fields->ConvertBodyToPlainText();
           if (mdd->overrideComposeFormat)
             composeFormat = nsIMsgCompFormat::OppositeOfDefault;
-          CreateTheComposeWindow(fields, newAttachData, nsIMsgCompType::ForwardInline, composeFormat, mdd->identity, mdd->originalMsgURI, mdd->origMsgHdr);
+          if (mdd->forwardInlineFilter)
+          {
+            fields->SetTo(mdd->forwardToAddress);
+            SendTheMessage(fields, newAttachData, nsIMsgCompType::ForwardInline,
+                           composeFormat, mdd->identity, mdd->originalMsgURI,
+                           mdd->origMsgHdr);
+          }
+          else
+            CreateTheComposeWindow(fields, newAttachData, nsIMsgCompType::ForwardInline, composeFormat, mdd->identity, mdd->originalMsgURI, mdd->origMsgHdr);
         }
         else
         {
           fields->SetDraftId(mdd->url_name);
           CreateTheComposeWindow(fields, newAttachData, nsIMsgCompType::Draft, composeFormat, mdd->identity, mdd->originalMsgURI, mdd->origMsgHdr);
         }
       }
     }
@@ -2035,16 +2094,18 @@ mime_bridge_create_draft_stream(
       urlString.Cut(typeIndex, sizeof("&type=application/x-message-display") - 1);
 
     mdd->url_name = ToNewCString(urlString);
     if (!(mdd->url_name))
       goto FAIL;
   }
 
   newPluginObj2->GetForwardInline(&mdd->forwardInline);
+  newPluginObj2->GetForwardInlineFilter(&mdd->forwardInlineFilter);
+  newPluginObj2->GetForwardToAddress(mdd->forwardToAddress);
   newPluginObj2->GetOverrideComposeFormat(&mdd->overrideComposeFormat);
   newPluginObj2->GetIdentity(getter_AddRefs(mdd->identity));
   newPluginObj2->GetOriginalMsgURI(&mdd->originalMsgURI);
   newPluginObj2->GetOrigMsgHdr(getter_AddRefs(mdd->origMsgHdr));
   mdd->format_out = format_out;
   mdd->options = new  MimeDisplayOptions ;
   if (!mdd->options)
     goto FAIL;
--- a/mailnews/mime/src/mimemoz2.h
+++ b/mailnews/mime/src/mimemoz2.h
@@ -151,17 +151,19 @@ struct mime_draft_data
   nsMsgAttachedFile   *curAttachment;       // temp
 
   nsCOMPtr <nsILocalFile> tmpFile;
   nsCOMPtr <nsIOutputStream> tmpFileStream;      // output file handle
 
   MimeDecoderData     *decoder_data;
   char                *mailcharset;        // get it from CHARSET of Content-Type
   PRBool              forwardInline;
+  PRBool              forwardInlineFilter;
   PRBool              overrideComposeFormat; // Override compose format (for forward inline).
+  nsString            forwardToAddress;
   nsCOMPtr<nsIMsgIdentity>      identity;
   char                *originalMsgURI;     // the original URI of the message we are currently processing
   nsCOMPtr<nsIMsgDBHdr>         origMsgHdr;
 };
 
 ////////////////////////////////////////////////////////////////
 // Bridge routines for legacy mime code
 ////////////////////////////////////////////////////////////////
--- a/mailnews/mime/src/nsStreamConverter.cpp
+++ b/mailnews/mime/src/nsStreamConverter.cpp
@@ -521,20 +521,21 @@ nsStreamConverter::InternalCleanup(void)
 
 /*
  * Inherited methods for nsMimeConverter
  */
 nsStreamConverter::nsStreamConverter()
 {
   // Init member variables...
   mWrapperOutput = PR_FALSE;
-  mBridgeStream = NULL;
+  mBridgeStream = nsnull;
   mOutputFormat = "text/html";
   mAlreadyKnowOutputType = PR_FALSE;
   mForwardInline = PR_FALSE;
+  mForwardInlineFilter = PR_FALSE;
   mOverrideComposeFormat = PR_FALSE;
 
   mPendingRequest = nsnull;
   mPendingContext = nsnull;
 }
 
 nsStreamConverter::~nsStreamConverter()
 {
@@ -782,19 +783,33 @@ nsresult
 nsStreamConverter::SetMimeHeadersListener(nsIMimeStreamConverterListener *listener, nsMimeOutputType aType)
 {
    mMimeStreamConverterListener = listener;
    bridge_set_mime_stream_converter_listener((nsMIMESession *)mBridgeStream, listener, aType);
    return NS_OK;
 }
 
 NS_IMETHODIMP
-nsStreamConverter::SetForwardInline(PRBool forwardInline)
+nsStreamConverter::SetForwardInline(PRBool aForwardInline)
+{
+  mForwardInline = aForwardInline;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsStreamConverter::GetForwardToAddress(nsAString &aAddress)
 {
-  mForwardInline = forwardInline;
+  aAddress = mForwardToAddress;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsStreamConverter::SetForwardToAddress(const nsAString &aAddress)
+{
+  mForwardToAddress = aAddress;
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsStreamConverter::GetOverrideComposeFormat(PRBool *aResult)
 {
   if (!aResult)
     return NS_ERROR_NULL_POINTER;
@@ -805,20 +820,35 @@ nsStreamConverter::GetOverrideComposeFor
 NS_IMETHODIMP
 nsStreamConverter::SetOverrideComposeFormat(PRBool aOverrideComposeFormat)
 {
   mOverrideComposeFormat = aOverrideComposeFormat;
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsStreamConverter::GetForwardInline(PRBool *result)
+nsStreamConverter::GetForwardInline(PRBool *aResult)
+{
+  NS_ENSURE_ARG_POINTER(aResult);
+  *aResult = mForwardInline;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsStreamConverter::GetForwardInlineFilter(PRBool *aResult)
 {
-  if (!result) return NS_ERROR_NULL_POINTER;
-  *result = mForwardInline;
+  NS_ENSURE_ARG_POINTER(aResult);
+  *aResult = mForwardInlineFilter;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsStreamConverter::SetForwardInlineFilter(PRBool aForwardInlineFilter)
+{
+  mForwardInlineFilter = aForwardInlineFilter;
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsStreamConverter::GetIdentity(nsIMsgIdentity * *aIdentity)
 {
   if (!aIdentity) return NS_ERROR_NULL_POINTER;
   /*
--- a/mailnews/mime/src/nsStreamConverter.h
+++ b/mailnews/mime/src/nsStreamConverter.h
@@ -43,18 +43,18 @@
 #include "nsIMimeEmitter.h" 
 #include "nsIURI.h"
 #include "nsIAsyncInputStream.h"
 #include "nsIAsyncOutputStream.h"
 #include "nsIChannel.h"
 #include "nsStringGlue.h"
 #include "nsCOMPtr.h"
 
-class nsStreamConverter : public nsIStreamConverter, public nsIMimeStreamConverter { 
-public: 
+class nsStreamConverter : public nsIStreamConverter, public nsIMimeStreamConverter {
+public:
   nsStreamConverter();
   virtual ~nsStreamConverter();
 
   NS_DECL_ISUPPORTS 
 
   // nsIMimeStreamConverter support
   NS_DECL_NSIMIMESTREAMCONVERTER
   // nsIStreamConverter methods
@@ -95,23 +95,25 @@ private:
   nsCString                     mOutputFormat;
   nsCString                     mRealContentType; // if we know the content type for real, this will be set (used by attachments)
 
   nsCString                     mOverrideFormat;  // this is a possible override for emitter creation
   PRBool                        mWrapperOutput;   // Should we output the frame split message display 
 
   nsCOMPtr<nsIMimeStreamConverterListener>  mMimeStreamConverterListener;
   PRBool                        mForwardInline;
+  PRBool                        mForwardInlineFilter;
   PRBool                        mOverrideComposeFormat;
+  nsString                      mForwardToAddress;
   nsCOMPtr<nsIMsgIdentity>      mIdentity;
   nsCString                     mOriginalMsgURI;
   nsCOMPtr<nsIMsgDBHdr>         mOrigMsgHdr;
 
   nsCString                     mFromType;
   nsCString                     mToType;
 #ifdef DEBUG_mscott  
   PRTime mConvertContentTime;
 #endif
   nsIRequest *                  mPendingRequest;  // used when we need to delay to fire onStartRequest
   nsISupports *                 mPendingContext;  // used when we need to delay to fire onStartRequest
-}; 
+};
 
 #endif /* nsStreamConverter_h_ */