GWSAMPLE.C

// --gwsample.c----------------------------------------------------------------- 
//
// Sample gateway application.
//
// Copyright (C) Microsoft Corp. 1986-1996. All Rights Reserved.
// -----------------------------------------------------------------------------

#include "edk.h"
#include "gwmain.h"
#include "gwsample.h"
#include "attrname.h"
#include "convcwrp.h"
#include "ipmconv.h"
#include "sgwdata.h"

TCHAR szAppName[] = TEXT("GWSAMPLE");
TCHAR szWindowTitle[] = TEXT("Sample Gateway");

// Output/Input file name prefix.
TCHAR szFilePrefix[] = TEXT("SGW");

#define C_EQU TEXT("C=")
#define A_EQU TEXT("A=")
#define P_EQU TEXT("P=")

static TCHAR szServiceName[MAX_SERVICE_NAME_LENGTH+1] = {0};

static LPTSTR lpszLocalGDI = NULL;
static CRITICAL_SECTION csGatewaySeqNo = {0};
static ULONG ulGatewaySeqNo = 0;

static LPMAPISESSION lpSession = NULL;
static LPMDB lpStore = NULL;
static LPMAPIFOLDER lpRootFolder = NULL;
static LPMAPIFOLDER lpMtsInFolder = NULL;
static LPMAPIFOLDER lpMtsOutFolder = NULL;
static ULONG cbGalEid = 0;
static LPENTRYID lpGalEid = NULL;

//performance code

LONG cInThreads = 0;
ULONG cInMessages = 0;

LPTSTR lpszAddressType = NULL;

LPTSTR lpszSysAdminName = NULL;
LPTSTR lpszSysAdminAddr = NULL;

LPTSTR lpszInDirectory = NULL;
LPTSTR lpszInConverter = NULL;
LPWSTR lpszInConverterW = NULL;

BOOL fInEnabled = FALSE;

ULONG cbBufferSize = 0;
LPBYTE lpbBuffer = NULL;
ULONG cBufferArraySize = 0;
LPTSTR *lppszBufferArray = NULL;

DWORD dwInSleepInterval = 0;
DWORD dwInPollInterval = 0;

LONG cOutThreads = 0;
ULONG cOutMessages = 0;

LPTSTR lpszOutDirectory = NULL;
LPTSTR lpszOutConverter = NULL;
LPWSTR lpszOutConverterW = NULL;

BOOL fOutEnabled = FALSE;

DWORD dwOutSleepInterval = 0;
DWORD dwOutPollInterval = 0;

LPTSTR lpszArchiveDirectory = NULL;

HANDLE hEventLog = NULL;

typedef struct _id_item
{
CRITICAL_SECTION *lpcs; // only used by list
LPTSTR lpszId;
struct _id_item *next;
} IDITEM, *LPIDITEM;

static CRITICAL_SECTION csInboundIdList = {0};
static CRITICAL_SECTION csOutboundIdList = {0};

static IDITEM InboundIdList = {0};
static IDITEM OutboundIdList = {0};

// Size is because country 2-3, ADMD 0-16, PRMD is 1-16 and LocalId1-32 plus
// size for "/c=/p=/a=/l=". So 3+16+16+32+12+1 = 80.
#define cbMTSIDMax (80)

//$--HrCreateIdItem-------------------------------------------------------------
// Creates an ID item.
// -----------------------------------------------------------------------------
HRESULT HrCreateIdItem( // RETURNS: return code
IN LPSTR lpszId, // identifier
OUT LPIDITEM *lppIdItem) // identifier item
{
HRESULT hr = NOERROR;
LPIDITEM lpIdItem = NULL;
ULONG cBytes = 0;

*lppIdItem = NULL;

cBytes = sizeof(IDITEM);

hr = MAPIAllocateBuffer(cBytes, (void **)&lpIdItem);

if(FAILED(hr))
{
hr = HR_LOG(E_OUTOFMEMORY);
goto cleanup;
}

ZeroMemory(lpIdItem, cBytes);

cBytes = cbStrLen(lpszId);

hr = MAPIAllocateMore(cBytes, lpIdItem, (void **)&lpIdItem->lpszId);

if(FAILED(hr))
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}

lstrcpy(lpIdItem->lpszId, lpszId);

*lppIdItem = lpIdItem;

cleanup:

RETURN(hr);
}

//$--HrDestroyIdItem------------------------------------------------------------
// Destroys an ID item.
// -----------------------------------------------------------------------------
HRESULT HrDestroyIdItem( // RETURNS: return code
IN OUT LPIDITEM *lppIdItem) // identifier item
{
HRESULT hr = NOERROR;

MAPIFREEBUFFER(*lppIdItem);

RETURN(hr);
}

//$--HrLookupIdItem-------------------------------------------------------------
// Looks up an ID item.
// -----------------------------------------------------------------------------
HRESULT HrLookupIdItem( // RETURNS: return code
IN LPIDITEM lpIdList, // identifier item list
IN LPTSTR lpszId, // identifier
IN OUT LPIDITEM *lppIdItem) // identifier item
{
HRESULT hr = EDK_E_NOT_FOUND;
HRESULT hrT = NOERROR;
LPIDITEM lpIdItem = NULL;

__try
{
*lppIdItem = NULL;

lpIdItem = lpIdList->next;

while(lpIdItem != NULL)
{
if(!lstrcmpi(lpIdItem->lpszId, lpszId))
{
//
// Found identifier in ID list
//

*lppIdItem = lpIdItem;

hr = NOERROR;
goto cleanup;
}

lpIdItem = lpIdItem->next;
}
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
SetLastError(_exception_code());

hr = HR_LOG(E_FAIL);

MODULE_WARNING("**** Stopping gateway ****");

SetServiceExitCode( ERROR_INTERNAL_ERROR, NOERROR);

ServiceStop();
}

cleanup:

RETURN(hr);
}

//$--HrAddIdItem----------------------------------------------------------------
// Adds an ID item to a list.
// -----------------------------------------------------------------------------
HRESULT HrAddIdItem( // RETURNS: return code
IN LPIDITEM lpIdList, // identifier item list
IN LPTSTR lpszId, // identifier
IN OUT LPIDITEM *lppIdItem) // identifier item
{
HRESULT hr = EDK_E_NOT_FOUND;
HRESULT hrT = NOERROR;
LPIDITEM lpIdItem = NULL;

EnterCriticalSection(lpIdList->lpcs);

hr = HrLookupIdItem(lpIdList, lpszId, &lpIdItem);

if(hr != EDK_E_NOT_FOUND)
{
hr = HR_LOG(EDK_E_ALREADY_EXISTS);
goto cleanup;
}

__try
{
*lppIdItem = NULL;

hr = HrCreateIdItem(
lpszId,
&lpIdItem);

if(FAILED(hr))
{
goto cleanup;
}

lpIdItem->next = lpIdList->next;

lpIdList->next = lpIdItem;

*lppIdItem = lpIdItem;
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
SetLastError(_exception_code());

hr = HR_LOG(E_FAIL);

MODULE_WARNING("**** Stopping gateway ****");

SetServiceExitCode( ERROR_INTERNAL_ERROR, NOERROR);

ServiceStop();
}

cleanup:

LeaveCriticalSection(lpIdList->lpcs);

RETURN(hr);
}

//$--HrRemoveIdItem-------------------------------------------------------------
// Removes an ID item from a list.
// -----------------------------------------------------------------------------
HRESULT HrRemoveIdItem( // RETURNS: return code
IN LPIDITEM lpIdList, // identifier item list
IN LPIDITEM lpIdItem) // identifier item
{
HRESULT hr = EDK_E_NOT_FOUND;
HRESULT hrT = NOERROR;
LPIDITEM lpPrevIdItem = NULL;
LPIDITEM lpCurrIdItem = NULL;

EnterCriticalSection(lpIdList->lpcs);

__try
{
lpCurrIdItem = lpIdList->next;

while(lpCurrIdItem != NULL)
{
if(lpCurrIdItem == lpIdItem)
{
//
// Found identifier item in ID list
//

if(lpIdList->next == lpIdItem)
{
// item found at head of list
lpIdList->next = lpIdItem->next;
}
else
{
lpPrevIdItem->next = lpIdItem->next;
}

hr = NOERROR;
goto cleanup;
}

lpPrevIdItem = lpCurrIdItem;
lpCurrIdItem = lpCurrIdItem->next;
}
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
SetLastError(_exception_code());

hr = HR_LOG(E_FAIL);

MODULE_WARNING("**** Stopping gateway ****");

SetServiceExitCode( ERROR_INTERNAL_ERROR, NOERROR);

ServiceStop();
}

cleanup:

hrT = HrDestroyIdItem(&lpIdItem);

if(FAILED(hr))
{
hrT = HR_LOG(E_FAIL);
}

LeaveCriticalSection(lpIdList->lpcs);

RETURN(hr);
}

//$--HrEmptyIdList--------------------------------------------------------------
// Empty an ID list.
// -----------------------------------------------------------------------------
HRESULT HrEmptyIdList( // RETURNS: return code
IN LPIDITEM lpIdList) // identifier item list
{
HRESULT hr = NOERROR;
HRESULT hrT = NOERROR;
LPIDITEM lpIdItem = NULL;

EnterCriticalSection(lpIdList->lpcs);

__try
{
lpIdItem = lpIdList->next;

while(lpIdItem != NULL)
{
lpIdList->next = lpIdItem->next;

MAPIFREEBUFFER(lpIdItem);

lpIdItem = lpIdList->next;
}
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
SetLastError(_exception_code());

hr = HR_LOG(E_FAIL);

MODULE_WARNING("**** Stopping gateway ****");

SetServiceExitCode( ERROR_INTERNAL_ERROR, NOERROR);

ServiceStop();
}

LeaveCriticalSection(lpIdList->lpcs);

RETURN(hr);
}

//$--HrCreateMtsId--------------------------------------------------------------
// Returns the newly created stringized MTS identifier. It takes in a site
// MTS identifier string that contains the country, ADMD and PRMD code and
// creates the local identifier to create a new MTS identifier.
// -----------------------------------------------------------------------------
HRESULT HrCreateMtsId( // RETURNS: return code
IN LPSTR lpszSiteMtsId, // site MTS identifier
IN LPSTR lpszGatewayName, // gateway name
IN ULONG ulSeqNo, // sequence number
OUT LPSTR lpszMTSID) // MTS identifier
{
HRESULT hr = NOERROR;
SYSTEMTIME st = {0};
CHAR rgchUTC[cbMTSIDMax] = {0};
ULONG cbMTName = 0;
LPSTR lpszMTName[cbMTSIDMax] = {0};
ULONG cbSeqNo = 0;
CHAR rgchSeqNo[9] = {0};

// Get the current time and make it a UTCTime string
GetSystemTime(&st);
sprintf(rgchUTC, "%04u%02u%02u%02u%02u%02uZ",
st.wYear,
st.wMonth,
st.wDay,
st.wHour,
st.wMinute,
st.wSecond);

// format the ulSeqNo into a string and get's length
sprintf((LPSTR)rgchSeqNo, "%08lx", ulSeqNo);
cbSeqNo = strlen(rgchSeqNo);

// find out how much of the gateway name can be put into the local identifer
cbMTName = 32 - cbSeqNo - strlen(rgchUTC) - 2;

lstrcpy((LPSTR)lpszMTName, lpszGatewayName);

if(cbMTName < (ULONG)lstrlen((LPSTR)lpszMTName))
{
lpszMTName[cbMTName] = 0;
}

//
// Format of local identifier is:
// "Gateway Name-stringized UTC Time-stringized ulSeqNo"
// NOTE: DO NOT CHANGE Delimiter to "/".
//

sprintf(
lpszMTSID,
"%s;L=%s-%s-%s",
lpszSiteMtsId,
lpszMTName,
rgchUTC,
rgchSeqNo);

RETURN(hr);
}

//$--DumpPropProblems-----------------------------------------------------------
// Dumps property problems to the debug log.
//------------------------------------------------------------------------------
VOID DumpPropProblems( // RETURNS: nothing
IN LPSTR lpszFile, // source file name
IN ULONG ulLine, // source line number
IN LPSPropProblemArray lpProblems) // property problems
{
ULONG i = 0;

DEBUGPUBLIC("DumpPropProblems()\n");

if(lpProblems == NULL)
{
goto cleanup;
}

#ifdef DEBUG
for(i = 0; i < lpProblems->cProblem; i++)
{
_Assert("PROBLEM", lpszFile, ulLine, D_WARNING, 0, "%lu\t%08lx\t%08lx\n",
lpProblems->aProblem[i].ulIndex,
lpProblems->aProblem[i].ulPropTag,
lpProblems->aProblem[i].scode);
}
#endif

cleanup:

return;
}

#ifdef DEBUG
#define DUMPPROPPROBLEMS(_prob) DumpPropProblems(__FILE__,__LINE__,(_prob))
#else
#define DUMPPROPPROBLEMS(_prob) ((void)0)
#endif

//$--HrCreateEnterpriseGDI------------------------------------------------------
// Create the enterprise GDI from the input string.
// -----------------------------------------------------------------------------
HRESULT HrCreateEnterpriseGDI( // RETURNS: return code
IN LPTSTR lpsz, // pointer to input string
IN LPTSTR lpszEOT, // pointer to separator character(s)
OUT LPTSTR *lppszGDI) // pointer to enterprise GDI
{
HRESULT hr = NOERROR;
SCODE sc = 0;
ULONG cBytes = 0;
ULONG cArraySize = 0;
LPTSTR *lppszArray = NULL;
LPTSTR lpszCountry = NULL;
LPTSTR lpszAdmd = NULL;
LPTSTR lpszPrmd = NULL;
ULONG i = 0;

DEBUGPUBLIC("HrCreateEnterpriseGDI()\n");

*lppszGDI = NULL;

hr = HrStrTokAll(
lpsz,
lpszEOT,
&cArraySize,
&lppszArray);

if(FAILED(hr))
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}

for(i = 0; i < cArraySize; i++)
{
if(lppszArray[i] == NULL)
{
;
}
else if(!_tcsnicmp(lppszArray[i], C_EQU, lstrlen(C_EQU)))
{
lpszCountry = lppszArray[i];
}
else if(!_tcsnicmp(lppszArray[i], A_EQU, lstrlen(A_EQU)))
{
lpszAdmd = lppszArray[i];
}
else if(!_tcsnicmp(lppszArray[i], P_EQU, lstrlen(P_EQU)))
{
lpszPrmd = lppszArray[i];
}
}

if(lpszCountry == NULL)
{
lpszCountry = TEXT("C=;");
}

if(lpszAdmd == NULL)
{
lpszAdmd = TEXT("A=;");
}

if(lpszPrmd == NULL)
{
lpszPrmd = TEXT("P=;");
}

cBytes = (lstrlen(TEXT(";;;")) +
lstrlen(lpszCountry) +
lstrlen(lpszAdmd) +
lstrlen(lpszPrmd) + 1) * sizeof(TCHAR);

sc = MAPIAllocateBuffer(cBytes, (void **)lppszGDI);

if(FAILED(sc))
{
hr = HR_LOG(E_OUTOFMEMORY);
goto cleanup;
}

