STORAGE.CPP

/////////////////////////////////////////////////////////////////////////////// 
//
// File Name
// STORAGE.CPP
//
// Description
//
// Author
// Irving De la Cruz
//
// Revision: 1.7
//
// Written for Microsoft Windows Developer Support
// Copyright (c) 1995-1996 Microsoft Corporation. All rights reserved.
//
#include "_WINDS.H"
#include "WDSADM.H" // Header file generated by the MIDL compiler
#include "COMMON.H"
#include "STDIO.H"

// Remark this line to turn verbose tracing OFF
#define DO_INFO_TRACES
#ifdef DO_INFO_TRACES
#define InfoTrace(a) TraceInfoMessage(a)
#define InfoTraceRaw(a) TraceRaw(a)
#define InfoTraceProp(a) TraceProp(a)
#else
#define InfoTrace(a) 0
#define InfoTraceRaw(a) 0
#define InfoTraceProp(a) 0
#endif // DO_INFO_TRACES

extern "C"
{
HRESULT WINAPI LoadObjectProperties
(LPSTORAGE pStorage,
WINDS_AB_OBJTYPE Type,
LPTSTR pszObjectType,
LPMALLOC pMalloc);
HRESULT WINAPI GetDLProperties
(LPSTORAGE pStorage,
LPOLESTR pwcsDLName,
PDIST_LIST_INFO pDLInfo,
BOOL fGetMembers = FALSE);
HRESULT WINAPI SetDLProperties
(LPSTORAGE pStorage,
LPOLESTR pwcsDLName,
PDIST_LIST_INFO pDLInfo);
HRESULT WINAPI DLPropsAndMembers
(LPSTORAGE pStorage,
PDIST_LIST_INFO pDLInfo,
BOOL fGetProps);
HRESULT WINAPI CreateDistributionList
(LPSTORAGE pStorage,
PDIST_LIST_INFO pDLInfo);
HRESULT WINAPI DeleteDistributionList
(LPSTORAGE pStorage,
PDIST_LIST_INFO pDLInfo);
HRESULT WINAPI GetNextObjID
(LPSTORAGE pStorage,
DWORD & dwNextID);
HRESULT WINAPI ReadABContainerInfo
(LPSTORAGE pStorage,
LPMALLOC pMalloc,
DWORD dwContainerID,
HANDLE hPipe);
HRESULT WINAPI EnumContainerObjs
(LPSTORAGE pDirectoryStg,
HANDLE hPipe,
WINDS_AB_OBJTYPE Type,
LPMALLOC pMalloc);
HRESULT WINAPI GetDLRecipientsInfo
(LPSTORAGE pMBDirectory,
LPSTORAGE pDLDirectory,
HANDLE hPipe,
LPOLESTR pwcsDLName);
HRESULT WINAPI CreateMailbox
(LPSTORAGE pMBDirectory,
PMAILBOX_INFO pMBInfo);
HRESULT WINAPI MailboxProps
(LPSTORAGE pMBDirectory,
PMAILBOX_INFO pMBInfo,
BOOL fRetrieve);
HRESULT WINAPI GetGWContainerCount
(LPSTORAGE pStorage,
LPMALLOC pMalloc,
DWORD dwContainerID,
DWORD * pdwContainerCount);
HRESULT WINAPI CopyMsgFromFile
(LPSTORAGE pStorage,
HANDLE hFile,
LPTSTR pszMailbox,
LPTSTR pszHeader);
HRESULT WINAPI RemoveMessageFromMailbox
(LPSTORAGE pStorage,
LPTSTR pszMailbox,
DWORD dwStreamID);
HRESULT WINAPI UpdateMailboxHeaders
(LPSTORAGE pStorage,
LPSTORAGE pMBStg,
LPTSTR pszMailbox,
DWORD dwStreamID,
LPTSTR pszHeader,
BOOL fAddMsgToHeadersList);
HRESULT WINAPI LoadServerObjects
(LPSTORAGE pStorage,
LPMALLOC pMalloc);
HRESULT WINAPI OpenMsgsDataFile
(LPSTORAGE * ppStorage);
HRESULT WINAPI GetMailBoxInfo
(LPSTORAGE pStorage,
LPOLESTR pwcsName,
PMAILBOX_INFO pInfo);
HRESULT WINAPI SetMailBoxInfo
(LPSTORAGE pStorage,
LPOLESTR pwcsName,
PMAILBOX_INFO pInfo);
HRESULT WINAPI DeleteMailbox
(LPSTORAGE pStorage,
PMAILBOX_INFO pInfo);
HRESULT WINAPI EmptyMailBoxMsgs
(LPSTORAGE pStorage,
LPTSTR pszMailbox);
HRESULT WINAPI CopyHeadersToFile
(LPSTORAGE pStorage,
LPMALLOC pMalloc,
HANDLE hFile,
LPTSTR pszMailbox);
HRESULT WINAPI CopyMsgToFile
(LPSTORAGE pStorage,
LPTSTR pszMailbox,
HANDLE hFile,
ULONG * pulMsgLen,
DWORD dwStreamID,
BOOL fDeleteAfterCopy);
HRESULT WINAPI CopyStreamToFile
(LPSTREAM pStream,
HANDLE hFile,
ULONG * pulWritten);
HRESULT WINAPI CheckForPendingMailboxMsgs
(LPSTORAGE pStorage,
LPMALLOC pMalloc,
LPTSTR szMailbox,
DWORD * pdwMsgCount);
HRESULT WINAPI GetNextMailboxMsg
(LPSTORAGE pStorage,
LPMALLOC pMalloc,
LPTSTR szMailbox,
DWORD * pdwMsgID,
HANDLE hFile);
};

