This commit is contained in:
bienvenu%netscape.com 1999-07-13 18:43:04 +00:00
Родитель 59bd4dcba6
Коммит d0e76290e4
16 изменённых файлов: 331 добавлений и 72 удалений

Просмотреть файл

@ -16,7 +16,6 @@
# This is a list of local files which get copied to the mozilla:dist:mailnews directory
#
nsIMsgDatabase.h
nsINewsDatabase.h
nsMsgDatabase.h
nsMailDatabase.h

Просмотреть файл

@ -26,7 +26,6 @@ include $(DEPTH)/config/autoconf.mk
EXPORTS= \
nsMsgHdr.h \
nsIMsgDatabase.h \
nsINewsDatabase.h \
nsMsgDatabase.h \
nsMailDatabase.h \
@ -40,6 +39,7 @@ XPIDLSRCS = \
nsIDBFolderInfo.idl \
nsIDBChangeListener.idl \
nsIDBChangeAnnouncer.idl \
nsIMsgDatabase.idl \
$(NULL)
include $(topsrcdir)/config/config.mk

Просмотреть файл

@ -22,13 +22,13 @@ XPIDLSRCS = \
.\nsIDBFolderInfo.idl \
.\nsIDBChangeListener.idl \
.\nsIDBChangeAnnouncer.idl \
.\nsIMsgDatabase.idl \
$(NULL)
################################################################################
## exports
EXPORTS = \
nsIMsgDatabase.h \
nsINewsDatabase.h \
nsMsgDatabase.h \
nsMailDatabase.h \

Просмотреть файл

Просмотреть файл

@ -29,7 +29,7 @@ public:
nsImapMailDatabase();
virtual ~nsImapMailDatabase();
NS_IMETHOD Open(nsIFileSpec *folderName, PRBool create, nsIMsgDatabase** pMessageDB, PRBool upgrading /*=PR_FALSE*/);
NS_IMETHOD Open(nsIFileSpec *folderName, PRBool create, PRBool upgrading, nsIMsgDatabase** pMessageDB);
NS_IMETHOD SetSummaryValid(PRBool valid = TRUE);

Просмотреть файл

@ -40,8 +40,7 @@ class nsMailDatabase : public nsMsgDatabase
public:
nsMailDatabase();
virtual ~nsMailDatabase();
NS_IMETHOD Open(nsIFileSpec *aFolderName, PRBool create, nsIMsgDatabase** pMessageDB,
PRBool upgrading = PR_FALSE);
NS_IMETHOD Open(nsIFileSpec *aFolderName, PRBool create, PRBool upgrading, nsIMsgDatabase** pMessageDB);
static nsresult CloneInvalidDBInfoIntoNewDB(nsFileSpec &pathName, nsMailDatabase** pMailDB);

Просмотреть файл