lstrcpy(*lppszGDI, lpszCountry);
lstrcat(*lppszGDI, TEXT(";"));
lstrcat(*lppszGDI, lpszAdmd);
lstrcat(*lppszGDI, TEXT(";"));
lstrcat(*lppszGDI, lpszPrmd);
lstrcat(*lppszGDI, TEXT(";"));

CharUpperBuff(*lppszGDI, cBytes/sizeof(TCHAR));

cleanup:

if(FAILED(hr))
{
MAPIFREEBUFFER(*lppszGDI);
}

MAPIFREEBUFFER(lppszArray);

RETURN(hr);
}

//$--HrGetMtsIdEnterpriseGDI----------------------------------------------------
// Get the enterprise GDI from the MTS-ID (or SUBJECT-MTS-ID).
// -----------------------------------------------------------------------------
HRESULT HrGetMtsIdEnterpriseGDI( // RETURNS: return code
IN LPMESSAGE lpMessage, // pointer to message
IN ULONG ulPropTag, // MTS-ID property tag
OUT LPTSTR *lppszGDI) // pointer to enterprise GDI
{
HRESULT hr = NOERROR;
ULONG cBytes = 0;
LPTSTR lpszMtsId = NULL;

DEBUGPUBLIC("HrGetMtsIdEnterpriseGDI()\n");

*lppszGDI = NULL;

hr = HrMAPIGetPropBinary(
(LPMAPIPROP)lpMessage,
ulPropTag,
&cBytes,
(LPVOID *)&lpszMtsId);

if(FAILED(hr))
{
goto cleanup;
}

hr = HrCreateEnterpriseGDI(
lpszMtsId,
TEXT("/;"),
lppszGDI);

if(FAILED(hr))
{
goto cleanup;
}

cleanup:

if(FAILED(hr))
{
MAPIFREEBUFFER(*lppszGDI);
}

MAPIFREEBUFFER(lpszMtsId);

RETURN(hr);
}

//$--HrGetTraceEnterpriseGDI----------------------------------------------------
// Get the enterprise GDI from the external trace information.
// -----------------------------------------------------------------------------
HRESULT HrGetTraceEnterpriseGDI( // RETURNS: return code
IN LPMESSAGE lpMessage, // pointer to message
IN ULONG ulPropTag, // external trace info property tag
OUT LPTSTR *lppszGDI) // pointer to enterprise GDI
{
HRESULT hr = NOERROR;
SCODE sc = 0;
ULONG cBytes = 0;
LPTRACEINFO lpTraceInfo = NULL;
LPTRACEENTRY lpTraceEntry = NULL;
FILETIME ft = {0};
LPTSTR lpszT = NULL;
LPTSTR lpszCountry = NULL;
LPTSTR lpszAdmd = NULL;
LPTSTR lpszPrmd = NULL;
ULONG i = 0;

DEBUGPUBLIC("HrGetTraceEnterpriseGDI()\n");

*lppszGDI = NULL;

hr = HrMAPIGetPropBinary(
(LPMAPIPROP)lpMessage,
ulPropTag,
&cBytes,
(LPVOID *)&lpTraceInfo);

if(FAILED(hr))
{
goto cleanup;
}

hr = HrTraceGotoFirstEntry(
lpTraceInfo,
&i,
&lpTraceEntry);

if(FAILED(hr))
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}

hr = HrTraceOpenEntry(
lpTraceEntry,
&i,
&ft,
&ft,
&lpszAdmd,
&lpszCountry,
&lpszPrmd,
&lpszT,
&lpszT,
&lpszT);

if(FAILED(hr))
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}

if(lpszCountry == NULL)
{
lpszCountry = TEXT("C=;");
}

if(lpszAdmd == NULL)
{
lpszAdmd = TEXT("A=;");
}

if(lpszPrmd == NULL)
{
lpszPrmd = TEXT("P=;");
}

cBytes = (lstrlen(TEXT("C=;A=;P=;")) +
lstrlen(lpszCountry) +
lstrlen(lpszAdmd) +
lstrlen(lpszPrmd) + 1) * sizeof(TCHAR);

sc = MAPIAllocateBuffer(cBytes, (void **)lppszGDI);

if(FAILED(sc))
{
hr = HR_LOG(E_OUTOFMEMORY);
goto cleanup;
}

lstrcpy(*lppszGDI, C_EQU);
lstrcat(*lppszGDI, lpszCountry);
lstrcat(*lppszGDI, TEXT(";A="));
lstrcat(*lppszGDI, lpszAdmd);
lstrcat(*lppszGDI, TEXT(";P="));
lstrcat(*lppszGDI, lpszPrmd);
lstrcat(*lppszGDI, TEXT(";"));

CharUpperBuff(*lppszGDI, cBytes/sizeof(TCHAR));

cleanup:

if(FAILED(hr))
{
MAPIFREEBUFFER(*lppszGDI);
}

MAPIFREEBUFFER(lpTraceInfo);

RETURN(hr);
}

//$--HrFixUpRecipientNumbers----------------------------------------------------
// Fix up recipient numbers.
// -----------------------------------------------------------------------------
static HRESULT HrFixUpRecipientNumbers( // RETURNS: return code
IN OUT LPADRLIST lpEnvelopeAdrList, // pointer to envelope address list
IN OUT LPADRLIST lpMessageAdrList) // pointer to message address list
{
HRESULT hr = NOERROR;
HRESULT hrT = NOERROR;
SCODE sc = 0;
ULONG cb = 0;

ULONG* rgulOrigRecipNums = NULL;

LPSPropValue lpPropT = NULL;

ULONG i = 0;
ULONG j = 0;

ULONG cValues = 0;
LPSPropValue lpProps = NULL;

DEBUGPRIVATE("HrFixUpRecipientNumbers()\n");

if( (!((lpMessageAdrList == NULL) || (lpMessageAdrList->cEntries == 0))) &&
(!((lpEnvelopeAdrList == NULL) || (lpEnvelopeAdrList->cEntries == 0))))
{
cb = lpMessageAdrList->cEntries * (sizeof(ULONG) + MAX_ALIGN);

sc = MAPIAllocateBuffer(cb, (void **)&rgulOrigRecipNums);

if(FAILED(sc))
{
hr = HR_LOG(E_OUTOFMEMORY);
goto cleanup;
}

for(i = 0; i < lpMessageAdrList->cEntries; i++)
{
rgulOrigRecipNums[i] = 0;

cValues = lpMessageAdrList->aEntries[i].cValues;
lpProps = lpMessageAdrList->aEntries[i].rgPropVals;

if(lpProps != NULL)
{
lpPropT = LpValFindProp(PR_RECIPIENT_NUMBER, cValues, lpProps);

if(lpPropT == NULL)
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}

rgulOrigRecipNums[i] = lpPropT->Value.ul;

lpPropT->ulPropTag =
PROP_TAG(PT_ERROR, PROP_ID(lpPropT->ulPropTag));
}
}

for(i = 0; i < lpEnvelopeAdrList->cEntries; i++)
{
cValues = lpEnvelopeAdrList->aEntries[i].cValues;
lpProps = lpEnvelopeAdrList->aEntries[i].rgPropVals;

if(lpProps != NULL)
{
lpPropT = LpValFindProp(PR_RECIPIENT_NUMBER, cValues, lpProps);

if(lpPropT == NULL)
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}

for(j = 0; j < lpMessageAdrList->cEntries; j++)
{
if(rgulOrigRecipNums[j] == lpPropT->Value.ul)
{
lpPropT->Value.ul = j+1;
}
}
}
}

//
// Clear recipient numbers for message address list.
//

hr = HrDeleteAddressListProperty(
PR_RECIPIENT_NUMBER,
(LPADRLIST)lpMessageAdrList);

if(FAILED(hr))
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}
}

//
// Clear row IDs for envelope address list.
//

if(!((lpEnvelopeAdrList == NULL) || (lpEnvelopeAdrList->cEntries == 0)))
{
hr = HrDeleteAddressListProperty(
PR_ROWID,
(LPADRLIST)lpEnvelopeAdrList);

if(FAILED(hr))
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}
}

//
// Clear row IDs for message address list.
//

if(!((lpMessageAdrList == NULL) || (lpMessageAdrList->cEntries == 0)))
{
hr = HrDeleteAddressListProperty(
PR_ROWID,
(LPADRLIST)lpMessageAdrList);

if(FAILED(hr))
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}
}

cleanup:

MAPIFREEBUFFER(rgulOrigRecipNums);

RETURN(hr);
}

//$--HrDeleteSenderProps--------------------------------------------------------
// Delete sender properties from the message.
// -----------------------------------------------------------------------------
HRESULT HrDeleteSenderProps( // RETURNS: return code
IN LPMESSAGE lpMessage) // pointer to message
{
HRESULT hr = NOERROR;
HRESULT hrT = NOERROR;

LPSPropProblemArray lpProblems = NULL;

SizedSPropTagArray(10, rgPropTags) =
{
10,
{
PR_SENDER_NAME,
PR_SENDER_ADDRTYPE,
PR_SENDER_EMAIL_ADDRESS,
PR_SENDER_SEARCH_KEY,
PR_SENDER_ENTRYID,
PR_SENT_REPRESENTING_NAME,
PR_SENT_REPRESENTING_ADDRTYPE,
PR_SENT_REPRESENTING_EMAIL_ADDRESS,
PR_SENT_REPRESENTING_SEARCH_KEY,
PR_SENT_REPRESENTING_ENTRYID,
}
};

DEBUGPUBLIC("HrDeleteSenderProps()\n");

hrT = MAPICALL(lpMessage)->DeleteProps(
lpMessage,
(SPropTagArray *)&rgPropTags,
&lpProblems);

if(FAILED(hrT))
{
lpProblems = NULL;

hr = HR_LOG(E_FAIL);
goto cleanup;
}

DUMPPROPPROBLEMS(lpProblems);

cleanup:

MAPIFREEBUFFER(lpProblems);

RETURN(hr);
}

//$--HrDeleteMtsIdProps---------------------------------------------------------
// Delete MTS-ID properties from the message.
// -----------------------------------------------------------------------------
HRESULT HrDeleteMtsIdProps( // RETURNS: return code
IN LPMESSAGE lpMessage) // pointer to message
{
HRESULT hr = NOERROR;

LPSPropProblemArray lpProblems = NULL;

SizedSPropTagArray(1, rgPropTags) =
{
1,
{
PR_MTS_ID,
}
};

DEBUGPUBLIC("HrDeleteMtsIdProps()\n");

hr = MAPICALL(lpMessage)->DeleteProps(
lpMessage,
(SPropTagArray *)&rgPropTags,
&lpProblems);

if(FAILED(hr))
{
lpProblems = NULL;

hr = HR_LOG(E_FAIL);
goto cleanup;
}

DUMPPROPPROBLEMS(lpProblems);

cleanup:

MAPIFREEBUFFER(lpProblems);

RETURN(hr);
}

//$--HrDeleteTraceProps---------------------------------------------------------
// Delete trace properties from the message.
// -----------------------------------------------------------------------------
HRESULT HrDeleteTraceProps( // RETURNS: return code
IN LPMESSAGE lpMessage) // pointer to message
{
HRESULT hr = NOERROR;

LPSPropProblemArray lpProblems = NULL;

SizedSPropTagArray(1, rgPropTags) =
{
1,
{
PR_TRACE_INFO,
}
};

DEBUGPUBLIC("HrDeleteTraceProps()\n");

hr = MAPICALL(lpMessage)->DeleteProps(
lpMessage,
(SPropTagArray *)&rgPropTags,
&lpProblems);

if(FAILED(hr))
{
lpProblems = NULL;

hr = HR_LOG(E_FAIL);
goto cleanup;
}

DUMPPROPPROBLEMS(lpProblems);

cleanup:

MAPIFREEBUFFER(lpProblems);

RETURN(hr);
}

//$--HrNonDeliverAllRecipList---------------------------------------------------
// Create a recipient list to non-deliver all recipients.
// -----------------------------------------------------------------------------
HRESULT HrNonDeliverAllRecipList( // RETURNS: return code
IN LPMESSAGE lpMessage, // message
IN LPADRLIST *lppAdrList) // address list
{
HRESULT hr = NOERROR;
HRESULT hrT = NOERROR;
LPSRowSet lpRows = NULL;
LPADRLIST lpAdrList = NULL;
LPADRLIST lpAllAdrList = NULL;
LPMAPITABLE lpTable = NULL;

LPSPropValue lpPropT = NULL;

ULONG cFailedValues = 0;
LPSPropValue lpFailedProps = NULL;

ULONG i = 0;

DEBUGPUBLIC("HrNonDeliverAllRecipList()");

*lppAdrList = NULL;

//
// Get the recipient table for the message
//

hr = MAPICALL(lpMessage)->GetRecipientTable(
lpMessage,
MAPI_DEFERRED_ERRORS,
&lpTable);

if(FAILED(hr))
{
goto cleanup;
}

//
// Query all the rows
//

hr = HrQueryAllRows(
lpTable,
NULL,
NULL,
NULL,
0,
&lpRows);

if(FAILED(hr))
{
goto cleanup;
}

lpAdrList = (LPADRLIST)lpRows;

hr = HrNDRCreateFailedRecipList(
&lpAllAdrList);

if(FAILED(hr))
{
goto cleanup;
}

for(i = 0; i < lpAdrList->cEntries; i++)
{
hr = HrNDRGetFailedRecipList(
&lpAdrList->aEntries[i],
0,
NULL,
&cFailedValues,
&lpFailedProps);

if(FAILED(hr))
{
goto cleanup;
}

lpPropT = LpValFindProp(PR_RECIPIENT_NUMBER, cFailedValues, lpFailedProps);

if(lpPropT != NULL) 
{
lpPropT->Value.ul = (i+1);
}

hr = HrNDRAddToFailedRecipList(
cFailedValues,
lpFailedProps,
&lpAllAdrList);

if(FAILED(hr))
{
goto cleanup;
}

MAPIFREEBUFFER(lpFailedProps);
} // end for

*lppAdrList = lpAllAdrList;
lpAllAdrList = NULL;

cleanup:

MAPIFREEBUFFER(lpFailedProps);

FREEPADRLIST(lpAdrList); // also frees lpRows

FREEPADRLIST(lpAllAdrList);

ULRELEASE(lpTable);

if(FAILED(hr))
{
FREEPADRLIST(lpAllAdrList);
*lppAdrList = NULL;
}

RETURN(hr);
}

