gecko-dev/lib/libmsg/msghdr.cpp
1998-06-22 22:39:40 +00:00

593 lines
16 KiB
C++

/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#include "msg.h"
#include "xp.h"
#include "msghdr.h"
#include "xp_time.h"
#include "msgdbapi.h"
#include "msgstrob.h"
/* ****************************************************************** */
/** DBMessageHdr Class **/
/* ****************************************************************** */
#ifdef DEBUG_bienvenu
int32 DBMessageHdr::numMessageHdrs = 0;
#endif
DBMessageHdr::DBMessageHdr()
{
m_level = 0;
m_threadId = 0;
m_flags = 0;
m_messageKey = 0;
m_date = 0;
m_dbHeaderHandle = 0;
#ifdef DEBUG_bienvenu
numMessageHdrs++;
#endif
}
DBMessageHdr::DBMessageHdr(MSG_HeaderHandle handle)
{
MSG_DBHeaderExchange headerInfo;
m_dbHeaderHandle = handle;
if (handle)
{
MSG_HeaderHandle_GetHeaderInfo(handle, &headerInfo);
m_threadId = headerInfo.m_threadId;
m_messageKey = headerInfo.m_messageKey; //news: article number, mail mbox offset
m_date = headerInfo.m_date;
m_messageSize = headerInfo.m_messageSize; // lines for news articles, bytes for mail messages
m_flags = headerInfo.m_flags;
m_level = headerInfo.m_level;
}
else
{
m_threadId = kIdNone;
m_messageKey = kIdNone;
m_date = 0;
m_messageSize = 0;
m_flags = 0;
m_level = 0;
}
#ifdef DEBUG_bienvenu
numMessageHdrs++;
#endif
}
DBMessageHdr::~DBMessageHdr()
{
#ifdef DEBUG_bienvenu
numMessageHdrs--;
#endif
if (m_dbHeaderHandle)
MSG_HeaderHandle_RemoveReference(m_dbHeaderHandle);
}
XP_Bool DBMessageHdr::InitFromXOverLine(char * xOverLine, MSG_DBHandle db)
{
if (!ParseLine(xOverLine, this, db))
return FALSE;
return TRUE;
}
/* static method */
XP_Bool DBMessageHdr::ParseLine(char *line, DBMessageHdr *msgHdr, MSG_DBHandle db)
{
uint32 lines;
uint32 msgSize = 0;
char *next = line;
#define GET_TOKEN() \
line = next; \
next = (line ? XP_STRCHR (line, '\t') : 0); \
if (next) *next++ = 0
GET_TOKEN (); /* message number */
msgHdr->SetMessageKey (atol (line));
if (msgHdr->GetMessageKey() == 0) /* bogus xover data */
return FALSE;
GET_TOKEN (); /* subject */
if (line)
msgHdr->SetSubject(line, db);
GET_TOKEN (); /* sender */
if (line)
msgHdr->SetAuthor(line, db);
GET_TOKEN ();
if (line)
msgHdr->SetDate(XP_ParseTimeString (line, FALSE)); /* date */
GET_TOKEN (); /* message id */
if (line)
msgHdr->SetUnstrippedMessageId(line, db);
GET_TOKEN (); /* references */
if (line)
msgHdr->SetReferences(line, db);
GET_TOKEN (); /* bytes */
// msgSize = (line) ? atol (line) : 0;
// msgHdr->SetMessageSize(msgSize);
/* ignored */
GET_TOKEN (); /* lines */
lines = line ? atol (line) : 0;
if (!msgSize)
msgHdr->SetMessageSize(lines);
GET_TOKEN (); /* xref */
return TRUE;
}
// It would be nice to get rid of this in favor of the routine above that takes
// a DBMessageHdr.
/* static method */
XP_Bool DBMessageHdr::ParseLine(char *line, MessageHdrStruct *msgHdr)
{
uint32 lines;
char *next = line;
#define GET_TOKEN() \
line = next; \
next = (line ? XP_STRCHR (line, '\t') : 0); \
if (next) *next++ = 0
GET_TOKEN (); /* message number */
msgHdr->m_messageKey = atol (line);
if (msgHdr->m_messageKey == 0) /* bogus xover data */
return FALSE;
GET_TOKEN (); /* subject */
if (line)
msgHdr->SetSubject(line);
GET_TOKEN (); /* sender */
if (line)
msgHdr->SetAuthor(line);
GET_TOKEN ();
if (line)
msgHdr->SetDate(line); /* date */
GET_TOKEN (); /* message id */
if (line)
msgHdr->SetMessageID(line);
GET_TOKEN (); /* references */
if (line)
msgHdr->SetReferences(line);
GET_TOKEN (); /* bytes */
/* ignored */
GET_TOKEN (); /* lines */
lines = line ? atol (line) : 0;
msgHdr->SetLines(lines);
GET_TOKEN (); /* xref */
return TRUE;
}
void DBMessageHdr::CopyToMessageHdr(MessageHdrStruct *msgHdr, MSG_DBHandle db /* = NULL */)
{
MSG_HeaderHandle_CopyToMessageHdr(m_dbHeaderHandle, msgHdr, db);
}
void DBMessageHdr::CopyToShortMessageHdr(MSG_MessageLine *msgHdr, MSG_DBHandle db /* = NULL */)
{
MSG_HeaderHandle_CopyToShortMessageHdr(m_dbHeaderHandle, msgHdr, db);
// msgHdr should be set to zeroes by caller
}
void DBMessageHdr::CopyDBFlagsToMsgHdrFlags(uint32 *pflags)
{
uint32 dbFlags = GetFlags();
MessageDB::ConvertDBFlagsToPublicFlags(&dbFlags);
*pflags = dbFlags;
}
XP_Bool DBMessageHdr::SetThreadId(MessageKey threadId)
{
m_threadId = threadId;
MSG_HeaderHandle_SetThreadID(m_dbHeaderHandle, threadId);
return TRUE;
}
XP_Bool DBMessageHdr::SetMessageKey(MessageKey messageKey)
{
m_messageKey = messageKey;
MSG_HeaderHandle_SetMessageKey(m_dbHeaderHandle, messageKey);
// DMB TODO
// XP_ASSERT(messageKey != 0); // does this happen? should I set messageKey to 1 for db?
return TRUE;
}
// these could all be virtual inlines
MSG_PRIORITY DBMessageHdr::GetPriority() {return MSG_NoPriority;}
void DBMessageHdr::SetPriority(const char * /*priority*/) {}
void DBMessageHdr::SetPriority(MSG_PRIORITY /*priority*/) {}
int32 DBMessageHdr::GetNumRecipients() {return 0;}
int32 DBMessageHdr::GetNumCCRecipients() {return 0;}
void DBMessageHdr::GetCCList(XPStringObj & /*ccList*/ ,MSG_DBHandle /*db*/) {}
void DBMessageHdr::GetRecipients(XPStringObj & /*recipient*/, MSG_DBHandle /*db*/) {}
void DBMessageHdr::GetNameOfRecipient(XPStringObj & /*recipient*/, int /*whichRecipient*/, MSG_DBHandle /*db*/) {}
void DBMessageHdr::GetMailboxOfRecipient(XPStringObj & /*recipient*/, int /*whichRecipient*/, MSG_DBHandle /*db*/) {}
void DBMessageHdr::GetNameOfCCRecipient(XPStringObj & /*recipient*/, int /*whichRecipient*/, MSG_DBHandle /*db*/) {}
void DBMessageHdr::GetMailboxOfCCRecipient(XPStringObj & /*recipient*/, int /*whichRecipient*/, MSG_DBHandle /*db*/) {}
uint32 DBMessageHdr::GetByteLength() {return MSG_HeaderHandle_GetByteLength(GetHandle());}
uint32 DBMessageHdr::GetLineCount() {return MSG_HeaderHandle_GetLineCount(GetHandle());}
uint32 DBMessageHdr::GetMessageSize() {return MSG_HeaderHandle_GetMessageSize(GetHandle());}
void DBMessageHdr::PurgeArticle() {}
// This is the key used in the database, which is almost always the same
// as the m_messageKey, except for the first message in a mailbox,
// which has a m_messageKey of 0, but a non-zero fID in the database.
MessageKey DBMessageHdr::GetMessageKey()
{
m_messageKey = MSG_HeaderHandle_GetMessageKey(GetHandle());
return m_messageKey;
// DMB TODO - do we need to play the 0 key/id problem?
}
void DBMessageHdr::SetMessageSize(uint32 messageSize)
{
m_messageSize = messageSize;
MSG_HeaderHandle_SetMessageSize(m_dbHeaderHandle, messageSize);
}
XP_Bool DBMessageHdr::SetSubject(const char * subject, MSG_DBHandle db)
{
MSG_HeaderHandle_SetSubject(m_dbHeaderHandle, subject, db);
return TRUE;
}
XP_Bool DBMessageHdr::SetAuthor(const char * author,
MSG_DBHandle db)
{
MSG_HeaderHandle_SetAuthor(m_dbHeaderHandle, author, db);
return TRUE;
}
// This assumes the caller has done the stripping off of '<' and '>'
XP_Bool DBMessageHdr::SetMessageId(const char * messageId,
MSG_DBHandle db)
{
// XP_ASSERT(messageId[0] != '<'); Nelson Bolyard hits this assert because of some spam, so we can't leave it in.
MSG_HeaderHandle_SetMessageId(m_dbHeaderHandle, messageId, db);
return TRUE;
}
XP_Bool DBMessageHdr::SetUnstrippedMessageId(char * messageId,
MSG_DBHandle db)
{
if (messageId[0] == '<')
messageId++;
char * lastChar = messageId + strlen(messageId) -1;
if (*lastChar == '>')
*lastChar = '\0';
MSG_HeaderHandle_SetMessageId(m_dbHeaderHandle, messageId, db);
return TRUE;
}
XP_Bool DBMessageHdr::SetReferences(const char * references, MSG_DBHandle db)
{
MSG_HeaderHandle_SetReferences(m_dbHeaderHandle, references, db);
return TRUE;
}
void DBMessageHdr::SetFlags(uint32 flags)
{
m_flags = flags;
MSG_HeaderHandle_SetFlags(m_dbHeaderHandle, flags);
}
uint32 DBMessageHdr::OrFlags(uint32 flags)
{
return MSG_HeaderHandle_OrFlags(m_dbHeaderHandle, flags);
}
uint32 DBMessageHdr::AndFlags(uint32 flags)
{
return MSG_HeaderHandle_AndFlags(m_dbHeaderHandle, flags);
}
void DBMessageHdr::SetDate(time_t date)
{
m_date = date;
MSG_HeaderHandle_SetDate(m_dbHeaderHandle, date);
}
void DBMessageHdr::SetLevel(char level)
{
m_level = level;
MSG_HeaderHandle_SetLevel(m_dbHeaderHandle, level);
}
char DBMessageHdr::GetLevel()
{
return m_level;
}
uint32 DBMessageHdr::GetFlags()
{
return (m_flags = MSG_HeaderHandle_GetFlags(m_dbHeaderHandle));
}
uint32 DBMessageHdr::GetMozillaStatusFlags()
{
uint32 flags = 0;
uint32 priority = GetPriority();
// copy over flags that are the same
flags |= (kMozillaSameAsMSG_FLAG & m_flags);
if (m_flags & kExpunged) // is this needed?
flags |= MSG_FLAG_EXPUNGED;
if (m_flags & kHasRe)
flags |= MSG_FLAG_HAS_RE;
if (m_flags & kPartial)
flags |= MSG_FLAG_PARTIAL;
if (priority != 0)
{
flags |= (priority << 13); // use the upper three bits for priority.
}
// Disaster will ensue if we use more than 16 bits! If somebody adds a bad bit,
// make sure we don't corrupt the user's mail folder by writing out more than
// four characters.
uint32 legalFlags = flags & 0x0000FFFF;
XP_ASSERT(flags==legalFlags);
return legalFlags;
}
MessageId DBMessageHdr::GetArticleNum()
{
// XP_ASSERT(fID == m_messageKey || m_messageKey == 0);
// DMB TODO ???
return m_messageKey;
// return fID;
}
MessageId DBMessageHdr::GetThreadId()
{
return m_threadId;
}
void DBMessageHdr::CopyFromDBMsgHdr(DBMessageHdr *oldHdr, MSG_DBHandle srcDB, MSG_DBHandle destDB /*= NULL*/)
{
MSG_HeaderHandle_CopyFromMsgHdr(m_dbHeaderHandle, oldHdr->GetHandle(), srcDB, destDB);
}
XP_Bool DBMessageHdr::GetMessageId(XPStringObj &messageId, MSG_DBHandle db /* = NULL */)
{
char *messageIdStr;
XP_Bool ret = MSG_HeaderHandle_GetMessageId(m_dbHeaderHandle, &messageIdStr, db);
messageId.SetStrPtr(messageIdStr);
return ret;
}
XP_Bool DBMessageHdr::GetSubject(XPStringObj &subject, XP_Bool withRe, MSG_DBHandle db)
{
char *subjectStr;
XP_Bool ret = MSG_HeaderHandle_GetSubject(m_dbHeaderHandle, &subjectStr, withRe, db);
subject.SetStrPtr(subjectStr);
return ret;
}
XP_Bool DBMessageHdr::GetAuthor(XPStringObj &author, MSG_DBHandle db)
{
char *authorStr;
XP_Bool ret = MSG_HeaderHandle_GetAuthor(m_dbHeaderHandle, &authorStr, db);
author.SetStrPtr(authorStr);
return ret;
}
XP_Bool DBMessageHdr::GetRFC822Author(XPStringObj &author, MSG_DBHandle db)
{
XP_Bool ret = GetAuthor(author, db);
if (ret)
{
char *rfc822Sender;
rfc822Sender = MSG_ExtractRFC822AddressName (author);
if (rfc822Sender)
{
author = rfc822Sender;
FREEIF(rfc822Sender);
}
return TRUE;
}
return FALSE;
}
// copy the subject back into the passed buffer.
void DBMessageHdr::GetSubject(char *outSubject, int subjectLen, XP_Bool withRe, MSG_DBHandle db )
{
XPStringObj subjectStr;
GetSubject(subjectStr, withRe, db);
*outSubject = '\0';
if ((const char *) subjectStr != NULL)
{
// Fix problem of going one over the real length of the array
// for source strings that are longer than the destination.
if (subjectLen <= (int) XP_STRLEN(subjectStr))
subjectLen --;
XP_STRNCAT_SAFE(outSubject, subjectStr, subjectLen);
}
#ifdef DEBUG_bienvenu
else
XP_ASSERT(FALSE);
#endif
}
// copy the messageid back into the passed buffer.
void DBMessageHdr::GetMessageId(char *outMessageId, int messageIdLen, MSG_DBHandle db)
{
XPStringObj messageIdStr;
GetMessageId(messageIdStr, db);
if ((const char *) messageIdStr != NULL)
XP_STRNCPY_SAFE(outMessageId, messageIdStr, messageIdLen);
#ifdef DEBUG_bienvenu
else
XP_ASSERT(FALSE);
#endif
}
// copy the author back into the passed buffer.
void DBMessageHdr::GetAuthor(char *outAuthor, int authorLen, MSG_DBHandle db /* = NULL */)
{
XPStringObj authorStr;
GetAuthor(authorStr, db);
if ((const char* ) authorStr != NULL)
XP_STRNCPY_SAFE(outAuthor, authorStr, authorLen);
#ifdef DEBUG_bienvenu
else
XP_ASSERT(FALSE);
#endif
}
// copy the author back into the passed buffer.
void DBMessageHdr::GetRFC822Author(char *outAuthor, int authorLen, MSG_DBHandle db /* = NULL */)
{
XPStringObj authorStr;
GetAuthor(authorStr, db);
if ((const char *) authorStr != NULL)
{
char *rfc822Sender;
rfc822Sender = MSG_ExtractRFC822AddressName (authorStr);
if (rfc822Sender)
{
XP_STRNCPY_SAFE(outAuthor, rfc822Sender, authorLen);
FREEIF(rfc822Sender);
}
}
#ifdef DEBUG_bienvenu1
else
XP_ASSERT(FALSE);
#endif
}
void DBMessageHdr::GetMailboxOfAuthor(char *outAuthor, int authorLen, MSG_DBHandle db /* = NULL */)
{
XPStringObj authorStr;
GetAuthor(authorStr, db);
if ((const char *) authorStr != NULL)
{
char *rfc822Sender;
rfc822Sender = MSG_ExtractRFC822AddressMailboxes (authorStr);
if (rfc822Sender)
{
XP_STRNCPY_SAFE(outAuthor, rfc822Sender, authorLen);
FREEIF(rfc822Sender);
}
}
#ifdef DEBUG_bienvenu
else
XP_ASSERT(FALSE);
#endif
}
int32 DBMessageHdr::GetNumReferences()
{
return MSG_HeaderHandle_GetNumReferences(GetHandle());
}
// get the next <> delimited reference from nextRef and copy it into reference,
// which is a pointer to a buffer at least kMaxMsgIdLen long.
const char * DBMessageHdr::GetReference(const char *nextRef, char *reference)
{
const char *ptr = nextRef;
while ((*ptr == '<' || *ptr == ' ') && *ptr)
ptr++;
for (int i = 0; *ptr && *ptr != '>' && i < kMaxMsgIdLen; i++)
*reference++ = *ptr++;
if (*ptr == '>')
ptr++;
*reference = '\0';
return ptr;
}
// Get previous <> delimited reference - used to go backwards through the
// reference string. Caller will need to make sure that prevRef is not before
// the start of the reference string when we return.
const char *DBMessageHdr::GetPrevReference(const char *prevRef, char *reference)
{
const char *ptr = prevRef;
while ((*ptr == '>' || *ptr == ' ') && *ptr)
ptr--;
// scan back to '<'
for (int i = 0; *ptr && *ptr != '<' ; i++)
ptr--;
GetReference(ptr, reference);
if (*ptr == '<')
ptr--;
return ptr;
}
// If the m_messageIdID string in the hash table has a ref count
// greater than 1, the presumption is another header must
// refer to it.
XP_Bool DBMessageHdr::IsReferredTo(MSG_DBHandle db)
{
XP_Bool isReferredTo = FALSE;
// DMB TODO
#if 0
if (m_messageIdID != 0)
{
HashString *hashString = HashString::GetHashString(m_messageIdID, kMessageIdStringID, db);
if (hashString)
{
if (hashString->GetRefCount() > 1)
isReferredTo = TRUE;
hashString->unrefer();
}
}
#endif
return isReferredTo;
}
// Does this hdr refer to passed in hdr? I.e., should we be a child
// of the passed in hdr?
XP_Bool DBMessageHdr::RefersTo(DBMessageHdr *hdr)
{
// if the hash string id of the passed in hdr is equal to one of the
// hash string id's in our reference id array, then we refer to hdr.
// DMB TODO
return FALSE;
}
void DBMessageHdr::PurgeOfflineMessage(MSG_DBHandle /* db */)
{
// ### dmb could move the news and imap overrides into here
}