///////////////////////////////////////////////////////////////////////////////
// WorkingIOProc()
//
// Parameters
//
// Purpose
//
// Return Value
//
DWORD WINAPI WorkingIOProc()
{
//InfoTrace ("WorkingIOProc: Just starting up");
// Standard COM initialization so that we may use IStorage and IStream
LPMALLOC pMalloc;
HRESULT hResult = CoInitialize (NULL);
TraceResult ("WorkingIOProc: Failed to initialize the COM libraries", hResult);
if (!hResult)
{
hResult = CoGetMalloc (MEMCTX_TASK, &pMalloc);
TraceResult ("WorkingIOProc: Failed to get an IMalloc interface", hResult);
}
if (FAILED(hResult))
{
InfoTrace ("WorkingIOProc: Just bailing out now");
CoUninitialize();
g_hServerState = CO_E_NOTINITIALIZED;
return g_hServerState;
}
LPSTORAGE pStorage = NULL;

DWORD dwException = 0;

while (TRUE)
{
WaitForSingleObject (g_IOInfo.hResumeEvent, INFINITE);
//InfoTrace ("WorkingIOProc: Resumed. About to request the critical section...");
EnterCriticalSection (&g_csIOInfo);
//InfoTrace ("WorkingIOProc: ...Executing in critical section");
if (g_IOInfo.fAppIsTerminating)
{
InfoTrace ("WorkingIOProc: We are going down");
if (pStorage)
{
pStorage->Release();
pStorage = NULL;
}
break; // out of the WHILE() loop
}
ProcessNextAction:
switch (g_IOInfo.Action)
{
case IO_OPEN_STORAGE_FILE :
InfoTrace ("WorkingIOProc: Servicing IO_OPEN_STORAGE_FILE");
__try
{
hResult = OpenMsgsDataFile (&pStorage);
if (hResult)
{
g_hServerState = HRESULT_FROM_WIN32(ERROR_STATIC_INIT);
}
else
{
g_hServerState = S_OK; // Server is ready to accept requests
}
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
dwException = GetExceptionCode();
}
break;

case IO_LOAD_MAILBOX_NAMES :
InfoTrace ("WorkingIOProc: Servicing IO_LOAD_MAILBOX_NAMES");
__try
{
hResult = LoadServerObjects (pStorage, pMalloc);
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
dwException = GetExceptionCode();
}
// Restore notification links with the clients from a previous session
g_IOInfo.Action = IO_RESTORE_CLIENT_NOTIFICATIONS;
goto ProcessNextAction;
break;

case IO_GET_CONTAINER_RECIPIENTS :
InfoTrace ("WorkingIOProc: Servicing IO_GET_CONTAINER_RECIPIENTS");
__try
{
hResult = ReadABContainerInfo (pStorage,
pMalloc,
g_IOInfo.dwObjID,
g_IOInfo.hTmpFile);
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
dwException = GetExceptionCode();
}
break;

case IO_CREATE_NEW_MAILBOX :
InfoTrace ("WorkingIOProc: Servicing IO_CREATE_NEW_MAILBOX");
__try
{
hResult = CreateMailbox (pStorage, g_IOInfo.pMBInfo);
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
dwException = GetExceptionCode();
}
break;

case IO_EMPTY_MAILBOX :
InfoTrace ("WorkingIOProc: Servicing IO_EMPTY_MAILBOX");
__try
{
hResult = EmptyMailBoxMsgs (pStorage, g_IOInfo.szObject);
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
dwException = GetExceptionCode();
}
break;

case IO_REMOVE_MAILBOX :
InfoTrace ("WorkingIOProc: Servicing IO_REMOVE_MAILBOX");
__try
{
hResult = DeleteMailbox (pStorage, g_IOInfo.pMBInfo);
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
dwException = GetExceptionCode();
}
break;

case IO_GET_MAILBOX_PROPERTIES :
InfoTrace ("WorkingIOProc: Servicing IO_GET_MAILBOX_PROPERTIES");
__try
{
hResult = MailboxProps (pStorage, g_IOInfo.pMBInfo, TRUE);
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
dwException = GetExceptionCode();
}
break;

case IO_SET_MAILBOX_PROPERTIES :
InfoTrace ("WorkingIOProc: Servicing IO_SET_MAILBOX_PROPERTIES");
__try
{
hResult = MailboxProps (pStorage, g_IOInfo.pMBInfo, FALSE);
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
dwException = GetExceptionCode();
}
break;

case IO_COPY_MSG_FROM_FILE :
InfoTrace ("WorkingIOProc: Servicing IO_COPY_MSG_FROM_FILE");
__try
{
hResult = CopyMsgFromFile (pStorage,
g_IOInfo.hTmpFile,
g_IOInfo.szObject,
g_IOInfo.szHeader);
if (g_IOInfo.fCloseHandle)
{
CloseHandle (g_IOInfo.hTmpFile);
}
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
dwException = GetExceptionCode();
}
break;

case IO_COPY_HEADERS_TO_FILE :
InfoTrace ("WorkingIOProc: Servicing IO_COPY_HEADERS_TO_FILE");
__try
{
hResult = CopyHeadersToFile (pStorage,
pMalloc,
g_IOInfo.hTmpFile,
g_IOInfo.szObject);
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
dwException = GetExceptionCode();
}
break;

case IO_CHECK_PENDING_MESSAGES :
InfoTrace ("WorkingIOProc: Servicing IO_CHECK_PENDING_MESSAGES");
__try
{
hResult = CheckForPendingMailboxMsgs (pStorage,
pMalloc,
g_IOInfo.szObject,
g_IOInfo.pdwData);
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
dwException = GetExceptionCode();
}
break;

case IO_COPY_MSG_TO_FILE :
InfoTrace ("WorkingIOProc: Servicing IO_COPY_MSG_TO_FILE");
__try
{
hResult = CopyMsgToFile (pStorage,
g_IOInfo.szObject,
g_IOInfo.hTmpFile,
g_IOInfo.pdwData,
g_IOInfo.dwObjID,
FALSE);
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
dwException = GetExceptionCode();
}
break;

case IO_MOVE_MSG_TO_FILE :
InfoTrace ("WorkingIOProc: Servicing IO_MOVE_MSG_TO_FILE");
__try
{
hResult = CopyMsgToFile (pStorage,
g_IOInfo.szObject,
g_IOInfo.hTmpFile,
g_IOInfo.pdwData,
g_IOInfo.dwObjID,
TRUE);
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
dwException = GetExceptionCode();
}
break;

case IO_MOVE_NEXT_MSG_TO_FILE :
InfoTrace ("WorkingIOProc: Servicing IO_MOVE_NEXT_MSG_TO_FILE");
__try
{
hResult = GetNextMailboxMsg (pStorage,
pMalloc,
g_IOInfo.szObject,
g_IOInfo.pdwData,
g_IOInfo.hTmpFile);
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
dwException = GetExceptionCode();
}
break;

case IO_DELETE_MSG_IN_MAILBOX :
InfoTrace ("WorkingIOProc: Servicing IO_DELETE_MSG_IN_MAILBOX");
__try
{
hResult = RemoveMessageFromMailbox (pStorage,
g_IOInfo.szObject,
g_IOInfo.dwObjID);
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
dwException = GetExceptionCode();
}
break;

case IO_CREATE_DISTRIBUTION_LIST :
InfoTrace ("WorkingIOProc: Servicing IO_CREATE_DISTRIBUTION_LIST");
__try
{
hResult = CreateDistributionList (pStorage, g_IOInfo.pDLInfo);
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
dwException = GetExceptionCode();
}
break;

case IO_DELETE_DISTRIBUTION_LIST :
InfoTrace ("WorkingIOProc: Servicing IO_DELETE_DISTRIBUTION_LIST");
__try
{
hResult = DeleteDistributionList (pStorage, g_IOInfo.pDLInfo);
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
dwException = GetExceptionCode();
}
break;

case IO_GET_DL_PROPERTIES :
InfoTrace ("WorkingIOProc: Servicing IO_GET_DL_PROPERTIES");
__try
{
hResult = DLPropsAndMembers (pStorage, g_IOInfo.pDLInfo, TRUE);
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
dwException = GetExceptionCode();
}
break;

case IO_SET_DL_PROPERTIES :
InfoTrace ("WorkingIOProc: Servicing IO_SET_DL_PROPERTIES");
__try
{
hResult = DLPropsAndMembers (pStorage, g_IOInfo.pDLInfo, FALSE);
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
dwException = GetExceptionCode();
}
break;

case IO_GET_GW_CONTAINER_COUNT :
InfoTrace ("WorkingIOProc: Servicing IO_GET_GW_CONTAINER_COUNT");
__try
{
hResult = GetGWContainerCount (pStorage,
pMalloc,
g_IOInfo.dwObjID,
g_IOInfo.pdwData);
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
dwException = GetExceptionCode();
}
break;

case IO_SENT_SHUTDOWN_NOTIFICATION :
InfoTrace ("WorkingIOProc: Servicing IO_SENT_SHUTDOWN_NOTIFICATION");
__try
{
ClientNotifThreadProc (g_IOInfo.pNotif);
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
dwException = GetExceptionCode();
}
break;

case IO_RESTORE_CLIENT_NOTIFICATIONS :
InfoTrace ("WorkingIOProc: Servicing IO_RESTORE_CLIENT_NOTIFICATIONS");
__try
{
PWINDS_NOTIFICATION pNotif = (PWINDS_NOTIFICATION)HeapAlloc (ghHeap,
HEAP_ZERO_MEMORY,
sizeof(WINDS_NOTIFICATION));
if (NULL == pNotif)
{
TraceMessage ("WorkingIOProc: Failed to allocate notification structure");
}
else
{
pNotif->Event = SERVER_HAS_RESTARTED;
ClientNotifThreadProc (pNotif);
}
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
dwException = GetExceptionCode();
}
break;

case IO_ADMIN_GET_SERVER_MAILBOXES :
InfoTrace ("WorkingIOProc: Servicing IO_ADMIN_GET_SERVER_MAILBOXES");
__try
{
hResult = WaitForClientConnection (g_IOInfo.hTmpFile, 15);
if (S_OK == hResult)
{
hResult = EnumContainerObjs (pStorage, g_IOInfo.hTmpFile, SERVER_USER_MAILBOX, pMalloc);
}
CloseHandle (g_IOInfo.hTmpFile);
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
dwException = GetExceptionCode();
}
break;
case IO_ADMIN_GET_SERVER_DISTLISTS :
InfoTrace ("WorkingIOProc: Servicing IO_ADMIN_GET_SERVER_DISTLISTS");
__try
{
LPSTORAGE pDirectoryStg;
hResult = pStorage->OpenStorage (DISTRIBUTION_LISTS,
NULL,
OPEN_FLAGS,
NULL,
0,
&pDirectoryStg);
if (S_OK == hResult)
{
hResult = WaitForClientConnection (g_IOInfo.hTmpFile, 15);
if (S_OK == hResult)
{
hResult = EnumContainerObjs (pDirectoryStg,
g_IOInfo.hTmpFile,
SERVER_DISTRIBUTION_LIST,
pMalloc);
}
CloseHandle (g_IOInfo.hTmpFile);
pDirectoryStg->Release();
}
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
dwException = GetExceptionCode();
}
break;

default :
TraceString1 ("WorkingIOProc: Unknown action requested: %d", g_IOInfo.Action);
hResult = (DWORD)HRESULT_FROM_WIN32(ERROR_INVALID_FUNCTION);
break;
}
if (dwException)
{
TraceString2 ("WorkingIOProc: Exception %d occured processing action id %d", dwException, g_IOInfo.Action);
dwException = 0;
hResult = (DWORD)HRESULT_FROM_WIN32(ERROR_EXCEPTION_IN_SERVICE);
}

__try
{
if (g_IOInfo.phLastError)
{
*g_IOInfo.phLastError = hResult;
}
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
dwException = GetExceptionCode();
TraceString2 ("WorkingIOProc: Exception %d occured setting return error code for action id %d", dwException, g_IOInfo.Action);
dwException = 0;
}

if (g_IOInfo.hActionCompleted)
{
SetEvent (g_IOInfo.hActionCompleted);
}
g_IOInfo.Action = IO_IDLE;
g_IOInfo.phLastError = NULL;
g_IOInfo.hActionCompleted = NULL;
g_IOInfo.pdwData = NULL;

//InfoTrace ("WorkingIOProc: About to leave critical section...");
LeaveCriticalSection (&g_csIOInfo);
//InfoTrace ("WorkingIOProc: ...Left critical section");
}
pMalloc->Release();

CoUninitialize();

//InfoTrace ("WorkingIOProc: Just closing down");
if (g_IOInfo.hActionCompleted)
{
SetEvent (g_IOInfo.hActionCompleted);
}
//InfoTrace ("WorkingIOProc: About to leave critical section...");
LeaveCriticalSection (&g_csIOInfo);
//InfoTrace ("WorkingIOProc: ...Left critical section");
return 0;
}

