bug 582918 - Body of message (and message headers too) is missing when move to sub-folder of Local Folders and mailnews.downloadToTempFile=true, r=bienvenu
authorKent James <kent@caspia.com>
Fri, 29 Apr 2011 08:23:18 -0700
changeset 7641 4405b0bb5d38676b45f15f85a67049e40c690c79
parent 7640 bd052bea42c308d8a550546e522720935d2f166f
child 7642 0707a29119bec8cee077e62084895bcc13b8bf96
push idunknown
push userunknown
push dateunknown
reviewersbienvenu
bugs582918
bug 582918 - Body of message (and message headers too) is missing when move to sub-folder of Local Folders and mailnews.downloadToTempFile=true, r=bienvenu
mailnews/base/test/unit/test_quarantineFilterMove.js
mailnews/local/src/nsLocalMailFolder.cpp
mailnews/local/src/nsParseMailbox.cpp
mailnews/local/src/nsParseMailbox.h
mailnews/local/src/nsPop3Sink.cpp
new file mode 100644
--- /dev/null
+++ b/mailnews/base/test/unit/test_quarantineFilterMove.js
@@ -0,0 +1,218 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Kent James <kent@caspia.com>.
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/*
+ * tests message moves with filter and quarantine enabled per bug 582918
+ *
+ * adapted from test_copyThenMoveManual.js
+ */
+
+load("../../../resources/POP3pump.js");
+const gFiles = ["../../../data/bugmail1", "../../../data/bugmail2"];
+var gMoveFolder;
+var gFilter; // the test filter
+var gFilterList;
+var gCurTestNum = 1;
+const gTestArray =
+[
+  function createFilters() {
+    gFilterList = gPOP3Pump.fakeServer.getFilterList(null);
+    gFilter = gFilterList.createFilter("MoveAll");
+    let searchTerm = gFilter.createTerm();
+    searchTerm.matchAll = true;
+    gFilter.appendTerm(searchTerm);
+    let moveAction = gFilter.createAction();
+    moveAction.type = Ci.nsMsgFilterAction.MoveToFolder;
+    moveAction.targetFolderUri = gMoveFolder.URI;
+    gFilter.appendAction(moveAction);
+    gFilter.enabled = true;
+    gFilter.filterType = Ci.nsMsgFilterType.InboxRule;
+    gFilterList.insertFilterAt(0, gFilter);
+    ++gCurTestNum;
+    doTest();
+  },
+  // just get a message into the local folder
+  function getLocalMessages1() {
+    gPOP3Pump.files = gFiles;
+    gPOP3Pump.onDone = doTest;
+    ++gCurTestNum;
+    gPOP3Pump.run();
+  },
+  function verifyFolders2() {
+    do_check_eq(folderCount(gMoveFolder), 2);
+    // the local inbox folder should now be empty, since the second
+    // operation was a move
+    do_check_eq(folderCount(gLocalInboxFolder), 0);
+
+    // Check that the messages have content
+    msgHdr = firstMsgHdr(gMoveFolder);
+
+    messageContent = getContentFromMessage(msgHdr);
+    do_check_true(messageContent.indexOf("Some User <bugmail@example.org> changed") != -1);
+
+    ++gCurTestNum;
+    doTest();
+  }
+];
+
+function folderCount(folder)
+{
+  let enumerator = folder.msgDatabase.EnumerateMessages();
+  let count = 0;
+  while (enumerator.hasMoreElements())
+  {
+    count++;
+    let hdr = enumerator.getNext();
+  }
+  return count;
+}
+
+function run_test()
+{
+  /* may not work in Linux */
+  //if ("@mozilla.org/gnome-gconf-service;1" in Cc)
+  //  return;
+  /**/
+
+  // quarantine messages
+  let prefs = Cc["@mozilla.org/preferences-service;1"]
+                .getService(Ci.nsIPrefBranch);
+  prefs.setBoolPref("mailnews.downloadToTempFile", true);
+  if (!gLocalInboxFolder)
+    loadLocalMailAccount();
+
+  gMoveFolder = gLocalIncomingServer.rootFolder.addSubfolder("MoveFolder");
+  const mailSession = Cc["@mozilla.org/messenger/services/session;1"]
+                        .getService(Ci.nsIMsgMailSession);
+
+  mailSession.AddFolderListener(FolderListener, Ci.nsIFolderListener.event |
+                                                Ci.nsIFolderListener.added |
+                                                Ci.nsIFolderListener.removed);
+
+  // "Master" do_test_pending(), paired with a do_test_finished() at the end of
+  // all the operations.
+  do_test_pending();
+
+  //start first test
+  doTest();
+}
+
+function doTest()
+{
+  var test = gCurTestNum;
+  if (test <= gTestArray.length)
+  {
+    var testFn = gTestArray[test-1];
+    dump("Doing test " + test + " " + testFn.name + "\n");
+
+    try {
+      testFn();
+    } catch(ex) {
+      do_throw ('TEST FAILED ' + ex);
+    }
+  }
+  else
+    do_timeout(1000, endTest);
+}
+
+// nsIFolderListener implementation
+var FolderListener = {
+  OnItemAdded: function OnItemAdded(aParentItem, aItem) {
+    this._showEvent(aParentItem, "OnItemAdded");
+  },
+  OnItemRemoved: function OnItemRemoved(aParentItem, aItem) {
+    this._showEvent(aParentItem, "OnItemRemoved");
+    // continue test, as all tests remove a message during the move
+    do_timeout(0, doTest);
+  },
+  OnItemEvent: function OnItemEvent(aEventFolder, aEvent) {
+    this._showEvent(aEventFolder, aEvent.toString())
+  },
+  _showEvent: function showEvent(aFolder, aEventString) {
+        dump("received folder event " + aEventString +
+         " folder " + aFolder.name +
+         "\n");
+  }
+};
+
+function endTest()
+{
+  // Cleanup, null out everything, close all cached connections and stop the
+  // server
+  dump("Exiting mail tests\n");
+  let thread = gThreadManager.currentThread;
+  while (thread.hasPendingEvents())
+    thread.processNextEvent(true);
+  gPOP3Pump = null;
+
+  do_test_finished(); // for the one in run_test()
+}
+
+/*
+ * Get the full message content.
+ *
+ * aMsgHdr: nsIMsgDBHdr object whose text body will be read
+ *          returns: string with full message contents
+ */
+function getContentFromMessage(aMsgHdr) {
+  const MAX_MESSAGE_LENGTH = 65536;
+  let msgFolder = aMsgHdr.folder;
+  let msgUri = msgFolder.getUriForMsg(aMsgHdr);
+
+  let messenger = Cc["@mozilla.org/messenger;1"]
+                    .createInstance(Ci.nsIMessenger);
+  let streamListener = Cc["@mozilla.org/network/sync-stream-listener;1"]
+                         .createInstance(Ci.nsISyncStreamListener);
+  messenger.messageServiceFromURI(msgUri).streamMessage(msgUri,
+                                                        streamListener,
+                                                        null,
+                                                        null,
+                                                        false,
+                                                        "",
+                                                        false);
+  let sis = Cc["@mozilla.org/scriptableinputstream;1"]
+              .createInstance(Ci.nsIScriptableInputStream);
+  sis.init(streamListener.inputStream);
+  return sis.read(MAX_MESSAGE_LENGTH);
+}
+
+// get the first message header found in a folder
+function firstMsgHdr(folder) {
+  let enumerator = folder.msgDatabase.EnumerateMessages();
+  if (enumerator.hasMoreElements())
+    return enumerator.getNext().QueryInterface(Ci.nsIMsgDBHdr);
+  return null;
+}
--- a/mailnews/local/src/nsLocalMailFolder.cpp
+++ b/mailnews/local/src/nsLocalMailFolder.cpp
@@ -3881,17 +3881,17 @@ nsMsgLocalMailFolder::AddMessageBatch(PR
   GetLocked(&isLocked);
   if (isLocked)
     return NS_MSG_FOLDER_BUSY;
 
   AcquireSemaphore(static_cast<nsIMsgLocalMailFolder*>(this));
 
   nsCOMPtr <nsIInputStream> inputStream = do_QueryInterface(outFileStream);
   rv = newMailParser->Init(rootFolder, this,
-                           path, inputStream, nsnull);
+                           inputStream, nsnull);
   // nsMailDatabase needs the stream so it can update the status flags during
   // the OnStopRequest logic.
   newMailParser->SetDBFolderStream(outFileStream);
   if (NS_SUCCEEDED(rv))
   {
     for (PRUint32 i = 0; i < aMessageCount; i++)
     {
       PRUint32 bytesWritten, messageLen = strlen(aMessages[i]);
--- a/mailnews/local/src/nsParseMailbox.cpp
+++ b/mailnews/local/src/nsParseMailbox.cpp
@@ -1690,21 +1690,23 @@ nsParseNewMailState::nsParseNewMailState
   m_ibuffer_size = 0;
   m_ibuffer_fp = 0;
   m_numNotNewMessages = 0;
  }
 
 NS_IMPL_ISUPPORTS_INHERITED1(nsParseNewMailState, nsMsgMailboxParser, nsIMsgFilterHitNotify)
 
 nsresult
-nsParseNewMailState::Init(nsIMsgFolder *serverFolder, nsIMsgFolder *downloadFolder, nsILocalFile *folder,
+nsParseNewMailState::Init(nsIMsgFolder *serverFolder, nsIMsgFolder *downloadFolder,
                           nsIInputStream *inboxFileStream, nsIMsgWindow *aMsgWindow)
 {
   nsresult rv;
   PRInt64 folderSize;
+  nsCOMPtr<nsILocalFile> folder;
+  downloadFolder->GetFilePath(getter_AddRefs(folder));
   folder->GetFileSize(&folderSize);
   m_position = folderSize;
   m_rootFolder = serverFolder;
   m_inboxFile = folder;
   m_inboxFileStream = inboxFileStream;
   m_msgWindow = aMsgWindow;
   m_downloadFolder = downloadFolder;
 
--- a/mailnews/local/src/nsParseMailbox.h
+++ b/mailnews/local/src/nsParseMailbox.h
@@ -231,17 +231,17 @@ private:
 
 class nsParseNewMailState : public nsMsgMailboxParser
 , public nsIMsgFilterHitNotify
 {
 public:
   nsParseNewMailState();
   virtual ~nsParseNewMailState();
   NS_DECL_ISUPPORTS_INHERITED
-  nsresult Init(nsIMsgFolder *rootFolder, nsIMsgFolder *downloadFolder, nsILocalFile *folder,
+  nsresult Init(nsIMsgFolder *rootFolder, nsIMsgFolder *downloadFolder,
                 nsIInputStream *inboxFileStream, nsIMsgWindow *aMsgWindow);
 
   virtual void  DoneParsingFolder(nsresult status);
 
   void DisableFilters() {m_disableFilters = PR_TRUE;}
 
   NS_DECL_NSIMSGFILTERHITNOTIFY
 
--- a/mailnews/local/src/nsPop3Sink.cpp
+++ b/mailnews/local/src/nsPop3Sink.cpp
@@ -296,16 +296,17 @@ nsPop3Sink::BeginMailDelivery(PRBool uid
   {
     PR_LOG(POP3LOGMODULE, PR_LOG_MAX, ("BeginMailDelivery folder locked"));
     return NS_MSG_FOLDER_BUSY;
   }
 
   nsCOMPtr<nsILocalFile> path;
 
   m_folder->GetFilePath(getter_AddRefs(path));
+  nsCOMPtr <nsIInputStream> inboxInputStream;
 
   nsCOMPtr<nsIPrefBranch> pPrefBranch(do_GetService(NS_PREFSERVICE_CONTRACTID, &rv));
   if (pPrefBranch)
      pPrefBranch->GetBoolPref("mailnews.downloadToTempFile", &m_downloadingToTempFile);
 
   if (m_downloadingToTempFile)
   {
     // need to create an nsIOFileStream from a temp file...
@@ -322,21 +323,26 @@ nsPop3Sink::BeginMailDelivery(PRBool uid
     NS_ENSURE_SUCCESS(rv, rv);
 
     m_tmpDownloadFile = do_QueryInterface(tmpDownloadFile, &rv);
     if (NS_SUCCEEDED(rv))
     {
       rv = MsgGetFileStream(m_tmpDownloadFile, getter_AddRefs(m_outFileStream));
       NS_ENSURE_SUCCESS(rv, rv);
     }
+    nsCOMPtr<nsIOutputStream> inboxOutputStream;
+    rv = MsgGetFileStream(path, getter_AddRefs(inboxOutputStream));
+    NS_ENSURE_SUCCESS(rv, rv);
+    inboxInputStream = do_QueryInterface(inboxOutputStream);
   }
   else
   {
     rv = MsgGetFileStream(path, getter_AddRefs(m_outFileStream));
     NS_ENSURE_SUCCESS(rv, rv);
+    inboxInputStream = do_QueryInterface(m_outFileStream);
   }
   // The following (!m_outFileStream etc) was added to make sure that we don't write somewhere
   // where for some reason or another we can't write to and lose the messages
   // See bug 62480
   if (!m_outFileStream)
       return NS_ERROR_OUT_OF_MEMORY;
 
   nsCOMPtr <nsISeekableStream> seekableOutStream = do_QueryInterface(m_outFileStream);
@@ -348,19 +354,18 @@ nsPop3Sink::BeginMailDelivery(PRBool uid
   if (m_newMailParser == nsnull)
     return NS_ERROR_OUT_OF_MEMORY;
 
   m_folder->GetNumNewMessages(PR_FALSE, &m_numNewMessagesInFolder);
   nsCOMPtr <nsIMsgFolder> serverFolder;
   rv = GetServerFolder(getter_AddRefs(serverFolder));
   if (NS_FAILED(rv)) return rv;
 
-  nsCOMPtr <nsIInputStream> inboxInputStream = do_QueryInterface(m_outFileStream);
-  rv = m_newMailParser->Init(serverFolder, m_folder, (m_downloadingToTempFile) ? m_tmpDownloadFile : path,
-                            inboxInputStream, aMsgWindow);
+  rv = m_newMailParser->Init(serverFolder, m_folder,
+                             inboxInputStream, aMsgWindow);
   // If we failed to initialize the parser, then just don't use it!!!
   // We can still continue without one.
 
   if (NS_FAILED(rv))
   {
     NS_IF_RELEASE(m_newMailParser);
     rv = NS_OK;
   }