try to fix some corrupt thread issues, r=standard8, sr=neil, 457052
authorDavid Bienvenu <bienvenu@nventure.com>
Mon, 20 Oct 2008 15:50:53 -0700
changeset 654 3795036c606778c6e9c3ad0a892d23202907e56c
parent 653 35e3e61336a8b62315614f1471a963890da0c8c9
child 656 f74e5af1cf6047bd3b5e5986f120b97dea16134c
push idunknown
push userunknown
push dateunknown
reviewersstandard8, neil, 457052
bugs457052
try to fix some corrupt thread issues, r=standard8, sr=neil, 457052
mailnews/db/msgdb/src/nsMsgHdr.cpp
mailnews/db/msgdb/src/nsMsgThread.cpp
--- a/mailnews/db/msgdb/src/nsMsgHdr.cpp
+++ b/mailnews/db/msgdb/src/nsMsgHdr.cpp
@@ -874,17 +874,17 @@ void nsMsgHdr::ReparentInThread(nsIMsgTh
   // bail out early for the singleton thread case.
   if (numChildren == 1)
   {
     SetThreadParent(nsMsgKey_None);
     return;
   }
   else
   {
-    nsCOMPtr <nsIMsgDBHdr> curHdr;
+    nsCOMPtr<nsIMsgDBHdr> curHdr;
     // loop through thread, looking for our proper parent.
     for (PRUint32 childIndex = 0; childIndex < numChildren; childIndex++)
     {
       thread->GetChildHdrAt(childIndex, getter_AddRefs(curHdr));
       // closed system, cast ok
       nsMsgHdr* curMsgHdr = static_cast<nsMsgHdr*>(curHdr.get());
       if (curHdr && curMsgHdr->IsParentOf(this))
       {
@@ -892,17 +892,17 @@ void nsMsgHdr::ReparentInThread(nsIMsgTh
         curHdr->GetMessageKey(&curHdrKey);
         SetThreadParent(curHdrKey);
         return;
       }
     }
     // we didn't find it. So either the root header is our parent,
     // or we're the root.
     PRInt32 rootIndex;
-    nsCOMPtr <nsIMsgDBHdr> rootHdr;
+    nsCOMPtr<nsIMsgDBHdr> rootHdr;
     thread->GetRootHdr(&rootIndex, getter_AddRefs(rootHdr));
     NS_ASSERTION(rootHdr, "thread has no root hdr - shouldn't happen");
     if (rootHdr)
     {
       nsMsgKey rootKey;
       rootHdr->GetMessageKey(&rootKey);
       // if we're the root, our thread parent is -1.
       SetThreadParent(rootKey == m_messageKey ? nsMsgKey_None : rootKey);
@@ -920,26 +920,28 @@ PRBool nsMsgHdr::IsAncestorKilled(PRUint
   {
     nsMsgKey threadParent;
     GetThreadParent(&threadParent);
 
     if (threadParent == m_messageKey)
     {
       // isKilled is false by virtue of the enclosing if statement
       NS_ERROR("Thread is parent of itself, please fix!");
-
+      nsCOMPtr<nsIMsgThread> thread;
+      (void) m_mdb->GetThreadContainingMsgHdr(this, getter_AddRefs(thread));
+      ReparentInThread(thread);
       // Something's wrong, but the problem happened some time ago, so erroring
       // out now is probably not a good idea. Ergo, we'll pretend to be OK, show
       // the user the thread (err on the side of caution), and let the assertion
       // alert debuggers to a problem.
       return PR_FALSE;
     }
     if (threadParent != nsMsgKey_None)
     {
-      nsCOMPtr <nsIMsgDBHdr> parentHdr;
+      nsCOMPtr<nsIMsgDBHdr> parentHdr;
       (void) m_mdb->GetMsgHdrForKey(threadParent, getter_AddRefs(parentHdr));
 
       if (parentHdr)
       {
         // More proofing against crashers. This crasher was derived from the
         // fact that something got borked, leaving is in hand with a circular
         // reference to borked headers inducing these loops. The defining
         // characteristic of these headers is that they don't actually seat
--- a/mailnews/db/msgdb/src/nsMsgThread.cpp
+++ b/mailnews/db/msgdb/src/nsMsgThread.cpp
@@ -915,34 +915,51 @@ nsresult nsMsgThread::ReparentMsgsWithIn
 
       curChild->GetThreadParent(&parentKey);
 
       if (parentKey != nsMsgKey_None)
       {
         GetChild(parentKey, getter_AddRefs(parent));
         if (!parent)
           curChild->SetThreadParent(threadParentKey);
+        else
+        {
+          nsMsgKey childKey;
+          curChild->GetMessageKey(&childKey);
+          // can't be your own parent; set parent to thread parent,
+          // or make ourselves the root if we are the root.
+          if (childKey == parentKey)
+            curChild->SetThreadParent(m_threadRootKey == childKey ? 
+                                      nsMsgKey_None : m_threadRootKey);
+        }
       }
     }
   }
   return rv;
 }
 
 NS_IMETHODIMP nsMsgThread::GetRootHdr(PRInt32 *resultIndex, nsIMsgDBHdr **result)
 {
   NS_ENSURE_ARG_POINTER(result);
 
   *result = nsnull;
 
   if (m_threadRootKey != nsMsgKey_None)
   {
     nsresult rv = GetChildHdrForKey(m_threadRootKey, result, resultIndex);
     if (NS_SUCCEEDED(rv) && *result)
-      return rv;
-#ifdef DEBUG_bienvenu
+    {
+      // check that we're really the root key.
+      nsMsgKey parentKey;
+      (*result)->GetThreadParent(&parentKey);
+      if (parentKey == nsMsgKey_None)
+        return rv;
+      NS_RELEASE(*result);
+    }
+#ifdef DEBUG_David_Bienvenu
     printf("need to reset thread root key\n");
 #endif
     PRUint32 numChildren;
     nsMsgKey threadParentKey = nsMsgKey_None;
     GetNumChildren(&numChildren);
 
     for (PRInt32 childIndex = 0; childIndex < (PRInt32) numChildren; childIndex++)
     {
@@ -950,18 +967,22 @@ NS_IMETHODIMP nsMsgThread::GetRootHdr(PR
       rv  = GetChildHdrAt(childIndex, getter_AddRefs(curChild));
       if (NS_SUCCEEDED(rv) && curChild)
       {
         nsMsgKey parentKey;
 
         curChild->GetThreadParent(&parentKey);
         if (parentKey == nsMsgKey_None)
         {
-          NS_ASSERTION(!(*result), "two top level msgs, not good");
           curChild->GetMessageKey(&threadParentKey);
+          if (*result)
+          {
+            NS_WARNING("two top level msgs, not good");
+            continue;
+          }
           SetThreadRootKey(threadParentKey);
           if (resultIndex)
             *resultIndex = childIndex;
           NS_ADDREF(*result = curChild);
           ReparentMsgsWithInvalidParent(numChildren, threadParentKey);
           //            return NS_OK;
         }
       }
@@ -1049,18 +1070,26 @@ nsresult nsMsgThread::GetChildHdrForKey(
       {
         nsMsgKey threadKey;
         (*result)->GetThreadId(&threadKey);
         if (threadKey != m_threadKey) // this msg isn't in this thread
         {
           PRUint32 msgSize;
           (*result)->GetMessageSize(&msgSize);
           if (msgSize == 0) // this is a phantom message - let's get rid of it.
+          {
             RemoveChild(msgKey);
-          rv = NS_ERROR_UNEXPECTED;
+            rv = NS_ERROR_UNEXPECTED;
+          }
+          else
+          {
+            // otherwise, this message really appears to be in this
+            // thread, so fix up its thread id.
+            (*result)->SetThreadId(threadKey);
+          }
         }
         break;
       }
       NS_RELEASE(*result);
     }
   }
   if (resultIndex)
     *resultIndex = childIndex;