Bug 805626 - make draft message saved in offline mode use fake db key. r+a=Standard8 GECKO1701_2013010313_RELBRANCH
authorDavid Lechner <david@lechnology.com>
Thu, 06 Dec 2012 16:41:25 -0600
branchGECKO1701_2013010313_RELBRANCH
changeset 30926 d6956629395ce5ed980ec319a904197805d32019
parent 30925 49618fc13d0e99a3e27bf1d3cf78e02d8bc3bc19
child 30927 0d85a282b92c71320b3a339b055e2069f57b30ac
push id1
push userclokep@gmail.com
push dateMon, 07 May 2018 22:45:56 +0000
treeherdercomm-esr60@57eacde5ef40 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs805626
Bug 805626 - make draft message saved in offline mode use fake db key. r+a=Standard8
mailnews/imap/src/nsImapService.cpp
mailnews/imap/test/unit/test_offlineDraftDataloss.js
mailnews/imap/test/unit/test_offlinePlayback.js
mailnews/imap/test/unit/xpcshell.ini
--- a/mailnews/imap/src/nsImapService.cpp
+++ b/mailnews/imap/src/nsImapService.cpp
@@ -2024,19 +2024,19 @@ nsresult nsImapService::OfflineAppendFro
       nsCOMPtr <nsIOutputStream> offlineStore;
       nsCOMPtr<nsIMsgPluggableStore> msgStore;
       nsCOMPtr<nsIMsgIncomingServer> dstServer;
       nsCOMPtr<nsIMsgDBHdr> newMsgHdr;
 
       aDstFolder->GetServer(getter_AddRefs(dstServer));
       rv = dstServer->GetMsgStore(getter_AddRefs(msgStore));
       NS_ENSURE_SUCCESS(rv, rv);
-      bool reusable;
-      msgStore->GetNewMsgOutputStream(aDstFolder, getter_AddRefs(newMsgHdr),
-                                      &reusable, getter_AddRefs(offlineStore));
+      rv = destDB->CreateNewHdr(fakeKey, getter_AddRefs(newMsgHdr));
+      NS_ENSURE_SUCCESS(rv, rv);
+      rv = aDstFolder->GetOfflineStoreOutputStream(newMsgHdr, getter_AddRefs(offlineStore));
 
       if (NS_SUCCEEDED(rv) && offlineStore)
       {
         int64_t curOfflineStorePos = 0;
         nsCOMPtr <nsISeekableStream> seekable = do_QueryInterface(offlineStore);
         if (seekable)
           seekable->Tell(&curOfflineStorePos);
         else
@@ -2058,55 +2058,58 @@ nsresult nsImapService::OfflineAppendFro
                                                                                true,    // allocate new lines
                                                                                false);  // leave CRLFs on the returned string
           int64_t fileSize;
           aFile->GetFileSize(&fileSize);
           uint32_t bytesWritten;
           rv = NS_OK;
 //        rv = inputStream->Read(inputBuffer, inputBufferSize, &bytesRead);
 //        if (NS_SUCCEEDED(rv) && bytesRead > 0)
+          msgParser->SetState(nsIMsgParseMailMsgState::ParseHeadersState);
           msgParser->SetNewMsgHdr(newMsgHdr);
-          msgParser->SetState(nsIMsgParseMailMsgState::ParseHeadersState);
           // set the env pos to fake key so the msg hdr will have that for a key
           msgParser->SetEnvelopePos(fakeKey);
           bool needMoreData = false;
           char * newLine = nullptr;
           uint32_t numBytesInLine = 0;
           do
           {
             newLine = inputStreamBuffer->ReadNextLine(inputStream, numBytesInLine, needMoreData); 
             if (newLine)
             {
               msgParser->ParseAFolderLine(newLine, numBytesInLine);
               rv = offlineStore->Write(newLine, numBytesInLine, &bytesWritten);
               NS_Free(newLine);
             }
           } while (newLine);
+          msgParser->FinishHeader();
 
           nsCOMPtr<nsIMsgDBHdr> fakeHdr;
-          msgParser->FinishHeader();
           msgParser->GetNewMsgHdr(getter_AddRefs(fakeHdr));
           if (fakeHdr)
           {
             if (NS_SUCCEEDED(rv) && fakeHdr)
             {
               uint32_t resultFlags;
               fakeHdr->SetMessageOffset(curOfflineStorePos);
               fakeHdr->OrFlags(nsMsgMessageFlags::Offline | nsMsgMessageFlags::Read, &resultFlags);
               fakeHdr->SetOfflineMessageSize(fileSize);
               destDB->AddNewHdrToDB(fakeHdr, true /* notify */);
               aDstFolder->SetFlag(nsMsgFolderFlags::OfflineEvents);
+              if (msgStore)
+                msgStore->FinishNewMessage(offlineStore, fakeHdr);
             }
           }
           // tell the listener we're done.
           inputStream->Close();
           inputStream = nullptr;
           aListener->OnStopRunningUrl(aUrl, NS_OK);
           delete inputStreamBuffer;
         }