///////////////////////////////////////////////////////////////////////////////
// OpenMsgsDataFile()
//
// Parameters
//
// Purpose
//
// Return Value
//
HRESULT WINAPI OpenMsgsDataFile (LPSTORAGE * ppStorage)
{
DBINFO_DATA dbInfo = { 0 };
LPSTREAM pStream;
HRESULT hResult = S_OK;

#ifdef UNICODE
LPWSTR szFileName = g_szDataFile;
#else
WCHAR wcsFileName[MAX_PATH];
LPWSTR szFileName = wcsFileName;
hResult = AnsiToUnicode (g_szDataFile, wcsFileName, MAX_PATH);
if (hResult)
{
TraceResult ("OpenMsgDataFile: Failed to convert file name to UNICODE", hResult);
return hResult;
}
#endif // UNICODE

hResult = StgIsStorageFile (szFileName);
if (S_OK != hResult)
{
if (S_FALSE == hResult)
{
hResult = S_OK;
goto CreateFileNow;
}
else
{
if (STG_E_FILENOTFOUND != hResult)
{
// else, if any other error occurred
TraceResult ("OpenMsgsDataFile: StgIsStorageFile failed", hResult);
return hResult;
}
else
{
goto CreateFileNow;
}
}
}

hResult = StgOpenStorage (szFileName, NULL, OPEN_FLAGS, NULL, 0, ppStorage);
if (!hResult)
{
hResult = (*ppStorage)->OpenStream (DBINFO_STREAM, NULL, OPEN_FLAGS, 0, &pStream);
if (hResult)
{
TraceResult ("OpenMsgsDataFile: Failed to open DBINFO stream", hResult);
if (STG_E_FILENOTFOUND == hResult)
{
hResult = STG_E_FILENOTFOUND;
}
}
else
{
hResult = pStream->Read (&dbInfo, sizeof(DBINFO_DATA), NULL);
TraceResult ("OpenMsgsDataFile: Failed to read from the DBINFO stream", hResult);
if (!hResult)
{
// If the database version does not match, we will delete
// it and create a new one.
if (WINDS_DATABASE_VERSION != dbInfo.dwVersion)
{
hResult = STG_E_FILENOTFOUND;
}
}
pStream->Release();
}
if (hResult)
{
(*ppStorage)->Release();
*ppStorage = NULL;
}
}
if (STG_E_FILENOTFOUND == hResult)
{
CreateFileNow:
DeleteFile (g_szDataFile);
hResult = StgCreateDocfile (szFileName, CREATE_FLAGS, 0, ppStorage);
TraceResult ("OpenMsgsDataFile: failed to open or create storage object", hResult);
if (!hResult)
{
hResult = (*ppStorage)->CreateStream (DBINFO_STREAM, CREATE_FLAGS, 0, 0, &pStream);
TraceResult ("OpenMsgsDataFile: Failed to create DBINFO stream", hResult);
if (!hResult)
{
dbInfo.dwVersion = WINDS_DATABASE_VERSION;
hResult = pStream->Write (&dbInfo, sizeof(DBINFO_DATA), NULL);
TraceResult ("OpenMsgsDataFile: Failed to write to the DBINFO stream", hResult);
pStream->Release();
if (!hResult)
{
hResult = (*ppStorage)->CreateStream (OBJ_ID_POOL_STREAM, CREATE_FLAGS, 0, 0, &pStream);
TraceResult ("OpenMsgsDataFile: Failed to create Object ID Pool stream", hResult);
if (!hResult)
{
DWORD dwZero = 0;
hResult = pStream->Write (&dwZero, sizeof(DWORD), NULL);

pStream->Release(); 
}
}
}
}
if (!hResult)
{
CreateDLsDirectory (*ppStorage);
CreateGatewayDirectories (*ppStorage);
CreatePublicFoldersDirectory (*ppStorage);
}
if (hResult)
{
DeleteFile (g_szDataFile);
}
}
TraceResult ("OpenMsgsDataFile", hResult);
return hResult;
}

///////////////////////////////////////////////////////////////////////////////
// ReadABContainerInfo()
//
// Parameters
//
// Purpose
//
// Return Value
//
HRESULT WINAPI ReadABContainerInfo (LPSTORAGE pStorage,
LPMALLOC pMalloc,
DWORD dwContainerID,
HANDLE hPipe)
{
BOOL fGalContainer = FALSE;
DWORD dwLastContainerDone = 0;
LPSTORAGE pDirectoryStg;
HRESULT hResult = WaitForClientConnection (hPipe, 15); // 15 second timeout
if (hResult)
{
goto ErrorExit;
}
DoNextContainer:
switch (dwContainerID)
{
case GAL_CONTAINER_ID :
fGalContainer = TRUE;
EnumContainerObjs (pStorage, hPipe, SERVER_USER_MAILBOX, pMalloc);
if (S_OK == pStorage->OpenStorage (DISTRIBUTION_LISTS, NULL, OPEN_FLAGS, NULL, 0, &pDirectoryStg))
{
EnumContainerObjs (pDirectoryStg, hPipe, SERVER_DISTRIBUTION_LIST, pMalloc);
pDirectoryStg->Release();
}
dwLastContainerDone = GAL_CONTAINER_ID;
break;
case EXCHANGE_CONTAINER_ID :
case SMTP_CONTAINER_ID :
case FAX_CONTAINER_ID :
break;
default :
{
TCHAR szDLAlias[MAX_ALIAS_SIZE+1] = { 0 };
WINDS_AB_OBJTYPE Type = UNDEFINED_OBJECT_TYPE;
WCHAR wcsDLalias[64] = { 0 };
if (S_OK == GlobalObjectMap.FindObjFromID (dwContainerID, szDLAlias, &Type) &&
SERVER_DISTRIBUTION_LIST == Type)
{
AnsiToUnicode (szDLAlias, wcsDLalias, 64);
hResult = pStorage->OpenStorage (DISTRIBUTION_LISTS, NULL, OPEN_FLAGS, NULL, 0, &pDirectoryStg);
if (!hResult)
{
hResult = GetDLRecipientsInfo (pStorage, pDirectoryStg, hPipe, wcsDLalias);
pDirectoryStg->Release();
}
TraceResult ("ReadABContainerInfo: Getting DL recipients", hResult);
hResult = S_OK;
}
else
{
hResult = HRESULT_FROM_WIN32(ERROR_NO_SUCH_GROUP);
TraceResult ("ReadABContainerInfo: Invalid container ID passed in", hResult);
}
}
break;
}
if (fGalContainer)
{
dwContainerID++;
if (dwContainerID <= FAX_CONTAINER_ID)
{
goto DoNextContainer;
}
}
ErrorExit:
TraceResult ("ReadABContainerInfo", hResult);
CloseHandle (hPipe);
return hResult;
}

///////////////////////////////////////////////////////////////////////////////
// EnumContainerObjs()
//
// Parameters
//
// Purpose
//
// Return Value
//
HRESULT WINAPI EnumContainerObjs (LPSTORAGE pDirectoryStg,
HANDLE hPipe,
WINDS_AB_OBJTYPE Type,
LPMALLOC pMalloc)
{
LPENUMSTATSTG pEnum;
STATSTG aStat[ELEMENTS_TO_FETCH];
AB_ENTRY_INFO abEntry = { 0 };
abEntry.Type = Type;
LPTSTR pszObjAlias = (SERVER_DISTRIBUTION_LIST == Type ? abEntry.Info.DL.szDLAlias : abEntry.Info.MB.szMailboxName);
ULONG ulMBoxFound = 1;
DWORD dwBytesWritten;
BOOL fFailure;
int nChars;
HRESULT hResult = pDirectoryStg->EnumElements (0, NULL, 0, &pEnum);
TraceResult ("EnumContainerObjs: Failed to get ENUM interface", hResult);
if (!hResult)
{
while (!hResult && ulMBoxFound)
{
hResult = pEnum->Next (ELEMENTS_TO_FETCH, aStat, &ulMBoxFound);
if (FAILED(hResult)) // We might get S_FALSE
{
TraceResult ("EnumContainerObjs: Failed to ENUM streams", hResult);
}
else
{
if (ulMBoxFound)
{
for (ULONG i=0; i<ulMBoxFound; i++)
{
if (STGTY_STORAGE == aStat[i].type && (L'_' != aStat[i].pwcsName[0]))
{
nChars = WideCharToMultiByte (CP_ACP,
0,
aStat[i].pwcsName,
-1,
pszObjAlias,
MAX_ALIAS_SIZE+1,
NULL,
NULL);
if (!nChars)
{
TraceResult ("EnumContainerObjs: Failed to convert storage name", HRESULT_FROM_WIN32(GetLastError()));
}
else
{
if (SERVER_DISTRIBUTION_LIST == Type)
{
fFailure = GetDLProperties (pDirectoryStg, aStat[i].pwcsName, &abEntry.Info.DL);
}
else
{
fFailure = GetMailBoxInfo (pDirectoryStg, aStat[i].pwcsName, &abEntry.Info.MB);
}
if (!fFailure)
{
WriteFile (hPipe, &abEntry, sizeof(AB_ENTRY_INFO), &dwBytesWritten, NULL);
}
}
}
pMalloc->Free (aStat[i].pwcsName);
}
}
}
}
pEnum->Release();
}
if (S_FALSE == hResult)
{
hResult = S_OK;
}
return hResult;
}