@ -58,7 +58,7 @@ public:
//////////////////////////////////////////////////////////////////////////////
// nsIMsgDatabase methods:
NS_IMETHOD Open(nsIFileSpec *folderName, PRBool create, nsIMsgDatabase** pMessageDB, PRBool upgrading);
NS_IMETHOD Open(nsIFileSpec *folderName, PRBool create, PRBool upgrading, nsIMsgDatabase** pMessageDB);
NS_IMETHOD Close(PRBool forceCommit);
// argh, these two shouldn't be Interface methods, but I can't diddle the interfaces
@ -66,7 +66,7 @@ public:
NS_IMETHOD OpenMDB(const char *dbName, PRBool create);
NS_IMETHOD CloseMDB(PRBool commit);
NS_IMETHOD Commit(nsMsgDBCommitType commitType);
NS_IMETHOD Commit(nsMsgDBCommit commitType);
// Force closed is evil, and we should see if we can do without it.
// In 4.x, it was mainly used to remove corrupted databases.
NS_IMETHOD ForceClosed(void);
@ -128,9 +128,9 @@ public:
NS_IMETHOD MarkHasAttachments(nsMsgKey key, PRBool bHasAttachments,
nsIDBChangeListener *instigator);
NS_IMETHOD MarkThreadIgnored(nsThreadMessageHdr *thread, nsMsgKey threadKey, PRBool bIgnored,
NS_IMETHOD MarkThreadIgnored(nsIMsgThread *thread, nsMsgKey threadKey, PRBool bIgnored,
nsIDBChangeListener *instigator);
NS_IMETHOD MarkThreadWatched(nsThreadMessageHdr *thread, nsMsgKey threadKey, PRBool bWatched,
NS_IMETHOD MarkThreadWatched(nsIMsgThread *thread, nsMsgKey threadKey, PRBool bWatched,
nsIDBChangeListener *instigator);
NS_IMETHOD IsRead(nsMsgKey key, PRBool *pRead);
@ -157,7 +157,7 @@ public:
nsIDBChangeListener *instigator);
// returns NS_OK on success, NS_COMFALSE on failure
NS_IMETHOD AllMsgKeysImapDeleted(const nsMsgKeyArray *keys);
NS_IMETHOD AllMsgKeysImapDeleted(nsMsgKeyArray *keys);
NS_IMETHOD MarkImapDeleted(nsMsgKey key, PRBool deleted,
nsIDBChangeListener *instigator);
@ -199,8 +199,8 @@ public:
//helper function to fill in nsStrings from hdr row cell contents.
nsresult RowCellColumnTonsString(nsIMdbRow *row, mdb_token columnToken, nsString &resultStr);
nsresult RowCellColumnToUInt32(nsIMdbRow *row, mdb_token columnToken, PRUint32 *uint32Result);
nsresult RowCellColumnToUInt32(nsIMdbRow *row, mdb_token columnToken, PRUint32 &uint32Result);
nsresult RowCellColumnToUInt32(nsIMdbRow *row, mdb_token columnToken, PRUint32 *uint32Result, PRUint32 defaultValue = 0);
nsresult RowCellColumnToUInt32(nsIMdbRow *row, mdb_token columnToken, PRUint32 &uint32Result, PRUint32 defaultValue = 0);
nsresult RowCellColumnToMime2EncodedString(nsIMdbRow *row, mdb_token columnToken, nsString &resultStr);
nsresult RowCellColumnToCollationKey(nsIMdbRow *row, mdb_token columnToken, nsString &resultStr);
@ -241,7 +241,6 @@ protected:
nsMsgHdr * GetMsgHdrForReference(nsString2 &reference);
nsIMsgDBHdr * GetMsgHdrForMessageID(nsString2 &msgID);
nsIMsgDBHdr * GetMsgHdrForSubject(nsString2 &msgID);
nsMsgThread * GetThreadContainingMsgHdr(nsMsgHdr *msgHdr);
// threading interfaces
virtual nsresult CreateNewThread(nsMsgKey key, const char *subject, nsMsgThread **newThread);
virtual PRBool ThreadBySubjectWithoutRe();
@ -319,6 +318,7 @@ protected:
mdb_token m_numReferencesColumnToken;
mdb_token m_messageCharSetColumnToken;
mdb_token m_threadParentColumnToken;
mdb_token m_threadRootKeyColumnToken;
nsIMsgHeaderParser *m_HeaderParser;
};

Просмотреть файл

@ -102,6 +102,7 @@ public:
NS_DECL_ISUPPORTS
nsIMdbRow *GetMDBRow() {return m_mdbRow;}
PRBool IsParentOf(nsIMsgDBHdr *possibleChild);
protected:
nsresult SetStringColumn(const char *str, mdb_token token);
nsresult SetUInt32Column(PRUint32 value, mdb_token token);

Просмотреть файл

@ -34,6 +34,8 @@ public:
nsMsgThread(nsMsgDatabase *db, nsIMdbTable *table);
virtual ~nsMsgThread();
friend class nsMsgThreadEnumerator;
NS_DECL_ISUPPORTS
NS_IMETHOD SetThreadKey(nsMsgKey threadKey);
@ -52,6 +54,7 @@ public:
NS_IMETHOD RemoveChildHdr(nsIMsgDBHdr *child);
NS_IMETHOD MarkChildRead(PRBool bRead);
NS_IMETHOD EnumerateMessages(nsMsgKey parent, nsIEnumerator* *result);
NS_IMETHOD GetRootHdr(PRInt32 *resultIndex, nsIMsgDBHdr **result);
// non-interface methods
PRBool TryReferenceThreading(nsIMsgDBHdr *newHeader);
@ -66,6 +69,10 @@ protected:
nsresult ChangeChildCount(PRInt32 delta);
nsresult ChangeUnreadChildCount(PRInt32 delta);
nsresult RemoveChild(nsMsgKey msgKey);
nsresult SetThreadRootKey(nsMsgKey threadRootKey);
nsresult GetChildHdrForKey(nsMsgKey desiredKey,
nsIMsgDBHdr **result, PRInt32 *resultIndex);
nsMsgKey m_threadKey;
PRUint32 m_numChildren;
@ -74,7 +81,7 @@ protected:
nsIMdbTable *m_mdbTable;
nsIMdbRow *m_metaRow;
PRBool m_cachedValuesInitialized;
nsMsgKey m_threadRootKey;
};
#endif

Просмотреть файл

@ -37,10 +37,10 @@ public:
virtual nsresult MessageDBOpenUsingURL(const char * groupURL);
char *GetGroupURL() { return m_groupURL; }
NS_IMETHOD Open(nsIFileSpec *newsgroupName, PRBool create, nsIMsgDatabase** pMessageDB, PRBool upgrading /*=PR_FALSE*/);
NS_IMETHOD Open(nsIFileSpec *newsgroupName, PRBool create, PRBool upgrading, nsIMsgDatabase** pMessageDB);
NS_IMETHOD Close(PRBool forceCommit);
NS_IMETHOD ForceClosed();
NS_IMETHOD Commit(nsMsgDBCommitType commitType);
NS_IMETHOD Commit(nsMsgDBCommit commitType);
virtual PRUint32 GetCurVersion();
// methods to get and set docsets for ids.

