You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1136 lines
37 KiB
1136 lines
37 KiB
// --------------------------------------------------------------------------------
|
|
// DownOE5.cpp
|
|
// --------------------------------------------------------------------------------
|
|
#include "pch.hxx"
|
|
#include "utility.h"
|
|
#include "migrate.h"
|
|
#include "migerror.h"
|
|
#include "structs.h"
|
|
#include "resource.h"
|
|
#include <oestore.h>
|
|
#include <mimeole.h>
|
|
|
|
const static BYTE rgbZero[4] = {0};
|
|
|
|
//--------------------------------------------------------------------------
|
|
// PFNREADTYPEDATA
|
|
//--------------------------------------------------------------------------
|
|
typedef void (APIENTRY *PFNREADTYPEDATA)(LPBYTE pbSource, DWORD cbLength,
|
|
LPCTABLECOLUMN pColumn, LPVOID pRecord, LPDWORD pcPtrRefs);
|
|
|
|
//--------------------------------------------------------------------------
|
|
// g_rgpfnReadTypeData
|
|
//--------------------------------------------------------------------------
|
|
extern const PFNREADTYPEDATA g_rgpfnReadTypeData[CDT_LASTTYPE];
|
|
|
|
//--------------------------------------------------------------------------
|
|
// ReadTypeData
|
|
//--------------------------------------------------------------------------
|
|
#define ReadTypeData(_pbSource, _cbLength, _pColumn, _pRecord, _pcPtrRefs) \
|
|
(*(g_rgpfnReadTypeData[(_pColumn)->type]))(_pbSource, _cbLength, (_pColumn), _pRecord, _pcPtrRefs)
|
|
|
|
//--------------------------------------------------------------------------
|
|
inline void ReadTypeDataFILETIME(LPBYTE pbSource, DWORD cbLength,
|
|
LPCTABLECOLUMN pColumn, LPVOID pRecord, LPDWORD pcPtrRefs)
|
|
{
|
|
Assert(cbLength == sizeof(FILETIME));
|
|
CopyMemory((LPBYTE)pRecord + pColumn->ofBinding, pbSource, sizeof(FILETIME));
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
inline void ReadTypeDataFIXSTRA(LPBYTE pbSource, DWORD cbLength,
|
|
LPCTABLECOLUMN pColumn, LPVOID pRecord, LPDWORD pcPtrRefs)
|
|
{
|
|
Assert(cbLength == pColumn->cbSize);
|
|
CopyMemory((LPBYTE)pRecord + pColumn->ofBinding, pbSource, pColumn->cbSize);
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
inline void ReadTypeDataVARSTRA(LPBYTE pbSource, DWORD cbLength,
|
|
LPCTABLECOLUMN pColumn, LPVOID pRecord, LPDWORD pcPtrRefs)
|
|
{
|
|
Assert((LPSTR)((LPBYTE)pbSource)[cbLength - 1] == '\0');
|
|
*((LPSTR *)((LPBYTE)pRecord + pColumn->ofBinding)) = (LPSTR)((LPBYTE)pbSource);
|
|
(*pcPtrRefs)++;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
inline void ReadTypeDataBYTE(LPBYTE pbSource, DWORD cbLength,
|
|
LPCTABLECOLUMN pColumn, LPVOID pRecord, LPDWORD pcPtrRefs)
|
|
{
|
|
Assert(cbLength == sizeof(BYTE));
|
|
CopyMemory((LPBYTE)pRecord + pColumn->ofBinding, pbSource, sizeof(BYTE));
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
inline void ReadTypeDataDWORD(LPBYTE pbSource, DWORD cbLength,
|
|
LPCTABLECOLUMN pColumn, LPVOID pRecord, LPDWORD pcPtrRefs)
|
|
{
|
|
Assert(cbLength == sizeof(DWORD));
|
|
CopyMemory((LPBYTE)pRecord + pColumn->ofBinding, pbSource, sizeof(DWORD));
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
inline void ReadTypeDataWORD(LPBYTE pbSource, DWORD cbLength,
|
|
LPCTABLECOLUMN pColumn, LPVOID pRecord, LPDWORD pcPtrRefs)
|
|
{
|
|
Assert(cbLength == sizeof(WORD));
|
|
CopyMemory((LPBYTE)pRecord + pColumn->ofBinding, pbSource, sizeof(WORD));
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
inline void ReadTypeDataSTREAM(LPBYTE pbSource, DWORD cbLength,
|
|
LPCTABLECOLUMN pColumn, LPVOID pRecord, LPDWORD pcPtrRefs)
|
|
{
|
|
Assert(cbLength == sizeof(FILEADDRESS));
|
|
CopyMemory((LPBYTE)pRecord + pColumn->ofBinding, pbSource, sizeof(FILEADDRESS));
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
inline void ReadTypeDataVARBLOB(LPBYTE pbSource, DWORD cbLength,
|
|
LPCTABLECOLUMN pColumn, LPVOID pRecord, LPDWORD pcPtrRefs)
|
|
{
|
|
LPBLOB pBlob = (LPBLOB)((LPBYTE)pRecord + pColumn->ofBinding);
|
|
pBlob->cbSize = cbLength;
|
|
if (pBlob->cbSize > 0)
|
|
{
|
|
pBlob->pBlobData = pbSource;
|
|
(*pcPtrRefs)++;
|
|
}
|
|
else
|
|
pBlob->pBlobData = NULL;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
inline void ReadTypeDataFIXBLOB(LPBYTE pbSource, DWORD cbLength,
|
|
LPCTABLECOLUMN pColumn, LPVOID pRecord, LPDWORD pcPtrRefs)
|
|
{
|
|
Assert(pColumn->cbSize == cbLength);
|
|
CopyMemory((LPBYTE)pRecord + pColumn->ofBinding, pbSource, pColumn->cbSize);
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
const PFNREADTYPEDATA g_rgpfnReadTypeData[CDT_LASTTYPE] = {
|
|
(PFNREADTYPEDATA)ReadTypeDataFILETIME,
|
|
(PFNREADTYPEDATA)ReadTypeDataFIXSTRA,
|
|
(PFNREADTYPEDATA)ReadTypeDataVARSTRA,
|
|
(PFNREADTYPEDATA)ReadTypeDataBYTE,
|
|
(PFNREADTYPEDATA)ReadTypeDataDWORD,
|
|
(PFNREADTYPEDATA)ReadTypeDataWORD,
|
|
(PFNREADTYPEDATA)ReadTypeDataSTREAM,
|
|
(PFNREADTYPEDATA)ReadTypeDataVARBLOB,
|
|
(PFNREADTYPEDATA)ReadTypeDataFIXBLOB
|
|
};
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// DowngradeReadMsgInfoV5
|
|
// --------------------------------------------------------------------------------
|
|
HRESULT DowngradeReadMsgInfoV5(LPRECORDBLOCKV5 pRecord, LPMESSAGEINFO pMsgInfo)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
DWORD i;
|
|
DWORD cColumns;
|
|
DWORD cbRead=0;
|
|
DWORD cbLength;
|
|
DWORD cbData;
|
|
DWORD cPtrRefs;
|
|
LPBYTE pbData;
|
|
LPBYTE pbSource;
|
|
LPDWORD prgdwOffset=(LPDWORD)((LPBYTE)pRecord + sizeof(RECORDBLOCKV5));
|
|
|
|
// Trace
|
|
TraceCall("DowngradeReadMsgInfoV5");
|
|
|
|
// Set cbData
|
|
cbData = (pRecord->cbRecord - sizeof(RECORDBLOCKV5) - (pRecord->cColumns * sizeof(DWORD)));
|
|
|
|
// Allocate
|
|
IF_NULLEXIT(pbData = (LPBYTE)g_pMalloc->Alloc(cbData));
|
|
|
|
// Free This
|
|
pMsgInfo->pvMemory = pbData;
|
|
|
|
// Set pbData
|
|
pbSource = (LPBYTE)((LPBYTE)pRecord + sizeof(RECORDBLOCKV5) + (pRecord->cColumns * sizeof(DWORD)));
|
|
|
|
// Copy the data
|
|
CopyMemory(pbData, pbSource, cbData);
|
|
|
|
// Compute number of columns to read
|
|
cColumns = min(pRecord->cColumns, MSGCOL_LASTID);
|
|
|
|
// Read the Record
|
|
for (i=0; i<cColumns; i++)
|
|
{
|
|
// Compute cbLength
|
|
cbLength = (i + 1 == cColumns) ? (cbData - prgdwOffset[i]) : (prgdwOffset[i + 1] - prgdwOffset[i]);
|
|
|
|
// Bad-Record
|
|
if (prgdwOffset[i] != cbRead || cbRead + cbLength > cbData)
|
|
{
|
|
hr = TraceResult(MIGRATE_E_BADRECORDFORMAT);
|
|
goto exit;
|
|
}
|
|
|
|
// ReadTypeData
|
|
ReadTypeData(pbData + cbRead, cbLength, &g_MessageTableSchema.prgColumn[i], pMsgInfo, &cPtrRefs);
|
|
|
|
// Increment cbRead
|
|
cbRead += cbLength;
|
|
}
|
|
|
|
exit:
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// DowngradeLocalStoreFileV5
|
|
// --------------------------------------------------------------------------------
|
|
HRESULT DowngradeLocalStoreFileV5(MIGRATETOTYPE tyMigrate, LPFILEINFO pInfo,
|
|
LPMEMORYFILE pFile, LPPROGRESSINFO pProgress)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
DWORD cRecords=0;
|
|
CHAR szIdxPath[MAX_PATH + MAX_PATH];
|
|
CHAR szMbxPath[MAX_PATH + MAX_PATH];
|
|
HANDLE hIdxFile=NULL;
|
|
HANDLE hMbxFile=NULL;
|
|
MESSAGEINFO MsgInfo={0};
|
|
IDXFILEHEADER IdxHeader;
|
|
MBXFILEHEADER MbxHeader;
|
|
MBXMESSAGEHEADER MbxMessage;
|
|
IDXMESSAGEHEADER IdxMessage;
|
|
LPRECORDBLOCKV5 pRecord;
|
|
LPSTREAMBLOCK pStmBlock;
|
|
LPBYTE pbData;
|
|
DWORD faRecord;
|
|
DWORD faIdxWrite;
|
|
DWORD faMbxWrite;
|
|
DWORD faStreamBlock;
|
|
DWORD cbAligned;
|
|
DWORD faMbxCurrent;
|
|
LPTABLEHEADERV5 pHeader=(LPTABLEHEADERV5)pFile->pView;
|
|
|
|
// Trace
|
|
TraceCall("DowngradeLocalStoreFileV5");
|
|
|
|
// Set idx path
|
|
ReplaceExtension(pInfo->szFilePath, ".idx", szIdxPath, ARRAYSIZE(szIdxPath));
|
|
|
|
// Set mbx path
|
|
ReplaceExtension(pInfo->szFilePath, ".mbx", szMbxPath, ARRAYSIZE(szMbxPath));
|
|
|
|
// Delete Both Files
|
|
DeleteFile(szIdxPath);
|
|
DeleteFile(szMbxPath);
|
|
|
|
// Open the idx file
|
|
hIdxFile = CreateFile(szIdxPath, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_FLAG_RANDOM_ACCESS | FILE_ATTRIBUTE_NORMAL, NULL);
|
|
if (INVALID_HANDLE_VALUE == hIdxFile)
|
|
{
|
|
hIdxFile = NULL;
|
|
hr = TraceResult(MIGRATE_E_CANTOPENFILE);
|
|
goto exit;
|
|
}
|
|
|
|
// Initialize Idx Header
|
|
ZeroMemory(&IdxHeader, sizeof(IDXFILEHEADER));
|
|
IdxHeader.dwMagic = CACHEFILE_MAGIC;
|
|
IdxHeader.ver = CACHEFILE_VER;
|
|
IdxHeader.verBlob = 1; // this will force the .idx blobs to be rebuilt when imn 1.0 or oe v4.0 is run again
|
|
|
|
// Write the header
|
|
IF_FAILEXIT(hr = MyWriteFile(hIdxFile, 0, &IdxHeader, sizeof(IDXFILEHEADER)));
|
|
|
|
// Open the mbx file
|
|
hMbxFile = CreateFile(szMbxPath, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_FLAG_RANDOM_ACCESS | FILE_ATTRIBUTE_NORMAL, NULL);
|
|
if (INVALID_HANDLE_VALUE == hMbxFile)
|
|
{
|
|
hMbxFile = NULL;
|
|
hr = TraceResult(MIGRATE_E_CANTOPENFILE);
|
|
goto exit;
|
|
}
|
|
|
|
// Initialize MBX Header
|
|
ZeroMemory(&MbxHeader, sizeof(MBXFILEHEADER));
|
|
MbxHeader.dwMagic = MSGFILE_MAGIC;
|
|
MbxHeader.ver = MSGFILE_VER;
|
|
|
|
// Write the header
|
|
IF_FAILEXIT(hr = MyWriteFile(hMbxFile, 0, &MbxHeader, sizeof(MBXFILEHEADER)));
|
|
|
|
// Set First Record
|
|
faRecord = pHeader->faFirstRecord;
|
|
|
|
// Set faIdxWrite
|
|
faIdxWrite = sizeof(IDXFILEHEADER);
|
|
|
|
// Set faMbxWrite
|
|
faMbxWrite = sizeof(MBXFILEHEADER);
|
|
|
|
// While we have a record
|
|
while(faRecord)
|
|
{
|
|
// Bad Length
|
|
if (faRecord + sizeof(RECORDBLOCKV5) > pFile->cbSize)
|
|
{
|
|
hr = TraceResult(MIGRATE_E_OUTOFRANGEADDRESS);
|
|
goto exit;
|
|
}
|
|
|
|
// Cast the Record
|
|
pRecord = (LPRECORDBLOCKV5)((LPBYTE)pFile->pView + faRecord);
|
|
|
|
// Invalid Record Signature
|
|
if (faRecord != pRecord->faRecord)
|
|
{
|
|
hr = TraceResult(MIGRATE_E_BADRECORDSIGNATURE);
|
|
goto exit;
|
|
}
|
|
|
|
// Bad Length
|
|
if (faRecord + pRecord->cbRecord > pFile->cbSize)
|
|
{
|
|
hr = TraceResult(MIGRATE_E_OUTOFRANGEADDRESS);
|
|
goto exit;
|
|
}
|
|
|
|
// Load MsgInfo
|
|
IF_FAILEXIT(hr = DowngradeReadMsgInfoV5(pRecord, &MsgInfo));
|
|
|
|
// No Stream ?
|
|
if (0 == MsgInfo.faStream)
|
|
goto NextRecord;
|
|
|
|
// Set msgidLast
|
|
if ((DWORD)MsgInfo.idMessage > MbxHeader.msgidLast)
|
|
MbxHeader.msgidLast = (DWORD)MsgInfo.idMessage;
|
|
|
|
// Zero Out the Message Structures
|
|
ZeroMemory(&MbxMessage, sizeof(MBXMESSAGEHEADER));
|
|
ZeroMemory(&IdxMessage, sizeof(IDXMESSAGEHEADER));
|
|
|
|
// Fill MbxMessage
|
|
MbxMessage.dwMagic = MSGHDR_MAGIC;
|
|
MbxMessage.msgid = (DWORD)MsgInfo.idMessage;
|
|
|
|
// Fixup the Flags
|
|
if (FALSE == ISFLAGSET(MsgInfo.dwFlags, ARF_READ))
|
|
FLAGSET(IdxMessage.dwState, MSG_UNREAD);
|
|
if (ISFLAGSET(MsgInfo.dwFlags, ARF_VOICEMAIL))
|
|
FLAGSET(IdxMessage.dwState, MSG_VOICEMAIL);
|
|
if (ISFLAGSET(MsgInfo.dwFlags, ARF_REPLIED))
|
|
FLAGSET(IdxMessage.dwState, MSG_REPLIED);
|
|
if (ISFLAGSET(MsgInfo.dwFlags, ARF_FORWARDED))
|
|
FLAGSET(IdxMessage.dwState, MSG_FORWARDED);
|
|
if (ISFLAGSET(MsgInfo.dwFlags, ARF_FLAGGED))
|
|
FLAGSET(IdxMessage.dwState, MSG_FLAGGED);
|
|
if (ISFLAGSET(MsgInfo.dwFlags, ARF_RCPTSENT))
|
|
FLAGSET(IdxMessage.dwState, MSG_RCPTSENT);
|
|
if (ISFLAGSET(MsgInfo.dwFlags, ARF_NOSECUI))
|
|
FLAGSET(IdxMessage.dwState, MSG_NOSECUI);
|
|
if (ISFLAGSET(MsgInfo.dwFlags, ARF_NEWSMSG))
|
|
FLAGSET(IdxMessage.dwState, MSG_NEWSMSG);
|
|
if (ISFLAGSET(MsgInfo.dwFlags, ARF_UNSENT))
|
|
FLAGSET(IdxMessage.dwState, MSG_UNSENT);
|
|
if (ISFLAGSET(MsgInfo.dwFlags, ARF_SUBMITTED))
|
|
FLAGSET(IdxMessage.dwState, MSG_SUBMITTED);
|
|
if (ISFLAGSET(MsgInfo.dwFlags, ARF_RECEIVED))
|
|
FLAGSET(IdxMessage.dwState, MSG_RECEIVED);
|
|
|
|
// Save faMbxCurrent
|
|
faMbxCurrent = faMbxWrite;
|
|
|
|
// Validate alignment
|
|
Assert((faMbxCurrent % 4) == 0);
|
|
|
|
// Write the mbx header
|
|
IF_FAILEXIT(hr = MyWriteFile(hMbxFile, faMbxCurrent, &MbxMessage, sizeof(MBXMESSAGEHEADER)));
|
|
|
|
// Increment faMbxWrite
|
|
faMbxWrite += sizeof(MBXMESSAGEHEADER);
|
|
|
|
// Initialize dwMsgSize
|
|
MbxMessage.dwMsgSize = sizeof(MBXMESSAGEHEADER);
|
|
|
|
// Set faStreamBlock
|
|
faStreamBlock = MsgInfo.faStream;
|
|
|
|
// While we have stream block
|
|
while(faStreamBlock)
|
|
{
|
|
// Bad Length
|
|
if (faStreamBlock + sizeof(STREAMBLOCK) > pFile->cbSize)
|
|
{
|
|
hr = TraceResult(MIGRATE_E_OUTOFRANGEADDRESS);
|
|
goto exit;
|
|
}
|
|
|
|
// Cast the Record
|
|
pStmBlock = (LPSTREAMBLOCK)((LPBYTE)pFile->pView + faStreamBlock);
|
|
|
|
// Invalid Record Signature
|
|
if (faStreamBlock != pStmBlock->faThis)
|
|
{
|
|
hr = TraceResult(MIGRATE_E_BADSTREAMBLOCKSIGNATURE);
|
|
goto exit;
|
|
}
|
|
|
|
// Bad Length
|
|
if (faStreamBlock + pStmBlock->cbBlock > pFile->cbSize)
|
|
{
|
|
hr = TraceResult(MIGRATE_E_OUTOFRANGEADDRESS);
|
|
goto exit;
|
|
}
|
|
|
|
// Set pbData
|
|
pbData = (LPBYTE)((LPBYTE)(pStmBlock) + sizeof(STREAMBLOCK));
|
|
|
|
// Write into the stream
|
|
IF_FAILEXIT(hr = MyWriteFile(hMbxFile, faMbxWrite, pbData, pStmBlock->cbData));
|
|
|
|
// Increment dwBodySize
|
|
MbxMessage.dwBodySize += pStmBlock->cbData;
|
|
|
|
// Increment dwMsgSize
|
|
MbxMessage.dwMsgSize += pStmBlock->cbData;
|
|
|
|
// Increment faMbxWrite
|
|
faMbxWrite += pStmBlock->cbData;
|
|
|
|
// Goto Next Block
|
|
faStreamBlock = pStmBlock->faNext;
|
|
}
|
|
|
|
// Pad the Message on a dword boundary
|
|
cbAligned = (faMbxWrite % 4);
|
|
|
|
// cbAligned ?
|
|
if (cbAligned)
|
|
{
|
|
// Reset cbAligned
|
|
cbAligned = 4 - cbAligned;
|
|
|
|
// Write the mbx header
|
|
IF_FAILEXIT(hr = MyWriteFile(hMbxFile, faMbxWrite, (LPVOID)rgbZero, cbAligned));
|
|
|
|
// Increment faMbxWrite
|
|
faMbxWrite += cbAligned;
|
|
|
|
// Increment
|
|
MbxMessage.dwMsgSize += cbAligned;
|
|
}
|
|
|
|
// Validate alignment
|
|
Assert((faMbxWrite % 4) == 0);
|
|
|
|
// Write the mbx header again
|
|
IF_FAILEXIT(hr = MyWriteFile(hMbxFile, faMbxCurrent, &MbxMessage, sizeof(MBXMESSAGEHEADER)));
|
|
|
|
// Fill IdxMessage
|
|
IdxMessage.dwLanguage = (DWORD)MAKELONG(MsgInfo.wLanguage, MsgInfo.wHighlight);
|
|
IdxMessage.msgid = (DWORD)MsgInfo.idMessage;
|
|
IdxMessage.dwOffset = faMbxCurrent;
|
|
IdxMessage.dwMsgSize = MbxMessage.dwMsgSize;
|
|
IdxMessage.dwHdrOffset = 0;
|
|
IdxMessage.dwSize = sizeof(IDXMESSAGEHEADER);
|
|
IdxMessage.dwHdrSize = 0;
|
|
IdxMessage.rgbHdr[4] = 0;
|
|
|
|
// Write the mbx header
|
|
IF_FAILEXIT(hr = MyWriteFile(hIdxFile, faIdxWrite, &IdxMessage, sizeof(IDXMESSAGEHEADER)));
|
|
|
|
// Increment faIdxWrite
|
|
faIdxWrite += IdxMessage.dwSize;
|
|
|
|
// Increment cRecords
|
|
cRecords++;
|
|
|
|
NextRecord:
|
|
// Progress
|
|
IncrementProgress(pProgress, pInfo);
|
|
|
|
// Cleanup
|
|
SafeMemFree(MsgInfo.pvMemory);
|
|
|
|
// Goto Next
|
|
faRecord = pRecord->faNext;
|
|
}
|
|
|
|
// Set the Record Counts
|
|
MbxHeader.cMsg = cRecords;
|
|
IdxHeader.cMsg = cRecords;
|
|
|
|
// Set the Flags
|
|
IdxHeader.dwFlags = 1; // STOREINIT_MAIL
|
|
MbxHeader.dwFlags = 1; // STOREINIT_MAIL
|
|
|
|
// Get the Size of the idx file
|
|
IdxHeader.cbValid = ::GetFileSize(hIdxFile, NULL);
|
|
if (0xFFFFFFFF == IdxHeader.cbValid)
|
|
{
|
|
hr = TraceResult(MIGRATE_E_CANTGETFILESIZE);
|
|
goto exit;
|
|
}
|
|
|
|
// Get the Size of the mbx file
|
|
MbxHeader.cbValid = ::GetFileSize(hMbxFile, NULL);
|
|
if (0xFFFFFFFF == MbxHeader.cbValid)
|
|
{
|
|
hr = TraceResult(MIGRATE_E_CANTGETFILESIZE);
|
|
goto exit;
|
|
}
|
|
|
|
// Write the header
|
|
IF_FAILEXIT(hr = MyWriteFile(hIdxFile, 0, &IdxHeader, sizeof(IDXFILEHEADER)));
|
|
|
|
// Write the header
|
|
IF_FAILEXIT(hr = MyWriteFile(hMbxFile, 0, &MbxHeader, sizeof(MBXFILEHEADER)));
|
|
|
|
exit:
|
|
// Cleanup
|
|
SafeCloseHandle(hIdxFile);
|
|
SafeCloseHandle(hMbxFile);
|
|
SafeMemFree(MsgInfo.pvMemory);
|
|
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// DowngradeRecordV5
|
|
// --------------------------------------------------------------------------------
|
|
HRESULT DowngradeRecordV5(MIGRATETOTYPE tyMigrate, LPFILEINFO pInfo,
|
|
LPMEMORYFILE pFile, LPCHAINNODEV5 pNode, LPDWORD pcbRecord)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
DWORD cbRecord=0;
|
|
DWORD cbOffsets;
|
|
DWORD cbData;
|
|
DWORD cb;
|
|
LPBYTE pbData;
|
|
LPBYTE pbStart;
|
|
MESSAGEINFO MsgInfo={0};
|
|
RECORDBLOCKV5B1 RecordOld;
|
|
LPRECORDBLOCKV5 pRecord;
|
|
|
|
// Trace
|
|
TraceCall("DowngradeRecordV5");
|
|
|
|
// Invalid
|
|
if (pNode->faRecord + sizeof(RECORDBLOCKV5) > pFile->cbSize || 0 == pNode->faRecord)
|
|
return TraceResult(MIGRATE_E_OUTOFRANGEADDRESS);
|
|
|
|
// Access the Record
|
|
pRecord = (LPRECORDBLOCKV5((LPBYTE)pFile->pView + pNode->faRecord));
|
|
|
|
// Bad Record
|
|
if (pRecord->faRecord != pNode->faRecord)
|
|
return TraceResult(MIGRATE_E_BADRECORDSIGNATURE);
|
|
|
|
// Invalid
|
|
if (pNode->faRecord + sizeof(RECORDBLOCKV5) + pRecord->cbRecord > pFile->cbSize)
|
|
return TraceResult(MIGRATE_E_OUTOFRANGEADDRESS);
|
|
|
|
// Fill an old record header
|
|
RecordOld.faRecord = pRecord->faRecord;
|
|
RecordOld.faNext = pRecord->faNext;
|
|
RecordOld.faPrevious = pRecord->faPrevious;
|
|
|
|
// Reformat the record
|
|
if (FILE_IS_NEWS_MESSAGES == pInfo->tyFile || FILE_IS_IMAP_MESSAGES == pInfo->tyFile)
|
|
{
|
|
// Read the v5 record into a msginfo structure
|
|
IF_FAILEXIT(hr = DowngradeReadMsgInfoV5(pRecord, &MsgInfo));
|
|
}
|
|
|
|
// Compute offset table length
|
|
cbOffsets = (pRecord->cColumns * sizeof(DWORD));
|
|
|
|
// Cast the datablock
|
|
pbData = ((LPBYTE)pRecord + sizeof(RECORDBLOCKV5B1));
|
|
|
|
// Set Size
|
|
cbData = (pRecord->cbRecord - cbOffsets - sizeof(RECORDBLOCKV5));
|
|
|
|
// Remove the Offset Table
|
|
MoveMemory(pbData, ((LPBYTE)pRecord + sizeof(RECORDBLOCKV5) + cbOffsets), cbData);
|
|
|
|
// Reformat the record
|
|
if (FILE_IS_NEWS_MESSAGES == pInfo->tyFile || FILE_IS_IMAP_MESSAGES == pInfo->tyFile)
|
|
{
|
|
// Set pbStart
|
|
pbStart = pbData;
|
|
|
|
// DWORD - idMessage
|
|
CopyMemory(pbData, &MsgInfo.idMessage, sizeof(MsgInfo.idMessage));
|
|
pbData += sizeof(MsgInfo.idMessage);
|
|
|
|
// VERSION - dwFlags
|
|
if (IMSG_PRI_HIGH == MsgInfo.wPriority)
|
|
FLAGSET(MsgInfo.dwFlags, 0x00000200);
|
|
else if (IMSG_PRI_LOW == MsgInfo.wPriority)
|
|
FLAGSET(MsgInfo.dwFlags, 0x00000100);
|
|
|
|
// VERSION - Normalized Subject -
|
|
if (lstrcmpi(MsgInfo.pszSubject, MsgInfo.pszNormalSubj) != 0)
|
|
MsgInfo.dwFlags = (DWORD)MAKELONG(MsgInfo.dwFlags, MAKEWORD(0, 4));
|
|
|
|
// DWORD - dwFlags
|
|
CopyMemory(pbData, &MsgInfo.dwFlags, sizeof(MsgInfo.dwFlags));
|
|
pbData += sizeof(MsgInfo.dwFlags);
|
|
|
|
// FILETIME - ftSent
|
|
CopyMemory(pbData, &MsgInfo.ftSent, sizeof(MsgInfo.ftSent));
|
|
pbData += sizeof(MsgInfo.ftSent);
|
|
|
|
// DWORD - cLines
|
|
CopyMemory(pbData, &MsgInfo.cLines, sizeof(MsgInfo.cLines));
|
|
pbData += sizeof(MsgInfo.cLines);
|
|
|
|
// DWORD - faStream
|
|
CopyMemory(pbData, &MsgInfo.faStream, sizeof(MsgInfo.faStream));
|
|
pbData += sizeof(MsgInfo.faStream);
|
|
|
|
// VERSION - DWORD - cbArticle
|
|
CopyMemory(pbData, &MsgInfo.cbMessage, sizeof(MsgInfo.cbMessage));
|
|
pbData += sizeof(MsgInfo.cbMessage);
|
|
|
|
// FILETIME - ftDownloaded
|
|
CopyMemory(pbData, &MsgInfo.ftDownloaded, sizeof(MsgInfo.ftDownloaded));
|
|
pbData += sizeof(MsgInfo.ftDownloaded);
|
|
|
|
// LPSTR - pszMessageId
|
|
cb = lstrlen(MsgInfo.pszMessageId) + 1;
|
|
CopyMemory(pbData, MsgInfo.pszMessageId, cb);
|
|
pbData += cb;
|
|
|
|
// LPSTR - pszSubject
|
|
cb = lstrlen(MsgInfo.pszSubject) + 1;
|
|
CopyMemory(pbData, MsgInfo.pszSubject, cb);
|
|
pbData += cb;
|
|
|
|
// LPSTR - pszFromHeader
|
|
cb = lstrlen(MsgInfo.pszFromHeader) + 1;
|
|
CopyMemory(pbData, MsgInfo.pszFromHeader, cb);
|
|
pbData += cb;
|
|
|
|
// LPSTR - pszReferences
|
|
cb = lstrlen(MsgInfo.pszReferences) + 1;
|
|
CopyMemory(pbData, MsgInfo.pszReferences, cb);
|
|
pbData += cb;
|
|
|
|
// LPSTR - pszXref
|
|
cb = lstrlen(MsgInfo.pszXref) + 1;
|
|
CopyMemory(pbData, MsgInfo.pszXref, cb);
|
|
pbData += cb;
|
|
|
|
// LPSTR - pszServer
|
|
cb = lstrlen(MsgInfo.pszServer) + 1;
|
|
CopyMemory(pbData, MsgInfo.pszServer, cb);
|
|
pbData += cb;
|
|
|
|
// LPSTR - pszDisplayFrom
|
|
cb = lstrlen(MsgInfo.pszDisplayFrom) + 1;
|
|
CopyMemory(pbData, MsgInfo.pszDisplayFrom, cb);
|
|
pbData += cb;
|
|
|
|
// LPSTR - pszEmailFrom
|
|
cb = lstrlen(MsgInfo.pszEmailFrom) + 1;
|
|
CopyMemory(pbData, MsgInfo.pszEmailFrom, cb);
|
|
pbData += cb;
|
|
|
|
// Going to V4 ?
|
|
if (DOWNGRADE_V5_TO_V4 == tyMigrate)
|
|
{
|
|
// WORD - wLanguage
|
|
CopyMemory(pbData, &MsgInfo.wLanguage, sizeof(MsgInfo.wLanguage));
|
|
pbData += sizeof(MsgInfo.wLanguage);
|
|
|
|
// WORD - wReserved
|
|
MsgInfo.wHighlight = 0;
|
|
CopyMemory(pbData, &MsgInfo.wHighlight, sizeof(MsgInfo.wHighlight));
|
|
pbData += sizeof(MsgInfo.wHighlight);
|
|
|
|
// DWORD - cbMessage
|
|
CopyMemory(pbData, &MsgInfo.cbMessage, sizeof(MsgInfo.cbMessage));
|
|
pbData += sizeof(MsgInfo.cbMessage);
|
|
|
|
// DWORD - ftReceived
|
|
CopyMemory(pbData, &MsgInfo.ftReceived, sizeof(MsgInfo.ftReceived));
|
|
pbData += sizeof(MsgInfo.ftReceived);
|
|
|
|
// LPSTR - pszDisplayTo
|
|
cb = lstrlen(MsgInfo.pszDisplayTo) + 1;
|
|
CopyMemory(pbData, MsgInfo.pszDisplayTo, cb);
|
|
pbData += cb;
|
|
}
|
|
|
|
// Add on Reserved
|
|
cbRecord = (40 + sizeof(RECORDBLOCKV5B1) + (pbData - pbStart));
|
|
|
|
// Better be smaller
|
|
Assert(cbRecord <= pRecord->cbRecord);
|
|
}
|
|
|
|
// Otherwise, much easier
|
|
else
|
|
{
|
|
// Set Size
|
|
cbRecord = (pRecord->cbRecord - cbOffsets - sizeof(RECORDBLOCKV5)) + sizeof(RECORDBLOCKV5B1);
|
|
}
|
|
|
|
// Set the Record Size
|
|
RecordOld.cbRecord = cbRecord;
|
|
|
|
// Write the new record header
|
|
CopyMemory((LPBYTE)pRecord, &RecordOld, sizeof(RECORDBLOCKV5B1));
|
|
|
|
// Return size
|
|
*pcbRecord = cbRecord;
|
|
|
|
exit:
|
|
// Cleanup
|
|
SafeMemFree(MsgInfo.pvMemory);
|
|
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// DowngradeIndexV5
|
|
// --------------------------------------------------------------------------------
|
|
HRESULT DowngradeIndexV5(MIGRATETOTYPE tyMigrate, LPFILEINFO pInfo,
|
|
LPMEMORYFILE pFile, LPPROGRESSINFO pProgress, DWORD faRootChain, DWORD faChain)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
LONG i;
|
|
LPCHAINBLOCKV5 pChain;
|
|
CHAINBLOCKV5B1 ChainOld;
|
|
DWORD cbRecord;
|
|
|
|
// Trace
|
|
TraceCall("DowngradeIndexV5");
|
|
|
|
// Nothing to validate
|
|
if (0 == faChain)
|
|
return S_OK;
|
|
|
|
// Out-of-bounds
|
|
if (faChain + CB_CHAIN_BLOCKV5 > pFile->cbSize)
|
|
return TraceResult(MIGRATE_E_OUTOFRANGEADDRESS);
|
|
|
|
// De-ref the block
|
|
pChain = (LPCHAINBLOCKV5)((LPBYTE)pFile->pView + faChain);
|
|
|
|
// Out-of-Bounds
|
|
if (pChain->faStart != faChain)
|
|
return TraceResult(MIGRATE_E_BADCHAINSIGNATURE);
|
|
|
|
// Too many nodes
|
|
if (pChain->cNodes > BTREE_ORDER)
|
|
return TraceResult(MIGRATE_E_TOOMANYCHAINNODES);
|
|
|
|
// Validate Minimum Filled Constraint
|
|
if (pChain->cNodes < BTREE_MIN_CAP && pChain->faStart != faRootChain)
|
|
return TraceResult(MIGRATE_E_BADMINCAPACITY);
|
|
|
|
// Go to the left
|
|
IF_FAILEXIT(hr = DowngradeIndexV5(tyMigrate, pInfo, pFile, pProgress, faRootChain, pChain->faLeftChain));
|
|
|
|
// Convert pChain to ChainOld
|
|
ChainOld.faStart = pChain->faStart;
|
|
ChainOld.cNodes = pChain->cNodes;
|
|
ChainOld.faLeftChain = pChain->faLeftChain;
|
|
|
|
// Loop throug right chains
|
|
for (i=0; i<pChain->cNodes; i++)
|
|
{
|
|
// Bump Progress
|
|
IncrementProgress(pProgress, pInfo);
|
|
|
|
/// Downgrad this record
|
|
IF_FAILEXIT(hr = DowngradeRecordV5(tyMigrate, pInfo, pFile, &pChain->rgNode[i], &cbRecord));
|
|
|
|
// Update Old Node
|
|
ChainOld.rgNode[i].faRecord = pChain->rgNode[i].faRecord;
|
|
ChainOld.rgNode[i].cbRecord = cbRecord;
|
|
ChainOld.rgNode[i].faRightChain = pChain->rgNode[i].faRightChain;
|
|
|
|
// Validate the Right Chain
|
|
IF_FAILEXIT(hr = DowngradeIndexV5(tyMigrate, pInfo, pFile, pProgress, faRootChain, pChain->rgNode[i].faRightChain));
|
|
}
|
|
|
|
// Write this new chain
|
|
CopyMemory((LPBYTE)pChain, &ChainOld, CB_CHAIN_BLOCKV5B1);
|
|
|
|
exit:
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// DowngradeFileV5
|
|
// --------------------------------------------------------------------------------
|
|
HRESULT DowngradeFileV5(MIGRATETOTYPE tyMigrate, LPFILEINFO pInfo,
|
|
LPPROGRESSINFO pProgress)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
MEMORYFILE File={0};
|
|
TABLEHEADERV5 HeaderV5;
|
|
LPTABLEHEADERV5B1 pHeaderV5B1;
|
|
CHAR szDstFile[MAX_PATH + MAX_PATH];
|
|
|
|
// Trace
|
|
TraceCall("DowngradeFileV5");
|
|
|
|
// Local message file
|
|
if (FILE_IS_LOCAL_MESSAGES == pInfo->tyFile)
|
|
{
|
|
// Get the File Header
|
|
IF_FAILEXIT(hr = OpenMemoryFile(pInfo->szFilePath, &File));
|
|
|
|
// UpgradeLocalStoreFileV5
|
|
IF_FAILEXIT(hr = DowngradeLocalStoreFileV5(tyMigrate, pInfo, &File, pProgress));
|
|
}
|
|
|
|
// Old News or Imap file
|
|
else
|
|
{
|
|
// Create xxx.nch file
|
|
if (FILE_IS_POP3UIDL == pInfo->tyFile)
|
|
ReplaceExtension(pInfo->szFilePath, ".dat", szDstFile, ARRAYSIZE(szDstFile));
|
|
else
|
|
ReplaceExtension(pInfo->szFilePath, ".nch", szDstFile, ARRAYSIZE(szDstFile));
|
|
|
|
// Copy the file
|
|
if (0 == CopyFile(pInfo->szFilePath, szDstFile, FALSE))
|
|
{
|
|
hr = TraceResult(MIGRATE_E_CANTCOPYFILE);
|
|
goto exit;
|
|
}
|
|
|
|
// Get the File Header
|
|
IF_FAILEXIT(hr = OpenMemoryFile(szDstFile, &File));
|
|
|
|
// Copy Table Header
|
|
CopyMemory(&HeaderV5, (LPBYTE)File.pView, sizeof(TABLEHEADERV5));
|
|
|
|
// De-Ref the header
|
|
pHeaderV5B1 = (LPTABLEHEADERV5B1)File.pView;
|
|
|
|
// Fixup the Header
|
|
ZeroMemory(pHeaderV5B1, sizeof(TABLEHEADERV5B1));
|
|
pHeaderV5B1->dwSignature = HeaderV5.dwSignature;
|
|
pHeaderV5B1->wMajorVersion = (WORD)HeaderV5.dwMajorVersion;
|
|
pHeaderV5B1->faRootChain = HeaderV5.rgfaIndex[0];
|
|
pHeaderV5B1->faFreeRecordBlock = HeaderV5.faFreeRecordBlock;
|
|
pHeaderV5B1->faFirstRecord = HeaderV5.faFirstRecord;
|
|
pHeaderV5B1->faLastRecord = HeaderV5.faLastRecord;
|
|
pHeaderV5B1->cRecords = HeaderV5.cRecords;
|
|
pHeaderV5B1->cbAllocated = HeaderV5.cbAllocated;
|
|
pHeaderV5B1->cbFreed = HeaderV5.cbFreed;
|
|
pHeaderV5B1->dwReserved1 = 0;
|
|
pHeaderV5B1->dwReserved2 = 0;
|
|
pHeaderV5B1->cbUserData = HeaderV5.cbUserData;
|
|
pHeaderV5B1->cDeletes = 0;
|
|
pHeaderV5B1->cInserts = 0;
|
|
pHeaderV5B1->cActiveThreads = 0;
|
|
pHeaderV5B1->dwReserved3 = 0;
|
|
pHeaderV5B1->cbStreams = HeaderV5.cbStreams;
|
|
pHeaderV5B1->faFreeStreamBlock = HeaderV5.faFreeStreamBlock;
|
|
pHeaderV5B1->faFreeChainBlock = HeaderV5.faFreeChainBlock;
|
|
pHeaderV5B1->faNextAllocate = HeaderV5.faNextAllocate;
|
|
pHeaderV5B1->dwNextId = HeaderV5.dwNextId;
|
|
pHeaderV5B1->AllocateRecord = HeaderV5.AllocateRecord;
|
|
pHeaderV5B1->AllocateChain = HeaderV5.AllocateChain;
|
|
pHeaderV5B1->AllocateStream = HeaderV5.AllocateStream;
|
|
pHeaderV5B1->fCorrupt = FALSE;
|
|
pHeaderV5B1->fCorruptCheck = TRUE;
|
|
|
|
// DowngradeIndexV5
|
|
IF_FAILEXIT(hr = DowngradeIndexV5(tyMigrate, pInfo, &File, pProgress, pHeaderV5B1->faRootChain, pHeaderV5B1->faRootChain));
|
|
|
|
// Reset the version
|
|
pHeaderV5B1->wMajorVersion = OBJECTDB_VERSION_PRE_V5;
|
|
|
|
// Set the Minor Version
|
|
if (FILE_IS_NEWS_MESSAGES == pInfo->tyFile || FILE_IS_IMAP_MESSAGES == pInfo->tyFile)
|
|
pHeaderV5B1->wMinorVersion = ACACHE_VERSION_PRE_V5;
|
|
|
|
// Folder cache version
|
|
else if (FILE_IS_LOCAL_FOLDERS == pInfo->tyFile || FILE_IS_IMAP_FOLDERS == pInfo->tyFile)
|
|
pHeaderV5B1->wMinorVersion = FLDCACHE_VERSION_PRE_V5;
|
|
|
|
// UIDL Cache Version
|
|
else if (FILE_IS_POP3UIDL == pInfo->tyFile)
|
|
pHeaderV5B1->wMinorVersion = UIDCACHE_VERSION_PRE_V5;
|
|
|
|
// Bad mojo
|
|
else
|
|
Assert(FALSE);
|
|
}
|
|
|
|
exit:
|
|
// Cleanup
|
|
CloseMemoryFile(&File);
|
|
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// DowngradeProcessFileListV5
|
|
// --------------------------------------------------------------------------------
|
|
HRESULT DowngradeProcessFileListV5(LPFILEINFO pHead, LPDWORD pcMax, LPDWORD pcbNeeded)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
MEMORYFILE File={0};
|
|
LPFILEINFO pCurrent;
|
|
LPTABLEHEADERV5 pHeader;
|
|
|
|
// Trace
|
|
TraceCall("DowngradeProcessFileListV5");
|
|
|
|
// Invalid Arg
|
|
Assert(pHead);
|
|
|
|
// 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))
|
|
{
|
|
// Don't Migrate
|
|
pCurrent->fMigrate = FALSE;
|
|
|
|
// Set hrMigrate
|
|
pCurrent->hrMigrate = hr;
|
|
|
|
// Reset hr
|
|
hr = S_OK;
|
|
|
|
// Get the LastError
|
|
pCurrent->dwLastError = GetLastError();
|
|
|
|
// Goto Next
|
|
goto NextFile;
|
|
}
|
|
|
|
// De-Ref the header
|
|
pHeader = (LPTABLEHEADERV5)File.pView;
|
|
|
|
// Check the Signature...
|
|
if (File.cbSize < sizeof(TABLEHEADERV5) || OBJECTDB_SIGNATURE != pHeader->dwSignature || OBJECTDB_VERSION_V5 != pHeader->dwMajorVersion)
|
|
{
|
|
// 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;
|
|
|
|
// Initialize counters
|
|
InitializeCounters(&File, pCurrent, pcMax, pcbNeeded, FALSE);
|
|
|
|
// Yes, Migrate
|
|
pCurrent->fMigrate = TRUE;
|
|
|
|
NextFile:
|
|
// Close the File
|
|
CloseMemoryFile(&File);
|
|
}
|
|
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// DowngradeDeleteFilesV5
|
|
// --------------------------------------------------------------------------------
|
|
void DowngradeDeleteFilesV5(LPFILEINFO pHeadFile)
|
|
{
|
|
// Locals
|
|
CHAR szDstFile[MAX_PATH + MAX_PATH];
|
|
LPFILEINFO pCurrent;
|
|
|
|
// Trace
|
|
TraceCall("DowngradeDeleteFilesV5");
|
|
|
|
// Delete all files
|
|
for (pCurrent=pHeadFile; pCurrent!=NULL; pCurrent=pCurrent->pNext)
|
|
{
|
|
// Succeeded
|
|
Assert(SUCCEEDED(pCurrent->hrMigrate));
|
|
|
|
// Delete the file
|
|
DeleteFile(pCurrent->szFilePath);
|
|
}
|
|
|
|
// Done
|
|
return;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// DowngradeDeleteIdxMbxNchDatFilesV5
|
|
// --------------------------------------------------------------------------------
|
|
void DowngradeDeleteIdxMbxNchDatFilesV5(LPFILEINFO pHeadFile)
|
|
{
|
|
// Locals
|
|
CHAR szDstFile[MAX_PATH + MAX_PATH];
|
|
LPFILEINFO pCurrent;
|
|
|
|
// Trace
|
|
TraceCall("DowngradeDeleteIdxMbxNchDatFilesV5");
|
|
|
|
// Delete all old files
|
|
for (pCurrent=pHeadFile; pCurrent!=NULL; pCurrent=pCurrent->pNext)
|
|
{
|
|
// 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);
|
|
|
|
// Replace file extension
|
|
ReplaceExtension(pCurrent->szFilePath, ".mbx", szDstFile, ARRAYSIZE(szDstFile));
|
|
|
|
// Delete the file
|
|
DeleteFile(szDstFile);
|
|
}
|
|
|
|
// Otherwise, pop3uidl.dat
|
|
else if (FILE_IS_POP3UIDL == pCurrent->tyFile)
|
|
{
|
|
// Replace file extension
|
|
ReplaceExtension(pCurrent->szFilePath, ".dat", szDstFile, ARRAYSIZE(szDstFile));
|
|
|
|
// Delete the file
|
|
DeleteFile(szDstFile);
|
|
}
|
|
|
|
// Otherwise, it has a .nch extension
|
|
else
|
|
{
|
|
// Replace file extension
|
|
ReplaceExtension(pCurrent->szFilePath, ".nch", szDstFile, ARRAYSIZE(szDstFile));
|
|
|
|
// Delete the file
|
|
DeleteFile(szDstFile);
|
|
}
|
|
}
|
|
|
|
// Done
|
|
return;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// DowngradeV5
|
|
// --------------------------------------------------------------------------------
|
|
HRESULT DowngradeV5(MIGRATETOTYPE tyMigrate, LPCSTR pszStoreRoot,
|
|
LPPROGRESSINFO pProgress, LPFILEINFO *ppHeadFile)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
ENUMFILEINFO EnumInfo={0};
|
|
LPFILEINFO pCurrent;
|
|
DWORD cbNeeded;
|
|
DWORDLONG dwlFree;
|
|
|
|
// Trace
|
|
TraceCall("DowngradeV5");
|
|
|
|
// Initialize
|
|
*ppHeadFile = NULL;
|
|
|
|
// Setup the EnumFile Info
|
|
EnumInfo.pszExt = ".dbx";
|
|
EnumInfo.pszFoldFile = "folders.dbx";
|
|
EnumInfo.pszUidlFile = "pop3uidl.dbx";
|
|
|
|
// Enumerate All ODB files in szStoreRoot...
|
|
IF_FAILEXIT(hr = EnumerateStoreFiles(pszStoreRoot, DIR_IS_ROOT, NULL, &EnumInfo, ppHeadFile));
|
|
|
|
// Compute some Counts, and validate that the files are valid to migrate...
|
|
IF_FAILEXIT(hr = DowngradeProcessFileListV5(*ppHeadFile, &pProgress->cMax, &cbNeeded));
|
|
|
|
// Delete all source files
|
|
DowngradeDeleteIdxMbxNchDatFilesV5(*ppHeadFile);
|
|
|
|
// Enought DiskSpace ?
|
|
IF_FAILEXIT(hr = GetAvailableDiskSpace(pszStoreRoot, &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);
|
|
|
|
// Downgrade the file
|
|
hr = pCurrent->hrMigrate = DowngradeFileV5(tyMigrate, pCurrent, pProgress);
|
|
|
|
// Failure ?
|
|
if (FAILED(pCurrent->hrMigrate))
|
|
{
|
|
// Set Last Error
|
|
pCurrent->dwLastError = GetLastError();
|
|
|
|
// Done
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Failure, delete all destination files
|
|
if (FAILED(hr))
|
|
{
|
|
// Delete.idx, .mbx and .nch fles
|
|
DowngradeDeleteIdxMbxNchDatFilesV5(*ppHeadFile);
|
|
}
|
|
|
|
// Otherwise, delete source files
|
|
else
|
|
{
|
|
// Delete all source files
|
|
DowngradeDeleteFilesV5(*ppHeadFile);
|
|
}
|
|
|
|
exit:
|
|
// Done
|
|
return hr;
|
|
}
|