///////////////////////////////////////////////////////////////////////////////
// LoadServerObjects()
//
// Parameters
//
// Purpose
//
// Return Value
//
HRESULT WINAPI LoadServerObjects (LPSTORAGE pStorage, LPMALLOC pMalloc)
{
LoadObjectProperties (pStorage, SERVER_USER_MAILBOX, TEXT("User Mailbox"), pMalloc);
LPSTORAGE pDirectoryStg;
HRESULT hResult = pStorage->OpenStorage (DISTRIBUTION_LISTS, NULL, OPEN_FLAGS, NULL, 0, &pDirectoryStg);
RestartDL:
if (!hResult)
{
LoadObjectProperties (pDirectoryStg, SERVER_DISTRIBUTION_LIST, TEXT("Distribution List"), pMalloc);
pDirectoryStg->Release();
}
else
{
if (STG_E_FILENOTFOUND == hResult)
{
hResult = pStorage->CreateStorage (DISTRIBUTION_LISTS, CREATE_FLAGS, 0, 0, &pDirectoryStg);
goto RestartDL;
}
}
LPSTORAGE pGatewaysStg;
hResult = pStorage->OpenStorage (FOREIGN_DIRECTORIES, NULL, OPEN_FLAGS, NULL, 0, &pGatewaysStg);
RestartGateways:
if (!hResult)
{
if (!pGatewaysStg->OpenStorage (EXCHANGE_GATEWAY, NULL, OPEN_FLAGS, NULL, 0, &pDirectoryStg))
{
LoadObjectProperties (pDirectoryStg, GATEWAY_RECIPIENT, TEXT("Gateway Recipient"), pMalloc);
pDirectoryStg->Release();
}
if (!pGatewaysStg->OpenStorage (FAX_GATEWAY, NULL, OPEN_FLAGS, NULL, 0, &pDirectoryStg))
{
LoadObjectProperties (pDirectoryStg, GATEWAY_RECIPIENT, TEXT("Gateway Recipient"), pMalloc);
pDirectoryStg->Release();
}
if (!pGatewaysStg->OpenStorage (SMTP_GATEWAY, NULL, OPEN_FLAGS, NULL, 0, &pDirectoryStg))
{
LoadObjectProperties (pDirectoryStg, GATEWAY_RECIPIENT, TEXT("Gateway Recipient"), pMalloc);
pDirectoryStg->Release();
}
pGatewaysStg->Release();
}
else
{
if (STG_E_FILENOTFOUND == hResult)
{
hResult = pStorage->CreateStorage (FOREIGN_DIRECTORIES, CREATE_FLAGS, 0, 0, &pGatewaysStg);
goto RestartGateways;
}
}
return S_OK;
}
///////////////////////////////////////////////////////////////////////////////
// LoadObjectProperties()
//
// Parameters
//
// Purpose
//
// Return Value
//
HRESULT WINAPI LoadObjectProperties (LPSTORAGE pStorage,
WINDS_AB_OBJTYPE Type,
LPTSTR pszObjectType,
LPMALLOC pMalloc)
{
LPENUMSTATSTG pEnum;
STATSTG aStat[ELEMENTS_TO_FETCH];
MAILBOX_INFO MBInfo = { 0 };
DIST_LIST_INFO DLInfo = { 0 };
ULONG i, ulMBoxFound = 1;
HRESULT hResult = pStorage->EnumElements (0, NULL, 0, &pEnum);
TraceResult ("LoadObjectProperties: Failed to get ENUM interface", hResult);
if (!hResult)
{
while (!hResult && ulMBoxFound)
{
hResult = pEnum->Next (ELEMENTS_TO_FETCH, aStat, &ulMBoxFound);
if (FAILED(hResult)) // We might get S_FALSE
{
TraceResult ("LoadObjectProperties: Failed to ENUM streams", hResult);
}
else
{
if (ulMBoxFound)
{
for (i=0; i<ulMBoxFound; i++)
{
if (STGTY_STORAGE == aStat[i].type && (L'_' != aStat[i].pwcsName[0]))
{
int nChars = WideCharToMultiByte (CP_ACP,
0,
aStat[i].pwcsName,
-1,
(SERVER_DISTRIBUTION_LIST == Type ? DLInfo.szDLAlias : MBInfo.szMailboxName),
MAX_ALIAS_SIZE+1,
NULL,
NULL);
if (!nChars)
{
TraceResult ("LoadObjectProperties: Failed to convert storage name", HRESULT_FROM_WIN32(GetLastError()));
}
else
{
if (SERVER_DISTRIBUTION_LIST == Type)
{
if (S_OK == GetDLProperties (pStorage, aStat[i].pwcsName, &DLInfo))
{
GlobalObjectMap.Insert (DLInfo.dwObjID, DLInfo.szDLAlias, SERVER_DISTRIBUTION_LIST);
}
}
else
{
if (S_OK == GetMailBoxInfo (pStorage, aStat[i].pwcsName, &MBInfo))
{
GlobalObjectMap.Insert (MBInfo.dwObjID, MBInfo.szMailboxName, SERVER_USER_MAILBOX);
}
}
}
}
pMalloc->Free (aStat[i].pwcsName);
}
}
}
}
pEnum->Release();
}
if (S_FALSE == hResult)
{
hResult = S_OK;
}
return hResult;
}

///////////////////////////////////////////////////////////////////////////////
// MailboxProps()
//
// Parameters
//
// Purpose
//
// Return Value
//
HRESULT WINAPI MailboxProps (LPSTORAGE pMBDirectory, PMAILBOX_INFO pMBInfo, BOOL fRetrieve)
{
HRESULT hResult;
WCHAR wcsMailbox[64] = { 0 };
AnsiToUnicode (pMBInfo->szMailboxName, wcsMailbox, 64);
if (fRetrieve)
{
hResult = GetMailBoxInfo (pMBDirectory, wcsMailbox, pMBInfo);
}
else
{
hResult = SetMailBoxInfo (pMBDirectory, wcsMailbox, pMBInfo);
}
TraceResult ("MailboxProps", hResult);
return hResult;
}

///////////////////////////////////////////////////////////////////////////////
// GetMailBoxInfo()
//
// Parameters
//
// Purpose
//
// Return Value
//
HRESULT WINAPI GetMailBoxInfo (LPSTORAGE pStorage, LPOLESTR pwcsName, PMAILBOX_INFO pInfo)
{
LPSTREAM pStream;
LPSTORAGE pSubStorage;
HRESULT hResult = pStorage->OpenStorage (pwcsName, NULL, OPEN_FLAGS, NULL, 0, &pSubStorage);
TraceResult ("GetMailBoxInfo: Failed to open mailbox storage", hResult);
if (!hResult)
{
hResult = pSubStorage->OpenStream (USER_PROPERTIES, NULL, OPEN_FLAGS, 0, &pStream);
TraceResult ("GetMailBoxInfo: Failed to open the properties stream", hResult);
if (!hResult)
{
hResult = pStream->Read (pInfo, sizeof(MAILBOX_INFO), NULL);
TraceResult ("GetMailBoxInfo: Failed to read the MBOX stream", hResult);
pStream->Release();
}
pSubStorage->Release();
}
return hResult;
}

///////////////////////////////////////////////////////////////////////////////
// SetMailBoxInfo()
//
// Parameters
//
// Purpose
//
// Return Value
//
HRESULT WINAPI SetMailBoxInfo (LPSTORAGE pStorage, LPOLESTR pwcsName, PMAILBOX_INFO pInfo)
{
LPSTREAM pStream;
LPSTORAGE pSubStorage;
HRESULT hResult = pStorage->OpenStorage (pwcsName, NULL, OPEN_FLAGS, NULL, 0, &pSubStorage);
TraceResult ("SetMailBoxInfo: Failed to open mailbox storage", hResult);
if (!hResult)
{
hResult = pSubStorage->OpenStream (USER_PROPERTIES, NULL, OPEN_FLAGS, 0, &pStream);
TraceResult ("SetMailBoxInfo: Failed to open the properties stream", hResult);
if (!hResult)
{
hResult = pStream->Write (pInfo, sizeof(MAILBOX_INFO), NULL);
TraceResult ("SetMailBoxInfo: Failed to write to the MBOX stream", hResult);
pStream->Release();
}
pSubStorage->Release();
}
return hResult;
}

///////////////////////////////////////////////////////////////////////////////
// EmptyMailBoxMsgs()
//
// Parameters
//
// Purpose
//
// Return Value
//
HRESULT WINAPI EmptyMailBoxMsgs (LPSTORAGE pStorage, LPTSTR pszMailbox)
{
LPSTORAGE pMBStg, pSubStg;
WCHAR wcsMailbox[64] = { 0 };
AnsiToUnicode (pszMailbox, wcsMailbox, 64);
HRESULT hResult = pStorage->OpenStorage (wcsMailbox, NULL, OPEN_FLAGS, NULL, 0, &pMBStg);
if (!hResult)
{
hResult = pMBStg->DestroyElement (HEADERS_STORAGE);
if (!hResult)
{
hResult = pMBStg->CreateStorage (HEADERS_STORAGE, CREATE_FLAGS, 0, 0, &pSubStg);
if (!hResult)
{
pSubStg->Release();
hResult = pMBStg->DestroyElement (MSGS_STORAGE);
if (!hResult)
{
hResult = pMBStg->CreateStorage (MSGS_STORAGE, CREATE_FLAGS, 0, 0, &pSubStg);
if (!hResult)
{
pSubStg->Release();
}
}
}
}
pMBStg->Release();
}
TraceResult ("EmptyMailBoxMsgs", hResult);
return hResult;
}

