Leaked source code of windows server 2003
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.
 
 
 
 
 
 

5169 lines
146 KiB

//----------------------------------------------------------------------------------
// Storutil.cpp
//----------------------------------------------------------------------------------
#include "pch.hxx"
#include "optres.h"
#include "frntpage.h"
#include "acctview.h"
#include "storfldr.h"
#include "shared.h"
#include "util.h"
#include "msgview.h"
#include "storutil.h"
#include "xpcomm.h"
#include "migerror.h"
#include "storecb.h"
#include "taskutil.h"
#include "flagconv.h"
#include "msgfldr.h"
#include "syncop.h"
#include "store.h"
#include "storsync.h"
#include "shlwapip.h"
#include <multiusr.h>
#include "instance.h"
#include <newsdlgs.h>
#include "msgtable.h"
#include "newsstor.h"
#include "..\imap\imapsync.h"
#include "..\http\httpserv.h"
#include "demand.h"
#include "acctutil.h"
//----------------------------------------------------------------------------------
// Consts
//----------------------------------------------------------------------------------
#define FIDARRAY_START 50
#define FIDARRAY_GROW 50
//----------------------------------------------------------------------------------
// DELETEMSGS
//----------------------------------------------------------------------------------
typedef struct tagDELETEMSGS {
LPCSTR pszRootDir;
CProgress *pProgress;
BOOL fReset;
} DELETEMSGS, *LPDELETEMSGS;
//----------------------------------------------------------------------------------
// REMOVEBODIES
//----------------------------------------------------------------------------------
typedef struct tagREMOVEBODIES {
CProgress *pProgress;
CLEANUPFOLDERFLAGS dwFlags;
DWORD cExpireDays;
} REMOVEBODIES, *LPREMOVEBODIES;
//----------------------------------------------------------------------------------
// ENUMFOLDERSIZE
//----------------------------------------------------------------------------------
typedef struct tagENUMFOLDERSIZE {
DWORD cbFile;
DWORD cbFreed;
DWORD cbStreams;
} ENUMFOLDERSIZE, *LPENUMFOLDERSIZE;
//----------------------------------------------------------------------------------
// FOLDERENUMINFO
//----------------------------------------------------------------------------------
typedef struct tagFOLDERENUMINFO {
FOLDERID *prgFIDArray;
DWORD dwNumFolderIDs;
DWORD dwCurrentIdx;
} FOLDERENUMINFO;
//----------------------------------------------------------------------------------
// COMPACTCOOKIE
//----------------------------------------------------------------------------------
typedef struct tagCOMPACTCOOKIE {
HWND hwndParent;
BOOL fUI;
CProgress *pProgress;
} COMPACTCOOKIE, *LPCOMPACTCOOKIE;
//----------------------------------------------------------------------------------
// Prototypes
//----------------------------------------------------------------------------------
HRESULT FixPOP3UIDLFile(IDatabase *pDB);
HRESULT HashChildren(IMessageStore *pStore, FOLDERID idParent, IHashTable *pHash,
LPSTR *ppszPath, DWORD dwChildOffset, DWORD *pdwAlloc);
HRESULT FlattenHierarchyHelper(IMessageStore *pStore, FOLDERID idParent,
BOOL fIncludeParent, BOOL fSubscribedOnly,
FOLDERID **pprgFIDArray, LPDWORD pdwAllocated,
LPDWORD pdwUsed);
const static char c_szFolderFileSep[] = " - ";
// --------------------------------------------------------------------------------
// CreateMessageTable
// --------------------------------------------------------------------------------
HRESULT CreateMessageTable(FOLDERID idFolder, BOOL fThreaded, IMessageTable **ppTable)
{
// Locals
HRESULT hr=S_OK;
FOLDERSORTINFO SortInfo;
IMessageTable *pTable=NULL;
// Trace
TraceCall("CreateMessageTable");
// Init
*ppTable = NULL;
// Allocate the Table
IF_NULLEXIT(pTable = new CMessageTable);
// Initialize the Message Table
IF_FAILEXIT(hr = pTable->Initialize(idFolder, NULL, FALSE, NULL));
// Get the Current Sort Info
IF_FAILEXIT(hr = pTable->GetSortInfo(&SortInfo));
// Set fThread
SortInfo.fThreaded = fThreaded;
// Sort It...
IF_FAILEXIT(hr = pTable->SetSortInfo(&SortInfo, NULL));
// Return It
*ppTable = pTable;
// Don't Release It
pTable = NULL;
exit:
// Cleanup
SafeRelease(pTable);
// Done
return(hr);
}
// --------------------------------------------------------------------------------
// GetAvailableDiskSpace
// --------------------------------------------------------------------------------
HRESULT GetAvailableDiskSpace(
/* in */ LPCSTR pszFilePath,
/* out */ DWORDLONG *pdwlFree)
{
// Locals
HRESULT hr=S_OK;
CHAR szDrive[5];
DWORD dwSectorsPerCluster;
DWORD dwBytesPerSector;
DWORD dwNumberOfFreeClusters;
DWORD dwTotalNumberOfClusters;
// Trace
TraceCall("GetAvailableDiskSpace");
// Invalid Args
Assert(pszFilePath && pszFilePath[1] == ':' && pdwlFree);
// Split the path
szDrive[0] = *pszFilePath;
szDrive[1] = ':';
szDrive[2] = '\\';
szDrive[3] = '\0';
// Get free disk space - if it fails, lets pray we have enought disk space
if (!GetDiskFreeSpace(szDrive, &dwSectorsPerCluster, &dwBytesPerSector, &dwNumberOfFreeClusters, &dwTotalNumberOfClusters))
{
hr = TraceResult(E_FAIL);
goto exit;
}
// Return Amount of Free Disk Space
*pdwlFree = (dwNumberOfFreeClusters * (dwSectorsPerCluster * dwBytesPerSector));
exit:
// Done
return hr;
}
//--------------------------------------------------------------------------
// GetFolderAccountName
//--------------------------------------------------------------------------
HRESULT GetFolderAccountName(LPFOLDERINFO pFolder, LPSTR pszAccountName)
{
// Locals
HRESULT hr=S_OK;
IImnAccount *pAccount=NULL;
CHAR szAccountId[CCHMAX_ACCOUNT_NAME];
// Trace
TraceCall("GetFolderAccountName");
// Get Folder AccountId
IF_FAILEXIT(hr = GetFolderAccountId(pFolder, szAccountId, ARRAYSIZE(szAccountId)));
// Find the Account
IF_FAILEXIT(hr = g_pAcctMan->FindAccount(AP_ACCOUNT_ID, szAccountId, &pAccount));
// Get the Account Name
IF_FAILEXIT(hr = pAccount->GetPropSz(AP_ACCOUNT_NAME, pszAccountName, CCHMAX_ACCOUNT_NAME));
exit:
// Cleanup
SafeRelease(pAccount);
// Done
return(hr);
}
//--------------------------------------------------------------------------
// BuildFriendlyFolderFileName
//--------------------------------------------------------------------------
HRESULT BuildFriendlyFolderFileName(LPCSTR pszDir, LPFOLDERINFO pFolder,
LPSTR pszFilePath, DWORD cchFilePathMax, LPCSTR pszCurrentFile,
BOOL *pfChanged)
{
// Locals
HRESULT hr=S_OK;
LPSTR pszFileName=NULL;
LPSTR pszTemp=NULL;
DWORD_PTR i;
CHAR szFile[MAX_PATH];
CHAR szAccountName[CCHMAX_ACCOUNT_NAME];
DWORD cchFileName;
// Validate
Assert(pszDir && pFolder && pFolder->pszName && pszFilePath && cchFilePathMax >= MAX_PATH);
// Init
if (pfChanged)
*pfChanged = TRUE;
// Keep the names basic (i.e. no account prefix) for news and local folders.
if (FOLDER_NEWS == pFolder->tyFolder || FOLDER_LOCAL == pFolder->tyFolder)
{
// No Account name Prefix
*szAccountName = '\0';
}
// Otherwise
else
{
// Get Folder Account Name
IF_FAILEXIT(hr = GetFolderAccountName(pFolder, szAccountName));
}
// Build the name
DWORD cchSize = (lstrlen(szAccountName) + lstrlen(pFolder->pszName) + lstrlen(c_szFolderFileSep) + 1);
IF_NULLEXIT(pszFileName = PszAllocA(cchSize));
// Format the Name
cchFileName = wnsprintf(pszFileName, cchSize, "%s%s%s", szAccountName, *szAccountName ? c_szFolderFileSep : c_szEmpty, pFolder->pszName);
// Cleanup the filename
CleanupFileNameInPlaceA(CP_ACP, pszFileName);
// Same As Current ?
if (pszCurrentFile)
{
// Add a .dbx extension to pszFilename
DWORD cchSizeTemp = (cchFileName + lstrlen(c_szDbxExt) + 1);
IF_NULLEXIT(pszTemp = PszAllocA(cchSizeTemp));
// Format psztemp
wnsprintf(pszTemp, cchSizeTemp, "%s%s", pszFileName, c_szDbxExt);
// Not Changed ?
if (0 == lstrcmpi(pszTemp, pszCurrentFile))
{
// Not Changed
if (pfChanged)
*pfChanged = FALSE;
// Done
goto exit;
}
}
// Build szDstFile
hr = GenerateUniqueFileName(pszDir, pszFileName, c_szDbxExt, pszFilePath, cchFilePathMax);
// If that failed, then try to generate a unqiue name
if (FAILED(hr))
{
// Reset hr
hr = S_OK;
// Loop
for (i=(DWORD_PTR)pFolder->idFolder;;i++)
{
// Format the File Name
wnsprintf(szFile, ARRAYSIZE(szFile), "%08d%s", i, c_szDbxExt);
// Make the file path
IF_FAILEXIT(hr = MakeFilePath(pszDir, szFile, c_szEmpty, pszFilePath, cchFilePathMax));
// If the file still exists, renumber szFile until it doesn't exist
if (FALSE == PathFileExists(pszFilePath))
break;
}
}
exit:
// Cleanup
SafeMemFree(pszFileName);
SafeMemFree(pszTemp);
// Done
return(hr);
}
//--------------------------------------------------------------------------
// PutMessagesIntoFolder
//--------------------------------------------------------------------------
HRESULT PutMessagesIntoFolder(CProgress *pProgress, IDatabase *pStreams,
IMessageFolder *pFolder)
{
// Locals
HRESULT hr=S_OK;
HROWSET hRowset=NULL;
MESSAGEINFO Message={0};
STREAMINFO Stream={0};
// Walk through the Folder
IF_FAILEXIT(hr = pFolder->CreateRowset(IINDEX_PRIMARY, 0, &hRowset));
// Walk It
while (S_OK == pFolder->QueryRowset(hRowset, 1, (LPVOID *)&Message, NULL))
{
// Has a idStream ?
if (Message.idStreamOld)
{
// Initialize Message
Message.faStream = 0;
Message.Offsets.cbSize = 0;
Message.Offsets.pBlobData = NULL;
Message.idParentOld = 0;
Message.ThreadIdOld.pBlobData = 0;
Message.ThreadIdOld.cbSize = 0;
Message.pszUserNameOld = NULL;
// Set the Streamid
Stream.idStream = Message.idStreamOld;
// Find the Stream
if (DB_S_FOUND == pStreams->FindRecord(IINDEX_PRIMARY, COLUMNS_ALL, &Stream, NULL))
{
// faStream ?
if (Stream.faStream)
{
// Copy the Stream
IF_FAILEXIT(hr = pStreams->CopyStream(pFolder, Stream.faStream, &Message.faStream));
// Save the Offsets
Message.Offsets = Stream.Offsets;
}
// Free
pStreams->FreeRecord(&Stream);
}
// Clear idStreamOld
Message.idStreamOld = 0;
}
// Update the Record
IF_FAILEXIT(hr = pFolder->UpdateRecord(&Message));
// Cleanup
pFolder->FreeRecord(&Message);
// Update Progress
pProgress->HrUpdate(1);
}
exit:
// Cleanup
pStreams->FreeRecord(&Stream);
pFolder->FreeRecord(&Message);
pFolder->CloseRowset(&hRowset);
// Done
return(hr);
}
//--------------------------------------------------------------------------
// GetRidOfMessagesODSFile
//--------------------------------------------------------------------------
HRESULT GetRidOfMessagesODSFile(void)
{
// Locals
HRESULT hr=S_OK;
FOLDERINFO Folder={0};
CHAR szStoreRoot[MAX_PATH];
CHAR szMessagesFile[MAX_PATH];
CHAR szFile[MAX_PATH];
CHAR szSrcFile[MAX_PATH + MAX_PATH];
CHAR szDstFile[MAX_PATH + MAX_PATH];
CHAR szRes[255];
IDatabase *pStreams=NULL;
IMessageFolder *pFolder=NULL;
HROWSET hRowset=NULL;
DWORD cRecords;
DWORD cTotal=0;
DWORD cbFile;
DWORDLONG dwlDiskFree;
BOOL fErrorDisplayed=FALSE;
LPSTR pszExt=NULL;
CProgress cProgress;
// Trace
TraceCall("GetRidOfMessagesODSFile");
// Validate
Assert(g_pDBSession);
// Error Box
AthMessageBoxW(NULL, MAKEINTRESOURCEW(idsAthena), MAKEINTRESOURCEW(idsMigrateMessagesODS), 0, MB_OK | MB_ICONEXCLAMATION);
// Get Uidcache file path
IF_FAILEXIT(hr = GetStoreRootDirectory(szStoreRoot, sizeof(szStoreRoot)));
// Make File Path
IF_FAILEXIT(hr = MakeFilePath(szStoreRoot, "messages.ods", c_szEmpty, szMessagesFile, sizeof(szMessagesFile)));
// Allocate Table Object
IF_FAILEXIT(hr = g_pDBSession->OpenDatabase(szMessagesFile, NOFLAGS, &g_StreamTableSchema, NULL, &pStreams));
// Do a file size Check...
IF_FAILEXIT(hr = pStreams->GetSize(&cbFile, NULL, NULL, NULL));
// Get Available DiskSpace
IF_FAILEXIT(hr = GetAvailableDiskSpace(szStoreRoot, &dwlDiskFree));
// Not Enought Disk Space
if (((DWORDLONG) cbFile) > dwlDiskFree)
{
// Locals
CHAR szRes[255];
CHAR szMsg[255];
CHAR szSize[50];
// cbFile is DWORD and in this case we can downgrade dwlDiskFree to DWORD
// Format the Size Needed
StrFormatByteSizeA(cbFile - ((DWORD) dwlDiskFree), szSize, ARRAYSIZE(szSize));
// Load the REs
AthLoadString(idsMigMsgsODSNoDiskSpace, szRes, ARRAYSIZE(szRes));
// Format the Message
wnsprintf(szMsg, ARRAYSIZE(szMsg), szRes, szSize, szStoreRoot);
// Display the Message
AthMessageBox(NULL, MAKEINTRESOURCE(idsAthena), szMsg, 0, MB_OK | MB_ICONEXCLAMATION);
// Error Displayed
fErrorDisplayed = TRUE;
// Build
hr = TraceResult(DB_E_DISKFULL);
// Done
goto exit;
}
// Enumerate through subscribed folders....
IF_FAILEXIT(hr = g_pStore->CreateRowset(IINDEX_PRIMARY, 0, &hRowset));
// Loop
while (S_OK == g_pStore->QueryRowset(hRowset, 1, (LPVOID *)&Folder, NULL))
{
// Open the folder
if (Folder.pszFile && SUCCEEDED(g_pStore->OpenFolder(Folder.idFolder, NULL, OPEN_FOLDER_NOCREATE, &pFolder)))
{
// Cleanup
g_pStore->FreeRecord(&Folder);
// Refetch the folderinfo because opening a folder can update the folder info...
IF_FAILEXIT(hr = g_pStore->GetFolderInfo(Folder.idFolder, &Folder));
// Get Extension
pszExt = PathFindExtensionA(Folder.pszFile);
// Get Record Count
IF_FAILEXIT(hr = pFolder->GetRecordCount(IINDEX_PRIMARY, &cRecords));
// Put the messages into the folder
cTotal += cRecords;
// If not a .dbx file yet
if (NULL == pszExt || lstrcmpi(pszExt, c_szDbxExt) != 0)
{
// Build szSrcFile
IF_FAILEXIT(hr = MakeFilePath(szStoreRoot, Folder.pszFile, c_szEmpty, szSrcFile, sizeof(szSrcFile)));
// Release
SafeRelease(pFolder);
// Build Friendly Name
IF_FAILEXIT(hr = BuildFriendlyFolderFileName(szStoreRoot, &Folder, szDstFile, ARRAYSIZE(szDstFile), NULL, NULL));
// Delete the Dest
DeleteFile(szDstFile);
// Store
if (0 == MoveFile(szSrcFile, szDstFile))
{
hr = TraceResult(E_FAIL);
goto exit;
}
// Get the new pszFile...
Folder.pszFile = PathFindFileName(szDstFile);
// Update the Record
IF_FAILEXIT(hr = g_pStore->UpdateRecord(&Folder));
}
// Release
SafeRelease(pFolder);
}
// Otherwise, if there is a file name, lets reset it
else if (Folder.pszFile)
{
// Cleanup
g_pStore->FreeRecord(&Folder);
// Refetch the folderinfo because opening a folder can update the folder info...
IF_FAILEXIT(hr = g_pStore->GetFolderInfo(Folder.idFolder, &Folder));
// Get the new pszFile...
Folder.pszFile = NULL;
// Update the Record
IF_FAILEXIT(hr = g_pStore->UpdateRecord(&Folder));
}
// Cleanup
g_pStore->FreeRecord(&Folder);
}
// Get the Title
AthLoadString(idsMigDBXTitle, szRes, ARRAYSIZE(szRes));
// Create a Progress Meter...
cProgress.Init(NULL, szRes, NULL, cTotal, idanCompact, FALSE);
// Show the Progress
cProgress.Show();
// Seek the rowset
IF_FAILEXIT(hr = g_pStore->SeekRowset(hRowset, SEEK_ROWSET_BEGIN, 0, NULL));
// Loop
while (S_OK == g_pStore->QueryRowset(hRowset, 1, (LPVOID *)&Folder, NULL))
{
// Open the folder
if (Folder.pszFile && SUCCEEDED(g_pStore->OpenFolder(Folder.idFolder, NULL, OPEN_FOLDER_NOCREATE, &pFolder)))
{
// Set the Message
cProgress.SetMsg(Folder.pszName);
// Put the messages into the folder
IF_FAILEXIT(hr = PutMessagesIntoFolder(&cProgress, pStreams, pFolder));
// Release
SafeRelease(pFolder);
}
// Better not have a file
else
Assert(NULL == Folder.pszFile);
// Cleanup
g_pStore->FreeRecord(&Folder);
}
// Release the Streams File so that I can delete it
SafeRelease(pStreams);
// Delete messages.ods
DeleteFile(szMessagesFile);
exit:
// Cleanup
SafeRelease(pStreams);
SafeRelease(pFolder);
g_pStore->CloseRowset(&hRowset);
g_pStore->FreeRecord(&Folder);
// Show an Error
if (FAILED(hr) && FALSE == fErrorDisplayed)
{
// Show an Error
AthErrorMessageW(NULL, MAKEINTRESOURCEW(idsAthenaMail), MAKEINTRESOURCEW(idsMigMsgsODSError), hr);
}
// Done
return(hr);
}
//----------------------------------------------------------------------------------
// GetFolderIdFromMsgTable
//----------------------------------------------------------------------------------
HRESULT GetFolderIdFromMsgTable(IMessageTable *pTable, LPFOLDERID pidFolder)
{
// Locals
HRESULT hr=S_OK;
IMessageFolder *pFolder=NULL;
IServiceProvider *pService=NULL;
// Trace
TraceCall("GetFolderIdFromMsgTable");
// Invalid Args
Assert(pTable && pidFolder);
// Get IServiceProvider
IF_FAILEXIT(hr = pTable->QueryInterface(IID_IServiceProvider, (LPVOID *)&pService));
// Get IID_IMessageFolder
IF_FAILEXIT(hr = pService->QueryService(IID_IMessageFolder, IID_IMessageFolder, (LPVOID *)&pFolder));
// Get the Folder id
IF_FAILEXIT(hr = pFolder->GetFolderId(pidFolder));
exit:
// Cleanup
SafeRelease(pFolder);
SafeRelease(pService);
// Done
return(hr);
}
//----------------------------------------------------------------------------------
// EmptyMessageFolder
//----------------------------------------------------------------------------------
HRESULT EmptyMessageFolder(LPFOLDERINFO pFolder, BOOL fReset, CProgress *pProgress)
{
// Locals
HRESULT hr=S_OK;
CMessageFolder *pObject=NULL;
// Trace
TraceCall("EmptyMessageFolder");
// Invalid Args
Assert(pFolder);
// If not a server
if (ISFLAGSET(pFolder->dwFlags, FOLDER_SERVER))
goto exit;
// Root
if (FOLDERID_ROOT == pFolder->idFolder)
goto exit;
// No File
if (NULL == pFolder->pszFile)
goto exit;
// New CMessageFolder
IF_NULLEXIT(pObject = new CMessageFolder);
// Open the folder
if (FAILED(pObject->Initialize(g_pStore, NULL, OPEN_FOLDER_NOCREATE, pFolder->idFolder)))
goto exit;
// If this is a news folder ?
if (fReset)
{
// Update pFolder
pFolder->dwClientHigh = pFolder->dwClientLow = 0;
pFolder->dwNotDownloaded = 0;
pFolder->Requested.cbSize = 0;
pFolder->Requested.pBlobData = NULL;
// Update the Folder
IF_FAILEXIT(hr = g_pStore->UpdateRecord(pFolder));
}
// Delete All Record
IF_FAILEXIT(hr = pObject->DeleteMessages(DELETE_MESSAGE_NOPROMPT | DELETE_MESSAGE_NOTRASHCAN, NULL, NULL, (IStoreCallback *)pProgress));
exit:
// Cleanup
SafeRelease(pObject);
// Done
return(hr);
}
//----------------------------------------------------------------------------------
// DeleteAllRecords
//----------------------------------------------------------------------------------
HRESULT DeleteAllRecords(LPCTABLESCHEMA pSchema, IDatabase *pDB,
CProgress *pProgress)
{
// Locals
HRESULT hr=S_OK;
LPVOID pBinding=NULL;
HROWSET hRowset=NULL;
HLOCK hNotifyLock=NULL;
// Trace
TraceCall("DeleteAllRecords");
// Lock Down Notifications
pDB->LockNotify(NOFLAGS, &hNotifyLock);
// Allocate a record
IF_NULLEXIT(pBinding = ZeroAllocate(pSchema->cbBinding));
// Create a Rowset
IF_FAILEXIT(hr = pDB->CreateRowset(IINDEX_PRIMARY, NOFLAGS, &hRowset));
// While we have a node address
while (S_OK == pDB->QueryRowset(hRowset, 1, (LPVOID *)pBinding, NULL))
{
// Delete this record
IF_FAILEXIT(hr = pDB->DeleteRecord(pBinding));
// Free Record Data
pDB->FreeRecord(pBinding);
// Do Progress
if (pProgress)
{
// Do Some Progress
IF_FAILEXIT(hr = pProgress->HrUpdate(1));
}
}
exit:
// Cleanup
if (pBinding)
{
pDB->FreeRecord(pBinding);
g_pMalloc->Free(pBinding);
}
// Close Rowset
pDB->CloseRowset(&hRowset);
// Lock Down Notifications
pDB->UnlockNotify(&hNotifyLock);
// Done
return(hr);
}
// --------------------------------------------------------------------------------
// GetFolderServerId
// --------------------------------------------------------------------------------
HRESULT GetFolderServerId(FOLDERID idFolder, LPFOLDERID pidServer)
{
// Locals
HRESULT hr=S_OK;
FOLDERINFO Server={0};
// Trace
TraceCall("GetFolderServerId");
// Get the Server Info
IF_FAILEXIT(hr = GetFolderServer(idFolder, &Server));
// Return Server
*pidServer = Server.idFolder;
exit:
// Cleanup
g_pStore->FreeRecord(&Server);
// Done
return(hr);
}
//----------------------------------------------------------------------------------
// GetFolderServer
//----------------------------------------------------------------------------------
HRESULT GetFolderServer(FOLDERID idFolder, LPFOLDERINFO pServer)
{
// Locals
HRESULT hr=S_OK;
// Trace
TraceCall("GetFolderServer");
// Walk the Parent Chain
while (1)
{
// Get Folder Info
hr = g_pStore->GetFolderInfo(idFolder, pServer);
if (FAILED(hr))
goto exit;
// Is this a server ?
if (ISFLAGSET(pServer->dwFlags, FOLDER_SERVER))
goto exit;
// Set Next
idFolder = pServer->idParent;
// Free
g_pStore->FreeRecord(pServer);
}
exit:
// Done
return(hr);
}
//----------------------------------------------------------------------------------
// GetFolderType
//----------------------------------------------------------------------------------
FOLDERTYPE GetFolderType(FOLDERID idFolder)
{
// Locals
FOLDERINFO Folder;
// Trace
TraceCall("GetFolderType");
// Get Folder Info
if (SUCCEEDED(g_pStore->GetFolderInfo(idFolder, &Folder)))
{
// Get the Type
FOLDERTYPE tyFolder = Folder.tyFolder;
// Cleanup
g_pStore->FreeRecord(&Folder);
// Done
return(tyFolder);
}
// Done
return(FOLDER_ROOTNODE);
}
//----------------------------------------------------------------------------------
// FHasChildren
//----------------------------------------------------------------------------------
BOOL FHasChildren(LPFOLDERINFO pFolder, BOOL fSubscribed)
{
// Locals
HRESULT hr=S_OK;
BOOL fHasChildren=FALSE;
FOLDERINFO Folder;
IEnumerateFolders *pChildren=NULL;
// Trace
TraceCall("FHasChildren");
// Create Enumerator
IF_FAILEXIT(hr = g_pStore->EnumChildren(pFolder->idFolder, fSubscribed, &pChildren));
// Get first row
if (S_OK == pChildren->Next(1, &Folder, NULL))
{
// Has Children
fHasChildren = TRUE;
// Free Record
g_pStore->FreeRecord(&Folder);
}
exit:
// Cleanup
SafeRelease(pChildren);
// Done
return(fHasChildren);
}
//----------------------------------------------------------------------------------
// GetFolderAccountId
//----------------------------------------------------------------------------------
HRESULT GetFolderAccountId(LPFOLDERINFO pFolder, LPSTR pszAccountId, DWORD cchSize)
{
Assert(g_pStore);
if (!g_pStore)
return E_UNEXPECTED;
// Locals
HRESULT hr=S_OK;
FOLDERINFO Server={0};
// Trace
TraceCall("GetFolderAccountId");
// Args
Assert(pFolder && pszAccountId);
// If this is a server
if (ISFLAGSET(pFolder->dwFlags, FOLDER_SERVER))
{
// Validate
Assert(!FIsEmptyA(pFolder->pszAccountId));
// Copy It
StrCpyN(pszAccountId, pFolder->pszAccountId, cchSize);
// Done
goto exit;
}
// Validate
Assert(FIsEmptyA(pFolder->pszAccountId));
// Get Server Info
IF_FAILEXIT(hr = GetFolderServer(pFolder->idFolder, &Server));
// Copy Account Id
if (FIsEmptyA(Server.pszAccountId))
{
hr = TraceResult(E_FAIL);
goto exit;
}
// Copy It
StrCpyN(pszAccountId, Server.pszAccountId, cchSize);
exit:
// Cleanup
g_pStore->FreeRecord(&Server);
// Done
return(hr);
}
//----------------------------------------------------------------------------------
// CreateMessageServerType
//----------------------------------------------------------------------------------
HRESULT CreateMessageServerType(FOLDERTYPE tyFolder, IMessageServer **ppServer)
{
// Locals
HRESULT hr=S_OK;
IUnknown *pUnknown=NULL;
// Trace
TraceCall("CreateMessageServerType");
// Handle Folder
switch(tyFolder)
{
case FOLDER_NEWS:
IF_FAILEXIT(hr = CreateNewsStore(NULL, &pUnknown));
break;
case FOLDER_IMAP:
IF_FAILEXIT(hr = CreateImapStore(NULL, &pUnknown));
break;
case FOLDER_HTTPMAIL:
IF_FAILEXIT(hr = CreateHTTPMailStore(NULL, &pUnknown));
break;
default:
hr = TraceResult(E_FAIL);
goto exit;
}
// QI Unknown
IF_FAILEXIT(hr = pUnknown->QueryInterface(IID_IMessageServer, (LPVOID *)ppServer));
exit:
// Cleanup
SafeRelease(pUnknown);
// Done
return(hr);
}
//----------------------------------------------------------------------------------
// GetDefaultServerId
//----------------------------------------------------------------------------------
HRESULT GetDefaultServerId(ACCTTYPE tyAccount, LPFOLDERID pidServer)
{
// Locals
HRESULT hr=S_OK;
IImnAccount *pAccount=NULL;
FOLDERID idServer;
DWORD dwServers;
CHAR szAcctId[CCHMAX_ACCOUNT_NAME];
// Trace
TraceCall("GetDefaultServerId");
// Invalid Args
Assert(pidServer);
// Get the Default Account
IF_FAILEXIT(hr = g_pAcctMan->GetDefaultAccount(tyAccount, &pAccount));
// Get Server Types
IF_FAILEXIT(hr = pAccount->GetServerTypes(&dwServers));
// If POP3, special case to the local store
if (ISFLAGSET(dwServers, SRV_POP3))
{
// Set Id
*pidServer = FOLDERID_LOCAL_STORE;
// Done
goto exit;
}
// Get the Account Id
IF_FAILEXIT(hr = pAccount->GetPropSz(AP_ACCOUNT_ID, szAcctId, ARRAYSIZE(szAcctId)));
// Get the Server Id
IF_FAILEXIT(hr = g_pStore->FindServerId(szAcctId, pidServer));
exit:
// Cleanup
SafeRelease(pAccount);
// Done
return(hr);
}
//----------------------------------------------------------------------------------
// IsSubFolder
//----------------------------------------------------------------------------------
HRESULT IsSubFolder(FOLDERID idFolder, FOLDERID idParent)
{
// Locals
HRESULT hr = S_OK;
FOLDERINFO Folder={0};
FOLDERID idCurrent = idFolder;
// Trace
TraceCall("IsSubFolder");
// Invalid Args
Assert(idFolder != FOLDERID_INVALID);
Assert(idParent != FOLDERID_INVALID);
// Walk up the parent chain
while (SUCCEEDED(hr = g_pStore->GetFolderInfo(idCurrent, &Folder)))
{
// Done ?
if (Folder.idParent == idParent)
{
// Cleanup
g_pStore->FreeRecord(&Folder);
// Done
break;
}
// Goto Parent
idCurrent = Folder.idParent;
// Cleanup
g_pStore->FreeRecord(&Folder);
#ifdef _WIN64
INT_PTR p = (INT_PTR) idCurrent;
INT_PTR n = (INT_PTR) FOLDERID_INVALID;
if ((((int) p) & 0xffffffff) == (((int) n) & 0xffffffff))
#else
if (idCurrent == FOLDERID_INVALID)
#endif // _WIN64
{
hr = S_FALSE;
break;
}
}
// Done
return(hr);
}
//----------------------------------------------------------------------------------
// GetMessageInfo
//----------------------------------------------------------------------------------
HRESULT GetMessageInfo(IDatabase *pDB, MESSAGEID idMessage,
LPMESSAGEINFO pInfo)
{
// Locals
HRESULT hr=S_OK;
// Trace
TraceCall("GetMessageInfo");
// Set pInfo
pInfo->idMessage = idMessage;
// Return
IF_FAILEXIT(hr = pDB->FindRecord(IINDEX_PRIMARY, COLUMNS_ALL, pInfo, NULL));
// Not Found
if (DB_S_NOTFOUND == hr)
{
hr = DB_E_NOTFOUND;
goto exit;
}
// Found
hr = S_OK;
exit:
// Done
return(hr);
}
//----------------------------------------------------------------------------------
// GetFolderIdFromName
//----------------------------------------------------------------------------------
HRESULT GetFolderIdFromName(IMessageStore *pStore, LPCSTR pszName, FOLDERID idParent,
LPFOLDERID pidFolder)
{
// Locals
HRESULT hr=S_OK;
FOLDERINFO Folder={0};
// Trace
TraceCall("GetFolderIdFromName");
// Invalid Args
if (NULL == pszName)
return TraceResult(E_INVALIDARG);
// Initialize
*pidFolder = FOLDERID_INVALID;
// Fill Folder
Folder.idParent = idParent;
Folder.pszName = (LPSTR)pszName;
// Do a Find Record
IF_FAILEXIT(hr = pStore->FindRecord(IINDEX_ALL, COLUMNS_ALL, &Folder, NULL));
// Not Found
if (DB_S_NOTFOUND == hr)
{
hr = DB_E_NOTFOUND;
goto exit;
}
// Return
*pidFolder = Folder.idFolder;
exit:
// Cleanup
pStore->FreeRecord(&Folder);
// Done
return hr;
}
//----------------------------------------------------------------------------------
// GetFolderStoreInfo
//----------------------------------------------------------------------------------
HRESULT GetFolderStoreInfo(FOLDERID idFolder, LPFOLDERINFO pStore)
{
// Locals
HRESULT hr=S_OK;
FOLDERID idCurrent=idFolder;
FOLDERINFO Folder={0};
// Trace
TraceCall("GetFolderStoreInfo");
// Walk the Parent Chain
while (1)
{
// Get Current Folder Info
IF_FAILEXIT(hr = g_pStore->GetFolderInfo(idCurrent, &Folder));
// No Parent
if (ISFLAGSET(Folder.dwFlags, FOLDER_SERVER))
{
// Copy to pStore
CopyMemory(pStore, &Folder, sizeof(FOLDERINFO));
// Don't Free It
ZeroMemory(&Folder, sizeof(FOLDERINFO));
// Done
goto exit;
}
// Goto Parent
idCurrent = Folder.idParent;
// Cleanup
g_pStore->FreeRecord(&Folder);
}
exit:
// Cleanup
g_pStore->FreeRecord(&Folder);
// Done
return hr;
}
//----------------------------------------------------------------------------------
// GetFolderIcon
//----------------------------------------------------------------------------------
int GetFolderIcon(FOLDERID idFolder, BOOL fNoStateIcons)
{
// Locals
HRESULT hr=S_OK;
int iIcon=iFolderClosed;
FOLDERINFO Folder={0};
// Trace
TraceCall("GetFolderIcon");
// Get Info
IF_FAILEXIT(hr = g_pStore->GetFolderInfo(idFolder, &Folder));
// Get the Icon
iIcon = GetFolderIcon(&Folder);
exit:
// Cleanup
g_pStore->FreeRecord(&Folder);
// Done
return iIcon;
}
//----------------------------------------------------------------------------------
// GetFolderIcon
//----------------------------------------------------------------------------------
int GetFolderIcon(LPFOLDERINFO pFolder, BOOL fNoStateIcons)
{
// Locals
int iIcon=iFolderClosed;
// Trace
TraceCall("GetFolderIcon");
// Invalid Args
if (NULL == pFolder)
return TraceResult(E_INVALIDARG);
if (FOLDER_ROOTNODE == pFolder->tyFolder)
{
if (g_dwAthenaMode & MODE_NEWSONLY)
{
iIcon = iNewsRoot;
}
else
{
iIcon = iMailNews;
}
}
// News
else if (FOLDER_NEWS == pFolder->tyFolder)
{
// New Server ?
if (ISFLAGSET(pFolder->dwFlags, FOLDER_SERVER))
{
// Subscribed Server
if (ISFLAGSET(pFolder->dwFlags, FOLDER_SUBSCRIBED))
iIcon = iNewsServer;
// Otherwise, non-subscribed new server
else
iIcon = iUnsubServer;
}
// Synchronize...
else if (!fNoStateIcons && !!(pFolder->dwFlags & (FOLDER_DOWNLOADHEADERS | FOLDER_DOWNLOADNEW | FOLDER_DOWNLOADALL)))
iIcon = iNewsGroupSync;
// Subscribed ?
else if (ISFLAGSET(pFolder->dwFlags, FOLDER_SUBSCRIBED))
iIcon = iNewsGroup;
// Otherwise, not subscribed
else
iIcon = iUnsubGroup;
}
// Local Store, IMAP and HTTP servers
else
{
// Local Folders
if (FOLDERID_LOCAL_STORE == pFolder->idFolder)
iIcon = iLocalFolders;
// Mail Server
else if (ISFLAGSET(pFolder->dwFlags, FOLDER_SERVER))
{
// msn branded server
if (ISFLAGSET(pFolder->dwFlags, FOLDER_MSNSERVER))
iIcon = iMsnServer;
// otherwise, generic mail server
else
iIcon = iMailServer;
}
// Not Special
else if (FOLDER_NOTSPECIAL == pFolder->tySpecial)
{
if (!fNoStateIcons && !!(pFolder->dwFlags & (FOLDER_DOWNLOADHEADERS | FOLDER_DOWNLOADNEW | FOLDER_DOWNLOADALL)))
iIcon = iFolderDownload;
else
iIcon = iFolderClosed;
}
// Otherwise, base off of special folder type
// but we don't have a special icon for Bulk mail folder
else if (!fNoStateIcons && !!(pFolder->dwFlags & (FOLDER_DOWNLOADHEADERS | FOLDER_DOWNLOADNEW | FOLDER_DOWNLOADALL)))
iIcon = (iInboxDownload + (((pFolder->tySpecial == FOLDER_BULKMAIL) ? FOLDER_JUNK : pFolder->tySpecial) - 1));
else
iIcon = (iInbox + (((pFolder->tySpecial == FOLDER_BULKMAIL) ? FOLDER_JUNK : pFolder->tySpecial) - 1));
}
// Done
return iIcon;
}
//----------------------------------------------------------------------------------
// GetStoreRootDirectory
//----------------------------------------------------------------------------------
HRESULT GetStoreRootDirectory(LPSTR pszDir, DWORD cchMaxDir)
{
// Locals
HRESULT hr=S_OK;
DWORD cb, cch;
DWORD dwType;
// Trace
TraceCall("GetStoreRootDirectory");
// Get the Root Directory
cb = (cchMaxDir * sizeof(pszDir[0]));
if (ERROR_SUCCESS != AthUserGetValue(NULL, c_szRegStoreRootDir, &dwType, (LPBYTE)pszDir, &cb))
{
hr = TraceResult(E_FAIL);
goto exit;
}
// Expand the string's enviroment vars
if (dwType == REG_EXPAND_SZ)
{
// Locals
CHAR szExpanded[MAX_PATH];
// Expand enviroment strings
cch = ExpandEnvironmentStrings(pszDir, szExpanded, ARRAYSIZE(szExpanded));
// Failure
if (cch == 0 || cch > ARRAYSIZE(szExpanded))
{
hr = TraceResult(E_FAIL);
goto exit;
}
// Copy into szRoot
StrCpyN(pszDir, szExpanded, cchMaxDir);
}
// Get the length
cch = lstrlen(pszDir);
// No root
if (0 == cch)
{
hr = TraceResult(E_FAIL);
goto exit;
}
// Fixup the end
PathRemoveBackslash(pszDir);
// If the directory doesn't exist yet ?
if (FALSE == PathIsDirectory(pszDir))
{
// Our default directory doesn't exist, so create it
IF_FAILEXIT(hr = OpenDirectory(pszDir));
}
exit:
// Done
return hr;
}
//----------------------------------------------------------------------------------
// CreateFolderViewObject
//----------------------------------------------------------------------------------
HRESULT CreateFolderViewObject(FOLDERID idFolder, HWND hwndOwner,
REFIID riid, LPVOID * ppvOut)
{
// Locals
HRESULT hr=S_OK;
FOLDERINFO Folder={0};
// Trace
TraceCall("CreateFolderViewObject");
// Get Folder Info
IF_FAILEXIT(hr = g_pStore->GetFolderInfo(idFolder, &Folder));
// Root Object
if (FOLDERID_ROOT == idFolder)
{
CFrontPage *pFP = new CFrontPage();
if (pFP)
{
if (SUCCEEDED(pFP->HrInit(idFolder)))
{
hr = pFP->QueryInterface(riid, ppvOut);
}
pFP->Release();
}
else
hr = E_OUTOFMEMORY;
}
else if (ISFLAGSET(Folder.dwFlags, FOLDER_SERVER))
{
CAccountView *pAV = new CAccountView();
if (pAV)
{
if (SUCCEEDED(pAV->HrInit(idFolder)))
{
hr = pAV->QueryInterface(riid, ppvOut);
}
pAV->Release();
}
else
hr = E_OUTOFMEMORY;
}
else
{
CMessageView *pMV = new CMessageView();
if (pMV)
{
if (SUCCEEDED(pMV->Initialize(idFolder)))
{
hr = pMV->QueryInterface(riid, ppvOut);
}
pMV->Release();
}
else
hr = E_OUTOFMEMORY;
}
exit:
// Cleanup
g_pStore->FreeRecord(&Folder);
// Done
return hr;
}
//----------------------------------------------------------------------------------
// OpenUidlCache
//----------------------------------------------------------------------------------
HRESULT OpenUidlCache(IDatabase **ppDB)
{
// Locals
HRESULT hr=S_OK;
CHAR szStoreRoot[MAX_PATH];
CHAR szFilePath[MAX_PATH];
IDatabase *pDB=NULL;
// Trace
TraceCall("OpenUidlCache");
// Get Uidcache file path
IF_FAILEXIT(hr = GetStoreRootDirectory(szStoreRoot, sizeof(szStoreRoot)));
// Make File Path
IF_FAILEXIT(hr = MakeFilePath(szStoreRoot, c_szPop3UidlFile, c_szEmpty, szFilePath, sizeof(szFilePath)));
// Allocate Table Object
IF_FAILEXIT(hr = g_pDBSession->OpenDatabase(szFilePath, NOFLAGS, &g_UidlTableSchema, NULL, &pDB));
// Fix the file
SideAssert(SUCCEEDED(FixPOP3UIDLFile(pDB)));
// Return It
*ppDB = pDB;
pDB = NULL;
exit:
// Cleanup
SafeRelease(pDB);
// Done
return hr;
}
//----------------------------------------------------------------------------------
// FixPOP3UIDLFile
//----------------------------------------------------------------------------------
const char c_szFixedPOP3UidlFile[] = "FixedPOP3UidlFile";
typedef struct tagSERVERNAME {
CHAR szServer[CCHMAX_SERVER_NAME];
CHAR szAccountId[CCHMAX_ACCOUNT_NAME];
} SERVERNAME, *LPSERVERNAME;
HRESULT FixPOP3UIDLFile(IDatabase *pDB)
{
// Locals
HRESULT hr=S_OK;
DWORD fFixed=FALSE;
DWORD cb;
DWORD dwType;
IImnAccount *pAccount=NULL;
IImnEnumAccounts *pEnum=NULL;
DWORD dwTemp;
DWORD cServers;
LPSERVERNAME prgServerName=NULL;
HROWSET hRowset=NULL;
UIDLRECORD UidlInfo={0};
DWORD i;
// Trace
TraceCall("FixPOP3UIDLFile");
// Need to fixup the UIDL cache ?
cb = sizeof(fFixed);
if (ERROR_SUCCESS != AthUserGetValue(NULL, c_szFixedPOP3UidlFile, &dwType, (LPBYTE)&fFixed, &cb))
fFixed = FALSE;
else if (fFixed)
return(S_OK);
// First try to see if we can find such a server.
IF_FAILEXIT(hr = g_pAcctMan->Enumerate(SRV_POP3, &pEnum));
// Count
IF_FAILEXIT(hr = pEnum->GetCount(&cServers));
// If no POP3 servers
if (0 == cServers)
{
// Delete all the records...
IF_FAILEXIT(hr = pDB->CreateRowset(IINDEX_PRIMARY, 0, &hRowset));
// Loop
while (S_OK == pDB->QueryRowset(hRowset, 1, (LPVOID *)&UidlInfo, NULL))
{
// Delete the Record
pDB->DeleteRecord(&UidlInfo);
// Free It
pDB->FreeRecord(&UidlInfo);
}
// Fixed
fFixed = TRUE;
// Done
goto exit;
}
// Allocate
IF_NULLEXIT(prgServerName = (LPSERVERNAME)g_pMalloc->Alloc(cServers * sizeof(SERVERNAME)));
// Reset cServers
cServers = 0;
// Enumerate the POP3 servers
while (SUCCEEDED(pEnum->GetNext(&pAccount)))
{
// Get the server name
if (SUCCEEDED(pAccount->GetPropSz(AP_POP3_SERVER, prgServerName[cServers].szServer, ARRAYSIZE(prgServerName[cServers].szServer))))
{
// Get the pop3 username
if (SUCCEEDED(pAccount->GetPropSz(AP_ACCOUNT_ID, prgServerName[cServers].szAccountId, ARRAYSIZE(prgServerName[cServers].szAccountId))))
{
// Increment
cServers++;
}
}
// Release the Account
SafeRelease(pAccount);
}
// Delete all the records...
IF_FAILEXIT(hr = pDB->CreateRowset(IINDEX_PRIMARY, 0, &hRowset));
// Loop
while (S_OK == pDB->QueryRowset(hRowset, 1, (LPVOID *)&UidlInfo, NULL))
{
// Does UidlInfo.pszServer exist in prgServerName
if (UidlInfo.pszServer)
{
// Delete the Record
pDB->DeleteRecord(&UidlInfo);
// Reset fExist
for (i=0; i<cServers; i++)
{
// Is this it
if (lstrcmpi(UidlInfo.pszServer, prgServerName[i].szServer) == 0)
{
// Update the Record
UidlInfo.pszAccountId = prgServerName[i].szAccountId;
// Update the Record
pDB->InsertRecord(&UidlInfo);
}
}
}
// Free It
pDB->FreeRecord(&UidlInfo);
}
// Compact
pDB->Compact(NULL, 0);
// Fixed
fFixed = TRUE;
exit:
// Cleanup
if (pDB && hRowset)
pDB->CloseRowset(&hRowset);
SafeRelease(pAccount);
SafeRelease(pEnum);
SafeMemFree(prgServerName);
// Set the Value
SideAssert(ERROR_SUCCESS == AthUserSetValue(NULL, c_szFixedPOP3UidlFile, REG_DWORD, (LPBYTE)&fFixed, sizeof(fFixed)));
// Done
return(hr);
}
//----------------------------------------------------------------------------------
// SetStoreDirectory
//----------------------------------------------------------------------------------
HRESULT SetStoreDirectory(
/* in */ LPCSTR pszRoot)
{
// Locals
HRESULT hr=S_OK;
LPCSTR psz;
CHAR szProfile[MAX_PATH];
DWORD cb;
DWORD type;
// Trace
TraceCall("SetStoreDirectory");
// Invalid Args
Assert(pszRoot);
// Bad Root
if (lstrlen(pszRoot) >= MAX_PATH || FIsEmptyA(pszRoot))
{
hr = TraceResult(E_INVALIDARG);
goto exit;
}
type = AddEnvInPath(pszRoot, szProfile, ARRAYSIZE(szProfile)) ? REG_EXPAND_SZ : REG_SZ;
// Store the Value in the Registry
if (ERROR_SUCCESS != AthUserSetValue(NULL, c_szRegStoreRootDir, type, (LPBYTE)szProfile, lstrlen(szProfile) + 1))
{
hr = TraceResult(E_FAIL);
goto exit;
}
exit:
// Done
return hr;
}
//----------------------------------------------------------------------------------
// InitializeLocalStoreDirectory
//----------------------------------------------------------------------------------
HRESULT InitializeLocalStoreDirectory(
/* in */ HWND hwndOwner,
/* in */ BOOL fNoCreate)
{
// Locals
HRESULT hr=S_OK;
CHAR szPath[MAX_PATH];
// Trace
TraceCall("InitializeLocalStoreDirectory");
// Get root directory
if (SUCCEEDED(GetStoreRootDirectory(szPath, ARRAYSIZE(szPath))))
goto exit;
// Don't create
if (fNoCreate)
{
hr = TraceResult(E_FAIL);
goto exit;
}
// Get Default Root
IF_FAILEXIT(hr = GetDefaultStoreRoot(hwndOwner, szPath, ARRAYSIZE(szPath)));
// If the directory doesn't exist yet ?
if (FALSE == PathIsDirectory(szPath))
{
// Our default directory doesn't exist, so create it
IF_FAILEXIT(hr = OpenDirectory(szPath));
}
// Set the Store Directory
IF_FAILEXIT(hr = SetStoreDirectory(szPath));
exit:
// Done
return hr;
}
//----------------------------------------------------------------------------------
// CloneMessageIDList
//----------------------------------------------------------------------------------
HRESULT CloneMessageIDList(LPMESSAGEIDLIST pSourceList, LPMESSAGEIDLIST *ppNewList)
{
LPMESSAGEIDLIST pNewList = NULL;
LPMESSAGEID pNewMsgIDArray = NULL;
BOOL fResult;
TraceCall("CloneMessageIDList");
Assert(NULL != ppNewList);
if (NULL == pSourceList)
{
*ppNewList = NULL;
return S_OK;
}
// Init return values
*ppNewList = NULL;
if (!MemAlloc((LPVOID *)&pNewList, sizeof(MESSAGEIDLIST) + pSourceList->cMsgs * sizeof(MESSAGEID)))
return TraceResult(E_OUTOFMEMORY);
// Fill in fields, allocate and copy prgidMsg array
pNewList->cAllocated = 0;
pNewList->cMsgs = pSourceList->cMsgs;
pNewMsgIDArray = (LPMESSAGEID)((LPBYTE)pNewList + sizeof(MESSAGEIDLIST));
CopyMemory(pNewMsgIDArray, pSourceList->prgidMsg, pSourceList->cMsgs * sizeof(MESSAGEID));
pNewList->prgidMsg = pNewMsgIDArray;
*ppNewList = pNewList;
return S_OK;
}
HRESULT CloneAdjustFlags(LPADJUSTFLAGS pFlags, LPADJUSTFLAGS *ppNewFlags)
{
LPADJUSTFLAGS pNewFlags;
if (!MemAlloc((LPVOID *)&pNewFlags, sizeof(ADJUSTFLAGS)))
return TraceResult(E_OUTOFMEMORY);
CopyMemory(pNewFlags, pFlags, sizeof(ADJUSTFLAGS));
*ppNewFlags = pNewFlags;
return S_OK;
}
//----------------------------------------------------------------------------------
// ConnStateIsEqual
//----------------------------------------------------------------------------------
BOOL ConnStateIsEqual(IXPSTATUS ixpStatus, CONNECT_STATE csState)
{
BOOL fResult = FALSE;
TraceCall("ConnStateIsEqual");
switch (csState)
{
case CONNECT_STATE_CONNECT:
// Remember IXP_CONNECTED doesn't necessarily mean we're authenticated
if (IXP_AUTHORIZED == ixpStatus)
fResult = TRUE;
break;
case CONNECT_STATE_DISCONNECT:
if (IXP_DISCONNECTED == ixpStatus)
fResult = TRUE;
break;
default:
AssertSz(FALSE, "I've never heard of this CONNECT_STATE!");
break;
} // switch
return fResult;
}
//----------------------------------------------------------------------------------
// RelocateStoreDirectory
//----------------------------------------------------------------------------------
// Extensions associated with OE v5 Store
const static TCHAR *rgszWildCards[] =
{
"*.dbx",
"*.dbl",
"*.log",
};
// Lengths of the above strings
const static int rgcchWilds[] =
{
5,
5,
5,
};
// Build a string of the form:
// C:\\foo\\*.bar\0C:\\foo\\*.car\0\0
// Return E_FAIL if we run out of memory
// Return S_FALSE if there are no *.bar or *.car files in C:\foo
// Return S_OK otherwise
HRESULT GenerateWildCards(LPTSTR pszBuf, DWORD cchBuf, LPTSTR pszSource, DWORD cchSource)
{
UINT i;
DWORD cchWildCard = 0;
HRESULT hr = S_FALSE;
WIN32_FIND_DATA fd;
HANDLE hFound;
TCHAR szTempBuf[MAX_PATH];
BOOL fFound;
DWORD cchOrig;
// Form common root
if(lstrlen(pszSource) >= sizeof(szTempBuf) / sizeof(szTempBuf[0])) return E_FAIL;
StrCpyN(szTempBuf,pszSource, ARRAYSIZE(szTempBuf));
if (_T('\\') == *CharPrev(szTempBuf, szTempBuf + cchSource))
// Avoid \\foo and \_foo
cchSource--;
else
szTempBuf[cchSource] = _T('\\');
// Go through list of extensions we are interested in
for (i = 0; i < ARRAYSIZE(rgszWildCards); i++)
{
// Add the extension to the common root
StrCpyN(&szTempBuf[cchSource+1], rgszWildCards[i],ARRAYSIZE(szTempBuf)-cchSource-1);
// Should we bother with this wildcard?
fFound = FALSE;
hFound = FindFirstFile(szTempBuf, &fd);
if (INVALID_HANDLE_VALUE != hFound)
{
do
{
if (!ISFLAGSET(fd.dwFileAttributes, FILE_ATTRIBUTE_DIRECTORY))
fFound = TRUE;
}
while (!fFound && FindNextFile(hFound, &fd));
FindClose(hFound);
if (fFound)
{
// Do we have enough space for this wildcard?
// 3 = 1 for slash + 2 for double null termination
if (cchWildCard + cchSource + rgcchWilds[i] + 3 > cchBuf)
{
hr = TraceResult(E_FAIL);
goto exit;
}
hr = S_OK;
// Add extension to the list
StrCpyN(&pszBuf[cchWildCard], szTempBuf, cchBuf-cchWildCard);
// 2 = 1 for slash + 1 to skip over NULL
cchWildCard += cchSource + rgcchWilds[i] + 2;
}
}
}
// Double Null-term
pszBuf[cchWildCard] = '\0';
exit:
return hr;
}
HRESULT RelocateStoreDirectory(HWND hwnd, LPCSTR pszDstDir, BOOL fMove)
{
// Locals
HRESULT hr=S_OK;
HRESULT hrT;
DWORD cchDstDir;
DWORD cchSrcDir;
CHAR szWildCard[MAX_PATH * ARRAYSIZE(rgszWildCards)];
CHAR szSrcDir[MAX_PATH];
CHAR szDstDir[MAX_PATH];
CHAR szDrive[4] = "x:\\";
CHAR szRes[255];
SHFILEOPSTRUCT op;
BOOL fSome;
Assert(pszDstDir && *pszDstDir);
// Trace
TraceCall("RelocateStoreDirectory");
// Get the Current Root Store Location (won't have trailing slash)
IF_FAILEXIT(hr = GetStoreRootDirectory(szWildCard, ARRAYSIZE(szWildCard)));
// Make a copy of pszDstDir, stripping out any relative path padding
PathCanonicalize(szDstDir, pszDstDir);
// Make sure the destination directory exists (it came from the reg...)
IF_FAILEXIT(hr=OpenDirectory(szDstDir));
// Strip out any relative path padding
PathCanonicalize(szSrcDir, szWildCard);
// Get Dest Dir Length
cchDstDir = lstrlen(szDstDir);
// Remove any slash termination
if (_T('\\') == *CharPrev(szDstDir, szDstDir+cchDstDir))
szDstDir[--cchDstDir] = 0;
// BUGBUG: This isn't a very thorough test...
// Source and Destination are the Same ?
if (lstrcmpi(szSrcDir, szDstDir) == 0)
{
hr = TraceResult(S_FALSE);
goto exit;
}
// Get Source Dir Length
cchSrcDir = lstrlen(szSrcDir);
// Normally, GetStoreRootDir should have have removed the backslash
// But maybe we move to C:\
//Assert(*CharPrev(szSrcDir, szSrcDir+cchSrcDir) != _T('\\'));
// Set Drive Number
szDrive[0] = szDstDir[0];
// If destination is not a fixed drive, failure
if (DRIVE_FIXED != GetDriveType(szDrive))
{
hr = TraceResult(S_FALSE);
goto exit;
}
if (fMove)
{
// Enough space for one more character
if (cchSrcDir + 2 >= ARRAYSIZE(szSrcDir))
{
hr = TraceResult(S_FALSE);
goto exit;
}
// Double Null-term
szSrcDir[cchSrcDir + 1] = _T('\0');
// Validate
Assert(szSrcDir[cchSrcDir] == _T('\0') && szSrcDir[cchSrcDir + 1] == _T('\0'));
// Enough space for one more character
if (cchDstDir + 1 >= ARRAYSIZE(szDstDir))
{
// This is never going to work so tell caller not to bother us again
hr = TraceResult(S_FALSE);
goto exit;
}
// Double Null-term
szDstDir[cchDstDir + 1] = '\0';
// Validate
Assert(szDstDir[cchDstDir] == '\0' && szDstDir[cchDstDir + 1] == '\0');
hrT = GenerateWildCards(szWildCard, ARRAYSIZE(szWildCard), szDstDir, cchDstDir);
if (FAILED(hrT))
{
hr = TraceResult(S_FALSE);
goto exit;
}
else if (S_OK == hrT)
{
// Delete the Files from the target location
ZeroMemory(&op, sizeof(SHFILEOPSTRUCT));
op.hwnd = hwnd;
op.wFunc = FO_DELETE;
op.fFlags = FOF_SILENT | FOF_NOCONFIRMATION | FOF_FILESONLY | FOF_NORECURSION;
op.pFrom = szWildCard;
op.fAnyOperationsAborted = FALSE;
// Delete the files
if (SHFileOperation(&op) != 0)
{
hr = TraceResult(E_FAIL);
goto exit;
}
}
// Make the file source paths
hrT = GenerateWildCards(szWildCard, ARRAYSIZE(szWildCard), szSrcDir, cchSrcDir);
if (FAILED(hrT))
{
hr = TraceResult(S_FALSE);
goto exit;
}
else if (S_OK == hrT)
{
// Load the Progress String
LoadString(g_hLocRes, idsMoveStoreProgress, szRes, ARRAYSIZE(szRes));
// Setup for the file move operation
ZeroMemory(&op, sizeof(SHFILEOPSTRUCT));
op.hwnd = hwnd;
op.wFunc = FO_COPY;
op.fFlags = FOF_NOCONFIRMMKDIR | FOF_SIMPLEPROGRESS | FOF_FILESONLY | FOF_NORECURSION;
op.lpszProgressTitle = szRes;
op.fAnyOperationsAborted = FALSE;
op.pFrom = szWildCard;
op.pTo = szDstDir;
// Did that succeed and was not aborted
if (SHFileOperation(&op) == 0 && FALSE == op.fAnyOperationsAborted)
{
// Update the Store Root Directory
// Use original string
SideAssert(SUCCEEDED(SetStoreDirectory(pszDstDir)));
}
// Canceled
else
{
// Failure ?
hr = (op.fAnyOperationsAborted ? S_FALSE : E_FAIL);
// Delete what we moved
hrT = GenerateWildCards(szWildCard, ARRAYSIZE(szWildCard), szDstDir, cchDstDir);
}
if (S_OK == hrT)
{
// Delete the Files from the original location
op.wFunc = FO_DELETE;
op.fFlags = FOF_SILENT | FOF_NOCONFIRMATION | FOF_FILESONLY | FOF_NORECURSION;
// Delete the files
SHFileOperation(&op);
}
}
else
AssertSz(FALSE, "We're moving the store, but found no store to move!");
}
else
SideAssert(SUCCEEDED(SetStoreDirectory(pszDstDir)));
exit:
// Done
return(hr);
}
//----------------------------------------------------------------------------------
// FlattenHierarchy
//----------------------------------------------------------------------------------
// Not the most efficient way to flatten a hierarchy, but it's quick impl
// Later enhancements can include implementing a stack to flatten hierarchy
// in real-time using enumerator functions
HRESULT FlattenHierarchy(IMessageStore *pStore, FOLDERID idParent,
BOOL fIncludeParent, BOOL fSubscribedOnly,
FOLDERID **pprgFIDArray, LPDWORD pdwAllocated,
LPDWORD pdwUsed)
{
TraceCall("FlattenHierarchy");
Assert(NULL != pStore);
Assert(NULL != pprgFIDArray);
Assert(NULL != pdwAllocated);
Assert(NULL != pdwUsed);
// Initialize values
*pprgFIDArray = NULL;
*pdwAllocated = 0;
*pdwUsed = 0;
return FlattenHierarchyHelper(pStore, idParent, fIncludeParent, fSubscribedOnly,
pprgFIDArray, pdwAllocated, pdwUsed);
} // FlattenHierarchy
HRESULT FlattenHierarchyHelper(IMessageStore *pStore, FOLDERID idParent,
BOOL fIncludeParent, BOOL fSubscribedOnly,
FOLDERID **pprgFIDArray, LPDWORD pdwAllocated,
LPDWORD pdwUsed)
{
HRESULT hrResult = S_OK;
IEnumerateFolders *pEnumFldr = NULL;
TraceCall("FlattenHierarchy");
Assert(NULL != pStore);
Assert(NULL != pprgFIDArray);
Assert(NULL != pdwAllocated);
Assert(NULL != pdwUsed);
Assert(*pdwAllocated >= *pdwUsed);
Assert(*pdwUsed + FIDARRAY_GROW >= *pdwAllocated);
// Check for invalid folder ID's
if (FOLDERID_INVALID == idParent)
{
hrResult = S_OK;
goto exit; // Nothing to do here!
}
// Check if we need to grow the FolderID Array
if (*pdwUsed + 1 > *pdwAllocated)
{
BOOL fResult;
fResult = MemRealloc((void **)pprgFIDArray,
(*pdwAllocated + FIDARRAY_GROW) * sizeof(FOLDERID));
if (FALSE == fResult)
{
hrResult = TraceResult(E_OUTOFMEMORY);
goto exit;
}
*pdwAllocated += FIDARRAY_GROW;
}
// First thing we do is add current node to the ID array
if (fIncludeParent)
{
(*pprgFIDArray)[*pdwUsed] = idParent;
*pdwUsed += 1;
}
// OK, now add child folders
hrResult = pStore->EnumChildren(idParent, fSubscribedOnly, &pEnumFldr);
if (FAILED(hrResult))
{
TraceResult(hrResult);
goto exit;
}
do
{
const BOOL fINCLUDE_PARENT = TRUE;
FOLDERINFO fiFolderInfo;
// Get info on next child folder
hrResult = pEnumFldr->Next(1, &fiFolderInfo, NULL);
if (S_OK != hrResult)
{
TraceError(hrResult);
break;
}
// Recurse on child
hrResult = FlattenHierarchyHelper(pStore, fiFolderInfo.idFolder, fINCLUDE_PARENT,
fSubscribedOnly, pprgFIDArray, pdwAllocated, pdwUsed);
pStore->FreeRecord(&fiFolderInfo);
if (FAILED(hrResult))
{
TraceResult(hrResult);
break;
}
} while (1);
exit:
if (NULL != pEnumFldr)
pEnumFldr->Release();
return hrResult;
} // FlattenHierarchyHelper
HRESULT GetInboxId(IMessageStore *pStore,
FOLDERID idParent,
FOLDERID **pprgFIDArray,
LPDWORD pdwUsed)
{
BOOL fResult;
HRESULT hrResult;
IEnumerateFolders *pEnumFldr = NULL;
Assert(NULL != pStore);
Assert(NULL != pprgFIDArray);
Assert(NULL != pdwUsed);
fResult = MemAlloc((void **)pprgFIDArray, sizeof(FOLDERID));
if (FALSE == fResult)
{
hrResult = TraceResult(E_OUTOFMEMORY);
goto exit;
}
hrResult = pStore->EnumChildren(idParent, FALSE, &pEnumFldr);
if (FAILED(hrResult))
{
TraceResult(hrResult);
goto exit;
}
do
{
FOLDERINFO fiFolderInfo;
// Get info on next child folder
hrResult = pEnumFldr->Next(1, &fiFolderInfo, NULL);
if (S_OK != hrResult)
{
TraceError(hrResult);
break;
}
if (fiFolderInfo.tySpecial == FOLDER_INBOX)
{
(*pprgFIDArray)[*pdwUsed] = fiFolderInfo.idFolder;
*pdwUsed += 1;
break;
}
pStore->FreeRecord(&fiFolderInfo);
} while (1);
exit:
if (NULL != pEnumFldr)
pEnumFldr->Release();
return hrResult;
}
//----------------------------------------------------------------------------------
// RecurseFolderHierarchy
//----------------------------------------------------------------------------------
HRESULT RecurseFolderHierarchy(FOLDERID idFolder, RECURSEFLAGS dwFlags,
DWORD dwReserved, DWORD_PTR dwCookie, PFNRECURSECALLBACK pfnCallback)
{
// Locals
HRESULT hr=S_OK;
FOLDERINFO Folder={0};
DWORD cIndent=dwReserved;
IEnumerateFolders *pChildren=NULL;
// Trace
TraceCall("RecurseFolderHierarchy");
// Include idFolder ?
if (ISFLAGSET(dwFlags, RECURSE_INCLUDECURRENT))
{
// Process idFolder
IF_FAILEXIT(hr = g_pStore->GetFolderInfo(idFolder, &Folder));
// No Local Store
if (!ISFLAGSET(dwFlags, RECURSE_NOLOCALSTORE) || FOLDERID_LOCAL_STORE != Folder.idFolder)
{
// Call the Callback
IF_FAILEXIT(hr = (*(pfnCallback))(&Folder, ISFLAGSET(dwFlags, RECURSE_SUBFOLDERS), cIndent, dwCookie));
}
// Cleanup
g_pStore->FreeRecord(&Folder);
}
// Don't include current anymore
FLAGCLEAR(dwFlags, RECURSE_INCLUDECURRENT);
// Do Sub Folders ?
if (ISFLAGSET(dwFlags, RECURSE_SUBFOLDERS))
{
// No Local Store
if (!ISFLAGSET(dwFlags, RECURSE_NOLOCALSTORE) || FOLDERID_LOCAL_STORE != idFolder)
{
// Create Enumerator for the Children
IF_FAILEXIT(hr = g_pStore->EnumChildren(idFolder, ISFLAGSET(dwFlags, RECURSE_ONLYSUBSCRIBED), &pChildren));
// Loop
while (S_OK == pChildren->Next(1, &Folder, NULL))
{
// No Local Store
if (((!ISFLAGSET(dwFlags, RECURSE_NOLOCALSTORE) || FOLDERID_LOCAL_STORE != Folder.idFolder)) &&
((!ISFLAGSET(dwFlags, RECURSE_ONLYLOCAL) || FOLDER_LOCAL == Folder.tyFolder)) &&
((!ISFLAGSET(dwFlags, RECURSE_ONLYNEWS) || FOLDER_NEWS == Folder.tyFolder)))
{
// Call the Callback
IF_FAILEXIT(hr = (*(pfnCallback))(&Folder, ISFLAGSET(dwFlags, RECURSE_SUBFOLDERS), cIndent, dwCookie));
// Enumerate Children
IF_FAILEXIT(hr = RecurseFolderHierarchy(Folder.idFolder, dwFlags, cIndent + 1, dwCookie, pfnCallback));
}
// Free Folder
g_pStore->FreeRecord(&Folder);
}
}
}
exit:
// Cleanup
g_pStore->FreeRecord(&Folder);
SafeRelease(pChildren);
// Done
return(hr);
}
//----------------------------------------------------------------------------------
// RecurseFolderCounts
//----------------------------------------------------------------------------------
HRESULT RecurseFolderCounts(LPFOLDERINFO pFolder, BOOL fSubFolders,
DWORD cIndent, DWORD_PTR dwCookie)
{
// Locals
LPDWORD pcMsgs=(LPDWORD)dwCookie;
// Trace
TraceCall("RecurseFolderCounts");
// If not a server
if (FALSE == ISFLAGSET(pFolder->dwFlags, FOLDER_SERVER) && FOLDERID_ROOT != pFolder->idFolder)
{
// Increment Max
(*pcMsgs) += pFolder->cMessages;
}
// Done
return(S_OK);
}
//----------------------------------------------------------------------------------
// DoCompactionError
//----------------------------------------------------------------------------------
HRESULT DoCompactionError(HWND hwndParent, LPCSTR pszFolder, LPCSTR pszFile,
BOOL fSubFolders, HRESULT hrError)
{
// Determine Message Box Flags
UINT uAnswer;
UINT uFlags = (fSubFolders ? MB_OKCANCEL | MB_ICONSTOP : MB_OK | MB_ICONSTOP);
CHAR szRes[255];
CHAR szReason[255];
CHAR szMsg[1024];
// Trace
TraceCall("DoCompactionError");
// Should be a failure
Assert(FAILED(hrError));
// Cancel
if (hrUserCancel == hrError)
return(hrUserCancel);
// General message
AthLoadString(idsFailACacheCompact, szRes, ARRAYSIZE(szRes));
// Disk Full
if (hrError == hrDiskFull || hrError == DB_E_DISKFULL)
{
// Load the Disk Full Error
AthLoadString(idsDiskFull, szReason, ARRAYSIZE(szRes));
// Append It to the String
wnsprintf(szMsg, ARRAYSIZE(szMsg), szRes, pszFolder, szReason, pszFile, hrError);
// Show It
uAnswer = AthMessageBox(hwndParent, MAKEINTRESOURCE(idsAthena), szMsg, 0, uFlags);
}
// Access Denied
else if (hrError == DB_E_ACCESSDENIED)
{
// Load the Disk Full Error
AthLoadString(idsDBAccessDenied, szReason, ARRAYSIZE(szRes));
// Append It to the String
wnsprintf(szMsg, ARRAYSIZE(szMsg), szRes, pszFolder, szReason, pszFile, hrError);
// Show It
uAnswer = AthMessageBox(hwndParent, MAKEINTRESOURCE(idsAthena), szMsg, 0, uFlags);
}
// Memory
else if (hrError == hrMemory || hrError == E_OUTOFMEMORY)
{
// Load the Error
AthLoadString(idsMemory, szReason, ARRAYSIZE(szReason));
// Append It to the String
wnsprintf(szMsg, ARRAYSIZE(szMsg), szRes, pszFolder, szReason, pszFile, hrError);
// Show the Error
uAnswer = AthMessageBox(hwndParent, MAKEINTRESOURCE(idsAthena), szMsg, 0, uFlags);
}
// Show general error
else
{
// Load the String
AthLoadString(idsFailACacheCompactReason, szRes, ARRAYSIZE(szRes));
// Append It to the String
wnsprintf(szMsg, ARRAYSIZE(szMsg), szRes, pszFolder, szReason, pszFile, hrError);
// Show the Error
uAnswer = AthMessageBox(hwndParent, MAKEINTRESOURCE(idsAthena), szMsg, 0, uFlags);
}
// Return hrError
return(uAnswer == IDCANCEL ? hrUserCancel : S_OK);
}
//----------------------------------------------------------------------------------
// RecurseCompactFolders
//----------------------------------------------------------------------------------
HRESULT RecurseCompactFolders(LPFOLDERINFO pFolder, BOOL fSubFolders,
DWORD cIndent, DWORD_PTR dwCookie)
{
// Locals
HRESULT hr=S_OK;
IMessageFolder *pFolderObject=NULL;
LPCOMPACTCOOKIE pCompact=(LPCOMPACTCOOKIE)dwCookie;
// Trace
TraceCall("RecurseCompactFolders");
// If not a server
if (ISFLAGSET(pFolder->dwFlags, FOLDER_SERVER))
goto exit;
// Root
if (FOLDERID_ROOT == pFolder->idFolder)
goto exit;
// Open the Folder...
if (FAILED(g_pStore->OpenFolder(pFolder->idFolder, NULL, OPEN_FOLDER_NOCREATE, &pFolderObject)))
goto exit;
// Set Msg
pCompact->pProgress->SetMsg(pFolder->pszName);
// Cleanup this folder
hr = pFolderObject->Compact((IDatabaseProgress *)pCompact->pProgress, 0);
// Failure
if (FAILED(hr))
{
// Do UI
if (pCompact->fUI && hrUserCancel == DoCompactionError(pCompact->hwndParent, pFolder->pszName, pFolder->pszFile, fSubFolders, hr))
goto exit;
}
// Reset hr
hr = S_OK;
exit:
// Cleanup
SafeRelease(pFolderObject);
// Done
return(hr);
}
// --------------------------------------------------------------------------------
// CompactSpecialDatabase
// --------------------------------------------------------------------------------
HRESULT CompactSpecialDatabase(LPCOMPACTCOOKIE pCompact, LPCSTR pszFile,
IDatabase *pDB, UINT idName)
{
// Locals
HRESULT hr=S_OK;
CHAR szRes[255];
// Trace
TraceCall("CompactSpecialDatabase");
// No Database
if (NULL == pDB)
goto exit;
// Load the String
LoadString(g_hLocRes, idName, szRes, ARRAYSIZE(szRes));
// Set Msg
pCompact->pProgress->SetMsg(szRes);
// Cleanup this folder
hr = pDB->Compact((IDatabaseProgress *)pCompact->pProgress, 0);
// Failure
if (FAILED(hr))
{
// Do UI
if (pCompact->fUI && hrUserCancel == DoCompactionError(pCompact->hwndParent, szRes, pszFile, TRUE, hr))
goto exit;
}
// Reset hr
hr = S_OK;
exit:
// Done
return(hr);
}
// --------------------------------------------------------------------------------
// CompactFolders
// --------------------------------------------------------------------------------
HRESULT CompactFolders(HWND hwndParent, RECURSEFLAGS dwRecurse, FOLDERID idFolder)
{
// Locals
HRESULT hr=S_OK;
DWORD cTotal=0;
DWORD cRecords;
CHAR szFilePath[MAX_PATH + MAX_PATH];
CHAR szRootDir[MAX_PATH + MAX_PATH];
CHAR szTitle[255];
COMPACTCOOKIE Compact;
IDatabase *pUidlCache=NULL;
IDatabase *pOffline=NULL;
CProgress *pProgress=NULL;
// Trace
TraceCall("CompactFolders");
// Get the Root Store Directory
IF_FAILEXIT(hr = GetStoreRootDirectory(szRootDir, ARRAYSIZE(szRootDir)));
// Get Folder Counts
IF_FAILEXIT(hr = RecurseFolderHierarchy(idFolder, dwRecurse, 0, (DWORD_PTR)&cTotal, (PFNRECURSECALLBACK)RecurseFolderCounts));
// Compacting All
if (FOLDERID_ROOT == idFolder && ISFLAGSET(dwRecurse, RECURSE_SUBFOLDERS))
{
// Get Folders Record Count
IF_FAILEXIT(hr = g_pStore->GetRecordCount(IINDEX_PRIMARY, &cRecords));
// Increment cTotal
cTotal += cRecords;
// Make File Path
IF_FAILEXIT(hr = MakeFilePath(szRootDir, c_szPop3UidlFile, c_szEmpty, szFilePath, sizeof(szFilePath)));
// If file exists
if (PathFileExists(szFilePath))
{
// Allocate Table Object
IF_FAILEXIT(hr = g_pDBSession->OpenDatabase(szFilePath, NOFLAGS, &g_UidlTableSchema, NULL, &pUidlCache));
// Get Record Count
IF_FAILEXIT(hr = pUidlCache->GetRecordCount(IINDEX_PRIMARY, &cRecords));
// Increment cTotal
cTotal += cRecords;
}
// Open Offline Transaction Log
IF_FAILEXIT(hr = MakeFilePath(szRootDir, c_szOfflineFile, c_szEmpty, szFilePath, ARRAYSIZE(szFilePath)));
// If the file exists
if (PathFileExists(szFilePath))
{
// Create pOffline
IF_FAILEXIT(hr = g_pDBSession->OpenDatabase(szFilePath, NOFLAGS, &g_SyncOpTableSchema, NULL, &pOffline));
// Get Record Count
IF_FAILEXIT(hr = pOffline->GetRecordCount(IINDEX_PRIMARY, &cRecords));
// Increment cTotal
cTotal += cRecords;
}
}
// Create progress meter
IF_NULLEXIT(pProgress = new CProgress);
// Dialog title
AthLoadString(idsCompacting, szTitle, sizeof(szTitle)/sizeof(TCHAR));
// Init progress meter
pProgress->Init(hwndParent, szTitle, (LPSTR)NULL, cTotal, idanCompact, TRUE, FALSE);
// Show progress
pProgress->Show(0);
// Setup Compact Cookie
Compact.hwndParent = hwndParent;
Compact.pProgress = pProgress;
Compact.fUI = (ISFLAGSET(dwRecurse, RECURSE_NOUI) == TRUE) ? FALSE : TRUE;
// Get Folder Counts
IF_FAILEXIT(hr = RecurseFolderHierarchy(idFolder, dwRecurse, 0, (DWORD_PTR)&Compact, (PFNRECURSECALLBACK)RecurseCompactFolders));
// Compacting All
if (FOLDERID_ROOT == idFolder && ISFLAGSET(dwRecurse, RECURSE_SUBFOLDERS))
{
// Compact Special Databae
IF_FAILEXIT(hr = CompactSpecialDatabase(&Compact, c_szPop3UidlFile, pUidlCache, idsPop3UidlFile));
// Compact Special Databae
IF_FAILEXIT(hr = CompactSpecialDatabase(&Compact, c_szOfflineFile, pOffline, idsOfflineFile));
// Compact Special Databae
IF_FAILEXIT(hr = CompactSpecialDatabase(&Compact, c_szFoldersFile, g_pStore, idsFoldersFile));
}
exit:
// Cleanup
SafeRelease(pProgress);
SafeRelease(pUidlCache);
SafeRelease(pOffline);
// Done
return (hrUserCancel == hr) ? S_OK : hr;
}
// --------------------------------------------------------------------------------
// RecurseRemoveMessageBodies
// --------------------------------------------------------------------------------
HRESULT RecurseRemoveMessageBodies(LPFOLDERINFO pFolder, BOOL fSubFolders,
DWORD cIndent, DWORD_PTR dwCookie)
{
// Locals
HRESULT hr=S_OK;
MESSAGEINFO Message={0};
BOOL fRemoveBody;
HROWSET hRowset=NULL;
IMessageFolder *pFolderObject=NULL;
IDatabase *pDB=NULL;
FILETIME ftCurrent;
LPREMOVEBODIES pRemove=(LPREMOVEBODIES)dwCookie;
// Trace
TraceCall("RecurseRemoveMessageBodies");
// If not a server
if (ISFLAGSET(pFolder->dwFlags, FOLDER_SERVER))
goto exit;
// Root
if (FOLDERID_ROOT == pFolder->idFolder)
goto exit;
// Open the folder...
if (FAILED(g_pStore->OpenFolder(pFolder->idFolder, NULL, OPEN_FOLDER_NOCREATE, &pFolderObject)))
goto exit;
// Get the database
IF_FAILEXIT(hr = pFolderObject->GetDatabase(&pDB));
// Set Msg
pRemove->pProgress->SetMsg(pFolder->pszName);
// Adjust cExpireDays
if (pRemove->cExpireDays <= 0)
pRemove->cExpireDays = 5;
// Get Current Time
GetSystemTimeAsFileTime(&ftCurrent);
// Create a Rowset
IF_FAILEXIT(hr = pDB->CreateRowset(IINDEX_PRIMARY, NOFLAGS, &hRowset));
// Loop
while (S_OK == pDB->QueryRowset(hRowset, 1, (LPVOID *)&Message, NULL))
{
// Only if this message has a body
if (!ISFLAGSET(Message.dwFlags, ARF_KEEPBODY) && !ISFLAGSET(Message.dwFlags, ARF_WATCH) && 0 != Message.faStream)
{
// Reset Bits
fRemoveBody = FALSE;
// Otherwise, remove body ?
if (ISFLAGSET(pRemove->dwFlags, CLEANUP_REMOVE_ALL))
{
// Remove the Body
fRemoveBody = TRUE;
}
// Otherwise
else
{
// Removing Read and this message is read ?
if (ISFLAGSET(pRemove->dwFlags, CLEANUP_REMOVE_READ) && ISFLAGSET(Message.dwFlags, ARF_READ))
{
// Remove the Body
fRemoveBody = TRUE;
}
// Otherwise, if expiring...
if (FALSE == fRemoveBody && ISFLAGSET(pRemove->dwFlags, CLEANUP_REMOVE_EXPIRED))
{
// If difference
if ((UlDateDiff(&Message.ftDownloaded, &ftCurrent) / SECONDS_INA_DAY) >= pRemove->cExpireDays)
{
// Remove the Body
fRemoveBody = TRUE;
}
}
}
// Otherwise, fRemoveBody ?
if (fRemoveBody)
{
// Save the Address
FILEADDRESS faDelete = Message.faStream;
// Zero out the record's strema
Message.faStream = 0;
// Fixup the Record
FLAGCLEAR(Message.dwFlags, ARF_HASBODY);
FLAGCLEAR(Message.dwFlags, ARF_ARTICLE_EXPIRED);
// Clear downloaded time
ZeroMemory(&Message.ftDownloaded, sizeof(FILETIME));
// Update the Record
IF_FAILEXIT(hr = pDB->UpdateRecord(&Message));
// Delete the Stream
SideAssert(SUCCEEDED(pDB->DeleteStream(faDelete)));
}
}
// Free Current
pDB->FreeRecord(&Message);
// Update the Progress
if (pRemove->pProgress && hrUserCancel == pRemove->pProgress->HrUpdate(1))
break;
}
exit:
// Cleanup
if (pDB)
{
pDB->FreeRecord(&Message);
pDB->CloseRowset(&hRowset);
pDB->Release();
}
SafeRelease(pFolderObject);
// Done
return hr;
}
// --------------------------------------------------------------------------------
// RemoveMessageBodies
// --------------------------------------------------------------------------------
HRESULT RemoveMessageBodies(HWND hwndParent, RECURSEFLAGS dwRecurse,
FOLDERID idFolder, CLEANUPFOLDERFLAGS dwFlags, DWORD cExpireDays)
{
// Locals
HRESULT hr=S_OK;
DWORD cTotal=0;
CHAR szTitle[255];
REMOVEBODIES RemoveBodies;
CProgress *pProgress=NULL;
// Trace
TraceCall("CompactFolders");
// Get Folder Counts
IF_FAILEXIT(hr = RecurseFolderHierarchy(idFolder, dwRecurse, 0, (DWORD_PTR)&cTotal, (PFNRECURSECALLBACK)RecurseFolderCounts));
// Create progress meter
IF_NULLEXIT(pProgress = new CProgress);
// Dialog title
AthLoadString(idsCleaningUp, szTitle, sizeof(szTitle)/sizeof(TCHAR));
// Init progress meter
pProgress->Init(hwndParent, szTitle, (LPSTR)NULL, cTotal, idanCompact, TRUE, FALSE);
// Show progress
pProgress->Show(0);
// Setup Compact Cookie
RemoveBodies.pProgress = pProgress;
RemoveBodies.dwFlags = dwFlags;
RemoveBodies.cExpireDays = cExpireDays;
// Get Folder Counts
IF_FAILEXIT(hr = RecurseFolderHierarchy(idFolder, dwRecurse, 0, (DWORD_PTR)&RemoveBodies, (PFNRECURSECALLBACK)RecurseRemoveMessageBodies));
exit:
// Cleanup
SafeRelease(pProgress);
// Done
return (hrUserCancel == hr) ? S_OK : hr;
}
// --------------------------------------------------------------------------------
// RecurseDeleteMessages
// --------------------------------------------------------------------------------
HRESULT RecurseDeleteMessages(LPFOLDERINFO pFolder, BOOL fSubFolders,
DWORD cIndent, DWORD_PTR dwCookie)
{
// Locals
HRESULT hr=S_OK;
LPDELETEMSGS pDelete=(LPDELETEMSGS)dwCookie;
// Trace
TraceCall("RecurseDeleteMessages");
// Set Msg
pDelete->pProgress->SetMsg(pFolder->pszName);
// If not a server
IF_FAILEXIT(hr = EmptyMessageFolder(pFolder, pDelete->fReset, pDelete->pProgress));
exit:
// Done
return(hr);
}
// --------------------------------------------------------------------------------
// CleanupDeleteMessages
// --------------------------------------------------------------------------------
HRESULT CleanupDeleteMessages(HWND hwndParent, RECURSEFLAGS dwRecurse,
FOLDERID idFolder, BOOL fReset)
{
// Locals
HRESULT hr=S_OK;
DWORD cTotal=0;
CHAR szTitle[255];
DELETEMSGS DeleteMsgs;
CProgress *pProgress=NULL;
// Trace
TraceCall("CompactFolders");
// Get Folder Counts
IF_FAILEXIT(hr = RecurseFolderHierarchy(idFolder, dwRecurse, 0, (DWORD_PTR)&cTotal, (PFNRECURSECALLBACK)RecurseFolderCounts));
// Create progress meter
IF_NULLEXIT(pProgress = new CProgress);
// Dialog title
AthLoadString(idsCleaningUp, szTitle, sizeof(szTitle)/sizeof(TCHAR));
// Init progress meter
pProgress->Init(hwndParent, szTitle, (LPSTR)NULL, cTotal, idanCompact, TRUE, FALSE);
// Show progress
pProgress->Show(0);
// Setup Compact Cookie
DeleteMsgs.pProgress = pProgress;
DeleteMsgs.fReset = fReset;
// Get Folder Counts
IF_FAILEXIT(hr = RecurseFolderHierarchy(idFolder, dwRecurse, 0, (DWORD_PTR)&DeleteMsgs, (PFNRECURSECALLBACK)RecurseDeleteMessages));
exit:
// Cleanup
SafeRelease(pProgress);
// Done
return (hrUserCancel == hr) ? S_OK : hr;
}
// --------------------------------------------------------------------------------
// CleanupFolder
// --------------------------------------------------------------------------------
HRESULT CleanupFolder(HWND hwndParent, RECURSEFLAGS dwRecurse, FOLDERID idFolder,
CLEANUPFOLDERTYPE tyCleanup)
{
// Locals
HRESULT hr=S_OK;
// Trace
TraceCall("CleanupFolder");
// Handle Cleanup Type
if (CLEANUP_COMPACT == tyCleanup)
{
// Compact
IF_FAILEXIT(hr = CompactFolders(hwndParent, dwRecurse, idFolder));
}
// Delete ?
else if (CLEANUP_DELETE == tyCleanup)
{
// Delete all the headers
IF_FAILEXIT(hr = CleanupDeleteMessages(hwndParent, dwRecurse, idFolder, FALSE));
}
// Reset
else if (CLEANUP_RESET == tyCleanup)
{
// Delete all the headers
IF_FAILEXIT(hr = CleanupDeleteMessages(hwndParent, dwRecurse, idFolder, TRUE));
}
// Remove Message Bodies
else if (CLEANUP_REMOVEBODIES == tyCleanup)
{
// RemoveMessageBodies
IF_FAILEXIT(hr = RemoveMessageBodies(hwndParent, dwRecurse, idFolder, CLEANUP_REMOVE_ALL | CLEANUP_PROGRESS, 0));
}
exit:
// Done
return(hr);
}
// --------------------------------------------------------------------------------
// InitFolderPickerEdit
// --------------------------------------------------------------------------------
HRESULT InitFolderPickerEdit(HWND hwndEdit, FOLDERID idSelected)
{
// Locals
HRESULT hr=S_OK;
FOLDERINFO Folder={0};
TCHAR sz[CCHMAX_STRINGRES];
LPTSTR psz;
// Trace
TraceCall("InitFolderPickerEdit");
// Fix Selected ?
if (FAILED(g_pStore->GetFolderInfo(idSelected, &Folder)))
{
// Try to get the Root
IF_FAILEXIT(hr = g_pStore->GetFolderInfo(FOLDERID_ROOT, &Folder));
}
// SetWndThisPtr
SetWndThisPtr(hwndEdit, Folder.idFolder);
if ((g_dwAthenaMode & MODE_OUTLOOKNEWS) && (idSelected == 0))
{
LoadString(g_hLocRes, idsOutlookNewsReader, sz, ARRAYSIZE(sz));
psz = sz;
}
else
{
psz = Folder.pszName;
}
// Set the Text
SetWindowText(hwndEdit, psz);
exit:
// Cleanup
g_pStore->FreeRecord(&Folder);
// Done
return(hr);
}
// --------------------------------------------------------------------------------
// GetFolderIdFromEdit
// --------------------------------------------------------------------------------
FOLDERID GetFolderIdFromEdit(HWND hwndEdit)
{
// Trace
TraceCall("GetFolderIdFromEdit");
// GetWndThisPtr
return(FOLDERID)(GetWndThisPtr(hwndEdit));
}
// --------------------------------------------------------------------------------
// PickFolderInEdit
// --------------------------------------------------------------------------------
HRESULT PickFolderInEdit(HWND hwndParent, HWND hwndEdit, FOLDERDIALOGFLAGS dwFlags,
LPCSTR pszTitle, LPCSTR pszText, LPFOLDERID pidSelected)
{
// Locals
HRESULT hr=S_OK;
FOLDERINFO Folder={0};
// Trace
TraceCall("PickFolderInEdit");
// Invalid Args
Assert(hwndParent && hwndEdit && pidSelected);
// Select Folder
IF_FAILEXIT(hr = SelectFolderDialog(hwndParent, SFD_SELECTFOLDER, GetFolderIdFromEdit(hwndEdit), dwFlags | FD_FORCEINITSELFOLDER, pszTitle, pszText, pidSelected));
// Fix Selected ?
IF_FAILEXIT(hr = g_pStore->GetFolderInfo(*pidSelected, &Folder));
// SetWndThisPtr
SetWndThisPtr(hwndEdit, Folder.idFolder);
// Set the Text
SetWindowText(hwndEdit, Folder.pszName);
exit:
// Cleanup
g_pStore->FreeRecord(&Folder);
// Done
return(hr);
}
// --------------------------------------------------------------------------------
// LighweightOpenMessage
// --------------------------------------------------------------------------------
HRESULT LighweightOpenMessage(IDatabase *pDB, LPMESSAGEINFO pHeader,
IMimeMessage **ppMessage)
{
// Locals
HRESULT hr=S_OK;
IStream *pStream=NULL;
IMimeMessage *pMessage;
// Invalid Args
Assert(pDB && pHeader && ppMessage);
// No Stream
if (0 == pHeader->faStream)
{
hr = TraceResult(E_FAIL);
goto exit;
}
// Need to create a message ?
if (NULL == *ppMessage)
{
// Create a Message
IF_FAILEXIT(hr = MimeOleCreateMessage(NULL, &pMessage));
// Set pMessage
(*ppMessage) = pMessage;
}
// Otherwise, InitNew
else
{
// Set pMesage
pMessage = (*ppMessage);
// InitNew
pMessage->InitNew();
}
// Open the Stream from the Store
IF_FAILEXIT(hr = pDB->OpenStream(ACCESS_READ, pHeader->faStream, &pStream));
// If there is an offset table
if (pHeader->Offsets.cbSize > 0)
{
// Create a ByteStream Object
CByteStream cByteStm(pHeader->Offsets.pBlobData, pHeader->Offsets.cbSize);
// Load the Offset Table Into the message
pMessage->LoadOffsetTable(&cByteStm);
// Take the bytes back out of the bytestream object (so that it doesn't try to free it)
cByteStm.AcquireBytes(&pHeader->Offsets.cbSize, &pHeader->Offsets.pBlobData, ACQ_DISPLACE);
}
// Load the pMessage
IF_FAILEXIT(hr = pMessage->Load(pStream));
exit:
// Cleanup
SafeRelease(pStream);
// Done
return(hr);
}
// --------------------------------------------------------------------------------
// RecurseFolderSizeInfo
// --------------------------------------------------------------------------------
HRESULT RecurseFolderSizeInfo(LPFOLDERINFO pFolder, BOOL fSubFolders,
DWORD cIndent, DWORD_PTR dwCookie)
{
// Locals
HRESULT hr=S_OK;
DWORD cbFile;
DWORD cbFreed;
DWORD cbStreams;
IMessageFolder *pObject=NULL;
LPENUMFOLDERSIZE pEnumSize=(LPENUMFOLDERSIZE)dwCookie;
// Trace
TraceCall("RecurseFolderSizeInfo");
// If not hidden
if (ISFLAGSET(pFolder->dwFlags, FOLDER_HIDDEN) || FOLDERID_ROOT == pFolder->idFolder)
goto exit;
// Open the Folder Database
if (SUCCEEDED(g_pStore->OpenFolder(pFolder->idFolder, NULL, OPEN_FOLDER_NOCREATE, &pObject)))
{
// Get Size Information
IF_FAILEXIT(hr = pObject->GetSize(&cbFile, NULL, &cbFreed, &cbStreams));
// Increment
pEnumSize->cbFile += cbFile;
pEnumSize->cbFreed += cbFreed;
pEnumSize->cbStreams += cbStreams;
}
exit:
// Cleanup
SafeRelease(pObject);
// Done
return(hr);
}
// --------------------------------------------------------------------------------
// DisplayFolderSizeInfo
// --------------------------------------------------------------------------------
HRESULT DisplayFolderSizeInfo(HWND hwnd, RECURSEFLAGS dwRecurse, FOLDERID idFolder)
{
// Locals
HRESULT hr=S_OK;
CHAR szSize[255];
CHAR szRes[255];
CHAR szMsg[255];
ENUMFOLDERSIZE EnumSize={0};
// Trace
TraceCall("DisplayFolderSizeInfo");
// Recurse and Get File Size Information...
IF_FAILEXIT(hr = RecurseFolderHierarchy(idFolder, dwRecurse, 0, (DWORD_PTR)&EnumSize, (PFNRECURSECALLBACK)RecurseFolderSizeInfo));
// Total Size
StrFormatByteSizeA(EnumSize.cbFile, szSize, ARRAYSIZE(szSize));
// Display the Text
SetWindowText(GetDlgItem(hwnd, idcTotalSize), szSize);
// Size of the Streams
StrFormatByteSizeA(EnumSize.cbStreams, szSize, ARRAYSIZE(szSize));
// Wasted Space
StrFormatByteSizeA(EnumSize.cbFreed, szSize, ARRAYSIZE(szSize));
// Wasted Space
AthLoadString(idsWastedKB, szRes, ARRAYSIZE(szRes));
// Format the String
wnsprintf(szMsg, ARRAYSIZE(szMsg), szRes, szSize, (EnumSize.cbFile != 0) ? ((EnumSize.cbFreed * 100) / EnumSize.cbFile) : 0);
// Show the Text
SetWindowText(GetDlgItem(hwnd, idcWastedSpace), szMsg);
exit:
// Done
return(hr);
}
// --------------------------------------------------------------------------------
// MigrateLocalStore
// --------------------------------------------------------------------------------
HRESULT MigrateLocalStore(HWND hwndParent, LPTSTR pszSrc, LPTSTR pszDest)
{
// Locals
HRESULT hr=S_OK;
DWORD dw, cb;
CHAR szFilePath[MAX_PATH];
CHAR szExpanded[MAX_PATH];
CHAR szCommand[MAX_PATH+20];
LPSTR psz=(LPSTR)c_szMigrationExe;
PROCESS_INFORMATION pi;
STARTUPINFO sti;
HKEY hkey;
// Try to find the path to oemig50.exe
if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, c_szRegFlat, 0, KEY_QUERY_VALUE, &hkey))
{
cb = sizeof(szFilePath);
if (ERROR_SUCCESS == RegQueryValueEx(hkey, c_szInstallRoot, 0, &dw, (LPBYTE)szFilePath, &cb))
{
if (REG_EXPAND_SZ == dw)
{
ExpandEnvironmentStrings(szFilePath, szExpanded, ARRAYSIZE(szExpanded));
psz = szExpanded;
}
else
psz = szFilePath;
// Append backslash
PathAddBackslash(psz);
// Add in oemig50.exe
StrCatBuff(psz, c_szMigrationExe, MAX_PATH);
}
RegCloseKey(hkey);
}
// Form the command
wnsprintf(szCommand, ARRAYSIZE(szCommand), "%s /type:V1+V4-V5 /src:%s /dst:%s", psz, pszSrc, pszDest);
// Zero startup info
ZeroMemory(&sti, sizeof(sti));
sti.cb = sizeof(STARTUPINFO);
// run oemig50.exe
if (CreateProcess(NULL, szCommand, NULL, NULL, FALSE, 0, NULL, NULL, &sti, &pi))
{
// Wait for the process to finish
WaitForSingleObject(pi.hProcess, INFINITE);
// Get the Exit Process Code
if (0 == GetExitCodeProcess(pi.hProcess, &dw))
{
// General Failure
dw = TraceResult(E_FAIL);
}
// Close the Thread
CloseHandle(pi.hThread);
// Close the Process
CloseHandle(pi.hProcess);
// Failure ?
if (MIGRATE_E_NOCONTINUE == (HRESULT)dw)
{
// Abort this process
ExitProcess(dw);
// Set hr
hr = TraceResult(E_FAIL);
}
// Success
else
hr = S_OK;
}
// Failure
else
{
hr = TraceResult(E_FAIL);
goto exit;
}
exit:
// Done
return hr;
}
HRESULT CopyMoveMessages(HWND hwnd, FOLDERID src, FOLDERID dst, LPMESSAGEIDLIST pList, COPYMESSAGEFLAGS dwFlags)
{
HRESULT hr;
IMessageFolder *pFolderSrc, *pFolderDst;
Assert(pList != NULL);
Assert(hwnd != NULL);
hr = g_pStore->OpenFolder(src, NULL, 0, &pFolderSrc);
if (SUCCEEDED(hr))
{
hr = g_pStore->OpenFolder(dst, NULL, 0, &pFolderDst);
if (SUCCEEDED(hr))
{
hr = CopyMessagesProgress(hwnd, pFolderSrc, pFolderDst, dwFlags, pList, NULL);
pFolderDst->Release();
}
pFolderSrc->Release();
}
return(hr);
}
// --------------------------------------------------------------------------------
// CallbackOnLogonPrompt
// --------------------------------------------------------------------------------
HRESULT CallbackOnLogonPrompt(HWND hwndParent, LPINETSERVER pServer, IXPTYPE ixpServerType)
{
// Locals
HRESULT hr=S_OK;
IImnAccount *pAccount=NULL;
DWORD apidUserName;
DWORD apidPassword;
DWORD apidPromptPwd;
// Trace
TraceCall("CallbackOnLogonPrompt");
// Invalid Args
Assert(g_pAcctMan && hwndParent && IsWindow(hwndParent) && pServer);
switch (ixpServerType)
{
case IXP_POP3:
apidUserName = AP_POP3_USERNAME;
apidPassword = AP_POP3_PASSWORD;
apidPromptPwd = AP_POP3_PROMPT_PASSWORD;
break;
case IXP_SMTP:
apidUserName = AP_SMTP_USERNAME;
apidPassword = AP_SMTP_PASSWORD;
apidPromptPwd = AP_SMTP_PROMPT_PASSWORD;
break;
case IXP_NNTP:
apidUserName = AP_NNTP_USERNAME;
apidPassword = AP_NNTP_PASSWORD;
apidPromptPwd = AP_NNTP_PROMPT_PASSWORD;
break;
case IXP_IMAP:
apidUserName = AP_IMAP_USERNAME;
apidPassword = AP_IMAP_PASSWORD;
apidPromptPwd = AP_IMAP_PROMPT_PASSWORD;
break;
case IXP_HTTPMail:
apidUserName = AP_HTTPMAIL_USERNAME;
apidPassword = AP_HTTPMAIL_PASSWORD;
apidPromptPwd = AP_HTTPMAIL_PROMPT_PASSWORD;
break;
default:
AssertSz(FALSE, "Not a valid server type");
hr = TraceResult(E_FAIL);
goto exit;
}
// Find the Account for pServer
IF_FAILEXIT(hr = g_pAcctMan->FindAccount(AP_ACCOUNT_NAME, pServer->szAccount, &pAccount));
// Call Task Util
IF_FAILEXIT(hr = TaskUtil_OnLogonPrompt(pAccount, NULL, hwndParent, pServer, apidUserName, apidPassword, apidPromptPwd, TRUE));
exit:
// Cleanup
SafeRelease(pAccount);
// Done
return(hr);
}
// --------------------------------------------------------------------------------
// CallbackOnPrompt
// --------------------------------------------------------------------------------
HRESULT CallbackOnPrompt(HWND hwndParent, HRESULT hrError, LPCTSTR pszText,
LPCTSTR pszCaption, UINT uType, INT *piUserResponse)
{
// Trace
TraceCall("CallbackOnPrompt");
// Invalid Arg
Assert(pszText && pszCaption && piUserResponse);
// Do the message box
*piUserResponse = AthMessageBox(hwndParent, MAKEINTRESOURCE(idsAthena), (LPSTR)pszText, NULL, uType | MB_TASKMODAL);
// Done
return(S_OK);
}
// --------------------------------------------------------------------------------
// CallbackOnTimeout
// --------------------------------------------------------------------------------
HRESULT CallbackOnTimeout(LPINETSERVER pServer, IXPTYPE ixpServerType, DWORD dwTimeout,
ITimeoutCallback *pCallback, LPHTIMEOUT phTimeout)
{
// Locals
HWND hwndTimeout;
// Trace
TraceCall("CallbackOnTimeout");
// Invalid Args
Assert(pServer && phTimeout);
// Set hwndTimeout
hwndTimeout = (HWND)TlsGetValue(g_dwTlsTimeout);
// We are already showing a timeout dialog
if (NULL == hwndTimeout)
{
LPCSTR pszProtocol;
// Do the Dialog
GetProtocolString(&pszProtocol, ixpServerType);
hwndTimeout = TaskUtil_HwndOnTimeout(pServer->szServerName, pServer->szAccount, pszProtocol, dwTimeout, pCallback);
// Cast to phTimeout
*phTimeout = (HTIMEOUT)hwndTimeout;
// Store It
TlsSetValue(g_dwTlsTimeout, (LPVOID)hwndTimeout);
}
// Done
return(S_OK);
}
// --------------------------------------------------------------------------------
// CallbackCloseTimeout
// --------------------------------------------------------------------------------
HRESULT CallbackCloseTimeout(LPHTIMEOUT phTimeout)
{
// Locals
HWND hwndTimeout=NULL;
// Trace
TraceCall("CallbackCloseTimeout");
// Invalid Args
Assert(phTimeout);
// Nothing to Close
if (NULL == *phTimeout)
return(S_OK);
// Get Timeout
hwndTimeout = (HWND)TlsGetValue(g_dwTlsTimeout);
// Must Equal hwndTimeout
Assert(hwndTimeout == (HWND)*phTimeout);
// Kill the Window
if (hwndTimeout && IsWindow(hwndTimeout) && hwndTimeout == (HWND)*phTimeout)
{
// Kil It
DestroyWindow(hwndTimeout);
}
// Not Timeout
TlsSetValue(g_dwTlsTimeout, NULL);
// Null phTmieout
*phTimeout = NULL;
// Done
return(S_OK);
}
// --------------------------------------------------------------------------------
// CallbackOnTimeoutResponse
// --------------------------------------------------------------------------------
HRESULT CallbackOnTimeoutResponse(TIMEOUTRESPONSE eResponse, IOperationCancel *pCancel,
LPHTIMEOUT phTimeout)
{
// Trace
TraceCall("CallbackOnTimeoutResponse");
// better have a Cancel
Assert(pCancel);
// Handle the timeout
switch(eResponse)
{
case TIMEOUT_RESPONSE_STOP:
if (pCancel)
pCancel->Cancel(CT_ABORT);
break;
case TIMEOUT_RESPONSE_WAIT:
CallbackCloseTimeout(phTimeout);
break;
default:
Assert(FALSE);
break;
}
// Kill the timeout dialog
CallbackCloseTimeout(phTimeout);
// Done
return(S_OK);
}
// --------------------------------------------------------------------------------
// CallbackCanConnect
// --------------------------------------------------------------------------------
HRESULT CallbackCanConnect(LPCSTR pszAccountId, HWND hwndParent, BOOL fPrompt)
{
// Locals
HRESULT hr=S_OK;
// Trace
TraceCall("CallbackCanConnect");
// Validate the Args
Assert(pszAccountId);
Assert(hwndParent);
// We Should hav g_pConMan
Assert(g_pConMan);
// Call Into It
if (g_pConMan)
{
// Can We Connect
hr = g_pConMan->CanConnect((LPSTR)pszAccountId);
if ((hr != S_OK) && (hr != HR_E_DIALING_INPROGRESS) && (fPrompt))
{
//We go ahead and connect
hr = g_pConMan->Connect((LPSTR)pszAccountId, hwndParent, fPrompt);
}
}
// Done
return(hr);
}
// --------------------------------------------------------------------------------
// CallbackDisplayError
// --------------------------------------------------------------------------------
HRESULT CallbackDisplayError(HWND hwndParent, HRESULT hrResult, LPSTOREERROR pError)
{
// Locals
CHAR sz[CCHMAX_STRINGRES + 512];
LPSTR pszError = NULL;
// Trace
TraceCall("CallbackDisplayError");
// Do not show errors that are caused by explicit user action
switch (hrResult)
{
case HR_E_OFFLINE_FOLDER_CREATE:
LoadString(g_hLocRes, idsErrOfflineFldrCreate, sz, ARRAYSIZE(sz));
pError->pszProblem = sz;
break;
case HR_E_OFFLINE_FOLDER_MOVE:
LoadString(g_hLocRes, idsErrOfflineFldrMove, sz, ARRAYSIZE(sz));
pError->pszProblem = sz;
break;
case HR_E_OFFLINE_FOLDER_DELETE:
LoadString(g_hLocRes, idsErrOfflineFldrDelete, sz, ARRAYSIZE(sz));
pError->pszProblem = sz;
break;
case HR_E_OFFLINE_FOLDER_RENAME:
LoadString(g_hLocRes, idsErrOfflineFldrRename, sz, ARRAYSIZE(sz));
pError->pszProblem = sz;
break;
case STORE_E_OPERATION_CANCELED:
case HR_E_USER_CANCEL_CONNECT:
case HR_E_OFFLINE:
case HR_E_DIALING_INPROGRESS:
case STORE_E_EXPIRED:
case STORE_E_NOREMOTESPECIALFLDR: // Note should handle this case itself
case IXP_E_USER_CANCEL:
case IXP_E_HTTP_NOT_MODIFIED:
case hrUserCancel:
return(S_OK);
}
// Figure out error description string, if none provided
if (NULL == pError || pError->pszProblem == NULL || '\0' == pError->pszProblem[0])
{
UINT idsError = IDS_IXP_E_UNKNOWN;
LPCTASKERROR pTaskError=NULL;
char szRes[CCHMAX_STRINGRES];
if (pError)
{
// Try to locate an Error Info
pTaskError = PTaskUtil_GetError(pError->hrResult, NULL);
}
// Try to locate an Error Info
if (NULL == pTaskError)
{
// Try to find a task error
pTaskError = PTaskUtil_GetError(hrResult, NULL);
}
// If we have a task error
if (pTaskError)
{
// Set the String
idsError = pTaskError->ulStringId;
}
// Better Succeed
SideAssert(LoadString(g_hLocRes, idsError, szRes, ARRAYSIZE(szRes)) > 0);
// Add any extra information to the error string that might be necessary
switch (idsError)
{
// Requires account name
case idsNNTPErrUnknownResponse:
case idsNNTPErrNewgroupsFailed:
case idsNNTPErrListFailed:
case idsNNTPErrPostFailed:
case idsNNTPErrDateFailed:
case idsNNTPErrPasswordFailed:
case idsNNTPErrServerTimeout:
wnsprintf(sz, ARRAYSIZE(sz), szRes, (pError && pError->pszAccount ? pError->pszAccount : TEXT("")));
break;
// Group name, then account name
case idsNNTPErrListGroupFailed:
case idsNNTPErrGroupFailed:
case idsNNTPErrGroupNotFound:
wnsprintf(sz, ARRAYSIZE(sz), szRes, (pError && pError->pszFolder ? pError->pszFolder : TEXT("")), (pError && pError->pszAccount ? pError->pszAccount : TEXT("")));
break;
// Group name only
case idsNNTPErrHeadersFailed:
case idsNNTPErrXhdrFailed:
wnsprintf(sz, ARRAYSIZE(sz), szRes, (pError->pszFolder ? pError->pszFolder : TEXT("")));
break;
default:
StrCpyN(sz, szRes, ARRAYSIZE(sz));
break;
}
pszError = sz;
}
else
// Provided error string should always override generic HRESULT error str
pszError = pError->pszProblem;
// No pError ?
if (pError)
{
INETMAILERROR ErrorInfo={0};
// Setup the Error Structure
ErrorInfo.dwErrorNumber = pError->uiServerError;
ErrorInfo.hrError = pError->hrResult;
ErrorInfo.pszServer = pError->pszServer;
ErrorInfo.pszAccount = pError->pszAccount;
ErrorInfo.pszMessage = pszError;
ErrorInfo.pszUserName = pError->pszUserName;
ErrorInfo.pszProtocol = pError->pszProtocol;
ErrorInfo.pszDetails = pError->pszDetails;
ErrorInfo.dwPort = pError->dwPort;
ErrorInfo.fSecure = pError->fSSL;
// Beep
MessageBeep(MB_OK);
// Show the error
DialogBoxParam(g_hLocRes, MAKEINTRESOURCE(iddInetMailError), hwndParent, InetMailErrorDlgProc, (LPARAM)&ErrorInfo);
}
// Otherwise, show an error
else
{
// Beep
MessageBeep(MB_OK);
// Show an error
AthMessageBox(hwndParent, MAKEINTRESOURCE(idsAthena), pszError, NULL, MB_OK | MB_TASKMODAL);
}
// Done
return(S_OK);
}
// --------------------------------------------------------------------------------
// CompareTableIndexes
// --------------------------------------------------------------------------------
HRESULT CompareTableIndexes(LPCTABLEINDEX pIndex1, LPCTABLEINDEX pIndex2)
{
// Locals
DWORD i;
// Trace
TraceCall("CompareTableIndexes");
// Different Number of Keys
if (pIndex1->cKeys != pIndex2->cKeys)
return(S_FALSE);
// Loop through the keys
for (i=0; i<pIndex1->cKeys; i++)
{
// Different Column
if (pIndex1->rgKey[i].iColumn != pIndex2->rgKey[i].iColumn)
return(S_FALSE);
// Different Compare Flags
if (pIndex1->rgKey[i].bCompare != pIndex2->rgKey[i].bCompare)
return(S_FALSE);
// Different Compare Bits
if (pIndex1->rgKey[i].dwBits != pIndex2->rgKey[i].dwBits)
return(S_FALSE);
}
// Equal
return(S_OK);
}
// --------------------------------------------------------------------------------
// EmptyFolder
// --------------------------------------------------------------------------------
HRESULT EmptyFolder(HWND hwndParent, FOLDERID idFolder)
{
// Locals
char sz[CCHMAX_STRINGRES], szT[CCHMAX_STRINGRES];
HRESULT hr=S_OK;
FOLDERINFO Folder={0};
IMessageFolder *pFolder=NULL;
// Trace
TraceCall("EmptyFolder");
// Open the Folder
IF_FAILEXIT(hr = g_pStore->OpenFolder(idFolder, NULL, NOFLAGS, &pFolder));
// Delete all the messages from the folder
IF_FAILEXIT(hr = DeleteMessagesProgress(hwndParent, pFolder, DELETE_MESSAGE_NOPROMPT | DELETE_MESSAGE_NOTRASHCAN, NULL));
// Delete Sub Folders..
IF_FAILEXIT(hr = DeleteFolderProgress(hwndParent, idFolder, DELETE_FOLDER_CHILDRENONLY | DELETE_FOLDER_RECURSIVE));
exit:
// Cleanup
SafeRelease(pFolder);
// Error Message
if (FAILED(hr))
{
g_pStore->GetFolderInfo(idFolder, &Folder);
AthLoadString(idsErrDeleteOnExit, sz, ARRAYSIZE(sz));
wnsprintf(szT, ARRAYSIZE(szT), sz, Folder.pszName);
AthErrorMessage(g_hwndInit, MAKEINTRESOURCE(idsAthenaMail), szT, hr);
g_pStore->FreeRecord(&Folder);
}
// Done
return(hr);
}
// --------------------------------------------------------------------------------
// EmptySpecialFolder
// --------------------------------------------------------------------------------
HRESULT EmptySpecialFolder(HWND hwndParent, SPECIALFOLDER tySpecial)
{
// Locals
HRESULT hr=S_OK;
FOLDERINFO Folder={0};
// Trace
TraceCall("EmptySpecialFolder");
// Get special folder information
IF_FAILEXIT(hr = g_pStore->GetSpecialFolderInfo(FOLDERID_LOCAL_STORE, tySpecial, &Folder));
// Delete all the messages from the folder
IF_FAILEXIT(hr = EmptyFolder(hwndParent, Folder.idFolder));
exit:
// Cleanup
g_pStore->FreeRecord(&Folder);
// Done
return(hr);
}
//----------------------------------------------------------------------------------
// IsParentDeletedItems
//----------------------------------------------------------------------------------
HRESULT IsParentDeletedItems(FOLDERID idFolder, LPFOLDERID pidDeletedItems,
LPFOLDERID pidServer)
{
// Locals
BOOL fInTrashCan=FALSE;
FOLDERID idCurrent=idFolder;
FOLDERINFO Folder={0};
// Trace
TraceCall("IsParentDeletedItems");
// Invalid Arg
Assert(pidDeletedItems && pidServer);
// Initialize
*pidDeletedItems = FOLDERID_INVALID;
*pidServer = FOLDERID_INVALID;
// Walk up the parent chain
while (SUCCEEDED(g_pStore->GetFolderInfo(idCurrent, &Folder)))
{
// If this is the deleted items folder
if (FOLDER_DELETED == Folder.tySpecial)
{
// idFolder is a child of the deleted items folder...
fInTrashCan = TRUE;
// Save the Id
*pidDeletedItems = Folder.idFolder;
}
// If This is a Server, done
if (ISFLAGSET(Folder.dwFlags, FOLDER_SERVER))
{
// Return Server
*pidServer = Folder.idFolder;
// Done
break;
}
// Set idCurrent
idCurrent = Folder.idParent;
// Cleanup
g_pStore->FreeRecord(&Folder);
}
// Validate
Assert(FOLDERID_INVALID != *pidServer);
// Cleanup
g_pStore->FreeRecord(&Folder);
// Done
return(TRUE == fInTrashCan ? S_OK : S_FALSE);
}
HRESULT CreateTempNewsAccount(LPCSTR pszServer, DWORD dwPort, BOOL fSecure, IImnAccount **ppAcct)
{
IImnAccount *pAcct, *pDefAcct;
IImnEnumAccounts *pEnum;
DWORD dwTemp;
char szServer[1024];
HRESULT hr;
*ppAcct = NULL;
if (lstrlen(pszServer) >= CCHMAX_SERVER_NAME)
return(E_FAIL);
// First try to see if we can find such a server.
if (SUCCEEDED(g_pAcctMan->Enumerate(SRV_NNTP, &pEnum)))
{
while (SUCCEEDED(pEnum->GetNext(&pAcct)))
{
if (SUCCEEDED(pAcct->GetPropSz(AP_NNTP_SERVER, szServer, ARRAYSIZE(szServer))))
{
if (0 == lstrcmpi(pszServer, szServer))
{
// The server names are the same, but we also need to make
// sure the port numbers are the same as well
if (SUCCEEDED(pAcct->GetPropDw(AP_NNTP_PORT, &dwTemp)) && dwTemp == dwPort)
{
// This is really bizzare. Since this value doesn't seem to have a default
// setting, if it hasn't been set yet, it returns E_NoPropData.
hr = pAcct->GetPropDw(AP_NNTP_SSL, &dwTemp);
if (hr == E_NoPropData || (SUCCEEDED(hr) && dwTemp == (DWORD) fSecure))
{
*ppAcct = pAcct;
break;
}
}
}
}
pAcct->Release();
}
pEnum->Release();
}
if (*ppAcct)
return (S_OK);
// Try to create a new account object
if (FAILED(hr = g_pAcctMan->CreateAccountObject(ACCT_NEWS, &pAcct)))
return (hr);
// We have the object, so set the account name and server name to pszServer.
StrCpyN(szServer, pszServer, ARRAYSIZE(szServer));
g_pAcctMan->GetUniqueAccountName(szServer, ARRAYSIZE(szServer));
pAcct->SetPropSz(AP_ACCOUNT_NAME, szServer);
pAcct->SetPropSz(AP_NNTP_SERVER, (LPSTR)pszServer);
pAcct->SetPropDw(AP_NNTP_PORT, dwPort);
pAcct->SetPropDw(AP_NNTP_SSL, fSecure);
// Load the default news account
if (SUCCEEDED(hr = g_pAcctMan->GetDefaultAccount(ACCT_NEWS, &pDefAcct)))
{
// Copy the User Name
if (SUCCEEDED(hr = pDefAcct->GetPropSz(AP_NNTP_DISPLAY_NAME, szServer, ARRAYSIZE(szServer))))
pAcct->SetPropSz(AP_NNTP_DISPLAY_NAME, szServer);
// Copy the Org
if (SUCCEEDED(hr = pDefAcct->GetPropSz(AP_NNTP_ORG_NAME, szServer, ARRAYSIZE(szServer))))
pAcct->SetPropSz(AP_NNTP_ORG_NAME, szServer);
// Copy the email
if (SUCCEEDED(hr = pDefAcct->GetPropSz(AP_NNTP_EMAIL_ADDRESS, szServer, ARRAYSIZE(szServer))))
pAcct->SetPropSz(AP_NNTP_EMAIL_ADDRESS, szServer);
// Copy the reply to
if (SUCCEEDED(hr = pDefAcct->GetPropSz(AP_NNTP_REPLY_EMAIL_ADDRESS, szServer, ARRAYSIZE(szServer))))
pAcct->SetPropSz(AP_NNTP_REPLY_EMAIL_ADDRESS, szServer);
pDefAcct->Release();
}
// Tag this account as a temporary account
pAcct->SetPropDw(AP_TEMP_ACCOUNT, (DWORD)TRUE);
// save the changes
pAcct->SaveChanges();
*ppAcct = pAcct;
return (S_OK);
}
void CleanupTempNewsAccounts()
{
IImnAccount *pAcct;
IImnEnumAccounts *pEnum;
DWORD dwTemp;
BOOL fSub;
FOLDERID idAcct;
HRESULT hr;
FOLDERINFO info;
char szAcct[CCHMAX_ACCOUNT_NAME];
if (SUCCEEDED(g_pAcctMan->Enumerate(SRV_NNTP, &pEnum)))
{
while (SUCCEEDED(pEnum->GetNext(&pAcct)))
{
if (SUCCEEDED(pAcct->GetPropDw(AP_TEMP_ACCOUNT, &dwTemp)) && dwTemp)
{
if (SUCCEEDED(pAcct->GetPropSz(AP_ACCOUNT_ID, szAcct, ARRAYSIZE(szAcct))))
{
// if it doesn't have any subscribed children,
// we can delete it
fSub = FALSE;
hr = g_pStore->FindServerId(szAcct, &idAcct);
if (SUCCEEDED(hr))
{
IEnumerateFolders *pFldrEnum;
// News accounts only have ONE level, so enumerate immediate
// subscribed children to see if there is at least one of them
hr = g_pStore->EnumChildren(idAcct, TRUE, &pFldrEnum);
if (SUCCEEDED(hr))
{
hr = pFldrEnum->Next(1, &info, NULL);
if (S_OK == hr)
{
if (info.dwFlags & FOLDER_SUBSCRIBED)
fSub = TRUE;
g_pStore->FreeRecord(&info);
}
pFldrEnum->Release();
}
}
if (fSub)
pAcct->SetPropDw(AP_TEMP_ACCOUNT, (DWORD)FALSE);
else
pAcct->Delete();
}
}
pAcct->Release();
}
pEnum->Release();
}
}
HRESULT FindGroupAccount(LPCSTR pszGroup, LPSTR pszAccount, UINT cchAccount)
{
IImnEnumAccounts *pEnum;
IImnAccount *pAcct;
FOLDERID idAcct;
HRESULT hr;
HLOCK hLock;
FOLDERINFO Folder;
char szAccount[CCHMAX_ACCOUNT_NAME], szDefAcct[CCHMAX_ACCOUNT_NAME];
UINT cScore, cScoreMax = 0;
*szDefAcct = 0;
if (SUCCEEDED(g_pAcctMan->GetDefaultAccount(ACCT_NEWS, &pAcct)))
{
pAcct->GetPropSz(AP_ACCOUNT_ID, szDefAcct, ARRAYSIZE(szDefAcct));
pAcct->Release();
}
if (SUCCEEDED(g_pAcctMan->Enumerate(SRV_NNTP, &pEnum)))
{
while (SUCCEEDED(pEnum->GetNext(&pAcct)))
{
if (SUCCEEDED(pAcct->GetPropSz(AP_ACCOUNT_ID, szAccount, ARRAYSIZE(szAccount))) &&
SUCCEEDED(g_pStore->FindServerId(szAccount, &idAcct)) &&
SUCCEEDED(g_pStore->Lock(&hLock)))
{
cScore = 0;
ZeroMemory(&Folder, sizeof(FOLDERINFO));
Folder.idParent = idAcct;
Folder.pszName = (LPSTR)pszGroup;
if (DB_S_FOUND == g_pStore->FindRecord(IINDEX_ALL, COLUMNS_ALL, &Folder, NULL))
{
// look for it in the group list
cScore += 1;
// check to see if it is subscribed
if (!!(Folder.dwFlags & FOLDER_SUBSCRIBED))
cScore += 4;
g_pStore->FreeRecord(&Folder);
}
if (cScore)
{
// is this the default account?
if (0 == lstrcmpi(szAccount, szDefAcct))
cScore += 2;
if (cScore > cScoreMax)
{
cScoreMax = cScore;
StrCpyN(pszAccount, szAccount, cchAccount);
}
}
g_pStore->Unlock(&hLock);
}
pAcct->Release();
}
pEnum->Release();
}
return(cScoreMax > 0 ? S_OK : E_FAIL);
}
HRESULT GetNewsGroupFolderId(LPCSTR pszAccount, LPCSTR pszGroup, FOLDERID *pid)
{
FOLDERID idAcct;
HRESULT hr;
HLOCK hLock;
FOLDERINFO Folder = {0};
Assert(pszAccount != NULL);
Assert(pszGroup != NULL);
Assert(pid != NULL);
hr = g_pStore->FindServerId(pszAccount, &idAcct);
if (FAILED(hr))
return(hr);
hr = g_pStore->Lock(&hLock);
if (FAILED(hr))
return(hr);
Folder.idParent = idAcct;
Folder.pszName = (LPSTR)pszGroup;
if (DB_S_FOUND == g_pStore->FindRecord(IINDEX_ALL, COLUMNS_ALL, &Folder, NULL))
{
*pid = Folder.idFolder;
g_pStore->FreeRecord(&Folder);
}
else
{
ZeroMemory(&Folder, sizeof(FOLDERINFO));
Folder.idParent = idAcct;
Folder.tySpecial = FOLDER_NOTSPECIAL;
Folder.pszName = (LPSTR)pszGroup;
hr = g_pStore->CreateFolder(CREATE_FOLDER_LOCALONLY, &Folder, NULL);
if (SUCCEEDED(hr))
*pid = Folder.idFolder;
}
g_pStore->Unlock(&hLock);
return(hr);
}
HRESULT GetFolderIdFromNewsUrl(LPCSTR pszServer, UINT uPort, LPCSTR pszGroup, BOOL fSecure, FOLDERID *pid)
{
char szAccount[CCHMAX_ACCOUNT_NAME];
IImnAccount *pAcct;
HRESULT hr;
Assert(pid != NULL);
*pid = FOLDERID_INVALID;
// Bug #20448 - Handle IE 2.0's "news:netnews" and "news:*". These
// should just cause us to launch normally.
if (0 == lstrcmpi(pszGroup, c_szURLNetNews) ||
0 == lstrcmpi(pszGroup, g_szAsterisk))
{
pszGroup = NULL;
}
*szAccount = 0;
if (uPort == -1)
uPort = fSecure ? DEF_SNEWSPORT : DEF_NNTPPORT;
if (pszServer != NULL &&
SUCCEEDED(CreateTempNewsAccount(pszServer, uPort, fSecure, &pAcct)))
{
pAcct->GetPropSz(AP_ACCOUNT_ID, szAccount, ARRAYSIZE(szAccount));
pAcct->Release();
}
else
{
if (pszGroup == NULL || FAILED(FindGroupAccount(pszGroup, szAccount, ARRAYSIZE(szAccount))))
{
if (FAILED(g_pAcctMan->GetDefaultAccount(ACCT_NEWS, &pAcct)))
return(E_FAIL);
pAcct->GetPropSz(AP_ACCOUNT_ID, szAccount, ARRAYSIZE(szAccount));
pAcct->Release();
}
}
if (pszGroup != NULL)
{
hr = GetNewsGroupFolderId(szAccount, pszGroup, pid);
}
else
{
hr = g_pStore->FindServerId(szAccount, pid);
}
return(hr);
}
#define CHASH_BUCKETS 50
HRESULT CreateFolderHash(IMessageStore *pStore, FOLDERID idRoot, IHashTable **ppHash)
{
IHashTable *pHash=0;
HRESULT hr;
LPSTR pszTemp;
DWORD dwTemp;
hr = MimeOleCreateHashTable(CHASH_BUCKETS, TRUE, &pHash);
if (FAILED(hr))
{
TraceResult(hr);
goto exit;
}
pszTemp = NULL;
dwTemp = 0;
hr = HashChildren(pStore, idRoot, pHash, &pszTemp, 0, &dwTemp);
SafeMemFree(pszTemp);
if (FAILED(hr))
{
TraceResult(hr);
goto exit;
}
*ppHash = pHash;
pHash = NULL;
exit:
ReleaseObj(pHash);
return hr;
}
HRESULT HashChildren(IMessageStore *pStore, FOLDERID idParent, IHashTable *pHash,
LPSTR *ppszPath, DWORD dwChildOffset, DWORD *pdwAlloc)
{
FOLDERINFO fi;
HRESULT hr=S_OK;
IEnumerateFolders *pFldrEnum=0;
LPSTR pszInsertPt;
pszInsertPt = *ppszPath + dwChildOffset;
hr = pStore->EnumChildren(idParent, FALSE, &pFldrEnum);
if (FAILED(hr))
{
TraceResult(hr);
goto exit;
}
while (pFldrEnum->Next(1, &fi, NULL)==S_OK)
{
DWORD dwFldrNameLen;
// Check if path buffer is large enough to accommodate current
// foldername + hierarchy char + null term
dwFldrNameLen = lstrlen(fi.pszName);
if (dwFldrNameLen + dwChildOffset + 1 >= *pdwAlloc)
{
BOOL fResult;
DWORD dwNewSize;
dwNewSize = dwChildOffset + dwFldrNameLen + 51; // 1 byte for HC, 50 bytes worth of insurance
Assert(dwNewSize > *pdwAlloc);
fResult = MemRealloc((void **) ppszPath, dwNewSize * sizeof(**ppszPath));
if (FALSE == fResult)
{
hr = TraceResult(E_OUTOFMEMORY);
pStore->FreeRecord(&fi);
goto exit;
}
*pdwAlloc = dwNewSize;
pszInsertPt = *ppszPath + dwChildOffset;
}
// Construct current folder path, insert into table
StrCpyN(pszInsertPt, fi.pszName, *pdwAlloc - (int) (pszInsertPt - *ppszPath));
hr = pHash->Insert(*ppszPath, (LPVOID)fi.idFolder, NOFLAGS);
if (FAILED(hr))
{
TraceResult(hr);
pStore->FreeRecord(&fi);
goto exit;
}
// if this folder has kids, recurse into it's child folders
if (fi.dwFlags & FOLDER_HASCHILDREN)
{
// Append hierarchy character to current foldername
IxpAssert(0 != fi.bHierarchy && 0xFF != fi.bHierarchy);
Assert(dwFldrNameLen + 1 + dwChildOffset < *pdwAlloc); // Hierarchy char is guaranteed to fit (see above)
pszInsertPt[dwFldrNameLen] = fi.bHierarchy;
pszInsertPt[dwFldrNameLen + 1] = '\0'; // Don't need to null-term
hr = HashChildren(pStore, fi.idFolder, pHash, ppszPath,
dwChildOffset + dwFldrNameLen + 1, pdwAlloc);
if (FAILED(hr))
{
TraceResult(hr);
pStore->FreeRecord(&fi);
goto exit;
}
// Recalculate pszInsertPt, in case HashChildren re-alloc'ed
pszInsertPt = *ppszPath + dwChildOffset;
}
pStore->FreeRecord(&fi);
}
exit:
ReleaseObj(pFldrEnum);
return hr;
}
#define CMAX_DELETE_SEARCH_BLOCK 50
HRESULT UnsubscribeHashedFolders(IMessageStore *pStore, IHashTable *pHash)
{
ULONG cFound=0;
LPVOID *rgpv;
pHash->Reset();
while (SUCCEEDED(pHash->Next(CMAX_DELETE_SEARCH_BLOCK, &rgpv, &cFound)))
{
while(cFound--)
{
pStore->SubscribeToFolder((FOLDERID)rgpv[cFound], FALSE, NULL);
}
SafeMemFree(rgpv);
}
return S_OK;
}
#ifdef DEBUG
LPCSTR sotToSz(STOREOPERATIONTYPE sot)
{
switch (sot)
{
case SOT_INVALID:
return "Invalid";
case SOT_CONNECTION_STATUS:
return "ConnectionStatus";
case SOT_SYNC_FOLDER:
return "SyncFolder";
case SOT_GET_MESSAGE:
return "GetMessage";
case SOT_PUT_MESSAGE:
return "PutMessage";
case SOT_COPYMOVE_MESSAGE:
return "CopyMoveMessage";
case SOT_SYNCING_STORE:
return "SyncStore";
case SOT_CREATE_FOLDER:
return "CreateFolder";
case SOT_SEARCHING:
return "Search";
case SOT_DELETING_MESSAGES:
return "DeleteMessage";
case SOT_SET_MESSAGEFLAGS:
return "SetMessageFlags";
case SOT_MOVE_FOLDER:
return "MoveFolder";
case SOT_DELETE_FOLDER:
return "DeleteFolder";
case SOT_RENAME_FOLDER:
return "RenameFolder";
case SOT_SUBSCRIBE_FOLDER:
return "SubscribeFolder";
case SOT_UPDATE_FOLDER:
return "UpdateFolderCounts";
case SOT_GET_NEW_GROUPS:
return "GetNewGroups";
case SOT_PURGING_MESSAGES:
return "PurgeMessages";
case SOT_NEW_MAIL_NOTIFICATION:
return "NewMailNotify";
default:
return "<SOT_UNKNOWN>";
}
}
#endif
HRESULT SetSynchronizeFlags(FOLDERID idFolder, DWORD flags)
{
FOLDERINFO info;
HRESULT hr;
Assert(0 == (flags & ~(FOLDER_DOWNLOADHEADERS | FOLDER_DOWNLOADNEW | FOLDER_DOWNLOADALL)));
hr = g_pStore->GetFolderInfo(idFolder, &info);
if (SUCCEEDED(hr))
{
info.dwFlags &= ~(FOLDER_DOWNLOADHEADERS | FOLDER_DOWNLOADNEW | FOLDER_DOWNLOADALL);
if (flags != 0)
info.dwFlags |= flags;
hr = g_pStore->UpdateRecord(&info);
g_pStore->FreeRecord(&info);
}
return(hr);
}
HRESULT CreateMessageFromInfo(MESSAGEINFO *pInfo, IMimeMessage **ppMessage, FOLDERID folderID)
{
IMimeMessage *pMsg=0;
HRESULT hr;
PROPVARIANT pv;
if (!ppMessage || !pInfo)
return TraceResult(E_INVALIDARG);
*ppMessage = NULL;
hr = HrCreateMessage(&pMsg);
if (FAILED(hr))
{
TraceResult(hr);
goto exit;
}
// sent-time
pv.vt = VT_FILETIME;
CopyMemory(&pv.filetime, &pInfo->ftSent, sizeof(FILETIME));
pMsg->SetProp(PIDTOSTR(PID_ATT_SENTTIME), 0, &pv);
MimeOleSetBodyPropA(pMsg, HBODY_ROOT, PIDTOSTR(PID_HDR_MESSAGEID), NOFLAGS, pInfo->pszMessageId);
MimeOleSetBodyPropA(pMsg, HBODY_ROOT, PIDTOSTR(PID_HDR_SUBJECT), NOFLAGS, pInfo->pszSubject);
MimeOleSetBodyPropA(pMsg, HBODY_ROOT, PIDTOSTR(PID_HDR_FROM), NOFLAGS, pInfo->pszFromHeader);
MimeOleSetBodyPropA(pMsg, HBODY_ROOT, PIDTOSTR(PID_HDR_TO), NOFLAGS, pInfo->pszDisplayTo);
if (FOLDERID_INVALID != folderID)
{
FOLDERINFO fi;
hr = g_pStore->GetFolderInfo(folderID, &fi);
if (SUCCEEDED(hr))
{
if (FOLDER_NEWS == fi.tyFolder)
{
if (0 == (FOLDER_SERVER & fi.dwFlags))
hr = MimeOleSetBodyPropA(pMsg, HBODY_ROOT, PIDTOSTR(PID_HDR_NEWSGROUPS), NOFLAGS, fi.pszName);
}
g_pStore->FreeRecord(&fi);
}
}
HrSetAccount(pMsg, pInfo->pszAcctName);
*ppMessage = pMsg;
pMsg = NULL;
hr = S_OK;
exit:
ReleaseObj(pMsg);
return hr;
}
HRESULT CommitMessageToStore(IMessageFolder *pFolder, ADJUSTFLAGS *pflags, MESSAGEID idMessage, LPSTREAM pstm)
{
HRESULT hr;
IMimeMessage *pMsg=0;
DWORD dwFlags=0,
dwAddFlags=0,
dwRemoveFlags=0;
MESSAGEIDLIST rMsgList;
ADJUSTFLAGS rAdjFlags;
TraceCall("CIMAPSync::_OnMessageDownload");
Assert (pFolder);
hr = MimeOleCreateMessage(NULL, &pMsg);
if (FAILED(hr))
{
TraceResult(hr);
goto exit;
}
hr = pMsg->Load(pstm);
if (FAILED(hr))
{
TraceResult(hr);
goto exit;
}
if (SUCCEEDED(pMsg->GetFlags(&dwFlags)))
dwAddFlags = ConvertIMFFlagsToARF(dwFlags);
// We always want to remove ARF_DOWNLOAD when downloading a message body
dwRemoveFlags |= ARF_DOWNLOAD;
rMsgList.cAllocated = 0;
rMsgList.cMsgs = 1;
rMsgList.prgidMsg = &idMessage;
if (pflags==NULL)
{
pflags = &rAdjFlags;
rAdjFlags.dwRemove = 0;
rAdjFlags.dwAdd = 0;
}
pflags->dwAdd |= dwAddFlags;
pflags->dwRemove |= dwRemoveFlags;
hr = pFolder->SetMessageFlags(&rMsgList, pflags, NULL, NULL);
if (FAILED(hr))
{
TraceResult(hr);
goto exit;
}
hr = pFolder->SetMessageStream(idMessage, pstm);
if (FAILED(hr))
{
TraceResult(hr);
goto exit;
}
exit:
ReleaseObj(pMsg);
return hr;
}
HRESULT CreatePersistentWriteStream(IMessageFolder *pFolder, IStream **ppStream, LPFILEADDRESS pfaStream)
{
HRESULT hr=S_OK;
TraceCall("CreateOpenStream");
Assert(NULL != pFolder && NULL != ppStream && NULL != pfaStream);
if (NULL == pFolder || NULL == ppStream || NULL == pfaStream)
return E_INVALIDARG;
*ppStream = NULL;
*pfaStream = 0;
hr = pFolder->CreateStream(pfaStream);
if (!FAILED(hr))
{
hr = pFolder->OpenStream(ACCESS_WRITE, *pfaStream, ppStream);
if (FAILED(hr))
{
pFolder->DeleteStream(*pfaStream);
*pfaStream = 0;
}
}
return hr;
}
HRESULT GetHighestCachedMsgID(IMessageFolder *pFolder, DWORD_PTR *pdwHighestCachedMsgID)
{
HRESULT hr;
HROWSET hRowSet = HROWSET_INVALID;
MESSAGEINFO miMsgInfo = {0};
TraceCall("GetHighestCachedMsgID");
Assert(NULL != pdwHighestCachedMsgID);
hr = pFolder->CreateRowset(IINDEX_PRIMARY, NOFLAGS, &hRowSet);
if (FAILED(hr))
{
TraceResult(hr);
goto exit;
}
hr = pFolder->SeekRowset(hRowSet, SEEK_ROWSET_END, 0, NULL);
if (FAILED(hr))
{
TraceResult(hr);
goto exit;
}
hr = pFolder->QueryRowset(hRowSet, 1, (void **)&miMsgInfo, NULL);
if (FAILED(hr))
{
TraceResult(hr);
goto exit;
}
exit:
if (HROWSET_INVALID != hRowSet)
{
HRESULT hrTemp;
// Record but otherwise ignore error
hrTemp = pFolder->CloseRowset(&hRowSet);
TraceError(hrTemp);
}
// Return highest cached UID
if (DB_E_NORECORDS == hr)
{
// No problem, no records means highest cached UID = 0
*pdwHighestCachedMsgID = 0;
hr = S_OK;
}
else if (SUCCEEDED(hr))
{
*pdwHighestCachedMsgID = (DWORD_PTR) miMsgInfo.idMessage;
pFolder->FreeRecord(&miMsgInfo);
}
return hr;
}
HRESULT DeleteMessageFromStore(MESSAGEINFO * pMsgInfo, IDatabase *pDB, IDatabase * pUidlDB)
{
// Locals
HRESULT hr = S_OK;
UIDLRECORD UidlInfo = {0};
// Trace
TraceCall("DeleteMessageFromStore");
Assert(NULL != g_pStore);
// Check incoming params
if ((NULL == pMsgInfo) || (NULL == pDB))
{
hr = E_INVALIDARG;
goto exit;
}
// Delete the message
IF_FAILEXIT(hr = pDB->DeleteRecord(pMsgInfo));
// Update UIDL Cache ?
if (pUidlDB && !FIsEmptyA(pMsgInfo->pszUidl) && !FIsEmptyA(pMsgInfo->pszServer))
{
// Set Search Key
UidlInfo.pszUidl = pMsgInfo->pszUidl;
UidlInfo.pszServer = pMsgInfo->pszServer;
UidlInfo.pszAccountId = pMsgInfo->pszAcctId;
// Loop it up
if (DB_S_FOUND == pUidlDB->FindRecord(IINDEX_PRIMARY, COLUMNS_ALL, &UidlInfo, NULL))
{
// Deleted on client
UidlInfo.fDeleted = TRUE;
// Set the prop
pUidlDB->UpdateRecord(&UidlInfo);
// Free the Record
pUidlDB->FreeRecord(&UidlInfo);
}
}
hr = S_OK;
exit:
// Done
return(hr);
}
BOOL FFolderIsServer(FOLDERID id)
{
FOLDERINFO fi = {0};
HRESULT hr;
BOOL fServer = FALSE;
// Get Folder Info
hr = g_pStore->GetFolderInfo(id, &fi);
if (FAILED(hr))
return (FALSE);
// Is this a server ?
fServer = ISFLAGSET(fi.dwFlags, FOLDER_SERVER);
g_pStore->FreeRecord(&fi);
return (fServer);
}
HRESULT GetIdentityStoreRootDirectory(IUserIdentity *pId, LPSTR pszDir, DWORD cchMaxDir)
{
// Locals
HKEY hkey;
char szProfile[MAX_PATH];
HRESULT hr=S_OK;
DWORD cb;
DWORD dwType;
Assert(pId != NULL);
Assert(pszDir != NULL);
Assert(cchMaxDir >= MAX_PATH);
hr = pId->OpenIdentityRegKey(KEY_ALL_ACCESS, &hkey);
if (FAILED(hr))
return(hr);
// Get the Root Directory
cb = cchMaxDir;
if (ERROR_SUCCESS != SHGetValue(hkey, c_szRegRoot, c_szRegStoreRootDir, &dwType, (LPBYTE)pszDir, &cb))
{
// Get Default Root
IF_FAILEXIT(hr = MU_GetIdentityDirectoryRoot(pId, pszDir, cchMaxDir));
// If the directory doesn't exist yet ?
if (FALSE == PathIsDirectory(pszDir))
{
// Our default directory doesn't exist, so create it
IF_FAILEXIT(hr = OpenDirectory(pszDir));
}
// Set the Store Directory
dwType = AddEnvInPath(pszDir, szProfile, ARRAYSIZE(szProfile)) ? REG_EXPAND_SZ : REG_SZ;
SHSetValue(hkey, c_szRegRoot, c_szRegStoreRootDir, dwType, pszDir, lstrlen(pszDir) + 1);
}
// Get the length
cb = lstrlen(pszDir);
// No root
if (0 == cb)
{
hr = TraceResult(E_FAIL);
goto exit;
}
// Fixup the end
PathRemoveBackslash(pszDir);
// If the directory doesn't exist yet ?
if (FALSE == PathIsDirectory(pszDir))
{
// Our default directory doesn't exist, so create it
IF_FAILEXIT(hr = OpenDirectory(pszDir));
}
exit:
RegCloseKey(hkey);
return hr;
}
HRESULT ImportSubNewsGroups(IUserIdentity *pId, IImnAccount *pAcct, LPCSTR pszGroups)
{
HRESULT hr;
FOLDERINFO Folder;
IMessageStore *pStore;
FOLDERID idServer;
char szStoreDir[MAX_PATH + MAX_PATH];
Assert(pszGroups != NULL);
if (pId == NULL)
{
Assert(g_pLocalStore != NULL);
pStore = g_pLocalStore;
pStore->AddRef();
}
else
{
hr = GetIdentityStoreRootDirectory(pId, szStoreDir, ARRAYSIZE(szStoreDir));
if (FAILED(hr))
return(hr);
hr = CoCreateInstance(CLSID_MessageStore, NULL, CLSCTX_INPROC_SERVER, IID_IMessageStore, (LPVOID *)&pStore);
if (FAILED(hr))
return(hr);
hr = pStore->Initialize(szStoreDir);
if (FAILED(hr))
{
pStore->Release();
return(hr);
}
}
hr = pStore->CreateServer(pAcct, NOFLAGS, &idServer);
if (SUCCEEDED(hr))
{
while (*pszGroups != 0)
{
ZeroMemory(&Folder, sizeof(FOLDERINFO));
Folder.pszName = (LPSTR)pszGroups;
Folder.idParent = idServer;
if (DB_S_FOUND == pStore->FindRecord(IINDEX_ALL, COLUMNS_ALL, &Folder, NULL))
{
if ((Folder.dwFlags & FOLDER_SUBSCRIBED) == 0)
{
Folder.dwFlags |= FOLDER_SUBSCRIBED;
pStore->UpdateRecord(&Folder);
}
pStore->FreeRecord(&Folder);
}
else
{
Folder.tySpecial = FOLDER_NOTSPECIAL;
Folder.dwFlags = FOLDER_SUBSCRIBED;
hr = pStore->CreateFolder(NOFLAGS, &Folder, NULL);
Assert(hr != STORE_S_ALREADYEXISTS);
if (FAILED(hr))
break;
}
pszGroups += (lstrlen(pszGroups) + 1);
}
}
pStore->Release();
return(hr);
}
HRESULT DoNewsgroupSubscribe()
{
HKEY hkey, hkeyT, hkeyUser;
char szKey[MAX_PATH];
DWORD cAccts, iAcct, cb;
LONG lResult, cch, i;
LPSTR psz;
BOOL fDelete;
HRESULT hr;
IImnAccount *pAcct;
fDelete = TRUE;
hkeyUser = MU_GetCurrentUserHKey();
if (ERROR_SUCCESS == RegOpenKeyEx(hkeyUser, c_szRegRootSubscribe, 0, KEY_READ, &hkey))
{
if (ERROR_SUCCESS == RegQueryInfoKey(hkey, NULL, NULL, 0, &cAccts, NULL, NULL, NULL, NULL, NULL, NULL, NULL) &&
cAccts > 0)
{
for (iAcct = 0; iAcct < cAccts; iAcct++)
{
cb = sizeof(szKey);
lResult = RegEnumKeyEx(hkey, iAcct, szKey, &cb, 0, NULL, NULL, NULL);
// No more items
if (lResult == ERROR_NO_MORE_ITEMS)
break;
// Error, lets move onto the next account
if (lResult != ERROR_SUCCESS)
{
Assert(FALSE);
continue;
}
hr = S_OK;
if (SUCCEEDED(g_pAcctMan->FindAccount(AP_ACCOUNT_ID, szKey, &pAcct)))
{
if (ERROR_SUCCESS == RegQueryValue(hkey, szKey, NULL, &cch) && cch > 0)
{
hr = E_FAIL;
cch++;
if (MemAlloc((void **)&psz, cch))
{
if (ERROR_SUCCESS == RegQueryValue(hkey, szKey, psz, &cch))
{
for (i = 0; i < cch; i++)
{
if (psz[i] == ',')
psz[i] = 0;
}
psz[cch] = 0;
hr = ImportSubNewsGroups(NULL, pAcct, psz);
}
MemFree(psz);
}
}
pAcct->Release();
}
if (SUCCEEDED(hr))
RegDeleteKey(hkey, szKey);
else
fDelete = FALSE;
}
}
RegCloseKey(hkey);
if (fDelete)
RegDeleteKey(hkeyUser, c_szRegRootSubscribe);
}
return(S_OK);
}
void GetProtocolString(LPCSTR *ppszResult, IXPTYPE ixpServerType)
{
switch (ixpServerType)
{
case IXP_POP3:
*ppszResult = "POP3";
break;
case IXP_SMTP:
*ppszResult = "SMTP";
break;
case IXP_NNTP:
*ppszResult = "NNTP";
break;
case IXP_IMAP:
*ppszResult = "IMAP";
break;
case IXP_HTTPMail:
*ppszResult = "HTTPMail";
break;
default:
*ppszResult = "Unknown";
break;
}
}
INT_PTR CALLBACK UpdateNewsgroup(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
char sz[CCHMAX_STRINGRES];
BOOL fEnabled;
HICON hicon;
static PUPDATENEWSGROUPINFO puni = 0;
switch (uMsg)
{
case WM_INITDIALOG:
// Get the init info
puni = (PUPDATENEWSGROUPINFO) lParam;
Assert(puni);
if (!puni->fNews)
{
AthLoadString(idsSyncFolderTitle, sz, ARRAYSIZE(sz));
SetWindowText(hwnd, sz);
hicon = LoadIcon(g_hLocRes, MAKEINTRESOURCE(idiDLMail));
SendDlgItemMessage(hwnd, idcStatic1, STM_SETIMAGE, IMAGE_ICON, (LPARAM)hicon);
}
// Initialize the dialog settings
fEnabled = (puni->dwGroupFlags & (FOLDER_DOWNLOADHEADERS | FOLDER_DOWNLOADNEW | FOLDER_DOWNLOADALL));
Button_SetCheck(GetDlgItem(hwnd, IDC_GET_CHECK), fEnabled);
Button_Enable(GetDlgItem(hwnd, IDC_NEWHEADERS_RADIO), fEnabled);
Button_Enable(GetDlgItem(hwnd, IDC_NEWMSGS_RADIO), fEnabled);
Button_Enable(GetDlgItem(hwnd, IDC_ALLMSGS_RADIO), fEnabled);
// Check the right radio button
if (fEnabled)
{
if (puni->dwGroupFlags & FOLDER_DOWNLOADHEADERS)
Button_SetCheck(GetDlgItem(hwnd, IDC_NEWHEADERS_RADIO), TRUE);
if (puni->dwGroupFlags & FOLDER_DOWNLOADNEW)
Button_SetCheck(GetDlgItem(hwnd, IDC_NEWMSGS_RADIO), TRUE);
if (puni->dwGroupFlags & FOLDER_DOWNLOADALL)
Button_SetCheck(GetDlgItem(hwnd, IDC_ALLMSGS_RADIO), TRUE);
}
else if (puni->fNews)
{
Button_SetCheck(GetDlgItem(hwnd, IDC_NEWMSGS_RADIO), TRUE);
}
else
{
Button_SetCheck(GetDlgItem(hwnd, IDC_ALLMSGS_RADIO), TRUE);
}
Button_SetCheck(GetDlgItem(hwnd, IDC_GETMARKED_CHECK), puni->cMarked != 0);
EnableWindow(GetDlgItem(hwnd, IDC_GETMARKED_CHECK), puni->cMarked != 0);
EnableWindow(GetDlgItem(hwnd, IDOK), fEnabled || puni->cMarked != 0);
return (TRUE);
case WM_COMMAND:
switch (GET_WM_COMMAND_ID(wParam, lParam))
{
case IDC_GET_CHECK:
// Check to see whether this is actually checked or not
fEnabled = Button_GetCheck(GET_WM_COMMAND_HWND(wParam, lParam));
// Enable or disable the radio buttons
Button_Enable(GetDlgItem(hwnd, IDC_NEWHEADERS_RADIO), fEnabled);
Button_Enable(GetDlgItem(hwnd, IDC_NEWMSGS_RADIO), fEnabled);
Button_Enable(GetDlgItem(hwnd, IDC_ALLMSGS_RADIO), fEnabled);
EnableWindow(GetDlgItem(hwnd, IDOK), fEnabled || Button_GetCheck(GetDlgItem(hwnd, IDC_GETMARKED_CHECK)));
return (TRUE);
case IDC_GETMARKED_CHECK:
EnableWindow(GetDlgItem(hwnd, IDOK), Button_GetCheck(GET_WM_COMMAND_HWND(wParam, lParam)) || Button_GetCheck(GetDlgItem(hwnd, IDC_GET_CHECK)));
return(TRUE);
case IDOK:
// Set up the return value
if (Button_GetCheck(GetDlgItem(hwnd, IDC_GET_CHECK)))
{
if (Button_GetCheck(GetDlgItem(hwnd, IDC_NEWHEADERS_RADIO)))
puni->idCmd |= DELIVER_OFFLINE_HEADERS;
else if (Button_GetCheck(GetDlgItem(hwnd, IDC_ALLMSGS_RADIO)))
puni->idCmd |= DELIVER_OFFLINE_ALL;
else if (Button_GetCheck(GetDlgItem(hwnd, IDC_NEWMSGS_RADIO)))
puni->idCmd |= DELIVER_OFFLINE_NEW;
}
if (Button_GetCheck(GetDlgItem(hwnd, IDC_GETMARKED_CHECK)))
{
puni->idCmd |= DELIVER_OFFLINE_MARKED;
}
EndDialog(hwnd, 0);
return (TRUE);
case IDCANCEL:
puni->idCmd = -1;
EndDialog(hwnd, 0);
return (TRUE);
}
return (FALSE);
}
return (FALSE);
}
HRESULT HasMarkedMsgs(FOLDERID idFolder, BOOL *pfMarked)
{
HRESULT hr;
HROWSET hRowset;
MESSAGEINFO MsgInfo;
IMessageFolder *pFolder;
Assert(pfMarked != NULL);
*pfMarked = FALSE;
hr = g_pStore->OpenFolder(idFolder, NULL, OPEN_FOLDER_NOCREATE, &pFolder);
if (FAILED(hr))
return(hr);
hr = pFolder->CreateRowset(IINDEX_PRIMARY, 0, &hRowset);
if (SUCCEEDED(hr))
{
while (S_OK == pFolder->QueryRowset(hRowset, 1, (void **)&MsgInfo, NULL))
{
if (!!(MsgInfo.dwFlags & (ARF_DOWNLOAD | ARF_WATCH)) && 0 == (MsgInfo.dwFlags & ARF_HASBODY))
{
pFolder->FreeRecord(&MsgInfo);
*pfMarked = TRUE;
break;
}
// Free the header info
pFolder->FreeRecord(&MsgInfo);
}
// Release Lock
pFolder->CloseRowset(&hRowset);
}
pFolder->Release();
return (hr);
}
HRESULT SimpleInitStoreForDir(LPCSTR szStoreDir)
{
CStoreSync *pStore;
HRESULT hr = S_OK;
if (g_pStore == NULL)
{
Assert(g_pLocalStore == NULL);
g_pLocalStore = new CMessageStore(FALSE);
if (g_pLocalStore == NULL)
return(E_OUTOFMEMORY);
hr = g_pLocalStore->Initialize(szStoreDir);
if (SUCCEEDED(hr))
{
pStore = new CStoreSync;
if (pStore == NULL)
{
hr = E_OUTOFMEMORY;
}
else
{
hr = pStore->Initialize(g_pLocalStore);
if (SUCCEEDED(hr))
{
g_pStore = pStore;
hr = g_pLocalStore->Validate(STORE_VALIDATE_DONTSYNCWITHACCOUNTS);
}
else
{
pStore->Release();
}
}
}
}
return(hr);
}
HRESULT SimpleStoreInit(GUID *guid, LPCSTR szStoreDir)
{
HRESULT hr = S_OK;
// Init options
if (FALSE == InitGlobalOptions(NULL, NULL))
{
goto exit;
}
// Create account manger
if (NULL == g_pAcctMan)
{
hr = AcctUtil_CreateAccountManagerForIdentity(guid ? guid : PGUIDCurrentOrDefault(), &g_pAcctMan);
if (FAILED(hr))
{
TraceResult(hr);
goto exit;
}
}
// Create the global connection manager
if (NULL == g_pConMan)
{
g_pConMan = new CConnectionManager();
if (NULL == g_pConMan)
{
hr = TraceResult(E_OUTOFMEMORY);
goto exit;
}
// CoIncrementInit the Connection Manager
hr = g_pConMan->HrInit(g_pAcctMan);
if (FAILED(hr))
{
TraceResult(hr);
goto exit;
}
}
hr = SimpleInitStoreForDir(szStoreDir);
if (FAILED(hr))
{
TraceResult(hr);
goto exit;
}
exit:
return hr;
}
HRESULT SimpleStoreRelease()
{
HRESULT hr = S_OK;
SafeRelease(g_pLocalStore);
SafeRelease(g_pStore);
SafeRelease(g_pConMan);
SafeRelease(g_pAcctMan);
DeInitGlobalOptions();
return hr;
}