Blob Blame History Raw
# vim: se ft=diff :
# HG changeset patch
# User Jan Horak <jhorak>
# Date 2017-04-26 02:36
# Parent  540cd06b1aea0bfa6f906b86393f5480914c01c2
Bug 1158578 - fix crash when compacting IMAP account. r=jorgk

diff --git a/mailnews/base/src/nsMsgFolderCompactor.cpp b/mailnews/base/src/nsMsgFolderCompactor.cpp
--- a/mailnews/base/src/nsMsgFolderCompactor.cpp
+++ b/mailnews/base/src/nsMsgFolderCompactor.cpp
@@ -31,16 +31,17 @@
 #include "nsIMsgStatusFeedback.h"
 #include "nsMsgBaseCID.h"
 #include "nsIMsgFolderNotificationService.h"
 #include "nsIMsgPluggableStore.h"
 #include "nsMsgFolderCompactor.h"
 #include <algorithm>
 #include "nsIOutputStream.h"
 #include "nsIInputStream.h"
+#include "nsPrintfCString.h"
 
 
 //////////////////////////////////////////////////////////////////////////////
 // nsFolderCompactState
 //////////////////////////////////////////////////////////////////////////////
 
 NS_IMPL_ISUPPORTS(nsFolderCompactState, nsIMsgFolderCompactor, nsIRequestObserver, nsIStreamListener, nsICopyMessageStreamListener, nsIUrlListener)
 
@@ -1096,16 +1097,24 @@ nsOfflineStoreCompactState::OnStopReques
   // check for it specifically and don't terminate the compaction.
   if (NS_FAILED(rv) && rv != NS_MSG_ERROR_MSG_NOT_OFFLINE)
     goto done;
   uri = do_QueryInterface(ctxt, &rv);
   if (NS_FAILED(rv)) goto done;
   rv = GetMessage(getter_AddRefs(msgHdr));
   if (NS_FAILED(rv)) goto done;
 
+  // This is however an unexpected condition, so let's print a warning.
+  if (rv == NS_MSG_ERROR_MSG_NOT_OFFLINE) {
+    nsAutoCString spec;
+    uri->GetSpec(spec);
+    nsPrintfCString msg("Message expectedly not available offline: %s", spec.get());
+    NS_WARNING(msg.get());
+  }
+
   if (msgHdr)
   {
     if (NS_SUCCEEDED(status))
     {
       msgHdr->SetMessageOffset(m_startOfNewMsg);
       char storeToken[100];
       PR_snprintf(storeToken, sizeof(storeToken), "%lld", m_startOfNewMsg);
       msgHdr->SetStringProperty("storeToken", storeToken);
diff --git a/mailnews/imap/src/nsImapProtocol.cpp b/mailnews/imap/src/nsImapProtocol.cpp
--- a/mailnews/imap/src/nsImapProtocol.cpp
+++ b/mailnews/imap/src/nsImapProtocol.cpp
@@ -9500,35 +9500,66 @@ nsresult nsImapMockChannel::ReadFromMemC
     // Content is modified so return an error so we try to open it the
     // old fashioned way.
     rv = NS_ERROR_FAILURE;
   }
 
   return rv;
 }
 
+class nsReadFromImapConnectionFailure : public mozilla::Runnable
+{
+public:
+  nsReadFromImapConnectionFailure(nsImapMockChannel *aChannel)
+    : mImapMockChannel(aChannel)
+  {}
+
+  NS_IMETHOD Run()
+  {
+    if (mImapMockChannel) {
+      mImapMockChannel->RunOnStopRequestFailure();
+    }
+    return NS_OK;
+  }
+private:
+  RefPtr<nsImapMockChannel> mImapMockChannel;
+};
+
+
+nsresult nsImapMockChannel::RunOnStopRequestFailure()
+{
+  if (m_channelListener) {
+    m_channelListener->OnStopRequest(this, m_channelContext,
+                                     NS_MSG_ERROR_MSG_NOT_OFFLINE);
+  }
+  return NS_OK;
+}
+
 // the requested url isn't in any of our caches so create an imap connection
 // to process it.
 nsresult nsImapMockChannel::ReadFromImapConnection()
 {
   nsresult rv = NS_OK;
   nsCOMPtr<nsIImapUrl> imapUrl = do_QueryInterface(m_url);
   nsCOMPtr<nsIMsgMailNewsUrl> mailnewsUrl = do_QueryInterface(m_url);
 
   bool localOnly = false;
   imapUrl->GetLocalFetchOnly(&localOnly);
   if (localOnly)
   {
     // This will cause an OnStartRunningUrl, and the subsequent close
     // will then cause an OnStopRunningUrl with the cancel status.
     NotifyStartEndReadFromCache(true);
     Cancel(NS_MSG_ERROR_MSG_NOT_OFFLINE);
-    if (m_channelListener)
-      m_channelListener->OnStopRequest(this, m_channelContext,
-                                       NS_MSG_ERROR_MSG_NOT_OFFLINE);
+
+    // Dispatch error notification, so ReadFromImapConnection() returns *before*
+    // the error is sent to the listener's OnStopRequest(). This avoids
+    // endless recursion where the caller relies on async execution.
+    nsCOMPtr<nsIRunnable> event = new nsReadFromImapConnectionFailure(this);
+    NS_DispatchToCurrentThread(event);
     return NS_MSG_ERROR_MSG_NOT_OFFLINE;
   }
 
   nsCOMPtr <nsILoadGroup> loadGroup;
   GetLoadGroup(getter_AddRefs(loadGroup));
   if (!loadGroup) // if we don't have one, the url will snag one from the msg window...
     mailnewsUrl->GetLoadGroup(getter_AddRefs(loadGroup));
 
diff --git a/mailnews/imap/src/nsImapProtocol.h b/mailnews/imap/src/nsImapProtocol.h
--- a/mailnews/imap/src/nsImapProtocol.h
+++ b/mailnews/imap/src/nsImapProtocol.h
@@ -714,16 +714,17 @@ public:
   NS_DECL_NSIIMAPMOCKCHANNEL
   NS_DECL_NSICHANNEL
   NS_DECL_NSIREQUEST
   NS_DECL_NSICACHEENTRYOPENCALLBACK
   NS_DECL_NSITRANSPORTEVENTSINK
 
   nsImapMockChannel();
   static nsresult Create (const nsIID& iid, void **result);
+  nsresult RunOnStopRequestFailure();
 
 protected:
   virtual ~nsImapMockChannel();
   nsCOMPtr <nsIURI> m_url;
 
   nsCOMPtr<nsIURI> m_originalUrl;
   nsCOMPtr<nsILoadGroup> m_loadGroup;
   nsCOMPtr<nsILoadInfo> m_loadInfo;