///////////////////////////////////////////////////////////////////////////////
// GetNextObjID()
//
// Parameters
//
// Purpose
//
// Return Value
//
HRESULT WINAPI GetNextObjID (LPSTORAGE pStorage, DWORD & dwNextID)
{
LPSTREAM pStream;
LARGE_INTEGER liZero = { 0 };
HRESULT hResult = pStorage->OpenStream (OBJ_ID_POOL_STREAM, NULL, OPEN_FLAGS, 0, &pStream);
if (!hResult)
{
// From the opened stream, read the next available ID
hResult = pStream->Read (&dwNextID, sizeof(DWORD), NULL);
if (!hResult)
{
// Set the stream seek pointer back to the beginning and write the ID
hResult = pStream->Seek (liZero, STREAM_SEEK_SET, NULL);
if (!hResult)
{
dwNextID++;
hResult = pStream->Write (&dwNextID, sizeof(DWORD), NULL);
}
}
pStream->Release();
}
// If any, trace out the error code.
TraceResult ("GetNextObjID", hResult);
return hResult;
}

///////////////////////////////////////////////////////////////////////////////
// CreateMailbox()
//
// Parameters
//
// Purpose
//
// Return Value
//
HRESULT WINAPI CreateMailbox (LPSTORAGE pMBDirectory, PMAILBOX_INFO pMBInfo)
{
LPSTORAGE pMBStg, pSubStg;
LPSTREAM pStream;
DWORD dwZero = 0;
HRESULT hResult = GetNextObjID (pMBDirectory, pMBInfo->dwObjID);
if (hResult)
{
return hResult;
}
WCHAR wcsMailbox[64] = { 0 };
AnsiToUnicode (pMBInfo->szMailboxName, wcsMailbox, 64);
hResult = pMBDirectory->CreateStorage (wcsMailbox, CREATE_FLAGS, 0, 0, &pMBStg);
if (!hResult)
{
hResult = pMBStg->CreateStream (USER_PROPERTIES, CREATE_FLAGS, 0, 0, &pStream);
if (!hResult)
{
hResult = pStream->Write (pMBInfo, sizeof(MAILBOX_INFO), NULL);
if (!hResult)
{
hResult = pMBStg->CreateStorage (HEADERS_STORAGE, CREATE_FLAGS, 0, 0, &pSubStg);
if (!hResult)
{
pSubStg->Release();
hResult = pMBStg->CreateStream (OBJ_ID_POOL_STREAM, CREATE_FLAGS, 0, 0, &pStream);
if (!hResult)
{
hResult = pStream->Write (&dwZero, sizeof(DWORD), NULL);
pStream->Release();
if (!hResult)
{
hResult = pMBStg->CreateStorage (MSGS_STORAGE, CREATE_FLAGS, 0, 0, &pSubStg);
if (!hResult)
{
pSubStg->Release();
}
}
}
}
}
}
pMBStg->Release();
if (hResult)
{
hResult = pMBDirectory->DestroyElement (wcsMailbox);
}
}
TraceResult ("CreateMailbox", hResult);
return hResult;
}

///////////////////////////////////////////////////////////////////////////////
// DeleteMailbox()
//
// Parameters
//
// Purpose
//
// Return Value
//
HRESULT WINAPI DeleteMailbox (LPSTORAGE pStorage, PMAILBOX_INFO pMBInfo)
{
WCHAR wcsMailbox[64] = { 0 };
AnsiToUnicode (pMBInfo->szMailboxName, wcsMailbox, 64);
GetMailBoxInfo (pStorage, wcsMailbox, pMBInfo);
HRESULT hResult = pStorage->DestroyElement (wcsMailbox);
TraceResult ("DeleteMailbox: Failed to delete storage of mailbox", hResult);
return hResult;
}

///////////////////////////////////////////////////////////////////////////////
// CopyMsgFromFile()
//
// Parameters
//
// Purpose
//
// Return Value
//
HRESULT WINAPI CopyMsgFromFile (LPSTORAGE pStorage,
HANDLE hFile,
LPTSTR szMailbox,
LPTSTR szHeader)
{
LPSTORAGE pMBStg, pMsgStg;
LPSTREAM pStream;
WCHAR wcsMailbox[64] = { 0 }, wcsStreamName[NAME_FORMAT_SIZE];
AnsiToUnicode (szMailbox, wcsMailbox, 64);

BYTE abBuffer[IO_BUFFERSIZE];
DWORD dwBytesRead, dwLastError = 0, dwStreamID;
HRESULT hResult = pStorage->OpenStorage (wcsMailbox, NULL, OPEN_FLAGS, NULL, 0, &pMBStg);
if (!hResult)
{
hResult = pMBStg->OpenStorage (MSGS_STORAGE, NULL, OPEN_FLAGS, NULL, 0, &pMsgStg);
if (!hResult)
{
hResult = GetNextObjID (pMBStg, dwStreamID);
if (!hResult)
{
wsprintfW (wcsStreamName, MSG_STREAM_FORMAT, dwStreamID);
hResult = pMsgStg->CreateStream (wcsStreamName, CREATE_FLAGS, 0, 0, &pStream);
if (!hResult)
{
do
{
if (!ReadFile (hFile, abBuffer, IO_BUFFERSIZE, &dwBytesRead, NULL))
{
dwLastError = HRESULT_FROM_WIN32(GetLastError());
TraceResult ("CopyMsgFromFile: Failed to read from the tmp file", dwLastError);
}
if (dwBytesRead)
{
hResult = pStream->Write (abBuffer, dwBytesRead, NULL);
TraceResult ("CopyMsgFromFile: Failed to write into mb stream", hResult);
}
} while (dwBytesRead && !hResult && !dwLastError);
if (!hResult && !dwLastError)
{
hResult = UpdateMailboxHeaders (pStorage, pMBStg, NULL, dwStreamID, szHeader, TRUE);
}
pStream->Release();
if (hResult || dwLastError)
{
pMsgStg->DestroyElement (wcsStreamName);
if (dwLastError)
{
hResult = dwLastError;
}
}
}
}
pMsgStg->Release();
}
pMBStg->Release();
}
// If there were no error storing the message in the user mailbox, send a
// notification to client transports indicating that a new message
// is pending download.
if (S_OK == hResult)
{
PWINDS_NOTIFICATION pNotif = (PWINDS_NOTIFICATION)HeapAlloc (ghHeap,
HEAP_ZERO_MEMORY,
sizeof(WINDS_NOTIFICATION));
if (pNotif)
{
pNotif->Event = XP_NEW_MAIL_ARRIVED;
lstrcpy (pNotif->Info.MB.szMailboxName, szMailbox);
NotifyClients (pNotif); // This will take care of freeing the notification structure
}
else
{
TraceMessage ("CopyMsgFromFile: Failed to allocate memory for client notification");
}
}
TraceResult ("CopyMsgFromFile", hResult);
return hResult;
}

///////////////////////////////////////////////////////////////////////////////
// RemoveMessageFromMailbox()
//
// Parameters
//
// Purpose
//
// Return Value
//
HRESULT WINAPI RemoveMessageFromMailbox (LPSTORAGE pStorage,
LPTSTR szMailbox,
DWORD dwStreamID)
{
LPSTORAGE pHeaders, pMBStg, pMsgStg;
WCHAR wcsMailbox[64] = { 0 }, wcsStreamName[NAME_FORMAT_SIZE];
AnsiToUnicode (szMailbox, wcsMailbox, 64);

HRESULT hResult = pStorage->OpenStorage (wcsMailbox, NULL, OPEN_FLAGS, NULL, 0, &pMBStg);
if (!hResult)
{
hResult = pMBStg->OpenStorage (MSGS_STORAGE, NULL, OPEN_FLAGS, NULL, 0, &pMsgStg);
if (!hResult)
{
wsprintfW (wcsStreamName, MSG_STREAM_FORMAT, dwStreamID);
hResult = pMsgStg->DestroyElement (wcsStreamName);
if (!hResult)
{
hResult = pMBStg->OpenStorage (HEADERS_STORAGE, NULL, OPEN_FLAGS, NULL, 0, &pHeaders);
if (!hResult)
{
wsprintfW (wcsStreamName, HEADER_STREAM_FORMAT, dwStreamID);
pHeaders->DestroyElement (wcsStreamName); // Drop the error code here
pHeaders->Release();
}
}
pMsgStg->Release();
}
pMBStg->Release();
}
TraceResult ("RemoveMessageFromMailbox", hResult);
return hResult;
}