//$--HrCreateNonDeliveryReport--------------------------------------------------
// Create a non-delivery report.
// -----------------------------------------------------------------------------
HRESULT HrCreateNonDeliveryReport( // RETURNS: return code
IN BOOL fCreateMtsId, // create MTS identifier
IN LPADRBOOK lpAdrBook, // pointer to address book
IN LPMAPIFOLDER lpFolder, // pointer to folder
IN LPMESSAGE lpMessage, // pointer to message
IN LPADRLIST lpAdrList, // pointer to address list
OUT LPMESSAGE *lppReport) // pointer to report
{
HRESULT hr = NOERROR;
LPMESSAGE lpReport = NULL;
ULONG cBytes = 0;
ULONG cValues = 0;
LPSPropValue lpProps = NULL;

LPTSTR lpszEmailDisplayName = NULL;
LPTSTR lpszEmailAddressType = NULL;
LPTSTR lpszEmailAddress = NULL;
LPTSTR lpszEmailSearchKey = NULL;
ULONG cbEmailEid = 0;
LPENTRYID lpEmailEid = NULL;

LPSPropProblemArray lpProblems = NULL;

CHAR szGatewayName[MAX_SERVICE_NAME_LENGTH+1] = {0};

ULONG ulMtsIdSeqNo = 0;
CHAR rgchMTSID[cbMTSIDMax] = {0};

DEBUGPUBLIC("HrCreateNonDeliveryReport()\n");

*lppReport = NULL;

if(fCreateMtsId == TRUE)
{
EnterCriticalSection(&csGatewaySeqNo);
ulMtsIdSeqNo = ++ulGatewaySeqNo;
LeaveCriticalSection(&csGatewaySeqNo);

//
// Get gateway service name.
//

hr = HrServiceGetName(
szGatewayName);

if(FAILED(hr))
{
goto cleanup;
}

hr = HrCreateMtsId(
lpszLocalGDI,
szGatewayName,
ulMtsIdSeqNo,
rgchMTSID);

if(FAILED(hr))
{
goto cleanup;
}
}

hr = HrNDRGetFailedProps(
lpMessage,
&cValues,
&lpProps);

if(FAILED(hr))
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}

hr = HrNDRCreate(
lpAdrBook,
lpFolder,
lpMessage,
lpAdrList,
cValues,
lpProps,
&lpReport);

MAPIFREEBUFFER(lpProps);

if(FAILED(hr))
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}

cBytes = CbNewSPropValue(6);

hr = MAPIAllocateBuffer(cBytes, (void **)&lpProps);

if(FAILED(hr))
{
hr = HR_LOG(E_OUTOFMEMORY);
goto cleanup;
}

ZeroMemory(lpProps, cBytes);

hr = HrCreateProxyAddress(
lpAdrBook,
lpProps,
TRUE,
SYSTEM_ADMINISTRATOR,
SYSTEM,
SYSTEM_ADMINISTRATOR,
&lpszEmailDisplayName,
&lpszEmailAddressType,
&lpszEmailAddress,
&lpszEmailSearchKey,
&cbEmailEid,
&lpEmailEid);

if(FAILED(hr))
{
goto cleanup;
}

lpProps[0].ulPropTag = PR_SENDER_NAME;
lpProps[0].Value.LPSZ = lpszEmailDisplayName;

lpProps[1].ulPropTag = PR_SENDER_ADDRTYPE;
lpProps[1].Value.LPSZ = lpszEmailAddressType;

lpProps[2].ulPropTag = PR_SENDER_EMAIL_ADDRESS;
lpProps[2].Value.LPSZ = lpszEmailAddress;

lpProps[3].ulPropTag = PR_SENDER_SEARCH_KEY;

if(lpszEmailSearchKey == NULL)
{
lpProps[3].Value.bin.cb = 0;
lpProps[3].Value.bin.lpb = NULL;
}
else
{
lpProps[3].Value.bin.cb = cbStrLen(lpszEmailSearchKey);
lpProps[3].Value.bin.lpb = lpszEmailSearchKey;
}

lpProps[4].ulPropTag = PR_SENDER_ENTRYID;
lpProps[4].Value.bin.cb = cbEmailEid;
lpProps[4].Value.bin.lpb = (LPBYTE)lpEmailEid;

lpProps[5].ulPropTag = PR_MTS_ID;
lpProps[5].Value.bin.cb = cbStrLen(rgchMTSID);
lpProps[5].Value.bin.lpb = (LPBYTE)rgchMTSID;

if(fCreateMtsId == TRUE)
{
cValues = 6;
}
else
{
cValues = 5;
}

hr = MAPICALL(lpReport)->SetProps(
lpReport,
cValues,
lpProps,
&lpProblems);

if(FAILED(hr))
{
lpProblems = NULL;

hr = HR_LOG(E_FAIL);
goto cleanup;
}

DUMPPROPPROBLEMS(lpProblems);
MAPIFREEBUFFER(lpProblems);

// Save changes just made to report envelope
hr = MAPICALL(lpReport)->SaveChanges(
lpReport,
KEEP_OPEN_READWRITE);

if ( FAILED(hr) )
{
hr = HR_LOG(E_FAIL);

goto cleanup;
}

*lppReport = lpReport;

cleanup:

MAPIFREEBUFFER(lpProps);

MAPIFREEBUFFER(lpProblems);

RETURN(hr);
}

//$--HrImportMessage------------------------------------------------------------
// Process an IPM/IPN in MTS-IN.
// -----------------------------------------------------------------------------
HRESULT HrImportMessage( // RETURNS: return code
IN LPADRBOOK lpAdrBook, // pointer to address book
IN LPABCONT lpGalABCont, // pointer to GAL
IN BOOL fIgnoreRespValue, // ignore responsibility value
IN BOOL fSendNDR, // TRUE if NDRs should be generated
IN DWORD dwStartProcessingTime, // start processing time
IN OUT LPMESSAGE lpEnvelope) // pointer to envelope
{
HRESULT hr = NOERROR;
HRESULT hrT = NOERROR;

LPMESSAGE lpMessage = NULL;
LPATTACH lpAttach = NULL;

ULONG cEnvelopeValues = 0;
LPSPropValue lpEnvelopeProps = NULL;
ULONG cMessageValues = 0;
LPSPropValue lpMessageProps = NULL;

LPADRLIST lpOriginalEnvelopeAdrList = NULL;
LPADRLIST lpOriginalMessageAdrList = NULL;

LPADRLIST lpEnvelopeAdrList = NULL;
LPADRLIST lpMessageAdrList = NULL;

LPADRLIST lpEnvelope_NDR_AdrList = NULL;
LPADRLIST lpMessage_NDR_AdrList = NULL;

DWORD dwEndProcessingTime = 0;
DWORD dwTotalProcessingTime = 0;
DWORD dwSleepProcessingTime = 0;

ULONG cEnvelopeMesgAddr = 0;
ULONG cEnvelopeReplyAddr = 0;
ULONG cEnvelopeRecipAddr = 0;
LPADRLIST lpEnvelopeAllAdrList = NULL;
LPADRLIST lpMappedEnvelopeAdrList = NULL;

ULONG cMessageMesgAddr = 0;
ULONG cMessageReplyAddr = 0;
ULONG cMessageRecipAddr = 0;
LPADRLIST lpMessageAllAdrList = NULL;
LPADRLIST lpMappedMessageAdrList = NULL;

BOOL HasContent = TRUE;

LPSPropProblemArray lpProblems = NULL;

DEBUGPUBLIC("HrImportMessage()\n");

// Get the attachment in the envelope
hrT = MAPICALL(lpEnvelope)->OpenAttach(
lpEnvelope,
0,
NULL,
MAPI_MODIFY,
&lpAttach);

if((FAILED(hrT)) && (hrT != MAPI_E_NOT_FOUND))
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}

if(hrT == MAPI_E_NOT_FOUND)
{
//
// Message does not have an attachment.
//

HasContent = FALSE;
lpAttach = NULL;
}

if(HasContent == TRUE)
{
// Open a message interface on the attachment
hrT = MAPICALL(lpAttach)->OpenProperty(
lpAttach,
PR_ATTACH_DATA_OBJ,
(LPIID)&IID_IMessage,
0,
MAPI_DEFERRED_ERRORS|MAPI_MODIFY,
(LPUNKNOWN *)&lpMessage);

if(FAILED(hrT))
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}
}

//------------------------------------------------------------------------------

//
// Map envelope addresses
//

hr = HrExpandMessageAddressList(
lpEnvelope,
&cEnvelopeMesgAddr,
&cEnvelopeReplyAddr,
&cEnvelopeRecipAddr,
&lpOriginalEnvelopeAdrList,
&lpEnvelopeAllAdrList);

if(FAILED(hr))
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}

hr = HrMapAddrToProxy(
lpAdrBook,
lpszAddressType,
lpEnvelopeAllAdrList);

if(FAILED(hr))
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}

hr = HrMapGatewayProxyToAddr(
lpAdrBook,
lpszAddressType,
lpEnvelopeAllAdrList);

if(FAILED(hr))
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}

hr = HrMapProxyToAddr(
lpAdrBook,
lpGalABCont,
lpEnvelopeAllAdrList);

if(FAILED(hr))
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}

hr = HrCollapseMessageAddressList(
lpEnvelope,
cEnvelopeMesgAddr,
cEnvelopeReplyAddr,
cEnvelopeRecipAddr,
lpEnvelopeAllAdrList,
&cEnvelopeValues,
&lpEnvelopeProps,
&lpMappedEnvelopeAdrList);

if(FAILED(hr))
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}

FREEPADRLIST(lpEnvelopeAllAdrList);

//
// TNEF encode is setting the value of PR_RESPONSIBILITY to FALSE
// for each recipient entry.
//

{
ULONG i = 0;
LPSPropValue lpPropT = NULL;

for(i = 0; i < lpOriginalEnvelopeAdrList->cEntries; i++)
{
lpPropT = LpValFindProp(
PR_RESPONSIBILITY,
lpOriginalEnvelopeAdrList->aEntries[i].cValues,
lpOriginalEnvelopeAdrList->aEntries[i].rgPropVals);

if(lpPropT != NULL)
{
lpPropT->Value.b = TRUE;
}
}

for(i = 0; i < lpMappedEnvelopeAdrList->cEntries; i++)
{
lpPropT = LpValFindProp(
PR_RESPONSIBILITY,
lpMappedEnvelopeAdrList->aEntries[i].cValues,
lpMappedEnvelopeAdrList->aEntries[i].rgPropVals);

if(lpPropT != NULL)
{
lpPropT->Value.b = TRUE;
}
}
}

if(HasContent == TRUE)
{
//
// Map message addresses
//

hr = HrExpandMessageAddressList(
lpMessage,
&cMessageMesgAddr,
&cMessageReplyAddr,
&cMessageRecipAddr,
&lpOriginalMessageAdrList,
&lpMessageAllAdrList);

if(FAILED(hr))
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}

hr = HrMapAddrToProxy(
lpAdrBook,
lpszAddressType,
lpMessageAllAdrList);

if(FAILED(hr))
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}

hr = HrMapGatewayProxyToAddr(
lpAdrBook,
lpszAddressType,
lpMessageAllAdrList);

if(FAILED(hr))
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}

hr = HrMapProxyToAddr(
lpAdrBook,
lpGalABCont,
lpMessageAllAdrList);

if(FAILED(hr))
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}

hr = HrCollapseMessageAddressList(
lpMessage,
cMessageMesgAddr,
cMessageReplyAddr,
cMessageRecipAddr,
lpMessageAllAdrList,
&cMessageValues,
&lpMessageProps,
&lpMappedMessageAdrList);

if(FAILED(hr))
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}

FREEPADRLIST(lpMessageAllAdrList);
}

//------------------------------------------------------------------------------

hr = HrMapRecipProxyToAddr(
lpAdrBook,
TRUE,
fIgnoreRespValue,
lpGalABCont,
lpszAddressType,
lpOriginalEnvelopeAdrList,
lpMappedEnvelopeAdrList,
NULL,
NULL,
lpEnvelope,
&lpEnvelopeAdrList,
&lpEnvelope_NDR_AdrList);

if(FAILED(hr))
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}

if(HasContent == TRUE)
{
hr = HrMapRecipProxyToAddr(
lpAdrBook,
FALSE,
fIgnoreRespValue,
lpGalABCont,
lpszAddressType,
lpOriginalMessageAdrList,
lpMappedMessageAdrList,
lpEnvelopeAdrList,
lpEnvelope_NDR_AdrList,
lpMessage,
&lpMessageAdrList,
&lpMessage_NDR_AdrList);

FREEPADRLIST(lpOriginalMessageAdrList);

FREEPADRLIST(lpMessage_NDR_AdrList);

if(FAILED(hr))
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}
}

// Non-deliver any recipients that could not be mapped.

if((lpEnvelope_NDR_AdrList != NULL) &&
(lpEnvelope_NDR_AdrList->cEntries != 0) &&
(fSendNDR == TRUE))
{
LPMESSAGE lpReportEnvelope = NULL;

//
// Clear row IDs for envelope NDR address list.
//

hr = HrDeleteAddressListProperty(
PR_ROWID,
(LPADRLIST)lpEnvelope_NDR_AdrList);

if(FAILED(hr))
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}

//
// Create a non delivery report in MTS-OUT
//

hr = HrCreateNonDeliveryReport(
TRUE,
lpAdrBook,
lpMtsOutFolder,
lpMessage,
lpEnvelope_NDR_AdrList,
&lpReportEnvelope);

if(FAILED(hr))
{
;
}
else
{
HANDLE hNewMailEvent = GetGWNewMailEvent();

if((hNewMailEvent != NULL) && (!SetEvent(hNewMailEvent)))
{
hr = HR_LOG(E_FAIL);
}
}

ULRELEASE(lpReportEnvelope);
}

FREEPADRLIST(lpEnvelope_NDR_AdrList);

if((lpEnvelopeAdrList == NULL) || (lpEnvelopeAdrList->cEntries == 0))
{
FREEPADRLIST(lpEnvelopeAdrList);

hr = HR_LOG(E_FAIL);
goto cleanup;
}

if(HasContent == TRUE)
{
if((lpMessageAdrList == NULL) || (lpMessageAdrList->cEntries == 0))
{
FREEPADRLIST(lpMessageAdrList);

hr = HR_LOG(E_FAIL);
goto cleanup;
}
}

//------------------------------------------------------------------------------

// Fix up recipient numbers
hr = HrFixUpRecipientNumbers(lpEnvelopeAdrList, lpMessageAdrList);

if(FAILED(hr))
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}

//------------------------------------------------------------------------------

hrT = MAPICALL(lpEnvelope)->SetProps(
lpEnvelope,
cEnvelopeValues,
lpEnvelopeProps,
&lpProblems);

if(FAILED(hrT))
{
lpProblems = NULL;

hr = HR_LOG(E_FAIL);
goto cleanup;
}

DUMPPROPPROBLEMS(lpProblems);
MAPIFREEBUFFER(lpProblems);

hr = HrMAPISetPropBoolean(
(LPMAPIPROP)lpEnvelope,
PR_DELETE_AFTER_SUBMIT,
TRUE);

if(FAILED(hr))
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}

if(HasContent == TRUE)
{
hrT = MAPICALL(lpMessage)->SetProps(
lpMessage,
cMessageValues,
lpMessageProps,
&lpProblems);

if(FAILED(hrT))
{
lpProblems = NULL;

hr = HR_LOG(E_FAIL);
goto cleanup;
}

DUMPPROPPROBLEMS(lpProblems);
MAPIFREEBUFFER(lpProblems);
}

//------------------------------------------------------------------------------

// Set envelope recipients
hrT = MAPICALL(lpEnvelope)->ModifyRecipients(
lpEnvelope,
0,
lpEnvelopeAdrList);

if(FAILED(hrT))
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}

if(HasContent == TRUE)
{
// Set message recipients
hrT = MAPICALL(lpMessage)->ModifyRecipients(
lpMessage,
0,
lpMessageAdrList);

if(FAILED(hrT))
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}
}

//------------------------------------------------------------------------------

if(HasContent == TRUE)
{
// Save changes to the message
hrT = MAPICALL(lpMessage)->SaveChanges(
lpMessage,
MAPI_DEFERRED_ERRORS|KEEP_OPEN_READWRITE);

if(FAILED(hrT))
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}

