Bug 623522 - Stop IMAP touching the preference service from background threads | Permanent Orange | TEST-UNEXPECTED-FAIL | test_dod.js | false == true; Patch by Standard8 and bienvenu; r=Standard8 for bienvenu's parts and r=bienvenu for Standard8's parts.
authorMark Banner <bugzilla@standard8.plus.com>
Fri, 07 Jan 2011 19:27:41 +0000
changeset 6918 a36b59e34e7e18556cc9f0309c1a00aaeda52a66
parent 6917 238a7966dbe17e292a6db7cc4906d1ce5561414a
child 6919 6f67325cc686e901274da4d05523887edb653967
push idunknown
push userunknown
push dateunknown
reviewersStandard8, bienvenu
bugs623522
Bug 623522 - Stop IMAP touching the preference service from background threads | Permanent Orange | TEST-UNEXPECTED-FAIL | test_dod.js | false == true; Patch by Standard8 and bienvenu; r=Standard8 for bienvenu's parts and r=bienvenu for Standard8's parts.
mailnews/imap/public/nsIIMAPHostSessionList.h
mailnews/imap/src/nsIMAPBodyShell.cpp
mailnews/imap/src/nsIMAPBodyShell.h
mailnews/imap/src/nsIMAPHostSessionList.cpp
mailnews/imap/src/nsIMAPHostSessionList.h
mailnews/imap/src/nsImapProtocol.cpp
mailnews/imap/src/nsImapProtocol.h
mailnews/imap/src/nsImapServerResponseParser.cpp
mailnews/imap/test/unit/test_dod.js
--- a/mailnews/imap/public/nsIIMAPHostSessionList.h
+++ b/mailnews/imap/public/nsIIMAPHostSessionList.h
@@ -121,14 +121,15 @@ public:
   NS_IMETHOD  FlushUncommittedNamespacesForHost(const char *serverKey, PRBool &result) = 0;
   
   // Hierarchy Delimiters
   NS_IMETHOD  SetNamespaceHierarchyDelimiterFromMailboxForHost(const char *serverKey, const char *boxName, char delimiter) = 0;
 
   // Message Body Shells
   NS_IMETHOD  AddShellToCacheForHost(const char *serverKey, nsIMAPBodyShell *shell) = 0;
   NS_IMETHOD  FindShellInCacheForHost(const char *serverKey, const char *mailboxName, const char *UID, IMAP_ContentModifiedType modType, nsIMAPBodyShell **result) = 0;
+  NS_IMETHOD  ClearShellCacheForHost(const char *serverKey) = 0;
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(nsIImapHostSessionList,
                               NS_IIMAPHOSTSESSIONLIST_IID)
 
 #endif
--- a/mailnews/imap/src/nsIMAPBodyShell.cpp
+++ b/mailnews/imap/src/nsIMAPBodyShell.cpp
@@ -570,19 +570,23 @@ PRBool nsIMAPBodypart::ShouldExplicitlyN
 {
   return PR_FALSE;
 }
 
 
 ///////////// nsIMAPBodypartLeaf /////////////////////////////
 
 
