зеркало из https://github.com/mozilla/pjs.git
675 строки
18 KiB
C++
675 строки
18 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 "maildb.h"
|
||
|
#include "dberror.h"
|
||
|
|
||
|
#include "msgdbvw.h"
|
||
|
#include "mailhdr.h"
|
||
|
#include "thrhead.h"
|
||
|
#include "grpinfo.h"
|
||
|
#include "imap.h"
|
||
|
#include "msgmast.h"
|
||
|
#include "msgprefs.h"
|
||
|
#include "msgimap.h"
|
||
|
#include "imapoff.h"
|
||
|
#include "prefapi.h"
|
||
|
#include "msgdbapi.h"
|
||
|
|
||
|
extern "C"
|
||
|
{
|
||
|
extern int MK_MSG_CANT_OPEN;
|
||
|
}
|
||
|
|
||
|
MailDB::MailDB()
|
||
|
{
|
||
|
m_folderName = NULL;
|
||
|
m_reparse = FALSE;
|
||
|
m_folderFile = NULL;
|
||
|
m_master = NULL;
|
||
|
}
|
||
|
|
||
|
MailDB::~MailDB()
|
||
|
{
|
||
|
FREEIF(m_folderName);
|
||
|
}
|
||
|
|
||
|
MsgERR MailDB::OnNewPath (const char *newPath)
|
||
|
{
|
||
|
FREEIF(m_folderName);
|
||
|
m_folderName = XP_STRDUP (newPath);
|
||
|
return eSUCCESS;
|
||
|
}
|
||
|
|
||
|
// static method. This routine works in very different ways depending on the passed flags.
|
||
|
// If create is true, we will create a database if none was there.
|
||
|
// If upgrading is TRUE, the caller is upgrading and does not care that the database is
|
||
|
// gone, or out of sync with the mail folder. The caller will upgrade in the background
|
||
|
// and just wants a db open to upgrade into.
|
||
|
MsgERR MailDB::Open(const char * folderName, XP_Bool create,
|
||
|
MailDB** pMessageDB,
|
||
|
XP_Bool upgrading /*=FALSE*/)
|
||
|
{
|
||
|
MailDB *mailDB;
|
||
|
int statResult;
|
||
|
XP_StatStruct st;
|
||
|
DBFolderInfo *folderInfo = NULL;
|
||
|
XP_Bool newFile = FALSE;
|
||
|
char *dbName;
|
||
|
|
||
|
*pMessageDB = NULL;
|
||
|
|
||
|
if (m_cacheEnabled)
|
||
|
{
|
||
|
dbName = WH_FileName(folderName, xpMailFolderSummary);
|
||
|
if (!dbName) return eOUT_OF_MEMORY;
|
||
|
mailDB = (MailDB *) FindInCache(dbName);
|
||
|
XP_FREE(dbName);
|
||
|
if (mailDB)
|
||
|
{
|
||
|
*pMessageDB = mailDB;
|
||
|
// make this behave like the non-cache case. Is global dB set? DMB TODO
|
||
|
++(mailDB->m_useCount);
|
||
|
return(eSUCCESS);
|
||
|
}
|
||
|
}
|
||
|
// if the old summary doesn't exist, we're creating a new one.
|
||
|
if (XP_Stat (folderName, &st, xpMailFolderSummary) && create)
|
||
|
newFile = TRUE;
|
||
|
|
||
|
|
||
|
mailDB = new MailDB;
|
||
|
|
||
|
if (!mailDB)
|
||
|
return(eOUT_OF_MEMORY);
|
||
|
|
||
|
mailDB->m_folderName = XP_STRDUP(folderName);
|
||
|
|
||
|
dbName = WH_FileName(folderName, xpMailFolderSummary);
|
||
|
if (!dbName) return eOUT_OF_MEMORY;
|
||
|
// stat file before we open the db, because if we've latered
|
||
|
// any messages, handling latered will change time stamp on
|
||
|
// folder file.
|
||
|
statResult = XP_Stat (folderName, &st, xpMailFolder);
|
||
|
|
||
|
MsgERR err = mailDB->MessageDBOpen(dbName, create);
|
||
|
XP_FREE(dbName);
|
||
|
|
||
|
if (err == eSUCCESS)
|
||
|
{
|
||
|
folderInfo = mailDB->GetDBFolderInfo();
|
||
|
if (folderInfo == NULL)
|
||
|
{
|
||
|
err = eOldSummaryFile;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// if opening existing file, make sure summary file is up to date.
|
||
|
// if caller is upgrading, don't return eOldSummaryFile so the caller
|
||
|
// can pull out the transfer info for the new db.
|
||
|
if (!newFile && !statResult && !upgrading)
|
||
|
{
|
||
|
if (folderInfo->m_folderSize != st.st_size ||
|
||
|
folderInfo->m_folderDate != st.st_mtime || folderInfo->GetNumNewMessages() < 0)
|
||
|
err = eOldSummaryFile;
|
||
|
}
|
||
|
// compare current version of db versus filed out version info.
|
||
|
if (mailDB->GetCurVersion() != folderInfo->GetDiskVersion())
|
||
|
err = eOldSummaryFile;
|
||
|
}
|
||
|
if (err != eSUCCESS)
|
||
|
{
|
||
|
mailDB->Close();
|
||
|
mailDB = NULL;
|
||
|
}
|
||
|
}
|
||
|
if (err != eSUCCESS || newFile)
|
||
|
{
|
||
|
// if we couldn't open file, or we have a blank one, and we're supposed
|
||
|
// to upgrade, updgrade it.
|
||
|
if (newFile && !upgrading) // caller is upgrading, and we have empty summary file,
|
||
|
{ // leave db around and open so caller can upgrade it.
|
||
|
err = eNoSummaryFile;
|
||
|
}
|
||
|
else if (err != eSUCCESS)
|
||
|
{
|
||
|
*pMessageDB = NULL;
|
||
|
delete mailDB;
|
||
|
}
|
||
|
}
|
||
|
if (err == eSUCCESS || err == eNoSummaryFile)
|
||
|
{
|
||
|
*pMessageDB = mailDB;
|
||
|
if (m_cacheEnabled)
|
||
|
GetDBCache()->Add(mailDB);
|
||
|
if (err == eSUCCESS)
|
||
|
mailDB->HandleLatered();
|
||
|
|
||
|
}
|
||
|
return(err);
|
||
|
}
|
||
|
|
||
|
// This routine opens an invalid db, pulls out the information worth saving, (like sort order),
|
||
|
// blows away the invalid db, creates a new empty one, and restores the information worth saving.
|
||
|
/* static */
|
||
|
MsgERR MailDB::CloneInvalidDBInfoIntoNewDB(const char * pathname, MailDB** pMailDB)
|
||
|
{
|
||
|
XP_StatStruct folderst;
|
||
|
MailDB *mailDB;
|
||
|
TDBFolderInfoTransfer *originalInfo = NULL;
|
||
|
|
||
|
int status = MailDB::Open(pathname, TRUE, &mailDB, TRUE);
|
||
|
|
||
|
if (status == eSUCCESS && mailDB != NULL)
|
||
|
{
|
||
|
originalInfo = new TDBFolderInfoTransfer(*mailDB->GetDBFolderInfo());
|
||
|
mailDB->Close();
|
||
|
}
|
||
|
|
||
|
XP_Trace("blowing away old summary file\n");
|
||
|
if (!XP_Stat(pathname, &folderst, xpMailFolderSummary) && XP_FileRemove(pathname, xpMailFolderSummary) != 0)
|
||
|
{
|
||
|
status = MK_MSG_CANT_OPEN;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
status = MailDB::Open(pathname, TRUE, &mailDB, TRUE);
|
||
|
if (originalInfo)
|
||
|
{
|
||
|
if (status == eSUCCESS && mailDB != NULL)
|
||
|
originalInfo->TransferFolderInfo(*mailDB->GetDBFolderInfo());
|
||
|
delete originalInfo;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
*pMailDB = mailDB;
|
||
|
return status;
|
||
|
}
|
||
|
|
||
|
MSG_FolderInfo *MailDB::GetFolderInfo()
|
||
|
{
|
||
|
if (!m_folderInfo)
|
||
|
{
|
||
|
m_folderInfo = m_master->FindMailFolder(m_folderName, FALSE);
|
||
|
}
|
||
|
return m_folderInfo;
|
||
|
}
|
||
|
|
||
|
|
||
|
// caller needs to unrefer when finished.
|
||
|
MailMessageHdr *MailDB::GetMailHdrForKey(MessageKey messageKey)
|
||
|
{
|
||
|
MailMessageHdr *headerObject = NULL;
|
||
|
MSG_HeaderHandle headerHandle = MSG_DBHandle_GetHandleForKey(m_dbHandle, messageKey);
|
||
|
if (headerHandle)
|
||
|
headerObject = new MailMessageHdr(headerHandle);
|
||
|
|
||
|
return headerObject;
|
||
|
}
|
||
|
|
||
|
MsgERR MailDB::DeleteMessages(IDArray &messageKeys, ChangeListener *instigator)
|
||
|
{
|
||
|
m_folderFile = XP_FileOpen(m_folderName, xpMailFolder,
|
||
|
XP_FILE_UPDATE_BIN);
|
||
|
MsgERR err = MessageDB::DeleteMessages(messageKeys, instigator);
|
||
|
if (m_folderFile)
|
||
|
XP_FileClose(m_folderFile);
|
||
|
m_folderFile = NULL;
|
||
|
SetFolderInfoValid(m_folderName, 0, 0);
|
||
|
return err;
|
||
|
}
|
||
|
|
||
|
// Helper routine - lowest level of flag setting
|
||
|
void MailDB::SetHdrFlag(DBMessageHdr *msgHdr, XP_Bool bSet, MsgFlags flag)
|
||
|
{
|
||
|
XP_File fid = NULL;
|
||
|
|
||
|
MessageDB::SetHdrFlag(msgHdr, bSet, flag);
|
||
|
// update summary flag
|
||
|
if (msgHdr->GetFlags() & kDirty)
|
||
|
{
|
||
|
// ### Hack - we know it's a mail message hdr 'cuz it's in a maildb
|
||
|
// ImapMailDB::UpdateFolderFlag does nothing
|
||
|
UpdateFolderFlag((MailMessageHdr *) msgHdr, bSet, flag, &fid);
|
||
|
if (fid != NULL)
|
||
|
{
|
||
|
XP_FileClose(fid);
|
||
|
SetFolderInfoValid(m_folderName, 0, 0);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// We let the caller close the file in case he's updating a lot of flags
|
||
|
// and we don't want to open and close the file every time through.
|
||
|
// As an experiment, try caching the fid in the db as m_folderFile.
|
||
|
// If this is set, use it but don't return *pFid.
|
||
|
void MailDB::UpdateFolderFlag(MailMessageHdr *mailHdr, XP_Bool /*bSet*/,
|
||
|
MsgFlags /*flag*/, XP_File *pFid)
|
||
|
{
|
||
|
static char buf[30];
|
||
|
XP_File fid = (m_folderFile) ? m_folderFile : *pFid;
|
||
|
if (mailHdr->GetFlags() & kDirty)
|
||
|
{
|
||
|
if (mailHdr->GetStatusOffset() > 0)
|
||
|
{
|
||
|
if (fid == NULL)
|
||
|
{
|
||
|
fid = XP_FileOpen(m_folderName, xpMailFolder,
|
||
|
XP_FILE_UPDATE_BIN);
|
||
|
}
|
||
|
if (fid)
|
||
|
{
|
||
|
uint32 position =
|
||
|
mailHdr->GetStatusOffset() + mailHdr->GetMessageOffset();
|
||
|
XP_ASSERT(mailHdr->GetStatusOffset() < 10000);
|
||
|
XP_FileSeek(fid, position, SEEK_SET);
|
||
|
buf[0] = '\0';
|
||
|
if (XP_FileReadLine(buf, sizeof(buf), fid))
|
||
|
{
|
||
|
if (strncmp(buf, X_MOZILLA_STATUS, X_MOZILLA_STATUS_LEN) == 0 &&
|
||
|
strncmp(buf + X_MOZILLA_STATUS_LEN, ": ", 2) == 0 &&
|
||
|
strlen(buf) > X_MOZILLA_STATUS_LEN + 6)
|
||
|
{
|
||
|
XP_FileSeek(fid, position, SEEK_SET);
|
||
|
// We are filing out old Cheddar flags here
|
||
|
XP_FilePrintf(fid, X_MOZILLA_STATUS_FORMAT,
|
||
|
(mailHdr->GetMozillaStatusFlags() & ~MSG_FLAG_RUNTIME_ONLY));
|
||
|
// time to upate x-mozilla-status2
|
||
|
position = XP_FileTell(fid);
|
||
|
XP_FileSeek(fid, position + LINEBREAK_LEN, SEEK_SET);
|
||
|
if (XP_FileReadLine(buf, sizeof(buf), fid))
|
||
|
{
|
||
|
if (strncmp(buf, X_MOZILLA_STATUS2, X_MOZILLA_STATUS2_LEN) == 0 &&
|
||
|
strncmp(buf + X_MOZILLA_STATUS2_LEN, ": ", 2) == 0 &&
|
||
|
strlen(buf) > X_MOZILLA_STATUS2_LEN + 10)
|
||
|
{
|
||
|
uint32 dbFlags = mailHdr->GetFlags();
|
||
|
MessageDB::ConvertDBFlagsToPublicFlags(&dbFlags);
|
||
|
dbFlags &= (MSG_FLAG_MDN_REPORT_NEEDED | MSG_FLAG_MDN_REPORT_SENT | MSG_FLAG_TEMPLATE);
|
||
|
XP_FileSeek(fid, position + LINEBREAK_LEN, SEEK_SET);
|
||
|
XP_FilePrintf(fid, X_MOZILLA_STATUS2_FORMAT, dbFlags);
|
||
|
}
|
||
|
}
|
||
|
} else
|
||
|
{
|
||
|
PRINTF(("Didn't find %s where expected at position %ld\n"
|
||
|
"instead, found %s.\n",
|
||
|
X_MOZILLA_STATUS, (long) position, buf));
|
||
|
SetReparse(TRUE);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
PRINTF(("Couldn't read old status line at all at position %ld\n",
|
||
|
(long) position));
|
||
|
SetReparse(TRUE);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
PRINTF(("Couldn't open mail folder for update%s!\n", m_folderName));
|
||
|
XP_ASSERT(FALSE);
|
||
|
}
|
||
|
}
|
||
|
if (!m_folderFile)
|
||
|
*pFid = fid;
|
||
|
mailHdr->AndFlags(~kDirty);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Use this function if you have the correct counts, but just want to protect
|
||
|
// from a crash. In theory, this Commit should be quick, since there's only
|
||
|
// one or two dirty objects.
|
||
|
MsgERR MailDB::SetSummaryValid(XP_Bool valid /*= TRUE*/)
|
||
|
{
|
||
|
XP_StatStruct folderst;
|
||
|
|
||
|
if (XP_Stat((char*) m_folderName, &folderst, xpMailFolder))
|
||
|
return eDBExistsNot;
|
||
|
if (valid)
|
||
|
{
|
||
|
m_dbFolderInfo->m_folderSize = folderst.st_size;
|
||
|
m_dbFolderInfo->m_folderDate = folderst.st_mtime;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
m_dbFolderInfo->m_folderDate = 0; // that ought to do the trick.
|
||
|
}
|
||
|
// m_dbFolderInfo->setDirty(); DMB TODO
|
||
|
Commit();
|
||
|
return eSUCCESS;
|
||
|
}
|
||
|
|
||
|
MsgERR MailDB::GetIdsWithNoBodies (IDArray &bodylessIds)
|
||
|
{
|
||
|
DBMessageHdr *currentHeader;
|
||
|
ListContext *listContext = NULL;
|
||
|
MsgERR dbErr = ListFirst (&listContext, ¤tHeader);
|
||
|
int32 maxMsgSize = 0x7fffffff;
|
||
|
XP_Bool respectMsgSizeLimit = FALSE;
|
||
|
|
||
|
PREF_GetBoolPref("mail.limit_message_size", &respectMsgSizeLimit);
|
||
|
|
||
|
if (respectMsgSizeLimit && PREF_OK == PREF_GetIntPref("mail.max_size", &maxMsgSize))
|
||
|
maxMsgSize *= 1024;
|
||
|
|
||
|
while (dbErr == eSUCCESS)
|
||
|
{
|
||
|
if (0 == ((MailMessageHdr *)currentHeader)->GetOfflineMessageLength(GetDB()) && currentHeader->GetByteLength() < (uint32) maxMsgSize)
|
||
|
bodylessIds.Add(currentHeader->GetMessageKey());
|
||
|
delete currentHeader;
|
||
|
dbErr = ListNext(listContext, ¤tHeader);
|
||
|
}
|
||
|
|
||
|
if (dbErr == eDBEndOfList)
|
||
|
{
|
||
|
dbErr = eSUCCESS;
|
||
|
ListDone(listContext);
|
||
|
}
|
||
|
|
||
|
return dbErr;
|
||
|
}
|
||
|
|
||
|
/* static */
|
||
|
MsgERR MailDB::SetFolderInfoValid(const char* pathname, int num, int numunread)
|
||
|
{
|
||
|
XP_StatStruct folderst;
|
||
|
MsgERR err;
|
||
|
|
||
|
if (XP_Stat((char*) pathname, &folderst, xpMailFolder))
|
||
|
return eDBExistsNot;
|
||
|
|
||
|
char *dbName = WH_FileName(pathname, xpMailFolderSummary);
|
||
|
if (!dbName) return eOUT_OF_MEMORY;
|
||
|
MessageDB *pMessageDB = MessageDB::FindInCache(dbName);
|
||
|
if (pMessageDB == NULL)
|
||
|
{
|
||
|
pMessageDB = new MailDB;
|
||
|
// ### this does later stuff (marks latered messages unread), which may be a problem
|
||
|
err = pMessageDB->MessageDBOpen(dbName, FALSE);
|
||
|
if (err != eSUCCESS)
|
||
|
{
|
||
|
delete pMessageDB;
|
||
|
pMessageDB = NULL;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
pMessageDB->AddUseCount();
|
||
|
|
||
|
XP_FREE(dbName);
|
||
|
|
||
|
if (pMessageDB == NULL)
|
||
|
{
|
||
|
XP_Trace("Exception opening summary file\n");
|
||
|
return eOldSummaryFile;
|
||
|
}
|
||
|
|
||
|
pMessageDB->m_dbFolderInfo->m_folderSize = folderst.st_size;
|
||
|
pMessageDB->m_dbFolderInfo->m_folderDate = folderst.st_mtime;
|
||
|
pMessageDB->m_dbFolderInfo->ChangeNumVisibleMessages(num);
|
||
|
pMessageDB->m_dbFolderInfo->ChangeNumNewMessages(numunread);
|
||
|
pMessageDB->m_dbFolderInfo->ChangeNumMessages(num);
|
||
|
pMessageDB->Close();
|
||
|
return eSUCCESS;
|
||
|
}
|
||
|
|
||
|
|
||
|
// This is used to remember that the db is out of sync with the mail folder
|
||
|
// and needs to be regenerated.
|
||
|
void MailDB::SetReparse(XP_Bool reparse)
|
||
|
{
|
||
|
m_reparse = reparse;
|
||
|
}
|
||
|
|
||
|
ImapMailDB::ImapMailDB() : MailDB()
|
||
|
{
|
||
|
}
|
||
|
|
||
|
ImapMailDB::~ImapMailDB()
|
||
|
{}
|
||
|
|
||
|
MsgERR ImapMailDB::Open(const char * folderName, XP_Bool create,
|
||
|
MailDB** pMessageDB,
|
||
|
MSG_Master* mailMaster,
|
||
|
XP_Bool *dbWasCreated)
|
||
|
{
|
||
|
ImapMailDB *mailDB=NULL;
|
||
|
XP_StatStruct st;
|
||
|
DBFolderInfo *folderInfo = NULL;
|
||
|
XP_Bool newFile = FALSE;
|
||
|
char* dbName;
|
||
|
MsgERR err=eUNKNOWN;
|
||
|
XP_Bool dbFoundInCache=FALSE;
|
||
|
|
||
|
XP_ASSERT(mailMaster);
|
||
|
|
||
|
*dbWasCreated = FALSE;
|
||
|
|
||
|
// code below can't call XP_File routines, or dbName will be crunched.
|
||
|
|
||
|
if (m_cacheEnabled)
|
||
|
{
|
||
|
dbName = WH_FileName(folderName, xpMailFolderSummary);
|
||
|
if (!dbName) return eOUT_OF_MEMORY;
|
||
|
mailDB = (ImapMailDB *) FindInCache(dbName);
|
||
|
XP_FREE(dbName);
|
||
|
if (mailDB)
|
||
|
{
|
||
|
*pMessageDB = mailDB;
|
||
|
++(mailDB->m_useCount);
|
||
|
// make this behave like the non-cache case. Is global DB set? DMB TODO
|
||
|
err = eSUCCESS;
|
||
|
dbFoundInCache = TRUE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (!dbFoundInCache)
|
||
|
{
|
||
|
// if the old summary doesn't exist, we're creating a new one.
|
||
|
if (XP_Stat (folderName, &st, xpMailFolderSummary) && create)
|
||
|
{
|
||
|
newFile = TRUE;
|
||
|
*dbWasCreated = TRUE;
|
||
|
}
|
||
|
|
||
|
mailDB = new ImapMailDB;
|
||
|
if (!mailDB)
|
||
|
{
|
||
|
*pMessageDB = NULL;
|
||
|
return(eOUT_OF_MEMORY);
|
||
|
}
|
||
|
mailDB->m_folderName = XP_STRDUP(folderName);
|
||
|
|
||
|
dbName = WH_FileName(folderName, xpMailFolderSummary);
|
||
|
if (!dbName) {
|
||
|
err = eOUT_OF_MEMORY;
|
||
|
} else {
|
||
|
err = mailDB->MessageDBOpen(dbName, create);
|
||
|
XP_FREE(dbName);
|
||
|
}
|
||
|
if (err == eSUCCESS)
|
||
|
{
|
||
|
folderInfo = mailDB->GetDBFolderInfo();
|
||
|
// if opening existing file, make sure summary file is up to date.
|
||
|
if (!newFile && !XP_Stat (folderName, &st, xpMailFolder))
|
||
|
{
|
||
|
if (folderInfo->m_folderSize != st.st_size)
|
||
|
err = eOldSummaryFile;
|
||
|
}
|
||
|
if (mailDB->GetCurVersion() != folderInfo->GetDiskVersion())
|
||
|
err = eOldSummaryFile;
|
||
|
if (err != eSUCCESS)
|
||
|
{
|
||
|
mailDB->Close();
|
||
|
mailDB = NULL;
|
||
|
}
|
||
|
}
|
||
|
if (err == eSUCCESS)
|
||
|
{
|
||
|
*pMessageDB = mailDB;
|
||
|
if (m_cacheEnabled)
|
||
|
GetDBCache()->Add(mailDB);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (mailDB)
|
||
|
{
|
||
|
mailDB->SetMaster(mailMaster);
|
||
|
if (mailMaster)
|
||
|
{
|
||
|
// this causes an infinite recursion, so don't do it.
|
||
|
// MSG_FolderInfoMail *folderInfo = mailMaster->FindImapMailFolder(folderName);
|
||
|
// mailDB->SetFolderInfo(folderInfo);
|
||
|
}
|
||
|
}
|
||
|
return(err);
|
||
|
}
|
||
|
|
||
|
void ImapMailDB::UpdateFolderFlag(MailMessageHdr *, XP_Bool ,
|
||
|
MsgFlags , XP_File *fid)
|
||
|
{
|
||
|
fid = NULL;
|
||
|
}
|
||
|
|
||
|
MSG_FolderInfo *ImapMailDB::GetFolderInfo()
|
||
|
{
|
||
|
if (!m_folderInfo)
|
||
|
{
|
||
|
XPStringObj mailBoxName;
|
||
|
|
||
|
m_dbFolderInfo->GetMailboxName(mailBoxName);
|
||
|
m_folderInfo = m_master->FindImapMailFolderFromPath(m_folderName);
|
||
|
}
|
||
|
return m_folderInfo;
|
||
|
}
|
||
|
|
||
|
|
||
|
// caller needs to unrefer when finished.
|
||
|
DBOfflineImapOperation *MailDB::GetOfflineOpForKey(MessageKey messageKey, XP_Bool create)
|
||
|
{
|
||
|
DBOfflineImapOperation *offlineObject = NULL;
|
||
|
MSG_OfflineIMAPOperationHandle offlineOpHandle = MSG_DBHandle_GetOfflineOp(m_dbHandle, messageKey);
|
||
|
if (offlineOpHandle)
|
||
|
{
|
||
|
offlineObject = new DBOfflineImapOperation;
|
||
|
if (offlineObject)
|
||
|
{
|
||
|
offlineObject->SetHandle(offlineOpHandle);
|
||
|
offlineObject->SetDBHandle(m_dbHandle);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (!offlineObject && create)
|
||
|
{
|
||
|
offlineObject = new DBOfflineImapOperation;
|
||
|
if (offlineObject)
|
||
|
{
|
||
|
offlineObject->SetHandle(GetOfflineIMAPOperation());
|
||
|
|
||
|
offlineObject->SetMessageKey(messageKey);
|
||
|
offlineObject->SetDBHandle(m_dbHandle);
|
||
|
|
||
|
// if there is a corresponding msg, use its flags
|
||
|
MailMessageHdr *msgHdr = GetMailHdrForKey(messageKey);
|
||
|
if (msgHdr)
|
||
|
{
|
||
|
imapMessageFlagsType imapFlags = kNoImapMsgFlag;
|
||
|
if (msgHdr->GetFlags() & MSG_FLAG_READ)
|
||
|
imapFlags |= kImapMsgSeenFlag;
|
||
|
if (msgHdr->GetFlags() & MSG_FLAG_REPLIED)
|
||
|
imapFlags |= kImapMsgAnsweredFlag;
|
||
|
if (msgHdr->GetFlags() & MSG_FLAG_MARKED)
|
||
|
imapFlags |= kImapMsgFlaggedFlag;
|
||
|
if (msgHdr->GetFlags() & MSG_FLAG_FORWARDED)
|
||
|
imapFlags |= kImapMsgForwardedFlag;
|
||
|
offlineObject->SetInitialImapFlags(imapFlags);
|
||
|
delete msgHdr;
|
||
|
}
|
||
|
|
||
|
AddOfflineOp(offlineObject);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return offlineObject;
|
||
|
}
|
||
|
|
||
|
MsgERR MailDB::SetSourceMailbox(DBOfflineImapOperation *op, const char *mailbox, MessageKey key)
|
||
|
{
|
||
|
MsgERR err = MSG_OfflineIMAPOperationHandle_SetSourceMailbox(op->GetHandle(), m_dbHandle, mailbox, key);
|
||
|
if (err == eCorruptDB)
|
||
|
SetSummaryValid(FALSE);
|
||
|
return err;
|
||
|
}
|
||
|
|
||
|
MsgERR MailDB::ListAllOfflineOpIds(IDArray &outputIds)
|
||
|
{
|
||
|
MessageKey *resultKeys;
|
||
|
int32 numKeys;
|
||
|
MsgERR err = MSG_DBHandle_ListAllOflineOperationKeys(m_dbHandle, &resultKeys, &numKeys);
|
||
|
outputIds.SetArray(resultKeys, numKeys, numKeys);
|
||
|
return err;
|
||
|
}
|
||
|
|
||
|
// List the ids of messages that are going to be deleted via offline playback,
|
||
|
// because we don't need to refetch those headers.
|
||
|
int MailDB::ListAllOfflineDeletes(IDArray &outputIds)
|
||
|
{
|
||
|
MessageKey *deletedKeys;
|
||
|
int32 numKeys;
|
||
|
MsgERR err = MSG_DBHandle_ListAllOfflineDeletedMessageKeys(m_dbHandle, &deletedKeys, &numKeys);
|
||
|
outputIds.Add(deletedKeys, numKeys);
|
||
|
XP_FREE(deletedKeys);
|
||
|
return numKeys;
|
||
|
}
|
||
|
|
||
|
MsgERR MailDB::AddOfflineOp(DBOfflineImapOperation *op)
|
||
|
{
|
||
|
MSG_DBHandle_AddOfflineOperation(m_dbHandle, op->GetHandle());
|
||
|
MSG_FolderInfo *folderInfo = GetFolderInfo();
|
||
|
XP_ASSERT(folderInfo); // it would be bad if we couldn't get the folder info.
|
||
|
if (folderInfo)
|
||
|
{
|
||
|
folderInfo->SetFolderPrefFlags(folderInfo->GetFolderPrefFlags() | MSG_FOLDER_PREF_OFFLINEEVENTS);
|
||
|
if (folderInfo->GetType() == FOLDER_IMAPMAIL)
|
||
|
{
|
||
|
MSG_IMAPFolderInfoMail *imapFolder = (MSG_IMAPFolderInfoMail *) folderInfo;
|
||
|
imapFolder->SetHasOfflineEvents(TRUE);
|
||
|
// where should we clear this flag? At the end of the process events url?
|
||
|
}
|
||
|
}
|
||
|
return eSUCCESS;
|
||
|
}
|
||
|
|
||
|
MsgERR MailDB::DeleteOfflineOp(MessageKey opKey)
|
||
|
{
|
||
|
DBOfflineImapOperation *doomedOp = GetOfflineOpForKey(opKey, FALSE);
|
||
|
if (doomedOp)
|
||
|
{
|
||
|
MSG_DBHandle_RemoveOfflineOperation(m_dbHandle, doomedOp->GetHandle());
|
||
|
delete doomedOp;
|
||
|
}
|
||
|
return eSUCCESS;
|
||
|
}
|
||
|
|
||
|
MsgERR ImapMailDB::SetSummaryValid(XP_Bool valid /* = TRUE */)
|
||
|
{
|
||
|
return MessageDB::SetSummaryValid(valid);
|
||
|
}
|