// Save changes to attachment object
hrT = MAPICALL(lpAttach)->SaveChanges(
lpAttach,
MAPI_DEFERRED_ERRORS|KEEP_OPEN_READWRITE);

if(FAILED(hrT))
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}

ULRELEASE(lpMessage);

ULRELEASE(lpAttach);
}

//----------------------------------------------------------------------
dwEndProcessingTime = GetTickCount();

dwTotalProcessingTime = dwEndProcessingTime - dwStartProcessingTime;

dwSleepProcessingTime =
((dwTotalProcessingTime < dwInSleepInterval) ?
(dwInSleepInterval - dwTotalProcessingTime) : 0);

if(dwSleepProcessingTime > 0)
{
Sleep(dwSleepProcessingTime);
}
//----------------------------------------------------------------------

// Submit message
hrT = MAPICALL(lpEnvelope)->SubmitMessage(lpEnvelope, FORCE_SUBMIT);

if(FAILED(hrT))
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}

cleanup:

MAPIFREEBUFFER(lpProblems);

FREEPADRLIST(lpEnvelopeAdrList);

FREEPADRLIST(lpMessageAdrList);

FREEPADRLIST(lpEnvelope_NDR_AdrList);

FREEPADRLIST(lpMessage_NDR_AdrList);

FREEPADRLIST(lpOriginalEnvelopeAdrList);
FREEPADRLIST(lpOriginalMessageAdrList);

FREEPADRLIST(lpEnvelopeAllAdrList);
FREEPADRLIST(lpMessageAllAdrList);

FREEPADRLIST(lpMappedEnvelopeAdrList);
FREEPADRLIST(lpMappedMessageAdrList);

MAPIFREEBUFFER(lpEnvelopeProps);
MAPIFREEBUFFER(lpMessageProps);

ULRELEASE(lpMessage);

ULRELEASE(lpAttach);

RETURN(hr);
}

//$--HrCheckExternalTraceInformation--------------------------------------------
// Process messages in MTS-IN.
// -----------------------------------------------------------------------------
HRESULT HrCheckExternalTraceInformation( // RETURNS: return code
IN LPMESSAGE lpEnvelope) // pointer to envelope
{
HRESULT hr = NOERROR;
LPTSTR lpszMtsIdGDI = NULL;
LPTSTR lpszTraceGDI = NULL;

DEBUGPUBLIC("HrCheckExternalTraceInformation()\n");

hr = HrGetMtsIdEnterpriseGDI(
lpEnvelope,
PR_MTS_ID,
&lpszMtsIdGDI);

if((FAILED(hr)) && (hr != MAPI_E_NOT_FOUND))
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}

hr = HrGetTraceEnterpriseGDI(
lpEnvelope,
PR_TRACE_INFO,
&lpszTraceGDI);

if((FAILED(hr)) && (hr != MAPI_E_NOT_FOUND))
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}

if((lpszMtsIdGDI == NULL) && (lpszTraceGDI == NULL))
{
// consistent
}
else if((lpszMtsIdGDI == NULL) || (lpszTraceGDI == NULL))
{
// warning
MODULE_ERROR("**** Inconsistent external trace ****");

if((lpszTraceGDI != NULL) &&
(lstrcmpi(lpszTraceGDI, lpszLocalGDI) == 0))
{
// delete MTS-ID
hr = HrDeleteMtsIdProps(
lpEnvelope);

if(FAILED(hr))
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}
}
else if((lpszMtsIdGDI != NULL) &&
(lstrcmpi(lpszMtsIdGDI, lpszLocalGDI) == 0))
{
// delete trace
hr = HrDeleteTraceProps(
lpEnvelope);

if(FAILED(hr))
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}
}
else
{
// delete trace
hr = HrDeleteTraceProps(
lpEnvelope);

if(FAILED(hr))
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}

// delete MTS-ID
hr = HrDeleteMtsIdProps(
lpEnvelope);

if(FAILED(hr))
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}
}
}
else
{
if(lstrcmpi(lpszMtsIdGDI, lpszTraceGDI) != 0)
{
// warning
MODULE_ERROR("**** Inconsistent external trace ****");

if(lstrcmpi(lpszTraceGDI, lpszLocalGDI) == 0)
{
// delete MTS-ID
hr = HrDeleteMtsIdProps(
lpEnvelope);

if(FAILED(hr))
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}
}
else if(lstrcmpi(lpszMtsIdGDI, lpszLocalGDI) == 0)
{
// delete trace
hr = HrDeleteTraceProps(
lpEnvelope);

if(FAILED(hr))
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}
}
else
{
// delete trace
hr = HrDeleteTraceProps(
lpEnvelope);

if(FAILED(hr))
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}

// delete MTS-ID
hr = HrDeleteMtsIdProps(
lpEnvelope);

if(FAILED(hr))
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}
}
}
else
{
// consistent
}
}

cleanup:

hr = NOERROR;

MAPIFREEBUFFER(lpszMtsIdGDI);

MAPIFREEBUFFER(lpszTraceGDI);

RETURN(hr);
}

//$--HrNonDeliverMtsInMessage---------------------------------------------------
// Non-deliver a message in MTS-IN.
// -----------------------------------------------------------------------------
HRESULT HrNonDeliverMtsInMessage( // RETURNS: zero
IN LPTSTR lpszMessageClass, // message class
IN LPMESSAGE lpEnvelope) // envelope
{
HRESULT hr = NOERROR;
LPADRBOOK lpAdrBook = NULL;
LPMESSAGE lpMessage = NULL;
LPMESSAGE lpSubjectMessage = NULL;
LPMESSAGE lpReportEnvelope = NULL;
LPADRLIST lpReportAdrList = NULL;
LPATTACH lpAttach = NULL;
BOOL HasContent = TRUE;

DEBUGPUBLIC("HrNonDeliverMtsInMessage()\n");

lpAdrBook = GetAdrBookPtr();

MODULE_ERROR1(
"**** [IN ] Unknown message class [%s] ****",
((lpszMessageClass == NULL) ? "(null)" : lpszMessageClass));

hr = HrNonDeliverAllRecipList(
lpEnvelope,
&lpReportAdrList);

if(FAILED(hr))
{
goto cleanup;
}

// Get the attachment in the envelope
hr = MAPICALL(lpEnvelope)->OpenAttach(
lpEnvelope,
0,
NULL,
MAPI_MODIFY,
&lpAttach);

if((FAILED(hr)) && (hr != MAPI_E_NOT_FOUND))
{
goto cleanup;
}

if(hr == MAPI_E_NOT_FOUND)
{
//
// Message does not have an attachment.
//

HasContent = FALSE;
lpAttach = NULL;
}

lpSubjectMessage = NULL;

if(HasContent == TRUE)
{
// Open a message interface on the attachment
hr = MAPICALL(lpAttach)->OpenProperty(
lpAttach,
PR_ATTACH_DATA_OBJ,
(LPIID)&IID_IMessage,
0,
MAPI_DEFERRED_ERRORS|MAPI_MODIFY,
(LPUNKNOWN *)&lpMessage);

if(FAILED(hr))
{
goto cleanup;
}

lpSubjectMessage = lpMessage;
}
else
{
lpSubjectMessage = lpEnvelope;
}

//
// Create a non delivery report in MTS-OUT
//

if(lpSubjectMessage != NULL)
{
hr = HrCreateNonDeliveryReport(
TRUE,
lpAdrBook,
lpMtsOutFolder,
lpSubjectMessage,
lpReportAdrList,
&lpReportEnvelope);

if(FAILED(hr))
{
;
}
else
{
HANDLE hNewMailEvent = GetGWNewMailEvent();

if((hNewMailEvent != NULL) && (!SetEvent(hNewMailEvent)))
{
hr = HR_LOG(E_FAIL);
}
}
}

cleanup:

ULRELEASE(lpReportEnvelope);

ULRELEASE(lpMessage);

FREEPADRLIST(lpReportAdrList);

RETURN(hr);
}

//$--ProcessMtsIn---------------------------------------------------------------
// Process messages in MTS-IN.
// -----------------------------------------------------------------------------
DWORD ProcessMtsIn( // RETURNS: zero
IN LPVOID lpParameter) // parameter
{
HRESULT hr = NOERROR;
HRESULT hrT = NOERROR;
ULONG i = 0;
ULONG cRows = 0;

LPMESSAGE lpEnvelope = NULL;

ULONG cbMessageClass = 0;
LPTSTR lpszMessageClass = NULL;

LPSTREAM lpStream = NULL;
TCHAR rgchFileName[MAX_PATH+1] = {0};

DWORD dwStartProcessingTime = 0;

LPADRBOOK lpAdrBook = NULL;
LPABCONT lpGalABCont = NULL;
ULONG ulObjType = 0;

SPropTagArray sptExcludeNone = {0};
LPSTnefProblemArray lptpa = NULL;

LPWIN32_FIND_DATA rgFindData = NULL;
LPWIN32_FIND_DATA lpFindData = NULL;

EDKCNVRES crRes = GCR_OK;

//
// Declare an environment for the conversion.
//

EDKCNVENV envTmp =
{
1,

lpszInConverterW, 
(LHANDLE)NULL,
NULL,
NULL,
NULL
};

CONV_OPTIONS sConvOptions =
{
FALSE, // attach TNEF encapsulation
NULL // address type
};

const LPCWSTR pszMessageClassW = L"ENVELOPE.IPM";

PVOID pvConvInstance = NULL;

LPIDITEM lpIdItem = NULL;

DEBUGPUBLIC("ProcessMtsIn()\n");

//performance code

// Initialize conversion engine instance data.
hr = HrConvInitInstance(hEventLog, &pvConvInstance);

if(FAILED(hr))
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}

cRows = GetGWFindDataSize(lpParameter);

rgFindData = GetGWFindData(lpParameter);

lpAdrBook = GetAdrBookPtr();

lpGalABCont = GetGWGAL();


for(i = 0; i < cRows; i++)
{
dwStartProcessingTime = GetTickCount();

//------------------------------------------------------------------------------
// Build file name of incoming message

lpFindData = &rgFindData[i];

lstrcpy(rgchFileName, lpszInDirectory);
lstrcat(rgchFileName, lpFindData->cFileName);

//------------------------------------------------------------------------------

// Adding file to the "being processed" list!
// Prevents another thread from processing this file.
hr = HrAddIdItem(&InboundIdList, rgchFileName, &lpIdItem);

if(hr == EDK_E_ALREADY_EXISTS)
{
//
// Don't process this message. It is already being processed
// by another thread.
//

continue;
}

if(FAILED(hr))
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}

//------------------------------------------------------------------------------

// Open a buffered stream on the input file.
hrT = OpenStreamOnFile(
MAPIAllocateBuffer,
MAPIFreeBuffer,
STGM_READ | STGM_SHARE_EXCLUSIVE,// stream interface flags
rgchFileName,
NULL,
&lpStream);

if(FAILED(hrT))
{
// Temporarily can't access this file.
// We MUST remove it from the being processed list, since
// this thread added it, but now can't continue to process it.
goto SKIP;
}

lpEnvelope = NULL;

hrT = MAPICALL(lpMtsInFolder)->CreateMessage(
lpMtsInFolder,
NULL,
MAPI_DEFERRED_ERRORS,
&lpEnvelope);

if(FAILED(hrT))
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}

//------------------------------------------------------------------------------

// Initialize the conversion environment structure

sConvOptions.lpszAddressType = lpszAddressType;

envTmp.lphSession = (LHANDLE)lpSession;
envTmp.lpAB = lpAdrBook;
envTmp.pGatewayDefined = &sConvOptions;

//
// Perform the conversion.
//

hr = HrConvConvert(
pvConvInstance, // conversion instance pointer
&envTmp, // environment structure pointer
pszMessageClassW, // dummy message class
lpStream, // stream to read from
lpEnvelope, // message to convert to
&crRes); // result pointer

if(FAILED(hr) || crRes != GCR_OK)
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}

//------------------------------------------------------------------------------

// Get the message class

MAPIFREEBUFFER(lpszMessageClass);

cbMessageClass = 0;
lpszMessageClass = NULL;

hr = HrMAPIGetPropString(
(LPMAPIPROP)lpEnvelope,
PR_MESSAGE_CLASS,
&cbMessageClass,
(void **)&lpszMessageClass);

if(FAILED(hr))
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}

MODULE_WARNING1(
"**** [IN ] Processing message of class [%s] ****",
((lpszMessageClass == NULL) ? "(null)" : lpszMessageClass));

//
// Check for inconsistencies in MTS-ID & external trace information.
//

hr = HrCheckExternalTraceInformation(lpEnvelope);

if(FAILED(hr))
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}

// Process the message

if(_tcsstr(lpszMessageClass, TEXT("ENVELOPE.IPM")) != NULL)
{
hr = HrMAPISetPropBoolean(
(LPMAPIPROP)lpEnvelope,
PR_ORIGINATOR_NON_DELIVERY_REPORT_REQUESTED,
TRUE);

if(FAILED(hr))
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}

hr = HrMAPISetPropBoolean(
(LPMAPIPROP)lpEnvelope,
PR_NON_RECEIPT_NOTIFICATION_REQUESTED,
TRUE);

if(FAILED(hr))
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}

hr = HrImportMessage(
lpAdrBook,
lpGalABCont,
FALSE,
TRUE,
dwStartProcessingTime,
lpEnvelope);
}
else if((_tcsstr(lpszMessageClass, TEXT("REPORT.IPM")) != NULL) &&
(_tcsstr(lpszMessageClass, TEXT(".NDR")) != NULL))
{
hr = HrMAPISetPropBoolean(
(LPMAPIPROP)lpEnvelope,
PR_ORIGINATOR_NON_DELIVERY_REPORT_REQUESTED,
TRUE);

if(FAILED(hr))
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}

hr = HrDeleteSenderProps(
lpEnvelope);

if(FAILED(hr))
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}

hr = HrImportMessage(
lpAdrBook,
lpGalABCont,
TRUE,
FALSE,
dwStartProcessingTime,
lpEnvelope);
}
else if((_tcsstr(lpszMessageClass, TEXT("REPORT.IPM")) != NULL) &&
(_tcsstr(lpszMessageClass, TEXT(".DR")) != NULL))
{
hr = HrMAPISetPropBoolean(
(LPMAPIPROP)lpEnvelope,
PR_ORIGINATOR_DELIVERY_REPORT_REQUESTED,
TRUE);

if(FAILED(hr))
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}

hr = HrDeleteSenderProps(
lpEnvelope);

if(FAILED(hr))
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}

hr = HrImportMessage(
lpAdrBook,
lpGalABCont,
TRUE,
FALSE,
dwStartProcessingTime,
lpEnvelope);
}
else if((_tcsstr(lpszMessageClass, TEXT("REPORT.IPM")) != NULL) &&
(_tcsstr(lpszMessageClass, TEXT(".IPNNRN")) != NULL))
{
hr = HrMAPISetPropBoolean(
(LPMAPIPROP)lpEnvelope,
PR_NON_RECEIPT_NOTIFICATION_REQUESTED,
TRUE);

if(FAILED(hr))
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}

