Thread

mozilla/ mailnews/ db/ msgdb/ src/ nsMsgDatabase.cpp
3430 nsresult nsMsgDatabase::ThreadNewHdr(nsMsgHdr* newHdr, PRBool &newThread)
3431 {
3432     nsresult result=NS_ERROR_UNEXPECTED;
3433     nsCOMPtr <nsIMsgThread> thread;
3434     nsCOMPtr <nsIMsgDBHdr> replyToHdr;
3435     nsMsgKey threadId = nsMsgKey_None;
3436 
3437     if (!newHdr)
3438         return NS_ERROR_NULL_POINTER;
3439 
3440     PRUint16 numReferences = 0;
3441     PRUint32 newHdrFlags = 0;
3442 
3443     newHdr->GetFlags(&newHdrFlags);
3444     newHdr->GetNumReferences(&numReferences);
3445 
3446 #define SUBJ_THREADING 1// try reference threading first
3447     for (PRInt32 i = numReferences - 1; i >= 0;  i--)
3448     {
3449         nsCAutoString reference;
3450 
3451         newHdr->GetStringReference(i, reference);
3452         // first reference we have hdr for is best top-level hdr.
3453         // but we have to handle case of promoting new header to top-level
3454         // in case the top-level header comes after a reply.
3455 
3456         if (reference.Length() == 0)
3457             break;
3458 
3459         thread = getter_AddRefs(GetThreadForReference(reference, getter_AddRefs(replyToHdr))) ;
3460         if (thread)
3461         {
3462             thread->GetThreadKey(&threadId);
3463             newHdr->SetThreadId(threadId);
3464             result = AddToThread(newHdr, thread, replyToHdr, PR_TRUE);
3465             break;
3466         }
3467     }
3468 #ifdef SUBJ_THREADING
3469     // try subject threading if we couldn't find a reference and the subject starts with Re:
3470     nsXPIDLCString subject;
3471 
3472     newHdr->GetSubject(getter_Copies(subject));
3473     if ((ThreadBySubjectWithoutRe() || (newHdrFlags & MSG_FLAG_HAS_RE)) && (!thread))
3474     {
3475         nsCAutoString cSubject(subject);
3476         thread = getter_AddRefs(GetThreadForSubject(cSubject));
3477         if(thread)
3478         {
3479             thread->GetThreadKey(&threadId);
3480             newHdr->SetThreadId(threadId);
3481             //TRACE("threading based on subject %s\n", (const char *) msgHdr->m_subject);
3482             // if we move this and do subject threading after, ref threading, 
3483             // don't thread within children, since we know it won't work. But for now, pass TRUE.
3484             result = AddToThread(newHdr, thread, nsnull, PR_TRUE);     
3485         }
3486     }
3487 #endif // SUBJ_THREADING
3488 
3489     if (!thread)
3490     {
3491         // couldn't find any parent articles - msgHdr is top-level thread, for now
3492         result = AddNewThread(newHdr);
3493         newThread = PR_TRUE;
3494     }
3495     else
3496     {
3497         newThread = PR_FALSE;
3498     }
3499     return result;
3500 }
3337 nsIMsgThread *nsMsgDatabase::GetThreadForReference(nsCString &msgID, nsIMsgDBHdr **pMsgHdr)
3338 {
3339   nsIMsgDBHdr   *msgHdr = nsnull;
3340   GetMsgHdrForMessageID(msgID.get(), &msgHdr);  
3341   nsIMsgThread *thread = NULL;
3342   
3343   if (msgHdr != NULL)
3344   {
3345     nsMsgKey threadId;
3346     if (NS_SUCCEEDED(msgHdr->GetThreadId(&threadId)))
3347     {
3348       // find thread header for header whose message id we matched.
3349       thread = GetThreadForThreadId(threadId);
3350     }
3351     if (pMsgHdr)
3352       *pMsgHdr = msgHdr;
3353     else
3354       msgHdr->Release();
3355   }
3356   return thread;
3357 }
3515 NS_IMETHODIMP nsMsgDatabase::GetMsgHdrForMessageID(const char *msgID, nsIMsgDBHdr **aHdr)
3516 {
3517   NS_ENSURE_ARG_POINTER(aHdr);
3518   nsIMsgDBHdr   *msgHdr = nsnull;
3519   nsresult rv = NS_OK;
3520   mdbYarn   messageIdYarn;
3521 
3522   messageIdYarn.mYarn_Buf = (void *) msgID;
3523   messageIdYarn.mYarn_Fill = PL_strlen(msgID);
3524   messageIdYarn.mYarn_Form = 0;
3525   messageIdYarn.mYarn_Size = messageIdYarn.mYarn_Fill;
3526 
3527   nsIMdbRow *hdrRow;
3528   mdbOid        outRowId;
3529   mdb_err result = GetStore()->FindRow(GetEnv(), m_hdrRowScopeToken,
3530       m_messageIdColumnToken, &messageIdYarn,  &outRowId, 
3531       &hdrRow);
3532   if (NS_SUCCEEDED(result) && hdrRow)
3533   {
3534       //Get key from row
3535       mdbOid outOid;
3536       nsMsgKey key=0;
3537       if (hdrRow->GetOid(GetEnv(), &outOid) == NS_OK)
3538           key = outOid.mOid_Id;
3539       rv = GetHdrFromUseCache(key, &msgHdr);
3540       if (NS_SUCCEEDED(rv) && msgHdr)
3541           hdrRow->Release();
3542       else
3543           rv = CreateMsgHdr(hdrRow, key, &msgHdr);
3544   }
3545   NS_IF_ADDREF(*aHdr = msgHdr);
3546   return NS_OK; // it's not an error not to find a msg hdr.
3547 }
3611 // caller needs to unrefer.
3612 nsIMsgThread *  nsMsgDatabase::GetThreadForThreadId(nsMsgKey threadId)
3613 {
3614   
3615   if (threadId == m_cachedThreadId && m_cachedThread)
3616   {
3617     nsIMsgThread *retThread = m_cachedThread;
3618     NS_ADDREF(retThread);
3619     return retThread;
3620   }
3621   nsMsgThread *pThread = nsnull;
3622   if (m_mdbStore)
3623   {
3624     mdbOid tableId;
3625     tableId.mOid_Id = threadId;
3626     tableId.mOid_Scope = m_hdrRowScopeToken;
3627     
3628     nsIMdbTable *threadTable;
3629     mdb_err res = m_mdbStore->GetTable(GetEnv(), &tableId, &threadTable);
3630     
3631     if (NS_SUCCEEDED(res) && threadTable)
3632     {
3633       pThread = new nsMsgThread(this, threadTable);
3634       if(pThread)
3635       {
3636         NS_ADDREF(pThread);
3637         m_cachedThread = pThread;
3638         m_cachedThreadId = threadId;
3639       }
3640     }
3641   }
3642   return pThread;
3643 }
3645 // make the passed in header a thread header
3646 nsresult nsMsgDatabase::AddNewThread(nsMsgHdr *msgHdr)
3647 {
3648   
3649   if (!msgHdr)
3650     return NS_ERROR_NULL_POINTER;
3651   
3652   nsMsgThread *threadHdr = nsnull;
3653   
3654   nsXPIDLCString subject;
3655   nsMsgKey threadKey = msgHdr->m_messageKey;
3656   // can't have a thread with key 1 since that's the table id of the all msg hdr table,
3657   // so give it kTableKeyForThreadOne (0xfffffffe).
3658   if (threadKey == 1)
3659     threadKey = kTableKeyForThreadOne;
3660 
3661   nsresult err = msgHdr->GetSubject(getter_Copies(subject));
3662   
3663   err = CreateNewThread(threadKey, subject, &threadHdr);
3664   msgHdr->SetThreadId(threadKey);
3665   if (threadHdr)
3666   {
3667     //      nsCString subject;
3668     
3669     threadHdr->AddRef();
3670     //      err = msgHdr->GetSubject(subject);
3671     //      threadHdr->SetThreadKey(msgHdr->m_messageKey);
3672     //      threadHdr->SetSubject(subject.get());
3673     
3674     // need to add the thread table to the db.
3675     AddToThread(msgHdr, threadHdr, nsnull, PR_FALSE);
3676     
3677     threadHdr->Release();
3678   }
3679   return err;
3680 }
3292 nsresult nsMsgDatabase::CreateNewThread(nsMsgKey threadId, const char *subject, nsMsgThread **pnewThread)
3293 {
3294   nsresult  err = NS_OK;
3295   nsIMdbTable       *threadTable;
3296   struct mdbOid threadTableOID;
3297   struct mdbOid allThreadsTableOID;
3298   
3299   if (!pnewThread || !m_mdbStore)
3300     return NS_ERROR_NULL_POINTER;
3301   
3302   threadTableOID.mOid_Scope = m_hdrRowScopeToken;
3303   threadTableOID.mOid_Id = threadId;
3304   
3305   err  = GetStore()->NewTableWithOid(GetEnv(), &threadTableOID, m_threadTableKindToken, 
3306     PR_FALSE, nsnull, &threadTable);
3307   if (NS_FAILED(err)) 
3308     return err;
3309   
3310   allThreadsTableOID.mOid_Scope = m_threadRowScopeToken;
3311   allThreadsTableOID.mOid_Id = threadId;    
3312   
3313   // add a row for this thread in the table of all threads that we'll use
3314   // to do our mapping between subject strings and threads.
3315   nsIMdbRow *threadRow = nsnull;
3316   
3317   err = m_mdbStore->GetRow(GetEnv(), &allThreadsTableOID, &threadRow);
3318   if (!threadRow)   
3319   {
3320     err  = m_mdbStore->NewRowWithOid(GetEnv(), &allThreadsTableOID, &threadRow);
3321     if (NS_SUCCEEDED(err) && threadRow)
3322     {
3323       if (m_mdbAllThreadsTable)
3324         m_mdbAllThreadsTable->AddRow(GetEnv(), threadRow);
3325       err = CharPtrToRowCellColumn(threadRow, m_threadSubjectColumnToken, subject);
3326       threadRow->Release();
3327     }
3328   }
3329   
3330   *pnewThread = new nsMsgThread(this, threadTable);
3331   if (*pnewThread)
3332     (*pnewThread)->SetThreadKey(threadId);
3333   return err;
3334 }