Просмотреть файл

@ -29,7 +29,7 @@ nsImapMailDatabase::~nsImapMailDatabase()
{
}
NS_IMETHODIMP nsImapMailDatabase::Open(nsIFileSpec *aFolderName, PRBool create, nsIMsgDatabase** pMessageDB, PRBool upgrading /*=PR_FALSE*/)
NS_IMETHODIMP nsImapMailDatabase::Open(nsIFileSpec *aFolderName, PRBool create, PRBool upgrading, nsIMsgDatabase** pMessageDB)
{
nsImapMailDatabase *mailDB;
PRBool summaryFileExists;

Просмотреть файл

@ -38,7 +38,7 @@ nsMailDatabase::~nsMailDatabase()
NS_IMETHODIMP nsMailDatabase::Open(nsIFileSpec *aFolderName, PRBool create, nsIMsgDatabase** pMessageDB, PRBool upgrading /*=PR_FALSE*/)
NS_IMETHODIMP nsMailDatabase::Open(nsIFileSpec *aFolderName, PRBool create, PRBool upgrading, nsIMsgDatabase** pMessageDB)
{
nsMailDatabase *mailDB;
PRBool summaryFileExists;
@ -485,7 +485,7 @@ nsresult nsMailDatabase::SetFolderInfoValid(nsFileSpec *folderName, int num, int
}
else if (pMessageDB)
{
err = pMessageDB->Commit(kSessionCommit);
err = pMessageDB->Commit(nsMsgDBCommitType::kSessionCommit);
pMessageDB->Release();
}
return err;
@ -501,7 +501,7 @@ void nsMailDatabase::SetReparse(PRBool reparse)
static PRBool gGotThreadingPrefs = PR_FALSE;
static PRBool gThreadWithoutRe = PR_FALSE;
static PRBool gThreadWithoutRe = PR_TRUE;
// should we thread messages with common subjects that don't start with Re: together?
@ -514,6 +514,7 @@ PRBool nsMailDatabase::ThreadBySubjectWithoutRe()
gGotThreadingPrefs = PR_TRUE;
}
gThreadWithoutRe = PR_TRUE; // we need to this to be true for now.
return gThreadWithoutRe;
}

Просмотреть файл

