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 }