///////////////////////////////////////////////////////////////////////////////
// UpdateMailboxHeaders()
//
// Parameters
//
// Purpose
//
// Return Value
//
long WINAPI UpdateMailboxHeaders (LPSTORAGE pStorage,
LPSTORAGE pMBStg,
LPTSTR szMailbox,
DWORD dwStreamID,
LPTSTR pszHeader,
BOOL fAddMsgToHeadersList)
{
WCHAR wcsMailbox[64] = { 0 }, wcsStreamName[NAME_FORMAT_SIZE];

LPSTORAGE pHeadersStg;
LPSTREAM pHeader;
HRESULT hResult = S_OK;
BOOL fReleaseLocalStorage = FALSE;
if (!pMBStg)
{
fReleaseLocalStorage = TRUE;
AnsiToUnicode (szMailbox, wcsMailbox, 64);
hResult = pStorage->OpenStorage (wcsMailbox, NULL, OPEN_FLAGS, NULL, 0, &pMBStg);
TraceResult ("UpdateMailboxHeaders: Failed to open mailbox", hResult);
}
if (!hResult)
{
hResult = pMBStg->OpenStorage (HEADERS_STORAGE, NULL, OPEN_FLAGS, NULL, 0, &pHeadersStg);
TraceResult ("UpdateMailboxHeaders: Failed to open header storage", hResult);
if (!hResult)
{
wsprintfW (wcsStreamName, HEADER_STREAM_FORMAT, dwStreamID);
if (fAddMsgToHeadersList)
{
hResult = pHeadersStg->CreateStream (wcsStreamName, CREATE_FLAGS, 0, 0, &pHeader);
TraceResult ("UpdateMailboxHeaders: Failed to create header stream", hResult);
if (!hResult)
{
BYTE abEntryID[16];
ZeroMemory (abEntryID, 16);
wsprintfA ((LPSTR)&abEntryID[4], "%d", dwStreamID);

ULONG cbSize = 16 + lstrlen(pszHeader) * sizeof(TCHAR);
hResult = pHeader->Write (&cbSize, sizeof(ULONG), NULL);
TraceResult ("UpdateMailboxHeaders: Failed to write header size", hResult);
if (!hResult)
{
hResult = pHeader->Write (abEntryID, 16, NULL);
TraceResult ("UpdateMailboxHeaders: Failed to write message EID", hResult);
if (!hResult)
{
hResult = pHeader->Write (pszHeader, cbSize - 16, NULL);
TraceResult ("UpdateMailboxHeaders: Failed to write header to stream", hResult);
}
}
pHeader->Release();
if (hResult)
{
TraceIO2 ("UpdateMailboxHeaders", pHeadersStg->DestroyElement(wcsStreamName));
}
}
}
else
{
hResult = pMBStg->DestroyElement (wcsStreamName);
TraceResult ("UpdateMailboxHeaders: Failed to remove header stream", hResult);
}
pHeadersStg->Release();
}
if (fReleaseLocalStorage)
{
pMBStg->Release();
}
}
return hResult;
}

///////////////////////////////////////////////////////////////////////////////
// CopyHeadersToFile()
//
// Parameters
//
// Purpose
//
// Return Value
//
HRESULT WINAPI CopyHeadersToFile (LPSTORAGE pStorage,
LPMALLOC pMalloc,
HANDLE hFile,
LPTSTR szMailbox)
{
BOOL fAtLeastOneCopied = FALSE, fSubStreamFailed = FALSE;
LPSTORAGE pMBStg, pHeadersStg;
LPSTREAM pStream;
LPENUMSTATSTG pEnum;
BYTE abBuffer[IO_BUFFERSIZE];
STATSTG aStat[ELEMENTS_TO_FETCH];
ULONG ulStreamsFound, ulBytesRead;
DWORD dwBytesWrite;

WCHAR wcsMailbox[64] = { 0 };
AnsiToUnicode (szMailbox, wcsMailbox, 64);

HRESULT hResult = pStorage->OpenStorage (wcsMailbox, NULL, OPEN_FLAGS, NULL, 0, &pMBStg);
TraceResult ("CopyHeadersToFile: Failed to mailbox storage", hResult);

if (!hResult) 
{
hResult = pMBStg->OpenStorage (HEADERS_STORAGE, NULL, OPEN_FLAGS, NULL, 0, &pHeadersStg);
TraceResult ("CopyHeadersToFile: Failed to open headers storage", hResult);
if (!hResult)
{
hResult = pHeadersStg->EnumElements (0, NULL, 0, &pEnum);
TraceResult ("CopyHeadersToFile: Failed to get ENUM interface", hResult);
if (!hResult)
{
hResult = 0;
ulStreamsFound = 1;
while (!hResult && ulStreamsFound)
{
hResult = pEnum->Next (ELEMENTS_TO_FETCH, aStat, &ulStreamsFound);
if (ulStreamsFound)
{
for (ULONG i=0; i<ulStreamsFound; i++)
{
hResult = pHeadersStg->OpenStream (aStat[i].pwcsName, NULL, OPEN_FLAGS, 0, &pStream);
TraceResult ("CopyHeadersToFile: Failed to open header stream", hResult);
if (!hResult)
{
ASSERT (IO_BUFFERSIZE >= aStat[i].cbSize.LowPart);
hResult = pStream->Read (abBuffer, aStat[i].cbSize.LowPart, &ulBytesRead);
if (!hResult)
{
if (!WriteFile (hFile, abBuffer, ulBytesRead, &dwBytesWrite, NULL))
{
fSubStreamFailed = TRUE;
TraceResult ("CopyHeadersToFile: Failed to write header to tmp file", HRESULT_FROM_WIN32(GetLastError()));
}
else
{
fAtLeastOneCopied = TRUE;
}
}
pStream->Release();
}
pMalloc->Free (aStat[i].pwcsName);
}
}
else
{
if (FAILED(hResult)) // We might get S_FALSE
{
TraceResult ("CopyHeadersToFile: Failed to ENUM streams", hResult);
}
}
}
if (S_FALSE == hResult)
{
hResult = S_OK;
}
pEnum->Release();
}
pHeadersStg->Release();
}
pMBStg->Release();
}
if (hResult)
{
if (fSubStreamFailed)
{
if (fAtLeastOneCopied)
{
hResult = MAKE_HRESULT(0, FACILITY_WIN32, ERROR_PARTIAL_COPY);
}
}
}
SetFilePointer (hFile, 0, NULL, FILE_BEGIN);
return hResult;
}

///////////////////////////////////////////////////////////////////////////////
// CopyStreamToFile()
//
// Parameters
//
// Purpose
//
// Return Value
//
HRESULT WINAPI CopyStreamToFile (LPSTREAM pStream,
HANDLE hFile,
ULONG * pulWritten)
{
BYTE aBuffer[IO_BUFFERSIZE];
ULONG ulRead, ulRemain, ulWritten;
STATSTG StatInfo;
*pulWritten = 0;
HRESULT hResult = pStream->Stat (&StatInfo, STATFLAG_NONAME);
if (!hResult)
{
ulRemain = StatInfo.cbSize.LowPart;
for (; ulRemain>0; ulRemain -= ulWritten)
{
hResult = pStream->Read (aBuffer, min(ulRemain, IO_BUFFERSIZE), &ulRead);
if (hResult)
{
break; // Out of the FOR() loop
}
else
{
if (!WriteFile (hFile, aBuffer, ulRead, &ulWritten, NULL))
{
hResult = HRESULT_FROM_WIN32(GetLastError());
break; // Out of the FOR() loop
}
}
*pulWritten += ulWritten;
}
}
TraceResult ("CopyStreamToFile", hResult);
return hResult;
}

///////////////////////////////////////////////////////////////////////////////
// CopyMsgToFile()
//
// Parameters
//
// Purpose
//
// Return Value
//
HRESULT WINAPI CopyMsgToFile (LPSTORAGE pStorage,
LPTSTR szMailbox,
HANDLE hFile,
ULONG * pulMsgLen,
DWORD dwStreamID,
BOOL fDeleteAfterCopy)
{
LPSTORAGE pMBStg, pMsgStg, pHeaders;
LPSTREAM pStream;
WCHAR wcsMailbox[64] = { 0 }, wcsStreamName[NAME_FORMAT_SIZE];
wsprintfW (wcsStreamName, MSG_STREAM_FORMAT, dwStreamID);

AnsiToUnicode (szMailbox, wcsMailbox, 64);
HRESULT hResult = pStorage->OpenStorage (wcsMailbox, NULL, OPEN_FLAGS, NULL, 0, &pMBStg);
if (!hResult)
{
hResult = pMBStg->OpenStorage (MSGS_STORAGE, NULL, OPEN_FLAGS, NULL, 0, &pMsgStg);
if(!hResult)
{
hResult = pMsgStg->OpenStream (wcsStreamName, NULL, OPEN_FLAGS, 0, &pStream);
if (!hResult)
{
hResult = CopyStreamToFile (pStream, hFile, pulMsgLen);
pStream->Release();
if (!hResult && fDeleteAfterCopy)
{
hResult = pMsgStg->DestroyElement (wcsStreamName);
if (!hResult)
{
hResult = pMBStg->OpenStorage (HEADERS_STORAGE, NULL, OPEN_FLAGS, NULL, 0, &pHeaders);
if (!hResult)
{
wsprintfW (wcsStreamName, HEADER_STREAM_FORMAT, dwStreamID);
hResult = pHeaders->DestroyElement (wcsStreamName);
pHeaders->Release();
}
}
hResult = S_OK; // We don't want to propagate errors at this level, since the message is already copied.
}
}
pMsgStg->Release();
}
pMBStg->Release();
}
TraceResult ("CopyMsgToFile", hResult);
return hResult;
}