@ -302,6 +302,7 @@ nsMsgDatabase::nsMsgDatabase()
m_numReferencesColumnToken(0),
m_messageCharSetColumnToken(0),
m_threadParentColumnToken(0),
m_threadRootKeyColumnToken(0),
m_HeaderParser(nsnull)
{
NS_INIT_REFCNT();
@ -495,7 +496,7 @@ void nsMsgDatabase::NativeToUnix(char*& ioPath)
}
#endif /* XP_MAC */
NS_IMETHODIMP nsMsgDatabase::Open(nsIFileSpec *folderName, PRBool create, nsIMsgDatabase** pMessageDB, PRBool upgrading /*=PR_FALSE*/)
NS_IMETHODIMP nsMsgDatabase::Open(nsIFileSpec *folderName, PRBool create, PRBool upgrading, nsIMsgDatabase** pMessageDB)
{
NS_ASSERTION(FALSE, "must override");
return NS_ERROR_NOT_IMPLEMENTED;
@ -620,7 +621,7 @@ NS_IMETHODIMP nsMsgDatabase::OpenMDB(const char *dbName, PRBool create)
NS_IMETHODIMP nsMsgDatabase::CloseMDB(PRBool commit)
{
if (commit)
Commit(kSessionCommit);
Commit(nsMsgDBCommitType::kSessionCommit);
return(NS_OK);
}
@ -657,28 +658,28 @@ NS_IMETHODIMP nsMsgDatabase::GetDBFolderInfo(nsIDBFolderInfo **result)
return NS_OK;
}
NS_IMETHODIMP nsMsgDatabase::Commit(nsMsgDBCommitType commitType)
NS_IMETHODIMP nsMsgDatabase::Commit(nsMsgDBCommit commitType)
{
nsresult err = NS_OK;
nsIMdbThumb *commitThumb = NULL;
commitType = kCompressCommit; // ### until incremental writing works.
commitType = nsMsgDBCommitType::kCompressCommit; // ### until incremental writing works.
if (m_mdbStore)
{
switch (commitType)
{
case kSmallCommit:
case nsMsgDBCommitType::kSmallCommit:
err = m_mdbStore->SmallCommit(GetEnv());
break;
case kLargeCommit:
case nsMsgDBCommitType::kLargeCommit:
err = m_mdbStore->LargeCommit(GetEnv(), &commitThumb);
break;
case kSessionCommit:
case nsMsgDBCommitType::kSessionCommit:
// comment out until persistence works.
err = m_mdbStore->SessionCommit(GetEnv(), &commitThumb);
break;
case kCompressCommit:
case nsMsgDBCommitType::kCompressCommit:
err = m_mdbStore->CompressCommit(GetEnv(), &commitThumb);
break;
}
@ -732,6 +733,7 @@ const char *kThreadUnreadChildrenColumnName = "unreadChildren";
const char *kThreadSubjectColumnName = "threadSubject";
const char *kMessageCharSetColumnName = "msgCharSet";
const char *kThreadParentColumnName = "threadParent";
const char *kThreadRootColumnName = "threadRoot";
struct mdbOid gAllMsgHdrsTableOID;
struct mdbOid gAllThreadsTableOID;
@ -840,6 +842,7 @@ nsresult nsMsgDatabase::InitMDBInfo()
err = GetStore()->StringToToken(GetEnv(), kAllThreadsTableKind, &m_allThreadsTableKindToken);
err = GetStore()->StringToToken(GetEnv(), kThreadHdrsScope, &m_threadRowScopeToken);
err = GetStore()->StringToToken(GetEnv(), kThreadParentColumnName, &m_threadParentColumnToken);
err = GetStore()->StringToToken(GetEnv(), kThreadRootColumnName, &m_threadRootKeyColumnToken);
if (err == NS_OK)
{
// The table of all message hdrs will have table id 1.
@ -941,7 +944,7 @@ NS_IMETHODIMP nsMsgDatabase::DeleteMessages(nsMsgKeyArray* nsMsgKeys, nsIDBChang
if (err != NS_OK)
break;
}
Commit(kSmallCommit);
Commit(nsMsgDBCommitType::kSmallCommit);
return err;
}
@ -985,7 +988,7 @@ NS_IMETHODIMP nsMsgDatabase::DeleteHeader(nsIMsgDBHdr *msg, nsIDBChangeListener
}
if (commit)
Commit(kLargeCommit); // ### dmb is this a good time to commit?
Commit(nsMsgDBCommitType::kLargeCommit); // ### dmb is this a good time to commit?
return ret;
}
@ -1088,7 +1091,7 @@ NS_IMETHODIMP nsMsgDatabase::IsIgnored(nsMsgKey key, PRBool *pIgnored)
if (!pIgnored)
return NS_ERROR_NULL_POINTER;
#ifdef WE_DO_THREADING_YET
nsThreadMessageHdr *threadHdr = GetnsThreadHdrForMsgID(nsMsgKey);
nsIMsgThread *threadHdr = GetnsThreadHdrForMsgID(nsMsgKey);
// This should be very surprising, but we leave that up to the caller
// to determine for now.
if (threadHdr == NULL)
@ -1182,14 +1185,14 @@ NS_IMETHODIMP nsMsgDatabase::MarkHasAttachments(nsMsgKey key, PRBool bHasAttachm
}
NS_IMETHODIMP
nsMsgDatabase::MarkThreadIgnored(nsThreadMessageHdr *thread, nsMsgKey threadKey, PRBool bIgnored,
nsMsgDatabase::MarkThreadIgnored(nsIMsgThread *thread, nsMsgKey threadKey, PRBool bIgnored,
nsIDBChangeListener *instigator)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsMsgDatabase::MarkThreadWatched(nsThreadMessageHdr *thread, nsMsgKey threadKey, PRBool bWatched,
nsMsgDatabase::MarkThreadWatched(nsIMsgThread *thread, nsMsgKey threadKey, PRBool bWatched,
nsIDBChangeListener *instigator)
{
return NS_ERROR_NOT_IMPLEMENTED;
@ -1208,7 +1211,7 @@ NS_IMETHODIMP nsMsgDatabase::MarkOffline(nsMsgKey key, PRBool offline,
}
NS_IMETHODIMP
nsMsgDatabase::AllMsgKeysImapDeleted(const nsMsgKeyArray *keys)
nsMsgDatabase::AllMsgKeysImapDeleted(nsMsgKeyArray *keys)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
@ -1324,7 +1327,7 @@ NS_IMETHODIMP nsMsgDatabase::MarkHdrRead(nsIMsgDBHdr *msgHdr, PRBool bRead,
if (!!isRead != !!bRead)
{
#ifdef WE_DO_THREADING_YET
nsThreadMessageHdr *threadHdr = GetnsThreadHdrForMsgID(msgHdr->GetMessageKey());
nsIMsgThread *threadHdr = GetnsThreadHdrForMsgID(msgHdr->GetMessageKey());
if (threadHdr != NULL)
{
threadHdr->MarkChildRead(bRead);
@ -1366,7 +1369,7 @@ NS_IMETHODIMP nsMsgDatabase::MarkAllRead(nsMsgKeyArray *thoseMarked)
}
if (numChanged > 0) // commit every once in a while
Commit(kSmallCommit);
Commit(nsMsgDBCommitType::kSmallCommit);
// force num new to 0.
PRInt32 numNewMessages;
@ -1418,7 +1421,7 @@ NS_IMETHODIMP nsMsgDatabase::MarkReadByDate (PRTime startDate, PRTime endDate, n
NS_RELEASE(pHeader);
}
if (numChanged > 0)
Commit(kSmallCommit);
Commit(nsMsgDBCommitType::kSmallCommit);
return rv;
}
@ -2059,18 +2062,18 @@ nsIMsgHeaderParser *nsMsgDatabase::GetHeaderParser()
}
nsresult nsMsgDatabase::RowCellColumnToUInt32(nsIMdbRow *hdrRow, mdb_token columnToken, PRUint32 &uint32Result)
nsresult nsMsgDatabase::RowCellColumnToUInt32(nsIMdbRow *hdrRow, mdb_token columnToken, PRUint32 &uint32Result, PRUint32 defaultValue)
{
return RowCellColumnToUInt32(hdrRow, columnToken, &uint32Result);
return RowCellColumnToUInt32(hdrRow, columnToken, &uint32Result, defaultValue);
}
nsresult nsMsgDatabase::RowCellColumnToUInt32(nsIMdbRow *hdrRow, mdb_token columnToken, PRUint32 *uint32Result)
nsresult nsMsgDatabase::RowCellColumnToUInt32(nsIMdbRow *hdrRow, mdb_token columnToken, PRUint32 *uint32Result, PRUint32 defaultValue)
{
nsresult err = NS_OK;
nsIMdbCell *hdrCell;
if (uint32Result)
*uint32Result = 0;
*uint32Result = defaultValue;
if (hdrRow) // ### probably should be an error if hdrRow is NULL...
{
err = hdrRow->GetCell(GetEnv(), columnToken, &hdrCell);
@ -2327,7 +2330,7 @@ nsresult nsMsgDatabase::ThreadNewHdr(nsMsgHdr* newHdr, PRBool &newThread)
newHdr->GetNumReferences(&numReferences);
#define SUBJ_THREADING 1// try reference threading first
for (PRInt32 i = 0; i < numReferences; i++)
for (PRInt32 i = numReferences - 1; i >= 0; i--)
{
nsString2 reference(eOneByte);

Просмотреть файл

@ -592,3 +592,16 @@ const char *nsMsgHdr::GetPrevReference(const char *prevRef, nsString2 &reference
return ptr;
}
PRBool nsMsgHdr::IsParentOf(nsIMsgDBHdr *possibleChild)
{
PRUint16 numReferences = 0;
possibleChild->GetNumReferences(&numReferences);
nsAutoString2 reference(eOneByte);
nsAutoString2 messageId(eOneByte);
GetMessageId(messageId);
possibleChild->GetStringReference(numReferences - 1, reference);
return (messageId.Equals(reference));
}

Просмотреть файл

@ -45,6 +45,7 @@ nsMsgThread::nsMsgThread(nsMsgDatabase *db, nsIMdbTable *table)
void nsMsgThread::Init()
{
m_threadKey = nsMsgKey_None;
m_threadRootKey = nsMsgKey_None;
m_numChildren = 0;
m_numUnreadChildren = 0;
m_flags = 0;
@ -79,7 +80,7 @@ nsresult nsMsgThread::InitCachedValues()
err = m_mdbDB->RowCellColumnToUInt32(m_metaRow, m_mdbDB->m_threadChildrenColumnToken, &m_numChildren);
err = m_mdbDB->RowCellColumnToUInt32(m_metaRow, m_mdbDB->m_threadIdColumnToken, &m_threadKey);
err = m_mdbDB->RowCellColumnToUInt32(m_metaRow, m_mdbDB->m_threadUnreadChildrenColumnToken, &m_numUnreadChildren);
err = m_mdbDB->RowCellColumnToUInt32(m_metaRow, m_mdbDB->m_threadRootKeyColumnToken, &m_threadRootKey, nsMsgKey_None);
if (NS_SUCCEEDED(err))
m_cachedValuesInitialized = PR_TRUE;
@ -92,6 +93,8 @@ NS_IMETHODIMP nsMsgThread::SetThreadKey(nsMsgKey threadKey)
nsresult ret = NS_OK;
m_threadKey = threadKey;
// by definition, the initial thread key is also the thread root key.
SetThreadRootKey(threadKey);
ret = m_mdbDB->UInt32ToRowCellColumn(m_metaRow, m_mdbDB->m_threadIdColumnToken, threadKey);
// gotta set column in meta row here.
return ret;
@ -171,9 +174,12 @@ NS_IMETHODIMP nsMsgThread::AddChild(nsIMsgDBHdr *child, nsIMsgDBHdr *inReplyTo,
nsresult ret = NS_OK;
nsMsgHdr* hdr = NS_STATIC_CAST(nsMsgHdr*, child); // closed system, cast ok
PRUint32 newHdrFlags = 0;
nsMsgKey newHdrKey = 0;
nsIMdbRow *hdrRow = hdr->GetMDBRow();
hdr->GetFlags(&newHdrFlags);
hdr->GetMessageKey(&newHdrKey);
if (m_mdbTable)
{
m_mdbTable->AddRow(m_mdbDB->GetEnv(), hdrRow);
@ -181,6 +187,74 @@ NS_IMETHODIMP nsMsgThread::AddChild(nsIMsgDBHdr *child, nsIMsgDBHdr *inReplyTo,
if (! (newHdrFlags & MSG_FLAG_READ))
ChangeUnreadChildCount(1);
}
if (inReplyTo)
{
nsMsgKey parentKey;
inReplyTo->GetMessageKey(&parentKey);
child->SetThreadParent(parentKey);
}
if (inReplyTo)
{
nsMsgKey parentKey;
inReplyTo->GetMessageKey(&parentKey);
child->SetThreadParent(parentKey);
}
// check if this header is a parent of one of the messages in this thread
PRUint32 numChildren;
PRUint32 childIndex = 0;
GetNumChildren(&numChildren);
nsCOMPtr <nsIMsgDBHdr> curHdr;
for (childIndex = 0; childIndex < numChildren; childIndex++)
{
nsMsgKey msgKey;
ret = GetChildHdrAt(childIndex, getter_AddRefs(curHdr));
if (NS_SUCCEEDED(ret) && curHdr)
{
// ### check if this is the thead root key!
if (hdr->IsParentOf(curHdr))
{
curHdr->GetMessageKey(&msgKey);
curHdr->SetThreadParent(newHdrKey);
#ifdef DEBUG_bienvenu
if (newHdrKey != m_threadKey)
printf("adding second level child\n");
#endif
// If this hdr was the root, then the new hdr is the root.
if (msgKey == m_threadRootKey)
SetThreadRootKey(newHdrKey);
}
}
}
// If this header is not a reply to a header in the thread, and isn't a parent
// check to see if it starts with Re: - if not, and the first header does start
// with re, should we make this header the top level header?
// If it's date is less (or it's ID?), then yes.
if (numChildren > 0 && !(newHdrFlags & MSG_FLAG_HAS_RE) && !inReplyTo)
{
PRTime newHdrDate;
PRTime topLevelHdrDate;
nsCOMPtr <nsIMsgDBHdr> topLevelHdr;
ret = GetRootHdr(nsnull, getter_AddRefs(topLevelHdr));
if (NS_SUCCEEDED(ret) && topLevelHdr)
{
child->GetDate(&newHdrDate);
topLevelHdr->GetDate(&topLevelHdrDate);
if (LL_CMP(newHdrDate, <, topLevelHdrDate))
{
#ifdef MOVE_ROW_IMPL
mdb_pos outPos;
m_mdbTable->MoveRow(m_mdbDB->GetEnv(), hdrRow, -1, 0, &outPos);
#endif // MOVE_ROW_IMPL
topLevelHdr->SetThreadParent(newHdrKey);
SetThreadRootKey(newHdrKey);
}
}
}
return ret;
}
@ -387,13 +461,15 @@ public:
nsMsgThreadEnumerator(nsMsgThread *thread, nsMsgKey startKey,
nsMsgThreadEnumeratorFilter filter, void* closure);
PRInt32 MsgKeyFirstChildIndex(nsMsgKey inMsgKey);
virtual ~nsMsgThreadEnumerator();
protected:
nsIMdbTableRowCursor* mRowCursor;
nsIMsgDBHdr* mResultHdr;
nsCOMPtr <nsIMsgDBHdr> mResultHdr;
nsMsgThread* mThread;
nsMsgKey mCurKey;
nsMsgKey mThreadParentKey;
nsMsgKey mFirstMsgKey;
PRInt32 mChildIndex;
PRBool mDone;
nsMsgThreadEnumeratorFilter mFilter;
@ -402,34 +478,71 @@ protected:
nsMsgThreadEnumerator::nsMsgThreadEnumerator(nsMsgThread *thread, nsMsgKey startKey,
nsMsgThreadEnumeratorFilter filter, void* closure)
: mRowCursor(nsnull), mResultHdr(nsnull), mDone(PR_FALSE),
: mRowCursor(nsnull), mDone(PR_FALSE),
mFilter(filter), mClosure(closure)
{
NS_INIT_REFCNT();
mCurKey = startKey;
mChildIndex = 1;
mThreadParentKey = startKey;
mChildIndex = 0;
mThread = thread;
if (mCurKey != nsMsgKey_None)
mFirstMsgKey = nsMsgKey_None;
nsresult rv = mThread->GetRootHdr(nsnull, getter_AddRefs(mResultHdr));
if (NS_SUCCEEDED(rv) && mResultHdr)
mResultHdr->GetMessageKey(&mFirstMsgKey);
PRUint32 numChildren;
mThread->GetNumChildren(&numChildren);
if (mThreadParentKey != nsMsgKey_None)
{
nsMsgKey msgKey = nsMsgKey_None;
nsresult rv = mThread->GetChildHdrAt(0, &mResultHdr);
if (NS_SUCCEEDED(rv) && mResultHdr)
PRUint32 childIndex = 0;
for (childIndex = 0; childIndex < numChildren; childIndex++)
{
// we're only doing one level of threading, so check if caller is
// asking for children of the first message in the thread or not.
// if not, we will tell him there are no children.
mResultHdr->GetMessageKey(&msgKey);
if (msgKey != mCurKey)
mDone = PR_TRUE;
rv = mThread->GetChildHdrAt(childIndex, getter_AddRefs(mResultHdr));
if (NS_SUCCEEDED(rv) && mResultHdr)
{
mResultHdr->GetMessageKey(&msgKey);
NS_RELEASE(mResultHdr);
mResultHdr = nsnull;
if (msgKey == startKey)
{
mChildIndex = MsgKeyFirstChildIndex(msgKey);
mDone = (mChildIndex < 0);
break;
}
if (mDone)
break;
}
else
NS_ASSERTION(PR_FALSE, "couldn't get child from thread");
}
else
NS_ASSERTION(PR_FALSE, "couldn't get child from thread");
mChildIndex = 1;
}
#ifdef DEBUG_bienvenu
nsCOMPtr <nsIMsgDBHdr> child;
for (PRUint32 childIndex = 0; childIndex < numChildren; childIndex++)
{
rv = mThread->GetChildHdrAt(childIndex, getter_AddRefs(child));
if (NS_SUCCEEDED(rv) && child)
{
nsMsgKey threadParent;
nsMsgKey msgKey;
// we're only doing one level of threading, so check if caller is
// asking for children of the first message in the thread or not.
// if not, we will tell him there are no children.
child->GetMessageKey(&msgKey);
child->GetThreadParent(&threadParent);
printf("index = %ld key = %ld parent = %lx\n", childIndex, msgKey, threadParent);
}
}
#endif
NS_ADDREF(thread);
}
@ -448,21 +561,84 @@ NS_IMETHODIMP nsMsgThreadEnumerator::First(void)
return NS_ERROR_NULL_POINTER;
rv = Next();
NS_ASSERTION(mCurKey != nsMsgKey_None || NS_SUCCEEDED(rv), "first failed, can't have that");
NS_ASSERTION(mThreadParentKey != nsMsgKey_None || NS_SUCCEEDED(rv), "first failed, can't have that");
return rv;
}
PRInt32 nsMsgThreadEnumerator::MsgKeyFirstChildIndex(nsMsgKey inMsgKey)
{
// if (msgKey != mThreadParentKey)
// mDone = PR_TRUE;
// look through rest of thread looking for a child of this message.
// If the inMsgKey is the first message in the thread, then all children
// without parents are considered to be children of inMsgKey.
// Otherwise, only true children qualify.
PRUint32 numChildren;
nsCOMPtr <nsIMsgDBHdr> curHdr;
PRInt32 firstChildIndex = -1;
mThread->GetNumChildren(&numChildren);
// if this is the first message in the thread, just check if there's more than
// one message in the thread.
if (inMsgKey == mThread->m_threadRootKey)
return (numChildren > 1) ? 1 : -1;
for (PRUint32 curChildIndex = 0; curChildIndex < numChildren; curChildIndex++)
{
nsresult rv = mThread->GetChildHdrAt(curChildIndex, getter_AddRefs(curHdr));
if (NS_SUCCEEDED(rv) && curHdr)
{
nsMsgKey parentKey;
curHdr->GetThreadParent(&parentKey);
if (parentKey == inMsgKey)
{
firstChildIndex = curChildIndex;
break;
}
}
}
#ifdef DEBUG_bienvenu
printf("first child index of %ld = %ld\n", inMsgKey, firstChildIndex);
#endif
return firstChildIndex;
}
NS_IMETHODIMP nsMsgThreadEnumerator::Next(void)
{
nsresult rv;
if (mCurKey == nsMsgKey_None)
mResultHdr = nsnull;
if (mThreadParentKey == nsMsgKey_None)
{
rv = mThread->GetChildHdrAt(0, &mResultHdr);
mChildIndex = 1;
rv = mThread->GetRootHdr(&mChildIndex, getter_AddRefs(mResultHdr));
mChildIndex = 0; // since root can be anywhere, set mChildIndex to 0.
}
else if (!mDone)
{
rv = mThread->GetChildHdrAt(mChildIndex++, &mResultHdr);
PRUint32 numChildren;
mThread->GetNumChildren(&numChildren);
while (mChildIndex < (PRInt32) numChildren)
{
rv = mThread->GetChildHdrAt(mChildIndex++, getter_AddRefs(mResultHdr));
if (NS_SUCCEEDED(rv) && mResultHdr)
{
nsMsgKey parentKey;
nsMsgKey curKey;
mResultHdr->GetThreadParent(&parentKey);
mResultHdr->GetMessageKey(&curKey);
// if the parent is the same as the msg we're enumerating over,
// or the parentKey isn't set, and we're iterating over the top
// level message in the thread, then leave mResultHdr set to cur msg.
if (parentKey == mThreadParentKey ||
((parentKey == 0 || parentKey == nsMsgKey_None)
&& mThreadParentKey == mFirstMsgKey && curKey != mThreadParentKey))
break;
mResultHdr = nsnull;
}
}
}
if (!mResultHdr)
{
@ -474,15 +650,22 @@ NS_IMETHODIMP nsMsgThreadEnumerator::Next(void)
mDone = PR_TRUE;
return rv;
}
#ifdef DEBUG_bienvenu
nsMsgKey debugMsgKey;
mResultHdr->GetMessageKey(&debugMsgKey);
printf("next for %ld = %ld\n", mThreadParentKey, debugMsgKey);
#endif
return rv;
}
NS_IMETHODIMP nsMsgThreadEnumerator::CurrentItem(nsISupports **aItem)
{
if (!aItem)
return NS_ERROR_NULL_POINTER;
if (mResultHdr) {
*aItem = mResultHdr;
NS_ADDREF(mResultHdr);
NS_ADDREF(*aItem);
return NS_OK;
}
return NS_ERROR_FAILURE;
@ -507,6 +690,17 @@ NS_IMETHODIMP nsMsgThread::EnumerateMessages(nsMsgKey parentKey, nsIEnumerator*
return ret;
}
NS_IMETHODIMP nsMsgThread::GetRootHdr(PRInt32 *resultIndex, nsIMsgDBHdr **result)
{
if (m_threadRootKey == nsMsgKey_None)
{
*resultIndex = 0;
return GetChildHdrAt(0, result);
}
else
return GetChildHdrForKey(m_threadRootKey, result, resultIndex);
}
nsresult nsMsgThread::ChangeChildCount(PRInt32 delta)
{
nsresult ret = NS_OK;
@ -528,3 +722,45 @@ nsresult nsMsgThread::ChangeUnreadChildCount(PRInt32 delta)
ret = m_mdbDB->UInt32ToRowCellColumn(m_metaRow, m_mdbDB->m_threadUnreadChildrenColumnToken, childCount);
return ret;
}
nsresult nsMsgThread::SetThreadRootKey(nsMsgKey threadRootKey)
{
nsresult ret = NS_OK;
m_threadRootKey = threadRootKey;
ret = m_mdbDB->UInt32ToRowCellColumn(m_metaRow, m_mdbDB->m_threadRootKeyColumnToken, threadRootKey);
return ret;
}
nsresult nsMsgThread::GetChildHdrForKey(nsMsgKey desiredKey, nsIMsgDBHdr **result, PRInt32 *resultIndex)
{
PRUint32 numChildren;
PRUint32 childIndex = 0;
nsresult rv;
if (!result)
return NS_ERROR_NULL_POINTER;
GetNumChildren(&numChildren);
for (childIndex = 0; childIndex < numChildren; childIndex++)
{
rv = GetChildHdrAt(childIndex, result);
if (NS_SUCCEEDED(rv) && result)
{
nsMsgKey msgKey;
// we're only doing one level of threading, so check if caller is
// asking for children of the first message in the thread or not.
// if not, we will tell him there are no children.
(*result)->GetMessageKey(&msgKey);
if (msgKey == desiredKey)
break;
NS_RELEASE(*result);
}
}
if (resultIndex)
*resultIndex = childIndex;
return rv;
}

Просмотреть файл

@ -73,7 +73,7 @@ nsresult nsNewsDatabase::MessageDBOpenUsingURL(const char * groupURL)
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP nsNewsDatabase::Open(nsIFileSpec *aNewsgroupName, PRBool create, nsIMsgDatabase** pMessageDB, PRBool upgrading /*=PR_FALSE*/)
NS_IMETHODIMP nsNewsDatabase::Open(nsIFileSpec *aNewsgroupName, PRBool create, PRBool upgrading, nsIMsgDatabase** pMessageDB)
{
nsNewsDatabase *newsDB;
@ -159,7 +159,7 @@ nsresult nsNewsDatabase::ForceClosed()
return nsMsgDatabase::ForceClosed();
}
nsresult nsNewsDatabase::Commit(nsMsgDBCommitType commitType)
nsresult nsNewsDatabase::Commit(nsMsgDBCommit commitType)
{
return nsMsgDatabase::Commit(commitType);
}
@ -210,7 +210,7 @@ NS_IMETHODIMP nsNewsDatabase::MarkHdrRead(nsIMsgDBHdr *msgHdr, PRBool bRead,
// since committing every time is expensive if we mark a
// whole bunch of headers as read, we should commit after we are
// done marking.
Commit(kSessionCommit);
Commit(nsMsgDBCommitType::kSessionCommit);
return rv;
}