Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

3205 lines
92 KiB

//#define INCL_INETSRV_INCS
//#include "smtpinc.h"
#include <atq.h>
#include <pudebug.h>
#include <inetcom.h>
#include <inetinfo.h>
#include <tcpdll.hxx>
#include <tsunami.hxx>
#include <tchar.h>
#include <iistypes.hxx>
#include <iisendp.hxx>
#include <metacach.hxx>
#include <cpool.h>
#include <address.hxx>
#include <mailmsgprops.h>
extern "C" {
#include <rpc.h>
#define SECURITY_WIN32
#include <wincrypt.h>
#include <sspi.h>
#include <spseal.h>
#include <issperr.h>
#include <ntlmsp.h>
}
#include <tcpproc.h>
#include <tcpcons.h>
#include <rdns.hxx>
#include <simauth2.h>
#include "dbgtrace.h"
#include "imd.h"
#include "mb.hxx"
#include <stdio.h>
#define _ATL_NO_DEBUG_CRT
#define _ATL_STATIC_REGISTRY 1
#define _ASSERTE _ASSERT
#define _WINDLL
#include "atlbase.h"
extern CComModule _Module;
#include "atlcom.h"
#undef _WINDLL
#include "filehc.h"
#include "seo.h"
#include "seolib.h"
#include "smtpdisp_i.c"
#include "mailmsgi.h"
#include <smtpevent.h>
#include "cdo.h"
#include "cdo_i.c"
#include "cdoconstimsg.h"
#include "seomgr.h"
#define MAX_RULE_LENGTH 4096
//
// Message object
//
#define MAILMSG_PROGID L"Exchange.MailMsg"
#define INITGUID
#include "initguid.h"
#include "smtpguid.h"
#include "wildmat.h"
#include "smtpdisp.h"
#include "seodisp.h"
#include "evntwrap.h"
// {0xCD000080,0x8B95,0x11D1,{0x82,0xDB,0x00,0xC0,0x4F,0xB1,0x62,0x5D}}
DEFINE_GUID(IID_IConstructIMessageFromIMailMsg, 0xCD000080,0x8B95,0x11D1,0x82,
0xDB,0x00,0xC0,0x4F,0xB1,0x62,0x5D);
extern VOID
ServerEventCompletion(
PVOID pvContext,
DWORD cbWritten,
DWORD dwCompletionStatus,
OVERLAPPED * lpo
);
#define SKIPSINK_CALL_NO_MORE_SINKS 0xffffffff
class CStoreCreateOptions : public CEventCreateOptionsBase
{
public:
CStoreCreateOptions( SMTP_ALLOC_PARAMS * pContext)
{
_ASSERT (pContext != NULL);
m_Context = pContext;
}
private:
HRESULT STDMETHODCALLTYPE Init(REFIID iidDesired, IUnknown **ppUnkObject, IEventBinding *, IUnknown *)
{
ISMTPStoreDriver *pSink = NULL;
IUnknown * ThisUnknown = NULL;
IUnknown * NewUnknown = NULL;
HRESULT hrRes = S_OK;
TraceFunctEnterEx((LPARAM)this, "Calling create options");
ThisUnknown = *ppUnkObject;
hrRes = ThisUnknown->QueryInterface(IID_ISMTPStoreDriver, (void **)&pSink);
if (hrRes == E_NOINTERFACE) {
return (E_NOTIMPL);
}
if (FAILED(hrRes))
return(hrRes);
DebugTrace((LPARAM)this, "Calling startup events on sinks ...");
hrRes = pSink->Init(m_Context->m_InstanceId,
NULL,
(IUnknown *) m_Context->m_EventSmtpServer,
m_Context->m_dwStartupType,
&NewUnknown);
pSink->Release();
if (FAILED(hrRes) && (hrRes != E_NOTIMPL)) {
return (hrRes);
}
if(NewUnknown)
{
hrRes = NewUnknown->QueryInterface(iidDesired, (void **)ppUnkObject);
NewUnknown->Release();
if (!SUCCEEDED(hrRes)) {
return (hrRes);
}
ThisUnknown->Release();
}
return (E_NOTIMPL);
};
public:
SMTP_ALLOC_PARAMS * m_Context;
};
CStoreDispatcher::CStoreAllocParams::CStoreAllocParams()
{
m_hContent = NULL;
}
CStoreDispatcher::CStoreAllocParams::~CStoreAllocParams()
{
}
//+------------------------------------------------------------
//
// Function: CStoreDispatcher::CreateCParams
//
// Synopsis: Based on dwEventType, create the appropriate Params object
//
// Arguments:
// dwEventType - specifies SMTP event
// pContext - context to pass into Init function
//
// Returns:
// S_OK: Success
// E_OUTOFMEMORY
// or error from InitParamData
//
// History:
// jstamerj 980610 18:30:20: Created.
//
//-------------------------------------------------------------
HRESULT CStoreDispatcher::CreateCParams(
DWORD dwEventType,
LPVOID pContext,
IMailTransportNotify *pINotify,
REFIID rGuidEventType,
CStoreBaseParams **ppCParams)
{
_ASSERT(ppCParams);
HRESULT hr;
switch(dwEventType) {
case SMTP_STOREDRV_STARTUP_EVENT:
if (!SUCCEEDED(GetData(NULL,NULL))) {
hr = SetData(((SMTP_ALLOC_PARAMS *) pContext)->m_EventSmtpServer,
((SMTP_ALLOC_PARAMS *) pContext)->m_InstanceId);
_ASSERT(SUCCEEDED(hr));
}
// fall through
case SMTP_MAIL_DROP_EVENT:
case SMTP_STOREDRV_ENUMMESS_EVENT:
case SMTP_STOREDRV_DELIVERY_EVENT:
case SMTP_STOREDRV_ALLOC_EVENT:
case SMTP_STOREDRV_PREPSHUTDOWN_EVENT:
case SMTP_STOREDRV_SHUTDOWN_EVENT:
*ppCParams = new CStoreParams();
break;
case SMTP_MAILTRANSPORT_SUBMISSION_EVENT:
*ppCParams = new CMailTransportSubmissionParams();
break;
case SMTP_MAILTRANSPORT_PRECATEGORIZE_EVENT:
*ppCParams = new CMailTransportPreCategorizeParams();
break;
case SMTP_MAILTRANSPORT_CATEGORIZE_REGISTER_EVENT:
*ppCParams = new CMailTransportCatRegisterParams();
break;
case SMTP_MAILTRANSPORT_CATEGORIZE_BEGIN_EVENT:
*ppCParams = new CMailTransportCatBeginParams();
break;
case SMTP_MAILTRANSPORT_CATEGORIZE_END_EVENT:
*ppCParams = new CMailTransportCatEndParams();
break;
case SMTP_MAILTRANSPORT_CATEGORIZE_BUILDQUERY_EVENT:
*ppCParams = new CMailTransportCatBuildQueryParams();
break;
case SMTP_MAILTRANSPORT_CATEGORIZE_BUILDQUERIES_EVENT:
*ppCParams = new CMailTransportCatBuildQueriesParams();
break;
case SMTP_MAILTRANSPORT_CATEGORIZE_SENDQUERY_EVENT:
*ppCParams = new CMailTransportCatSendQueryParams();
break;
case SMTP_MAILTRANSPORT_CATEGORIZE_SORTQUERYRESULT_EVENT:
*ppCParams = new CMailTransportCatSortQueryResultParams();
break;
case SMTP_MAILTRANSPORT_CATEGORIZE_PROCESSITEM_EVENT:
*ppCParams = new CMailTransportCatProcessItemParams();
break;
case SMTP_MAILTRANSPORT_CATEGORIZE_EXPANDITEM_EVENT:
*ppCParams = new CMailTransportCatExpandItemParams();
break;
case SMTP_MAILTRANSPORT_CATEGORIZE_COMPLETEITEM_EVENT:
*ppCParams = new CMailTransportCatCompleteItemParams();
break;
case SMTP_MAILTRANSPORT_POSTCATEGORIZE_EVENT:
*ppCParams = new CMailTransportPostCategorizeParams();
break;
case SMTP_MAILTRANSPORT_GET_ROUTER_FOR_MESSAGE_EVENT:
*ppCParams = new CMailTransportRouterParams();
break;
case SMTP_MSGTRACKLOG_EVENT:
*ppCParams = new CMsgTrackLogParams();
break;
case SMTP_DNSRESOLVERRECORDSINK_EVENT:
*ppCParams = new CDnsResolverRecordParams();
break;
case SMTP_MAXMSGSIZE_EVENT:
*ppCParams = new CSmtpMaxMsgSizeParams();
break;
case SMTP_LOG_EVENT:
*ppCParams = new CSmtpLogParams();
break;
case SMTP_GET_AUX_DOMAIN_INFO_FLAGS_EVENT:
*ppCParams = new CSmtpGetAuxDomainInfoFlagsParams();
break;
default:
_ASSERT(0 && "Unknown server event");
*ppCParams = NULL;
break;
}
if(*ppCParams == NULL) {
return E_OUTOFMEMORY;
}
hr = (*ppCParams)->InitParamData(
pContext,
dwEventType,
pINotify,
this,
rGuidEventType);
if(FAILED(hr)) {
(*ppCParams)->Release();
*ppCParams = NULL;
return hr;
}
return S_OK;
}
//+------------------------------------------------------------
//
// Function: CStoreDispatcher::CStoreBaseParams::CStoreBaseParams
//
// Synopsis: Sets member data to pre-initialized values
//
// Arguments: NONE
//
// Returns: NOTHING
//
// History:
// jstamerj 1998/06/23 13:58:01: Created.
//
//-------------------------------------------------------------
CStoreDispatcher::CStoreBaseParams::CStoreBaseParams() :
m_rguidEventType(CATID_SMTP_STORE_DRIVER)
{
m_dwSignature = SIGNATURE_VALID_CSTOREPARAMS;
m_dwIdx_SinkSkip = 0;
m_fDefaultProcessingCalled = FALSE;
m_pINotify = NULL;
m_pIUnknownSink = NULL;
m_pDispatcher = NULL;
}
//+------------------------------------------------------------
//
// Function: CStoreDispatcher::CStoreBaseParams::~CStoreBaseParams
//
// Synopsis: Release the IMailTransportNotify reference if held
//
// Arguments: NONE
//
// Returns: NOTHING
//
// History:
// jstamerj 1998/06/23 13:58:51: Created.
//
//-------------------------------------------------------------
CStoreDispatcher::CStoreBaseParams::~CStoreBaseParams()
{
if(m_pINotify)
m_pINotify->Release();
_ASSERT(m_dwSignature == SIGNATURE_VALID_CSTOREPARAMS);
m_dwSignature = SIGNATURE_INVALID_CSTOREPARAMS;
}
//+------------------------------------------------------------
//
// Function: InitParamData
//
// Synopsis: Initializes object. This includes calling Init() which
// is implemented in dervied objects.
//
// Arguments:
// pContext: Context passed in - specific for server event
// dwEventType: Specifies which server event we are for
// pINotify: IMailTransportNotify interface for async completion
// rguidEventType: guid for event type binding
//
// Returns:
// S_OK: Success
// Error from Init()
//
// History:
// jstamerj 980615 19:16:55: Created.
//
//-------------------------------------------------------------
HRESULT CStoreDispatcher::CStoreBaseParams::InitParamData(
PVOID pContext,
DWORD dwEventType,
IMailTransportNotify *pINotify,
CStoreDispatcher *pDispatcher,
REFIID rguidEventType)
{
TraceFunctEnterEx((LPARAM)this, "CStoreBaseParams::InitParamData");
HRESULT hr;
m_dwEventType = dwEventType;
m_dwIdx_SinkSkip = 0;
m_fDefaultProcessingCalled = FALSE;
m_pINotify = pINotify;
m_pINotify->AddRef();
m_rguidEventType = rguidEventType;
m_pDispatcher = pDispatcher;
hr = Init(pContext);
if(FAILED(hr)) {
ErrorTrace((LPARAM)this, "Init() failed, hr = %08lx", hr);
TraceFunctLeaveEx((LPARAM)this);
return hr;
}
return S_OK;
}
//+------------------------------------------------------------
//
// Function: CStoreDispatcher::CStoreBaseParams::CallObject
//
// Synopsis: Called by the dispatcher when time to call a sink. This
// implements some default functionality -- create the sink with a
// null CCreateOptions
//
// Arguments:
// IEventManager
// CBinding
//
// Returns:
// S_OK: Success
// or error from CreateSink/CallObject
//
// History:
// jstamerj 1998/06/23 13:53:57: Created.
//
//-------------------------------------------------------------
HRESULT CStoreDispatcher::CStoreBaseParams::CallObject(
IEventManager *pManager,
CBinding& bBinding)
{
HRESULT hrRes;
CComPtr<IUnknown> pUnkSink;
if (!pManager) {
return (E_POINTER);
}
hrRes = pManager->CreateSink(bBinding.m_piBinding,NULL,&pUnkSink);
if (!SUCCEEDED(hrRes)) {
return (hrRes);
}
return (CallObject(bBinding,pUnkSink));
}
//+------------------------------------------------------------
//
// Function: CStoreDispatcher::CStoreBaseParams::CheckMailMsgRule
//
// Synopsis: Determines if a mailmsg string rule passes or fails given
// the mailmsg and the CBinding object
//
// Arguments:
// pBinding: CBinding object for this sink
// pMsgProps: IMailMsgProperteries of the message to check
//
// Returns:
// S_OK: Success, call this sink
// S_FALSE: Success, don't call this sink
//
// History:
// jstamerj 1999/01/11 17:04:01: Created.
//
//-------------------------------------------------------------
HRESULT CStoreDispatcher::CStoreBaseParams::CheckMailMsgRule(
CBinding *pBinding,
IMailMsgProperties *pIMsgProps)
{
HRESULT hr;
BOOL fDomainLoaded = FALSE;
BOOL fSenderLoaded = FALSE;
CHAR szDomain[MAX_INTERNET_NAME + 2];
CHAR szSender[MAX_INTERNET_NAME + 2];
LPSTR szRule;
CStoreBinding *pStoreBinding = (CStoreBinding *)pBinding;
TraceFunctEnterEx((LPARAM)this, "CStoreDispatcher::CStoreBaseParams::CheckMailMsgRule");
_ASSERT(pStoreBinding);
_ASSERT(pIMsgProps);
// Get the cached rule from the binding
szRule = pStoreBinding->GetRuleString();
DebugTrace((LPARAM)this, "Rule string: %s", (szRule)?szRule:"NULL (No rule)");
// If the rule is NULL, we will don't have a rule
// string and we will return a match
if (!szRule)
{
TraceFunctLeaveEx((LPARAM)this);
return(S_OK);
}
// try each comma delimited rule in the header patterns list
char *pszHeader = (char *) _alloca(lstrlen(szRule)+1);
if (!pszHeader) {
return (E_OUTOFMEMORY);
}
lstrcpy(pszHeader,szRule);
while (pszHeader != NULL && *pszHeader != 0)
{
// find the next semicolon in the string and turn it into a 0
// if it exists
char *pszSemiColon = strchr(pszHeader, ';');
if (pszSemiColon != NULL)
*pszSemiColon = 0;
// set pszContents to point to the text which must be matched
// in the header. if pszContents == NULL then just having
// the header exist is good enough.
char *pszPatterns = strchr(pszHeader, '=');
if (pszPatterns != NULL)
{
*pszPatterns = 0;
(pszPatterns++);
}
// we now have the header that we are looking for in
// pszHeader and the list of patterns that we are interested
// in pszPatterns. Make the lookup into the header
// data structure
hr = S_FALSE;
DebugTrace((LPARAM)this, "Processing Header <%s> with pattern <%s>",
pszHeader, pszPatterns);
if (!lstrcmpi(pszHeader, "EHLO")) {
// Process a client domain rule ...
if (!fDomainLoaded) {
hr = pIMsgProps->GetStringA(
IMMPID_MP_HELO_DOMAIN,
sizeof(szDomain),
szDomain);
if (hr == S_OK) {
fDomainLoaded = TRUE;
}
}
if (fDomainLoaded) {
hr = MatchEmailOrDomainName(szDomain, pszPatterns, FALSE);
}
} else if (!lstrcmpi(pszHeader, "MAIL FROM")) {
// Process a sender name rule ...
if (!fSenderLoaded) {
hr = pIMsgProps->GetStringA(
IMMPID_MP_SENDER_ADDRESS_SMTP,
sizeof(szSender),
szSender);
if (hr == S_OK)
{
fSenderLoaded = TRUE;
}
}
if (fSenderLoaded) {
hr = MatchEmailOrDomainName(szSender, pszPatterns, TRUE);
}
}
else if (!lstrcmpi(pszHeader, "RCPT TO"))
{
hr = CheckMailMsgRecipientsRule(
pIMsgProps,
pszPatterns);
}
// We don't want to destroy the rule string so we restore all the
// semicolons and equal signs
if (pszSemiColon)
*pszSemiColon = ';';
if (pszPatterns)
*(pszPatterns - 1) = '=';
// Exit immediately if we found a match!
if (hr == S_OK)
goto Cleanup;
// the next pattern is the one past the end of the semicolon
pszHeader = (pszSemiColon == NULL) ? NULL : pszSemiColon + 1;
}
Cleanup:
DebugTrace((LPARAM)this, "Returning hr %08lx", hr);
TraceFunctLeaveEx((LPARAM)this);
return(hr);
}
//+------------------------------------------------------------
//
// Function: CStoreDispatcher::CStoreBaseParams::CheckMailMsgRecipientsRule
//
// Synopsis: Determines if a mailmsg pattern string matches mailmsg
// recipients or not
//
// Arguments:
// pIMsg: An interface to a mailmsg object
// pszPatterns: The sink rule to check
//
// Returns:
// S_OK: Success, call this sink
// S_FALSE: Success, don't call this sink
// error from mailmsg
//
// History:
// jstamerj 1999/01/12 15:25:55: Copied from MCIS2 and modified for Platinum
//
//-------------------------------------------------------------
HRESULT CStoreDispatcher::CStoreBaseParams::CheckMailMsgRecipientsRule(
IUnknown *pIMsg,
LPSTR pszPattern)
{
HRESULT hr;
DWORD dwNumRecips;
IMailMsgRecipients *pIRecips = NULL;
BOOL fMatch = FALSE;
DWORD dwCount;
CHAR szRecip [MAX_INTERNET_NAME + 2];
TraceFunctEnterEx((LPARAM)this,
"CStoreDispatcher::CStoreBaseParams::CheckMailMsgRecipientsRule");
hr = pIMsg->QueryInterface(
IID_IMailMsgRecipients,
(LPVOID *)&pIRecips);
if(FAILED(hr))
goto CLEANUP;
hr = pIRecips->Count(&dwNumRecips);
if(FAILED(hr))
goto CLEANUP;
DebugTrace((LPARAM)this, "Checking rule \"%s\" for %d recipients",
pszPattern, pIMsg);
for(dwCount = 0;
(fMatch == FALSE) && (dwCount < dwNumRecips);
dwCount++) {
hr = pIRecips->GetStringA(
dwCount,
IMMPID_RP_ADDRESS_SMTP,
sizeof(szRecip),
szRecip);
if(FAILED(hr) && (hr != MAILMSG_E_PROPNOTFOUND))
goto CLEANUP;
if(hr != MAILMSG_E_PROPNOTFOUND) {
hr = MatchEmailOrDomainName(szRecip,pszPattern,TRUE);
if(hr == S_OK)
fMatch = TRUE;
else if(FAILED(hr))
goto CLEANUP;
}
}
hr = (fMatch) ? S_OK : S_FALSE;
CLEANUP:
if(pIRecips)
pIRecips->Release();
DebugTrace((LPARAM)this, "Returning hr %08lx", hr);
TraceFunctLeaveEx((LPARAM)this);
return hr;
}
//+------------------------------------------------------------
//
// Function: CStoreDispatcher::CStoreBaseparams::MatchEmailOrDomainName
//
// Synopsis: Given an email/domain name and a pattern, determine if
// the pattern matches or not
//
// Arguments:
// szEmail: The email address or domain name
// szPattern: The pattern to check
// fIsEmail: TRUE if szEmail is an email address, FALSE if szEmail is
// a domain
//
// Returns:
// S_OK: Success, match
// S_FALSE: Success, no match
// E_INVALIDARG
//
// History:
// jstamerj 1999/01/12 15:25:36: Copied from MCIS2 and modified for Platinum
//
//-------------------------------------------------------------
HRESULT CStoreDispatcher::CStoreBaseParams::MatchEmailOrDomainName(
LPSTR szEmail,
LPSTR szPattern,
BOOL fIsEmail)
{
CAddr *pEmailAddress = NULL;
LPSTR szEmailDomain = NULL;
HRESULT hrRes;
TraceFunctEnterEx((LPARAM)this, "CStoreDispatcher::CStoreBaseParams::MatchEmailOrDomainName");
DebugTrace((LPARAM)NULL, "Matching <%s> against <%s>", szEmail, szPattern);
if (!szEmail || !szPattern)
return(E_INVALIDARG);
// This validates that it is a good email name
pEmailAddress = CAddr::CreateAddress(szEmail, fIsEmail?FROMADDR:CLEANDOMAIN);
if (!pEmailAddress)
return(E_INVALIDARG);
szEmail = pEmailAddress->GetAddress();
szEmailDomain = pEmailAddress->GetDomainOffset();
hrRes = ::MatchEmailOrDomainName(szEmail, szEmailDomain, szPattern, fIsEmail);
// Free the CAddr objects ...
if (pEmailAddress)
delete pEmailAddress;
TraceFunctLeaveEx((LPARAM)this);
return(hrRes);
}
CStoreDispatcher::CStoreBinding::CStoreBinding()
{
m_szRule = NULL;
}
CStoreDispatcher::CStoreBinding::~CStoreBinding()
{
if(m_szRule)
delete [] m_szRule;
}
//
// initialize a new binding. we cache information from the binding database
// here
// jstamerj 1999/01/12 16:25:59: Copied MCIS2 code to get the rule string
//
HRESULT CStoreDispatcher::CStoreBinding::Init(IEventBinding *piBinding)
{
HRESULT hr;
CComPtr<IEventPropertyBag> piEventProperties;
CComVariant vRule;
// get the parent initialized
hr = CBinding::Init(piBinding);
if (FAILED(hr))
return hr;
// get the binding database
hr = m_piBinding->get_SourceProperties(&piEventProperties);
if (FAILED(hr))
return hr;
// get the rule from the binding database
hr = piEventProperties->Item(&CComVariant("Rule"), &vRule);
if (FAILED(hr))
return hr;
// Process the rule string, the result code is not important
// since it will NULL our the string
if (hr == S_OK)
hr = GetAnsiStringFromVariant(vRule, &m_szRule);
return hr;
}
HRESULT CStoreDispatcher::CStoreBinding::GetAnsiStringFromVariant(
CComVariant &vString, LPSTR *ppszString)
{
HRESULT hr = S_OK;
_ASSERT(ppszString);
if (!ppszString)
return(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
// Default to NULL
*ppszString = NULL;
if (vString.vt == VT_BSTR)
{
DWORD dwLength = lstrlenW(vString.bstrVal) + 1;
// Convert to an ANSI string and store it as a member
*ppszString = new char[dwLength];
if (!*ppszString)
return HRESULT_FROM_WIN32(GetLastError());
// copy the rule into an ascii string
if (WideCharToMultiByte(CP_ACP, 0, vString.bstrVal,
-1, (*ppszString), dwLength, NULL, NULL) <= 0)
{
delete [] (*ppszString);
*ppszString = NULL;
return HRESULT_FROM_WIN32(GetLastError());
}
}
else
hr = HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
return(hr);
}
#if 1
//
// create and call the child object
//
HRESULT CStoreDispatcher::CStoreParams::CallObject(IEventManager *pManager, CBinding& bBinding)
{
CStoreCreateOptions opt (m_pContext);
HRESULT hrRes;
CComPtr<IUnknown> pUnkSink;
if (!pManager) {
return (E_POINTER);
}
hrRes = pManager->CreateSink(bBinding.m_piBinding,&opt,&pUnkSink);
if (!SUCCEEDED(hrRes)) {
return (hrRes);
}
return (CallObject(bBinding,pUnkSink));
}
#endif
//
// call the child object
//
HRESULT CStoreDispatcher::CStoreParams::CallObject(CBinding& bBinding, IUnknown *punkObject)
{
HRESULT hrRes = S_OK;
HRESULT hrTmp = S_OK;
TraceFunctEnterEx((LPARAM)this, "CStoreDispatcher::CServerParams::CallObject");
// We do this for different types of SMTP events
switch (m_dwEventType)
{
case SMTP_STOREDRV_STARTUP_EVENT:
break;
case SMTP_STOREDRV_ALLOC_EVENT:
{
IMailMsgStoreDriver *pSink = NULL;
IMailMsgProperties * pMsg = (IMailMsgProperties *)m_pContext->IMsgPtr;
IMailMsgBind *pBindInterface = NULL;
IMailMsgPropertyStream *pStream = NULL;
PATQ_CONTEXT pAtqFileContext = NULL;
DebugTrace((LPARAM)this, "Calling bind on sinks ...");
/*IID_ISMTPStoreDriver*/
hrRes = punkObject->QueryInterface(IID_IMailMsgStoreDriver, (void **)&pSink);
if (FAILED(hrRes))
return(hrRes);
// Allocate a new message
hrRes = pSink->AllocMessage(pMsg, NULL, &pStream, &m_pContext->hContent, NULL);
if(!FAILED(hrRes))
{
pBindInterface = (IMailMsgBind *)m_pContext->BindInterfacePtr;
#if 0
hrRes = pBindInterface->BindToStore(pStream, pSink, m_pContext->hContent,
m_pContext->pAtqClientContext, ServerEventCompletion,
INFINITE,
&m_pContext->pAtqContext,
AtqAddAsyncHandle,
AtqFreeContext);
#endif
hrRes = pBindInterface->BindToStore(pStream,
pSink,
m_pContext->hContent);
if (pStream)
{
pStream->Release();
pStream = NULL;
}
m_pContext->hr = hrRes;
if(FAILED(hrRes))
{
ErrorTrace((LPARAM)this, "pBindAtqInterface->BindToStore failed with %x", hrRes);
// Close the content handle
HRESULT myRes = pSink->CloseContentFile(
pMsg,
m_pContext->hContent);
if (FAILED(myRes))
{
FatalTrace((LPARAM)this, "Unable to close content file (%08x)", myRes);
_ASSERT(FALSE);
}
m_pContext->hContent = NULL;
hrTmp = pSink->Delete(pMsg, NULL);
_ASSERT(SUCCEEDED(hrTmp));
}
else
{
//Skip all sinks - temporary
hrRes = S_FALSE;
}
}
else
{
DebugTrace((LPARAM)this, "pSink->AllocMessage failed with %x", hrRes);
m_pContext->hr = hrRes;
}
pSink->Release();
}
break;
case SMTP_STOREDRV_DELIVERY_EVENT:
{
ISMTPStoreDriver *pSink;
IMailMsgNotify *pNotify;
hrRes = punkObject->QueryInterface(IID_ISMTPStoreDriver, (void **)&pSink);
if (FAILED(hrRes))
return(hrRes);
// if the caller has async notify support then pass in our
// notification class.
if (m_pContext->m_pNotify) {
// the sink might return async, so we need to keep local
// copies of our context data
hrRes = this->CopyContext();
if (FAILED(hrRes))
return hrRes;
hrRes = this->QueryInterface(IID_IMailMsgNotify,
(LPVOID *) &pNotify);
if (FAILED(hrRes))
return hrRes;
} else {
pNotify = NULL;
}
//
// Remember the sink so we can release this sink later if it
// returns pending
//
_ASSERT(m_pIUnknownSink == NULL);
m_pIUnknownSink = (IUnknown*)pSink;
m_pIUnknownSink->AddRef();
DebugTrace((LPARAM)this, "Calling local delivery sink sink ...");
hrRes = pSink->LocalDelivery(
(IMailMsgProperties *) m_pContext->IMsgPtr,
m_pContext->m_RecipientCount,
m_pContext->pdwRecipIndexes,
(IMailMsgNotify *) pNotify);
pSink->Release();
if(hrRes != MAILTRANSPORT_S_PENDING) {
//
// We completed synchronously, so release the sink
//
m_pIUnknownSink->Release();
m_pIUnknownSink = NULL;
}
// if LocalDelivery was going to do an async return then it
// should have AddRef'd pNotify
if (pNotify) pNotify->Release();
//
// jstamerj 1998/08/04 17:31:07:
// If the store driver sink returns this specific error
// code, we want to stop calling sinks and return from
// TriggerLocalDelivery
//
if(hrRes == STOREDRV_E_RETRY) {
DebugTrace((LPARAM)this, "Sink returned STOREDRV_E_RETRY on LocalDelivery");
m_pContext->hr = hrRes;
hrRes = S_FALSE;
}
}
break;
case SMTP_MAIL_DROP_EVENT:
// ISMTPStoreDriver *pSink;
// hrRes = punkObject->QueryInterface(IID_ISMTPStoreDriver, (void **)&pSink);
// if (FAILED(hrRes))
// return(hrRes);
// DebugTrace((LPARAM)this, "Calling mail drop sink ...");
// hrRes = pSink->DirectoryDrop((IMailMsgProperties *) m_pContext->IMsgPtr, m_pContext->m_RecipientCount, m_pContext->pdwRecipIndexes, m_pContext->m_DropDirectory, NULL);
// pSink->Release();
//}
break;
case SMTP_STOREDRV_PREPSHUTDOWN_EVENT:
{
ISMTPStoreDriver *pSink;
hrRes = punkObject->QueryInterface(IID_ISMTPStoreDriver, (void **)&pSink);
if (FAILED(hrRes))
return(hrRes);
DebugTrace((LPARAM)this, "Calling prepare to shutdown on sinks ...");
hrRes = pSink->PrepareForShutdown(0);
pSink->Release();
hrRes = S_OK;
}
break;
case SMTP_STOREDRV_SHUTDOWN_EVENT:
{
ISMTPStoreDriver *pSink;
hrRes = punkObject->QueryInterface(IID_ISMTPStoreDriver, (void **)&pSink);
if (FAILED(hrRes))
return(hrRes);
DebugTrace((LPARAM)this, "Calling shutdown on sinks ...");
hrRes = pSink->Shutdown(0);
pSink->Release();
hrRes = S_OK;
}
break;
case SMTP_STOREDRV_ENUMMESS_EVENT:
{
ISMTPStoreDriver *pSink;
hrRes = punkObject->QueryInterface(IID_ISMTPStoreDriver, (void **)&pSink);
if (FAILED(hrRes))
return(hrRes);
DebugTrace((LPARAM)this, "Calling Enumerate on sinks ...");
hrRes = pSink->EnumerateAndSubmitMessages(NULL);
pSink->Release();
hrRes = S_OK;
}
break;
default:
DebugTrace((LPARAM)this, "Invalid sink interface");
hrRes = E_NOINTERFACE;
}
TraceFunctLeaveEx((LPARAM)this);
return(hrRes);
}
//+------------------------------------------------------------
//
// Function: CStoreDispatcher::CStoreParams::CallDefault
//
// Synopsis: CStoreDispatcher::Dispatcher will call this routine when
// the default sink priority has been reached.
//
// Arguments: NONE
//
// Returns:
// S_OK: Success
//
// History:
// jstamerj 980611 14:19:57: Created.
//
//-------------------------------------------------------------
HRESULT CStoreDispatcher::CStoreParams::CallDefault()
{
return S_OK;
}
//+------------------------------------------------------------
//
// Function: CStoreDriver::CStoreParams::CallCompletion
//
// Synopsis: The dispatcher will call this routine after all sinks
// have been called
//
// Arguments:
// hrStatus: Status server event sinks have returned
//
// Returns:
// S_OK: Success
//
// History:
// jstamerj 980611 14:17:51: Created.
//
//-------------------------------------------------------------
HRESULT CStoreDispatcher::CStoreParams::CallCompletion(HRESULT hrStatus) {
// call the caller's completion method if there is one
IMailMsgNotify *pNotify = (IMailMsgNotify *) (m_pContext->m_pNotify);
if (pNotify) {
pNotify->Notify(m_pContext->hr);
pNotify->Release();
}
// do the normal call completion work
CStoreBaseParams::CallCompletion(hrStatus);
return S_OK;
}
//
// call the child object
//
HRESULT CStoreDispatcher::CStoreAllocParams::CallObject(CBinding& bBinding, IUnknown *punkObject)
{
HRESULT hrRes = S_OK;
#if 0
IMailMsgStoreDriver *pStoreDriver = NULL;
IMailMsgProperties *pMsg = NULL;
IMailMsgPropertyStream *pStream = NULL;
IMailMsgBindATQ *pBindInterface = NULL;
CLSID clsidMailMsg;
TraceFunctEnterEx((LPARAM)this, "CStoreDispatcher::CStoreAllocParams::CallObject");
hrRes = CLSIDFromProgID(MAILMSG_PROGID, &clsidMailMsg);
if (FAILED(hrRes))
{
DebugTrace((LPARAM)this, "CoCreateInstance IID_IMailMsgProperties failed, %X", hrRes);
return(hrRes);
}
// Create a new MailMsg
hrRes = CoCreateInstance(
clsidMailMsg,
NULL,
CLSCTX_INPROC_SERVER,
IID_IMailMsgProperties,
(LPVOID *)&pMsg);
if (FAILED(hrRes))
{
DebugTrace((LPARAM)this, "CoCreateInstance IID_IMailMsgProperties failed, %X", hrRes);
return(hrRes);
}
hrRes = punkObject->QueryInterface(IID_IMailMsgStoreDriver, (void **)&pStoreDriver);
if (FAILED(hrRes))
{
DebugTrace((LPARAM)this, "QueryInterface() on IID_IMailMsgStoreDriver failed, %X", hrRes);
goto Exit;
}
// Allocate a new message
hrRes = pStoreDriver->AllocMessage(
pMsg,
NULL,
&pStream,
&m_hContent,
NULL);
if (FAILED(hrRes))
{
DebugTrace((LPARAM)this, "pDriver->AllocMessage failed, %X", hrRes);
goto Exit;
}
hrRes = pMsg->QueryInterface(IID_IMailMsgBindATQ, (void **)&pBindInterface);
if (FAILED(hrRes))
{
DebugTrace((LPARAM)this, "QueryInterface() on IID_IMailMsgStoreDriver failed, %X", hrRes);
goto Exit;
}
hrRes = pBindInterface->SetATQInfo (NULL, NULL, NULL, INFINITE, NULL);
if (FAILED(hrRes))
{
DebugTrace((LPARAM)this, "QueryInterface() on IID_IMailMsgStoreDriver failed, %X", hrRes);
goto Exit;
}
Exit:
if(pStoreDriver)
{
pStoreDriver->Release();
}
if(pMsg)
{
pMsg->Release();
}
if(pBindInterface)
{
pBindInterface->Release();
}
TraceFunctLeaveEx((LPARAM)this);
#endif
return(hrRes);
}
#if 0
HRESULT STDMETHODCALLTYPE CStoreDispatcher::OnEvent(REFIID iidEvent,
DWORD dwEventType,
LPVOID pvContext)
{
HRESULT hr = S_OK;
// create the params object, and pass it into the dispatcher
CStoreParams ServerParams;
ServerParams.Init(dwEventType, pvContext);
hr = Dispatcher(iidEvent, &ServerParams);
return hr;
}
#endif
//+------------------------------------------------------------
//
// Function: CStoreDispatcher::OnEvent
//
// Synopsis: Prepares for server event
//
// Arguments:
// iidEvent: guid for event
// dwEventType: specifies the event
// pvContext: context for the params object
//
// Returns:
// S_OK: Success
//
// History:
// jstamerj 980616 13:27:55: Created.
//
//-------------------------------------------------------------
HRESULT STDMETHODCALLTYPE CStoreDispatcher::OnEvent(
REFIID iidEvent,
DWORD dwEventType,
LPVOID pvContext)
{
HRESULT hr;
IMailTransportNotify *pINotify = NULL;
//
// Call into ATL internals to get the interface we need to pass out
//
hr = _InternalQueryInterface(
IID_IMailTransportNotify,
(LPVOID *)&pINotify);
if(FAILED(hr))
return hr;
//
// create the CParams object on the heap -- the object will be
// needed after this call may be out of here (when a sink returns
// MAILTRANSPORT_S_PENDING and there are more sinks to call)
//
CStoreBaseParams *pCParams;
hr = CreateCParams(
dwEventType,
pvContext,
pINotify,
iidEvent,
&pCParams);
//
// The params object should addref pINotify
//
pINotify->Release();
if(FAILED(hr))
return hr;
//
// Start calling sinks
//
hr = Dispatcher(iidEvent, pCParams);
return hr;
}
//+------------------------------------------------------------
//
// Function: GuidForEvent
//
// Synopsis: Given dwEventType, return the appropriate GUID for the
// event binding
//
// Arguments:
// dwEventType: type of SMTP event
//
// Returns:
// REFIID of GUID for the event
//
// History:
// jstamerj 980610 18:24:24: Created.
//
//-------------------------------------------------------------
REFIID GuidForEvent(DWORD dwEventType)
{
switch(dwEventType) {
case SMTP_MAIL_DROP_EVENT:
case SMTP_STOREDRV_ENUMMESS_EVENT:
case SMTP_STOREDRV_DELIVERY_EVENT:
case SMTP_STOREDRV_ALLOC_EVENT:
case SMTP_STOREDRV_STARTUP_EVENT:
case SMTP_STOREDRV_PREPSHUTDOWN_EVENT:
case SMTP_STOREDRV_SHUTDOWN_EVENT:
default:
return CATID_SMTP_STORE_DRIVER;
case SMTP_MAILTRANSPORT_SUBMISSION_EVENT:
return CATID_SMTP_TRANSPORT_SUBMISSION;
case SMTP_MAILTRANSPORT_PRECATEGORIZE_EVENT:
return CATID_SMTP_TRANSPORT_PRECATEGORIZE;
case SMTP_MAILTRANSPORT_CATEGORIZE_REGISTER_EVENT:
case SMTP_MAILTRANSPORT_CATEGORIZE_BEGIN_EVENT:
case SMTP_MAILTRANSPORT_CATEGORIZE_END_EVENT:
case SMTP_MAILTRANSPORT_CATEGORIZE_BUILDQUERY_EVENT:
case SMTP_MAILTRANSPORT_CATEGORIZE_BUILDQUERIES_EVENT:
case SMTP_MAILTRANSPORT_CATEGORIZE_SENDQUERY_EVENT:
case SMTP_MAILTRANSPORT_CATEGORIZE_SORTQUERYRESULT_EVENT:
case SMTP_MAILTRANSPORT_CATEGORIZE_PROCESSITEM_EVENT:
case SMTP_MAILTRANSPORT_CATEGORIZE_EXPANDITEM_EVENT:
case SMTP_MAILTRANSPORT_CATEGORIZE_COMPLETEITEM_EVENT:
return CATID_SMTP_TRANSPORT_CATEGORIZE;
case SMTP_MAILTRANSPORT_POSTCATEGORIZE_EVENT:
return CATID_SMTP_TRANSPORT_POSTCATEGORIZE;
case SMTP_MAILTRANSPORT_GET_ROUTER_FOR_MESSAGE_EVENT:
return CATID_SMTP_TRANSPORT_ROUTER;
case SMTP_MSGTRACKLOG_EVENT:
return CATID_SMTP_MSGTRACKLOG;
case SMTP_DNSRESOLVERRECORDSINK_EVENT:
return CATID_SMTP_DNSRESOLVERRECORDSINK;
case SMTP_MAXMSGSIZE_EVENT:
return CATID_SMTP_MAXMSGSIZE;
case SMTP_LOG_EVENT:
return CATID_SMTP_LOG;
case SMTP_GET_AUX_DOMAIN_INFO_FLAGS_EVENT:
return CATID_SMTP_GET_AUX_DOMAIN_INFO_FLAGS;
}
}
//
// this function performs instance level server events registration
//
HRESULT RegisterPlatSEOInstance(DWORD dwInstanceID)
{
HRESULT hr;
//
// find the SMTP source type in the event manager
//
CComPtr<IEventManager> pEventManager;
hr = CoCreateInstance(CLSID_CEventManager, NULL, CLSCTX_ALL,
IID_IEventManager, (LPVOID *) &pEventManager);
if (hr != S_OK)
return hr;
CComPtr<IEventSourceTypes> pSourceTypes;
hr = pEventManager->get_SourceTypes(&pSourceTypes);
if (FAILED(hr))
return hr;
CComPtr<IEventSourceType> pSourceType;
CComBSTR bstrSourceTypeGUID = (LPCOLESTR) CStringGUID(GUID_SMTP_SOURCE_TYPE);
hr = pSourceTypes->Item(&CComVariant(bstrSourceTypeGUID), &pSourceType);
_ASSERT(hr != S_OK || pSourceType != NULL);
if (hr != S_OK)
return hr;
//
// generate a GUID for this source, which is based on GUID_SMTPSVC
// mangled by the instance ID
//
CComPtr<IEventUtil> pEventUtil;
hr = CoCreateInstance(CLSID_CEventUtil, NULL, CLSCTX_ALL,
IID_IEventUtil, (LPVOID *) &pEventUtil);
if (hr != S_OK)
return hr;
CComBSTR bstrSMTPSvcGUID = (LPCOLESTR) CStringGUID(GUID_SMTPSVC_SOURCE);
CComBSTR bstrSourceGUID;
hr = pEventUtil->GetIndexedGUID(bstrSMTPSvcGUID, dwInstanceID, &bstrSourceGUID);
if (FAILED(hr))
return hr;
//
// see if this source is registered with the list of sources for the
// SMTP source type
//
CComPtr<IEventSources> pEventSources;
hr = pSourceType->get_Sources(&pEventSources);
if (FAILED(hr))
return hr;
CComPtr<IEventSource> pEventSource;
hr = pEventSources->Item(&CComVariant(bstrSourceGUID), &pEventSource);
if (FAILED(hr))
return hr;
//
// if the source guid doesn't exist then we need to register a new
// source for the SMTP source type and add directory drop as a binding
//
if (hr == S_FALSE)
{
// register the SMTPSvc source
hr = pEventSources->Add(bstrSourceGUID, &pEventSource);
if (FAILED(hr))
return hr;
char szSourceDisplayName[50];
_snprintf(szSourceDisplayName, 50, "smtpsvc %lu", dwInstanceID);
CComBSTR bstrSourceDisplayName = szSourceDisplayName;
hr = pEventSource->put_DisplayName(bstrSourceDisplayName);
if (FAILED(hr))
return hr;
// create the event database for this source
CComPtr<IEventDatabaseManager> pDatabaseManager;
hr = CoCreateInstance(CLSID_CEventMetabaseDatabaseManager, NULL, CLSCTX_ALL,
IID_IEventDatabaseManager, (LPVOID *) &pDatabaseManager);
if (hr != S_OK)
return hr;
CComBSTR bstrEventPath;
CComBSTR bstrService = "smtpsvc";
hr = pDatabaseManager->MakeVServerPath(bstrService, dwInstanceID, &bstrEventPath);
if (FAILED(hr))
return hr;
CComPtr<IUnknown> pDatabaseMoniker;
hr = pDatabaseManager->CreateDatabase(bstrEventPath, &pDatabaseMoniker);
if (FAILED(hr))
return hr;
hr = pEventSource->put_BindingManagerMoniker(pDatabaseMoniker);
if (FAILED(hr))
return hr;
// save everything we've done so far
hr = pEventSource->Save();
if (FAILED(hr))
return hr;
hr = pSourceType->Save();
if (FAILED(hr))
return hr;
}
return S_OK;
}
//
// this function performs instance level unregistration
//
HRESULT UnregisterPlatSEOInstance(DWORD dwInstanceID)
{
HRESULT hr = S_OK;
//
// find the SMTP source type in the event manager
//
CComPtr<IEventManager> pEventManager;
hr = CoCreateInstance(CLSID_CEventManager, NULL, CLSCTX_ALL,
IID_IEventManager, (LPVOID *) &pEventManager);
if (hr != S_OK)
return hr;
CComPtr<IEventSourceTypes> pSourceTypes;
hr = pEventManager->get_SourceTypes(&pSourceTypes);
if (FAILED(hr))
return hr;
CComPtr<IEventSourceType> pSourceType;
CComBSTR bstrSourceTypeGUID = (LPCOLESTR) CStringGUID(GUID_SMTP_SOURCE_TYPE);
hr = pSourceTypes->Item(&CComVariant(bstrSourceTypeGUID), &pSourceType);
_ASSERT(hr != S_OK || pSourceType != NULL);
if (hr != S_OK)
return hr;
//
// generate a GUID for this source, which is based on GUID_SMTPSVC
// mangled by the instance ID
//
CComPtr<IEventUtil> pEventUtil;
hr = CoCreateInstance(CLSID_CEventUtil, NULL, CLSCTX_ALL,
IID_IEventUtil, (LPVOID *) &pEventUtil);
if (hr != S_OK)
return hr;
CComBSTR bstrSMTPSvcGUID = (LPCOLESTR) CStringGUID(GUID_SMTPSVC_SOURCE);
CComBSTR bstrSourceGUID;
hr = pEventUtil->GetIndexedGUID(bstrSMTPSvcGUID, dwInstanceID, &bstrSourceGUID);
if (FAILED(hr))
return hr;
//
// remove this source from the list of registered sources
//
CComPtr<IEventSources> pEventSources;
hr = pSourceType->get_Sources(&pEventSources);
if (FAILED(hr))
return hr;
CComPtr<IEventSource> pEventSource;
hr = pEventSources->Remove(&CComVariant(bstrSourceGUID));
if (FAILED(hr))
return hr;
return S_OK;
}
//+------------------------------------------------------------
//
// Function: CStoreDispatcher::Dispatcher
//
// Synopsis: Override the default functionality in seolib.cpp to
// provide some extra features (default functionality
//
// Arguments:
// rguidEventType: Guid specifying a server event
// pParams: CStoreBaseParams -- contains async info
//
// Returns:
// S_OK: Success, at least one sink called
// S_FALSE: No sinks were called
// otherwise error from CallObject
//
// History:
// jstamerj 980603 19:23:06: Created.
//
//-------------------------------------------------------------
HRESULT STDMETHODCALLTYPE CStoreDispatcher::Dispatcher(
REFIID rguidEventType,
CStoreBaseParams *pParams)
{
TraceFunctEnterEx((LPARAM)this, "CStoreDispatcher::Dispatcher");
_ASSERT(pParams);
//
// This code based on %STAXPT%\src\core\seo\lib\seolib.cpp
//
HRESULT hrRes = S_OK;
CETData *petdData;
BOOL bObjectCalled = (pParams->m_dwIdx_SinkSkip > 0);
//
// AddRef pParams here, release at the end of the function
// This way, if a sink returns MAILTRANSPORT_S_PENDING and does
// async completion before this function exits, we wont AV
// accessing pParams
//
pParams->AddRef();
petdData = m_Data.Find(rguidEventType);
if (pParams->m_dwIdx_SinkSkip != SKIPSINK_CALL_NO_MORE_SINKS) {
if(petdData) {
for(DWORD dwIdx = pParams->m_dwIdx_SinkSkip;
dwIdx < petdData->Count();
dwIdx++) {
if(!petdData->Index(dwIdx)->m_bIsValid) {
continue;
}
if(bObjectCalled && petdData->Index(dwIdx)->m_bExclusive) {
continue;
}
if(pParams->Abort() == S_OK) {
break;
}
//
// Call default processing method if the priority of the sink
// we're looking at is less than default priority
//
if((pParams->m_fDefaultProcessingCalled == FALSE) &&
(petdData->Index(dwIdx)->m_dwPriority >
SMTP_TRANSPORT_DEFAULT_PRIORITY)) {
// This is needed so we don't call the default
// processing again if the default processing returns
// MAILTRANSPORT_S_PENDING (and we reenter Dispatcher)
pParams->m_fDefaultProcessingCalled = TRUE;
//
// Set the correct index in our async structure -- our
// current index.
//
pParams->m_dwIdx_SinkSkip = dwIdx;
hrRes = pParams->CallDefault();
if((hrRes == MAILTRANSPORT_S_PENDING) ||
(hrRes == S_FALSE)) {
break;
}
}
//
// Now proceed with calling a real sink
//
hrRes = pParams->CheckRule(*petdData->Index(dwIdx));
if(hrRes == S_OK) {
if(pParams->Abort() == S_OK) {
break;
}
//
// jstamerj 980603 19:37:17: Set the correct index in our
// async structure -- this index plus one to skip the
// sink we are about to call
//
pParams->m_dwIdx_SinkSkip = dwIdx+1;
hrRes = pParams->CallObject(
m_piEventManager,
*petdData->Index(dwIdx));
if(!SUCCEEDED(hrRes)) {
continue;
}
bObjectCalled = TRUE;
if((hrRes == MAILTRANSPORT_S_PENDING) ||
(hrRes == S_FALSE) ||
(petdData->Index(dwIdx)->m_bExclusive)) {
break;
}
}
}
}
//
// It is possible we haven't called our default processing sink
// yet. Check for this case here. Make sure that a sink above in
// the loop isn't indicating async completion or skip (PENDING or
// S_FALSE)
//
if((pParams->m_fDefaultProcessingCalled == FALSE) &&
(hrRes != MAILTRANSPORT_S_PENDING) &&
(hrRes != S_FALSE)) {
// Make sure we don't call default again on async completion...
pParams->m_fDefaultProcessingCalled = TRUE;
//
// Set the index in our async structure so we don't reenter
// the above loop on async completion
//
pParams->m_dwIdx_SinkSkip = (petdData ? petdData->Count() : 0);
hrRes = pParams->CallDefault();
}
} else {
// bObjectCalled should always be set if SKIPSINK_CALL_NO_MORE_SINKS
// was set
_ASSERT(bObjectCalled);
}
if(hrRes != MAILTRANSPORT_S_PENDING) {
//
// It is time to call the completion processing
//
hrRes = pParams->CallCompletion(bObjectCalled ? S_OK : S_FALSE);
if(FAILED(hrRes)) {
goto CLEANUP;
}
hrRes = (bObjectCalled) ? S_OK : S_FALSE;
}
CLEANUP:
pParams->Release();
DebugTrace((LPARAM)this, "returning hr %08lx", hrRes);
TraceFunctLeaveEx((LPARAM)this);
return hrRes;
}
//+------------------------------------------------------------
//
// Function: CStoreDispatcher::Notify
//
// Synopsis: Handles async completions of sinks
//
// Arguments: pvContext - context passed into sink
//
// Returns:
// S_OK: Success
// E_INVALIDARG:
//
// History:
// jstamerj 980608 15:50:57: Created.
//
//-------------------------------------------------------------
HRESULT STDMETHODCALLTYPE CStoreDispatcher::Notify(
HRESULT hrStatus,
PVOID pvContext)
{
TraceFunctEnterEx((LPARAM)this, "CStoreDispatcher::Notify");
_ASSERT(pvContext);
if((pvContext == NULL) ||
IsBadReadPtr(
pvContext,
sizeof(CStoreBaseParams))) {
ErrorTrace((LPARAM)this, "Sink called Notify with bogus pvContext");
return E_INVALIDARG;
}
CStoreBaseParams *pParams = (CStoreBaseParams *)pvContext;
if(FAILED(pParams->CheckSignature())) {
ErrorTrace((LPARAM)this, "Sink called Notify with invalid pvContext");
return E_INVALIDARG;
}
//
// Release the sink that called us
// m_pIUnknownSink could be NULL if default processing returned pending
//
if(pParams->m_pIUnknownSink) {
pParams->m_pIUnknownSink->Release();
pParams->m_pIUnknownSink = NULL;
}
if (hrStatus == S_FALSE) {
// prevent the dispatcher from calling any more sinks.
pParams->m_dwIdx_SinkSkip = SKIPSINK_CALL_NO_MORE_SINKS;
}
Dispatcher(pParams->m_rguidEventType, pParams);
TraceFunctLeaveEx((LPARAM)this);
return S_OK;
}
//+------------------------------------------------------------
//
// Function: CStoreDispatcher::CStoreBaseParams::Notify
//
// Synopsis: Handles async completions of sinks using mailmsg notify
//
// Arguments: hrStatus - hresult from async operation
//
// Returns:
// S_OK: Success
// E_INVALIDARG:
//
// History:
// jstamerj 980608 15:50:57: Created.
//
//-------------------------------------------------------------
HRESULT STDMETHODCALLTYPE CStoreDispatcher::CStoreParams::Notify(
HRESULT hrStatus)
{
TraceFunctEnter("CStoreDispatcher::CStoreBaseParams::Notify");
//
// Release the sink that called us
// m_pIUnknownSink could be NULL if default processing returned pending
//
if(m_pIUnknownSink) {
m_pIUnknownSink->Release();
m_pIUnknownSink = NULL;
}
// this guy can either be STOREDRV_E_RETRY or S_OK. If he was ever
// set to STOREDRV_E_RETRY then we shouldn't be getting back to this
// point in the code because we never would have called another sink
_ASSERT(m_pContext->hr == S_OK);
if (hrStatus == STOREDRV_E_RETRY) {
DebugTrace((LPARAM)this, "Sink returned STOREDRV_E_RETRY on LocalDelivery");
m_pContext->hr = hrStatus;
hrStatus = S_FALSE;
}
if (hrStatus == S_FALSE) {
// prevent the dispatcher from calling any more sinks.
m_dwIdx_SinkSkip = SKIPSINK_CALL_NO_MORE_SINKS;
}
m_pDispatcher->Dispatcher(m_rguidEventType, this);
TraceFunctLeaveEx((LPARAM)this);
return S_OK;
}
//
// CMailTransportSubmissionParams:
//
//+------------------------------------------------------------
//
// Function: CStoreDispatcher::CMailTransportSubmissionParams::CallObject
//
// Synopsis: Create and call the child object
//
// Arguments:
// CBinding
// punkObject
//
// Returns:
// S_OK: Success
//
// History:
// jstamerj 980610 19:04:59: Created.
//
//-------------------------------------------------------------
HRESULT CStoreDispatcher::CMailTransportSubmissionParams::CallObject(
CBinding& bBinding,
IUnknown *punkObject)
{
HRESULT hrRes = S_OK;
TraceFunctEnterEx((LPARAM)this, "CStoreDispatcher::CMailTransportSubmissionParams::CallObject");
_ASSERT(m_dwEventType == SMTP_MAILTRANSPORT_SUBMISSION_EVENT);
IMailTransportSubmission *pSink;
hrRes = punkObject->QueryInterface(IID_IMailTransportSubmission,
(PVOID *)&pSink);
if(hrRes == E_NOINTERFACE) {
//
// See if we can get the interfaces we need for a CDO sink
//
hrRes = CallCDOSink(punkObject);
//
// Success or failure, return here
//
TraceFunctLeaveEx((LPARAM)this);
return hrRes;
} else if(FAILED(hrRes)) {
TraceFunctLeaveEx((LPARAM)this);
return(hrRes);
}
//
// Remember the sink so we can release this sink later if it
// returns pending
//
_ASSERT(m_pIUnknownSink == NULL);
m_pIUnknownSink = (IUnknown*)pSink;
m_pIUnknownSink->AddRef();
DebugTrace((LPARAM)this, "Calling submission event on this sink");
hrRes = pSink->OnMessageSubmission(
m_Context.pIMailMsgProperties,
m_pINotify,
(PVOID)this);
//
// We are done with pSink so release it
// In case of async completion, we hold a reference to the sink in
// m_pIUnknownSink
//
pSink->Release();
if(hrRes != MAILTRANSPORT_S_PENDING) {
//
// We completed synchronously, so release the sink
//
m_pIUnknownSink->Release();
m_pIUnknownSink = NULL;
}
TraceFunctLeaveEx((LPARAM)this);
return(hrRes);
}
//+------------------------------------------------------------
//
// Function: CStoreDispatcher::CMailTransportSubmissionParams::CallCDOSink
//
// Synopsis: Call the CDO Sink
//
// Arguments:
// pSink: IUnknown of the sink
//
// Returns:
// S_OK: Success
//
// History:
// jstamerj 1998/07/02 10:31:47: Created.
//
//-------------------------------------------------------------
HRESULT CStoreDispatcher::CMailTransportSubmissionParams::CallCDOSink(
IUnknown *pSink)
{
TraceFunctEnterEx((LPARAM)this, "CStoreDispatcher::CMailTransportSubmissionParams::CallCDOSink");
_ASSERT(pSink);
HRESULT hr;
ISMTPOnArrival *pCDOSink = NULL;
IConstructIMessageFromIMailMsg *pIConstruct = NULL;
CdoEventStatus eStatus = cdoRunNextSink;
hr = pSink->QueryInterface(IID_ISMTPOnArrival,
(PVOID *)&pCDOSink);
if(FAILED(hr))
goto CLEANUP;
if(m_pCDOMessage == NULL) {
//
// Yay. Create a CDO message
//
hr = CoCreateInstance(
CLSID_Message,
NULL,
CLSCTX_INPROC_SERVER,
IID_IMessage,
(LPVOID *)&m_pCDOMessage);
if(FAILED(hr))
goto CLEANUP;
//
// Fill in properties based on MailMsg
//
hr = m_pCDOMessage->QueryInterface(
IID_IConstructIMessageFromIMailMsg,
(LPVOID *)&pIConstruct);
if(FAILED(hr)) {
m_pCDOMessage->Release();
m_pCDOMessage = NULL;
goto CLEANUP;
}
hr = pIConstruct->Construct(
cdoSMTPOnArrival,
m_Context.pIMailMsgProperties);
if(FAILED(hr)) {
m_pCDOMessage->Release();
m_pCDOMessage = NULL;
goto CLEANUP;
}
}
//
// Call the sink
//
hr = pCDOSink->OnArrival(
m_pCDOMessage,
&eStatus);
CLEANUP:
//
// Release interfaces
//
if(pIConstruct)
pIConstruct->Release();
if(pCDOSink)
pCDOSink->Release();
DebugTrace((LPARAM)this, "CallCDOSink returning hr %08lx eStatus %d", hr, eStatus);
TraceFunctLeaveEx((LPARAM)this);
return FAILED(hr) ? hr :
((eStatus == cdoSkipRemainingSinks) ? S_FALSE : S_OK);
}
//+------------------------------------------------------------
//
// Function: CStoreDispatcher::CMailTransportSubmissionParams
//
// Synopsis: The dispatcher will call this routine when it the default
// sink processing priority is reached
//
// Arguments: NONE
//
// Returns:
// S_OK: Success, continueing calling sinks
// S_FALSE: Stop calling sinks
// MAILTRANSPORT_S_PENDING: Will call IMailTransportNotify::Notify
// when we are done.
//
// History:
// jstamerj 980611 14:15:43: Created.
//
//-------------------------------------------------------------
HRESULT CStoreDispatcher::CMailTransportSubmissionParams::CallDefault()
{
//
// No sinks need default processing yet..
//
return S_OK;
}
//+------------------------------------------------------------
//
// Function: CStoreDriver::CMailTransportSubmissionParams::CallCompletion
//
// Synopsis: The dispatcher will call this routine after all sinks
// have been called
//
// Arguments:
// hrStatus: Status server event sinks have returned
//
// Returns:
// S_OK: Success
//
// History:
// jstamerj 980611 14:17:51: Created.
//
//-------------------------------------------------------------
HRESULT CStoreDispatcher::CMailTransportSubmissionParams::CallCompletion(
HRESULT hrStatus)
{
_ASSERT(m_dwEventType == SMTP_MAILTRANSPORT_SUBMISSION_EVENT);
(*m_Context.pfnCompletion)(hrStatus, &m_Context);
CStoreBaseParams::CallCompletion(hrStatus);
return S_OK;
}
//+------------------------------------------------------------
//
// Function: CStoreDispatcher::CMailTransportSubmissionParams::CheckRule
//
// Synopsis: Check to see if this sink should be called or not
//
// Arguments:
// bBinding: CBinding object for this sink
//
// Returns:
// S_OK: Success, call the sink
// S_FALSE: Success, do not call the sink
// or error from mailmsg (sink will not be called)
//
// History:
// jstamerj 1999/01/12 16:55:29: Created.
//
//-------------------------------------------------------------
HRESULT CStoreDispatcher::CMailTransportSubmissionParams::CheckRule(
CBinding &bBinding)
{
HRESULT hr;
TraceFunctEnterEx((LPARAM)this,
"CStoreDispatcher::CMailTransportSubmissionParams::CheckRule");
//
// Call the generic function to check a mailmsg rule
//
hr = CheckMailMsgRule(
&bBinding,
m_Context.pIMailMsgProperties);
DebugTrace((LPARAM)this, "returning hr %08lx", hr);
TraceFunctLeaveEx((LPARAM)this);
return hr;
}
//
// CMailTransportPreCategorizeParams:
//
//+------------------------------------------------------------
//
// Function: CStoreDispatcher::CMailTransportPreCategorizeParams::CallObject
//
// Synopsis: Create and call the child object
//
// Arguments:
// CBinding
// punkObject
//
// Returns:
// S_OK: Success
//
// History:
// jstamerj 980610 19:04:59: Created.
//
//-------------------------------------------------------------
HRESULT CStoreDispatcher::CMailTransportPreCategorizeParams::CallObject(
CBinding& bBinding,
IUnknown *punkObject)
{
HRESULT hrRes = S_OK;
TraceFunctEnterEx((LPARAM)this, "CStoreDispatcher::CMailTransportPreCategorizeParams::CallObject");
_ASSERT(m_dwEventType == SMTP_MAILTRANSPORT_PRECATEGORIZE_EVENT);
IMailTransportOnPreCategorize *pSink;
hrRes = punkObject->QueryInterface(IID_IMailTransportOnPreCategorize,
(PVOID *)&pSink);
if(FAILED(hrRes))
return(hrRes);
//
// Remember the sink so we can release this sink later if it
// returns pending
//
_ASSERT(m_pIUnknownSink == NULL);
m_pIUnknownSink = (IUnknown*)pSink;
m_pIUnknownSink->AddRef();
DebugTrace((LPARAM)this, "Calling precategorize event on this sink");
hrRes = pSink->OnSyncMessagePreCategorize(
m_Context.pIMailMsgProperties,
m_pINotify,
(PVOID)this);
//
// We are done with pSink so release it
// In case of async completion, we hold a reference to the sink in
// m_pIUnknownSink
//
pSink->Release();
if(hrRes != MAILTRANSPORT_S_PENDING) {
//
// We completed synchronously, so release the sink
//
m_pIUnknownSink->Release();
m_pIUnknownSink = NULL;
}
TraceFunctLeaveEx((LPARAM)this);
return(hrRes);
}
//+------------------------------------------------------------
//
// Function: CStoreDispatcher::CMailTransportPreCategorizeParams
//
// Synopsis: The dispatcher will call this routine when it the default
// sink processing priority is reached
//
// Arguments: NONE
//
// Returns:
// S_OK: Success, continueing calling sinks
// S_FALSE: Stop calling sinks
// MAILTRANSPORT_S_PENDING: Will call IMailTransportNotify::Notify
// when we are done.
//
// History:
// jstamerj 980611 14:15:43: Created.
//
//-------------------------------------------------------------
HRESULT CStoreDispatcher::CMailTransportPreCategorizeParams::CallDefault()
{
//
// No sinks need default processing yet..
//
return S_OK;
}
//+------------------------------------------------------------
//
// Function: CStoreDriver::CMailTransportPreCategorizeParams::CallCompletion
//
// Synopsis: The dispatcher will call this routine after all sinks
// have been called
//
// Arguments:
// hrStatus: Status server event sinks have returned
//
// Returns:
// S_OK: Success
//
// History:
// jstamerj 980611 14:17:51: Created.
//
//-------------------------------------------------------------
HRESULT CStoreDispatcher::CMailTransportPreCategorizeParams::CallCompletion(
HRESULT hrStatus)
{
_ASSERT(m_dwEventType == SMTP_MAILTRANSPORT_PRECATEGORIZE_EVENT);
(*m_Context.pfnCompletion)(hrStatus, &m_Context);
CStoreBaseParams::CallCompletion(hrStatus);
return S_OK;
}
//+------------------------------------------------------------
//
// Function: CStoreDispatcher::CMailTransportPreCategorizeParams::CheckRule
//
// Synopsis: Check to see if this sink should be called or not
//
// Arguments:
// bBinding: CBinding object for this sink
//
// Returns:
// S_OK: Success, call the sink
// S_FALSE: Success, do not call the sink
// or error from mailmsg (sink will not be called)
//
// History:
// jstamerj 1999/01/12 16:59:59: Created
//
//-------------------------------------------------------------
HRESULT CStoreDispatcher::CMailTransportPreCategorizeParams::CheckRule(
CBinding &bBinding)
{
HRESULT hr;
TraceFunctEnterEx((LPARAM)this,
"CStoreDispatcher::CMailTransportPreCategorizeParams::CheckRule");
//
// Call the generic function to check a mailmsg rule
//
hr = CheckMailMsgRule(
&bBinding,
m_Context.pIMailMsgProperties);
DebugTrace((LPARAM)this, "returning hr %08lx", hr);
TraceFunctLeaveEx((LPARAM)this);
return hr;
}
//
// CMailTransportPostCategorizeParams:
//
//+------------------------------------------------------------
//
// Function: CStoreDispatcher::CMailTransportPostCategorizeParams::CallObject
//
// Synopsis: Create and call the child object
//
// Arguments:
// CBinding
// punkObject
//
// Returns:
// S_OK: Success
//
// History:
// jstamerj 980610 19:04:59: Created.
//
//-------------------------------------------------------------
HRESULT CStoreDispatcher::CMailTransportPostCategorizeParams::CallObject(
CBinding& bBinding,
IUnknown *punkObject)
{
HRESULT hrRes = S_OK;
TraceFunctEnterEx((LPARAM)this, "CStoreDispatcher::CMailTransportPostCategorizeParams::CallObject");
_ASSERT(m_dwEventType == SMTP_MAILTRANSPORT_POSTCATEGORIZE_EVENT);
IMailTransportOnPostCategorize *pSink;
hrRes = punkObject->QueryInterface(IID_IMailTransportOnPostCategorize,
(PVOID *)&pSink);
if(FAILED(hrRes))
return(hrRes);
//
// Remember the sink so we can release this sink later if it
// returns pending
//
_ASSERT(m_pIUnknownSink == NULL);
m_pIUnknownSink = (IUnknown*)pSink;
m_pIUnknownSink->AddRef();
DebugTrace((LPARAM)this, "Calling submission event on this sink");
hrRes = pSink->OnMessagePostCategorize(
m_Context.pIMailMsgProperties,
m_pINotify,
(PVOID)this);
//
// We are done with pSink so release it
// In case of async completion, we hold a reference to the sink in
// m_pIUnknownSink
//
pSink->Release();
if(hrRes != MAILTRANSPORT_S_PENDING) {
//
// We completed synchronously, so release the sink
//
m_pIUnknownSink->Release();
m_pIUnknownSink = NULL;
}
TraceFunctLeaveEx((LPARAM)this);
return(hrRes);
}
//+------------------------------------------------------------
//
// Function: CStoreDispatcher::CMailTransportPostCategorizeParams
//
// Synopsis: The dispatcher will call this routine when it the default
// sink processing priority is reached
//
// Arguments: NONE
//
// Returns:
// S_OK: Success, continueing calling sinks
// S_FALSE: Stop calling sinks
// MAILTRANSPORT_S_PENDING: Will call IMailTransportNotify::Notify
// when we are done.
//
// History:
// jstamerj 980611 14:15:43: Created.
//
//-------------------------------------------------------------
HRESULT CStoreDispatcher::CMailTransportPostCategorizeParams::CallDefault()
{
//
// No sinks need default processing yet..
//
return S_OK;
}
//+------------------------------------------------------------
//
// Function: CStoreDriver::CMailTransportPostCategorizeParams::CallCompletion
//
// Synopsis: The dispatcher will call this routine after all sinks
// have been called
//
// Arguments:
// hrStatus: Status server event sinks have returned
//
// Returns:
// S_OK: Success
//
// History:
// jstamerj 980611 14:17:51: Created.
//
//-------------------------------------------------------------
HRESULT CStoreDispatcher::CMailTransportPostCategorizeParams::CallCompletion(
HRESULT hrStatus)
{
_ASSERT(m_dwEventType == SMTP_MAILTRANSPORT_POSTCATEGORIZE_EVENT);
(*m_Context.pfnCompletion)(hrStatus, &m_Context);
CStoreBaseParams::CallCompletion(hrStatus);
return S_OK;
}
//+------------------------------------------------------------
//
// Function: CStoreDispatcher::CMailTransportPostCategorizeParams::CheckRule
//
// Synopsis: Check to see if this sink should be called or not
//
// Arguments:
// bBinding: CBinding object for this sink
//
// Returns:
// S_OK: Success, call the sink
// S_FALSE: Success, do not call the sink
// or error from mailmsg (sink will not be called)
//
// History:
// jstamerj 1999/01/12 17:01:40: Created
//
//-------------------------------------------------------------
HRESULT CStoreDispatcher::CMailTransportPostCategorizeParams::CheckRule(
CBinding &bBinding)
{
HRESULT hr;
TraceFunctEnterEx((LPARAM)this,
"CStoreDispatcher::CMailTransportPostCategorizeParams::CheckRule");
//
// Call the generic function to check a mailmsg rule
//
hr = CheckMailMsgRule(
&bBinding,
m_Context.pIMailMsgProperties);
DebugTrace((LPARAM)this, "returning hr %08lx", hr);
TraceFunctLeaveEx((LPARAM)this);
return hr;
}
//+------------------------------------------------------------
//
// Function: CStoreDispatcher::CRouterCreateOptions::Init
//
// Synopsis: This is called right after we CoCreate any routing sink
// -- so call routing's initialize function (RegisterRouterReset)
//
// Arguments:
// iidDesired: not used
// ppUnkObject: IUnknown of newly created sink object
// IEventBinding: not used
// IUnknown: not used
//
// Returns:
// E_NOTIMPL: Success, please do the regular Init thing
// otherwise error from QI or sink function
//
// History:
// jstamerj 1998/07/10 18:09:04: Created.
//
//-------------------------------------------------------------
HRESULT STDMETHODCALLTYPE CStoreDispatcher::CRouterCreateOptions::Init(
REFIID iidDesired,
IUnknown **ppUnkObject,
IEventBinding *,
IUnknown *)
{
TraceFunctEnterEx((LPARAM)this, "CStoreDispatcher::CRouterCreateOptions::Init");
IMailTransportSetRouterReset *pSink = NULL;
HRESULT hr;
hr = (*ppUnkObject)->QueryInterface(
IID_IMailTransportSetRouterReset,
(PVOID *)&pSink);
if(hr == E_NOINTERFACE) {
//
// It's okay; this sink just doesn't care about hooking
// the router reset interface
//
DebugTrace((LPARAM)this, "Router sink doesn't support IMailTransportSetRouterReset");
TraceFunctLeaveEx((LPARAM)this);
return E_NOTIMPL;
} else if(FAILED(hr)) {
ErrorTrace((LPARAM)this,
"QI for IMailTransportSetRouterReset failed with hr %08lx", hr);
TraceFunctLeaveEx((LPARAM)this);
return hr;
}
DebugTrace((LPARAM)this, "Calling RegisterRouterReset event onSink");
hr = pSink->RegisterResetInterface(
m_pContext->dwVirtualServerID,
m_pContext->pIRouterReset);
pSink->Release();
if(FAILED(hr) && (hr != E_NOTIMPL)) {
//
// A real failure occured
//
ErrorTrace((LPARAM)this, "RegisterResetInterface failed with hr %08lx", hr);
return hr;
}
//
// Return E_NOTIMPL so the real work of Init will be done
//
return E_NOTIMPL;
}
//
// CMailTransportRoutingParams:
//
//+------------------------------------------------------------
//
// Function: CStoreDispatcher::CMailTransportRouterParams::CallObject
//
// Synopsis: Creates (if necessary) and calls the sink object
//
// Arguments:
// pManager: IEventManager passed in from dispatcher
// bBinding: CBinding for this event
//
// Returns:
// S_OK: Success
// E_POINTER: bad pManager
// or error from CreateSink/CallObject
//
// History:
// jstamerj 1998/07/10 18:15:09: Created.
//
//-------------------------------------------------------------
//
// create and call the child object
//
HRESULT CStoreDispatcher::CMailTransportRouterParams::CallObject(
IEventManager *pManager,
CBinding& bBinding)
{
CRouterCreateOptions opt (m_pContext);
CComPtr<IUnknown> pUnkSink;
HRESULT hr;
TraceFunctEnterEx((LPARAM)this, "CStoreDispatcher::CMailTransportRotuerParams::CallObject");
if (pManager == NULL) {
ErrorTrace((LPARAM)this, "Invalid (NULL) pManager");
TraceFunctLeaveEx((LPARAM)this);
return (E_POINTER);
}
hr = pManager->CreateSink(bBinding.m_piBinding,&opt,&pUnkSink);
if (FAILED(hr)) {
ErrorTrace((LPARAM)this, "CreateSink returned error hr %08lx",
hr);
TraceFunctLeaveEx((LPARAM)this);
return hr;
}
hr = CallObject(bBinding,pUnkSink);
DebugTrace((LPARAM)this, "CallObject child returned error %08lx", hr);
TraceFunctLeaveEx((LPARAM)this);
return hr;
}
//+------------------------------------------------------------
//
// Function: CStoreDispatcher::CMailTransportRoutingParams::CallObject
//
// Synopsis: Create and call the child object
//
// Arguments:
// CBinding
// punkObject
//
// Returns:
// Error from QI or return code from sink function
//
// History:
// jstamerj 980610 19:04:59: Created.
//
//-------------------------------------------------------------
HRESULT CStoreDispatcher::CMailTransportRouterParams::CallObject(
CBinding& bBinding,
IUnknown *punkObject)
{
HRESULT hrRes = S_OK;
IMailTransportRoutingEngine *pSink;
IMessageRouter *pIMessageRouterNew = NULL;
TraceFunctEnterEx((LPARAM)this, "CStoreDispatcher::CMailTransportRouterParams::CallObject");
_ASSERT(m_dwEventType == SMTP_MAILTRANSPORT_GET_ROUTER_FOR_MESSAGE_EVENT);
//
// If they pass in a pIMailMsgProperties of NULL it means that they
// just want to create a router object, but not actually do the
// get message router call.
//
if (m_pContext->pIMailMsgProperties == NULL) {
DebugTrace((LPARAM) this, "Skipping GetMessageRouter call");
TraceFunctLeaveEx((LPARAM)this);
return S_OK;
}
hrRes = punkObject->QueryInterface(IID_IMailTransportRoutingEngine,
(PVOID *)&pSink);
if(FAILED(hrRes))
return(hrRes);
DebugTrace((LPARAM)this, "Calling GetMessageRouter event on this sink");
hrRes = pSink->GetMessageRouter(
m_pContext->pIMailMsgProperties,
m_pContext->pIMessageRouter,
&(pIMessageRouterNew));
//
// This sink is not allowed to complete async
//
_ASSERT(hrRes != MAILTRANSPORT_S_PENDING);
//
// We are done with pSink so release it
//
pSink->Release();
//
// If GetMessageRouter succeeded AND it returned a new
// IMessageRouter, release the old one and save the new one.
//
if(SUCCEEDED(hrRes) && (pIMessageRouterNew != NULL)) {
if(m_pContext->pIMessageRouter) {
m_pContext->pIMessageRouter->Release();
}
m_pContext->pIMessageRouter = pIMessageRouterNew;
}
DebugTrace((LPARAM)this, "Sink GetMessageRouter returned hr %08lx", hrRes);
TraceFunctLeaveEx((LPARAM)this);
return(hrRes);
}
//+------------------------------------------------------------
//
// Function: CStoreDispatcher::CMailTransportRouterParams
//
// Synopsis: The dispatcher will call this routine when it the default
// sink processing priority is reached
//
// Arguments: NONE
//
// Returns:
// S_OK: Success, continueing calling sinks
// S_FALSE: Stop calling sinks
//
// History:
// jstamerj 980611 14:15:43: Created.
//
//-------------------------------------------------------------
HRESULT CStoreDispatcher::CMailTransportRouterParams::CallDefault()
{
HRESULT hrRes;
IMessageRouter *pIMessageRouterNew = NULL;
TraceFunctEnterEx((LPARAM)this, "CStoreDispatcher::CMailTransportRouterParams::CallDefault");
_ASSERT(m_dwEventType == SMTP_MAILTRANSPORT_GET_ROUTER_FOR_MESSAGE_EVENT);
if (m_pContext->pIMailMsgProperties == NULL) {
DebugTrace((LPARAM) this, "Skipping GetMessageRouter call");
TraceFunctLeaveEx((LPARAM)this);
return S_OK;
}
//
// Call the default IMailTransportRoutingEngine (CatMsgQueue)
// just like any other sink except SEO didn't CoCreate it for us
//
DebugTrace((LPARAM)this, "Calling GetMessageRouter event on default sink");
hrRes = m_pContext->pIRoutingEngineDefault->GetMessageRouter(
m_pContext->pIMailMsgProperties,
m_pContext->pIMessageRouter,
&pIMessageRouterNew);
//
// This sink is not allowed to complete async
//
_ASSERT(hrRes != MAILTRANSPORT_S_PENDING);
//
// If GetMessageRouter succeeded AND it returned a new
// IMessageRouter, release the old one.
//
if(SUCCEEDED(hrRes) && (pIMessageRouterNew != NULL)) {
if(m_pContext->pIMessageRouter) {
m_pContext->pIMessageRouter->Release();
}
m_pContext->pIMessageRouter = pIMessageRouterNew;
}
TraceFunctLeaveEx((LPARAM)this);
DebugTrace((LPARAM)this, "Default processing returned hr %08lx", hrRes);
TraceFunctLeaveEx((LPARAM)this);
return hrRes;
}
//////////////////////////////////////////////////////////////////////////////
HRESULT CStoreDispatcher::CMsgTrackLogParams::CallObject(
CBinding& bBinding,
IUnknown *punkObject )
{
IMsgTrackLog *pSink = NULL;
HRESULT hr = punkObject->QueryInterface(IID_IMsgTrackLog, (void **)&pSink);
if( FAILED( hr ) )
{
return( hr );
}
hr = pSink->OnSyncLogMsgTrackInfo(
m_pContext->pIServer,
m_pContext->pIMailMsgProperties,
m_pContext->pMsgTrackInfo );
pSink->Release();
return( hr );
}
//////////////////////////////////////////////////////////////////////////////
HRESULT CStoreDispatcher::CMsgTrackLogParams::CallDefault()
{
return S_OK;
}
//////////////////////////////////////////////////////////////////////////////
HRESULT CStoreDispatcher::CDnsResolverRecordParams::CallObject(
CBinding& bBinding,
IUnknown *punkObject )
{
HRESULT hr = S_OK;
IDnsInfoSink *pAdvancedSink = NULL;
IDnsResolverRecordSink *pSink = NULL;
hr = punkObject->QueryInterface(IID_IDnsInfoSink, (void **)&pAdvancedSink);
if(hr == S_OK)
{
//
// Use the advanced interface. This extends the functionality
// of OnSyncGetDnsResolverRecord by adding the option for the
// sink to return ppDnsServerInfo.
//
hr = pAdvancedSink->OnSyncGetDnsInfo(
m_pContext->pszHostName,
m_pContext->pszFQDN,
m_pContext->dwVirtualServerId,
m_pContext->ppDnsServerInfo,
m_pContext->ppIDnsResolverRecord);
pAdvancedSink->Release();
return hr;
}
//
// If the QI for the IDnsSinkInfo failed, this sink does not support
// the newer interface. We need to call the older interface.
//
hr = punkObject->QueryInterface(IID_IDnsResolverRecordSink, (void **)&pSink);
if( FAILED( hr ) )
{
return( hr );
}
hr = pSink->OnSyncGetResolverRecord( m_pContext->pszHostName,
m_pContext->pszFQDN,
m_pContext->dwVirtualServerId,
m_pContext->ppIDnsResolverRecord );
pSink->Release();
return( hr );
}
//////////////////////////////////////////////////////////////////////////////
HRESULT CStoreDispatcher::CDnsResolverRecordParams::CallDefault()
{
return S_OK;
}
//////////////////////////////////////////////////////////////////////////////
HRESULT CStoreDispatcher::CSmtpMaxMsgSizeParams::CallObject(
CBinding& bBinding,
IUnknown *punkObject )
{
ISmtpMaxMsgSize *pSink = NULL;
HRESULT hr = punkObject->QueryInterface(IID_ISmtpMaxMsgSize, (void **)&pSink);
if( FAILED( hr ) )
{
return( hr );
}
hr = pSink->OnSyncMaxMsgSize( m_pContext->pIUnknown, m_pContext->pIMailMsg, m_pContext->pfShouldImposeLimit );
pSink->Release();
return( hr );
}
//////////////////////////////////////////////////////////////////////////////
HRESULT CStoreDispatcher::CSmtpMaxMsgSizeParams::CallDefault()
{
return S_OK;
}
//////////////////////////////////////////////////////////////////////////////
HRESULT CStoreDispatcher::CSmtpLogParams::CallObject(
CBinding& bBinding,
IUnknown *punkObject )
{
ISmtpLog *pSink = NULL;
HRESULT hr = punkObject->QueryInterface(IID_ISmtpLog, (void **)&pSink);
if( FAILED( hr ) )
{
return( hr );
}
hr = pSink->OnSyncLog(m_pContext->pSmtpEventLogInfo );
pSink->Release();
return( hr );
}
//////////////////////////////////////////////////////////////////////////////
HRESULT CStoreDispatcher::CSmtpLogParams::CallDefault()
{
HRESULT hrRes = S_OK;
SMTP_LOG_EVENT_INFO *pLogEventInfo;
CEventLogWrapper *pEventLog;
TraceFunctEnterEx((LPARAM)this, "CStoreDispatcher::CSmtpLogParams::CallDefault");
_ASSERT(m_dwEventType == SMTP_LOG_EVENT);
if ((m_pContext->pSmtpEventLogInfo == NULL) ||
(m_pContext->pDefaultEventLogHandler == NULL))
{
DebugTrace((LPARAM) this, "Skipping LogEvent call");
TraceFunctLeaveEx((LPARAM)this);
return S_OK;
}
// Params are m_pContext->pSmtpEventLogInfo
pLogEventInfo = m_pContext->pSmtpEventLogInfo;
// filter out events that the user isn't interested in
if (m_pContext->iSelectedDebugLevel < pLogEventInfo->iDebugLevel) {
return S_OK;
}
// Handler is m_pContext->pDefaultEventLogHandler
pEventLog = (CEventLogWrapper*)m_pContext->pDefaultEventLogHandler;
// Call into default logging handler
pEventLog->LogEvent(
pLogEventInfo->idMessage,
// pLogEventInfo->idCategory, // Not used by default handler
pLogEventInfo->cSubstrings,
pLogEventInfo->rgszSubstrings,
pLogEventInfo->wType,
pLogEventInfo->errCode,
pLogEventInfo->iDebugLevel,
pLogEventInfo->szKey,
pLogEventInfo->dwOptions,
pLogEventInfo->iMessageString,
pLogEventInfo->hModule);
TraceFunctLeaveEx((LPARAM)this);
return hrRes;
}
//////////////////////////////////////////////////////////////////////////////
HRESULT CStoreDispatcher::CSmtpGetAuxDomainInfoFlagsParams::CallObject(
CBinding& bBinding,
IUnknown *punkObject )
{
ISmtpGetAuxDomainInfoFlags *pSink = NULL;
HRESULT hr = punkObject->QueryInterface(IID_ISmtpGetAuxDomainInfoFlags, (void **)&pSink);
if( FAILED( hr ) )
{
return( hr );
}
hr = pSink->OnGetAuxDomainInfoFlags(m_pContext->pIServer,
m_pContext->pszDomainName,
m_pContext->pdwDomainInfoFlags );
pSink->Release();
return( hr );
}
//////////////////////////////////////////////////////////////////////////////
HRESULT CStoreDispatcher::CSmtpGetAuxDomainInfoFlagsParams::CallDefault()
{
return S_OK;
}
//////////////////////////////////////////////////////////////////////////////
//+------------------------------------------------------------
//
// Function: CStoreDriver::Setprevious
//
// Synopsis: Method of IEventDispatcherChain - gets calle dy the
// dispatcher, when binding changes happen.
//
// Arguments:
// pUnkPrevious: [in] Pointer to the previous dispatcher
// ppUnkPreload: [out] Receives an object which implements
// IEnumGUID, in order to tell the router
// which event types to pre-load.
//
// Returns:
// S_OK: Success
//
// History:
// dondu 06/22/98 Created
//
//-------------------------------------------------------------
const GUID* g_apStoreDispEventTypes[] = {&CATID_SMTP_STORE_DRIVER,&GUID_NULL};
HRESULT STDMETHODCALLTYPE CStoreDispatcher::SetPrevious(IUnknown *pUnkPrevious, IUnknown **ppUnkPreload) {
HRESULT hrRes;
if (ppUnkPreload) {
*ppUnkPreload = NULL;
}
if (!ppUnkPreload) {
return (E_POINTER);
}
_ASSERT(pUnkPrevious);
if (pUnkPrevious) {
CComQIPtr<CStoreDispatcherData,&__uuidof(CStoreDispatcherData)> pData;
LPVOID pvServer;
DWORD dwServerInstance;
pData = pUnkPrevious;
_ASSERT(pData);
if (pData) {
hrRes = pData->GetData(&pvServer,&dwServerInstance);
if (SUCCEEDED(hrRes)) {
hrRes = SetData(pvServer,dwServerInstance);
_ASSERT(SUCCEEDED(hrRes));
}
}
}
hrRes = CEDEnumGUID::CreateNew(ppUnkPreload,g_apStoreDispEventTypes);
return (hrRes);
};
HRESULT STDMETHODCALLTYPE CStoreDispatcher::SetContext(REFGUID guidEventType,
IEventRouter *piRouter,
IEventBindings *pBindings) {
HRESULT hrRes;
hrRes = CEventBaseDispatcher::SetContext(guidEventType,piRouter,pBindings);
if (SUCCEEDED(hrRes) && (guidEventType == CATID_SMTP_STORE_DRIVER)) {
HRESULT hrResTmp;
LPVOID pvServer;
DWORD dwServerInstance;
SMTP_ALLOC_PARAMS AllocParams;
hrResTmp = GetData(&pvServer,&dwServerInstance);
if (SUCCEEDED(hrResTmp)) {
ZeroMemory(&AllocParams, sizeof(AllocParams));
AllocParams.m_EventSmtpServer = (LPVOID *) pvServer;
AllocParams.m_InstanceId = dwServerInstance;
AllocParams.m_dwStartupType = SMTP_INIT_BINDING_CHANGE;
hrResTmp = OnEvent(CATID_SMTP_STORE_DRIVER,SMTP_STOREDRV_STARTUP_EVENT,&AllocParams);
_ASSERT(SUCCEEDED(hrResTmp));
}
}
return (hrRes);
}
//+------------------------------------------------------------
//
// Function: CSMTPSeoMgr::CSMTPSeoMgr
//
// Synopsis: Initialize member data
//
// Arguments: NONE
//
// Returns: NOTHING
//
// History:
// jstamerj 1999/06/25 19:24:18: Created.
//
//-------------------------------------------------------------
CSMTPSeoMgr::CSMTPSeoMgr()
{
TraceFunctEnterEx((LPARAM)this, "CSMTPSeoMgr::CSMTPSeoMgr");
m_dwSignature = SIGNATURE_CSMTPSEOMGR;
m_pIEventRouter = NULL;
m_pICatDispatcher = NULL;
TraceFunctLeaveEx((LPARAM)this);
} // CSMTPSeoMgr::CSMTPSeoMgr
//+------------------------------------------------------------
//
// Function: CSMTPSeoMgr::~CSMTPSeoMgr
//
// Synopsis: Deinitialize if necessary
//
// Arguments: NONE
//
// Returns: NOTHING
//
// History:
// jstamerj 1999/06/25 19:26:09: Created.
//
//-------------------------------------------------------------
CSMTPSeoMgr::~CSMTPSeoMgr()
{
TraceFunctEnterEx((LPARAM)this, "CSMTPSeoMgr::~CSMTPSeoMgr");
Deinit();
_ASSERT(m_dwSignature == SIGNATURE_CSMTPSEOMGR);
m_dwSignature = SIGNATURE_CSMTPSEOMGR_INVALID;
TraceFunctLeaveEx((LPARAM)this);
} // CSMTPSeoMgr::~CSMTPSeoMgr
//+------------------------------------------------------------
//
// Function: CSMTPSeoMgr::HrInit
//
// Synopsis: Initialize
//
// Arguments:
// dwVSID: The virtual server ID
//
// Returns:
// S_OK: Success
// error from SEO
//
// History:
// jstamerj 1999/06/25 19:27:30: Created.
//
//-------------------------------------------------------------
HRESULT CSMTPSeoMgr::HrInit(
DWORD dwVSID)
{
HRESULT hr = S_OK;
CStoreDispatcherClassFactory cf;
TraceFunctEnterEx((LPARAM)this, "CSMTPSeoMgr::HrInit");
_ASSERT(m_pIEventRouter == NULL);
hr = SEOGetRouter(
GUID_SMTP_SOURCE_TYPE,
(REFGUID) CStringGUID(GUID_SMTPSVC_SOURCE, dwVSID),
&m_pIEventRouter);
if(FAILED(hr) || (hr == S_FALSE)) {
//
// Map S_FALSE to file not found -- this happens when the
// source type is not registered
//
if(hr == S_FALSE)
hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
ErrorTrace((LPARAM)this, "SEOGetRouter failed hr %08lx", hr);
m_pIEventRouter = NULL;
goto CLEANUP;
}
//
// Grab the dispatcher for the categorizer
//
_ASSERT(m_pICatDispatcher == NULL);
hr = m_pIEventRouter->GetDispatcherByClassFactory(
CLSID_CStoreDispatcher,
&cf,
CATID_SMTP_TRANSPORT_CATEGORIZE,
IID_IServerDispatcher,
(IUnknown **) &m_pICatDispatcher);
if(FAILED(hr)) {
ErrorTrace((LPARAM)this, "GetDispatcherByClassFactory failed hr %08lx", hr);
m_pICatDispatcher = NULL;
goto CLEANUP;
}
CLEANUP:
if(FAILED(hr))
Deinit();
DebugTrace((LPARAM)this, "returning %08lx", hr);
TraceFunctLeaveEx((LPARAM)this);
return hr;
} // CSMTPSeoMgr::HrInit
//+------------------------------------------------------------
//
// Function: CSMTPSeoMgr::Deinit
//
// Synopsis: Deinitialize member variables
//
// Arguments: NONE
//
// Returns: NOTHING
//
// History:
// jstamerj 1999/06/25 19:41:20: Created.
//
//-------------------------------------------------------------
VOID CSMTPSeoMgr::Deinit()
{
TraceFunctEnterEx((LPARAM)this, "CSMTPSeoMgr::Deinit");
if(m_pICatDispatcher) {
m_pICatDispatcher->Release();
m_pICatDispatcher = NULL;
}
if(m_pIEventRouter) {
m_pIEventRouter->Release();
m_pIEventRouter = NULL;
}
TraceFunctLeaveEx((LPARAM)this);
} // CSMTPSeoMgr::Deinit
//+------------------------------------------------------------
//
// Function: CSMTPSeoMgr::HrTriggerServerEvent
//
// Synopsis: Trigger a server event
//
// Arguments:
// dwEventType: event type to trigger
// pvContext: structure specific to event type (see smtpseo.h)
//
// Returns:
// S_OK: Success, called one or more sinks
// S_FALSE: Success, no sinks called
// MAILTRANSPORT_S_PENDING: Proccessing events async
// E_OUTOFMEMORY
// error from SEO
//
// History:
// jstamerj 1999/06/25 19:43:00: Created.
//
//-------------------------------------------------------------
HRESULT CSMTPSeoMgr::HrTriggerServerEvent(
DWORD dwEventType,
PVOID pvContext)
{
HRESULT hr = S_OK;
CComPtr<IServerDispatcher> pEventDispatcher;
CStoreDispatcherClassFactory cf;
REFIID iidBindingPoint = GuidForEvent(dwEventType);
TraceFunctEnterEx((LPARAM)this, "CSMTPSeoMgr::HrTriggerServerEvent");
if(m_pIEventRouter == NULL)
return E_POINTER;
if(iidBindingPoint == CATID_SMTP_TRANSPORT_CATEGORIZE) {
//
// Use the cached Categorizer dispatcher
//
pEventDispatcher = m_pICatDispatcher;
} else {
//
// Get the latest dispatcher with all changes
//
hr = m_pIEventRouter->GetDispatcherByClassFactory(
CLSID_CStoreDispatcher,
&cf,
iidBindingPoint,
IID_IServerDispatcher,
(IUnknown **) &pEventDispatcher);
if (FAILED(hr)) {
ErrorTrace((LPARAM)this, "GetDispatcherByClassFactory failed hr %08lx", hr);
goto CLEANUP;
}
}
hr = pEventDispatcher->OnEvent(
iidBindingPoint,
dwEventType,
pvContext);
CLEANUP:
DebugTrace((LPARAM)this, "returning %08lx", hr);
TraceFunctLeaveEx((LPARAM)this);
return hr;
} // CSMTPSeoMgr::HrTriggerServerEvent