2858 lines
91 KiB
C++
2858 lines
91 KiB
C++
// --------------------------------------------------------------------------------
|
|
// upoe5.cpp
|
|
// --------------------------------------------------------------------------------
|
|
#include "pch.hxx"
|
|
#include "utility.h"
|
|
#include "migrate.h"
|
|
#include "migerror.h"
|
|
#include "structs.h"
|
|
#include "resource.h"
|
|
#define DEFINE_DIRECTDB
|
|
#include <shared.h>
|
|
#include <oestore.h>
|
|
#include <oerules.h>
|
|
#include <mimeole.h>
|
|
#include "msident.h"
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// Linearly Incrementing Folder Id
|
|
// --------------------------------------------------------------------------------
|
|
static DWORD g_idFolderNext=1000;
|
|
extern BOOL g_fQuiet;
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// FOLDERIDCHANGE
|
|
// --------------------------------------------------------------------------------
|
|
typedef struct tagFOLDERIDCHANGE {
|
|
FOLDERID idOld;
|
|
FOLDERID idNew;
|
|
} FOLDERIDCHANGE, *LPFOLDERIDCHANGE;
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// Forward Declarations
|
|
// --------------------------------------------------------------------------------
|
|
HRESULT SetIMAPSpecialFldrType(LPSTR pszAcctID, LPSTR pszFldrName, SPECIALFOLDER *psfType);
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// SplitMailCacheBlob
|
|
// --------------------------------------------------------------------------------
|
|
HRESULT SplitMailCacheBlob(IMimePropertySet *pNormalizer, LPBYTE pbCacheInfo,
|
|
DWORD cbCacheInfo, LPMESSAGEINFO pMsgInfo, LPSTR *ppszNormal, LPBLOB pOffsets)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
ULONG ib;
|
|
ULONG cbTree;
|
|
ULONG cbProps;
|
|
WORD wVersion;
|
|
DWORD dw;
|
|
DWORD cbMsg;
|
|
DWORD dwFlags;
|
|
WORD wPriority;
|
|
PROPVARIANT Variant;
|
|
|
|
// Invalid Arg
|
|
Assert(pbCacheInfo && cbCacheInfo && pMsgInfo);
|
|
|
|
// Init
|
|
ZeroMemory(pOffsets, sizeof(BLOB));
|
|
|
|
// Read Version
|
|
ib = 0;
|
|
IF_FAILEXIT(hr = BlobReadData(pbCacheInfo, cbCacheInfo, &ib, (LPBYTE)&wVersion, sizeof(wVersion)));
|
|
|
|
// Version Check
|
|
if (wVersion != MSG_HEADER_VERSISON)
|
|
{
|
|
hr = TraceResult(E_FAIL);
|
|
goto exit;
|
|
}
|
|
|
|
// Read Flags
|
|
IF_FAILEXIT(hr = BlobReadData(pbCacheInfo, cbCacheInfo, &ib, (LPBYTE)&dwFlags, sizeof(dwFlags)));
|
|
|
|
// IMF_ATTACHMENTS
|
|
if (ISFLAGSET(dwFlags, IMF_ATTACHMENTS))
|
|
FLAGSET(pMsgInfo->dwFlags, ARF_HASATTACH);
|
|
|
|
// IMF_SIGNED
|
|
if (ISFLAGSET(dwFlags, IMF_SIGNED))
|
|
FLAGSET(pMsgInfo->dwFlags, ARF_SIGNED);
|
|
|
|
// IMF_ENCRYPTED
|
|
if (ISFLAGSET(dwFlags, IMF_ENCRYPTED))
|
|
FLAGSET(pMsgInfo->dwFlags, ARF_ENCRYPTED);
|
|
|
|
// IMF_VOICEMAIL
|
|
if (ISFLAGSET(dwFlags, IMF_VOICEMAIL))
|
|
FLAGSET(pMsgInfo->dwFlags, ARF_VOICEMAIL);
|
|
|
|
// IMF_NEWS
|
|
if (ISFLAGSET(dwFlags, IMF_NEWS))
|
|
FLAGSET(pMsgInfo->dwFlags, ARF_NEWSMSG);
|
|
|
|
// Read Reserved
|
|
IF_FAILEXIT(hr = BlobReadData(pbCacheInfo, cbCacheInfo, &ib, (LPBYTE)&dw, sizeof(dw)));
|
|
|
|
// Read Message Size
|
|
IF_FAILEXIT(hr = BlobReadData(pbCacheInfo, cbCacheInfo, &ib, (LPBYTE)&cbMsg, sizeof(cbMsg)));
|
|
|
|
// Read Byte Count for the content list
|
|
IF_FAILEXIT(hr = BlobReadData(pbCacheInfo, cbCacheInfo, &ib, (LPBYTE)&cbTree, sizeof(cbTree)));
|
|
|
|
// Does the user want the tree ?
|
|
if (cbTree)
|
|
{
|
|
pOffsets->pBlobData = (pbCacheInfo + ib);
|
|
pOffsets->cbSize = cbTree;
|
|
}
|
|
|
|
// Increment passed the tree
|
|
ib += cbTree;
|
|
|
|
// Read Byte Count for the content list
|
|
IF_FAILEXIT(hr = BlobReadData(pbCacheInfo, cbCacheInfo, &ib, (LPBYTE)&cbProps, sizeof(cbProps)));
|
|
|
|
// Partial Number
|
|
IF_FAILEXIT(hr = BlobReadData(pbCacheInfo, cbCacheInfo, &ib, (LPBYTE)&pMsgInfo->dwPartial, sizeof(pMsgInfo->dwPartial)));
|
|
|
|
// Receive Time
|
|
IF_FAILEXIT(hr = BlobReadData(pbCacheInfo, cbCacheInfo, &ib, (LPBYTE)&pMsgInfo->ftReceived, sizeof(pMsgInfo->ftReceived)));
|
|
|
|
// Sent Time
|
|
IF_FAILEXIT(hr = BlobReadData(pbCacheInfo, cbCacheInfo, &ib, (LPBYTE)&pMsgInfo->ftSent, sizeof(pMsgInfo->ftSent)));
|
|
|
|
// Priority
|
|
IF_FAILEXIT(hr = BlobReadData(pbCacheInfo, cbCacheInfo, &ib, (LPBYTE)&wPriority, sizeof(wPriority)));
|
|
|
|
// Pritority
|
|
pMsgInfo->wPriority = wPriority;
|
|
|
|
// Subject
|
|
IF_FAILEXIT(hr = BlobReadData(pbCacheInfo, cbCacheInfo, &ib, (LPBYTE)&dw, sizeof(dw)));
|
|
pMsgInfo->pszSubject = (LPSTR)(pbCacheInfo + ib);
|
|
ib += dw;
|
|
|
|
// Init the Normalizer
|
|
pNormalizer->InitNew();
|
|
|
|
// Set the Subject
|
|
Variant.vt = VT_LPSTR;
|
|
Variant.pszVal = pMsgInfo->pszSubject;
|
|
|
|
// Set the Property
|
|
IF_FAILEXIT(hr = pNormalizer->SetProp(PIDTOSTR(PID_HDR_SUBJECT), 0, &Variant));
|
|
|
|
// Get the Normalized Subject back out
|
|
if (SUCCEEDED(pNormalizer->GetProp(PIDTOSTR(PID_ATT_NORMSUBJ), 0, &Variant)))
|
|
*ppszNormal = pMsgInfo->pszNormalSubj = Variant.pszVal;
|
|
|
|
// Otherwise, just use the subject
|
|
else
|
|
pMsgInfo->pszNormalSubj = pMsgInfo->pszSubject;
|
|
|
|
// Display To
|
|
IF_FAILEXIT(hr = BlobReadData(pbCacheInfo, cbCacheInfo, &ib, (LPBYTE)&dw, sizeof(dw)));
|
|
pMsgInfo->pszDisplayTo = (LPSTR)(pbCacheInfo + ib);
|
|
ib += dw;
|
|
|
|
// Display From
|
|
IF_FAILEXIT(hr = BlobReadData(pbCacheInfo, cbCacheInfo, &ib, (LPBYTE)&dw, sizeof(dw)));
|
|
pMsgInfo->pszDisplayFrom = (LPSTR)(pbCacheInfo + ib);
|
|
ib += dw;
|
|
|
|
// Server
|
|
IF_FAILEXIT(hr = BlobReadData(pbCacheInfo, cbCacheInfo, &ib, (LPBYTE)&dw, sizeof(dw)));
|
|
pMsgInfo->pszServer = (LPSTR)(pbCacheInfo + ib);
|
|
ib += dw;
|
|
|
|
// UIDL
|
|
IF_FAILEXIT(hr = BlobReadData(pbCacheInfo, cbCacheInfo, &ib, (LPBYTE)&dw, sizeof(dw)));
|
|
pMsgInfo->pszUidl = (LPSTR)(pbCacheInfo + ib);
|
|
ib += dw;
|
|
|
|
// User Name
|
|
IF_FAILEXIT(hr = BlobReadData(pbCacheInfo, cbCacheInfo, &ib, (LPBYTE)&dw, sizeof(dw)));
|
|
//pMsgInfo->pszUserName = (LPSTR)(pbCacheInfo + ib);
|
|
ib += dw;
|
|
|
|
// Account Name
|
|
IF_FAILEXIT(hr = BlobReadData(pbCacheInfo, cbCacheInfo, &ib, (LPBYTE)&dw, sizeof(dw)));
|
|
pMsgInfo->pszAcctName = (LPSTR)(pbCacheInfo + ib);
|
|
ib += dw;
|
|
|
|
// Partial Id
|
|
IF_FAILEXIT(hr = BlobReadData(pbCacheInfo, cbCacheInfo, &ib, (LPBYTE)&dw, sizeof(dw)));
|
|
pMsgInfo->pszPartialId = (LPSTR)(pbCacheInfo + ib);
|
|
ib += dw;
|
|
|
|
// Forward To
|
|
IF_FAILEXIT(hr = BlobReadData(pbCacheInfo, cbCacheInfo, &ib, (LPBYTE)&dw, sizeof(dw)));
|
|
pMsgInfo->pszForwardTo = (LPSTR)(pbCacheInfo + ib);
|
|
ib += dw;
|
|
|
|
// Sanity Check
|
|
Assert(ib == cbCacheInfo);
|
|
|
|
exit:
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
// GetMsgInfoFromPropertySet
|
|
//--------------------------------------------------------------------------
|
|
HRESULT GetMsgInfoFromPropertySet(
|
|
/* in */ IMimePropertySet *pPropertySet,
|
|
/* in,out */ LPMESSAGEINFO pMsgInfo)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
IMSGPRIORITY priority;
|
|
PROPVARIANT Variant;
|
|
SYSTEMTIME st;
|
|
FILETIME ftCurrent;
|
|
IMimeAddressTable *pAdrTable=NULL;
|
|
|
|
// Trace
|
|
TraceCall("GetMsgInfoFromPropertySet");
|
|
|
|
// Invalid Args
|
|
Assert(pPropertySet && pMsgInfo);
|
|
|
|
// Default Sent and Received Times...
|
|
GetSystemTime(&st);
|
|
SystemTimeToFileTime(&st, &ftCurrent);
|
|
|
|
// Set Variant tyStore
|
|
Variant.vt = VT_UI4;
|
|
|
|
// Priority
|
|
if (SUCCEEDED(pPropertySet->GetProp(PIDTOSTR(PID_ATT_PRIORITY), 0, &Variant)))
|
|
{
|
|
// Set Priority
|
|
pMsgInfo->wPriority = (WORD)Variant.ulVal;
|
|
}
|
|
|
|
// Partial Numbers...
|
|
if (pPropertySet->IsContentType(STR_CNT_MESSAGE, STR_SUB_PARTIAL) == S_OK)
|
|
{
|
|
// Locals
|
|
WORD cParts=0, iPart=0;
|
|
|
|
// Get Total
|
|
if (SUCCEEDED(pPropertySet->GetProp(STR_PAR_TOTAL, NOFLAGS, &Variant)))
|
|
cParts = (WORD)Variant.ulVal;
|
|
|
|
// Get Number
|
|
if (SUCCEEDED(pPropertySet->GetProp(STR_PAR_NUMBER, NOFLAGS, &Variant)))
|
|
iPart = (WORD)Variant.ulVal;
|
|
|
|
// Set Parts
|
|
pMsgInfo->dwPartial = MAKELONG(cParts, iPart);
|
|
}
|
|
|
|
// Otherwise, check for user property
|
|
else if (SUCCEEDED(pPropertySet->GetProp(PIDTOSTR(PID_ATT_COMBINED), NOFLAGS, &Variant)))
|
|
{
|
|
// Set the Partial Id
|
|
pMsgInfo->dwPartial = Variant.ulVal;
|
|
}
|
|
|
|
// Getting some file times
|
|
Variant.vt = VT_FILETIME;
|
|
|
|
// Get Received Time...
|
|
if (SUCCEEDED(pPropertySet->GetProp(PIDTOSTR(PID_ATT_RECVTIME), 0, &Variant)))
|
|
pMsgInfo->ftReceived = Variant.filetime;
|
|
else
|
|
pMsgInfo->ftReceived = ftCurrent;
|
|
|
|
// Get Sent Time...
|
|
if (SUCCEEDED(pPropertySet->GetProp(PIDTOSTR(PID_ATT_SENTTIME), 0, &Variant)))
|
|
pMsgInfo->ftSent = Variant.filetime;
|
|
else
|
|
pMsgInfo->ftSent = ftCurrent;
|
|
|
|
// Get Address Table
|
|
IF_FAILEXIT(hr = pPropertySet->BindToObject(IID_IMimeAddressTable, (LPVOID *)&pAdrTable));
|
|
|
|
// Display From
|
|
pAdrTable->GetFormat(IAT_FROM, AFT_DISPLAY_FRIENDLY, &pMsgInfo->pszDisplayFrom);
|
|
|
|
// Display To
|
|
pAdrTable->GetFormat(IAT_TO, AFT_DISPLAY_FRIENDLY, &pMsgInfo->pszDisplayTo);
|
|
|
|
// String Properties
|
|
Variant.vt = VT_LPSTR;
|
|
|
|
// pszDisplayFrom as newsgroups
|
|
if (NULL == pMsgInfo->pszDisplayFrom && SUCCEEDED(pPropertySet->GetProp(PIDTOSTR(PID_HDR_NEWSGROUPS), NOFLAGS, &Variant)))
|
|
pMsgInfo->pszDisplayFrom = Variant.pszVal;
|
|
|
|
// pszMessageId
|
|
if (SUCCEEDED(pPropertySet->GetProp(PIDTOSTR(PID_HDR_MESSAGEID), NOFLAGS, &Variant)))
|
|
pMsgInfo->pszMessageId = Variant.pszVal;
|
|
|
|
// pszXref
|
|
if (SUCCEEDED(pPropertySet->GetProp(PIDTOSTR(PID_HDR_XREF), NOFLAGS, &Variant)))
|
|
pMsgInfo->pszXref = Variant.pszVal;
|
|
|
|
// pszReferences
|
|
if (SUCCEEDED(pPropertySet->GetProp(PIDTOSTR(STR_HDR_REFS), NOFLAGS, &Variant)))
|
|
pMsgInfo->pszReferences = Variant.pszVal;
|
|
|
|
// pszSubject
|
|
if (SUCCEEDED(pPropertySet->GetProp(PIDTOSTR(PID_HDR_SUBJECT), NOFLAGS, &Variant)))
|
|
pMsgInfo->pszSubject = Variant.pszVal;
|
|
|
|
// Normalized Subject
|
|
if (SUCCEEDED(pPropertySet->GetProp(PIDTOSTR(PID_ATT_NORMSUBJ), NOFLAGS, &Variant)))
|
|
pMsgInfo->pszNormalSubj = Variant.pszVal;
|
|
|
|
// pszAccount
|
|
if (SUCCEEDED(pPropertySet->GetProp(STR_ATT_ACCOUNTNAME, NOFLAGS, &Variant)))
|
|
pMsgInfo->pszAcctName = Variant.pszVal;
|
|
|
|
// pszServer
|
|
if (SUCCEEDED(pPropertySet->GetProp(PIDTOSTR(PID_ATT_SERVER), NOFLAGS, &Variant)))
|
|
pMsgInfo->pszServer = Variant.pszVal;
|
|
|
|
// pszUidl
|
|
if (SUCCEEDED(pPropertySet->GetProp(PIDTOSTR(PID_ATT_UIDL), NOFLAGS, &Variant)))
|
|
pMsgInfo->pszUidl = Variant.pszVal;
|
|
|
|
// pszPartialId
|
|
if (pMsgInfo->dwPartial != 0 && SUCCEEDED(pPropertySet->GetProp(STR_PAR_ID, NOFLAGS, &Variant)))
|
|
pMsgInfo->pszPartialId = Variant.pszVal;
|
|
|
|
// ForwardTo
|
|
if (SUCCEEDED(pPropertySet->GetProp(PIDTOSTR(PID_ATT_FORWARDTO), NOFLAGS, &Variant)))
|
|
pMsgInfo->pszForwardTo = Variant.pszVal;
|
|
|
|
exit:
|
|
// Cleanup
|
|
SafeRelease(pAdrTable);
|
|
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
// GetMsgInfoFromMessage
|
|
//--------------------------------------------------------------------------
|
|
HRESULT GetMsgInfoFromMessage(IMimeMessage *pMessage, LPMESSAGEINFO pMsgInfo,
|
|
LPBLOB pOffsets)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
DWORD dwImf;
|
|
IMSGPRIORITY priority;
|
|
PROPVARIANT Variant;
|
|
SYSTEMTIME st;
|
|
FILETIME ftCurrent;
|
|
CByteStream cByteStm;
|
|
IMimePropertySet *pPropertySet=NULL;
|
|
|
|
// Trace
|
|
TraceCall("GetMsgInfoFromMessage");
|
|
|
|
// Invalid Args
|
|
Assert(pMessage && pMsgInfo);
|
|
|
|
// Get the Root Property Set from the Message
|
|
IF_FAILEXIT(hr = pMessage->BindToObject(HBODY_ROOT, IID_IMimePropertySet, (LPVOID *)&pPropertySet));
|
|
|
|
// File pMsgInfo from pPropertySet
|
|
IF_FAILEXIT(hr = GetMsgInfoFromPropertySet(pPropertySet, pMsgInfo));
|
|
|
|
// Get Message Flags
|
|
if (SUCCEEDED(pMessage->GetFlags(&dwImf)))
|
|
{
|
|
// IMF_ATTACHMENTS
|
|
if (ISFLAGSET(dwImf, IMF_ATTACHMENTS))
|
|
FLAGSET(pMsgInfo->dwFlags, ARF_HASATTACH);
|
|
|
|
// IMF_SIGNED
|
|
if (ISFLAGSET(dwImf, IMF_SIGNED))
|
|
FLAGSET(pMsgInfo->dwFlags, ARF_SIGNED);
|
|
|
|
// IMF_ENCRYPTED
|
|
if (ISFLAGSET(dwImf, IMF_ENCRYPTED))
|
|
FLAGSET(pMsgInfo->dwFlags, ARF_ENCRYPTED);
|
|
|
|
// IMF_VOICEMAIL
|
|
if (ISFLAGSET(dwImf, IMF_VOICEMAIL))
|
|
FLAGSET(pMsgInfo->dwFlags, ARF_VOICEMAIL);
|
|
|
|
// IMF_NEWS
|
|
if (ISFLAGSET(dwImf, IMF_NEWS))
|
|
FLAGSET(pMsgInfo->dwFlags, ARF_NEWSMSG);
|
|
}
|
|
|
|
// Get the Message Size
|
|
pMessage->GetMessageSize(&pMsgInfo->cbMessage, 0);
|
|
|
|
// Create the offset table
|
|
if (SUCCEEDED(pMessage->SaveOffsetTable(&cByteStm, 0)))
|
|
{
|
|
// pull the Bytes out of cByteStm
|
|
cByteStm.AcquireBytes(&pOffsets->cbSize, &pOffsets->pBlobData, ACQ_DISPLACE);
|
|
}
|
|
|
|
exit:
|
|
// Cleanup
|
|
SafeRelease(pPropertySet);
|
|
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
// FreeMsgInfo
|
|
//--------------------------------------------------------------------------
|
|
void FreeMsgInfo(
|
|
/* in,out */ LPMESSAGEINFO pMsgInfo)
|
|
{
|
|
// Trace
|
|
TraceCall("FreeMsgInfo");
|
|
|
|
// Invalid Args
|
|
Assert(pMsgInfo && NULL == pMsgInfo->pAllocated);
|
|
|
|
// Free The Dude
|
|
g_pMalloc->Free(pMsgInfo->pszMessageId);
|
|
g_pMalloc->Free(pMsgInfo->pszNormalSubj);
|
|
g_pMalloc->Free(pMsgInfo->pszSubject);
|
|
g_pMalloc->Free(pMsgInfo->pszFromHeader);
|
|
g_pMalloc->Free(pMsgInfo->pszReferences);
|
|
g_pMalloc->Free(pMsgInfo->pszXref);
|
|
g_pMalloc->Free(pMsgInfo->pszServer);
|
|
g_pMalloc->Free(pMsgInfo->pszDisplayFrom);
|
|
g_pMalloc->Free(pMsgInfo->pszEmailFrom);
|
|
g_pMalloc->Free(pMsgInfo->pszDisplayTo);
|
|
g_pMalloc->Free(pMsgInfo->pszUidl);
|
|
g_pMalloc->Free(pMsgInfo->pszPartialId);
|
|
g_pMalloc->Free(pMsgInfo->pszForwardTo);
|
|
g_pMalloc->Free(pMsgInfo->pszAcctName);
|
|
g_pMalloc->Free(pMsgInfo->pszAcctId);
|
|
|
|
// Zero It
|
|
ZeroMemory(pMsgInfo, sizeof(MESSAGEINFO));
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// UpgradeLocalStoreFileV5
|
|
// --------------------------------------------------------------------------------
|
|
HRESULT UpgradeLocalStoreFileV5(LPFILEINFO pInfo, LPMEMORYFILE pFile,
|
|
IDatabase *pDB, LPPROGRESSINFO pProgress, BOOL *pfContinue)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
CHAR szIdxPath[MAX_PATH];
|
|
DWORD i;
|
|
LPBYTE pbStream;
|
|
LPBYTE pbCacheBlob;
|
|
SYSTEMTIME st;
|
|
MESSAGEINFO MsgInfo={0};
|
|
LPSTR pszNormal=NULL;
|
|
MESSAGEINFO MsgInfoFree={0};
|
|
DWORD faIdxRead;
|
|
IStream *pStream=NULL;
|
|
IMimeMessage *pMessage=NULL;
|
|
BLOB Offsets;
|
|
LPBYTE pbFree=NULL;
|
|
MEMORYFILE IdxFile;
|
|
LPMEMORYFILE pIdxFile=NULL;
|
|
LPMEMORYFILE pMbxFile=pFile;
|
|
LPMBXFILEHEADER pMbxHeader=NULL;
|
|
LPIDXFILEHEADER pIdxHeader=NULL;
|
|
LPIDXMESSAGEHEADER pIdxMessage=NULL;
|
|
LPMBXMESSAGEHEADER pMbxMessage=NULL;
|
|
IMimePropertySet *pNormalizer=NULL;
|
|
LARGE_INTEGER liOrigin={0,0};
|
|
|
|
// Trace
|
|
TraceCall("UpgradeLocalStoreFileV5");
|
|
|
|
// Get System Time
|
|
GetSystemTime(&st);
|
|
|
|
// Create a Property Set for Normalizing Subjects
|
|
IF_FAILEXIT(hr = CoCreateInstance(CLSID_IMimePropertySet, NULL, CLSCTX_INPROC_SERVER, IID_IMimePropertySet, (LPVOID *)&pNormalizer));
|
|
|
|
// Split the Path
|
|
ReplaceExtension(pInfo->szFilePath, ".idx", szIdxPath, ARRAYSIZE(szIdxPath));
|
|
|
|
// Open the memory file
|
|
hr = OpenMemoryFile(szIdxPath, &IdxFile);
|
|
if (FAILED(hr))
|
|
{
|
|
*pfContinue = TRUE;
|
|
TraceResult(hr);
|
|
goto exit;
|
|
}
|
|
|
|
// Set pIdxFile
|
|
pIdxFile = &IdxFile;
|
|
|
|
// Don't use pFile
|
|
pFile = NULL;
|
|
|
|
// Read the Mbx File Header
|
|
pMbxHeader = (LPMBXFILEHEADER)(pMbxFile->pView);
|
|
|
|
// Read the Idx File Header
|
|
pIdxHeader = (LPIDXFILEHEADER)(pIdxFile->pView);
|
|
|
|
// Validate the Version of th idx file
|
|
if (pIdxHeader->ver != CACHEFILE_VER || pIdxHeader->dwMagic != CACHEFILE_MAGIC)
|
|
{
|
|
*pfContinue = TRUE;
|
|
hr = TraceResult(MIGRATE_E_INVALIDIDXHEADER);
|
|
goto exit;
|
|
}
|
|
|
|
// Setup faIdxRead
|
|
faIdxRead = sizeof(IDXFILEHEADER);
|
|
|
|
// Prepare to Loop
|
|
for (i=0; i<pIdxHeader->cMsg; i++)
|
|
{
|
|
// Done
|
|
if (faIdxRead >= pIdxFile->cbSize)
|
|
break;
|
|
|
|
// Read an idx message header
|
|
pIdxMessage = (LPIDXMESSAGEHEADER)((LPBYTE)pIdxFile->pView + faIdxRead);
|
|
|
|
// If this message is not marked as deleted...
|
|
if (ISFLAGSET(pIdxMessage->dwState, MSG_DELETED))
|
|
goto NextMessage;
|
|
|
|
// Zero Out the MsgInfo Structure
|
|
ZeroMemory(&MsgInfo, sizeof(MESSAGEINFO));
|
|
|
|
// Start filling message
|
|
MsgInfo.idMessage = (MESSAGEID)IntToPtr(pIdxMessage->msgid);
|
|
|
|
// Fixup the Flags
|
|
if (FALSE == ISFLAGSET(pIdxMessage->dwState, MSG_UNREAD))
|
|
FLAGSET(MsgInfo.dwFlags, ARF_READ);
|
|
if (ISFLAGSET(pIdxMessage->dwState, MSG_VOICEMAIL))
|
|
FLAGSET(MsgInfo.dwFlags, ARF_VOICEMAIL);
|
|
if (ISFLAGSET(pIdxMessage->dwState, MSG_REPLIED))
|
|
FLAGSET(MsgInfo.dwFlags, ARF_REPLIED);
|
|
if (ISFLAGSET(pIdxMessage->dwState, MSG_FORWARDED))
|
|
FLAGSET(MsgInfo.dwFlags, ARF_FORWARDED);
|
|
if (ISFLAGSET(pIdxMessage->dwState, MSG_FLAGGED))
|
|
FLAGSET(MsgInfo.dwFlags, ARF_FLAGGED);
|
|
if (ISFLAGSET(pIdxMessage->dwState, MSG_RCPTSENT))
|
|
FLAGSET(MsgInfo.dwFlags, ARF_RCPTSENT);
|
|
if (ISFLAGSET(pIdxMessage->dwState, MSG_NOSECUI))
|
|
FLAGSET(MsgInfo.dwFlags, ARF_NOSECUI);
|
|
if (ISFLAGSET(pIdxMessage->dwState, MSG_NEWSMSG))
|
|
FLAGSET(MsgInfo.dwFlags, ARF_NEWSMSG);
|
|
if (ISFLAGSET(pIdxMessage->dwState, MSG_UNSENT))
|
|
FLAGSET(MsgInfo.dwFlags, ARF_UNSENT);
|
|
if (ISFLAGSET(pIdxMessage->dwState, MSG_SUBMITTED))
|
|
FLAGSET(MsgInfo.dwFlags, ARF_SUBMITTED);
|
|
if (ISFLAGSET(pIdxMessage->dwState, MSG_RECEIVED))
|
|
FLAGSET(MsgInfo.dwFlags, ARF_RECEIVED);
|
|
|
|
// Zero Offsets
|
|
ZeroMemory(&Offsets, sizeof(BLOB));
|
|
|
|
// Do the Blob
|
|
if (pIdxHeader->verBlob == MAIL_BLOB_VER)
|
|
{
|
|
// Get the blob
|
|
pbCacheBlob = (LPBYTE)((LPBYTE)pIdxFile->pView + (faIdxRead + (sizeof(IDXMESSAGEHEADER) - 4)));
|
|
|
|
// Split the Cache Blob
|
|
if (FAILED(SplitMailCacheBlob(pNormalizer, pbCacheBlob, pIdxMessage->dwHdrSize, &MsgInfo, &pszNormal, &Offsets)))
|
|
goto NextMessage;
|
|
|
|
// Save the Language
|
|
MsgInfo.wLanguage = LOWORD(pIdxMessage->dwLanguage);
|
|
|
|
// Save the Highlight
|
|
MsgInfo.wHighlight = HIWORD(pIdxMessage->dwLanguage);
|
|
}
|
|
|
|
// Bad
|
|
if (pIdxMessage->dwOffset > pMbxFile->cbSize)
|
|
goto NextMessage;
|
|
|
|
// Lets read the message header in the mbx file to validate the msgids
|
|
pMbxMessage = (LPMBXMESSAGEHEADER)((LPBYTE)pMbxFile->pView + pIdxMessage->dwOffset);
|
|
|
|
// Set Sizes
|
|
MsgInfo.cbMessage = pMbxMessage->dwBodySize;
|
|
|
|
// Validate the Message Ids
|
|
if (pMbxMessage->msgid != pIdxMessage->msgid)
|
|
goto NextMessage;
|
|
|
|
// Check for magic
|
|
if (pMbxMessage->dwMagic != MSGHDR_MAGIC)
|
|
goto NextMessage;
|
|
|
|
// Has a Body
|
|
FLAGSET(MsgInfo.dwFlags, ARF_HASBODY);
|
|
|
|
// Create a Virtual Stream
|
|
IF_FAILEXIT(hr = pDB->CreateStream(&MsgInfo.faStream));
|
|
|
|
// Open the Stream
|
|
IF_FAILEXIT(hr = pDB->OpenStream(ACCESS_WRITE, MsgInfo.faStream, &pStream));
|
|
|
|
// Get the stream pointer
|
|
pbStream = (LPBYTE)((LPBYTE)pMbxFile->pView + (pIdxMessage->dwOffset + sizeof(MBXMESSAGEHEADER)));
|
|
|
|
// Write this
|
|
IF_FAILEXIT(hr = pStream->Write(pbStream, pMbxMessage->dwBodySize, NULL));
|
|
|
|
// Commit
|
|
IF_FAILEXIT(hr = pStream->Commit(STGC_DEFAULT));
|
|
|
|
// If not an OE4+ blob, then generate the msginfo from the message
|
|
if (pIdxHeader->verBlob != MAIL_BLOB_VER)
|
|
{
|
|
// Create an IMimeMessage
|
|
IF_FAILEXIT(hr = CoCreateInstance(CLSID_IMimeMessage, NULL, CLSCTX_INPROC_SERVER, IID_IMimeMessage, (LPVOID *)&pMessage));
|
|
|
|
// Rewind
|
|
if (FAILED(pStream->Seek(liOrigin, STREAM_SEEK_SET, NULL)))
|
|
goto NextMessage;
|
|
|
|
// Load the Message
|
|
if (FAILED(pMessage->Load(pStream)))
|
|
goto NextMessage;
|
|
|
|
// Get MsgInfo from the Message
|
|
if (FAILED(GetMsgInfoFromMessage(pMessage, &MsgInfo, &Offsets)))
|
|
goto NextMessage;
|
|
|
|
// Free
|
|
pbFree = Offsets.pBlobData;
|
|
|
|
// Free This MsgInfo
|
|
CopyMemory(&MsgInfoFree, &MsgInfo, sizeof(MESSAGEINFO));
|
|
}
|
|
|
|
// Set MsgInfo Offsets
|
|
MsgInfo.Offsets = Offsets;
|
|
|
|
// Save Downloaded Time
|
|
SystemTimeToFileTime(&st, &MsgInfo.ftDownloaded);
|
|
|
|
// Lookup Account Id from the Account Name...
|
|
if (MsgInfo.pszAcctName)
|
|
{
|
|
// Loop through the Accounts
|
|
for (DWORD i=0; i<g_AcctTable.cAccounts; i++)
|
|
{
|
|
// Is this the Account
|
|
if (lstrcmpi(g_AcctTable.prgAccount[i].szAcctName, MsgInfo.pszAcctName) == 0)
|
|
{
|
|
MsgInfo.pszAcctId = g_AcctTable.prgAccount[i].szAcctId;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Count
|
|
pInfo->cMessages++;
|
|
if (!ISFLAGSET(MsgInfo.dwFlags, ARF_READ))
|
|
pInfo->cUnread++;
|
|
|
|
// Migrated
|
|
FLAGSET(MsgInfo.dwFlags, 0x00000010);
|
|
|
|
// Store the Record
|
|
IF_FAILEXIT(hr = pDB->InsertRecord(&MsgInfo));
|
|
|
|
NextMessage:
|
|
// Bump Progress
|
|
if(!g_fQuiet)
|
|
IncrementProgress(pProgress, pInfo);
|
|
|
|
// Cleanup
|
|
SafeRelease(pStream);
|
|
SafeRelease(pMessage);
|
|
SafeMemFree(pszNormal);
|
|
SafeMemFree(pbFree);
|
|
FreeMsgInfo(&MsgInfoFree);
|
|
|
|
// Goto Next Header
|
|
Assert(pIdxMessage);
|
|
|
|
// Update faIdxRead
|
|
faIdxRead += pIdxMessage->dwSize;
|
|
}
|
|
|
|
exit:
|
|
// Cleanup
|
|
SafeRelease(pStream);
|
|
SafeRelease(pMessage);
|
|
SafeRelease(pNormalizer);
|
|
SafeMemFree(pszNormal);
|
|
SafeMemFree(pbFree);
|
|
FreeMsgInfo(&MsgInfoFree);
|
|
if (pIdxFile)
|
|
CloseMemoryFile(pIdxFile);
|
|
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// GetRecordBlock
|
|
// --------------------------------------------------------------------------------
|
|
HRESULT GetRecordBlock(LPMEMORYFILE pFile, DWORD faRecord, LPRECORDBLOCKV5B1 *ppRecord,
|
|
LPBYTE *ppbData, BOOL *pfContinue)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
|
|
// Trace
|
|
TraceCall("GetRecordBlock");
|
|
|
|
// Bad Length
|
|
if (faRecord + sizeof(RECORDBLOCKV5B1) > pFile->cbSize)
|
|
{
|
|
*pfContinue = TRUE;
|
|
hr = TraceResult(MIGRATE_E_OUTOFRANGEADDRESS);
|
|
goto exit;
|
|
}
|
|
|
|
// Cast the Record
|
|
(*ppRecord) = (LPRECORDBLOCKV5B1)((LPBYTE)pFile->pView + faRecord);
|
|
|
|
// Invalid Record Signature
|
|
if (faRecord != (*ppRecord)->faRecord)
|
|
{
|
|
*pfContinue = TRUE;
|
|
hr = TraceResult(MIGRATE_E_BADRECORDSIGNATURE);
|
|
goto exit;
|
|
}
|
|
|
|
// Bad Length
|
|
if (faRecord + (*ppRecord)->cbRecord > pFile->cbSize)
|
|
{
|
|
*pfContinue = TRUE;
|
|
hr = TraceResult(MIGRATE_E_OUTOFRANGEADDRESS);
|
|
goto exit;
|
|
}
|
|
|
|
// Set pbData
|
|
*ppbData = (LPBYTE)((LPBYTE)(*ppRecord) + sizeof(RECORDBLOCKV5B1));
|
|
|
|
exit:
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// GetStreamBlock
|
|
// --------------------------------------------------------------------------------
|
|
HRESULT GetStreamBlock(LPMEMORYFILE pFile, DWORD faBlock, LPSTREAMBLOCK *ppBlock,
|
|
LPBYTE *ppbData, BOOL *pfContinue)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
|
|
// Trace
|
|
TraceCall("GetStreamBlock");
|
|
|
|
// Bad Length
|
|
if (faBlock + sizeof(STREAMBLOCK) > pFile->cbSize)
|
|
{
|
|
*pfContinue = TRUE;
|
|
hr = TraceResult(MIGRATE_E_OUTOFRANGEADDRESS);
|
|
goto exit;
|
|
}
|
|
|
|
// Cast the Record
|
|
(*ppBlock) = (LPSTREAMBLOCK)((LPBYTE)pFile->pView + faBlock);
|
|
|
|
// Invalid Record Signature
|
|
if (faBlock != (*ppBlock)->faThis)
|
|
{
|
|
*pfContinue = TRUE;
|
|
hr = TraceResult(MIGRATE_E_BADSTREAMBLOCKSIGNATURE);
|
|
goto exit;
|
|
}
|
|
|
|
// Bad Length
|
|
if (faBlock + (*ppBlock)->cbBlock > pFile->cbSize)
|
|
{
|
|
*pfContinue = TRUE;
|
|
hr = TraceResult(MIGRATE_E_OUTOFRANGEADDRESS);
|
|
goto exit;
|
|
}
|
|
|
|
// Set pbData
|
|
*ppbData = (LPBYTE)((LPBYTE)(*ppBlock) + sizeof(STREAMBLOCK));
|
|
|
|
exit:
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// UpgradePropTreeMessageFileV5
|
|
// --------------------------------------------------------------------------------
|
|
HRESULT UpgradePropTreeMessageFileV5(LPFILEINFO pInfo, LPMEMORYFILE pFile,
|
|
IDatabase *pDB, LPPROGRESSINFO pProgress, BOOL *pfContinue)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
LPBYTE pbStart;
|
|
LPBYTE pbData;
|
|
DWORD faRecord;
|
|
DWORD faStreamBlock;
|
|
FILEADDRESS faDstStream;
|
|
MESSAGEINFO MsgInfo;
|
|
IStream *pStream=NULL;
|
|
FILEADDRESS faStream;
|
|
LPFOLDERUSERDATAV4 pUserDataV4;
|
|
FOLDERUSERDATA UserDataV5;
|
|
LPSTREAMBLOCK pStmBlock;
|
|
LPRECORDBLOCKV5B1 pRecord;
|
|
LPTABLEHEADERV5B1 pHeader=(LPTABLEHEADERV5B1)pFile->pView;
|
|
|
|
// Trace
|
|
TraceCall("UpgradePropTreeMessageFileV5");
|
|
|
|
// Validate
|
|
Assert(sizeof(FOLDERUSERDATAV4) == sizeof(FOLDERUSERDATA));
|
|
|
|
// Get CacheInfo
|
|
if (sizeof(FOLDERUSERDATA) != pHeader->cbUserData)
|
|
{
|
|
*pfContinue = TRUE;
|
|
hr = TraceResult(MIGRATE_E_USERDATASIZEDIFF);
|
|
goto exit;
|
|
}
|
|
|
|
// Get V4 UserData
|
|
pUserDataV4 = (LPFOLDERUSERDATAV4)((LPBYTE)pFile->pView + sizeof(TABLEHEADERV5B1));
|
|
|
|
// If there is a Server Name and acctid is empty...
|
|
if ('\0' != *pUserDataV4->szServer && '\0' == *pInfo->szAcctId)
|
|
{
|
|
// Loop through the Accounts
|
|
for (DWORD i=0; i<g_AcctTable.cAccounts; i++)
|
|
{
|
|
// Is this the Account
|
|
if (lstrcmpi(g_AcctTable.prgAccount[i].szServer, pUserDataV4->szServer) == 0)
|
|
{
|
|
StrCpyN(pInfo->szAcctId, g_AcctTable.prgAccount[i].szAcctId, ARRAYSIZE(pInfo->szAcctId));
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// If there is a folder name, copy it
|
|
if ('\0' != *pUserDataV4->szGroup)
|
|
{
|
|
// Copy
|
|
StrCpyN(pInfo->szFolder, pUserDataV4->szGroup, ARRAYSIZE(pInfo->szFolder));
|
|
}
|
|
|
|
// Zero New
|
|
ZeroMemory(&UserDataV5, sizeof(FOLDERUSERDATA));
|
|
|
|
// Copy Over Relavent Stuff
|
|
UserDataV5.dwUIDValidity = pUserDataV4->dwUIDValidity;
|
|
|
|
// Set user data
|
|
IF_FAILEXIT(hr = pDB->SetUserData(&UserDataV5, sizeof(FOLDERUSERDATA)));
|
|
|
|
// Initialize faRecord to start
|
|
faRecord = pHeader->faFirstRecord;
|
|
|
|
// While we have a record
|
|
while(faRecord)
|
|
{
|
|
// Get the Record
|
|
IF_FAILEXIT(hr = GetRecordBlock(pFile, faRecord, &pRecord, &pbData, pfContinue));
|
|
|
|
// Set pbStart
|
|
pbStart = pbData;
|
|
|
|
// Clear MsgInfo
|
|
ZeroMemory(&MsgInfo, sizeof(MESSAGEINFO));
|
|
|
|
// DWORD - idMessage
|
|
CopyMemory(&MsgInfo.idMessage, pbData, sizeof(MsgInfo.idMessage));
|
|
pbData += sizeof(MsgInfo.idMessage);
|
|
|
|
// Null Message Id
|
|
if (0 == MsgInfo.idMessage)
|
|
{
|
|
// Generate
|
|
pDB->GenerateId((LPDWORD)&MsgInfo.idMessage);
|
|
}
|
|
|
|
// DWORD - dwFlags
|
|
CopyMemory(&MsgInfo.dwFlags, pbData, sizeof(MsgInfo.dwFlags));
|
|
pbData += sizeof(MsgInfo.dwFlags);
|
|
|
|
// News ?
|
|
if (FILE_IS_NEWS_MESSAGES == pInfo->tyFile)
|
|
FLAGSET(MsgInfo.dwFlags, ARF_NEWSMSG);
|
|
|
|
// Priority
|
|
if (ISFLAGSET(MsgInfo.dwFlags, 0x00000200))
|
|
{
|
|
MsgInfo.wPriority = (WORD)IMSG_PRI_HIGH;
|
|
FLAGCLEAR(MsgInfo.dwFlags, 0x00000200);
|
|
}
|
|
else if (ISFLAGSET(MsgInfo.dwFlags, 0x00000100))
|
|
{
|
|
MsgInfo.wPriority = (WORD)IMSG_PRI_LOW;
|
|
FLAGCLEAR(MsgInfo.dwFlags, 0x00000100);
|
|
}
|
|
else
|
|
MsgInfo.wPriority = (WORD)IMSG_PRI_NORMAL;
|
|
|
|
// DWORD - ftSent
|
|
CopyMemory(&MsgInfo.ftSent, pbData, sizeof(MsgInfo.ftSent));
|
|
pbData += sizeof(MsgInfo.ftSent);
|
|
MsgInfo.ftReceived = MsgInfo.ftSent;
|
|
|
|
// DWORD - cLines
|
|
CopyMemory(&MsgInfo.cLines, pbData, sizeof(MsgInfo.cLines));
|
|
pbData += sizeof(MsgInfo.cLines);
|
|
|
|
// DWORD - faStream
|
|
CopyMemory(&faStream, pbData, sizeof(faStream));
|
|
pbData += sizeof(faStream);
|
|
|
|
// Has a Body
|
|
if (faStream)
|
|
{
|
|
// It has a body
|
|
FLAGSET(MsgInfo.dwFlags, ARF_HASBODY);
|
|
}
|
|
|
|
// DWORD - cbArticle / cbMessage (VERSION)
|
|
CopyMemory(&MsgInfo.cbMessage, pbData, sizeof(MsgInfo.cbMessage));
|
|
pbData += sizeof(MsgInfo.cbMessage);
|
|
|
|
// DWORD - ftDownloaded
|
|
CopyMemory(&MsgInfo.ftDownloaded, pbData, sizeof(MsgInfo.ftDownloaded));
|
|
pbData += sizeof(MsgInfo.ftDownloaded);
|
|
|
|
// LPSTR - pszMessageId
|
|
MsgInfo.pszMessageId = (LPSTR)pbData;
|
|
pbData += (lstrlen(MsgInfo.pszMessageId) + 1);
|
|
|
|
// LPSTR - pszSubject
|
|
MsgInfo.pszSubject = (LPSTR)pbData;
|
|
pbData += (lstrlen(MsgInfo.pszSubject) + 1);
|
|
|
|
// VERSION
|
|
MsgInfo.pszNormalSubj = MsgInfo.pszSubject + HIBYTE(HIWORD(MsgInfo.dwFlags));
|
|
|
|
// LPSTR - pszFromHeader
|
|
MsgInfo.pszFromHeader = (LPSTR)pbData;
|
|
pbData += (lstrlen(MsgInfo.pszFromHeader) + 1);
|
|
|
|
// LPSTR - pszReferences
|
|
MsgInfo.pszReferences = (LPSTR)pbData;
|
|
pbData += (lstrlen(MsgInfo.pszReferences) + 1);
|
|
|
|
// LPSTR - pszXref
|
|
MsgInfo.pszXref = (LPSTR)pbData;
|
|
pbData += (lstrlen(MsgInfo.pszXref) + 1);
|
|
|
|
// LPSTR - pszServer
|
|
MsgInfo.pszServer = (LPSTR)pbData;
|
|
pbData += (lstrlen(MsgInfo.pszServer) + 1);
|
|
|
|
// LPSTR - pszDisplayFrom
|
|
MsgInfo.pszDisplayFrom = (LPSTR)pbData;
|
|
pbData += (lstrlen(MsgInfo.pszDisplayFrom) + 1);
|
|
|
|
// No Display From and we have a from header
|
|
if ('\0' == *MsgInfo.pszDisplayFrom && '\0' != MsgInfo.pszFromHeader)
|
|
MsgInfo.pszDisplayFrom = MsgInfo.pszFromHeader;
|
|
|
|
// LPSTR - pszEmailFrom
|
|
MsgInfo.pszEmailFrom = (LPSTR)pbData;
|
|
pbData += (lstrlen(MsgInfo.pszEmailFrom) + 1);
|
|
|
|
// Going to V4 ?
|
|
if (pRecord->cbRecord - (DWORD)(pbData - pbStart) - sizeof(RECORDBLOCKV5B1) > 40)
|
|
{
|
|
// WORD - wLanguage
|
|
CopyMemory(&MsgInfo.wLanguage, pbData, sizeof(MsgInfo.wLanguage));
|
|
pbData += sizeof(MsgInfo.wLanguage);
|
|
|
|
// WORD - wReserved
|
|
pbData += sizeof(WORD);
|
|
|
|
// DWORD - cbMessage
|
|
CopyMemory(&MsgInfo.cbMessage, pbData, sizeof(MsgInfo.cbMessage));
|
|
pbData += sizeof(MsgInfo.cbMessage);
|
|
|
|
// FILETIME - ftReceived
|
|
CopyMemory(&MsgInfo.ftReceived, pbData, sizeof(MsgInfo.ftReceived));
|
|
pbData += sizeof(MsgInfo.ftReceived);
|
|
|
|
// SBAILEY: Raid-76295: News store corrupted when system dates are changed, Find dialog returns dates of 1900, 00 or blank
|
|
if (0 == MsgInfo.ftReceived.dwLowDateTime && 0 == MsgInfo.ftReceived.dwHighDateTime)
|
|
CopyMemory(&MsgInfo.ftReceived, &MsgInfo.ftSent, sizeof(FILETIME));
|
|
|
|
// LPSTR - pszDisplayTo
|
|
MsgInfo.pszDisplayTo = (LPSTR)pbData;
|
|
pbData += (lstrlen(MsgInfo.pszDisplayTo) + 1);
|
|
}
|
|
|
|
// Otherwise
|
|
else
|
|
{
|
|
// Set ftReceived
|
|
CopyMemory(&MsgInfo.ftReceived, &MsgInfo.ftSent, sizeof(FILETIME));
|
|
}
|
|
|
|
// Copy over the stream...
|
|
if (0 != faStream)
|
|
{
|
|
// Allocate a new stream
|
|
IF_FAILEXIT(hr = pDB->CreateStream(&faDstStream));
|
|
|
|
// Open the stream
|
|
IF_FAILEXIT(hr = pDB->OpenStream(ACCESS_WRITE, faDstStream, &pStream));
|
|
|
|
// Start Copying Message
|
|
faStreamBlock = faStream;
|
|
|
|
// While we have a stream block
|
|
while(faStreamBlock)
|
|
{
|
|
// Get a stream block
|
|
IF_FAILEXIT(hr = GetStreamBlock(pFile, faStreamBlock, &pStmBlock, &pbData, pfContinue));
|
|
|
|
// Write into the stream
|
|
IF_FAILEXIT(hr = pStream->Write(pbData, pStmBlock->cbData, NULL));
|
|
|
|
// Goto Next Block
|
|
faStreamBlock = pStmBlock->faNext;
|
|
}
|
|
|
|
// Commit
|
|
IF_FAILEXIT(hr = pStream->Commit(STGC_DEFAULT));
|
|
|
|
// Set new stream location
|
|
MsgInfo.faStream = faDstStream;
|
|
|
|
// Release the Stream
|
|
SafeRelease(pStream);
|
|
}
|
|
|
|
// If No Account Id and we have a server
|
|
if ('\0' == *pInfo->szAcctId && '\0' != *MsgInfo.pszServer)
|
|
{
|
|
// Loop through the Accounts
|
|
for (DWORD i=0; i<g_AcctTable.cAccounts; i++)
|
|
{
|
|
// Is this the Account
|
|
if (lstrcmpi(g_AcctTable.prgAccount[i].szServer, MsgInfo.pszServer) == 0)
|
|
{
|
|
StrCpyN(pInfo->szAcctId, g_AcctTable.prgAccount[i].szAcctId, ARRAYSIZE(pInfo->szAcctId));
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Default to szAcctId
|
|
MsgInfo.pszAcctId = pInfo->szAcctId;
|
|
|
|
// Lookup Account Id from the Account Name...
|
|
if (MsgInfo.pszAcctName)
|
|
{
|
|
// Loop through the Accounts
|
|
for (DWORD i=0; i<g_AcctTable.cAccounts; i++)
|
|
{
|
|
// Is this the Account
|
|
if (lstrcmpi(g_AcctTable.prgAccount[i].szAcctName, MsgInfo.pszAcctName) == 0)
|
|
{
|
|
MsgInfo.pszAcctId = g_AcctTable.prgAccount[i].szAcctId;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Otherwise, if we have an account Id, get the account name
|
|
else if ('\0' != *pInfo->szAcctId)
|
|
{
|
|
// Loop through the Accounts
|
|
for (DWORD i=0; i<g_AcctTable.cAccounts; i++)
|
|
{
|
|
// Is this the Account
|
|
if (lstrcmpi(g_AcctTable.prgAccount[i].szAcctId, MsgInfo.pszAcctId) == 0)
|
|
{
|
|
MsgInfo.pszAcctName = g_AcctTable.prgAccount[i].szAcctName;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Count
|
|
pInfo->cMessages++;
|
|
if (!ISFLAGSET(MsgInfo.dwFlags, ARF_READ))
|
|
pInfo->cUnread++;
|
|
|
|
// Migrated
|
|
FLAGSET(MsgInfo.dwFlags, 0x00000010);
|
|
|
|
// Insert the Record
|
|
IF_FAILEXIT(hr = pDB->InsertRecord(&MsgInfo));
|
|
|
|
// Bump Progress
|
|
if(!g_fQuiet)
|
|
IncrementProgress(pProgress, pInfo);
|
|
|
|
// Goto the Next Record
|
|
faRecord = pRecord->faNext;
|
|
}
|
|
|
|
exit:
|
|
// Cleanup
|
|
SafeRelease(pStream);
|
|
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// ParseFolderFileV5
|
|
// --------------------------------------------------------------------------------
|
|
HRESULT ParseFolderFileV5(LPMEMORYFILE pFile, LPFILEINFO pInfo,
|
|
LPPROGRESSINFO pProgress, LPDWORD pcFolders,
|
|
LPFLDINFO *pprgFolder)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
LPBYTE pbData;
|
|
DWORD faRecord;
|
|
LPFLDINFO pFolder;
|
|
LPFLDINFO prgFolder=NULL;
|
|
LPRECORDBLOCKV5B1 pRecord;
|
|
LPTABLEHEADERV5B1 pHeader;
|
|
BOOL fContinue;
|
|
DWORD cFolders=0;
|
|
|
|
// Trace
|
|
TraceCall("ParseFolderFileV5");
|
|
|
|
// De-ref the header
|
|
pHeader = (LPTABLEHEADERV5B1)pFile->pView;
|
|
|
|
// Get CacheInfo
|
|
if (sizeof(STOREUSERDATA) != pHeader->cbUserData)
|
|
{
|
|
hr = TraceResult(MIGRATE_E_USERDATASIZEDIFF);
|
|
goto exit;
|
|
}
|
|
|
|
// Allocate Folder Array
|
|
IF_NULLEXIT(prgFolder = (LPFLDINFO)ZeroAllocate(sizeof(FLDINFO) * pHeader->cRecords));
|
|
|
|
// Initialize faRecord to start
|
|
faRecord = pHeader->faFirstRecord;
|
|
|
|
// While we have a record
|
|
while(faRecord)
|
|
{
|
|
// Readability
|
|
pFolder = &prgFolder[cFolders];
|
|
|
|
// Get the Record
|
|
IF_FAILEXIT(hr = GetRecordBlock(pFile, faRecord, &pRecord, &pbData, &fContinue));
|
|
|
|
// DWORD - hFolder
|
|
CopyMemory(&pFolder->idFolder, pbData, sizeof(pFolder->idFolder));
|
|
pbData += sizeof(pFolder->idFolder);
|
|
|
|
// CHAR(MAX_FOLDER_NAME) - szFolder
|
|
CopyMemory(pFolder->szFolder, pbData, sizeof(pFolder->szFolder));
|
|
pbData += sizeof(pFolder->szFolder);
|
|
|
|
// CHAR(260) - szFile
|
|
CopyMemory(pFolder->szFile, pbData, sizeof(pFolder->szFile));
|
|
pbData += sizeof(pFolder->szFile);
|
|
|
|
// DWORD - idParent
|
|
CopyMemory(&pFolder->idParent, pbData, sizeof(pFolder->idParent));
|
|
pbData += sizeof(pFolder->idParent);
|
|
|
|
// DWORD - idChild
|
|
CopyMemory(&pFolder->idChild, pbData, sizeof(pFolder->idChild));
|
|
pbData += sizeof(pFolder->idChild);
|
|
|
|
// DWORD - idSibling
|
|
CopyMemory(&pFolder->idSibling, pbData, sizeof(pFolder->idSibling));
|
|
pbData += sizeof(pFolder->idSibling);
|
|
|
|
// DWORD - tySpecial
|
|
CopyMemory(&pFolder->tySpecial, pbData, sizeof(pFolder->tySpecial));
|
|
pbData += sizeof(pFolder->tySpecial);
|
|
|
|
// DWORD - cChildren
|
|
CopyMemory(&pFolder->cChildren, pbData, sizeof(pFolder->cChildren));
|
|
pbData += sizeof(pFolder->cChildren);
|
|
|
|
// DWORD - cMessages
|
|
CopyMemory(&pFolder->cMessages, pbData, sizeof(pFolder->cMessages));
|
|
pbData += sizeof(pFolder->cMessages);
|
|
|
|
// DWORD - cUnread
|
|
CopyMemory(&pFolder->cUnread, pbData, sizeof(pFolder->cUnread));
|
|
pbData += sizeof(pFolder->cUnread);
|
|
|
|
// DWORD - cbTotal
|
|
CopyMemory(&pFolder->cbTotal, pbData, sizeof(pFolder->cbTotal));
|
|
pbData += sizeof(pFolder->cbTotal);
|
|
|
|
// DWORD - cbUsed
|
|
CopyMemory(&pFolder->cbUsed, pbData, sizeof(pFolder->cbUsed));
|
|
pbData += sizeof(pFolder->cbUsed);
|
|
|
|
// DWORD - bHierarchy
|
|
CopyMemory(&pFolder->bHierarchy, pbData, sizeof(pFolder->bHierarchy));
|
|
pbData += sizeof(pFolder->bHierarchy);
|
|
|
|
// DWORD - dwImapFlags
|
|
CopyMemory(&pFolder->dwImapFlags, pbData, sizeof(pFolder->dwImapFlags));
|
|
pbData += sizeof(DWORD);
|
|
|
|
// BLOB - bListStamp
|
|
CopyMemory(&pFolder->bListStamp, pbData, sizeof(pFolder->bListStamp));
|
|
pbData += sizeof(BYTE);
|
|
|
|
// DWORD - bReserved[3]
|
|
pbData += (3 * sizeof(BYTE));
|
|
|
|
// DWORD - rgbReserved
|
|
pbData += 40;
|
|
|
|
// Increment Count
|
|
cFolders++;
|
|
|
|
// Bump Progress
|
|
if(!g_fQuiet)
|
|
IncrementProgress(pProgress, pInfo);
|
|
|
|
// Goto the Next Record
|
|
faRecord = pRecord->faNext;
|
|
}
|
|
|
|
// Return Folder Count
|
|
*pcFolders = cFolders;
|
|
|
|
// Return the Array
|
|
*pprgFolder = prgFolder;
|
|
|
|
// Don't Free It
|
|
prgFolder = NULL;
|
|
|
|
exit:
|
|
// Cleanup
|
|
SafeMemFree(prgFolder);
|
|
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// UpgradePop3UidlFileV5
|
|
// --------------------------------------------------------------------------------
|
|
HRESULT UpgradePop3UidlFileV5(LPFILEINFO pInfo, LPMEMORYFILE pFile,
|
|
IDatabase *pDB, LPPROGRESSINFO pProgress, BOOL *pfContinue)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
LPBYTE pbData;
|
|
DWORD faRecord;
|
|
UIDLRECORD UidlInfo;
|
|
LPRECORDBLOCKV5B1 pRecord;
|
|
LPTABLEHEADERV5B1 pHeader=(LPTABLEHEADERV5B1)pFile->pView;
|
|
|
|
// Trace
|
|
TraceCall("UpgradePop3UidlFileV5");
|
|
|
|
// Initialize faRecord to start
|
|
faRecord = pHeader->faFirstRecord;
|
|
|
|
// While we have a record
|
|
while(faRecord)
|
|
{
|
|
// Get the Record
|
|
IF_FAILEXIT(hr = GetRecordBlock(pFile, faRecord, &pRecord, &pbData, pfContinue));
|
|
|
|
// Clear UidlInfo
|
|
ZeroMemory(&UidlInfo, sizeof(UIDLRECORD));
|
|
|
|
// FILETIME - ftDownload
|
|
CopyMemory(&UidlInfo.ftDownload, pbData, sizeof(UidlInfo.ftDownload));
|
|
pbData += sizeof(UidlInfo.ftDownload);
|
|
|
|
// BYTE - fDownloaded
|
|
CopyMemory(&UidlInfo.fDownloaded, pbData, sizeof(UidlInfo.fDownloaded));
|
|
pbData += sizeof(UidlInfo.fDownloaded);
|
|
|
|
// BYTE - fDeleted
|
|
CopyMemory(&UidlInfo.fDeleted, pbData, sizeof(UidlInfo.fDeleted));
|
|
pbData += sizeof(UidlInfo.fDeleted);
|
|
|
|
// LPSTR - pszUidl
|
|
UidlInfo.pszUidl = (LPSTR)pbData;
|
|
pbData += (lstrlen(UidlInfo.pszUidl) + 1);
|
|
|
|
// LPSTR - pszServer
|
|
UidlInfo.pszServer = (LPSTR)pbData;
|
|
pbData += (lstrlen(UidlInfo.pszServer) + 1);
|
|
|
|
// Insert the Record
|
|
IF_FAILEXIT(hr = pDB->InsertRecord(&UidlInfo));
|
|
|
|
// Bump Progress
|
|
if(!g_fQuiet)
|
|
IncrementProgress(pProgress, pInfo);
|
|
|
|
// Goto the Next Record
|
|
faRecord = pRecord->faNext;
|
|
}
|
|
|
|
exit:
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// UpgradeFileV5
|
|
// --------------------------------------------------------------------------------
|
|
HRESULT UpgradeFileV5(IDatabaseSession *pSession, MIGRATETOTYPE tyMigrate,
|
|
LPFILEINFO pInfo, LPPROGRESSINFO pProgress, BOOL *pfContinue)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
MEMORYFILE File={0};
|
|
IDatabase *pDB=NULL;
|
|
|
|
// Trace
|
|
TraceCall("UpgradeFileV5");
|
|
|
|
// Local message file
|
|
if (FILE_IS_LOCAL_MESSAGES == pInfo->tyFile)
|
|
{
|
|
// Create an ObjectDatabase (upgrade only runs when OE5 is installed)
|
|
IF_FAILEXIT(hr = pSession->OpenDatabase(pInfo->szDstFile, 0, &g_MessageTableSchema, NULL, &pDB));
|
|
|
|
// Get the File Header
|
|
IF_FAILEXIT(hr = OpenMemoryFile(pInfo->szFilePath, &File));
|
|
|
|
// UpgradeLocalStoreFileV5
|
|
IF_FAILEXIT(hr = UpgradeLocalStoreFileV5(pInfo, &File, pDB, pProgress, pfContinue));
|
|
}
|
|
|
|
// Old News or Imap file
|
|
else if (FILE_IS_NEWS_MESSAGES == pInfo->tyFile || FILE_IS_IMAP_MESSAGES == pInfo->tyFile)
|
|
{
|
|
// Create an ObjectDatabase (upgrade only runs when OE5 is installed)
|
|
IF_FAILEXIT(hr = pSession->OpenDatabase(pInfo->szDstFile, 0, &g_MessageTableSchema, NULL, &pDB));
|
|
|
|
// Get the File Header
|
|
IF_FAILEXIT(hr = OpenMemoryFile(pInfo->szFilePath, &File));
|
|
|
|
// UpgradePropTreeMessageFileV5
|
|
IF_FAILEXIT(hr = UpgradePropTreeMessageFileV5(pInfo, &File, pDB, pProgress, pfContinue));
|
|
}
|
|
|
|
// pop3uidl file
|
|
else if (FILE_IS_POP3UIDL == pInfo->tyFile)
|
|
{
|
|
// Create an ObjectDatabase (upgrade only runs when OE5 is installed)
|
|
IF_FAILEXIT(hr = pSession->OpenDatabase(pInfo->szDstFile, 0, &g_UidlTableSchema, NULL, &pDB));
|
|
|
|
// Get the File Header
|
|
IF_FAILEXIT(hr = OpenMemoryFile(pInfo->szFilePath, &File));
|
|
|
|
// UpgradePop3UidlFileV5
|
|
IF_FAILEXIT(hr = UpgradePop3UidlFileV5(pInfo, &File, pDB, pProgress, pfContinue));
|
|
}
|
|
|
|
exit:
|
|
// Cleanup
|
|
SafeRelease(pDB);
|
|
CloseMemoryFile(&File);
|
|
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// UpgradeProcessFileListV5
|
|
// --------------------------------------------------------------------------------
|
|
HRESULT UpgradeProcessFileListV5(LPCSTR pszStoreSrc, LPCSTR pszStoreDst,
|
|
LPFILEINFO pHead, LPDWORD pcMax, LPDWORD pcbNeeded)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
MEMORYFILE File={0};
|
|
LPFILEINFO pCurrent;
|
|
LPTABLEHEADERV5B1 pHeader;
|
|
|
|
// Trace
|
|
TraceCall("UpgradeProcessFileListV5");
|
|
|
|
// Init
|
|
*pcMax = 0;
|
|
*pcbNeeded = 0;
|
|
|
|
// Loop
|
|
for (pCurrent=pHead; pCurrent!=NULL; pCurrent=pCurrent->pNext)
|
|
{
|
|
// Get the File Header
|
|
hr = OpenMemoryFile(pCurrent->szFilePath, &File);
|
|
|
|
// Failure ?
|
|
if (FAILED(hr) || 0 == File.cbSize)
|
|
{
|
|
// Don't Migrate
|
|
pCurrent->fMigrate = FALSE;
|
|
|
|
// Set hrMigrate
|
|
pCurrent->hrMigrate = (0 == File.cbSize ? S_OK : hr);
|
|
|
|
// Reset hr
|
|
hr = S_OK;
|
|
|
|
// Get the LastError
|
|
pCurrent->dwLastError = GetLastError();
|
|
|
|
// Goto Next
|
|
goto NextFile;
|
|
}
|
|
|
|
// Local message file
|
|
if (FILE_IS_LOCAL_MESSAGES == pCurrent->tyFile)
|
|
{
|
|
// Cast the Header
|
|
LPMBXFILEHEADER pMbxHeader=(LPMBXFILEHEADER)File.pView;
|
|
|
|
// Bad Version
|
|
if (File.cbSize < sizeof(MBXFILEHEADER) || pMbxHeader->dwMagic != MSGFILE_MAGIC || pMbxHeader->ver != MSGFILE_VER)
|
|
{
|
|
// Not a file that should be migrate
|
|
pCurrent->fMigrate = FALSE;
|
|
|
|
// Set hrMigrate
|
|
pCurrent->hrMigrate = MIGRATE_E_BADVERSION;
|
|
|
|
// Goto Next
|
|
goto NextFile;
|
|
}
|
|
|
|
// Save the Number of record
|
|
pCurrent->cRecords = pMbxHeader->cMsg;
|
|
}
|
|
|
|
// Otherwise, if its a news group list
|
|
else if (FILE_IS_NEWS_SUBLIST == pCurrent->tyFile)
|
|
{
|
|
// De-Ref the header
|
|
LPSUBLISTHEADER pSubList = (LPSUBLISTHEADER)File.pView;
|
|
|
|
// Check the Signature...
|
|
if (File.cbSize < sizeof(SUBLISTHEADER) ||
|
|
(SUBFILE_VERSION5 != pSubList->dwVersion &&
|
|
SUBFILE_VERSION4 != pSubList->dwVersion &&
|
|
SUBFILE_VERSION3 != pSubList->dwVersion &&
|
|
SUBFILE_VERSION2 != pSubList->dwVersion))
|
|
{
|
|
// Not a file that should be migrate
|
|
pCurrent->fMigrate = FALSE;
|
|
|
|
// Set hrMigrate
|
|
pCurrent->hrMigrate = MIGRATE_E_BADVERSION;
|
|
|
|
// Goto Next
|
|
goto NextFile;
|
|
}
|
|
|
|
// Save the Number of record
|
|
pCurrent->cRecords = pSubList->cSubscribed;
|
|
}
|
|
|
|
// Otherwise, if its a news sub list
|
|
else if (FILE_IS_NEWS_GRPLIST == pCurrent->tyFile)
|
|
{
|
|
// De-Ref the header
|
|
LPGRPLISTHEADER pGrpList = (LPGRPLISTHEADER)File.pView;
|
|
|
|
// Check the Signature...
|
|
if (File.cbSize < sizeof(GRPLISTHEADER) || GROUPLISTVERSION != pGrpList->dwVersion)
|
|
{
|
|
// Not a file that should be migrate
|
|
pCurrent->fMigrate = FALSE;
|
|
|
|
// Set hrMigrate
|
|
pCurrent->hrMigrate = MIGRATE_E_BADVERSION;
|
|
|
|
// Goto Next
|
|
goto NextFile;
|
|
}
|
|
|
|
// Save the Number of record
|
|
pCurrent->cRecords = pGrpList->cGroups;
|
|
}
|
|
|
|
// Otherwise, objectdb file
|
|
else
|
|
{
|
|
// De-Ref the header
|
|
pHeader = (LPTABLEHEADERV5B1)File.pView;
|
|
|
|
// Check the Signature...
|
|
if (File.cbSize < sizeof(TABLEHEADERV5B1) || OBJECTDB_SIGNATURE != pHeader->dwSignature || OBJECTDB_VERSION_PRE_V5 != pHeader->wMajorVersion)
|
|
{
|
|
// Not a file that should be migrate
|
|
pCurrent->fMigrate = FALSE;
|
|
|
|
// Set hrMigrate
|
|
pCurrent->hrMigrate = MIGRATE_E_BADVERSION;
|
|
|
|
// Goto Next
|
|
goto NextFile;
|
|
}
|
|
|
|
// Save the Number of record
|
|
pCurrent->cRecords = pHeader->cRecords;
|
|
}
|
|
|
|
// Special Case pop3uidl.dat
|
|
if (FILE_IS_POP3UIDL == pCurrent->tyFile)
|
|
{
|
|
// Compute Real Destination File
|
|
wnsprintf(pCurrent->szDstFile, ARRAYSIZE(pCurrent->szDstFile),"%s\\pop3uidl.dbx", pszStoreDst);
|
|
}
|
|
|
|
// Otherwise, generate a unqiue message file name
|
|
else
|
|
{
|
|
// Save the Folder Id
|
|
pCurrent->idFolder = g_idFolderNext;
|
|
|
|
// Build New Path
|
|
wnsprintf(pCurrent->szDstFile, ARRAYSIZE(pCurrent->szDstFile), "%s\\%08d.dbx", pszStoreDst, g_idFolderNext);
|
|
|
|
// Increment id
|
|
g_idFolderNext++;
|
|
}
|
|
|
|
// Initialize counters
|
|
InitializeCounters(&File, pCurrent, pcMax, pcbNeeded, TRUE);
|
|
|
|
// Yes, Migrate
|
|
pCurrent->fMigrate = TRUE;
|
|
|
|
NextFile:
|
|
// Close the File
|
|
CloseMemoryFile(&File);
|
|
}
|
|
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// UpgradeDeleteFilesV5
|
|
// --------------------------------------------------------------------------------
|
|
void UpgradeDeleteFilesV5(LPCSTR pszStoreDst)
|
|
{
|
|
// Locals
|
|
CHAR szSearch[MAX_PATH + MAX_PATH];
|
|
CHAR szFilePath[MAX_PATH + MAX_PATH];
|
|
HANDLE hFind=INVALID_HANDLE_VALUE;
|
|
WIN32_FIND_DATA fd;
|
|
|
|
// Trace
|
|
TraceCall("UpgradeDeleteFilesV5");
|
|
|
|
// Do we have a sub dir
|
|
wnsprintf(szSearch, ARRAYSIZE(szSearch),"%s\\*.dbx", pszStoreDst);
|
|
|
|
// Find first file
|
|
hFind = FindFirstFile(szSearch, &fd);
|
|
|
|
// Did we find something
|
|
if (INVALID_HANDLE_VALUE == hFind)
|
|
goto exit;
|
|
|
|
// Loop for ever
|
|
while(1)
|
|
{
|
|
// Make File Path
|
|
MakeFilePath(pszStoreDst, fd.cFileName, "", szFilePath, ARRAYSIZE(szFilePath));
|
|
|
|
// Delete
|
|
DeleteFile(szFilePath);
|
|
|
|
// Find the Next File
|
|
if (!FindNextFile(hFind, &fd))
|
|
break;
|
|
}
|
|
|
|
exit:
|
|
// Cleanup
|
|
if (hFind)
|
|
FindClose(hFind);
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// UpgradeDeleteIdxMbxNchDatFilesV5
|
|
// --------------------------------------------------------------------------------
|
|
void UpgradeDeleteIdxMbxNchDatFilesV5(LPFILEINFO pHeadFile)
|
|
{
|
|
// Locals
|
|
CHAR szDstFile[MAX_PATH + MAX_PATH];
|
|
LPFILEINFO pCurrent;
|
|
|
|
// Trace
|
|
TraceCall("UpgradeDeleteOdbFilesV5");
|
|
|
|
// Delete all old files
|
|
for (pCurrent=pHeadFile; pCurrent!=NULL; pCurrent=pCurrent->pNext)
|
|
{
|
|
// Succeeded
|
|
Assert(SUCCEEDED(pCurrent->hrMigrate));
|
|
|
|
// Delete the file
|
|
// DeleteFile(pCurrent->szFilePath);
|
|
|
|
// If local message file, need to delete the idx file
|
|
if (FILE_IS_LOCAL_MESSAGES == pCurrent->tyFile)
|
|
{
|
|
// Replace file extension
|
|
ReplaceExtension(pCurrent->szFilePath, ".idx", szDstFile, ARRAYSIZE(szDstFile));
|
|
|
|
// Delete the file
|
|
// DeleteFile(szDstFile);
|
|
}
|
|
}
|
|
|
|
// Done
|
|
return;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// GetSpecialFolderInfo
|
|
// --------------------------------------------------------------------------------
|
|
HRESULT GetSpecialFolderInfo(LPCSTR pszFilePath, LPSTR pszFolder,
|
|
DWORD cchFolder, DWORD *ptySpecial)
|
|
{
|
|
// Locals
|
|
CHAR szPath[_MAX_PATH];
|
|
CHAR szDrive[_MAX_DRIVE];
|
|
CHAR szDir[_MAX_DIR];
|
|
CHAR szFile[_MAX_FNAME];
|
|
CHAR szExt[_MAX_EXT];
|
|
CHAR szRes[255];
|
|
DWORD i;
|
|
|
|
// Trace
|
|
TraceCall("GetSpecialFolderInfo");
|
|
|
|
// Initialize
|
|
*ptySpecial = 0xffffffff;
|
|
|
|
// Split the Path
|
|
_splitpath(pszFilePath, szDrive, szDir, szFile, szExt);
|
|
|
|
// Set Folder Name
|
|
StrCpyN(pszFolder, szFile, cchFolder);
|
|
|
|
// Loop through special folder
|
|
for (i=FOLDER_INBOX; i<FOLDER_MAX; i++)
|
|
{
|
|
// Load the Special Folder Name
|
|
LoadString(g_hInst, IDS_INBOX + (i - 1), szRes, ARRAYSIZE(szRes));
|
|
|
|
// Compare with szFile
|
|
if (lstrcmpi(szFile, szRes) == 0)
|
|
{
|
|
// Copy the Folder Name
|
|
StrCpyN(pszFolder, szRes, cchFolder);
|
|
|
|
// Return special folder type
|
|
*ptySpecial = (i - 1);
|
|
|
|
// Success
|
|
return(S_OK);
|
|
}
|
|
}
|
|
|
|
// Done
|
|
return(E_FAIL);
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// FixupFolderUserData
|
|
// --------------------------------------------------------------------------------
|
|
HRESULT FixupFolderUserData(IDatabaseSession *pSession, FOLDERID idFolder,
|
|
LPCSTR pszName, SPECIALFOLDER tySpecial, LPFILEINFO pCurrent)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
FOLDERUSERDATA UserData;
|
|
IDatabase *pDB=NULL;
|
|
|
|
// Trace
|
|
TraceCall("FixupFolderUserData");
|
|
|
|
// Better not be in the store yet
|
|
Assert(FALSE == pCurrent->fInStore);
|
|
|
|
// Its in the store
|
|
pCurrent->fInStore = TRUE;
|
|
|
|
// Create an Ojbect Database
|
|
IF_FAILEXIT(hr = pSession->OpenDatabase(pCurrent->szDstFile, 0, &g_MessageTableSchema, NULL, &pDB));
|
|
|
|
// Store the User Data
|
|
IF_FAILEXIT(hr = pDB->GetUserData(&UserData, sizeof(FOLDERUSERDATA)));
|
|
|
|
// Its Initialized
|
|
UserData.fInitialized = TRUE;
|
|
|
|
// UserData.clsidType
|
|
if (ISFLAGSET(pCurrent->dwServer, SRV_POP3))
|
|
UserData.tyFolder = FOLDER_LOCAL;
|
|
else if (ISFLAGSET(pCurrent->dwServer, SRV_NNTP))
|
|
UserData.tyFolder = FOLDER_NEWS;
|
|
else if (ISFLAGSET(pCurrent->dwServer, SRV_IMAP))
|
|
UserData.tyFolder = FOLDER_IMAP;
|
|
|
|
// Copy the Account Id
|
|
StrCpyN(UserData.szAcctId, pCurrent->szAcctId, ARRAYSIZE(UserData.szAcctId));
|
|
|
|
// Save Folder Id
|
|
UserData.idFolder = idFolder;
|
|
|
|
// Save Special Folder Type
|
|
UserData.tySpecial = tySpecial;
|
|
|
|
// Copy the Folder name
|
|
StrCpyN(UserData.szFolder, pszName, ARRAYSIZE(UserData.szFolder));
|
|
|
|
// Must be Subscribed
|
|
UserData.fSubscribed = TRUE;
|
|
|
|
// Set the Sort Index Information
|
|
UserData.idSort = COLUMN_RECEIVED;
|
|
|
|
// Not Ascending
|
|
UserData.fAscending = FALSE;
|
|
|
|
// Not threaded
|
|
UserData.fThreaded = FALSE;
|
|
|
|
// Basic Filter
|
|
UserData.ridFilter = RULEID_VIEW_ALL;
|
|
|
|
// Add Welcome Message Again
|
|
UserData.fWelcomeAdded = FALSE;
|
|
|
|
// Show Deleted
|
|
UserData.fShowDeleted = TRUE;
|
|
|
|
// New thread model
|
|
UserData.fNewThreadModel = TRUE;
|
|
UserData.fTotalWatched = TRUE;
|
|
UserData.fWatchedCounts = TRUE;
|
|
|
|
// Store the User Data
|
|
IF_FAILEXIT(hr = pDB->SetUserData(&UserData, sizeof(FOLDERUSERDATA)));
|
|
|
|
exit:
|
|
// Cleanup
|
|
SafeRelease(pDB);
|
|
|
|
// Done
|
|
return(hr);
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// SetIMAPSpecialFldrType
|
|
// --------------------------------------------------------------------------------
|
|
HRESULT SetIMAPSpecialFldrType(LPSTR pszAcctID, LPSTR pszFldrName, SPECIALFOLDER *psfType)
|
|
{
|
|
char szPath[MAX_PATH + 1];
|
|
SPECIALFOLDER sfResult = FOLDER_NOTSPECIAL;
|
|
|
|
TraceCall("SetIMAPSpecialFldrType");
|
|
Assert(NULL != psfType);
|
|
Assert(FOLDER_NOTSPECIAL == *psfType);
|
|
|
|
LoadString(g_hInst, IDS_SENTITEMS, szPath, sizeof(szPath));
|
|
if (0 == lstrcmp(szPath, pszFldrName))
|
|
{
|
|
sfResult = FOLDER_SENT;
|
|
goto exit;
|
|
}
|
|
|
|
LoadString(g_hInst, IDS_DRAFT, szPath, sizeof(szPath));
|
|
if (0 == lstrcmp(szPath, pszFldrName))
|
|
{
|
|
sfResult = FOLDER_DRAFT;
|
|
goto exit;
|
|
}
|
|
|
|
|
|
exit:
|
|
*psfType = sfResult;
|
|
return S_OK;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// InsertFolderIntoStore
|
|
// --------------------------------------------------------------------------------
|
|
HRESULT InsertFolderIntoStore(IDatabaseSession *pSession, IMessageStore *pStore,
|
|
LPFLDINFO pThis, DWORD cFolders, LPFLDINFO prgFolder, FOLDERID idParentNew,
|
|
LPFILEINFO pInfo, LPFILEINFO pFileHead, LPFOLDERID pidNew)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
DWORD i;
|
|
CHAR szPath[_MAX_PATH];
|
|
CHAR szDrive[_MAX_DRIVE];
|
|
CHAR szDir[_MAX_DIR];
|
|
CHAR szFile[_MAX_FNAME];
|
|
CHAR szExt[_MAX_EXT];
|
|
CHAR szFilePath[MAX_PATH];
|
|
CHAR szInbox[MAX_PATH];
|
|
BOOL fFound=FALSE;
|
|
LPFILEINFO pCurrent=NULL;
|
|
FOLDERINFO Folder={0};
|
|
|
|
// Trace
|
|
TraceCall("InsertFolderIntoStore");
|
|
|
|
// Invalid Arg
|
|
//Assert(FILE_IS_LOCAL_FOLDERS == pInfo->tyFile || FILE_IS_IMAP_FOLDERS == pInfo->tyFile);
|
|
|
|
// Copy Stuff Over to Folder
|
|
Folder.pszName = pThis->szFolder;
|
|
Folder.idParent = idParentNew;
|
|
Folder.bHierarchy = pThis->bHierarchy;
|
|
Folder.dwFlags = FOLDER_SUBSCRIBED; // $$TODO$$ May need to adjust and map to new flags
|
|
Folder.tySpecial = (0xffffffff == pThis->tySpecial) ? FOLDER_NOTSPECIAL : (BYTE)(pThis->tySpecial + 1);
|
|
Folder.cMessages = pThis->cMessages;
|
|
Folder.cUnread = pThis->cUnread;
|
|
Folder.pszFile = pThis->szFile;
|
|
Folder.dwListStamp = pThis->bListStamp;
|
|
|
|
// For IMAP folders, we have to set tySpecial based on registry folder paths
|
|
if (pInfo && FILE_IS_IMAP_FOLDERS == pInfo->tyFile && NULL != pThis &&
|
|
FOLDERID_ROOT == (FOLDERID)IntToPtr(pThis->idParent))
|
|
{
|
|
HRESULT hrTemp;
|
|
|
|
if (FOLDER_NOTSPECIAL == Folder.tySpecial)
|
|
{
|
|
hrTemp = SetIMAPSpecialFldrType(pInfo->szAcctId, Folder.pszName, &Folder.tySpecial);
|
|
TraceError(hrTemp);
|
|
Assert(SUCCEEDED(hrTemp) || FOLDER_NOTSPECIAL == Folder.tySpecial);
|
|
}
|
|
else if (FOLDER_INBOX == Folder.tySpecial)
|
|
{
|
|
LoadString(g_hInst, IDS_INBOX, szInbox, ARRAYSIZE(szInbox));
|
|
Folder.pszName = szInbox;
|
|
}
|
|
}
|
|
|
|
// Look for Current
|
|
if (pInfo && pFileHead)
|
|
{
|
|
// Locate the file...
|
|
for (pCurrent=pFileHead; pCurrent!=NULL; pCurrent=pCurrent->pNext)
|
|
{
|
|
// Migrate
|
|
if (pCurrent->fMigrate)
|
|
{
|
|
// Local Folder ?
|
|
if (FILE_IS_LOCAL_FOLDERS == pInfo->tyFile && FILE_IS_LOCAL_MESSAGES == pCurrent->tyFile)
|
|
{
|
|
// Get the File Name
|
|
_splitpath(pCurrent->szFilePath, szDrive, szDir, szFile, szExt);
|
|
|
|
// Test For File Name
|
|
if (lstrcmpi(szFile, pThis->szFile) == 0)
|
|
{
|
|
// This is It
|
|
fFound = TRUE;
|
|
|
|
// Adjust the Flags
|
|
FLAGSET(Folder.dwFlags, FOLDER_SUBSCRIBED);
|
|
}
|
|
}
|
|
|
|
// IMAP Folders ?
|
|
else if (FILE_IS_IMAP_FOLDERS == pInfo->tyFile && FILE_IS_IMAP_MESSAGES == pCurrent->tyFile)
|
|
{
|
|
// Same Account
|
|
if (lstrcmpi(pCurrent->szAcctId, pInfo->szAcctId) == 0)
|
|
{
|
|
// Get the File Name
|
|
_splitpath(pCurrent->szFilePath, szDrive, szDir, szFile, szExt);
|
|
|
|
// Build File
|
|
wnsprintf(szFilePath, ARRAYSIZE(szFilePath), "%s.nch", szFile);
|
|
|
|
// Test For File Name
|
|
if (lstrcmpi(szFilePath, pThis->szFile) == 0)
|
|
{
|
|
// This is It
|
|
fFound = TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Found
|
|
if (fFound)
|
|
{
|
|
// Get the File Name
|
|
_splitpath(pCurrent->szDstFile, szDrive, szDir, szFile, szExt);
|
|
|
|
// Build File
|
|
wnsprintf(szFilePath, ARRAYSIZE(szFilePath), "%s.dbx", szFile);
|
|
|
|
// Local the File for this folder and set
|
|
Folder.pszFile = szFilePath;
|
|
|
|
// Set Folder Counts
|
|
Folder.cMessages = pCurrent->cMessages;
|
|
Folder.cUnread = pCurrent->cUnread;
|
|
|
|
// Done
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// If this is a special folder, then lets try to see if it already exists...
|
|
if (FOLDER_NOTSPECIAL != Folder.tySpecial)
|
|
{
|
|
// Locals
|
|
FOLDERINFO Special;
|
|
|
|
// pThis Parent should be invalid
|
|
Assert(FOLDERID_ROOT == (FOLDERID)IntToPtr(pThis->idParent));
|
|
|
|
// Try to get the special folder info
|
|
if (FAILED(pStore->GetSpecialFolderInfo(idParentNew, Folder.tySpecial, &Special)))
|
|
{
|
|
// Create the Folder
|
|
IF_FAILEXIT(hr = pStore->CreateFolder(NOFLAGS, &Folder, NOSTORECALLBACK));
|
|
|
|
// Update pThis->dwServerHigh with new folderid
|
|
pThis->idNewFolderId = (DWORD_PTR)Folder.idFolder;
|
|
}
|
|
|
|
// Otherwise...
|
|
else
|
|
{
|
|
// Update pThis->dwServerHigh with new folderid
|
|
pThis->idNewFolderId = (DWORD_PTR)Special.idFolder;
|
|
|
|
// Update the Special folder
|
|
Folder.idFolder = Special.idFolder;
|
|
|
|
// Update Special
|
|
Special.bHierarchy = Folder.bHierarchy;
|
|
Special.dwFlags = Folder.dwFlags; // $$TODO$$ May need to adjust and map to new flags
|
|
Special.cMessages = Folder.cMessages;
|
|
Special.cUnread = Folder.cUnread;
|
|
Special.pszFile = Folder.pszFile;
|
|
Special.dwListStamp = Folder.dwListStamp;
|
|
|
|
// Update the Record
|
|
IF_FAILEXIT(hr = pStore->UpdateRecord(&Special));
|
|
|
|
// Free Special
|
|
pStore->FreeRecord(&Special);
|
|
}
|
|
}
|
|
|
|
// Otherwise, just try to create the folder
|
|
else
|
|
{
|
|
// Create the Folder
|
|
IF_FAILEXIT(hr = pStore->CreateFolder(NOFLAGS, &Folder, NOSTORECALLBACK));
|
|
|
|
// Update pThis->dwServerHigh with new folderid
|
|
pThis->idNewFolderId = (DWORD_PTR)Folder.idFolder;
|
|
}
|
|
|
|
// If We Found a folder...
|
|
if (pCurrent)
|
|
{
|
|
// Update the Folder's UserData
|
|
IF_FAILEXIT(hr = FixupFolderUserData(pSession, Folder.idFolder, pThis->szFolder, Folder.tySpecial, pCurrent));
|
|
}
|
|
|
|
// Walk Insert the children of pThis
|
|
for (i=0; i<cFolders; i++)
|
|
{
|
|
// If Parent is equal to idParent, then lets insert this node under the new parent
|
|
if (prgFolder[i].idParent == pThis->idFolder)
|
|
{
|
|
// Can't be null
|
|
Assert(prgFolder[i].idFolder);
|
|
|
|
// InsertFolderIntoStore
|
|
IF_FAILEXIT(hr = InsertFolderIntoStore(pSession, pStore, &prgFolder[i], cFolders, prgFolder, Folder.idFolder, pInfo, pFileHead, NULL));
|
|
}
|
|
}
|
|
|
|
// Return the New Folder
|
|
if (pidNew)
|
|
*pidNew = Folder.idFolder;
|
|
|
|
exit:
|
|
// Done
|
|
return(hr);
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// MergeFolderCacheIntoStore
|
|
// --------------------------------------------------------------------------------
|
|
HRESULT MergeFolderCacheIntoStore(IDatabaseSession *pSession, IMessageStore *pStore,
|
|
LPFILEINFO pInfo, LPFILEINFO pHeadFile, LPPROGRESSINFO pProgress)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
MEMORYFILE File={0};
|
|
FOLDERID idServer;
|
|
DWORD cFolders;
|
|
DWORD i;
|
|
LPFLDINFO prgFolder=NULL;
|
|
LPFLDINFO pFolder;
|
|
HKEY hKey=NULL;
|
|
DWORD cbLength;
|
|
LPBYTE pbChange=NULL;
|
|
LPFOLDERIDCHANGE prgidChange;
|
|
IUserIdentityManager *pManager = NULL;
|
|
IUserIdentity *pIdentity = NULL;
|
|
HKEY hkeyID = NULL;
|
|
|
|
// Trace
|
|
TraceCall("MergeFolderCacheIntoStore");
|
|
|
|
// Find the Server Id
|
|
if (FAILED(pStore->FindServerId(pInfo->szAcctId, &idServer)))
|
|
goto exit;
|
|
|
|
// Open the File
|
|
IF_FAILEXIT(hr = OpenMemoryFile(pInfo->szFilePath, &File));
|
|
|
|
// Parse the file
|
|
IF_FAILEXIT(hr = ParseFolderFileV5(&File, pInfo, pProgress, &cFolders, &prgFolder));
|
|
|
|
// Loop through the folders
|
|
for (i=0; i<cFolders; i++)
|
|
{
|
|
// If this is the root folder node (OE4), remember to migrate the root hierarchy char
|
|
if ((FOLDERID)IntToPtr(prgFolder[i].idFolder) == FOLDERID_ROOT)
|
|
{
|
|
FOLDERINFO fiFolderInfo;
|
|
|
|
IF_FAILEXIT(hr = pStore->GetFolderInfo(idServer, &fiFolderInfo));
|
|
|
|
fiFolderInfo.bHierarchy = prgFolder[i].bHierarchy;
|
|
hr = pStore->UpdateRecord(&fiFolderInfo);
|
|
pStore->FreeRecord(&fiFolderInfo);
|
|
IF_FAILEXIT(hr);
|
|
}
|
|
// If Parent is equal to idParent, then lets insert this node under the new parent
|
|
else if ((FOLDERID)IntToPtr(prgFolder[i].idParent) == FOLDERID_ROOT)
|
|
{
|
|
// InsertFolderIntoStore
|
|
IF_FAILEXIT(hr = InsertFolderIntoStore(pSession, pStore, &prgFolder[i], cFolders, prgFolder, idServer, pInfo, pHeadFile, NULL));
|
|
}
|
|
}
|
|
|
|
// Local Folders
|
|
if (FILE_IS_LOCAL_FOLDERS == pInfo->tyFile)
|
|
{
|
|
// cbLength
|
|
cbLength = (sizeof(DWORD) + (sizeof(FOLDERIDCHANGE) * cFolders));
|
|
|
|
// Allocate a folderidchange array
|
|
IF_NULLEXIT(pbChange = (LPBYTE)g_pMalloc->Alloc(cbLength));
|
|
|
|
// Store cLocalFolders
|
|
CopyMemory(pbChange, &cFolders, sizeof(DWORD));
|
|
|
|
// Set prgidChange
|
|
prgidChange = (LPFOLDERIDCHANGE)(pbChange + sizeof(DWORD));
|
|
|
|
// Walk through the list of files and merge the folders, sublist, group lists into pFolder
|
|
for (i=0; i<cFolders; i++)
|
|
{
|
|
prgidChange[i].idOld = (FOLDERID)IntToPtr(prgFolder[i].idFolder);
|
|
prgidChange[i].idNew = (FOLDERID)prgFolder[i].idNewFolderId;
|
|
}
|
|
|
|
// Get a user manager
|
|
if (FAILED(CoCreateInstance(CLSID_UserIdentityManager, NULL, CLSCTX_INPROC_SERVER,
|
|
IID_IUserIdentityManager, (void **)&pManager)))
|
|
goto exit;
|
|
|
|
Assert(pManager);
|
|
|
|
// Get Default Identity
|
|
if (FAILED(pManager->GetIdentityByCookie((GUID*)&UID_GIBC_DEFAULT_USER, &pIdentity)))
|
|
goto exit;
|
|
|
|
Assert(pIdentity);
|
|
|
|
// Ensure that we have an identity and can get to its registry
|
|
if (FAILED(pIdentity->OpenIdentityRegKey(KEY_WRITE, &hkeyID)))
|
|
goto exit;
|
|
|
|
Assert(hkeyID);
|
|
|
|
// Open the HKCU
|
|
if (ERROR_SUCCESS != RegOpenKeyEx(hkeyID, "Software\\Microsoft\\Outlook Express\\5.0", 0, KEY_ALL_ACCESS, &hKey))
|
|
{
|
|
hr = TraceResult(MIGRATE_E_REGOPENKEY);
|
|
goto exit;
|
|
}
|
|
|
|
// Write it to the registry
|
|
if (ERROR_SUCCESS != RegSetValueEx(hKey, "FolderIdChange", 0, REG_BINARY, pbChange, cbLength))
|
|
{
|
|
hr = TraceResult(MIGRATE_E_REGSETVALUE);
|
|
goto exit;
|
|
}
|
|
}
|
|
|
|
exit:
|
|
// Cleanup
|
|
if (hKey)
|
|
RegCloseKey(hKey);
|
|
if (hkeyID)
|
|
RegCloseKey(hkeyID);
|
|
SafeMemFree(pbChange);
|
|
SafeMemFree(prgFolder);
|
|
SafeRelease(pIdentity);
|
|
SafeRelease(pManager);
|
|
|
|
CloseMemoryFile(&File);
|
|
|
|
// Done
|
|
return(hr);
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// MergeNewsGroupList
|
|
// --------------------------------------------------------------------------------
|
|
HRESULT MergeNewsGroupList(IDatabaseSession *pSession, IMessageStore *pStore,
|
|
LPFILEINFO pInfo, LPFILEINFO pHeadFile, LPPROGRESSINFO pProgress)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
DWORD i;
|
|
FOLDERINFO Folder={0};
|
|
MEMORYFILE File={0};
|
|
FOLDERID idServer;
|
|
DWORD cbRead;
|
|
LPSTR pszT;
|
|
LPSTR pszGroup;
|
|
LPSTR pszDescription;
|
|
FOLDERID idFolder;
|
|
LPFILEINFO pSubList=NULL;
|
|
LPFILEINFO pCurrent;
|
|
LPSUBLISTHEADER pSubListHeader;
|
|
IDatabase *pDB=NULL;
|
|
CHAR szPath[_MAX_PATH];
|
|
CHAR szDrive[_MAX_DRIVE];
|
|
CHAR szDir[_MAX_DIR];
|
|
CHAR szFile[_MAX_FNAME];
|
|
CHAR szExt[_MAX_EXT];
|
|
LPGRPLISTHEADER pHeader;
|
|
|
|
// Trace
|
|
TraceCall("MergeNewsGroupList");
|
|
|
|
// Find the Server Id
|
|
if (FAILED(pStore->FindServerId(pInfo->szAcctId, &idServer)))
|
|
goto exit;
|
|
|
|
// Set Progress File
|
|
SetProgressFile(pProgress, pInfo);
|
|
|
|
// Open the Group List File
|
|
IF_FAILEXIT(hr = OpenMemoryFile(pInfo->szFilePath, &File));
|
|
|
|
// Get the Header
|
|
pHeader = (LPGRPLISTHEADER)File.pView;
|
|
|
|
// Initialize cb
|
|
cbRead = sizeof(GRPLISTHEADER);
|
|
|
|
// Loop
|
|
for (i=0; i<pHeader->cGroups; i++)
|
|
{
|
|
// Set pszGroup
|
|
pszT = pszGroup = (LPSTR)((LPBYTE)File.pView + cbRead);
|
|
|
|
// Increment to end of pszGroup or end of file
|
|
while (*pszT && cbRead < File.cbSize)
|
|
{
|
|
// Increment cb
|
|
cbRead++;
|
|
|
|
// End of String
|
|
pszT = (LPSTR)((LPBYTE)File.pView + cbRead);
|
|
}
|
|
|
|
// Done
|
|
if (cbRead >= File.cbSize)
|
|
break;
|
|
|
|
// Step Over the Null
|
|
cbRead++;
|
|
|
|
// Set pszDescription
|
|
pszT = pszDescription = (LPSTR)((LPBYTE)File.pView + cbRead);
|
|
|
|
// Increment to end of pszGroup or end of file
|
|
while (*pszT && cbRead < File.cbSize)
|
|
{
|
|
// Increment cb
|
|
cbRead++;
|
|
|
|
// End of String
|
|
pszT = (LPSTR)((LPBYTE)File.pView + cbRead);
|
|
}
|
|
|
|
// Done
|
|
if (cbRead >= File.cbSize)
|
|
break;
|
|
|
|
// Increment over the null
|
|
cbRead++;
|
|
|
|
// Step over group type
|
|
cbRead += sizeof(DWORD);
|
|
|
|
// Not Empyt
|
|
if ('\0' == *pszGroup)
|
|
break;
|
|
|
|
// Set the Folder Info
|
|
Folder.pszName = pszGroup;
|
|
Folder.pszDescription = pszDescription;
|
|
Folder.idParent = idServer;
|
|
Folder.tySpecial = FOLDER_NOTSPECIAL;
|
|
|
|
// Create the Folder
|
|
pStore->CreateFolder(0, &Folder, NOSTORECALLBACK);
|
|
|
|
// Bump Progress
|
|
if(!g_fQuiet)
|
|
IncrementProgress(pProgress, pInfo);
|
|
}
|
|
|
|
// Walk through news message files and create folders for them.
|
|
for (pCurrent=pHeadFile; pCurrent!=NULL; pCurrent=pCurrent->pNext)
|
|
{
|
|
// Find the Sublist for this group
|
|
if (FILE_IS_NEWS_SUBLIST == pCurrent->tyFile && lstrcmpi(pCurrent->szAcctId, pInfo->szAcctId) == 0)
|
|
{
|
|
// Set pSubList
|
|
pSubList = pCurrent;
|
|
|
|
// Done
|
|
break;
|
|
}
|
|
}
|
|
|
|
// No Sub List
|
|
if (NULL == pSubList)
|
|
goto exit;
|
|
|
|
// Close the File
|
|
CloseMemoryFile(&File);
|
|
|
|
// Set Progress File
|
|
SetProgressFile(pProgress, pSubList);
|
|
|
|
// Open the Group List File
|
|
IF_FAILEXIT(hr = OpenMemoryFile(pSubList->szFilePath, &File));
|
|
|
|
// De-Ref the header
|
|
pSubListHeader = (LPSUBLISTHEADER)File.pView;
|
|
|
|
// SUBFILE_VERSION5
|
|
if (SUBFILE_VERSION5 == pSubListHeader->dwVersion)
|
|
{
|
|
// Locals
|
|
PGROUPSTATUS5 pStatus;
|
|
DWORD cbRead;
|
|
|
|
// Initialize cbRead
|
|
cbRead = sizeof(SUBLISTHEADER) + sizeof(DWORD);
|
|
|
|
// PGROUPSTATUS5
|
|
for (i=0; i<pSubListHeader->cSubscribed; i++)
|
|
{
|
|
// De-Ref the Group Status
|
|
pStatus = (PGROUPSTATUS5)((LPBYTE)File.pView + cbRead);
|
|
|
|
// Increment cbRead
|
|
cbRead += sizeof(GROUPSTATUS5);
|
|
|
|
// Read the Name
|
|
pszGroup = (LPSTR)((LPBYTE)File.pView + cbRead);
|
|
|
|
// Increment cbRead
|
|
cbRead += pStatus->cbName + pStatus->cbReadRange + pStatus->cbKnownRange + pStatus->cbMarkedRange + pStatus->cbRequestedRange;
|
|
|
|
// Find The Folder...
|
|
Folder.idParent = idServer;
|
|
Folder.pszName = pszGroup;
|
|
|
|
// Try to find this folder
|
|
if (DB_S_FOUND == pStore->FindRecord(IINDEX_ALL, COLUMNS_ALL, &Folder, NULL))
|
|
{
|
|
// Locals
|
|
CHAR szSrcFile[MAX_PATH];
|
|
|
|
// Subscribe to It
|
|
if (ISFLAGSET(pStatus->dwFlags, GSF_SUBSCRIBED))
|
|
{
|
|
// Its SubScribed
|
|
FLAGSET(Folder.dwFlags, FOLDER_SUBSCRIBED);
|
|
}
|
|
|
|
// Format the original file name
|
|
wnsprintf(szSrcFile, ARRAYSIZE(szSrcFile), "%08x", pStatus->dwCacheFileIndex);
|
|
|
|
// Try to find the folder in the list of files
|
|
for (pCurrent=pHeadFile; pCurrent!=NULL; pCurrent=pCurrent->pNext)
|
|
{
|
|
// Find the Sublist for this group
|
|
if (pCurrent->fMigrate && FILE_IS_NEWS_MESSAGES == pCurrent->tyFile && lstrcmpi(pCurrent->szAcctId, pInfo->szAcctId) == 0)
|
|
{
|
|
// Get the File Name
|
|
_splitpath(pCurrent->szFilePath, szDrive, szDir, szFile, szExt);
|
|
|
|
// Correct file name
|
|
if (lstrcmpi(szFile, szSrcFile) == 0)
|
|
{
|
|
// Get the File Name
|
|
_splitpath(pCurrent->szDstFile, szDrive, szDir, szFile, szExt);
|
|
|
|
// Format the original file name
|
|
wnsprintf(szSrcFile, ARRAYSIZE(szSrcFile), "%s%s", szFile, szExt);
|
|
|
|
// Set the File Path
|
|
Folder.pszFile = szSrcFile;
|
|
|
|
// Set Folder Counts
|
|
Folder.cMessages = pCurrent->cMessages;
|
|
Folder.cUnread = pCurrent->cUnread;
|
|
|
|
// FixupFolderUserData(
|
|
FixupFolderUserData(pSession, Folder.idFolder, pszGroup, FOLDER_NOTSPECIAL, pCurrent);
|
|
|
|
// Done
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Update the Record
|
|
pStore->UpdateRecord(&Folder);
|
|
|
|
// Free This
|
|
pStore->FreeRecord(&Folder);
|
|
}
|
|
|
|
// Bump Progress
|
|
if(!g_fQuiet)
|
|
IncrementProgress(pProgress, pSubList);
|
|
}
|
|
}
|
|
|
|
// SUBFILE_VERSION4
|
|
else if (SUBFILE_VERSION4 == pSubListHeader->dwVersion)
|
|
{
|
|
// Locals
|
|
PGROUPSTATUS4 pStatus;
|
|
DWORD cbRead;
|
|
|
|
// Initialize cbRead
|
|
cbRead = sizeof(SUBLISTHEADER);
|
|
|
|
// PGROUPSTATUS5
|
|
for (i=0; i<pSubListHeader->cSubscribed; i++)
|
|
{
|
|
// De-Ref the Group Status
|
|
pStatus = (PGROUPSTATUS4)((LPBYTE)File.pView + cbRead);
|
|
|
|
// Increment cbRead
|
|
cbRead += sizeof(GROUPSTATUS4);
|
|
|
|
// Read the Name
|
|
pszGroup = (LPSTR)((LPBYTE)File.pView + cbRead);
|
|
|
|
// Increment cbRead
|
|
cbRead += pStatus->cbName + pStatus->cbReadRange + pStatus->cbKnownRange + pStatus->cbMarkedRange + pStatus->cbRequestedRange;
|
|
|
|
// Find The Folder...
|
|
Folder.idParent = idServer;
|
|
Folder.pszName = pszGroup;
|
|
|
|
// Try to find this folder
|
|
if (DB_S_FOUND == pStore->FindRecord(IINDEX_ALL, COLUMNS_ALL, &Folder, NULL))
|
|
{
|
|
// Locals
|
|
CHAR szSrcFile[MAX_PATH];
|
|
|
|
// Subscribe to It
|
|
if (ISFLAGSET(pStatus->dwFlags, GSF_SUBSCRIBED))
|
|
{
|
|
// Its SubScribed
|
|
FLAGSET(Folder.dwFlags, FOLDER_SUBSCRIBED);
|
|
}
|
|
|
|
// Try to find the folder in the list of files
|
|
for (pCurrent=pHeadFile; pCurrent!=NULL; pCurrent=pCurrent->pNext)
|
|
{
|
|
// Find the Sublist for this group
|
|
if (pCurrent->fMigrate && FILE_IS_NEWS_MESSAGES == pCurrent->tyFile && lstrcmpi(pCurrent->szAcctId, pInfo->szAcctId) == 0)
|
|
{
|
|
// Correct file name
|
|
if (lstrcmpi(pszGroup, pCurrent->szFolder) == 0)
|
|
{
|
|
// Get the File Name
|
|
_splitpath(pCurrent->szDstFile, szDrive, szDir, szFile, szExt);
|
|
|
|
// Format the original file name
|
|
wnsprintf(szSrcFile, ARRAYSIZE(szSrcFile), "%s%s", szFile, szExt);
|
|
|
|
// Set the File Path
|
|
Folder.pszFile = szSrcFile;
|
|
|
|
// Set Folder Counts
|
|
Folder.cMessages = pCurrent->cMessages;
|
|
Folder.cUnread = pCurrent->cUnread;
|
|
|
|
// FixupFolderUserData(
|
|
FixupFolderUserData(pSession, Folder.idFolder, pszGroup, FOLDER_NOTSPECIAL, pCurrent);
|
|
|
|
// Done
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Update the Record
|
|
pStore->UpdateRecord(&Folder);
|
|
|
|
// Free This
|
|
pStore->FreeRecord(&Folder);
|
|
}
|
|
|
|
// Bump Progress
|
|
if(!g_fQuiet)
|
|
IncrementProgress(pProgress, pSubList);
|
|
}
|
|
}
|
|
|
|
// SUBFILE_VERSION3
|
|
else if (SUBFILE_VERSION3 == pSubListHeader->dwVersion)
|
|
{
|
|
Assert(FALSE);
|
|
}
|
|
|
|
// SUBFILE_VERSION2
|
|
else if (SUBFILE_VERSION2 == pSubListHeader->dwVersion)
|
|
{
|
|
Assert(FALSE);
|
|
}
|
|
|
|
exit:
|
|
// Close the File
|
|
CloseMemoryFile(&File);
|
|
|
|
// Done
|
|
return(hr);
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// BuildUnifiedFolderManager
|
|
// --------------------------------------------------------------------------------
|
|
HRESULT BuildUnifiedFolderManager(IDatabaseSession *pSession, IMessageStore *pStore,
|
|
LPFILEINFO pHeadFile, LPPROGRESSINFO pProgress)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
LPFILEINFO pCurrent;
|
|
|
|
// Trace
|
|
TraceCall("BuildUnifiedFolderManager");
|
|
|
|
// Walk through the list of files and merge the folders, sublist, group lists into pFolder
|
|
for (pCurrent=pHeadFile; pCurrent!=NULL; pCurrent=pCurrent->pNext)
|
|
{
|
|
// Handle Folders Type
|
|
if (FILE_IS_LOCAL_FOLDERS == pCurrent->tyFile)
|
|
{
|
|
// Merge Local Folder Cache into new Folder Manager
|
|
IF_FAILEXIT(hr = MergeFolderCacheIntoStore(pSession, pStore, pCurrent, pHeadFile, pProgress));
|
|
}
|
|
|
|
// IMAP Folder
|
|
else if (FILE_IS_IMAP_FOLDERS == pCurrent->tyFile)
|
|
{
|
|
// Merge IMAP Folder Cache into new Folder Manager
|
|
IF_FAILEXIT(hr = MergeFolderCacheIntoStore(pSession, pStore, pCurrent, pHeadFile, pProgress));
|
|
}
|
|
|
|
// News Group List
|
|
else if (FILE_IS_NEWS_GRPLIST == pCurrent->tyFile)
|
|
{
|
|
// Merge IMAP Folder Cache into new Folder Manager
|
|
IF_FAILEXIT(hr = MergeNewsGroupList(pSession, pStore, pCurrent, pHeadFile, pProgress));
|
|
}
|
|
}
|
|
|
|
// Walk through any files that were not merged into the store
|
|
for (pCurrent=pHeadFile; pCurrent!=NULL; pCurrent=pCurrent->pNext)
|
|
{
|
|
// Find the Sublist for this group
|
|
if (TRUE == pCurrent->fMigrate && FALSE == pCurrent->fInStore)
|
|
{
|
|
// Local Message File...
|
|
if (FILE_IS_LOCAL_MESSAGES == pCurrent->tyFile)
|
|
{
|
|
// Locals
|
|
FLDINFO Folder={0};
|
|
SPECIALFOLDER tySpecial;
|
|
CHAR szFolder[255];
|
|
CHAR szPath[_MAX_PATH];
|
|
CHAR szDrive[_MAX_DRIVE];
|
|
CHAR szDir[_MAX_DIR];
|
|
CHAR szFile[_MAX_FNAME];
|
|
CHAR szExt[_MAX_EXT];
|
|
|
|
// Get Special Folder Info
|
|
GetSpecialFolderInfo(pCurrent->szFilePath, szFolder, ARRAYSIZE(szFolder), &Folder.tySpecial);
|
|
|
|
// Special Case for News Special Folders from v1
|
|
if (0xffffffff == Folder.tySpecial && strstr(szFolder, "special folders") != NULL)
|
|
{
|
|
// Locals
|
|
CHAR szRes[255];
|
|
|
|
// News Outbox
|
|
LoadString(g_hInst, IDS_POSTEDITEMS, szRes, ARRAYSIZE(szRes));
|
|
|
|
// Contains "Posted Items"
|
|
if (strstr(szFolder, szRes) != NULL)
|
|
LoadString(g_hInst, IDS_NEWSPOSTED, szFolder, ARRAYSIZE(szFolder));
|
|
|
|
// Contains "Saved Items"
|
|
else
|
|
{
|
|
// News Saved Items
|
|
LoadString(g_hInst, IDS_SAVEDITEMS, szRes, ARRAYSIZE(szRes));
|
|
|
|
// Contains "Saved Items"
|
|
if (strstr(szFolder, szRes) != NULL)
|
|
LoadString(g_hInst, IDS_NEWSSAVED, szFolder, ARRAYSIZE(szFolder));
|
|
|
|
// Otherwise
|
|
else
|
|
{
|
|
// News Outbox
|
|
LoadString(g_hInst, IDS_OUTBOX, szRes, ARRAYSIZE(szRes));
|
|
|
|
// Contains Outbox
|
|
if (strstr(szFolder, szRes) != NULL)
|
|
LoadString(g_hInst, IDS_NEWSOUTBOX, szFolder, ARRAYSIZE(szFolder));
|
|
}
|
|
}
|
|
}
|
|
|
|
// Compute the File Name
|
|
_splitpath(pCurrent->szDstFile, szDrive, szDir, szFile, szExt);
|
|
wnsprintf(Folder.szFile, ARRAYSIZE(Folder.szFile), "%s.dbx", szFile);
|
|
|
|
// Set the Name
|
|
if ('\0' != *pCurrent->szFolder)
|
|
StrCpyN(Folder.szFolder, pCurrent->szFolder, ARRAYSIZE(Folder.szFolder));
|
|
else if ('\0' != *szFolder)
|
|
StrCpyN(Folder.szFolder, szFolder, ARRAYSIZE(Folder.szFolder));
|
|
else
|
|
StrCpyN(Folder.szFolder, szFile, ARRAYSIZE(Folder.szFolder));
|
|
|
|
// Set Message and Unread Count
|
|
Folder.cMessages = pCurrent->cMessages;
|
|
Folder.cUnread = pCurrent->cUnread;
|
|
|
|
// Insert into Local Store
|
|
InsertFolderIntoStore(pSession, pStore, &Folder, 0, NULL, FOLDERID_LOCAL_STORE, NULL, NULL, (LPFOLDERID)&Folder.idFolder);
|
|
|
|
// Fixup special
|
|
tySpecial = (Folder.tySpecial == 0xffffffff) ? FOLDER_NOTSPECIAL : (BYTE)(Folder.tySpecial + 1);
|
|
|
|
// Update the Folder's UserData
|
|
FixupFolderUserData(pSession, (FOLDERID)IntToPtr(Folder.idFolder), Folder.szFolder, tySpecial, pCurrent);
|
|
}
|
|
|
|
// Otherwise, just delete the file
|
|
else if (FILE_IS_POP3UIDL != pCurrent->tyFile)
|
|
DeleteFile(pCurrent->szDstFile);
|
|
}
|
|
}
|
|
|
|
exit:
|
|
// Done
|
|
return(hr);
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CleanupMessageStore
|
|
// --------------------------------------------------------------------------------
|
|
HRESULT CleanupMessageStore(LPCSTR pszStoreRoot, IMessageStore *pStore)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
FOLDERINFO Folder={0};
|
|
HROWSET hRowset=NULL;
|
|
CHAR szFilePath[MAX_PATH + MAX_PATH];
|
|
|
|
// Trace
|
|
TraceCall("CleanupMessageStore");
|
|
|
|
// Create a Rowset
|
|
IF_FAILEXIT(hr = pStore->CreateRowset(IINDEX_PRIMARY, 0, &hRowset));
|
|
|
|
// Walk the Rowset
|
|
while(S_OK == pStore->QueryRowset(hRowset, 1, (LPVOID *)&Folder, NULL))
|
|
{
|
|
// If it has a file and no messags.
|
|
if (Folder.pszFile && 0 == Folder.cMessages)
|
|
{
|
|
// Delete the file...
|
|
IF_FAILEXIT(hr = MakeFilePath(pszStoreRoot, Folder.pszFile, "", szFilePath, ARRAYSIZE(szFilePath)));
|
|
|
|
// Delete the File
|
|
DeleteFile(szFilePath);
|
|
|
|
// Reset the filename
|
|
Folder.pszFile = NULL;
|
|
|
|
// Update the Record
|
|
IF_FAILEXIT(hr = pStore->UpdateRecord(&Folder));
|
|
}
|
|
|
|
// Otherwise, if there is a file, force a folder rename
|
|
else if (Folder.pszFile)
|
|
{
|
|
// Rename the folder
|
|
pStore->RenameFolder(Folder.idFolder, Folder.pszName, 0, NULL);
|
|
}
|
|
|
|
// Cleanup
|
|
pStore->FreeRecord(&Folder);
|
|
}
|
|
|
|
exit:
|
|
// Cleanup
|
|
pStore->FreeRecord(&Folder);
|
|
pStore->CloseRowset(&hRowset);
|
|
|
|
// Done
|
|
return(hr);
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// UpgradeV5
|
|
// --------------------------------------------------------------------------------
|
|
HRESULT UpgradeV5(MIGRATETOTYPE tyMigrate, LPCSTR pszStoreSrc, LPCSTR pszStoreDst,
|
|
LPPROGRESSINFO pProgress, LPFILEINFO *ppHeadFile)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
ENUMFILEINFO EnumInfo;
|
|
LPFILEINFO pCurrent;
|
|
DWORD cbNeeded;
|
|
DWORDLONG dwlFree;
|
|
BOOL fContinue;
|
|
CHAR szFolders[MAX_PATH + MAX_PATH];
|
|
CHAR szMsg[512];
|
|
IMessageStore *pStore=NULL;
|
|
IDatabaseSession *pSession=NULL;
|
|
|
|
// Trace
|
|
TraceCall("UpgradeV5");
|
|
|
|
// Initialize
|
|
*ppHeadFile = NULL;
|
|
|
|
// Setup the EnumFile Info
|
|
ZeroMemory(&EnumInfo, sizeof(ENUMFILEINFO));
|
|
EnumInfo.pszExt = ".nch";
|
|
EnumInfo.pszFoldFile = "folders.nch";
|
|
EnumInfo.pszUidlFile = "pop3uidl.dat";
|
|
EnumInfo.pszSubList = "sublist.dat";
|
|
EnumInfo.pszGrpList = "grplist.dat";
|
|
EnumInfo.fFindV1News = TRUE;
|
|
|
|
// Enumerate All ODB files in szStoreRoot...
|
|
IF_FAILEXIT(hr = EnumerateStoreFiles(pszStoreSrc, DIR_IS_ROOT, NULL, &EnumInfo, ppHeadFile));
|
|
|
|
// Setup the EnumFile Info
|
|
ZeroMemory(&EnumInfo, sizeof(ENUMFILEINFO));
|
|
EnumInfo.pszExt = ".mbx";
|
|
EnumInfo.pszFoldFile = NULL;
|
|
EnumInfo.pszUidlFile = NULL;
|
|
|
|
// Enumerate All ODB files in szStoreRoot...
|
|
IF_FAILEXIT(hr = EnumerateStoreFiles(pszStoreSrc, DIR_IS_ROOT, NULL, &EnumInfo, ppHeadFile));
|
|
|
|
// Nothing to upgrade
|
|
if (NULL == *ppHeadFile)
|
|
goto exit;
|
|
|
|
// Compute some Counts, and validate that the files are valid to migrate...
|
|
IF_FAILEXIT(hr = UpgradeProcessFileListV5(pszStoreSrc, pszStoreDst, *ppHeadFile, &pProgress->cMax, &cbNeeded));
|
|
|
|
// Message
|
|
LoadString(g_hInst, IDS_UPGRADEMESSAGE, szMsg, ARRAYSIZE(szMsg));
|
|
|
|
// Message
|
|
if(!g_fQuiet)
|
|
MigrateMessageBox(szMsg, MB_OK | MB_ICONINFORMATION | MB_SETFOREGROUND);
|
|
|
|
// Delete fles
|
|
UpgradeDeleteFilesV5(pszStoreDst);
|
|
|
|
// Create an Ojbect Database
|
|
IF_FAILEXIT(hr = CoCreateInstance(CLSID_DatabaseSession, NULL, CLSCTX_INPROC_SERVER, IID_IDatabaseSession, (LPVOID *)&pSession));
|
|
|
|
// Create an Ojbect Database
|
|
IF_FAILEXIT(hr = CoCreateInstance(CLSID_MigrateMessageStore, NULL, CLSCTX_INPROC_SERVER, IID_IMessageStore, (LPVOID *)&pStore));
|
|
|
|
// Build the Folders.odb File Path
|
|
wnsprintf(szFolders, ARRAYSIZE(szFolders), "%s\\folders.dbx", pszStoreDst);
|
|
|
|
// Delete It First
|
|
DeleteFile(szFolders);
|
|
|
|
// Initialize the Store
|
|
IF_FAILEXIT(hr = pStore->Initialize(pszStoreDst));
|
|
|
|
// Initialize the Store
|
|
IF_FAILEXIT(hr = pStore->Validate(0));
|
|
|
|
// Enought DiskSpace ?
|
|
IF_FAILEXIT(hr = GetAvailableDiskSpace(pszStoreDst, &dwlFree));
|
|
|
|
// Not Enought Diskspace
|
|
if (((DWORDLONG) cbNeeded) > dwlFree)
|
|
{
|
|
// cbNeeded is DWORD and in this case we can downgrade dwlFree to DWORD
|
|
g_cbDiskNeeded = cbNeeded; g_cbDiskFree = ((DWORD) dwlFree);
|
|
hr = TraceResult(MIGRATE_E_NOTENOUGHDISKSPACE);
|
|
goto exit;
|
|
}
|
|
|
|
// Loop through the files and migrate each one
|
|
for (pCurrent=*ppHeadFile; pCurrent!=NULL; pCurrent=pCurrent->pNext)
|
|
{
|
|
// Migrate this file ?
|
|
if (pCurrent->fMigrate)
|
|
{
|
|
// Set Progress File
|
|
SetProgressFile(pProgress, pCurrent);
|
|
|
|
// Assume we will continue
|
|
fContinue = FALSE;
|
|
|
|
// Downgrade the file
|
|
hr = pCurrent->hrMigrate = UpgradeFileV5(pSession, tyMigrate, pCurrent, pProgress, &fContinue);
|
|
|
|
// Failure ?
|
|
if (FAILED(pCurrent->hrMigrate))
|
|
{
|
|
// Set Last Error
|
|
pCurrent->dwLastError = GetLastError();
|
|
|
|
// Stop
|
|
if (FALSE == fContinue)
|
|
break;
|
|
|
|
if(!g_fQuiet) {
|
|
// Fixup the progress
|
|
while (pCurrent->cProgCur < pCurrent->cProgMax)
|
|
{
|
|
IncrementProgress(pProgress, pCurrent);
|
|
}
|
|
}
|
|
|
|
// We are ok
|
|
hr = S_OK;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Process Folder Lists
|
|
hr = BuildUnifiedFolderManager(pSession, pStore, *ppHeadFile, pProgress);
|
|
|
|
// Failure, delete all destination files
|
|
if (FAILED(hr))
|
|
{
|
|
// Delete fles
|
|
UpgradeDeleteFilesV5(pszStoreDst);
|
|
}
|
|
|
|
// Otherwise, lets force a folder rename to build friendly file names
|
|
else
|
|
{
|
|
// Rename all the folders...
|
|
CleanupMessageStore(pszStoreDst, pStore);
|
|
}
|
|
|
|
#if 0
|
|
// Otherwise, delete source files
|
|
else
|
|
{
|
|
// Delete all source files
|
|
UpgradeDeleteIdxMbxNchDatFilesV5(*ppHeadFile);
|
|
}
|
|
#endif
|
|
|
|
exit:
|
|
// Cleanup
|
|
SafeRelease(pStore);
|
|
|
|
// Done
|
|
return hr;
|
|
}
|