+        offlineStore->Close();
       }
     }
   }
           
   if (destDB)
     destDB->Close(true);
   return rv;
 }
new file mode 100644
--- /dev/null
+++ b/mailnews/imap/test/unit/test_offlineDraftDataloss.js
@@ -0,0 +1,196 @@
+/* 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/. */
+
+/**
+ * This file tests that a message saved as draft in an IMAP folder in offline
+ * mode is not lost when going back online
+ * See Bug 805626
+ */
+
+// async support
+load("../../../resources/logHelper.js");
+load("../../../resources/mailTestUtils.js");
+load("../../../resources/asyncTestUtils.js");
+
+Components.utils.import("resource://gre/modules/Services.jsm");
+
+// IMAP pump
+load("../../../resources/IMAPpump.js");
+
+setupIMAPPump();
+
+// Definition of tests
+
+var tests = [
+  createDraftsFolder,
+  goOffline,
+  saveDraft,
+  goOnline,
+  checkResult,
+  endTest
+];
+
+let gDraftsFolder;
+
+function createDraftsFolder()
+{
+  gIMAPIncomingServer.rootFolder.createSubfolder("Drafts", null);
+  yield false;
+  gDraftsFolder = gIMAPIncomingServer.rootFolder.getChildNamed("Drafts");
+  do_check_true(gDraftsFolder instanceof Ci.nsIMsgImapMailFolder);
+  gDraftsFolder.updateFolderWithListener(null, asyncUrlListener);
+  yield false;
+}
+function goOffline()
+{
+  // Don't prompt about offline download when going offline
+  Services.prefs.setIntPref("offline.download.download_messages", 2);
+
+  gIMAPIncomingServer.closeCachedConnections();
+  let thread = gThreadManager.currentThread;
+  while (thread.hasPendingEvents())
+    thread.processNextEvent(true);
+
+  do_timeout(2000, async_driver);
+  yield false;
+
+  gIMAPServer.stop();
+  Services.io.offline = true;
+}
+
+function saveDraft()
+{
+  let msgCompose = Cc["@mozilla.org/messengercompose/compose;1"]
+                     .createInstance(Ci.nsIMsgCompose);
+  let fields = Cc["@mozilla.org/messengercompose/composefields;1"]
+                 .createInstance(Ci.nsIMsgCompFields);
+  let params = Cc["@mozilla.org/messengercompose/composeparams;1"]
+                 .createInstance(Ci.nsIMsgComposeParams);
+  params.composeFields = fields;
+  msgCompose.initialize(params);
+
+  let acctMgr = Cc["@mozilla.org/messenger/account-manager;1"]
+                  .getService(Ci.nsIMsgAccountManager);
+
+  // Set up the identity
+  let identity = acctMgr.createIdentity();
+  identity.draftFolder = gDraftsFolder.URI;
+
+  let progress = Cc["@mozilla.org/messenger/progress;1"]
+                   .createInstance(Ci.nsIMsgProgress);
+  progress.registerListener(progressListener);
+  msgCompose.SendMsg(Ci.nsIMsgSend.nsMsgSaveAsDraft, identity, "", null,
+                     progress);
+  yield false;
+  // verify that message is not on the server yet
+  do_check_eq(gIMAPDaemon.getMailbox("Drafts")._messages.length, 0);
+}
+
+function goOnline()
+{
+  let offlineManager = Cc["@mozilla.org/messenger/offline-manager;1"]
+                       .getService(Ci.nsIMsgOfflineManager);
+  gIMAPDaemon.closing = false;
+  Services.io.offline = false;
+
+  gIMAPServer.start(IMAP_PORT);
+  offlineManager.inProgress = true;
+  offlineManager.goOnline(false, true, null);
+  let waitForNotInProgress = function () {
+    if (offlineManager.inProgress)
+      do_timeout(250, waitForNotInProgress);
+    else
+      async_driver();
+  }
+  waitForNotInProgress();
+  yield false;
+}
+
+function checkResult()
+{
+  // verify that message is now on the server
+  do_check_eq(gIMAPDaemon.getMailbox("Drafts")._messages.length, 1);
+  yield true;
+}
+
+function endTest()
+{
+  teardownIMAPPump();
+  yield true;
+}
+
+function run_test()
+{
+  Services.prefs.setBoolPref("mail.server.default.autosync_offline_stores", false);
+  let server = gIMAPIncomingServer;
+
+  // Add folder listeners that will capture async events
+  const nsIMFNService = Ci.nsIMsgFolderNotificationService;
+  let MFNService = Cc["@mozilla.org/messenger/msgnotificationservice;1"]
+                      .getService(nsIMFNService);
+
+  let flags =
+        nsIMFNService.msgsMoveCopyCompleted |
+        nsIMFNService.folderAdded |
+        nsIMFNService.msgAdded;
+  MFNService.addListener(mfnListener, flags);
+
+  //start first test
+  async_run_tests(tests);
+}
+
+var mfnListener =
+{
+  msgsMoveCopyCompleted: function (aMove, aSrcMsgs, aDestFolder, aDestMsgs)
+  {
+    dl('msgsMoveCopyCompleted to folder ' + aDestFolder.name);
+  },
+
+  folderAdded: function (aFolder)
+  {
+    dl('folderAdded <' + aFolder.name + '>');
+    // we are only using async add on the Junk folder
+    if (aFolder.name == "Drafts")
+      async_driver();
+  },
+
+  msgAdded: function msgAdded(aMsg)
+  {
+    dl('msgAdded with subject <' + aMsg.subject + '>');
+  }
+};
+
+var progressListener = {
+  onStateChange: function(aWebProgress, aRequest, aStateFlags, aStatus) {
+    if (aStateFlags & Ci.nsIWebProgressListener.STATE_STOP){
+      dl('onStateChange');
+      async_driver();
+    }
+  },
+
+  onProgressChange: function(aWebProgress, aRequest, aCurSelfProgress,
+                             aMaxSelfProgress, aCurTotalProgress,
+                             aMaxTotalProgress) {},
+  onLocationChange: function(aWebProgress, aRequest, aLocation, aFlags) {},
+  onStatusChange: function(aWebProgress, aRequest, aStatus, aMessage) {},
+  onSecurityChange: function(aWebProgress, aRequest, state) {},
+
+  QueryInterface : function(iid) {
+    if (iid.equals(Ci.nsIWebProgressListener) ||
+        iid.equals(Ci.nsISupportsWeakReference) ||
+        iid.equals(Ci.nsISupports))
+      return this;
+
+    throw Components.results.NS_NOINTERFACE;
+  }
+};
+
+/*
+ * helper functions
+ */
+
+// quick shorthand for output of a line of text.
+function dl(text) {
+  dump(text + '\n');
+}
--- a/mailnews/imap/test/unit/test_offlinePlayback.js
+++ b/mailnews/imap/test/unit/test_offlinePlayback.js
@@ -59,17 +59,17 @@ var tests = [
                              null, true);
     copyService.CopyMessages(gIMAPInbox, headers2, gThirdFolder, true, null,
                              null, true);
     var file = do_get_file("../../../data/bugmail10");
     copyService.CopyFileMessage(file, gIMAPInbox, null, false, 0,
                                 "", asyncCopyListener, null);
     yield false;
   },
-  function goOffline() {
+  function goOnline() {
     gOfflineManager = Cc["@mozilla.org/messenger/offline-manager;1"]
                            .getService(Ci.nsIMsgOfflineManager);
     gIMAPDaemon.closing = false;
     nsIIOService.offline = false;
 
     gIMAPServer.start(IMAP_PORT);
     gOfflineManager.goOnline(false, true, null);
     do_timeout(2000, async_driver);
--- a/mailnews/imap/test/unit/xpcshell.ini
+++ b/mailnews/imap/test/unit/xpcshell.ini
@@ -33,16 +33,17 @@ skip-if = true
 [test_imapMove.js]
 [test_imapPasswordFailure.js]
 [test_imapProtocols.js]
 [test_imapStatusCloseDBs.js]
 [test_imapStoreMsgOffline.js]
 [test_imapUndo.js]
 [test_imapUrls.js]
 [test_offlineCopy.js]
+[test_offlineDraftDataloss.js]
 [test_largeOfflineStore.js]
 skip-if = os == 'mac'
 [test_listClosesDB.js]
 [test_localToImapFilter.js]
 # Disabled due to intermittent failures, bug 502928
 skip-if = true
 [test_localToImapFilterQuarantine.js]
 [test_mailboxes.js]