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.
951 lines
28 KiB
951 lines
28 KiB
//--------------------------------------------------------------------------
|
|
// OE4Imp.cpp
|
|
//--------------------------------------------------------------------------
|
|
#include "pch.hxx"
|
|
#include "oe4imp.h"
|
|
#include "structs.h"
|
|
#include "migerror.h"
|
|
#include <shared.h>
|
|
#include <impapi.h>
|
|
#include <shlwapi.h>
|
|
#include "dllmain.h"
|
|
#include "resource.h"
|
|
|
|
//--------------------------------------------------------------------------
|
|
// Constants
|
|
//--------------------------------------------------------------------------
|
|
static const char c_szMail[] = "mail";
|
|
static const char c_szFoldersNch[] = "folders.nch";
|
|
static const char c_szEmpty[] = "";
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// MSG_xxx flags
|
|
// --------------------------------------------------------------------------------
|
|
#define MSG_DELETED 0x0001
|
|
#define MSG_UNREAD 0x0002
|
|
#define MSG_SUBMITTED 0x0004
|
|
#define MSG_UNSENT 0x0008
|
|
#define MSG_RECEIVED 0x0010
|
|
#define MSG_NEWSMSG 0x0020
|
|
#define MSG_NOSECUI 0x0040
|
|
#define MSG_VOICEMAIL 0x0080
|
|
#define MSG_REPLIED 0x0100
|
|
#define MSG_FORWARDED 0x0200
|
|
#define MSG_RCPTSENT 0x0400
|
|
#define MSG_FLAGGED 0x0800
|
|
#define MSG_LAST 0x0200
|
|
#define MSG_EXTERNAL_FLAGS 0x00fe
|
|
#define MSG_FLAGS 0x000f
|
|
|
|
//--------------------------------------------------------------------------
|
|
// COE4Import_CreateInstance
|
|
//--------------------------------------------------------------------------
|
|
COE4Import_CreateInstance(IUnknown *pUnkOuter, IUnknown **ppUnknown)
|
|
{
|
|
// Trace
|
|
TraceCall("COE4Import_CreateInstance");
|
|
|
|
// Initialize
|
|
*ppUnknown = NULL;
|
|
|
|
// Create me
|
|
COE4Import *pNew = new COE4Import();
|
|
if (NULL == pNew)
|
|
return TraceResult(E_OUTOFMEMORY);
|
|
|
|
// Cast to unknown
|
|
*ppUnknown = SAFECAST(pNew, IMailImport *);
|
|
|
|
// Done
|
|
return(S_OK);
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// 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;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
// COE4Import::COE4Import
|
|
//--------------------------------------------------------------------------
|
|
COE4Import::COE4Import(void)
|
|
{
|
|
TraceCall("COE4Import::COE4Import");
|
|
m_cRef = 1;
|
|
m_pList = NULL;
|
|
*m_szDirectory = '\0';
|
|
m_cFolders = 0;
|
|
m_prgFolder = NULL;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
// COE4Import::~COE4Import
|
|
//--------------------------------------------------------------------------
|
|
COE4Import::~COE4Import(void)
|
|
{
|
|
TraceCall("COE4Import::~COE4Import");
|
|
_Cleanup();
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
// COE4Import::_FreeFolderList
|
|
//--------------------------------------------------------------------------
|
|
void COE4Import::_Cleanup(void)
|
|
{
|
|
_FreeFolderList(m_pList);
|
|
m_pList = NULL;
|
|
SafeMemFree(m_prgFolder);
|
|
m_cFolders = 0;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
// COE4Import::_FreeFolderList
|
|
//--------------------------------------------------------------------------
|
|
void COE4Import::_FreeFolderList(IMPFOLDERNODE *pNode)
|
|
{
|
|
// Locals
|
|
IMPFOLDERNODE *pNext;
|
|
IMPFOLDERNODE *pCurrent=pNode;
|
|
|
|
// Loop
|
|
while (pCurrent)
|
|
{
|
|
// Save next
|
|
pNext = pCurrent->pnext;
|
|
|
|
// Free Children ?
|
|
if (pCurrent->pchild)
|
|
{
|
|
// Free
|
|
_FreeFolderList(pCurrent->pchild);
|
|
}
|
|
|
|
// Free szName
|
|
g_pMalloc->Free(pCurrent->szName);
|
|
|
|
// Free pCurrent
|
|
g_pMalloc->Free(pCurrent);
|
|
|
|
// Set Current
|
|
pCurrent = pNext;
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
// COE4Import::QueryInterface
|
|
//--------------------------------------------------------------------------
|
|
STDMETHODIMP COE4Import::QueryInterface(REFIID riid, LPVOID *ppv)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
|
|
// Stack
|
|
TraceCall("COE4Import::QueryInterface");
|
|
|
|
// Find IID
|
|
if (IID_IUnknown == riid)
|
|
*ppv = (IUnknown *)this;
|
|
else if (IID_IMailImport == riid)
|
|
*ppv = (IMailImport *)this;
|
|
else
|
|
{
|
|
*ppv = NULL;
|
|
hr = TraceResult(E_NOINTERFACE);
|
|
goto exit;
|
|
}
|
|
|
|
// AddRef It
|
|
((IUnknown *)*ppv)->AddRef();
|
|
|
|
exit:
|
|
// Done
|
|
return(hr);
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
// COE4Import::AddRef
|
|
//--------------------------------------------------------------------------
|
|
STDMETHODIMP_(ULONG) COE4Import::AddRef(void)
|
|
{
|
|
TraceCall("COE4Import::AddRef");
|
|
return InterlockedIncrement(&m_cRef);
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
// COE4Import::Release
|
|
//--------------------------------------------------------------------------
|
|
STDMETHODIMP_(ULONG) COE4Import::Release(void)
|
|
{
|
|
TraceCall("COE4Import::Release");
|
|
LONG cRef = InterlockedDecrement(&m_cRef);
|
|
if (0 == cRef)
|
|
delete this;
|
|
return (ULONG)cRef;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
// COE4Import::InitializeImport
|
|
//--------------------------------------------------------------------------
|
|
STDMETHODIMP COE4Import::InitializeImport(HWND hwnd)
|
|
{
|
|
// Let Importer Ask for the Directory
|
|
return(S_OK);
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
// COE4Import::GetDirectory
|
|
//--------------------------------------------------------------------------
|
|
STDMETHODIMP COE4Import::GetDirectory(LPSTR pszDir, UINT cch)
|
|
{
|
|
// Locals
|
|
HKEY hKey=NULL;
|
|
DWORD dwType;
|
|
DWORD cb=cch;
|
|
|
|
// Try to query the OE4 store root...
|
|
if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_CURRENT_USER, "Software\\Microsoft\\Outlook Express", 0, KEY_READ, &hKey))
|
|
{
|
|
// Try to read the value
|
|
if (ERROR_SUCCESS == RegQueryValueEx(hKey, "Store Root", NULL, &dwType, (LPBYTE)pszDir, &cb))
|
|
goto exit;
|
|
}
|
|
|
|
if (hKey)
|
|
{
|
|
RegCloseKey(hKey);
|
|
hKey = NULL;
|
|
}
|
|
|
|
// Try V1
|
|
if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_CURRENT_USER, "Software\\Microsoft\\Internet Mail and News", 0, KEY_READ, &hKey))
|
|
{
|
|
// Query the Store Root
|
|
if (ERROR_SUCCESS == RegQueryValueEx(hKey, "Store Root", NULL, &dwType, (LPBYTE)pszDir, &cb))
|
|
goto exit;
|
|
}
|
|
|
|
// Null It Out
|
|
*pszDir = '\0';
|
|
|
|
exit:
|
|
// Close the Key
|
|
if (hKey)
|
|
RegCloseKey(hKey);
|
|
|
|
// Done
|
|
return(S_OK);
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
// COE4Import::SetDirectory
|
|
//--------------------------------------------------------------------------
|
|
STDMETHODIMP COE4Import::SetDirectory(LPSTR pszDir)
|
|
{
|
|
// Trace
|
|
TraceCall("COE4Import::SetDirectory");
|
|
|
|
// Save the Directory
|
|
StrCpyN(m_szDirectory, pszDir, ARRAYSIZE(m_szDirectory));
|
|
|
|
// Done
|
|
return(S_OK);
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
// COE4Import::_EnumerateV1Folders
|
|
//--------------------------------------------------------------------------
|
|
HRESULT COE4Import::_EnumerateV1Folders(void)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
CHAR szRes[255];
|
|
CHAR szMbxPath[MAX_PATH + MAX_PATH];
|
|
CHAR szSearch[MAX_PATH + MAX_PATH];
|
|
WIN32_FIND_DATA fd;
|
|
HANDLE hFind=INVALID_HANDLE_VALUE;
|
|
DWORD cAllocated=0;
|
|
LPFLDINFO pFolder;
|
|
DWORD i;
|
|
MEMORYFILE MbxFile={0};
|
|
LPMBXFILEHEADER pMbxHeader;
|
|
|
|
// Trace
|
|
TraceCall("COE4Import::_EnumerateV1Folders");
|
|
|
|
// Do we have a sub dir
|
|
wnsprintf(szSearch, ARRAYSIZE(szSearch), "%s\\*.mbx", m_szDirectory);
|
|
|
|
// Find first file
|
|
hFind = FindFirstFile(szSearch, &fd);
|
|
|
|
// Did we find something
|
|
if (INVALID_HANDLE_VALUE == hFind)
|
|
goto exit;
|
|
|
|
// Loop for ever
|
|
while(1)
|
|
{
|
|
// If this is not a directory
|
|
if (FALSE == ISFLAGSET(fd.dwFileAttributes, FILE_ATTRIBUTE_DIRECTORY))
|
|
{
|
|
// Open the file
|
|
IF_FAILEXIT(hr = MakeFilePath(m_szDirectory, fd.cFileName, c_szEmpty, szMbxPath, ARRAYSIZE(szMbxPath)));
|
|
|
|
// Open the memory file
|
|
if (SUCCEEDED(OpenMemoryFile(szMbxPath, &MbxFile)))
|
|
{
|
|
// Allocate
|
|
if (m_cFolders + 1 > cAllocated)
|
|
{
|
|
// Reallocate
|
|
IF_FAILEXIT(hr = HrRealloc((LPVOID *)&m_prgFolder, (cAllocated + 10) * sizeof(FLDINFO)));
|
|
|
|
// Set cAllocated
|
|
cAllocated += 10;
|
|
}
|
|
|
|
// Readability
|
|
pFolder = &m_prgFolder[m_cFolders];
|
|
|
|
// Zero this node
|
|
ZeroMemory(pFolder, sizeof(FLDINFO));
|
|
|
|
// Copy the filename
|
|
StrCpyN(pFolder->szFile, fd.cFileName, ARRAYSIZE(pFolder->szFile));
|
|
|
|
// Strip the Extension Off
|
|
PathRemoveExtensionA(pFolder->szFile);
|
|
|
|
// Copy the folder name
|
|
StrCpyN(pFolder->szFolder, pFolder->szFile, ARRAYSIZE(pFolder->szFolder));
|
|
|
|
// Set Special
|
|
pFolder->tySpecial = (FOLDER_TYPE_NORMAL - 1);
|
|
|
|
// Loop through special folder
|
|
for (i=FOLDER_TYPE_INBOX; i<CFOLDERTYPE; i++)
|
|
{
|
|
// Load the Special Folder Name
|
|
LoadString(g_hInstImp, idsInbox + (i - 1), szRes, ARRAYSIZE(szRes));
|
|
|
|
// Compare with szFile
|
|
if (lstrcmpi(pFolder->szFolder, szRes) == 0)
|
|
{
|
|
// Copy the Folder Name
|
|
pFolder->tySpecial = (i - 1);
|
|
|
|
// Done
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Read the Mbx File Header
|
|
pMbxHeader = (LPMBXFILEHEADER)(MbxFile.pView);
|
|
|
|
// Get the message Count so progress will work nicely
|
|
pFolder->cMessages = pMbxHeader->cMsg;
|
|
|
|
// Close the memory file
|
|
CloseMemoryFile(&MbxFile);
|
|
|
|
// Increment m_cFolders
|
|
m_cFolders++;
|
|
}
|
|
}
|
|
|
|
// Find the Next File
|
|
if (!FindNextFile(hFind, &fd))
|
|
break;
|
|
}
|
|
|
|
exit:
|
|
// Cleanup
|
|
if (hFind)
|
|
FindClose(hFind);
|
|
CloseMemoryFile(&MbxFile);
|
|
|
|
// Done
|
|
return(hr);
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
// COE4Import::EnumerateFolders
|
|
//--------------------------------------------------------------------------
|
|
STDMETHODIMP COE4Import::EnumerateFolders(DWORD_PTR dwCookie, IEnumFOLDERS **ppEnum)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
DWORD cchDir;
|
|
MEMORYFILE File={0};
|
|
LPTABLEHEADERV5B1 pHeader;
|
|
LPBYTE pbData;
|
|
DWORD faRecord;
|
|
LPFLDINFO pFolder;
|
|
LPRECORDBLOCKV5B1 pRecord;
|
|
BOOL fContinue;
|
|
COE4EnumFolders *pEnum=NULL;
|
|
CHAR szFilePath[MAX_PATH + MAX_PATH];
|
|
IMPFOLDERNODE *pList;
|
|
IMPFOLDERNODE *pNode=(IMPFOLDERNODE *)dwCookie;
|
|
|
|
// Trace
|
|
TraceCall("COE4Import::EnumerateFolders");
|
|
|
|
// Invalid Args
|
|
Assert(ppEnum);
|
|
|
|
// No folders yet ?
|
|
if (COOKIE_ROOT == dwCookie)
|
|
{
|
|
// Reset...
|
|
_Cleanup();
|
|
|
|
// Append \Mail onto m_szDirectory
|
|
cchDir = lstrlen(m_szDirectory);
|
|
|
|
// Is there enough room
|
|
if (cchDir + lstrlen(c_szMail) + 2 >= ARRAYSIZE(m_szDirectory))
|
|
{
|
|
hr = TraceResult(E_FAIL);
|
|
goto exit;
|
|
}
|
|
|
|
// Need a Wack ?
|
|
PathAddBackslash(m_szDirectory);
|
|
|
|
// Append \\mail
|
|
StrCatBuff(m_szDirectory, c_szMail, ARRAYSIZE(m_szDirectory));
|
|
|
|
// Make Path to folders.nch file
|
|
IF_FAILEXIT(hr = MakeFilePath(m_szDirectory, c_szFoldersNch, c_szEmpty, szFilePath, ARRAYSIZE(szFilePath)));
|
|
|
|
// If the folders.nch file doesn't exist, just try to enumerate the
|
|
if (FALSE == PathFileExists(szFilePath))
|
|
{
|
|
// EnumerateV1Folders
|
|
IF_FAILEXIT(hr = _EnumerateV1Folders());
|
|
}
|
|
|
|
// Otherwise, crack the folders.nch file
|
|
else
|
|
{
|
|
// Open the Folders file
|
|
IF_FAILEXIT(hr = OpenMemoryFile(szFilePath, &File));
|
|
|
|
// Validate Version
|
|
pHeader = (LPTABLEHEADERV5B1)File.pView;
|
|
|
|
// Check the Signature...
|
|
if (File.cbSize < sizeof(TABLEHEADERV5B1) || OBJECTDB_SIGNATURE != pHeader->dwSignature || OBJECTDB_VERSION_PRE_V5 != pHeader->wMajorVersion)
|
|
{
|
|
hr = TraceResult(E_FAIL);
|
|
goto exit;
|
|
}
|
|
|
|
// Allocate Folder Array
|
|
IF_NULLEXIT(m_prgFolder = (LPFLDINFO)ZeroAllocate(sizeof(FLDINFO) * pHeader->cRecords));
|
|
|
|
// Initialize faRecord to start
|
|
faRecord = pHeader->faFirstRecord;
|
|
|
|
// While we have a record
|
|
while(faRecord)
|
|
{
|
|
// Readability
|
|
pFolder = &m_prgFolder[m_cFolders];
|
|
|
|
// Get the Record
|
|
IF_FAILEXIT(hr = GetRecordBlock(&File, 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
|
|
m_cFolders++;
|
|
|
|
// Goto the Next Record
|
|
faRecord = pRecord->faNext;
|
|
}
|
|
}
|
|
|
|
// Build Import Folder Hierarchy
|
|
IF_FAILEXIT(hr = _BuildFolderHierarchy(0, 0, NULL, m_cFolders, m_prgFolder));
|
|
}
|
|
|
|
// Not Folders ?
|
|
else if (NULL == m_prgFolder)
|
|
{
|
|
hr = TraceResult(E_FAIL);
|
|
goto exit;
|
|
}
|
|
|
|
// What should I
|
|
if (dwCookie == COOKIE_ROOT)
|
|
pList = m_pList;
|
|
else
|
|
pList = pNode->pchild;
|
|
|
|
// Create Folder Enumerator
|
|
IF_NULLEXIT(pEnum = new COE4EnumFolders(pList));
|
|
|
|
// Return Enumerator
|
|
*ppEnum = (IEnumFOLDERS *)pEnum;
|
|
|
|
// Don't Free
|
|
pEnum = NULL;
|
|
|
|
exit:
|
|
// Cleanup
|
|
SafeRelease(pEnum);
|
|
CloseMemoryFile(&File);
|
|
|
|
// Done
|
|
return(hr);
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
// COE4Import::_BuildFolderHierarchy
|
|
//--------------------------------------------------------------------------
|
|
HRESULT COE4Import::_BuildFolderHierarchy(DWORD cDepth, DWORD idParent,
|
|
IMPFOLDERNODE *pParent, DWORD cFolders, LPFLDINFO prgFolder)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
DWORD i;
|
|
IMPFOLDERNODE *pPrevious=NULL;
|
|
IMPFOLDERNODE *pNode;
|
|
|
|
// Trace
|
|
TraceCall("COE4Import::_BuildFolderHierarchy");
|
|
|
|
// Walk through prgFolder and find items with parent of idParent
|
|
for (i=0; i<cFolders; i++)
|
|
{
|
|
// Correct Parent ?
|
|
if (idParent == prgFolder[i].idParent)
|
|
{
|
|
// Allocate the Root
|
|
IF_NULLEXIT(pNode = (IMPFOLDERNODE *)ZeroAllocate(sizeof(IMPFOLDERNODE)));
|
|
|
|
// Set Parent
|
|
pNode->pparent = pParent;
|
|
|
|
// Set Depth
|
|
pNode->depth = cDepth;
|
|
|
|
// Copy name
|
|
IF_NULLEXIT(pNode->szName = PszDupA(prgFolder[i].szFolder));
|
|
|
|
// Count of Messages
|
|
pNode->cMsg = prgFolder[i].cMessages;
|
|
|
|
// Set Type
|
|
pNode->type = (IMPORTFOLDERTYPE)(prgFolder[i].tySpecial + 1);
|
|
|
|
// Set lParam
|
|
pNode->lparam = i;
|
|
|
|
// Link pNode into List
|
|
if (pPrevious)
|
|
pPrevious->pnext = pNode;
|
|
else if (pParent)
|
|
pParent->pchild = pNode;
|
|
else
|
|
{
|
|
Assert(NULL == m_pList);
|
|
m_pList = pNode;
|
|
}
|
|
|
|
// Set pPrevious
|
|
pPrevious = pNode;
|
|
|
|
// Has Children ?
|
|
if (prgFolder[i].cChildren)
|
|
{
|
|
// Enumerate Children
|
|
IF_FAILEXIT(hr = _BuildFolderHierarchy(cDepth + 1, prgFolder[i].idFolder, pNode, cFolders, prgFolder));
|
|
}
|
|
}
|
|
}
|
|
|
|
exit:
|
|
// Done
|
|
return(hr);
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
// COE4Import::ImportFolder
|
|
//--------------------------------------------------------------------------
|
|
STDMETHODIMP COE4Import::ImportFolder(DWORD_PTR dwCookie, IFolderImport *pImport)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
CHAR szIdxPath[MAX_PATH + MAX_PATH];
|
|
CHAR szMbxPath[MAX_PATH + MAX_PATH];
|
|
MEMORYFILE IdxFile={0};
|
|
MEMORYFILE MbxFile={0};
|
|
LPBYTE pbStream;
|
|
LPMBXFILEHEADER pMbxHeader;
|
|
LPIDXFILEHEADER pIdxHeader;
|
|
DWORD faIdxRead;
|
|
LPIDXMESSAGEHEADER pIdxMessage;
|
|
LPMBXMESSAGEHEADER pMbxMessage;
|
|
DWORD cMessages=0;
|
|
DWORD dwMsgState;
|
|
DWORD i;
|
|
DWORD cb;
|
|
CByteStream *pStream=NULL;
|
|
IMPFOLDERNODE *pNode=(IMPFOLDERNODE *)dwCookie;
|
|
LPFLDINFO pFolder;
|
|
|
|
// Trace
|
|
TraceCall("COE4Import::ImportFolder");
|
|
|
|
// Set pFolder
|
|
pFolder = &m_prgFolder[pNode->lparam];
|
|
|
|
// .idx path
|
|
IF_FAILEXIT(hr = MakeFilePath(m_szDirectory, pFolder->szFile, ".idx", szIdxPath, ARRAYSIZE(szIdxPath)));
|
|
|
|
// .mbx path
|
|
IF_FAILEXIT(hr = MakeFilePath(m_szDirectory, pFolder->szFile, ".mbx", szMbxPath, ARRAYSIZE(szMbxPath)));
|
|
|
|
// Open the memory file
|
|
IF_FAILEXIT(hr = OpenMemoryFile(szIdxPath, &IdxFile));
|
|
|
|
// Open the memory file
|
|
IF_FAILEXIT(hr = OpenMemoryFile(szMbxPath, &MbxFile));
|
|
|
|
// Read the Mbx File Header
|
|
pMbxHeader = (LPMBXFILEHEADER)(MbxFile.pView);
|
|
|
|
// Read the Idx File Header
|
|
pIdxHeader = (LPIDXFILEHEADER)(IdxFile.pView);
|
|
|
|
// Validate the Version of th idx file
|
|
if (pIdxHeader->ver != CACHEFILE_VER || pIdxHeader->dwMagic != CACHEFILE_MAGIC)
|
|
{
|
|
hr = TraceResult(MIGRATE_E_INVALIDIDXHEADER);
|
|
goto exit;
|
|
}
|
|
|
|
// Setup faIdxRead
|
|
faIdxRead = sizeof(IDXFILEHEADER);
|
|
|
|
// Set Message Count
|
|
pImport->SetMessageCount(pIdxHeader->cMsg);
|
|
|
|
// Prepare to Loop
|
|
for (i=0; i<pIdxHeader->cMsg; i++)
|
|
{
|
|
// Done
|
|
if (faIdxRead >= IdxFile.cbSize)
|
|
break;
|
|
|
|
// Read an idx message header
|
|
pIdxMessage = (LPIDXMESSAGEHEADER)((LPBYTE)IdxFile.pView + faIdxRead);
|
|
|
|
// If this message is not marked as deleted...
|
|
if (ISFLAGSET(pIdxMessage->dwState, MSG_DELETED))
|
|
goto NextMessage;
|
|
|
|
// Initialize State
|
|
dwMsgState = 0;
|
|
|
|
// Fixup the Flags
|
|
if (ISFLAGSET(pIdxMessage->dwState, MSG_UNREAD))
|
|
FLAGSET(dwMsgState, MSG_STATE_UNREAD);
|
|
if (ISFLAGSET(pIdxMessage->dwState, MSG_UNSENT))
|
|
FLAGSET(dwMsgState, MSG_STATE_UNSENT);
|
|
if (ISFLAGSET(pIdxMessage->dwState, MSG_SUBMITTED))
|
|
FLAGSET(dwMsgState, MSG_STATE_SUBMITTED);
|
|
|
|
// Bad
|
|
if (pIdxMessage->dwOffset > MbxFile.cbSize)
|
|
goto NextMessage;
|
|
|
|
// Lets read the message header in the mbx file to validate the msgids
|
|
pMbxMessage = (LPMBXMESSAGEHEADER)((LPBYTE)MbxFile.pView + pIdxMessage->dwOffset);
|
|
|
|
// Validate the Message Ids
|
|
if (pMbxMessage->msgid != pIdxMessage->msgid)
|
|
goto NextMessage;
|
|
|
|
// Check for magic
|
|
if (pMbxMessage->dwMagic != MSGHDR_MAGIC)
|
|
goto NextMessage;
|
|
|
|
// Get the stream pointer
|
|
pbStream = (LPBYTE)((LPBYTE)MbxFile.pView + (pIdxMessage->dwOffset + sizeof(MBXMESSAGEHEADER)));
|
|
|
|
// New byte Stream
|
|
IF_NULLEXIT(pStream = new CByteStream(pbStream, pMbxMessage->dwBodySize));
|
|
|
|
// Import the message
|
|
IF_FAILEXIT(hr = pImport->ImportMessage(MSG_TYPE_MAIL, dwMsgState, pStream, NULL, 0));
|
|
|
|
// Count
|
|
cMessages++;
|
|
|
|
NextMessage:
|
|
// Cleanup
|
|
if (pStream)
|
|
{
|
|
pStream->AcquireBytes(&cb, &pbStream, ACQ_DISPLACE);
|
|
pStream->Release();
|
|
pStream = NULL;
|
|
}
|
|
|
|
// Goto Next Header
|
|
Assert(pIdxMessage);
|
|
|
|
// Update faIdxRead
|
|
faIdxRead += pIdxMessage->dwSize;
|
|
}
|
|
|
|
exit:
|
|
// Cleanup
|
|
if (pStream)
|
|
{
|
|
pStream->AcquireBytes(&cb, &pbStream, ACQ_DISPLACE);
|
|
pStream->Release();
|
|
pStream = NULL;
|
|
}
|
|
|
|
CloseMemoryFile(&IdxFile);
|
|
CloseMemoryFile(&MbxFile);
|
|
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
// COE4EnumFolders::COE4EnumFolders
|
|
//--------------------------------------------------------------------------
|
|
COE4EnumFolders::COE4EnumFolders(IMPFOLDERNODE *pList)
|
|
{
|
|
TraceCall("COE4EnumFolders::COE4EnumFolders");
|
|
m_cRef = 1;
|
|
m_pList = pList;
|
|
m_pNext = pList;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
// COE4EnumFolders::COE4EnumFolders
|
|
//--------------------------------------------------------------------------
|
|
COE4EnumFolders::~COE4EnumFolders(void)
|
|
{
|
|
TraceCall("COE4EnumFolders::~COE4EnumFolders");
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
// COE4EnumFolders::COE4EnumFolders
|
|
//--------------------------------------------------------------------------
|
|
STDMETHODIMP COE4EnumFolders::QueryInterface(REFIID riid, LPVOID *ppv)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
|
|
// Stack
|
|
TraceCall("COE4EnumFolders::QueryInterface");
|
|
|
|
// Find IID
|
|
if (IID_IUnknown == riid)
|
|
*ppv = (IUnknown *)this;
|
|
else if (IID_IEnumFOLDERS == riid)
|
|
*ppv = (IEnumFOLDERS *)this;
|
|
else
|
|
{
|
|
*ppv = NULL;
|
|
hr = TraceResult(E_NOINTERFACE);
|
|
goto exit;
|
|
}
|
|
|
|
// AddRef It
|
|
((IUnknown *)*ppv)->AddRef();
|
|
|
|
exit:
|
|
// Done
|
|
return(hr);
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
// COE4EnumFolders::AddRef
|
|
//--------------------------------------------------------------------------
|
|
STDMETHODIMP_(ULONG) COE4EnumFolders::AddRef(void)
|
|
{
|
|
TraceCall("COE4EnumFolders::AddRef");
|
|
return InterlockedIncrement(&m_cRef);
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
// COE4EnumFolders::Release
|
|
//--------------------------------------------------------------------------
|
|
STDMETHODIMP_(ULONG) COE4EnumFolders::Release(void)
|
|
{
|
|
TraceCall("COE4EnumFolders::Release");
|
|
LONG cRef = InterlockedDecrement(&m_cRef);
|
|
if (0 == cRef)
|
|
delete this;
|
|
return (ULONG)cRef;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
// COE4EnumFolders::Next
|
|
//--------------------------------------------------------------------------
|
|
STDMETHODIMP COE4EnumFolders::Next(IMPORTFOLDER *pFolder)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
|
|
// Trace
|
|
TraceCall("COE4EnumFolders::Next");
|
|
|
|
// Invalid Args
|
|
Assert(pFolder != NULL);
|
|
|
|
// Done
|
|
if (NULL == m_pNext)
|
|
return(S_FALSE);
|
|
|
|
// Zero
|
|
ZeroMemory(pFolder, sizeof(IMPORTFOLDER));
|
|
|
|
// Store pNext into dwCookie
|
|
pFolder->dwCookie = (DWORD_PTR)m_pNext;
|
|
|
|
// Copy Folder Name
|
|
StrCpyN(pFolder->szName, m_pNext->szName, ARRAYSIZE(pFolder->szName));
|
|
|
|
// Copy Type
|
|
pFolder->type = m_pNext->type;
|
|
|
|
// Has Sub Folders ?
|
|
pFolder->fSubFolders = (m_pNext->pchild != NULL);
|
|
|
|
// Goto Next
|
|
m_pNext = m_pNext->pnext;
|
|
|
|
// Done
|
|
return(S_OK);
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
// COE4EnumFolders::Reset
|
|
//--------------------------------------------------------------------------
|
|
STDMETHODIMP COE4EnumFolders::Reset(void)
|
|
{
|
|
// Trace
|
|
TraceCall("COE4EnumFolders::Reset");
|
|
|
|
// Reset
|
|
m_pNext = m_pList;
|
|
|
|
// Done
|
|
return(S_OK);
|
|
}
|