-nsIMAPBodypartLeaf::nsIMAPBodypartLeaf(char *partNum, nsIMAPBodypart *parentPart,
-  char *bodyType, char *bodySubType, char *bodyID, char *bodyDescription, char *bodyEncoding, PRInt32 partLength) : 
-nsIMAPBodypart(partNum, parentPart)
+nsIMAPBodypartLeaf::nsIMAPBodypartLeaf(char *partNum,
+                                       nsIMAPBodypart *parentPart,
+                                       char *bodyType, char *bodySubType,
+                                       char *bodyID, char *bodyDescription,
+                                       char *bodyEncoding, PRInt32 partLength,
+                                       PRBool preferPlainText)
+  : nsIMAPBodypart(partNum, parentPart), mPreferPlainText(preferPlainText)
 {
   m_bodyType = bodyType;
   m_bodySubType = bodySubType;
   m_bodyID = bodyID;
   m_bodyDescription = bodyDescription;
   m_bodyEncoding = bodyEncoding;
   m_partLength = partLength;
   if (m_bodyType && m_bodySubType)
@@ -706,32 +710,29 @@ PRBool nsIMAPBodypartLeaf::ShouldFetchIn
     if (m_parentPart->GetType() == IMAP_BODY_MESSAGE_RFC822)
       return m_parentPart->ShouldFetchInline(aShell);
     
     // View Attachments As Links is on.
     if (!(aShell->GetContentModified() == IMAP_CONTENT_MODIFIED_VIEW_INLINE))
     {
       // The last text part is still displayed inline,
       // even if View Attachments As Links is on.
-      nsCOMPtr<nsIPrefBranch> prefBranch(do_GetService(NS_PREFSERVICE_CONTRACTID));
-      PRBool preferPlainText = PR_FALSE;
-      if (prefBranch)
-        prefBranch->GetBoolPref("mailnews.display.prefer_plaintext", &preferPlainText);
-
       nsIMAPBodypart *grandParentPart = m_parentPart->GetParentPart();
-      if ((preferPlainText || !PL_strcasecmp(m_parentPart->GetBodySubType(), "mixed")) &&
+      if ((mPreferPlainText ||
+           !PL_strcasecmp(m_parentPart->GetBodySubType(), "mixed")) &&
           !PL_strcmp(m_partNumberString, "1") &&
           !PL_strcasecmp(m_bodyType, "text"))
         return PR_TRUE;         // we're downloading it inline
 
-      if (   (!PL_strcasecmp(m_parentPart->GetBodySubType(), "alternative") ||
-              (grandParentPart && !PL_strcasecmp(grandParentPart->GetBodySubType(), "alternative")))
-          && !PL_strcasecmp(m_bodyType, "text")
-          && ((!PL_strcasecmp(m_bodySubType, "plain") && preferPlainText) ||
-              (!PL_strcasecmp(m_bodySubType, "html") && !preferPlainText)))
+      if ((!PL_strcasecmp(m_parentPart->GetBodySubType(), "alternative") ||
+           (grandParentPart &&
+            !PL_strcasecmp(grandParentPart->GetBodySubType(), "alternative"))) &&
+          !PL_strcasecmp(m_bodyType, "text") &&
+          ((!PL_strcasecmp(m_bodySubType, "plain") && mPreferPlainText) ||
+           (!PL_strcasecmp(m_bodySubType, "html") && !mPreferPlainText)))
         return PR_TRUE;
 
       // This is the first text part of a top-level multipart.
       // For instance, a message with multipart body, where the first
       // part is multipart, and this is the first leaf of that first part.
       if (m_parentPart->GetType() == IMAP_BODY_MULTIPART &&
           (PL_strlen(m_partNumberString) >= 2) &&
           !PL_strcmp(m_partNumberString + PL_strlen(m_partNumberString) - 2, ".1") && // this is the first text type on this level
@@ -803,18 +804,28 @@ PRBool nsIMAPBodypartLeaf::PreflightChec
 {
   // only need to check this part, since it has no children.
   return ShouldFetchInline(aShell);
 }
 
 
 ///////////// nsIMAPBodypartMessage ////////////////////////
 
-nsIMAPBodypartMessage::nsIMAPBodypartMessage(char *partNum,  nsIMAPBodypart *parentPart,
-  PRBool topLevelMessage, char *bodyType, char *bodySubType, char *bodyID, char *bodyDescription, char *bodyEncoding, PRInt32 partLength) : nsIMAPBodypartLeaf(partNum, parentPart, bodyType, bodySubType, bodyID, bodyDescription, bodyEncoding, partLength)
+nsIMAPBodypartMessage::nsIMAPBodypartMessage(char *partNum,
+                                             nsIMAPBodypart *parentPart,
+                                             PRBool topLevelMessage,
+                                             char *bodyType, char *bodySubType,
+                                             char *bodyID,
+                                             char *bodyDescription,
+                                             char *bodyEncoding,
+                                             PRInt32 partLength,
+                                             PRBool preferPlainText)
+ : nsIMAPBodypartLeaf(partNum, parentPart, bodyType, bodySubType, bodyID,
+                      bodyDescription, bodyEncoding, partLength,
+                      preferPlainText)
 {
   m_topLevelMessage = topLevelMessage;
   if (m_topLevelMessage)
   {
     m_partNumberString = PR_smprintf("0");
     if (!m_partNumberString)
     {
       SetIsValid(PR_FALSE);
@@ -1249,16 +1260,21 @@ PRBool nsIMAPBodyShellCache::EjectEntry(
 	nsIMAPBodyShell *removedShell = (nsIMAPBodyShell *) (m_shellList->ElementAt(0));
 
 	m_shellList->RemoveElementAt(0);
 	m_shellHash.Remove(removedShell->GetUID());
 
 	return PR_TRUE;
 }
 
+void nsIMAPBodyShellCache::Clear()
+{
+  while (EjectEntry()) ;
+}
+
 PRBool	nsIMAPBodyShellCache::AddShellToCache(nsIMAPBodyShell *shell)
 {
 	// If it's already in the cache, then just return.
 	// This has the side-effect of re-ordering the LRU list
 	// to put this at the top, which is good, because it's what we want.
 	if (FindShellForUID(shell->GetUID(), shell->GetFolderName(), shell->GetContentModified()))
 		return PR_TRUE;
 
--- a/mailnews/imap/src/nsIMAPBodyShell.h
+++ b/mailnews/imap/src/nsIMAPBodyShell.h
@@ -173,32 +173,39 @@ protected:
 };
 
 
 // The name "leaf" is somewhat misleading, since a part of type message/rfc822 is technically
 // a leaf, even though it can contain other parts within it.
 class nsIMAPBodypartLeaf : public nsIMAPBodypart
 {
 public:
-    nsIMAPBodypartLeaf(char *partNum, nsIMAPBodypart *parentPart,
-      char *bodyType, char *bodySubType, char *bodyID, char *bodyDescription, char *bodyEncoding, PRInt32 partLength);
+  nsIMAPBodypartLeaf(char *partNum, nsIMAPBodypart *parentPart, char *bodyType,
+                     char *bodySubType, char *bodyID, char *bodyDescription,
+                     char *bodyEncoding, PRInt32 partLength,
+                     PRBool preferPlainText);
 	virtual nsIMAPBodypartType	GetType();
     // Generates an HTML representation of this part.  Returns content length generated, -1 if failed.
     virtual PRInt32 Generate(nsIMAPBodyShell *aShell, PRBool stream, PRBool prefetch);
     // returns PR_TRUE if this part should be fetched inline for generation.
     virtual PRBool ShouldFetchInline(nsIMAPBodyShell *aShell);
     virtual PRBool PreflightCheckAllInline(nsIMAPBodyShell *aShell);
+private:
+  PRBool mPreferPlainText;
 };
 
 
 class nsIMAPBodypartMessage : public nsIMAPBodypartLeaf
 {
 public:
-    nsIMAPBodypartMessage(char *partNum, nsIMAPBodypart *parentPart, PRBool topLevelMessage,
-      char *bodyType, char *bodySubType, char *bodyID, char *bodyDescription, char *bodyEncoding, PRInt32 partLength);
+  nsIMAPBodypartMessage(char *partNum, nsIMAPBodypart *parentPart,
+                        PRBool topLevelMessage, char *bodyType,
+                        char *bodySubType, char *bodyID,
+                        char *bodyDescription, char *bodyEncoding,
+                        PRInt32 partLength, PRBool preferPlainText);
     void SetBody(nsIMAPBodypart *body);
 	virtual nsIMAPBodypartType	GetType();
 	virtual ~nsIMAPBodypartMessage();
     virtual PRInt32 Generate(nsIMAPBodyShell *aShell, PRBool stream, PRBool prefetch);
     virtual PRBool ShouldFetchInline(nsIMAPBodyShell *aShell);
     virtual PRBool PreflightCheckAllInline(nsIMAPBodyShell *aShell);
 	virtual nsIMAPBodypart	*FindPartWithNumber(const char *partNum);	// Returns the part object with the given number
 	void	AdoptMessageHeaders(char *headers);			// Fills in buffer (and adopts storage) for header object
@@ -257,26 +264,26 @@ public:
                                               // Returns FALSE if the setting is "Show Attachments as Links"
   PRBool	PreflightCheckAllInline();		  // Returns PR_TRUE if all parts are inline, PR_FALSE otherwise.  Does not generate anything.
 
   // Helpers
   nsImapProtocol *GetConnection() { return m_protocolConnection; }
   PRBool	GetPseudoInterrupted();
   PRBool DeathSignalReceived();
   nsCString &GetUID() { return m_UID; }
-  const char	*GetFolderName() { return m_folderName; }
-  char	*GetGeneratingPart() { return m_generatingPart; }
-  PRBool	IsBeingGenerated() { return m_isBeingGenerated; }	// Returns PR_TRUE if this is in the process of being
-															  // generated, so we don't re-enter
+  const char *GetFolderName() { return m_folderName; }
+  char *GetGeneratingPart() { return m_generatingPart; }
+  // Returns PR_TRUE if this is in the process of being generated,
+  // so we don't re-enter
+  PRBool IsBeingGenerated() { return m_isBeingGenerated; }
   PRBool IsShellCached() { return m_cached; }
-  void	SetIsCached(PRBool isCached) { m_cached = isCached; }
-  PRBool	GetGeneratingWholeMessage() { return m_generatingWholeMessage; }
+  void SetIsCached(PRBool isCached) { m_cached = isCached; }
+  PRBool GetGeneratingWholeMessage() { return m_generatingWholeMessage; }
   IMAP_ContentModifiedType	GetContentModified() { return m_contentModified; }
-  void	SetContentModified(IMAP_ContentModifiedType modType) { m_contentModified = modType; }
-
+  void SetContentModified(IMAP_ContentModifiedType modType) { m_contentModified = modType; }
 protected:
 
   nsIMAPBodypartMessage	*m_message;
 
   nsIMAPMessagePartIDArray        *m_prefetchQueue;	// array of pipelined part prefetches.  Ok, so it's not really a queue.
 
   PRBool                          m_isValid;
   nsImapProtocol                  *m_protocolConnection;  // Connection, for filling in parts
@@ -312,16 +319,17 @@ public:
 	static nsIMAPBodyShellCache	*Create();
 	virtual ~nsIMAPBodyShellCache();
 
 	PRBool			AddShellToCache(nsIMAPBodyShell *shell);		// Adds shell to cache, possibly ejecting
 																// another entry based on scheme in EjectEntry().
 	nsIMAPBodyShell	*FindShellForUID(nsCString &UID, const char *mailboxName, IMAP_ContentModifiedType modType);	// Looks up a shell in the cache given the message's UID.
 	nsIMAPBodyShell	*FindShellForUID(PRUint32 UID, const char *mailboxName, IMAP_ContentModifiedType modType);	// Looks up a shell in the cache given the message's UID.
 															// Returns the shell if found, NULL if not found.
+  void Clear();
 
 protected:
 	nsIMAPBodyShellCache();
 	PRBool	EjectEntry();	// Chooses an entry to eject;  deletes that entry;  and ejects it from the cache,
 							// clearing up a new space.  Returns PR_TRUE if it found an entry to eject, PR_FALSE otherwise.
 	PRUint32	GetSize() { return m_shellList->Count(); }
 	PRUint32	GetMaxSize() { return 20; }
 
--- a/mailnews/imap/src/nsIMAPHostSessionList.cpp
+++ b/mailnews/imap/src/nsIMAPHostSessionList.cpp
@@ -737,8 +737,20 @@ NS_IMETHODIMP nsIMAPHostSessionList::Fin
 	PR_EnterMonitor(gCachedHostInfoMonitor);
 	nsIMAPHostInfo *host = FindHost(serverKey);
 	if (host)
 		if (host->fShellCache)
 			*shell = host->fShellCache->FindShellForUID(uidString, mailboxName, modType);
 	PR_ExitMonitor(gCachedHostInfoMonitor);
 	return (host == NULL) ? NS_ERROR_ILLEGAL_VALUE : NS_OK;
 }
+
+NS_IMETHODIMP 
+nsIMAPHostSessionList::ClearShellCacheForHost(const char *serverKey)
+{
+  PR_EnterMonitor(gCachedHostInfoMonitor);
+  nsIMAPHostInfo *host = FindHost(serverKey);
+  if (host && host->fShellCache)
+    host->fShellCache->Clear();
+  PR_ExitMonitor(gCachedHostInfoMonitor);
+  return (host == NULL) ? NS_ERROR_ILLEGAL_VALUE : NS_OK;
+}
+
--- a/mailnews/imap/src/nsIMAPHostSessionList.h
+++ b/mailnews/imap/src/nsIMAPHostSessionList.h
@@ -151,16 +151,16 @@ public:
   NS_IMETHOD FlushUncommittedNamespacesForHost(const char *serverKey, PRBool &result);
 
   // Hierarchy Delimiters
   NS_IMETHOD SetNamespaceHierarchyDelimiterFromMailboxForHost(const char *serverKey, const char *boxName, char delimiter);
 
   // Message Body Shells
   NS_IMETHOD AddShellToCacheForHost(const char *serverKey, nsIMAPBodyShell *shell);
   NS_IMETHOD FindShellInCacheForHost(const char *serverKey, const char *mailboxName, const char *UID, IMAP_ContentModifiedType modType, nsIMAPBodyShell	**result);
-
+  NS_IMETHOD ClearShellCacheForHost(const char *serverKey);
   PRMonitor *gCachedHostInfoMonitor;
   nsIMAPHostInfo *fHostInfoList;
 protected:
   nsresult SetNamespacesPrefForHost(nsIImapIncomingServer *aHost, EIMAPNamespaceType type, char *pref);
   nsIMAPHostInfo *FindHost(const char *serverKey);
 };
 #endif
--- a/mailnews/imap/src/nsImapProtocol.cpp
+++ b/mailnews/imap/src/nsImapProtocol.cpp
@@ -814,16 +814,34 @@ nsresult nsImapProtocol::SetupWithUrl(ns
     (void) imapServer->GetShuttingDown(&shuttingDown);
     if (!shuttingDown)
       (void) imapServer->GetUseIdle(&m_useIdle);
     else
       m_useIdle = PR_FALSE;
     if (imapServer)
       imapServer->GetFetchByChunks(&m_fetchByChunks);
 
+    nsAutoString trashFolderName;
+    if (NS_SUCCEEDED(imapServer->GetTrashFolderName(trashFolderName)))
+      CopyUTF16toMUTF7(trashFolderName, m_trashFolderName);
+
+    nsCOMPtr<nsIPrefBranch> prefBranch(do_GetService(NS_PREFSERVICE_CONTRACTID));
+    if (prefBranch)
+    {
+      PRBool preferPlainText;
+      prefBranch->GetBoolPref("mailnews.display.prefer_plaintext", &preferPlainText);
+      // If the pref has changed since the last time we ran a url,
+      // clear the shell cache for this host.
+      if (preferPlainText != m_preferPlainText)
+      {
+        m_hostSessionList->ClearShellCacheForHost(GetImapServerKey());
+        m_preferPlainText = preferPlainText;
+      }
+    }
+
     if ( m_runningUrl && !m_transport /* and we don't have a transport yet */)
     {
       // extract the file name and create a file transport...
       PRInt32 port=-1;
       server->GetPort(&port);
 
       if (port <= 0)
       {
@@ -4893,17 +4911,17 @@ nsImapProtocol::DiscoverMailboxSpec(nsIm
           {
             m_hostSessionList->GetOnlineTrashFolderExistsForHost(
                                   GetImapServerKey(), onlineTrashFolderExists);
           }
         }
 
         // Don't set the Trash flag if not using the Trash model
         if (GetDeleteIsMoveToTrash() && !onlineTrashFolderExists &&
-            adoptedBoxSpec->mAllocatedPathName.Find(GetTrashFolderName()) != -1)
+            adoptedBoxSpec->mAllocatedPathName.Find(m_trashFolderName) != -1)
         {
           PRBool trashExists = PR_FALSE;
           nsCString trashMatch;
           trashMatch.Adopt(CreatePossibleTrashName(nsPrefix));
           {
             char *serverTrashName = nsnull;
             m_runningUrl->AllocateCanonicalPath(trashMatch.get(), ns->GetDelimiter(), &serverTrashName);
             if (serverTrashName)
@@ -7549,37 +7567,20 @@ void nsImapProtocol::RenameMailbox(const
   nsresult rv = SendData(command.get());
   if (NS_SUCCEEDED(rv))
     ParseIMAPandCheckForNewMail();
 }
 
 char * nsImapProtocol::CreatePossibleTrashName(const char *prefix)
 {
   nsCString returnTrash(prefix);
-
-  returnTrash += GetTrashFolderName();
+  returnTrash += m_trashFolderName;
   return ToNewCString(returnTrash);
 }
 
-const char * nsImapProtocol::GetTrashFolderName()
-{
-  if (m_trashFolderName.IsEmpty())
-  {
-    nsCOMPtr<nsIImapIncomingServer> server = do_QueryReferent(m_server);
-    if (server)
-    {
-      nsAutoString trashFolderName;
-      if (NS_SUCCEEDED(server->GetTrashFolderName(trashFolderName)))
-        CopyUTF16toMUTF7(trashFolderName, m_trashFolderName);
-    }
-  }
-
-  return m_trashFolderName.get();
-}
-
 void nsImapProtocol::Lsub(const char *mailboxPattern, PRBool addDirectoryIfNecessary)
 {
   ProgressEventFunctionUsingId (IMAP_STATUS_LOOKING_FOR_MAILBOX);
 
   IncrementCommandTagNumber();
 
   char *boxnameWithOnlineDirectory = nsnull;
   if (addDirectoryIfNecessary)
--- a/mailnews/imap/src/nsImapProtocol.h
+++ b/mailnews/imap/src/nsImapProtocol.h
@@ -338,16 +338,18 @@ public:
   void HandleCurrentUrlError();
 
   // UIDPLUS extension
   void SetCopyResponseUid(const char* msgIdString);
 
   // Quota support
   void UpdateFolderQuotaData(nsCString& aQuotaRoot, PRUint32 aUsed, PRUint32 aMax);
 
+  PRBool GetPreferPlainText() { return m_preferPlainText; }
+
 private:
   // the following flag is used to determine when a url is currently being run. It is cleared when we
   // finish processng a url and it is set whenever we call Load on a url
   PRBool m_urlInProgress;
   nsCOMPtr<nsIImapUrl> m_runningUrl; // the nsIImapURL that is currently running
   nsImapAction m_imapAction;  // current imap action associated with this connnection...
 
   nsCString             m_hostName;
@@ -561,17 +563,16 @@ private:
   // notify the fe that a folder was deleted
   void FolderRenamed(const char *oldName,
     const char *newName);
 
   PRBool FolderIsSelected(const char *mailboxName);
 
   PRBool  MailboxIsNoSelectMailbox(const char *mailboxName);
   char * CreatePossibleTrashName(const char *prefix);
-  const char * GetTrashFolderName();
   PRBool FolderNeedsACLInitialized(const char *folderName);
   void DiscoverMailboxList();
   void DiscoverAllAndSubscribedBoxes();
   void MailboxDiscoveryFinished();
   void NthLevelChildList(const char *onlineMailboxPrefix, PRInt32 depth);
   void Lsub(const char *mailboxPattern, PRBool addDirectoryIfNecessary);
   void List(const char *mailboxPattern, PRBool addDirectoryIfNecessary,
             PRBool useXLIST = PR_FALSE);
@@ -666,16 +667,17 @@ private:
   PRBool m_checkForNewMailDownloadsHeaders;
   PRBool m_needNoop;
   PRBool m_idle;
   PRBool m_useIdle;
   PRInt32 m_noopCount;
   PRBool  m_autoSubscribe, m_autoUnsubscribe, m_autoSubscribeOnOpen;
   PRBool m_closeNeededBeforeSelect;
   PRBool m_retryUrlOnError;
+  PRBool m_preferPlainText;
 
   enum EMailboxHierarchyNameState {
     kNoOperationInProgress,
       kDiscoverBaseFolderInProgress,
       kDiscoverTrashFolderInProgress,
       kDeleteSubFoldersInProgress,
       kListingForInfoOnly,
       kListingForInfoAndDiscovery,
--- a/mailnews/imap/src/nsImapServerResponseParser.cpp
+++ b/mailnews/imap/src/nsImapServerResponseParser.cpp
@@ -2657,19 +2657,21 @@ void nsImapServerResponseParser::mime_pa
 // the [MIME-IMB] body structure of a message" [RFC 3501].
 void nsImapServerResponseParser::bodystructure_data()
 {
   AdvanceToNextToken();
   if (ContinueParse() && fNextToken && *fNextToken == '(')  // It has to start with an open paren.
   {
     // Turn the BODYSTRUCTURE response into a form that the nsIMAPBodypartMessage can be constructed from.
     // FIXME: Follow up on bug 384210 to investigate why the caller has to duplicate the two in-param strings.
-    nsIMAPBodypartMessage *message = new nsIMAPBodypartMessage(NULL, NULL, PR_TRUE,
-                                                               strdup("message"), strdup("rfc822"),
-                                                               NULL, NULL, NULL, 0);
+    nsIMAPBodypartMessage *message =
+      new nsIMAPBodypartMessage(NULL, NULL, PR_TRUE, strdup("message"),
+                                strdup("rfc822"),
+                                NULL, NULL, NULL, 0,
+                                fServerConnection.GetPreferPlainText());
     nsIMAPBodypart *body = bodystructure_part(PL_strdup("1"), message);
     if (body)
       message->SetBody(body);
     else
     {
       delete message;
       message = nsnull;
     }
@@ -2788,22 +2790,27 @@ nsImapServerResponseParser::bodystructur
     PR_FREEIF(bodyEncoding);
   }
   else
   {
     if (PL_strcasecmp(bodyType, "message") || PL_strcasecmp(bodySubType, "rfc822"))
     {
       skip_to_close_paren();
       return new nsIMAPBodypartLeaf(partNum, parentPart, bodyType, bodySubType,
-          bodyID, bodyDescription, bodyEncoding, partLength);
+                                    bodyID, bodyDescription, bodyEncoding,
+                                    partLength,
+                                    fServerConnection.GetPreferPlainText());
     }
     
     // This part is of type "message/rfc822"  (probably a forwarded message)
-    nsIMAPBodypartMessage *message = new nsIMAPBodypartMessage(partNum, parentPart, PR_FALSE,
-      bodyType, bodySubType, bodyID, bodyDescription, bodyEncoding, partLength);
+    nsIMAPBodypartMessage *message =
+      new nsIMAPBodypartMessage(partNum, parentPart, PR_FALSE,
+                                bodyType, bodySubType, bodyID, bodyDescription,
+                                bodyEncoding, partLength,
+                                fServerConnection.GetPreferPlainText());
 
     // there are three additional fields: envelope structure, bodystructure, and size in lines    
     // historical note: this code was originally in nsIMAPBodypartMessage::ParseIntoObjects()
 
     // envelope (ignored)
     if (*fNextToken == '(')
     {
       fNextToken++;
--- a/mailnews/imap/test/unit/test_dod.js
+++ b/mailnews/imap/test/unit/test_dod.js
@@ -1,105 +1,108 @@
-/*
- * Test bodystructure and body fetch by parts. Messages with problem of
- * 'This part will be downloaded on demand' in message pane content (text) area.
- * To add messages to the test, place the 'markerRe' text used for testing in the
- * offending part that is displaying the problem message.
- * Prepend to the filename 'bodystructure' and save in the database
- * See current test files for examples.
- */
-var gServer, gIMAPIncomingServer;
-function run_test()
-{
-  let IMAPDaemon = new imapDaemon();;
-  const ioS = Cc["@mozilla.org/network/io-service;1"]
-                .getService(Ci.nsIIOService);
-
-  // pref tuning: one connection only, turn off notifications
-  let prefBranch = Cc["@mozilla.org/preferences-service;1"]
-                     .getService(Ci.nsIPrefBranch);
-  prefBranch.setIntPref( "mail.server.server1.max_cached_connections", 1);
-  prefBranch.setBoolPref("mail.biff.play_sound", false);
-  prefBranch.setBoolPref("mail.biff.show_alert", false);
-  prefBranch.setBoolPref("mail.biff.show_tray_icon",    false);
-  prefBranch.setBoolPref("mail.biff.animate_dock_icon", false);
-  // Force bodypart fetching as best as we can.
-  // It would be adviseable to enable log and check to be sure body[] is not being
-  // fetched in lieu of parts. There may be conditions that bypass bodypart fetch.
-  prefBranch.setBoolPref("mail.inline_attachments",     false);
-  prefBranch.setIntPref ("browser.cache.disk.capacity",              0);
-  prefBranch.setIntPref ("mail.imap.mime_parts_on_demand_threshold", 1);
-  prefBranch.setIntPref ("mailnews.display.disallow_mime_handlers",  0);
-  prefBranch.setBoolPref("mail.server.default.fetch_by_chunks",  false);
-
-  gServer = makeServer(IMAPDaemon, "");
-  gIMAPIncomingServer = createLocalIMAPServer();
-  let inbox = IMAPDaemon.getMailbox("INBOX");
-  let imapS = Cc["@mozilla.org/messenger/messageservice;1?type=imap"]
-                .getService(Ci.nsIMsgMessageService);
-
-  do_test_pending();
-  do_timeout(10000, function(){
-    do_throw('Tests did not complete within 10 seconds. ABORTING.');
-    }
-  );
-
-  let fileNames = [];
-  let msgFiles = do_get_file("../../../data/").directoryEntries;
-  while (msgFiles.hasMoreElements()) {
-    let file = msgFiles.getNext();
-    let msgfileuri = ioS.newFileURI(file).QueryInterface(Ci.nsIFileURL);
-    if (/^bodystructure/i.test(msgfileuri.fileName)) {
-      inbox.addMessage(new imapMessage(msgfileuri.spec, inbox.uidnext++, []));
-      fileNames.push(msgfileuri.fileName);
-    }
-  }
-
-  // loop through the files twice, once for plain and one for html check
-  let isPlain = true;
-  for (let cnt = 2 ; cnt > 0 ; cnt--, isPlain = false) {
-    // adjust these for 'view body as' setting
-    // 0 orig html 3 sanitized 1 plain text
-    prefBranch.setIntPref ("mailnews.display.html_as", isPlain ? 1 : 0);
-    prefBranch.setBoolPref("mailnews.display.prefer_plaintext", isPlain);
-    let markerRe;
-    if (isPlain)
-      markerRe = /thisplaintextneedstodisplaytopasstest/;
-    else
-      markerRe = /thishtmltextneedstodisplaytopasstest/;
-
-    for (let i = 1; i < inbox.uidnext ; i++) {
-      let uri = {};
-      imapS.GetUrlForUri("imap-message://user@localhost/INBOX#" + i,uri,null);
-      uri.value.spec += "?header=quotebody";
-      let channel = ioS.newChannelFromURI(uri.value);
-      let inStream = channel.open();
-      let scriptableInStream = Cc["@mozilla.org/scriptableinputstream;1"]
-                 .createInstance(Ci.nsIScriptableInputStream);
-      scriptableInStream.init(inStream);
-      let availableCount;
-      let buf = "";
-      while(availableCount =  scriptableInStream.available()) {
-        buf += scriptableInStream.read(availableCount);
-      }
-      dump("##########\nTesting--->" + fileNames[i-1] +
-           "; 'prefer plain text': " + isPlain + "\n" +
-           buf + "\n" +
-           "##########\nTesting--->" + fileNames[i-1] +
-           "; 'prefer plain text': " + isPlain + "\n");
-      try {
-        do_check_true(markerRe.test(buf));
-       }
-      catch(e){}
-    }
-  }
-  do_timeout_function(700, endTest);
-}
-
-function endTest()
-{
-  gIMAPIncomingServer.closeCachedConnections();
-  gServer.stop();
-  let thread = gThreadManager.currentThread;
-  while (thread.hasPendingEvents())
-    thread.processNextEvent(true);
-  do_test_finished();
-}
+/*
+ * Test bodystructure and body fetch by parts. Messages with problem of
+ * 'This part will be downloaded on demand' in message pane content (text) area.
+ * To add messages to the test, place the 'markerRe' text used for testing in
+ * the offending part that is displaying the problem message.
+ * Prepend to the filename 'bodystructure' and save in the database
+ * See current test files for examples.
+ */
+var gServer, gIMAPIncomingServer;
+
+function run_test()
+{
+  let IMAPDaemon = new imapDaemon();
+  const ioS = Cc["@mozilla.org/network/io-service;1"]
+                .getService(Ci.nsIIOService);
+
+  // pref tuning: one connection only, turn off notifications
+  let prefBranch = Cc["@mozilla.org/preferences-service;1"]
+                     .getService(Ci.nsIPrefBranch);
+  prefBranch.setIntPref( "mail.server.server1.max_cached_connections", 1);
+  prefBranch.setBoolPref("mail.biff.play_sound", false);
+  prefBranch.setBoolPref("mail.biff.show_alert", false);
+  prefBranch.setBoolPref("mail.biff.show_tray_icon",    false);
+  prefBranch.setBoolPref("mail.biff.animate_dock_icon", false);
+
+  // Force bodypart fetching as best as we can.
+  // It would be adviseable to enable log and check to be sure body[] is not
+  // being fetched in lieu of parts. There may be conditions that bypass
+  // bodypart fetch.
+  prefBranch.setBoolPref("mail.inline_attachments",     false);
+  prefBranch.setIntPref ("browser.cache.disk.capacity",              0);
+  prefBranch.setIntPref ("mail.imap.mime_parts_on_demand_threshold", 1);
+  prefBranch.setIntPref ("mailnews.display.disallow_mime_handlers",  0);
+  prefBranch.setBoolPref("mail.server.default.fetch_by_chunks",  false);
+  prefBranch.setBoolPref("mail.server.server1.autosync_offline_stores", false);
+
+  gServer = makeServer(IMAPDaemon, "");
+  gIMAPIncomingServer = createLocalIMAPServer();
+  let inbox = IMAPDaemon.getMailbox("INBOX");
+  let imapS = Cc["@mozilla.org/messenger/messageservice;1?type=imap"]
+                .getService(Ci.nsIMsgMessageService);
+
+  do_test_pending();
+  do_timeout(10000, function() {
+    do_throw('Tests did not complete within 10 seconds. ABORTING.');
+  });
+
+  let fileNames = [];
+  let msgFiles = do_get_file("../../../data/").directoryEntries;
+  while (msgFiles.hasMoreElements()) {
+    let file = msgFiles.getNext();
+    let msgfileuri = ioS.newFileURI(file).QueryInterface(Ci.nsIFileURL);
+    if (/^bodystructure/i.test(msgfileuri.fileName)) {
+      inbox.addMessage(new imapMessage(msgfileuri.spec, inbox.uidnext++, []));
+      fileNames.push(msgfileuri.fileName);
+    }
+  }
+
+  // loop through the files twice, once for plain and one for html check
+  let isPlain = true;
+  for (let cnt = 2 ; cnt > 0 ; cnt--, isPlain = false) {
+    // adjust these for 'view body as' setting
+    // 0 orig html 3 sanitized 1 plain text
+    prefBranch.setIntPref ("mailnews.display.html_as", isPlain ? 1 : 0);
+    prefBranch.setBoolPref("mailnews.display.prefer_plaintext", isPlain);
+    let markerRe;
+    if (isPlain)
+      markerRe = /thisplaintextneedstodisplaytopasstest/;
+    else
+      markerRe = /thishtmltextneedstodisplaytopasstest/;
+
+    for (let i = 1; i < inbox.uidnext ; i++) {
+      let uri = {};
+      imapS.GetUrlForUri("imap-message://user@localhost/INBOX#" + i,uri,null);
+      uri.value.spec += "?header=quotebody";
+      let channel = ioS.newChannelFromURI(uri.value);
+      let inStream = channel.open();
+      let scriptableInStream = Cc["@mozilla.org/scriptableinputstream;1"]
+                 .createInstance(Ci.nsIScriptableInputStream);
+      scriptableInStream.init(inStream);
+      let availableCount;
+      let buf = "";
+      while ((availableCount = scriptableInStream.available())) {
+        buf += scriptableInStream.read(availableCount);
+      }
+      dump("##########\nTesting--->" + fileNames[i-1] +
+           "; 'prefer plain text': " + isPlain + "\n" +
+           buf + "\n" +
+           "##########\nTesting--->" + fileNames[i-1] +
+           "; 'prefer plain text': " + isPlain + "\n");
+      try {
+        do_check_true(markerRe.test(buf));
+      }
+      catch(e){}
+    }
+  }
+  do_timeout_function(700, endTest);
+}
+
+function endTest()
+{
+  gIMAPIncomingServer.closeCachedConnections();
+  gServer.stop();
+  let thread = gThreadManager.currentThread;
+  while (thread.hasPendingEvents())
+    thread.processNextEvent(true);
+  do_test_finished();
+}