mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-09 11:25:00 +00:00
change folder compaction to use base class offine store compaction code, 15865 r=naving, sr=mscott
This commit is contained in:
parent
0cddd31ff7
commit
f7d03cb909
@ -82,6 +82,7 @@
|
||||
#include "nsIInterfaceRequestor.h"
|
||||
#include "nsIPop3URL.h"
|
||||
#include "nsIMsgMailSession.h"
|
||||
#include "nsIMsgFolderCompactor.h"
|
||||
|
||||
|
||||
static NS_DEFINE_CID(kRDFServiceCID, NS_RDFSERVICE_CID);
|
||||
@ -100,278 +101,6 @@ extern char* ReadPopData(const char *hostname, const char* username, nsIFileSpec
|
||||
extern void SavePopData(char *data, nsIFileSpec* maildirectory);
|
||||
extern void net_pop3_delete_if_in_server(char *data, char *uidl, PRBool *changed);
|
||||
extern void KillPopData(char* data);
|
||||
//static void net_pop3_free_state(Pop3UidlHost* host);
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// nsFolderCompactState
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class nsFolderCompactState : public nsIStreamListener
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSISTREAMOBSERVER
|
||||
NS_DECL_NSISTREAMLISTENER
|
||||
|
||||
nsFolderCompactState(void);
|
||||
virtual ~nsFolderCompactState(void);
|
||||
nsresult FinishCompact();
|
||||
nsresult GetMessage(nsIMessage **message);
|
||||
|
||||
char *m_baseMessageUri; // base message uri
|
||||
nsCString m_messageUri; // current message uri being copy
|
||||
nsCOMPtr<nsIMsgFolder> m_folder; // current folder being compact
|
||||
nsCOMPtr<nsIMsgDatabase> m_db; // new database for the compact folder
|
||||
nsFileSpec m_fileSpec; // new mailbox for the compact folder
|
||||
nsOutputFileStream *m_fileStream; // output file stream for writing
|
||||
nsMsgKeyArray m_keyArray; // all message keys need to be copied over
|
||||
PRInt32 m_size; // size of the message key array
|
||||
PRInt32 m_curIndex; // index of the current copied message key in key array
|
||||
nsMsgKey m_newKey; // new message key for the copied message
|
||||
char m_dataBuffer[FOUR_K + 1]; // temp data buffer for copying message
|
||||
nsresult m_status; // the status of the copying operation
|
||||
nsIMsgMessageService* m_messageService; // message service for copying
|
||||
// message
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS2(nsFolderCompactState, nsIStreamObserver, nsIStreamListener)
|
||||
|
||||
nsFolderCompactState::nsFolderCompactState()
|
||||
{
|
||||
NS_INIT_ISUPPORTS();
|
||||
m_baseMessageUri = nsnull;
|
||||
m_fileStream = nsnull;
|
||||
m_size = 0;
|
||||
m_curIndex = -1;
|
||||
m_status = NS_OK;
|
||||
m_messageService = nsnull;
|
||||
}
|
||||
|
||||
nsFolderCompactState::~nsFolderCompactState()
|
||||
{
|
||||
if (m_fileStream)
|
||||
{
|
||||
m_fileStream->close();
|
||||
delete m_fileStream;
|
||||
m_fileStream = nsnull;
|
||||
}
|
||||
|
||||
if (m_messageService)
|
||||
{
|
||||
ReleaseMessageServiceFromURI(m_baseMessageUri, m_messageService);
|
||||
m_messageService = nsnull;
|
||||
}
|
||||
|
||||
if (m_baseMessageUri)
|
||||
{
|
||||
nsCRT::free(m_baseMessageUri);
|
||||
m_baseMessageUri = nsnull;
|
||||
}
|
||||
|
||||
if (NS_FAILED(m_status))
|
||||
{
|
||||
// if for some reason we failed remove the temp folder and database
|
||||
if (m_db)
|
||||
m_db->ForceClosed();
|
||||
nsLocalFolderSummarySpec summarySpec(m_fileSpec);
|
||||
m_fileSpec.Delete(PR_FALSE);
|
||||
summarySpec.Delete(PR_FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsFolderCompactState::FinishCompact()
|
||||
{
|
||||
// All okay time to finish up the compact process
|
||||
nsresult rv = NS_OK;
|
||||
nsCOMPtr<nsIFileSpec> pathSpec;
|
||||
nsCOMPtr<nsIFolder> parent;
|
||||
nsCOMPtr<nsIMsgFolder> parentFolder;
|
||||
nsCOMPtr<nsIDBFolderInfo> folderInfo;
|
||||
nsFileSpec fileSpec;
|
||||
PRUint32 flags;
|
||||
|
||||
// get leaf name and database name of the folder
|
||||
m_folder->GetFlags(&flags);
|
||||
rv = m_folder->GetPath(getter_AddRefs(pathSpec));
|
||||
pathSpec->GetFileSpec(&fileSpec);
|
||||
|
||||
nsLocalFolderSummarySpec summarySpec(fileSpec);
|
||||
nsXPIDLCString idlName;
|
||||
nsString dbName;
|
||||
|
||||
pathSpec->GetLeafName(getter_Copies(idlName));
|
||||
summarySpec.GetLeafName(dbName);
|
||||
|
||||
// close down the temp file stream; preparing for deleting the old folder
|
||||
// and its database; then rename the temp folder and database
|
||||
m_fileStream->flush();
|
||||
m_fileStream->close();
|
||||
delete m_fileStream;
|
||||
m_fileStream = nsnull;
|
||||
|
||||
// make sure the new database is valid
|
||||
m_db->SetSummaryValid(PR_TRUE);
|
||||
m_db->Commit(nsMsgDBCommitType::kLargeCommit);
|
||||
m_db->ForceClosed();
|
||||
m_db = null_nsCOMPtr();
|
||||
|
||||
nsLocalFolderSummarySpec newSummarySpec(m_fileSpec);
|
||||
|
||||
// close down database of the original folder and remove the folder node
|
||||
// and all it's message node from the tree
|
||||
m_folder->ForceDBClosed();
|
||||
m_folder->GetParent(getter_AddRefs(parent));
|
||||
parentFolder = do_QueryInterface(parent, &rv);
|
||||
m_folder->SetParent(nsnull);
|
||||
parentFolder->PropagateDelete(m_folder, PR_FALSE);
|
||||
|
||||
// remove the old folder and database
|
||||
fileSpec.Delete(PR_FALSE);
|
||||
summarySpec.Delete(PR_FALSE);
|
||||
// rename the copied folder and database to be the original folder and
|
||||
// database
|
||||
m_fileSpec.Rename((const char*) idlName);
|
||||
newSummarySpec.Rename(dbName);
|
||||
|
||||
// add the node back the tree
|
||||
nsCOMPtr<nsIMsgFolder> child;
|
||||
nsAutoString folderName; folderName.AssignWithConversion((const char*) idlName);
|
||||
rv = parentFolder->AddSubfolder(&folderName, getter_AddRefs(child));
|
||||
if (child)
|
||||
{
|
||||
child->SetFlags(flags);
|
||||
nsCOMPtr<nsISupports> childSupports = do_QueryInterface(child);
|
||||
nsCOMPtr<nsISupports> parentSupports = do_QueryInterface(parentFolder);
|
||||
if (childSupports && parentSupports)
|
||||
{
|
||||
parentFolder->NotifyItemAdded(parentSupports, childSupports,
|
||||
"folderView");
|
||||
}
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsFolderCompactState::GetMessage(nsIMessage **message)
|
||||
{
|
||||
nsresult rv = NS_ERROR_NULL_POINTER;
|
||||
|
||||
if (!message) return rv;
|
||||
|
||||
NS_WITH_SERVICE(nsIRDFService, rdfService, kRDFServiceCID, &rv);
|
||||
if(NS_SUCCEEDED(rv))
|
||||
{
|
||||
nsCOMPtr<nsIRDFResource> msgResource;
|
||||
if(NS_SUCCEEDED(rdfService->GetResource(m_messageUri,
|
||||
getter_AddRefs(msgResource))))
|
||||
rv = msgResource->QueryInterface(NS_GET_IID(nsIMessage),
|
||||
(void**)message);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsFolderCompactState::OnStartRequest(nsIChannel *channel, nsISupports *ctxt)
|
||||
{
|
||||
nsresult rv = NS_ERROR_FAILURE;
|
||||
NS_ASSERTION(m_fileStream, "Fatal, null m_fileStream...\n");
|
||||
if (m_fileStream)
|
||||
{
|
||||
// record the new message key for the message
|
||||
m_fileStream->flush();
|
||||
m_newKey = m_fileStream->tell();
|
||||
rv = NS_OK;
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsFolderCompactState::OnStopRequest(nsIChannel *channel, nsISupports *ctxt,
|
||||
nsresult status,
|
||||
const PRUnichar *errorMsg)
|
||||
{
|
||||
nsresult rv = status;
|
||||
nsCOMPtr<nsIMessage> message;
|
||||
nsCOMPtr<nsIDBMessage> dbMessage;
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
nsCOMPtr<nsIMsgDBHdr> msgHdr;
|
||||
nsCOMPtr<nsIMsgDBHdr> newMsgHdr;
|
||||
|
||||
if (NS_FAILED(rv)) goto done;
|
||||
uri = do_QueryInterface(ctxt, &rv);
|
||||
if (NS_FAILED(rv)) goto done;
|
||||
rv = GetMessage(getter_AddRefs(message));
|
||||
if (NS_FAILED(rv)) goto done;
|
||||
dbMessage = do_QueryInterface(message, &rv);
|
||||
if (NS_FAILED(rv)) goto done;
|
||||
rv = dbMessage->GetMsgDBHdr(getter_AddRefs(msgHdr));
|
||||
if (NS_FAILED(rv)) goto done;
|
||||
|
||||
// okay done with the current message; copying the existing message header
|
||||
// to the new database
|
||||
m_db->CopyHdrFromExistingHdr(m_newKey, msgHdr, PR_TRUE,
|
||||
getter_AddRefs(newMsgHdr));
|
||||
|
||||
m_db->Commit(nsMsgDBCommitType::kLargeCommit);
|
||||
// advance to next message
|
||||
m_curIndex ++;
|
||||
if (m_curIndex >= m_size)
|
||||
{
|
||||
msgHdr = nsnull;;
|
||||
newMsgHdr = nsnull;
|
||||
// no more to copy finish it up
|
||||
FinishCompact();
|
||||
Release(); // kill self
|
||||
}
|
||||
else
|
||||
{
|
||||
m_messageUri.SetLength(0); // clear the previous message uri
|
||||
rv = nsBuildLocalMessageURI(m_baseMessageUri, m_keyArray[m_curIndex],
|
||||
m_messageUri);
|
||||
if (NS_FAILED(rv)) goto done;
|
||||
rv = m_messageService->CopyMessage(m_messageUri, this, PR_FALSE, nsnull,
|
||||
/* ### should get msg window! */ nsnull, nsnull);
|
||||
|
||||
}
|
||||
|
||||
done:
|
||||
if (NS_FAILED(rv)) {
|
||||
m_status = rv; // set the status to rv so the destructor can remove the
|
||||
// temp folder and database
|
||||
Release(); // kill self
|
||||
return rv;
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsFolderCompactState::OnDataAvailable(nsIChannel *channel, nsISupports *ctxt,
|
||||
nsIInputStream *inStr,
|
||||
PRUint32 sourceOffset, PRUint32 count)
|
||||
{
|
||||
nsresult rv = NS_ERROR_FAILURE;
|
||||
if (!m_fileStream || !inStr) return rv;
|
||||
|
||||
PRUint32 maxReadCount, readCount, writeCount;
|
||||
rv = NS_OK;
|
||||
while (NS_SUCCEEDED(rv) && (PRInt32) count > 0)
|
||||
{
|
||||
maxReadCount = count > FOUR_K ? FOUR_K : count;
|
||||
rv = inStr->Read(m_dataBuffer, maxReadCount, &readCount);
|
||||
if (NS_SUCCEEDED(rv))
|
||||
{
|
||||
writeCount = m_fileStream->write(m_dataBuffer, readCount);
|
||||
count -= readCount;
|
||||
NS_ASSERTION (writeCount == readCount,
|
||||
"Oops, write fail, folder can be corrupted!\n");
|
||||
}
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// nsLocal
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
@ -1071,102 +800,43 @@ nsMsgLocalMailFolder::CreateSubfolder(const PRUnichar *folderName, nsIMsgWindow
|
||||
return rv;
|
||||
}
|
||||
|
||||
// **** jefft -- needs to provide nsIMsgWindow for the compact status
|
||||
// update; come back later
|
||||
NS_IMETHODIMP nsMsgLocalMailFolder::Compact(nsIUrlListener *aListener)
|
||||
{
|
||||
// **** jefft -- needs to provide nsIMsgWindow for the compact status
|
||||
// update; come back later
|
||||
|
||||
nsresult rv = NS_ERROR_FAILURE;
|
||||
nsCOMPtr<nsIMsgDatabase> db;
|
||||
nsCOMPtr<nsIDBFolderInfo> folderInfo;
|
||||
PRUint32 expungedBytes = 0;
|
||||
nsCOMPtr<nsIMsgDatabase> mailDBFactory;
|
||||
nsresult folderOpen = NS_OK;
|
||||
nsCOMPtr<nsIFileSpec> pathSpec;
|
||||
nsCOMPtr<nsIFileSpec> newPathSpec;
|
||||
|
||||
rv = GetExpungedBytes(&expungedBytes);
|
||||
|
||||
// check if we need to compact the folder
|
||||
if (expungedBytes > 0)
|
||||
nsresult rv;
|
||||
nsCOMPtr <nsIMsgFolderCompactor> folderCompactor = do_CreateInstance(NS_MSGLOCALFOLDERCOMPACTOR_CONTRACTID, &rv);
|
||||
if (NS_SUCCEEDED(rv) && folderCompactor)
|
||||
{
|
||||
nsFolderCompactState *compactState = new nsFolderCompactState();
|
||||
if (!compactState) return NS_ERROR_OUT_OF_MEMORY;
|
||||
rv = QueryInterface(NS_GET_IID(nsIMsgFolder), (void **)
|
||||
getter_AddRefs(compactState->m_folder));
|
||||
if (NS_FAILED(rv)) goto done;
|
||||
|
||||
compactState->m_baseMessageUri = nsCRT::strdup(mBaseMessageURI);
|
||||
if (!compactState->m_baseMessageUri) {
|
||||
rv = NS_ERROR_OUT_OF_MEMORY; goto done;
|
||||
}
|
||||
nsresult rv = NS_ERROR_FAILURE;
|
||||
nsCOMPtr<nsIMsgDatabase> db;
|
||||
nsCOMPtr<nsIDBFolderInfo> folderInfo;
|
||||
PRUint32 expungedBytes = 0;
|
||||
nsCOMPtr<nsIMsgDatabase> mailDBFactory;
|
||||
nsresult folderOpen = NS_OK;
|
||||
nsCOMPtr<nsIFileSpec> pathSpec;
|
||||
|
||||
rv = GetMsgDatabase(nsnull, getter_AddRefs(db));
|
||||
if (NS_FAILED(rv)) goto done;
|
||||
rv = GetExpungedBytes(&expungedBytes);
|
||||
|
||||
db ->ListAllKeys(compactState->m_keyArray);
|
||||
compactState->m_size = compactState->m_keyArray.GetSize();
|
||||
compactState->m_curIndex = 0;
|
||||
rv = GetPath(getter_AddRefs(pathSpec));
|
||||
|
||||
if (NS_FAILED(rv)) goto done;
|
||||
pathSpec->GetFileSpec(&compactState->m_fileSpec);
|
||||
compactState->m_fileSpec.SetLeafName("nstmp");
|
||||
|
||||
compactState->m_fileStream = new
|
||||
nsOutputFileStream(compactState->m_fileSpec);
|
||||
if (!compactState->m_fileStream) {
|
||||
rv = NS_ERROR_OUT_OF_MEMORY; goto done;
|
||||
}
|
||||
rv = NS_NewFileSpecWithSpec(compactState->m_fileSpec,
|
||||
getter_AddRefs(newPathSpec));
|
||||
|
||||
rv = nsComponentManager::CreateInstance(kCMailDB, nsnull,
|
||||
NS_GET_IID(nsIMsgDatabase),
|
||||
getter_AddRefs(mailDBFactory));
|
||||
if (NS_FAILED(rv)) goto done;
|
||||
folderOpen = mailDBFactory->Open(newPathSpec, PR_TRUE,
|
||||
PR_FALSE,
|
||||
getter_AddRefs(compactState->m_db));
|
||||
|
||||
if(!NS_SUCCEEDED(folderOpen) &&
|
||||
folderOpen == NS_MSG_ERROR_FOLDER_SUMMARY_OUT_OF_DATE ||
|
||||
folderOpen == NS_MSG_ERROR_FOLDER_SUMMARY_MISSING )
|
||||
// check if we need to compact the folder
|
||||
if (expungedBytes > 0)
|
||||
{
|
||||
// if it's out of date then reopen with upgrade.
|
||||
rv = mailDBFactory->Open(newPathSpec,
|
||||
PR_TRUE, PR_TRUE,
|
||||
getter_AddRefs(compactState->m_db));
|
||||
|
||||
rv = GetMsgDatabase(nsnull, getter_AddRefs(db));
|
||||
if (NS_FAILED(rv)) goto done;
|
||||
}
|
||||
rv = GetMessageServiceFromURI(mBaseMessageURI,
|
||||
&compactState->m_messageService);
|
||||
done:
|
||||
if (NS_SUCCEEDED(rv))
|
||||
{
|
||||
if (compactState->m_size > 0)
|
||||
|
||||
rv = GetPath(getter_AddRefs(pathSpec));
|
||||
|
||||
if (NS_SUCCEEDED(rv))
|
||||
{
|
||||
compactState->AddRef();
|
||||
rv = nsBuildLocalMessageURI(mBaseMessageURI,
|
||||
compactState->m_keyArray[0],
|
||||
compactState->m_messageUri);
|
||||
rv = folderCompactor->Init(this, mBaseMessageURI, db, pathSpec);
|
||||
if (NS_SUCCEEDED(rv))
|
||||
rv = compactState->m_messageService->CopyMessage(
|
||||
compactState->m_messageUri, compactState, PR_FALSE, nsnull,
|
||||
/* ### should get msg window! */ nsnull, nsnull);
|
||||
}
|
||||
else
|
||||
{ // no messages to copy with
|
||||
compactState->FinishCompact();
|
||||
delete compactState;
|
||||
rv = folderCompactor->StartCompacting();
|
||||
}
|
||||
}
|
||||
if (NS_FAILED(rv))
|
||||
{
|
||||
compactState->m_status = rv;
|
||||
delete compactState;
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
done:
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user