# vim: se ft=diff : # HG changeset patch # User Jan Horak # 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 #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 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 imapUrl = do_QueryInterface(m_url); nsCOMPtr 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 event = new nsReadFromImapConnectionFailure(this); + NS_DispatchToCurrentThread(event); return NS_MSG_ERROR_MSG_NOT_OFFLINE; } nsCOMPtr 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 m_url; nsCOMPtr m_originalUrl; nsCOMPtr m_loadGroup; nsCOMPtr m_loadInfo;