hr = HrImportMessage(
lpAdrBook,
lpGalABCont,
FALSE,
FALSE,
dwStartProcessingTime,
lpEnvelope);
}
else if((_tcsstr(lpszMessageClass, TEXT("REPORT.IPM")) != NULL) &&
(_tcsstr(lpszMessageClass, TEXT(".IPNRN")) != NULL))
{
hr = HrMAPISetPropBoolean(
(LPMAPIPROP)lpEnvelope,
PR_READ_RECEIPT_REQUESTED,
TRUE);

if(FAILED(hr))
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}

hr = HrImportMessage(
lpAdrBook,
lpGalABCont,
FALSE,
FALSE,
dwStartProcessingTime,
lpEnvelope);
}
else
{
hr = HrNonDeliverMtsInMessage(
lpszMessageClass,
lpEnvelope);

if(FAILED(hr))
{
; // failed to non-deliver message
}
}

if(FAILED(hr))
{
MODULE_ERROR1(
"**** [IN ] Error while processing message of class [%s] ****",
((lpszMessageClass == NULL) ? "(null)" : lpszMessageClass));

//
// This message will be moved to the archive directory.
//

ULRELEASE(lpStream);
MAPIFREEBUFFER(lpszMessageClass);
ULRELEASE(lpEnvelope);
continue;
}

ULRELEASE(lpStream);

MAPIFREEBUFFER(lpszMessageClass);

ULRELEASE(lpEnvelope);

//performance code

if(!DeleteFile(rgchFileName))
{
hr = HR_LOG(E_FAIL);
}

//------------------------------------------------------------------------------

SKIP: // can't process this file now, so remove it from the "being processed" list.

hr = HrRemoveIdItem(&InboundIdList, lpIdItem);

if(FAILED(hr))
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}

//------------------------------------------------------------------------------
}

cleanup:

ULRELEASE(lpStream);

MAPIFREEBUFFER(lpszMessageClass);

ULRELEASE(lpEnvelope);

if(pvConvInstance != NULL)
{
// De-initialize conversion engine instance data.
(VOID)HrConvUninitInstance(pvConvInstance);
pvConvInstance = NULL;
}

return(0);
}

//$--HrExportMessage------------------------------------------------------------
// Process an IPM/IPN in MTS-OUT.
// -----------------------------------------------------------------------------
HRESULT HrExportMessage( // RETURNS: return code
IN LPADRBOOK lpAdrBook, // pointer to address book
IN BOOL fIgnoreRespValue, // ignore responsibility value
IN BOOL fSendNDR, // TRUE if NDRs should be generated
IN DWORD dwStartProcessingTime, // start processing time
IN OUT LPMESSAGE lpEnvelope) // pointer to envelope
{
HRESULT hr = NOERROR;
HRESULT hrT = NOERROR;

LPMESSAGE lpMessage = NULL;
LPATTACH lpAttach = NULL;

ULONG cEnvelopeValues = 0;
LPSPropValue lpEnvelopeProps = NULL;
ULONG cMessageValues = 0;
LPSPropValue lpMessageProps = NULL;

LPADRLIST lpOriginalEnvelopeAdrList = NULL;
LPADRLIST lpOriginalMessageAdrList = NULL;

LPADRLIST lpEnvelopeAdrList = NULL;
LPADRLIST lpMessageAdrList = NULL;

LPADRLIST lpEnvelope_NDR_AdrList = NULL;
LPADRLIST lpMessage_NDR_AdrList = NULL;

DWORD dwEndProcessingTime = 0;
DWORD dwTotalProcessingTime = 0;
DWORD dwSleepProcessingTime = 0;

ULONG cbeid = 0;
LPENTRYID lpeid = NULL;

ULONG cEnvelopeMesgAddr = 0;
ULONG cEnvelopeReplyAddr = 0;
ULONG cEnvelopeRecipAddr = 0;
LPADRLIST lpEnvelopeAllAdrList = NULL;
LPADRLIST lpMappedEnvelopeAdrList = NULL;

ULONG cMessageMesgAddr = 0;
ULONG cMessageReplyAddr = 0;
ULONG cMessageRecipAddr = 0;
LPADRLIST lpMessageAllAdrList = NULL;
LPADRLIST lpMappedMessageAdrList = NULL;

BOOL HasContent = TRUE;

LPSPropProblemArray lpProblems = NULL;

DEBUGPUBLIC("HrExportMessage()\n");

// Get the attachment in the envelope
hrT = MAPICALL(lpEnvelope)->OpenAttach(
lpEnvelope,
0,
NULL,
MAPI_MODIFY,
&lpAttach);

if((FAILED(hrT)) && (hrT != MAPI_E_NOT_FOUND))
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}

if(hrT == MAPI_E_NOT_FOUND)
{
//
// Message does not have an attachment.
//

HasContent = FALSE;
lpAttach = NULL;
}

if(HasContent == TRUE)
{
// Open a message interface on the attachment
hrT = MAPICALL(lpAttach)->OpenProperty(
lpAttach,
PR_ATTACH_DATA_OBJ,
(LPIID)&IID_IMessage,
0,
MAPI_DEFERRED_ERRORS|MAPI_MODIFY,
(LPUNKNOWN *)&lpMessage);

if(FAILED(hrT))
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}
}

//------------------------------------------------------------------------------

//
// Map envelope addresses
//

hr = HrExpandMessageAddressList(
lpEnvelope,
&cEnvelopeMesgAddr,
&cEnvelopeReplyAddr,
&cEnvelopeRecipAddr,
&lpOriginalEnvelopeAdrList,
&lpEnvelopeAllAdrList);

if(FAILED(hr))
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}

hr = HrMapAddrToProxy(
lpAdrBook,
lpszAddressType,
lpEnvelopeAllAdrList);

if(FAILED(hr))
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}

hr = HrMapGatewayAddrToProxy(
lpAdrBook,
lpszAddressType,
lpEnvelopeAllAdrList);

if(FAILED(hr))
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}

hr = HrCollapseMessageAddressList(
lpEnvelope,
cEnvelopeMesgAddr,
cEnvelopeReplyAddr,
cEnvelopeRecipAddr,
lpEnvelopeAllAdrList,
&cEnvelopeValues,
&lpEnvelopeProps,
&lpMappedEnvelopeAdrList);

if(FAILED(hr))
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}

FREEPADRLIST(lpEnvelopeAllAdrList);

if(HasContent == TRUE)
{
//
// Map message addresses
//

hr = HrExpandMessageAddressList(
lpMessage,
&cMessageMesgAddr,
&cMessageReplyAddr,
&cMessageRecipAddr,
&lpOriginalMessageAdrList,
&lpMessageAllAdrList);

if(FAILED(hr))
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}

hr = HrMapAddrToProxy(
lpAdrBook,
lpszAddressType,
lpMessageAllAdrList);

if(FAILED(hr))
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}

hr = HrMapGatewayAddrToProxy(
lpAdrBook,
lpszAddressType,
lpMessageAllAdrList);

if(FAILED(hr))
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}

hr = HrCollapseMessageAddressList(
lpMessage,
cMessageMesgAddr,
cMessageReplyAddr,
cMessageRecipAddr,
lpMessageAllAdrList,
&cMessageValues,
&lpMessageProps,
&lpMappedMessageAdrList);

if(FAILED(hr))
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}

FREEPADRLIST(lpMessageAllAdrList);
}

//------------------------------------------------------------------------------

hr = HrMapRecipAddrToProxy(
lpAdrBook,
TRUE,
fIgnoreRespValue,
lpszAddressType,
NULL,
lpOriginalEnvelopeAdrList,
lpMappedEnvelopeAdrList,
NULL,
NULL,
lpEnvelope,
&lpEnvelopeAdrList,
&lpEnvelope_NDR_AdrList);

if(FAILED(hr))
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}

if(HasContent == TRUE)
{
hr = HrMapRecipAddrToProxy(
lpAdrBook,
FALSE,
fIgnoreRespValue,
lpszAddressType,
lpOriginalEnvelopeAdrList,
lpOriginalMessageAdrList,
lpMappedMessageAdrList,
lpEnvelopeAdrList,
lpEnvelope_NDR_AdrList,
lpMessage,
&lpMessageAdrList,
&lpMessage_NDR_AdrList);

FREEPADRLIST(lpOriginalEnvelopeAdrList);

FREEPADRLIST(lpOriginalMessageAdrList);

FREEPADRLIST(lpMessage_NDR_AdrList);

if(FAILED(hr))
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}
}

// Non-deliver any recipients that could not be mapped.

if((lpEnvelope_NDR_AdrList != NULL) &&
(lpEnvelope_NDR_AdrList->cEntries != 0) &&
(fSendNDR == TRUE))
{
LPMESSAGE lpReportEnvelope = NULL;

//
// Clear row IDs for envelope NDR address list.
//

hr = HrDeleteAddressListProperty(
PR_ROWID,
(LPADRLIST)lpEnvelope_NDR_AdrList);

if(FAILED(hr))
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}

//
// Create a non delivery report in MTS-IN
//

hr = HrCreateNonDeliveryReport(
FALSE,
lpAdrBook,
lpMtsInFolder,
lpMessage,
lpEnvelope_NDR_AdrList,
&lpReportEnvelope);

if(FAILED(hr))
{
goto cleanup;
}

hr = HrMAPISetPropBoolean(
(LPMAPIPROP)lpReportEnvelope,
PR_DELETE_AFTER_SUBMIT,
TRUE);

if(FAILED(hr))
{
hr = HR_LOG(E_FAIL);

ULRELEASE(lpReportEnvelope);

goto cleanup;
}

// Submit message
hrT = MAPICALL(lpReportEnvelope)->SubmitMessage(lpReportEnvelope, FORCE_SUBMIT);

if(FAILED(hrT))
{
hrT = HR_LOG(hrT);
}

ULRELEASE(lpReportEnvelope);
}

FREEPADRLIST(lpEnvelope_NDR_AdrList);

if((lpEnvelopeAdrList == NULL) || (lpEnvelopeAdrList->cEntries == 0))
{
FREEPADRLIST(lpEnvelopeAdrList);

hr = HR_LOG(E_FAIL);
goto cleanup;
}

if(HasContent == TRUE)
{
if((lpMessageAdrList == NULL) || (lpMessageAdrList->cEntries == 0))
{
FREEPADRLIST(lpMessageAdrList);

hr = HR_LOG(E_FAIL);
goto cleanup;
}
}

//------------------------------------------------------------------------------

// Fix up recipient numbers
hr = HrFixUpRecipientNumbers(lpEnvelopeAdrList, lpMessageAdrList);

if(FAILED(hr))
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}

//------------------------------------------------------------------------------

hrT = MAPICALL(lpEnvelope)->SetProps(
lpEnvelope,
cEnvelopeValues,
lpEnvelopeProps,
&lpProblems);

if(FAILED(hrT))
{
lpProblems = NULL;

hr = HR_LOG(E_FAIL);
goto cleanup;
}

DUMPPROPPROBLEMS(lpProblems);
MAPIFREEBUFFER(lpProblems);

if(HasContent == TRUE)
{
hrT = MAPICALL(lpMessage)->SetProps(
lpMessage,
cMessageValues,
lpMessageProps,
&lpProblems);

if(FAILED(hrT))
{
lpProblems = NULL;

hr = HR_LOG(E_FAIL);
goto cleanup;
}

DUMPPROPPROBLEMS(lpProblems);
MAPIFREEBUFFER(lpProblems);
}

//------------------------------------------------------------------------------

// Set envelope recipients
hrT = MAPICALL(lpEnvelope)->ModifyRecipients(
lpEnvelope,
0,
lpEnvelopeAdrList);

if(FAILED(hrT))
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}

if(HasContent == TRUE)
{
// Set message recipients
hrT = MAPICALL(lpMessage)->ModifyRecipients(
lpMessage,
0,
lpMessageAdrList);

if(FAILED(hrT))
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}
}

//------------------------------------------------------------------------------

if(HasContent == TRUE)
{
// Save changes to the message
hrT = MAPICALL(lpMessage)->SaveChanges(
lpMessage,
MAPI_DEFERRED_ERRORS|FORCE_SAVE);

if(FAILED(hrT))
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}

// Save changes to attachment object
hrT = MAPICALL(lpAttach)->SaveChanges(
lpAttach,
MAPI_DEFERRED_ERRORS|FORCE_SAVE);

if(FAILED(hrT))
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}

ULRELEASE(lpMessage);

ULRELEASE(lpAttach);
}

// Save changes to the envelope
hrT = MAPICALL(lpEnvelope)->SaveChanges(
lpEnvelope,
MAPI_DEFERRED_ERRORS|KEEP_OPEN_READWRITE);

if(FAILED(hrT))
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}

//----------------------------------------------------------------------
dwEndProcessingTime = GetTickCount();

dwTotalProcessingTime = dwEndProcessingTime - dwStartProcessingTime;

dwSleepProcessingTime =
((dwTotalProcessingTime < dwOutSleepInterval) ?
(dwOutSleepInterval - dwTotalProcessingTime) : 0);

if(dwSleepProcessingTime > 0)
{
Sleep(dwSleepProcessingTime);
}
//----------------------------------------------------------------------

cleanup:

MAPIFREEBUFFER(lpProblems);

MAPIFREEBUFFER(lpeid);

FREEPADRLIST(lpOriginalEnvelopeAdrList);

FREEPADRLIST(lpOriginalMessageAdrList);

FREEPADRLIST(lpEnvelopeAdrList);

FREEPADRLIST(lpMessageAdrList);

FREEPADRLIST(lpEnvelope_NDR_AdrList);

FREEPADRLIST(lpMessage_NDR_AdrList);

FREEPADRLIST(lpEnvelopeAllAdrList);

FREEPADRLIST(lpMessageAllAdrList);

FREEPADRLIST(lpMappedEnvelopeAdrList);
FREEPADRLIST(lpMappedMessageAdrList);

MAPIFREEBUFFER(lpEnvelopeProps);
MAPIFREEBUFFER(lpMessageProps);

ULRELEASE(lpMessage);

ULRELEASE(lpAttach);

RETURN(hr);
}

//$--HrConvertMtsOut------------------------------------------------------------
// Convert a message in MTS-OUT.
// -----------------------------------------------------------------------------
HRESULT HrConvertMtsOut( // RETURNS: return code
IN PVOID pvConvInstance, // converter instance
IN LPADRBOOK lpAdrBook, // pointer to address book
IN LPTSTR lpszMessageClass, // message class
IN LPMESSAGE lpMessage) // message
{
HRESULT hr = NOERROR;
HRESULT hrT = NOERROR;
LPSRowSet lpRows = NULL;
LPADRLIST lpAdrList = NULL;
LPMAPITABLE lpTable = NULL;
BOOL fFileCreated = FALSE; // TRUE if output file created

ULONG cValues = 0;
LPSPropValue lpProps = NULL;
LPSPropValue lpPropT = NULL;

BOOL IsMapiRecip = 0;
LPTSTR lpszAddress = NULL;

LPADRLIST lpMapiAdrList = NULL;
LPADRLIST lpNonMapiAdrList = NULL;

ULONG i = 0;

LPSTREAM lpStream = NULL;
TCHAR rgchOutFileName[MAX_PATH+1] = {0};

EDKCNVRES crRes = GCR_OK;

//
// Declare an environment for the conversion.
//

EDKCNVENV envTmp =
{
1,
lpszOutConverterW,
(LHANDLE)NULL,
NULL,
NULL,
NULL
};

CONV_OPTIONS sConvOptions =
{
FALSE, // attach TNEF encapsulation
NULL // address type
};

ULONG cbMessageClass = 0;
LPWSTR lpszMessageClassW = NULL;

ULONG iMapi = 0;
ULONG iNonMapi = 0;

SizedSPropTagArray(1, rgPropTags) =
{
1,
{
PR_REPORT_DESTINATION_ENTRYID,
}
};

// stream interface flags
const ULONGulFlags=STGM_CREATE | STGM_READWRITE |
SOF_UNIQUEFILENAME | STGM_SHARE_EXCLUSIVE;

DEBUGPUBLIC("HrConvertMtsOut()\n");

if(_tcsstr(lpszMessageClass, TEXT("ENVELOPE.IPM")) != NULL)
{
//
// Get the recipient table for the message
//

hrT = MAPICALL(lpMessage)->GetRecipientTable(
lpMessage,
MAPI_DEFERRED_ERRORS,
&lpTable);

if(FAILED(hrT))
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}

//
// Query all the rows
//

hr = HrQueryAllRows(
lpTable,
NULL,
NULL,
NULL,
0,
&lpRows);

if(FAILED(hr))
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}