///////////////////////////////////////////////////////////////////////////////
// CreateDistributionList()
//
// Parameters
//
// Purpose
//
// Return Value
//
HRESULT WINAPI CreateDistributionList (LPSTORAGE pStorage, PDIST_LIST_INFO pDLInfo)
{
HRESULT hResult = GetNextObjID (pStorage, pDLInfo->dwObjID);
if (hResult)
{
return hResult;
}
LPSTORAGE pDLDirectoryStg, pDLStg;
LPSTREAM pStream;
WCHAR wcsDLalias[64] = { 0 };
AnsiToUnicode (pDLInfo->szDLAlias, wcsDLalias, 64);

hResult = pStorage->OpenStorage (DISTRIBUTION_LISTS, NULL, OPEN_FLAGS, NULL, 0, &pDLDirectoryStg);
Restart:
if (!hResult)
{
hResult = pDLDirectoryStg->CreateStorage (wcsDLalias, CREATE_FLAGS, 0, 0, &pDLStg);
if (!hResult)
{
hResult = pDLStg->CreateStream (DL_PROPS, CREATE_FLAGS, 0, 0, &pStream);
if (!hResult)
{
pStream->Release();
hResult = pDLStg->CreateStream (DL_MEMBERS, CREATE_FLAGS, 0, 0, &pStream);
if (!hResult)
{
pStream->Release();
}
}
pDLStg->Release();
hResult = SetDLProperties (pDLDirectoryStg, wcsDLalias, pDLInfo);
}
if (hResult)
{
pDLDirectoryStg->DestroyElement (wcsDLalias);
}
pDLDirectoryStg->Release();
}
else
{
if (STG_E_FILENOTFOUND == hResult)
{
hResult = pStorage->CreateStorage (DISTRIBUTION_LISTS, CREATE_FLAGS, 0, 0, &pDLDirectoryStg);
goto Restart;
}
}
TraceResult ("CreateDistributionList", hResult);
return hResult;
}

///////////////////////////////////////////////////////////////////////////////
// DLPropsAndMembers()
//
// Parameters
//
// Purpose
//
// Return Value
//
HRESULT WINAPI DLPropsAndMembers (LPSTORAGE pStorage, PDIST_LIST_INFO pDLInfo, BOOL fGetProps)
{
LPSTORAGE pDLDirectoryStg;
WCHAR wcsDLalias[64] = { 0 };
AnsiToUnicode (pDLInfo->szDLAlias, wcsDLalias, 64);
HRESULT hResult = pStorage->OpenStorage (DISTRIBUTION_LISTS, NULL, OPEN_FLAGS, NULL, 0, &pDLDirectoryStg);
if (!hResult)
{
if (fGetProps)
{
hResult = GetDLProperties (pDLDirectoryStg, wcsDLalias, pDLInfo, TRUE);
}
else
{
hResult = SetDLProperties (pDLDirectoryStg, wcsDLalias, pDLInfo);
}
pDLDirectoryStg->Release();
}
TraceResult ("DLPropsAndMembers", hResult);
return hResult;
}

///////////////////////////////////////////////////////////////////////////////
// GetDLProperties()
//
// Parameters
//
// Purpose
//
// Return Value
//
HRESULT WINAPI GetDLProperties (LPSTORAGE pStorage,
LPOLESTR pwcsDLName,
PDIST_LIST_INFO pDLInfo,
BOOL fGetMembers)
{
LPSTREAM pStream;
LPSTORAGE pDLStg;
DWORD i;
DLM_INFO_A Info = { 0 };
DLM_LIST_A * pList = (DLM_LIST_A *)pDLInfo->pMembers;

HRESULT hResult = pStorage->OpenStorage (pwcsDLName, NULL, OPEN_FLAGS, NULL, 0, &pDLStg);
if (!hResult)
{
hResult = pDLStg->OpenStream (DL_PROPS, NULL, OPEN_FLAGS, 0, &pStream);
if (!hResult)
{
hResult = pStream->Read (pDLInfo,
sizeof(DIST_LIST_INFO) - 4, // Don't read the pMember pointer value
NULL);
pStream->Release();
}
if (!hResult && fGetMembers && pDLInfo->dwMemberCount && pList)
{
hResult = pDLStg->OpenStream (DL_MEMBERS, NULL, OPEN_FLAGS, 0, &pStream);
if (!hResult)
{
for (i=0; i<pDLInfo->dwMemberCount && !hResult; i++)
{
hResult = pStream->Read (&Info, sizeof(DLM_INFO_A), NULL);
if (!hResult)
{
if (i == 0)
{
pList->Info = Info;
}
else
{
InsertNewDLMNodeA (Info, pList);
}
}
}
pStream->Release();
}
}
pDLStg->Release();
}
TraceResult ("GetDLProperties", hResult);
return hResult;
}

///////////////////////////////////////////////////////////////////////////////
// SetDLProperties()
//
// Parameters
//
// Purpose
//
// Return Value
//
HRESULT WINAPI SetDLProperties (LPSTORAGE pStorage,
LPOLESTR pwcsDLName,
PDIST_LIST_INFO pDLInfo)
{
LPSTREAM pStream;
LPSTORAGE pDLStg;
ULARGE_INTEGER uliTotalSize = { 0 };
ULONG ulBytesWritten;
DLM_LIST_A * pNode;
HRESULT hResult = pStorage->OpenStorage (pwcsDLName, NULL, OPEN_FLAGS, NULL, 0, &pDLStg);
if (!hResult)
{
pDLInfo->dwMemberCount = 0;
hResult = pDLStg->OpenStream (DL_MEMBERS, NULL, OPEN_FLAGS, 0, &pStream);
if (!hResult)
{
pNode = (DLM_LIST_A *)pDLInfo->pMembers;
while (pNode && !hResult)
{
hResult = pStream->Write (&(pNode->Info),
sizeof(DLM_INFO_A),
&ulBytesWritten);
uliTotalSize.LowPart += ulBytesWritten;
pDLInfo->dwMemberCount++;
pNode = pNode->pNext;
}
pStream->SetSize (uliTotalSize);
pStream->Release();
}
if (!hResult)
{
hResult = pDLStg->OpenStream (DL_PROPS, NULL, OPEN_FLAGS, 0, &pStream);
if (!hResult)
{
hResult = pStream->Write (pDLInfo,
sizeof(DIST_LIST_INFO) - 4, // Don't write the last 4 byte (pMembers)
NULL);
pStream->Release();
}
}
pDLStg->Release();
}
TraceResult ("SetDLProperties", hResult);
return hResult;
}

///////////////////////////////////////////////////////////////////////////////
// DeleteDistributionList()
//
// Parameters
//
// Purpose
//
// Return Value
//
HRESULT WINAPI DeleteDistributionList (LPSTORAGE pStorage, PDIST_LIST_INFO pDLInfo)
{
LPSTORAGE pDLDirectoryStg;
WCHAR wcsDLalias[64] = { 0 };
AnsiToUnicode (pDLInfo->szDLAlias, wcsDLalias, 64);
HRESULT hResult = pStorage->OpenStorage (DISTRIBUTION_LISTS, NULL, OPEN_FLAGS, NULL, 0, &pDLDirectoryStg);
if (!hResult)
{
GetDLProperties (pDLDirectoryStg, wcsDLalias, pDLInfo, FALSE);
hResult = pDLDirectoryStg->DestroyElement (wcsDLalias);
pDLDirectoryStg->Release();
}
TraceResult ("DeleteDistributionList", hResult);
return hResult;
}

///////////////////////////////////////////////////////////////////////////////
// GetDLRecipientsInfo()
//
// Parameters
//
// Purpose
//
// Return Value
//
HRESULT WINAPI GetDLRecipientsInfo (LPSTORAGE pMBDirectory,
LPSTORAGE pDLDirectory,
HANDLE hPipe,
LPOLESTR pwcsDLName)
{
DLM_LIST_A Members = { 0 };
DIST_LIST_INFO DLInfo = { 0 };
DLInfo.pMembers = (LPVOID)&Members;
AB_ENTRY_INFO abEntry = { 0 };
OLECHAR wcsMemberAlias[MAX_ALIAS_SIZE+1];
int nChars;
DWORD dwBytesWritten;
DLM_LIST_A * pNode;

HRESULT hEntry, hResult = GetDLProperties (pDLDirectory, pwcsDLName, &DLInfo, TRUE);
if (!hResult && (0 != Members.Info.dwMemberID))
{
pNode = (DLM_LIST_A *)DLInfo.pMembers;
while (pNode)
{
nChars = MultiByteToWideChar (CP_ACP, MB_PRECOMPOSED, (LPSTR)pNode->Info.szMemberAlias, -1, wcsMemberAlias, MAX_ALIAS_SIZE+1);
if (!nChars)
{
TraceResult ("GetDLRecipientsInfo: Failed to convert alias name", HRESULT_FROM_WIN32(GetLastError()));
}
else
{
abEntry.Type = (WINDS_AB_OBJTYPE)pNode->Info.dwMemberType;
if (SERVER_DISTRIBUTION_LIST == abEntry.Type)
{
hEntry = GetDLProperties (pDLDirectory, wcsMemberAlias, &abEntry.Info.DL, FALSE);
}
else
{
if (SERVER_USER_MAILBOX == abEntry.Type)
{
hEntry = GetMailBoxInfo (pMBDirectory, wcsMemberAlias, &abEntry.Info.MB);
}
else
{
ASSERT (GATEWAY_RECIPIENT == abEntry.Type);
ASSERT (FALSE); // not implemented yet
hEntry = E_FAIL;
}
}
if (!hEntry)
{
if (!WriteFile (hPipe, &abEntry, sizeof(AB_ENTRY_INFO), &dwBytesWritten, NULL))
{
TraceResult ("GetDLRecipientsInfo: Failed to write to client pipe", HRESULT_FROM_WIN32(GetLastError()));
}
}
}
pNode = pNode->pNext;
}
FreeDLMList (&Members);
}
TraceResult ("GetDLRecipientsInfo", hResult);
return hResult;
}

