Bug 803843: Don't close stream before calling DiscardNewMessage; keep track of when we're downloading the entire message r=Standard8 a=Standard8
authorIrving Reid <irving@mozilla.com>
Fri, 26 Oct 2012 11:49:37 -0400
changeset 13514 e89e3afc61446f33d6db968bab7e379089f7b6c6
parent 13513 4a95ecbb75f2672012160956ebe6526421704eb0
child 13515 311cd01f7a7e90f4381062ebfa5bb174ddc63171
push idunknown
push userunknown
push dateunknown
reviewersStandard8, Standard8
bugs803843
Bug 803843: Don't close stream before calling DiscardNewMessage; keep track of when we're downloading the entire message r=Standard8 a=Standard8
mailnews/base/util/nsMsgDBFolder.cpp
mailnews/imap/src/nsImapProtocol.cpp
mailnews/imap/src/nsImapProtocol.h
--- a/mailnews/base/util/nsMsgDBFolder.cpp
+++ b/mailnews/base/util/nsMsgDBFolder.cpp
@@ -1712,36 +1712,35 @@ nsresult nsMsgDBFolder::EndNewOfflineMes
       messageSize -= m_numOfflineMsgLines;
 
     // We clear the offline flag on the message if the size
     // looks wrong. Check if we're off by more than one byte per line.
     if (messageSize > (uint32_t) curStorePos &&
        (messageSize - (uint32_t) curStorePos) > (uint32_t) m_numOfflineMsgLines)
     {
        mDatabase->MarkOffline(messageKey, false, nullptr);
-       // we should truncate the offline store at messgeOffset
-       nsCOMPtr <nsIFile> localStore;
-       rv = GetFilePath(getter_AddRefs(localStore));
-       if (NS_SUCCEEDED(rv))
-       {
+       // we should truncate the offline store at messageOffset
+       ReleaseSemaphore(static_cast<nsIMsgFolder*>(this));
+       if (msgStore)
+         // this closes the stream
+         msgStore->DiscardNewMessage(m_tempMessageStream, m_offlineHeader);
+       else
          m_tempMessageStream->Close();
-         m_tempMessageStream = nullptr;
-         ReleaseSemaphore(static_cast<nsIMsgFolder*>(this));
-         if (msgStore)
-           msgStore->DiscardNewMessage(m_tempMessageStream, m_offlineHeader);
-       }
+       m_tempMessageStream = nullptr;
 #ifdef _DEBUG
        nsCAutoString message("Offline message too small: messageSize=");
        message.AppendInt(messageSize);
        message.Append(" curStorePos=");
        message.AppendInt(curStorePos);
        message.Append(" numOfflineMsgLines=");
        message.AppendInt(m_numOfflineMsgLines);
        NS_ERROR(message.get());
 #endif
+       m_offlineHeader = nullptr;
+       return NS_ERROR_FAILURE;
     }
     else
       m_offlineHeader->SetLineCount(m_numOfflineMsgLines);
 #ifdef _DEBUG
     nsCOMPtr<nsIInputStream> inputStream;
     GetOfflineStoreInputStream(getter_AddRefs(inputStream));
     if (inputStream)
       NS_ASSERTION(VerifyOfflineMessage(m_offlineHeader, inputStream),
--- a/mailnews/imap/src/nsImapProtocol.cpp
+++ b/mailnews/imap/src/nsImapProtocol.cpp
@@ -369,16 +369,17 @@ nsImapProtocol::nsImapProtocol() : nsMsg
   m_currentAuthMethod = kCapabilityUndefined;
   m_socketType = nsMsgSocketType::trySTARTTLS;
   m_connectionStatus = NS_OK;
   m_safeToCloseConnection = false;
   m_hostSessionList = nullptr;
   m_flagState = nullptr;
   m_fetchBodyIdList = nullptr;
   m_isGmailServer = false;
+  m_fetchingWholeMessage = false;
 
   nsCOMPtr<nsIPrefBranch> prefBranch(do_GetService(NS_PREFSERVICE_CONTRACTID));
   NS_ASSERTION(prefBranch, "FAILED to create the preference service");
 
   // read in the accept languages preference
   if (prefBranch)
   {
     if (!gInitialized)
@@ -3260,16 +3261,18 @@ void nsImapProtocol::FetchMsgAttribute(c
     commandString.Append(" (");
     commandString.Append(attribute);
     commandString.Append(")" CRLF);
     nsresult rv = SendData(commandString.get());
 
     if (NS_SUCCEEDED(rv))
        ParseIMAPandCheckForNewMail(commandString.get());
     GetServerStateParser().SetFetchingFlags(false);
+    // Always clear this flag after every fetch.
+    m_fetchingWholeMessage = false;
 }
 
 // this routine is used to fetch a message or messages, or headers for a
 // message...
 
 void nsImapProtocol::FallbackToFetchWholeMsg(const nsCString &messageId, uint32_t messageSize)
 {
   if (m_imapMessageSink && m_runningUrl)
@@ -3294,16 +3297,17 @@ nsImapProtocol::FetchMessage(const nsCSt
   IncrementCommandTagNumber();
 
   nsCString commandString;
   commandString = "%s UID fetch";
 
   switch (whatToFetch) {
   case kEveryThingRFC822:
     m_flagChangeCount++;
+    m_fetchingWholeMessage = true;
     if (m_trackingTime)
       AdjustChunkSize();      // we started another segment
     m_startTime = PR_Now();     // save start of download time
     m_trackingTime = true;
     PR_LOG(IMAP, PR_LOG_DEBUG, ("FetchMessage everything: curFetchSize %u numBytes %u",
                                 m_curFetchSize, numBytes));
     if (numBytes > 0)
       m_curFetchSize = numBytes;
@@ -3340,16 +3344,17 @@ nsImapProtocol::FetchMessage(const nsCSt
     {
       PR_LOG(IMAP, PR_LOG_DEBUG, ("FetchMessage peek: curFetchSize %u numBytes %u",
                                   m_curFetchSize, numBytes));
       if (numBytes > 0)
         m_curFetchSize = numBytes;
       const char *formatString = "";
       eIMAPCapabilityFlags server_capabilityFlags = GetServerStateParser().GetCapabilityFlag();
 
+      m_fetchingWholeMessage = true;
       if (server_capabilityFlags & kIMAP4rev1Capability)
       {
         // use body[].peek since rfc822.peek is not in IMAP4rev1
         if (server_capabilityFlags & kHasXSenderCapability)
           formatString = " %s (XSENDER UID RFC822.SIZE BODY.PEEK[]";
         else
           formatString = " %s (UID RFC822.SIZE BODY.PEEK[]";
       }
@@ -3532,16 +3537,18 @@ nsImapProtocol::FetchMessage(const nsCSt
 
     nsresult rv = SendData(protocolString);
 
     nsMemory::Free(cCommandStr);
     if (NS_SUCCEEDED(rv))
       ParseIMAPandCheckForNewMail(protocolString);
     PR_Free(protocolString);
     GetServerStateParser().SetFetchingFlags(false);
+    // Always clear this flag after every fetch.
+    m_fetchingWholeMessage = false;
     if (GetServerStateParser().LastCommandSuccessful() && CheckNeeded())
       Check();
   }
   else
     HandleMemoryFailure();
 }
 
 void nsImapProtocol::FetchTryChunking(const nsCString &messageIds,
@@ -3903,17 +3910,19 @@ void nsImapProtocol::NormalMessageEndDow
       m_hdrDownloadCache->ResetAll();
     }
   }
   FlushDownloadCache();
 
   if (!GetServerStateParser().GetDownloadingHeaders())
   {
     int32_t updatedMessageSize = -1;
-    if (m_bytesToChannel != GetServerStateParser().SizeOfMostRecentMessage()) {
+    if (m_fetchingWholeMessage &&
+        (m_bytesToChannel != GetServerStateParser().SizeOfMostRecentMessage()))
+    {
       updatedMessageSize = m_bytesToChannel;
 #ifdef DEBUG
       nsCAutoString message("Server's RFC822.SIZE ");
       message.AppendInt(GetServerStateParser().SizeOfMostRecentMessage());
       message += " actual size ";
       message.AppendInt(m_bytesToChannel);
       NS_WARNING(message.get());
 #endif
--- a/mailnews/imap/src/nsImapProtocol.h
+++ b/mailnews/imap/src/nsImapProtocol.h
@@ -330,16 +330,17 @@ private:
 
   // Ouput stream for writing commands to the socket
   nsCOMPtr<nsISocketTransport>  m_transport;
 
   nsCOMPtr<nsIAsyncInputStream>   m_channelInputStream;
   nsCOMPtr<nsIAsyncOutputStream>  m_channelOutputStream;
   nsCOMPtr<nsIImapMockChannel>    m_mockChannel;   // this is the channel we should forward to people
   uint32_t m_bytesToChannel;
+  bool m_fetchingWholeMessage;
   //nsCOMPtr<nsIRequest> mAsyncReadRequest; // we're going to cancel this when we're done with the conn.
 
 
   // ******* Thread support *******
   nsCOMPtr<nsIThread>      m_iThread;
   PRThread     *m_thread;
   mozilla::ReentrantMonitor m_dataAvailableMonitor;   // used to notify the arrival of data from the server
   mozilla::ReentrantMonitor m_urlReadyToRunMonitor;   // used to notify the arrival of a new url to be processed