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