///////////////////////////////////////////////////////////////////////////////
// GetGWContainerCount()
//
// Parameters
//
// Purpose
//
// Return Value
//
HRESULT WINAPI GetGWContainerCount (LPSTORAGE pStorage,
LPMALLOC pMalloc,
DWORD dwContainerID,
DWORD * pdwContainerCount)
{
LPENUMSTATSTG pEnum;
STATSTG aStat[ELEMENTS_TO_FETCH];
ULONG ulMBoxFound = 1;
LPSTORAGE pDirectory, pGWContainer;
HRESULT hResult = pStorage->OpenStorage (FOREIGN_DIRECTORIES, NULL, OPEN_FLAGS, NULL, 0, &pDirectory);
if (!hResult)
{
switch (dwContainerID)
{
case FAX_CONTAINER_ID :
hResult = pStorage->OpenStorage (FAX_GATEWAY, NULL, OPEN_FLAGS, NULL, 0, &pGWContainer);
break;
case SMTP_CONTAINER_ID :
hResult = pStorage->OpenStorage (SMTP_GATEWAY, NULL, OPEN_FLAGS, NULL, 0, &pGWContainer);
break;
case EXCHANGE_CONTAINER_ID :
hResult = pStorage->OpenStorage (EXCHANGE_GATEWAY, NULL, OPEN_FLAGS, NULL, 0, &pGWContainer);
break;
}
if (!hResult)
{
hResult = pGWContainer->EnumElements (0, NULL, 0, &pEnum);
if (!hResult)
{
while (!hResult && ulMBoxFound)
{
hResult = pEnum->Next (ELEMENTS_TO_FETCH, aStat, &ulMBoxFound);
if (SUCCEEDED(hResult))
{
if (ulMBoxFound)
{
for (ULONG i=0; i<ulMBoxFound; i++)
{
if (STGTY_STORAGE == aStat[i].type && (L'_' != aStat[i].pwcsName[0]))
{
(*pdwContainerCount)++;
}
pMalloc->Free (aStat[i].pwcsName);
}
}
}
}
pEnum->Release();
}
hResult = S_OK;
pGWContainer->Release();
}
pDirectory->Release();
}
TraceResult ("GetGWContainerCount", hResult);
return hResult;
}

///////////////////////////////////////////////////////////////////////////////
// CheckForPendingMailboxMsgs()
//
// Parameters
//
// Purpose
//
// Return Value
//
HRESULT WINAPI CheckForPendingMailboxMsgs (LPSTORAGE pStorage,
LPMALLOC pMalloc,
LPTSTR szMailbox,
DWORD * pdwMsgCount)
{
WCHAR wcsMailbox[64] = { 0 };
AnsiToUnicode (szMailbox, wcsMailbox, 64);

ULONG ulMsgsFound, dwTotal = 0;
LPENUMSTATSTG pEnum;
STATSTG aStat[ELEMENTS_TO_FETCH];
LPSTORAGE pMailbox, pMessages;
HRESULT hResult = pStorage->OpenStorage (wcsMailbox, NULL, OPEN_FLAGS, NULL, 0, &pMailbox);
if (!hResult)
{
hResult = pMailbox->OpenStorage (MSGS_STORAGE, NULL, OPEN_FLAGS, NULL, 0, &pMessages);
if (!hResult)
{
hResult = pMessages->EnumElements (0, NULL, 0, &pEnum);
if (!hResult)
{
while (!hResult)
{
hResult = pEnum->Next (ELEMENTS_TO_FETCH, aStat, &ulMsgsFound);
if (FAILED(hResult)) // We might get S_FALSE
{
TraceResult ("CheckForPendingMailboxMsgs: Failed to ENUM streams", hResult);
}
else
{
if (ulMsgsFound)
{
dwTotal += ulMsgsFound;
}
pMalloc->Free (aStat[0].pwcsName);
}
}
pEnum->Release();
if (S_FALSE == hResult)
{
hResult = S_OK;
*pdwMsgCount = dwTotal;
}
}
pMessages->Release();
}
pMailbox->Release();
}
TraceResult ("CheckForPendingMailboxMsgs", hResult);
return hResult;
}

///////////////////////////////////////////////////////////////////////////////
// GetNextMailboxMsg()
//
// Parameters
//
// Purpose
//
// Return Value
//
HRESULT WINAPI GetNextMailboxMsg (LPSTORAGE pStorage,
LPMALLOC pMalloc,
LPTSTR szMailbox,
DWORD * pdwMsgID,
HANDLE hFile)
{
WCHAR wcsMailbox[64] = { 0 };
AnsiToUnicode (szMailbox, wcsMailbox, 64);

BYTE abBuffer[IO_BUFFERSIZE];
int nChars;
char szObjName[64];
LPSTR pSubStr;
DWORD dwBytesWritten;
ULONG ulMsgsFound = 0, ulBytesRead;
LPENUMSTATSTG pEnum;
STATSTG aStat[1];
LPSTORAGE pMailbox, pMessages;
LPSTREAM pOneMsg;
HRESULT hResult = pStorage->OpenStorage (wcsMailbox, NULL, OPEN_FLAGS, NULL, 0, &pMailbox);
if (!hResult)
{
hResult = pMailbox->OpenStorage (MSGS_STORAGE, NULL, OPEN_FLAGS, NULL, 0, &pMessages);
if (!hResult)
{
hResult = pMessages->EnumElements (0, NULL, 0, &pEnum);
if (!hResult)
{
hResult = pEnum->Next (1, aStat, &ulMsgsFound);
if (FAILED(hResult)) // We might get S_FALSE
{
TraceResult ("GetNextMailboxMsg: Failed to ENUM streams", hResult);
}
else
{
if (ulMsgsFound)
{
ASSERT (STGTY_STREAM == aStat[0].type)
nChars = WideCharToMultiByte (CP_ACP,
0,
aStat[0].pwcsName,
-1,
szObjName,
64,
NULL,
NULL);
if (!nChars)
{
TraceResult ("GetNextMailboxMsg: Failed to convert storage name", HRESULT_FROM_WIN32(GetLastError()));
}
hResult = pMessages->OpenStream (aStat[0].pwcsName,
NULL,
OPEN_FLAGS,
0,
&pOneMsg);
if (!hResult)
{
do
{
hResult = pOneMsg->Read (abBuffer, IO_BUFFERSIZE, &ulBytesRead);
if (!hResult && ulBytesRead)
{
if (!WriteFile (hFile, abBuffer, ulBytesRead, &dwBytesWritten, NULL))
{
hResult = HRESULT_FROM_WIN32(GetLastError());
}
}
} while (!hResult && ulBytesRead);
pOneMsg->Release();
}
if (!hResult && nChars)
{
pSubStr = &(szObjName[lstrlenA (szObjName)]);
while (' ' != *pSubStr)
{
pSubStr--;
}
pSubStr++;
sscanf (pSubStr, "%X", pdwMsgID);
}
pMalloc->Free (aStat[0].pwcsName);
}
}
pEnum->Release();
}
pMessages->Release();
}
pMailbox->Release();
}
#ifdef _DEBUG
if (hResult && S_FALSE != hResult)
{
TraceResult ("GetNextMailboxMsg", hResult);
}
#endif // _DEBUG

return hResult;
}

///////////////////////////////////////////////////////////////////////////////
// CreateGatewayQueues()
//
// Parameters
//
// Purpose
//
// Return Value
//
HRESULT WINAPI CreateGatewayQueues (LPSTORAGE pStorage)
{
LPSTORAGE pQueueStg;
if (!pStorage->CreateStorage (GW_OUTBOX, CREATE_FLAGS, 0, 0, &pQueueStg))
{
pQueueStg->Release();
}
if (!pStorage->CreateStorage (GW_INBOX, CREATE_FLAGS, 0, 0, &pQueueStg))
{
pQueueStg->Release();
}
return S_OK;
}

///////////////////////////////////////////////////////////////////////////////
// CreateGatewayDirectories()
//
// Parameters
//
// Purpose
//
// Return Value
//
HRESULT WINAPI CreateGatewayDirectories (LPSTORAGE pStorage)
{
LPSTORAGE pDirsStg, pGatewaysStg;
HRESULT hResult = pStorage->CreateStorage (FOREIGN_DIRECTORIES, CREATE_FLAGS, 0, 0, &pDirsStg);
if (!hResult)
{
if (!pDirsStg->CreateStorage (EXCHANGE_GATEWAY, CREATE_FLAGS, 0, 0, &pGatewaysStg))
{
CreateGatewayQueues (pGatewaysStg);
pGatewaysStg->Release();
}
if (!pDirsStg->CreateStorage (FAX_GATEWAY, CREATE_FLAGS, 0, 0, &pGatewaysStg))
{
CreateGatewayQueues (pGatewaysStg);
pGatewaysStg->Release();
}
if (!pDirsStg->CreateStorage (SMTP_GATEWAY, CREATE_FLAGS, 0, 0, &pGatewaysStg))
{
CreateGatewayQueues (pGatewaysStg);
pGatewaysStg->Release();
}
pDirsStg->Release();
}
return hResult;
}

// End of file for STORAGE.CPP