//
// Divide recipient list into MAPI and non-MAPI recipients
//

lpAdrList = (LPADRLIST)lpRows;

hr = HrMAPICreateSizedAddressList(
lpAdrList->cEntries,
&lpMapiAdrList);

if(FAILED(hr))
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}

hr = HrMAPICreateSizedAddressList(
lpAdrList->cEntries,
&lpNonMapiAdrList);

if(FAILED(hr))
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}

for(i = 0; i < lpAdrList->cEntries; i++)
{
cValues = lpAdrList->aEntries[i].cValues;
lpProps = lpAdrList->aEntries[i].rgPropVals;

lpPropT = LpValFindProp(PR_SEND_RICH_INFO, cValues, lpProps);

if(lpPropT != NULL)
{
IsMapiRecip = lpPropT->Value.b;
}
else
{
IsMapiRecip = FALSE;
}

if(IsMapiRecip == TRUE)
{
hr = HrMAPISetAddressList(
iMapi,
cValues,
lpProps,
lpMapiAdrList);

iMapi++;

if(FAILED(hr))
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}
}
else
{
hr = HrMAPISetAddressList(
iNonMapi,
cValues,
lpProps,
lpNonMapiAdrList);

iNonMapi++;

if(FAILED(hr))
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}
}
} // end for

//
// Convert message for MAPI recipients
//


if(iMapi > 0)
{
// Set envelope recipients
hrT = MAPICALL(lpMessage)->ModifyRecipients(
lpMessage,
0,
lpMapiAdrList);

if(FAILED(hrT))
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}

hrT = MAPICALL(lpMessage)->SaveChanges(
lpMessage,
KEEP_OPEN_READWRITE);

if(FAILED(hrT))
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}

//------------------------------------------------------------------------------

lstrcpy(rgchOutFileName, lpszOutDirectory);

// Open a buffered stream on our SGW*.TMP output file.
hrT = OpenStreamOnFile(
MAPIAllocateBuffer,
MAPIFreeBuffer,
ulFlags,// stream interface flags
rgchOutFileName,
szFilePrefix,
&lpStream);

if(FAILED(hrT))
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}

fFileCreated = TRUE; // output file has been created

//------------------------------------------------------------------------------

// Get the message class

MAPIFREEBUFFER(lpszMessageClassW);

cbMessageClass = 0;
lpszMessageClassW = NULL;

hr = HrMAPIGetPropString(
(LPMAPIPROP)lpMessage,
PR_MESSAGE_CLASS_W,
&cbMessageClass,
(void **)&lpszMessageClassW);

if(FAILED(hr))
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}

// Initialize the conversion environment structure

sConvOptions.fTnefEncode = TRUE;
sConvOptions.lpszAddressType = lpszAddressType;

envTmp.lphSession = (LHANDLE)lpSession;
envTmp.lpAB = lpAdrBook;
envTmp.pGatewayDefined = &sConvOptions;

//
// Perform the conversion.
//

hr = HrConvConvert(
pvConvInstance, // conversion instance pointer
&envTmp, // environment structure pointer
lpszMessageClassW, // message class
lpMessage, // message to convert from
lpStream, // stream to read to
&crRes); // result pointer

if(FAILED(hr) || crRes != GCR_OK)
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}

//------------------------------------------------------------------------------

ULRELEASE(lpStream);

//
// Finished processing message
//

{
BOOL fT = FALSE;

fT = SetFileAttributes(rgchOutFileName, FILE_ATTRIBUTE_NORMAL);

if(fT == FALSE)
{
hrT = HR_LOG(E_FAIL);
}
}
} // end if MAPI recipients

//
// Convert message for non-MAPI recipients
//

if(iNonMapi > 0)
{
// Set envelope recipients
hrT = MAPICALL(lpMessage)->ModifyRecipients(
lpMessage,
0,
lpNonMapiAdrList);

if(FAILED(hrT))
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}

hrT = MAPICALL(lpMessage)->SaveChanges(
lpMessage,
KEEP_OPEN_READWRITE);

if(FAILED(hrT))
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}

//------------------------------------------------------------------------------

lstrcpy(rgchOutFileName, lpszOutDirectory);

hrT = OpenStreamOnFile(
MAPIAllocateBuffer,
MAPIFreeBuffer,
STGM_CREATE | STGM_READWRITE | SOF_UNIQUEFILENAME,
rgchOutFileName,
szFilePrefix,
&lpStream);

if(FAILED(hrT))
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}

fFileCreated = TRUE; // output file has been created

//------------------------------------------------------------------------------

// Get the message class

MAPIFREEBUFFER(lpszMessageClassW);

cbMessageClass = 0;
lpszMessageClassW = NULL;

hr = HrMAPIGetPropString(
(LPMAPIPROP)lpMessage,
PR_MESSAGE_CLASS_W,
&cbMessageClass,
(void **)&lpszMessageClassW);

if(FAILED(hr))
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}

// Initialize the conversion environment structure

sConvOptions.fTnefEncode = FALSE;
sConvOptions.lpszAddressType = lpszAddressType;

envTmp.lphSession = (LHANDLE)lpSession;
envTmp.lpAB = lpAdrBook;
envTmp.pGatewayDefined = &sConvOptions;

//
// Perform the conversion.
//

hr = HrConvConvert(
pvConvInstance, // conversion instance pointer
&envTmp, // environment structure pointer
lpszMessageClassW, // message class
lpMessage, // message to convert from
lpStream, // stream to read to
&crRes); // result pointer

if(FAILED(hr) || crRes != GCR_OK)
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}

//------------------------------------------------------------------------------

ULRELEASE(lpStream);

//
// Finished processing message
//

{
BOOL fT = FALSE;

fT = SetFileAttributes(rgchOutFileName, FILE_ATTRIBUTE_NORMAL);

if(fT == FALSE)
{
hrT = HR_LOG(E_FAIL);
}
}
} // end if non-MAPI recipients
} // end if Interpersonal message

else if(_tcsstr(lpszMessageClass, TEXT("REPORT.IPM")) != NULL)
{
//
// Determine if the report/notification recipient is a MAPI
// or a non-MAPI recipient.
//

if((_tcsstr(lpszMessageClass, TEXT(".NDR")) != NULL) ||
(_tcsstr(lpszMessageClass, TEXT(".DR")) != NULL))
{
//
// Get destination of non-delivery/delivery report.
//

hr = MAPICALL(lpMessage)->GetProps(
lpMessage,
(SPropTagArray *)&rgPropTags,
fMapiUnicode,
&cValues,
&lpProps);

if(FAILED(hr))
{
lpProps = NULL;

hr = HR_LOG(E_FAIL);
goto cleanup;
}

hr = HrGWResolveProxy(
lpAdrBook,
lpProps->Value.bin.cb,
(LPENTRYID)lpProps->Value.bin.lpb,
lpszAddressType,
&IsMapiRecip,
&lpszAddress);

MAPIFREEBUFFER(lpProps);

if(FAILED(hr))
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}
}
else if((_tcsstr(lpszMessageClass, TEXT(".IPNNRN")) != NULL) ||
(_tcsstr(lpszMessageClass, TEXT(".IPNRN")) != NULL))
{
//
// Get the recipient table for the non-read/read notification.
//

hrT = MAPICALL(lpMessage)->GetRecipientTable(
lpMessage,
MAPI_DEFERRED_ERRORS,
&lpTable);

if(FAILED(hrT))
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}

//
// Query all the rows
//

hr = HrQueryAllRows(
lpTable,
NULL,
NULL,
NULL,
0,
&lpRows);

if(FAILED(hr))
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}

lpAdrList = (LPADRLIST)lpRows;
cValues = lpAdrList->aEntries[i].cValues;
lpProps = lpAdrList->aEntries[i].rgPropVals;

lpPropT = LpValFindProp(PR_SEND_RICH_INFO, cValues, lpProps);

if(lpPropT != NULL)
{
IsMapiRecip = lpPropT->Value.b;
}
else
{
IsMapiRecip = FALSE;
}

FREEPADRLIST(lpAdrList);
}
else
{
IsMapiRecip = FALSE;
}

//------------------------------------------------------------------------------

lstrcpy(rgchOutFileName, lpszOutDirectory);

hrT = OpenStreamOnFile(
MAPIAllocateBuffer,
MAPIFreeBuffer,
STGM_CREATE | STGM_READWRITE | SOF_UNIQUEFILENAME,
rgchOutFileName,
szFilePrefix,
&lpStream);

if(FAILED(hrT))
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}

fFileCreated = TRUE; // output file has been created

//------------------------------------------------------------------------------

// Get the message class

MAPIFREEBUFFER(lpszMessageClassW);

cbMessageClass = 0;
lpszMessageClassW = NULL;

hr = HrMAPIGetPropString(
(LPMAPIPROP)lpMessage,
PR_MESSAGE_CLASS_W,
&cbMessageClass,
(void **)&lpszMessageClassW);

if(FAILED(hr))
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}

// Initialize the conversion environment structure

sConvOptions.fTnefEncode = IsMapiRecip;
sConvOptions.lpszAddressType = lpszAddressType;

envTmp.lphSession = (LHANDLE)lpSession;
envTmp.lpAB = lpAdrBook;
envTmp.pGatewayDefined = &sConvOptions;

//
// Perform the conversion.
//

hr = HrConvConvert(
pvConvInstance, // conversion instance pointer
&envTmp, // environment structure pointer
lpszMessageClassW, // message class
lpMessage, // message to convert from
lpStream, // stream to read to
&crRes); // result pointer

if(FAILED(hr) || crRes != GCR_OK)
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}

//------------------------------------------------------------------------------

ULRELEASE(lpStream);

//
// Finished processing message
//

{
BOOL fT = FALSE;

fT = SetFileAttributes(rgchOutFileName, FILE_ATTRIBUTE_NORMAL);

if(fT == FALSE)
{
hrT = HR_LOG(E_FAIL);
}
}
} // end if report

else
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}

cleanup:

if ( FAILED(hr) )
{
// delete the output file created, if any.
if ( fFileCreated == TRUE )
{
// Must release the stream first!
ULRELEASE(lpStream);

(VOID)DeleteFile(rgchOutFileName);
}
}

MAPIFREEBUFFER(lpszAddress);
MAPIFREEBUFFER(lpszMessageClassW);

FREEPADRLIST(lpAdrList); // also frees lpRows

FREEPADRLIST(lpMapiAdrList);

FREEPADRLIST(lpNonMapiAdrList);

ULRELEASE(lpStream);

ULRELEASE(lpTable);

RETURN(hr);
}

//$--HrNonDeliverMtsOutMessage--------------------------------------------------
// Non-deliver a message in MTS-OUT.
// -----------------------------------------------------------------------------
HRESULT HrNonDeliverMtsOutMessage( // RETURNS: zero
IN LPTSTR lpszMessageClass, // message class
IN LPMESSAGE lpEnvelope) // envelope
{
HRESULT hr = NOERROR;
LPADRBOOK lpAdrBook = NULL;
LPMESSAGE lpMessage = NULL;
LPMESSAGE lpSubjectMessage = NULL;
LPMESSAGE lpReportEnvelope = NULL;
LPADRLIST lpReportAdrList = NULL;
LPATTACH lpAttach = NULL;
BOOL HasContent = TRUE;

DEBUGPUBLIC("HrNonDeliverMtsOutMessage()\n");

lpAdrBook = GetAdrBookPtr();

MODULE_ERROR1(
"**** [IN ] Unknown message class [%s] ****",
((lpszMessageClass == NULL) ? "(null)" : lpszMessageClass));

hr = HrNonDeliverAllRecipList(
lpEnvelope,
&lpReportAdrList);

if(FAILED(hr))
{
goto cleanup;
}

// Get the attachment in the envelope
hr = MAPICALL(lpEnvelope)->OpenAttach(
lpEnvelope,
0,
NULL,
MAPI_MODIFY,
&lpAttach);

if((FAILED(hr)) && (hr != MAPI_E_NOT_FOUND))
{
goto cleanup;
}

if(hr == MAPI_E_NOT_FOUND)
{
//
// Message does not have an attachment.
//

HasContent = FALSE;
lpAttach = NULL;
}

lpSubjectMessage = NULL;

if(HasContent == TRUE)
{
// Open a message interface on the attachment
hr = MAPICALL(lpAttach)->OpenProperty(
lpAttach,
PR_ATTACH_DATA_OBJ,
(LPIID)&IID_IMessage,
0,
MAPI_DEFERRED_ERRORS|MAPI_MODIFY,
(LPUNKNOWN *)&lpMessage);

if(FAILED(hr))
{
goto cleanup;
}

lpSubjectMessage = lpMessage;
}
else
{
lpSubjectMessage = lpEnvelope;
}

//
// Create a non delivery report in MTS-IN
//

if(lpSubjectMessage != NULL)
{
hr = HrCreateNonDeliveryReport(
FALSE,
lpAdrBook,
lpMtsInFolder,
lpSubjectMessage,
lpReportAdrList,
&lpReportEnvelope);

if(FAILED(hr))
{
goto cleanup;
}

hr = HrMAPISetPropBoolean(
(LPMAPIPROP)lpReportEnvelope,
PR_DELETE_AFTER_SUBMIT,
TRUE);

if(FAILED(hr))
{
goto cleanup;
}

// Submit message
hr = MAPICALL(lpReportEnvelope)->SubmitMessage(lpReportEnvelope, FORCE_SUBMIT);

if(FAILED(hr))
{
;
}
}

cleanup:

ULRELEASE(lpReportEnvelope);

ULRELEASE(lpMessage);

FREEPADRLIST(lpReportAdrList);

RETURN(hr);
}

