|
|
//#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
|