gecko-dev/lib/libmsg/msgpurge.cpp

234 строки
6.1 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.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
#include "msg.h"
#include "newspane.h"
#include "msgfinfo.h"
#include "pmsgsrch.h"
#include "newshdr.h"
#include "newsdb.h"
#include "xpgetstr.h"
#include "msgpurge.h"
#include "grpinfo.h"
#include "newshdr.h"
extern "C"
{
extern int MK_MSG_PURGING_NEWSGROUP_HEADER;
extern int MK_MSG_PURGING_NEWSGROUP_ARTICLE;
extern int MK_MSG_PURGING_NEWSGROUP_ETC;
extern int MK_MSG_PURGING_NEWSGROUP_DONE;
}
const int kPurgeCommitChunk = 200;
MSG_PurgeNewsgroupState::MSG_PurgeNewsgroupState(MSG_Pane *pane, MSG_FolderInfo *folder)
{
m_purgeCount = 0;
m_context = pane->GetContext();
m_folder = folder;
m_pane = pane;
m_listContext = NULL;
m_newsDB = NULL;
m_headerIndex = 0;
m_groupInfo = NULL;
m_headerPurgeInfo.m_purgeBy = MSG_PurgeNone;
}
MSG_PurgeNewsgroupState::~MSG_PurgeNewsgroupState()
{
if (m_newsDB)
{
if (m_listContext)
m_newsDB->ListDone (m_listContext);
m_newsDB->Close();
}
}
MsgERR MSG_PurgeNewsgroupState::Init()
{
MessageDB *newsDB;
DBFolderInfo *groupInfo;
MsgERR err = m_folder->GetDBFolderInfoAndDB(&groupInfo, &newsDB);
m_newsDB = newsDB->GetNewsDB();
const char *fmt = XP_GetString(MK_MSG_PURGING_NEWSGROUP_ETC);
const char *f = m_folder->GetPrettiestName();
char *statusString = PR_smprintf (fmt, f);
if (statusString)
{
FE_Progress(m_context, statusString);
XP_FREE(statusString);
}
MSG_GetHeaderPurgingInfo(m_folder, &m_headerPurgeInfo.m_useDefaults, &m_headerPurgeInfo.m_purgeBy,
&m_headerPurgeInfo.m_unreadOnly, &m_headerPurgeInfo.m_daysToKeep, &m_headerPurgeInfo.m_numHeadersToKeep);
MSG_GetArticlePurgingInfo(m_folder, &m_articlePurgeInfo.m_useDefaults, &m_articlePurgeInfo.m_purgeBy,
&m_articlePurgeInfo.m_daysToKeep);
m_groupInfo = m_newsDB->GetNewsFolderInfo();
m_pNextHeader = NULL;
return err;
}
int MSG_PurgeNewsgroupState::PurgeSomeMore()
{
MsgERR dbErr = eSUCCESS;
DBMessageHdr *pHeader = m_pNextHeader;
XP_Bool purgedSomething = FALSE;
if (!m_listContext)
dbErr = m_newsDB->ListFirst (&m_listContext, &pHeader);
// advance the iterator so we can delete this message.
if (eSUCCESS == dbErr && pHeader != NULL)
dbErr = m_newsDB->ListNext (m_listContext, &m_pNextHeader);
if (eSUCCESS != dbErr)
m_pNextHeader = NULL; // next time through, we'll return MK_CONNECTED.
if (pHeader == NULL)
{
// Do clean up for end-of-scope processing
if (m_listContext)
m_newsDB->ListDone (m_listContext);
m_listContext = NULL;
// Let go of the DB when we're done with it so we don't kill the db cache
if (m_newsDB)
m_newsDB->Close();
m_newsDB = NULL;
return MK_CONNECTED;
}
int32 percent = (100L * m_headerIndex) / (uint32) m_groupInfo->GetNumMessages();
FE_SetProgressBarPercent (m_context, percent);
if (m_articlePurgeInfo.m_purgeBy == MSG_PurgeByAge)
{
time_t now = XP_TIME();
long matchDay = now - (m_articlePurgeInfo.m_daysToKeep * 60 * 60 * 24);
if (pHeader->GetDate() < matchDay)
{
pHeader->PurgeArticle();
purgedSomething = TRUE;
}
}
if (m_headerPurgeInfo.m_unreadOnly)
{
XP_Bool isRead;
if (m_newsDB->IsRead(pHeader->GetMessageKey(), &isRead) == eSUCCESS && isRead)
PurgeHeader(pHeader);
else
{
delete pHeader;
m_headerIndex++;
}
}
else
{
switch (m_headerPurgeInfo.m_purgeBy)
{
case MSG_PurgeByAge:
{
time_t now = XP_TIME();
long matchDay = now - (m_headerPurgeInfo.m_daysToKeep * 60 * 60 * 24);
if (pHeader->GetDate() < matchDay)
PurgeHeader(pHeader);
else
{
delete pHeader;
m_headerIndex++;
}
break;
}
case MSG_PurgeByNumHeaders:
{
int32 numInDB = (m_headerPurgeInfo.m_unreadOnly) ? m_groupInfo->GetNumNewMessages() : m_groupInfo->GetNumMessages();
if (m_headerIndex < (numInDB - m_headerPurgeInfo.m_numHeadersToKeep + 1))
PurgeHeader(pHeader);
else
{
delete pHeader;
m_headerIndex++;
}
break;
}
default:
delete pHeader;
m_headerIndex++;
if (!purgedSomething)
{
if (m_pNextHeader)
{
delete m_pNextHeader;
m_pNextHeader = NULL;
}
return MK_CONNECTED;
}
}
}
// don't want to purge at MOD of 0, because when we're deleting by number
// of headers, m_headerIndex will stay at 0 for a while.
if (m_newsDB && m_headerIndex % kPurgeCommitChunk == 1)
m_newsDB->Commit();
return MK_WAITING_FOR_CONNECTION;
}
int MSG_PurgeNewsgroupState::FinishPurging()
{
if (m_folder)
m_folder->ClearRequiresCleanup();
return MK_CONNECTED;
}
void MSG_PurgeNewsgroupState::PurgeHeader(DBMessageHdr *hdr)
{
if (hdr != NULL)
{
m_newsDB->DeleteHeader(hdr, NULL, !(m_purgeCount % 200));
m_purgeCount++;
char *statusTemplate = XP_GetString (MK_MSG_PURGING_NEWSGROUP_HEADER);
char *statusString = PR_smprintf (statusTemplate, m_folder->GetPrettiestName(), m_purgeCount);
if (statusString)
{
FE_Progress (m_context, statusString);
XP_FREE(statusString);
}
}
}
void MSG_PurgeNewsgroupState::PurgeArticle(DBMessageHdr *hdr)
{
if (hdr != NULL)
{
// OK, we know it's a news hdr becuase it's a newsdb.
NewsMessageHdr *newsHdr = (NewsMessageHdr *) hdr;
newsHdr->PurgeArticle();
m_purgeCount++;
char *statusTemplate = XP_GetString (MK_MSG_PURGING_NEWSGROUP_ARTICLE);
char *statusString = PR_smprintf (statusTemplate, m_folder->GetPrettiestName(), m_purgeCount);
if (statusString)
{
FE_Progress (m_context, statusString);
XP_FREE(statusString);
}
}
}