//$--ProcessMtsOut--------------------------------------------------------------
// Process messages in MTS-OUT.
// -----------------------------------------------------------------------------
DWORD ProcessMtsOut( // RETURNS: zero
IN LPVOID lpParameter) // parameter
{
HRESULT hr = NOERROR;
HRESULT hrT = NOERROR;
SCODE sc = 0;
ULONG cbeid = 0;
LPENTRYID lpeid = NULL;
ULONG ulObjType = 0;
ULONG ulPropTag = 0;
ULONG cValues = 0;
ULONG i = 0;
ULONG j = 0;
ULONG cRows = 0;

LPMESSAGE lpEnvelope = NULL;

ULONG cbMessageClass = 0;
LPTSTR lpszMessageClass = NULL;

LPSPropValue lpProps = NULL;

LPSPropTagArray lpPropTagArray = NULL;

ULONG cValuesT = 0;
LPSPropValue lpPropsT = NULL;

DWORD dwStartProcessingTime = 0;

LPADRBOOK lpAdrBook = NULL;

ULONG cbMsgEid = 0;
LPENTRYID lpMsgEid = NULL;

SizedSPropTagArray(1, rgRecipPropTag) =
{
1,
{
PR_MESSAGE_RECIPIENTS
}
};

SizedSPropTagArray(1, rgRecordKeyPropTag) =
{
1,
{
PR_RECORD_KEY
}
};

ULONG cBytes = 0;
LPTSTR lpszRecordKey = 0;

PVOID pvConvInstance = NULL;

LPIDITEM lpIdItem = NULL;

DEBUGPUBLIC("ProcessMtsOut()\n");

//performance code

// Initialize conversion engine instance data.
hr = HrConvInitInstance(hEventLog, &pvConvInstance);

if(FAILED(hr))
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}

cRows = GetGWSRowSet(lpParameter)->cRows;

lpAdrBook = GetAdrBookPtr();


for(i = 0; i < cRows; i++)
{
dwStartProcessingTime = GetTickCount();

cValues = GetGWSRowSet(lpParameter)->aRow[i].cValues;

lpProps = GetGWSRowSet(lpParameter)->aRow[i].lpProps;

cbeid = lpProps[0].Value.bin.cb;
lpeid = (LPENTRYID)lpProps[0].Value.bin.lpb;

cbMsgEid = cbeid;
lpMsgEid = lpeid;

cValues = 0;
lpProps = NULL;

// Get the message in the MTS-OUT folder
hrT = MAPICALL(lpMtsOutFolder)->OpenEntry(
lpMtsOutFolder,
cbeid,
lpeid,
NULL,
MAPI_DEFERRED_ERRORS|MAPI_MODIFY,
&ulObjType,
(LPUNKNOWN FAR *)&lpEnvelope);

cbeid = 0;
lpeid = NULL;

if(FAILED(hrT))
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}

if(ulObjType != MAPI_MESSAGE)
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}

//------------------------------------------------------------------------------
// Get the message ID

MAPIFREEBUFFER(lpPropsT);
MAPIFREEBUFFER(lpszRecordKey);

cValuesT = 0;
lpPropsT = NULL;

hr = MAPICALL(lpEnvelope)->GetProps(
lpEnvelope,
(LPSPropTagArray)&rgRecordKeyPropTag,
fMapiUnicode,
&cValuesT,
&lpPropsT);

if(FAILED(hr))
{
goto cleanup;
}

if(lpPropsT[0].ulPropTag != PR_RECORD_KEY)
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}

if(lpPropsT[0].Value.bin.cb == 0)
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}

if(lpPropsT[0].Value.bin.lpb == NULL)
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}

cBytes = (lpPropsT[0].Value.bin.cb + sizeof(TCHAR)) * (2 * sizeof(TCHAR));

hr = MAPIAllocateBuffer(cBytes, (void **)&lpszRecordKey);

if(FAILED(hr))
{
goto cleanup;
}

HexFromBin(lpPropsT[0].Value.bin.lpb, lpPropsT[0].Value.bin.cb, lpszRecordKey);

MAPIFREEBUFFER(lpPropsT);

hr = HrAddIdItem(
&OutboundIdList,
lpszRecordKey,
&lpIdItem);

if(hr == EDK_E_ALREADY_EXISTS)
{
//
// Skip this message. It is already being processed
// by another thread.
//

MAPIFREEBUFFER(lpPropsT);
MAPIFREEBUFFER(lpszRecordKey);
ULRELEASE(lpEnvelope);
continue;
}

if(FAILED(hr))
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}

//------------------------------------------------------------------------------
// Get the message class

MAPIFREEBUFFER(lpszMessageClass);

cbMessageClass = 0;
lpszMessageClass = NULL;

hr = HrMAPIGetPropString(
(LPMAPIPROP)lpEnvelope,
PR_MESSAGE_CLASS,
&cbMessageClass,
(void **)&lpszMessageClass);

if(FAILED(hr))
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}

MODULE_WARNING1(
"**** [OUT] Processing message of class [%s] ****",
((lpszMessageClass == NULL) ? "(null)" : lpszMessageClass));

if(_tcsstr(lpszMessageClass, TEXT("ENVELOPE.IPM")) != NULL)
{
hr = HrExportMessage(
lpAdrBook,
FALSE,
TRUE,
dwStartProcessingTime,
lpEnvelope);
}
else if((_tcsstr(lpszMessageClass, TEXT("REPORT.IPM")) != NULL) &&
(_tcsstr(lpszMessageClass, TEXT(".NDR")) != NULL))
{
hr = HrExportMessage(
lpAdrBook,
TRUE,
FALSE,
dwStartProcessingTime,
lpEnvelope);
}
else if((_tcsstr(lpszMessageClass, TEXT("REPORT.IPM")) != NULL) &&
(_tcsstr(lpszMessageClass, TEXT(".DR")) != NULL))
{
hr = HrExportMessage(
lpAdrBook,
TRUE,
FALSE,
dwStartProcessingTime,
lpEnvelope);
}
else if((_tcsstr(lpszMessageClass, TEXT("REPORT.IPM")) != NULL) &&
(_tcsstr(lpszMessageClass, TEXT(".IPNNRN")) != NULL))
{
hr = HrExportMessage(
lpAdrBook,
FALSE,
FALSE,
dwStartProcessingTime,
lpEnvelope);
}
else if((_tcsstr(lpszMessageClass, TEXT("REPORT.IPM")) != NULL) &&
(_tcsstr(lpszMessageClass, TEXT(".IPNRN")) != NULL))
{
hr = HrExportMessage(
lpAdrBook,
FALSE,
FALSE,
dwStartProcessingTime,
lpEnvelope);
}
else
{
hr = HrNonDeliverMtsOutMessage(
lpszMessageClass,
lpEnvelope);

if(FAILED(hr))
{
; // failed to non-deliver message
}
}

if(FAILED(hr))
{
MODULE_ERROR1(
"**** [OUT] Error while processing message of class [%s] ****",
((lpszMessageClass == NULL) ? "(null)" : lpszMessageClass));

//
// This message will be moved to the archive folder.
//

MAPIFREEBUFFER(lpszMessageClass);
MAPIFREEBUFFER(lpPropsT);
MAPIFREEBUFFER(lpszRecordKey);
ULRELEASE(lpEnvelope);
continue;
}

//------------------------------------------------------------------------------
else
{
hr = HrConvertMtsOut(
pvConvInstance,
lpAdrBook,
lpszMessageClass,
lpEnvelope);

if(FAILED(hr))
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}
}
//------------------------------------------------------------------------------

ULRELEASE(lpEnvelope);

//performance code

hr = HrMAPIDeleteMessage(
lpMtsOutFolder,
cbMsgEid,
lpMsgEid);

if(FAILED(hr))
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}

//------------------------------------------------------------------------------

hr = HrRemoveIdItem(&OutboundIdList, lpIdItem);

if(FAILED(hr))
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}

//------------------------------------------------------------------------------

}

cleanup:

MAPIFREEBUFFER(lpPropsT);

MAPIFREEBUFFER(lpszRecordKey);

MAPIFREEBUFFER(lpszMessageClass);

ULRELEASE(lpEnvelope);

if(pvConvInstance != NULL)
{
// De-initialize conversion engine instance data.
(VOID)HrConvUninitInstance(pvConvInstance);
pvConvInstance = NULL;
}

return(0);
}

// $--AppendSlash----------------------------------------------------------
// This function will append a backslash to a pathname if one does not
// already exist.
// ------------------------------------------------------------------------
void AppendSlash ( // RETURNS: Nothing
IN OUT LPTSTR sz1) // pathname
{
LPTSTR sz2 = sz1;

while (*sz2) // Loop through each char until '\0'
{
sz1 = sz2;
sz2 = CharNext(sz1);
}

// Check there were no CharNext errors, then add a '\' if not there.
if (sz2 != sz1 + 1 || *sz1 != TEXT('\\'))
{
*sz2++ = TEXT('\\');
*sz2 = TEXT('\0');
}
}

//$--GWMain---------------------------------------------------------------------
// Start threads.
// -----------------------------------------------------------------------------
void GWMain(
void)
{
HRESULT hrT = NOERROR;
HRESULT hr = NOERROR;

EDK_SERVICE_CONTROL_T sc = 0;

LPMAPIPROP lpCurrentObject = NULL;
ULONG ulExtensionDataTag = 0;
ULONG cValues = 0;
LPSPropValue lpProps = NULL;
LPSBinary lpBlobArray = NULL;
ULONG cBlobArray = 0;
ULONG i = 0;
LPBYTE lpbBlob = NULL;
ULONG cbBlob = 0;
LPSPropValue lpUnpackedProps = NULL;
ULONG cUnpackedProps = 0;
LPTSTR lpszUnpackedName = NULL;
LPTSTR lpszDir = NULL;
ULONG cBytes = 0;
LPTSTR lpsz = NULL;

SizedSPropTagArray(1, rgPropTags) =
{
1,
{
0,
}
};

DEBUGPUBLIC("GWMain()\n");

//--------------------------------------------------------------------------

//
// Get a pointer to the current object
//

hr = HrOpenSessionObject(
lpSession,
&lpCurrentObject);

if(FAILED(hr))
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}

//
// Convert our MAPI Name ID to a property tag
//
hr = HrCfgPropertyTagFromNameId(
lpCurrentObject,
NM_EXTENSION_DATA,
&ulExtensionDataTag);

if(FAILED(hr))
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}

//
// Now get the properties we want from the site object
//

rgPropTags.aulPropTag[0] =
PROP_TAG(MV_FLAG|PT_BINARY, PROP_ID(ulExtensionDataTag));

hr = MAPICALL(lpCurrentObject)->GetProps(
lpCurrentObject,
(LPSPropTagArray)&rgPropTags,
fMapiUnicode,
&cValues,
&lpProps);

if(FAILED(hr))
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}

if(PROP_TYPE(lpProps[0].ulPropTag) == PT_ERROR)
{
hr = HR_LOG(E_FAIL);

goto cleanup;
}

lpBlobArray = lpProps->Value.MVbin.lpbin;
cBlobArray = lpProps->Value.MVbin.cValues;

for(i = 0; i < cBlobArray; i++)

{ 
if (!lstrcmpW(SGWBLOBNAMEW, (LPWSTR)lpBlobArray[i].lpb))
{
lpbBlob = lpBlobArray[i].lpb;
cbBlob = lpBlobArray[i].cb;
}
}

hr = HrCfgUnpackData(
cbBlob,
lpbBlob,
&lpszUnpackedName,
&cUnpackedProps,
&lpUnpackedProps);

if(FAILED(hr))
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}

//--------------------------------------------------------------------------

if(cUnpackedProps < 17)
{
hr = HR_LOG(E_FAIL);
goto cleanup;

}

lpszAddressType = lpUnpackedProps[IDX_ADDR_TYPE].Value.LPSZ;

lpszSysAdminName = lpUnpackedProps[IDX_DISP_NAME].Value.LPSZ;

lpszSysAdminAddr = lpUnpackedProps[IDX_EMAIL_ADDR].Value.LPSZ;

cInThreads = lpUnpackedProps[IDX_EDIT_THREADS_IN].Value.ul;

cInMessages = lpUnpackedProps[IDX_EDIT_MSGS_IN].Value.ul;

dwInSleepInterval = lpUnpackedProps[IDX_EDIT_SLEEP_IN].Value.ul;

lpszInDirectory = lpUnpackedProps[IDX_DIR_IN].Value.LPSZ;

dwInPollInterval = lpUnpackedProps[IDX_EDIT_POLLING_IN].Value.ul;

lpszInConverter = lpUnpackedProps[IDX_CONVERTER_IN].Value.LPSZ;

fInEnabled = lpUnpackedProps[IDX_CHECK_IN_BOUND].Value.b;

cOutThreads = lpUnpackedProps[IDX_EDIT_THREADS_OUT].Value.ul;

cOutMessages = lpUnpackedProps[IDX_EDIT_MSGS_OUT].Value.ul;

dwOutSleepInterval = lpUnpackedProps[IDX_EDIT_SLEEP_OUT].Value.ul;

lpszOutDirectory = lpUnpackedProps[IDX_DIR_OUT].Value.LPSZ;

dwOutPollInterval = lpUnpackedProps[IDX_EDIT_POLLING_OUT].Value.ul;

lpszOutConverter = lpUnpackedProps[IDX_CONVERTER_OUT].Value.LPSZ;

fOutEnabled = lpUnpackedProps[IDX_CHECK_OUT_BOUND].Value.b;

hr = HrStrToStrW(lpszInConverter, &lpszInConverterW);

if(FAILED(hr))
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}

hr = HrStrToStrW(lpszOutConverter, &lpszOutConverterW);

if(FAILED(hr))
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}

//
// Add trailing slash to inbound directory.
//

cBytes = cbStrLen(lpszInDirectory) + sizeof(TCHAR);
lpszDir = NULL;

hr = MAPIAllocateMore(cBytes, lpUnpackedProps, (void **)&lpszDir);

if(FAILED(hr))
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}

lstrcpy(lpszDir, lpszInDirectory);
AppendSlash(lpszDir);
lpszInDirectory = lpszDir;

//
// Add trailing slash to outbound directory.
//

cBytes = cbStrLen(lpszOutDirectory) + sizeof(TCHAR);
lpszDir = NULL;

hr = MAPIAllocateMore(cBytes, lpUnpackedProps, (void **)&lpszDir);

if(FAILED(hr))
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}

lstrcpy(lpszDir, lpszOutDirectory);
AppendSlash(lpszDir);
lpszOutDirectory = lpszDir;

//
// Add trailing slash to archive directory.
//

cBytes = cbStrLen(lpszOutDirectory) +
cbStrLen(TEXT("\\ARCHIVE")) +
sizeof(TCHAR);

lpszDir = NULL;

hr = MAPIAllocateBuffer(cBytes, (void **)&lpszDir);

if(FAILED(hr))
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}

lstrcpy(lpszDir, lpszOutDirectory);
AppendSlash(lpszDir);
lpszArchiveDirectory = lpszDir;

lpsz = lpszArchiveDirectory;
lpsz += lstrlen(lpszArchiveDirectory);
lpsz --;
*lpsz = 0;

while(lpsz != lpszArchiveDirectory)
{
if((*lpsz == TEXT('\\')) || (*lpsz == TEXT(':')))
{
if(*lpsz == TEXT(':'))
lpsz++;
lstrcpy(lpsz, "\\ARCHIVE\\");
break;
}

lpsz--;
}

//--------------------------------------------------------------------------

if(fInEnabled == TRUE)
{
hr = HrGWStartNewFileHandler(
dwInSleepInterval,
dwInPollInterval,
cInMessages,
cInThreads,
lpszAddressType,
TEXT("SGW*.TMP"),
lpszInDirectory,
(LPTHREAD_START_ROUTINE)ProcessMtsIn);

if(FAILED(hr))
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}
}
else
{
MODULE_WARNING("**** [IN] Processing not enabled ****");
}

//--------------------------------------------------------------------------

if(fOutEnabled == TRUE)
{
hr = HrGWStartNewMailHandler(
dwOutSleepInterval,
dwOutPollInterval,
cOutMessages,
cOutThreads,
lpszAddressType,
lpszOutDirectory,
(LPTHREAD_START_ROUTINE)ProcessMtsOut);

if(FAILED(hr))
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}
}
else
{
MODULE_WARNING("**** [OUT] Processing not enabled ****");
}

cleanup:

if(FAILED(hr))
{
MODULE_WARNING("**** Stopping gateway ****");

SetServiceExitCode( ERROR_INTERNAL_ERROR, NOERROR);

ServiceStop();
}

MAPIFREEBUFFER(lpProps);

MAPIFREEBUFFER(lpszUnpackedName);

ULRELEASE(lpCurrentObject);

//
// Wait for a request for the gateway to stop.
//

hr = HR_LOG(HrServiceWaitForStop(INFINITE, &sc));

MAPIFREEBUFFER(lpszInConverterW);

MAPIFREEBUFFER(lpszOutConverterW);

MAPIFREEBUFFER(lpUnpackedProps);

//
// IMPORTANT: Return from this function only if the gateway is ready to stop.
//

return;
}

//$--HrGWLogon------------------------------------------------------------------
// Logon to the gateway.
// -----------------------------------------------------------------------------
HRESULT HrGWLogon( // RETURNS: return code
void) // no arguments
{
HRESULT hr = NOERROR;
SCODE sc = 0;
BOOL fStatus = TRUE;
LPTSTR lpszT = NULL;
LPMAPIPROP lpSiteAddressing = NULL;
ULONG ulGatewayProxyTag = 0;
ULONG cValues = 0;
LPSPropValue lpProps = NULL;
ULONG i = 0;

SizedSPropTagArray(1, rgPropTags) =
{
1,
{
0,
}
};

DEBUGPUBLIC("HrGWLogon()\n");

InitializeCriticalSection(&csGatewaySeqNo);
InitializeCriticalSection(&csInboundIdList);
InitializeCriticalSection(&csOutboundIdList);

InboundIdList.lpcs = &csInboundIdList;
OutboundIdList.lpcs = &csOutboundIdList;

lpSession = GetGWSession();
lpStore = GetGWDefaultStore();
lpRootFolder = GetGWRootFolder();
lpMtsInFolder = GetGWMtsInFolder();
lpMtsOutFolder = GetGWMtsOutFolder();
cbGalEid = GetGWGALEntryIdSize();
lpGalEid = GetGWGALEntryId();

//
// Get a pointer to the site addressing object

hr = HrOpenSiteContainerAddressing(
lpSession,
&lpSiteAddressing);

if(FAILED(hr))
{
fStatus = FALSE;
goto cleanup;
}

//
// Convert our MAPI Name ID to a property tag
//
hr = HrCfgPropertyTagFromNameId(
lpSiteAddressing,
NM_GATEWAY_PROXY,
&ulGatewayProxyTag);

if(FAILED(hr))
{
fStatus = FALSE;
goto cleanup;
}

//
// Now get the properties we want from the site object
//

rgPropTags.aulPropTag[0] = ulGatewayProxyTag;

hr = MAPICALL(lpSiteAddressing)->GetProps(
lpSiteAddressing,
(LPSPropTagArray)&rgPropTags,
fMapiUnicode,
&cValues,
&lpProps);

if(FAILED(hr))
{
fStatus = FALSE;
goto cleanup;
}

if(PROP_TYPE(lpProps[0].ulPropTag) == PT_ERROR)
{
hr = HR_LOG(E_FAIL);

fStatus = FALSE;
goto cleanup;
}

if(lpProps[0].Value.MVSZ.cValues == 0)
{
hr = HR_LOG(E_FAIL);

fStatus = FALSE;
goto cleanup;
}

for(i = 0; i < (lpProps[0].Value.MVSZ.cValues); i++)
{
if(!_tcsnicmp(
lpProps[0].Value.MVSZ.LPPSZ[i],
TEXT("X400:"),
lstrlen(TEXT("X400:"))))
{
break;
}
}

sc = MAPIAllocateBuffer(
cbStrLen(lpProps[0].Value.MVSZ.LPPSZ[i]),
(void **)&lpszT);

if(FAILED(sc))
{
hr = HR_LOG(E_OUTOFMEMORY);
goto cleanup;
}

lstrcpy(lpszT, lpProps[0].Value.MVSZ.LPPSZ[i]);

//
// Create the local enterprise GDI.
//

hr = HrCreateEnterpriseGDI(
lpszT,
TEXT(":;"),
&lpszLocalGDI);

if(FAILED(hr))
{
fStatus = FALSE;
goto cleanup;
}

// Open an event log for this application.
hr = HrEventOpenLog(
szAppName, // application name
NULL, // executable name (will be computed)
TEXT("EDKMSG.DLL"), // event message file
NULL, // parameter message file (will be computed)
NULL, // category message file (will be computed)
&hEventLog); // event source handle

if ( FAILED(hr) || (hEventLog == NULL) )
{
goto cleanup;
}

// Initialize global conversion engine data.
hr = HrConvInitGlobals();

if ( FAILED(hr) )
{
fStatus = FALSE;
goto cleanup;
}

cleanup:

ULRELEASE(lpSiteAddressing);

MAPIFREEBUFFER(lpProps);

MAPIFREEBUFFER(lpszT);

if(fStatus == FALSE)
{
//
// Gateway logon failed.
//

MODULE_WARNING("**** Stopping gateway ****");

SetServiceExitCode( ERROR_INTERNAL_ERROR, NOERROR);

ServiceStop();
}

RETURN(hr);
}

//$--HrArchiveMtsOut------------------------------------------------------------
// Archive messages in MTS-OUT which could not be delivered.
// -----------------------------------------------------------------------------
HRESULT HrArchiveMtsOut( // RETURNS: zero
VOID) // parameter
{
HRESULT hr = NOERROR;
ULONG cbeid = 0;
LPENTRYID lpeid = NULL;
ULONG ulObjType = 0;
ULONG ulPropTag = 0;
ULONG cValues = 0;
ULONG i = 0;
ULONG cRows = 0;

LPMAPIFOLDER lpArchiveFolder = NULL;
LPMAPITABLE lpTable = NULL;

LPMESSAGE lpEnvelope = NULL;

LPSPropValue lpProps = NULL;

LPSPropTagArray lpPropTagArray = NULL;

ULONG cValuesT = 0;
LPSPropValue lpPropsT = NULL;

ULONG cbMsgEid = 0;
LPENTRYID lpMsgEid = NULL;

LPSRowSet lpRows = NULL;

SizedSPropTagArray(1, rgRecordKeyPropTag) =
{
1,
{
PR_RECORD_KEY
}
};

ULONG cBytes = 0;
LPTSTR lpszRecordKey = 0;

LPIDITEM lpIdItem = NULL;

SizedSPropTagArray(1, rgPropTag) =
{
1,
{
PR_ENTRYID
}
};

DEBUGPUBLIC("HrArchiveMtsOut()\n");

//
// Find and open the MTS-OUT archive folder.
//

hr = HrMAPIFindFolder(
GetGWRootFolder(),
TEXT("ARCHIVE"),
&cbeid,
&lpeid);

if(FAILED(hr))
{
hr = MAPICALL(lpRootFolder)->CreateFolder(
lpRootFolder,
FOLDER_GENERIC,
TEXT("ARCHIVE"),
NULL,
NULL,
MAPI_DEFERRED_ERRORS,
&lpArchiveFolder);

if(FAILED(hr))
{
goto cleanup;
}
}
else
{
// Open the archive folder in the root folder
hr = MAPICALL(lpRootFolder)->OpenEntry(
lpRootFolder,
cbeid,
lpeid,
NULL,
MAPI_DEFERRED_ERRORS|MAPI_MODIFY,
&ulObjType,
(LPUNKNOWN FAR *) &lpArchiveFolder);

MAPIFREEBUFFER(lpeid);

if(FAILED(hr))
{
goto cleanup;
}

if(ulObjType != MAPI_FOLDER)
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}
}

//
// Get the contents table for the MTS-OUT
//

hr = MAPICALL(lpMtsOutFolder)->GetContentsTable(
lpMtsOutFolder,
MAPI_DEFERRED_ERRORS,
&lpTable);

if(FAILED(hr))
{
goto cleanup;
}

hr = MAPICALL(lpTable)->SetColumns(
lpTable,
(LPSPropTagArray)&rgPropTag,
TBL_BATCH);

if(FAILED(hr))
{
goto cleanup;
}

//
// Query all the rows
//

hr = HrQueryAllRows(
lpTable,
NULL,
NULL,
NULL,
0,
&lpRows);

ULRELEASE(lpTable);

if(FAILED(hr))
{
goto cleanup;
}

cRows = lpRows->cRows;

for(i = 0; i < cRows; i++)
{
cValues = lpRows->aRow[i].cValues;

lpProps = lpRows->aRow[i].lpProps;

cbeid = lpProps[0].Value.bin.cb;
lpeid = (LPENTRYID)lpProps[0].Value.bin.lpb;

cbMsgEid = cbeid;
lpMsgEid = lpeid;

cValues = 0;
lpProps = NULL;

// Get the message in the MTS-OUT folder
hr = MAPICALL(lpMtsOutFolder)->OpenEntry(
lpMtsOutFolder,
cbeid,
lpeid,
NULL,
MAPI_DEFERRED_ERRORS|MAPI_MODIFY,
&ulObjType,
(LPUNKNOWN FAR *)&lpEnvelope);

cbeid = 0;
lpeid = NULL;

if(FAILED(hr))
{
goto cleanup;
}

if(ulObjType != MAPI_MESSAGE)
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}

//------------------------------------------------------------------------------

// Get the message ID

MAPIFREEBUFFER(lpPropsT);
MAPIFREEBUFFER(lpszRecordKey);

cValuesT = 0;
lpPropsT = NULL;

hr = MAPICALL(lpEnvelope)->GetProps(
lpEnvelope,
(LPSPropTagArray)&rgRecordKeyPropTag,
fMapiUnicode,
&cValuesT,
&lpPropsT);

if(FAILED(hr))
{
goto cleanup;
}

if(lpPropsT[0].ulPropTag != PR_RECORD_KEY)
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}

if(lpPropsT[0].Value.bin.cb == 0)
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}

if(lpPropsT[0].Value.bin.lpb == NULL)
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}

cBytes = (lpPropsT[0].Value.bin.cb + sizeof(TCHAR)) * (2 * sizeof(TCHAR));

hr = MAPIAllocateBuffer(cBytes, (void **)&lpszRecordKey);

if(FAILED(hr))
{
goto cleanup;
}

HexFromBin(lpPropsT[0].Value.bin.lpb, lpPropsT[0].Value.bin.cb, lpszRecordKey);

MAPIFREEBUFFER(lpPropsT);

hr = HrLookupIdItem(
&OutboundIdList,
lpszRecordKey,
&lpIdItem);

if(hr == EDK_E_NOT_FOUND)
{
//
// Skip this message. It is a new message.
//

MAPIFREEBUFFER(lpszRecordKey);
MAPIFREEBUFFER(lpPropsT);
ULRELEASE(lpEnvelope);
continue;
}

if(FAILED(hr))
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}

//------------------------------------------------------------------------------

MAPIFREEBUFFER(lpszRecordKey);
MAPIFREEBUFFER(lpPropsT);
ULRELEASE(lpEnvelope);

//------------------------------------------------------------------------------

hr = HrMAPIMoveMessage(
lpMtsOutFolder,
lpArchiveFolder,
cbMsgEid,
lpMsgEid);

if(FAILED(hr))
{
; // create an entry in the debug log
}
}

cleanup:

FREEPROWS(lpRows);

MAPIFREEBUFFER(lpPropsT);

MAPIFREEBUFFER(lpszRecordKey);

ULRELEASE(lpEnvelope);

ULRELEASE(lpArchiveFolder);

ULRELEASE(lpTable);

RETURN(hr);
}

//$--HrArchiveMtsIn-------------------------------------------------------------
// Archive messages in MTS-IN which could not be delivered.
// -----------------------------------------------------------------------------
HRESULT HrArchiveMtsIn( // RETURNS: return code
VOID) // no arguments
{
HRESULT hr = NOERROR;
HRESULT hrT = NOERROR;
LPIDITEM lpIdItem = NULL;
BOOL fRet = FALSE;
TCHAR rgchFileName[MAX_PATH+1] = {0};
TCHAR rgchPathName[MAX_PATH+1] = {0};
LPTSTR lpszPath = NULL;
LPIDITEM lpIdList = NULL;

//
// Find and open the MTS-IN archive directory.
//

lstrcpy(rgchPathName, lpszArchiveDirectory);

fRet = CreateDirectory(rgchPathName, NULL);

if(fRet == FALSE)
{
hr = HR_LOG(E_FAIL);
}

lpszPath = rgchPathName;

lpIdList = &InboundIdList;

EnterCriticalSection(lpIdList->lpcs);

__try
{
lpIdItem = lpIdList->next;

while(lpIdItem != NULL)
{
lpIdList->next = lpIdItem->next;

rgchFileName[0] = 0;

fRet = GetTempFileName32(lpszPath, TEXT("BAK"), 0, (LPTSTR)rgchFileName);

if(fRet == FALSE)
{
hr = HR_LOG(E_FAIL);
}
else
{
fRet = MoveFileEx(
lpIdItem->lpszId,
(LPTSTR)rgchFileName,
MOVEFILE_COPY_ALLOWED|MOVEFILE_REPLACE_EXISTING);

if(fRet == FALSE)
{
hr = HR_LOG(E_FAIL);
}
}

lpIdItem = lpIdList->next;
}
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
SetLastError(_exception_code());

hr = HR_LOG(E_FAIL);

MODULE_WARNING("**** Stopping gateway ****");

SetServiceExitCode( ERROR_INTERNAL_ERROR, NOERROR);

ServiceStop();
}

LeaveCriticalSection(lpIdList->lpcs);

RETURN(hr);
}

//$--HrGWLogoff-----------------------------------------------------------------
// Logoff of the gateway.
// -----------------------------------------------------------------------------
HRESULT HrGWLogoff( // RETURNS: return code
void) // no arguments
{
HRESULT hr = NOERROR;
HRESULT hrT = NOERROR;

DEBUGPUBLIC("HrGWLogoff()\n");

// De-initialize conversion engine global data.
ConvUninitGlobals();

// Close the event log.
(VOID)HrEventCloseLog();
hEventLog = NULL;

MAPIFREEBUFFER(lpbBuffer);

MAPIFREEBUFFER(lppszBufferArray);

MAPIFREEBUFFER(lpszLocalGDI);

//
// Archive messages which could not be delivered.
//

hrT = HR_LOG(HrArchiveMtsIn());

hrT = HR_LOG(HrArchiveMtsOut());


hrT = HR_LOG(HrEmptyIdList(&InboundIdList));

hrT = HR_LOG(HrEmptyIdList(&OutboundIdList));

DeleteCriticalSection(&csGatewaySeqNo);
DeleteCriticalSection(&csInboundIdList);
DeleteCriticalSection(&csOutboundIdList);

MAPIFREEBUFFER(lpszArchiveDirectory);

RETURN(hr);
}