windows-nt/Source/XPSP1/NT/inetsrv/iis/svcs/smtp/server/smtpsvr.cpp
2020-09-26 16:20:57 +08:00

596 lines
15 KiB
C++

// SMTPServer.cpp : Implementation of CSMTPServer
#define INCL_INETSRV_INCS
#include "smtpinc.h"
#include "stdafx.h"
#include "dbgtrace.h"
#include "filehc.h"
#include "mailmsg.h"
#include "mailmsgi.h"
#include "smtpsvr.h"
//DECLARE_DEBUG_PRINTS_OBJECT();
#define MAILMSG_PROGID L"Exchange.MailMsg"
/////////////////////////////////////////////////////////////////////////////
// CSMTPServer
STDMETHODIMP CSMTPServer::InterfaceSupportsErrorInfo(REFIID riid)
{
static const IID* arr[] =
{
&IID_ISMTPServer,
};
for (int i=0;i<sizeof(arr)/sizeof(arr[0]);i++)
{
if (InlineIsEqualGUID(*arr[i],riid))
return S_OK;
}
return S_FALSE;
}
BOOL InitExchangeSmtpServer(PVOID Ptr, PVOID Ptr2)
{
CSMTPServer * ThisPtr = (CSMTPServer *) Ptr;
ThisPtr->Init((SMTP_SERVER_INSTANCE *) Ptr2);
return TRUE;
}
//
// Add all your initialization needs here ...
//
HRESULT CSMTPServer::Init(SMTP_SERVER_INSTANCE * pInstance)
{
_ASSERT (pInstance != NULL);
m_pInstance = pInstance;
return(S_OK);
}
STDMETHODIMP CSMTPServer::QueryInterface(
REFIID iid,
void **ppvObject
)
{
if (iid == IID_IUnknown)
{
// Return our identity
*ppvObject = (IUnknown *)(ISMTPServerInternal *)this;
AddRef();
}
else if(iid == IID_ISMTPServer)
{
// Return our identity
*ppvObject = (ISMTPServerInternal *)this;
AddRef();
}
else if(iid == IID_ISMTPServerInternal)
{
// Return our identity
*ppvObject = (ISMTPServerInternal *)this;
AddRef();
}
else if(iid == IID_IMailTransportRouterReset)
{
// Return our identity
*ppvObject = (IMailTransportRouterReset *)this;
AddRef();
}
else if(iid == IID_IMailTransportSetRouterReset)
{
// Return our identity
*ppvObject = (IMailTransportSetRouterReset *)this;
AddRef();
}
else if(iid == IID_IMailTransportRouterSetLinkState)
{
// Return our identity
*ppvObject = (IMailTransportRouterSetLinkState *)this;
AddRef();
}
else if(iid == IID_ISMTPServerEx)
{
// Return our identity
*ppvObject = (ISMTPServerEx *)this;
AddRef();
}
else if(iid == IID_ISMTPServerGetAuxDomainInfoFlags)
{
// Return our identity
*ppvObject = (ISMTPServerGetAuxDomainInfoFlags *)this;
AddRef();
}
else if(iid == IID_ISMTPServerAsync)
{
// Return our identity
*ppvObject = (ISMTPServerAsync *)this;
AddRef();
}
else
{
return(E_NOINTERFACE);
}
return(S_OK);
}
STDMETHODIMP CSMTPServer::AllocMessage(
IMailMsgProperties **ppMsg
)
{
HRESULT hr = S_OK;
// Create a new MailMsg
hr = CoCreateInstance(
CLSID_MsgImp,
NULL,
CLSCTX_INPROC_SERVER,
IID_IMailMsgProperties,
(LPVOID *)ppMsg);
return(hr);
}
STDMETHODIMP CSMTPServer::SubmitMessage(
IMailMsgProperties *pMsg
)
{
HRESULT hr = S_FALSE;
if(m_pInstance)
{
hr = m_pInstance->InsertIntoAdvQueue(pMsg);
}
return(hr);
}
STDMETHODIMP CSMTPServer::TriggerLocalDelivery(
IMailMsgProperties *pMsg, DWORD dwRecipientCount, DWORD * pdwRecipIndexes
)
{
HRESULT hr = S_FALSE;
if(m_pInstance)
{
hr = m_pInstance->TriggerLocalDelivery(pMsg, dwRecipientCount, pdwRecipIndexes, NULL);
}
return(hr);
}
STDMETHODIMP CSMTPServer::TriggerLocalDeliveryAsync(
IMailMsgProperties *pMsg, DWORD dwRecipientCount, DWORD * pdwRecipIndexes, IMailMsgNotify *pNotify
)
{
HRESULT hr = S_FALSE;
if(m_pInstance)
{
hr = m_pInstance->TriggerLocalDelivery(pMsg, dwRecipientCount, pdwRecipIndexes, pNotify);
}
return(hr);
}
STDMETHODIMP CSMTPServer::TriggerServerEvent(
DWORD dwEventID,
PVOID pvContext)
{
HRESULT hr = S_FALSE;
if(m_pInstance)
{
hr = m_pInstance->TriggerServerEvent(dwEventID, pvContext);
}
return(hr);
}
STDMETHODIMP CSMTPServer::ReadMetabaseString(DWORD MetabaseId, LPBYTE Buffer, DWORD * BufferSize, BOOL fSecure)
{
HRESULT hr = S_FALSE;
if(m_pInstance)
{
hr = m_pInstance->SinkReadMetabaseString(MetabaseId, (char *) Buffer, BufferSize, (BOOL) fSecure);
}
return hr;
}
STDMETHODIMP CSMTPServer::ReadMetabaseDword(DWORD MetabaseId, DWORD * dwValue)
{
HRESULT hr = S_FALSE;
if(m_pInstance)
{
hr = m_pInstance->SinkReadMetabaseDword(MetabaseId, dwValue);
}
return hr;
}
STDMETHODIMP CSMTPServer::ServerStartHintFunction()
{
HRESULT hr = S_OK;
if(m_pInstance)
{
m_pInstance->SinkSmtpServerStartHintFunc();
}
return hr;
}
STDMETHODIMP CSMTPServer::ServerStopHintFunction()
{
HRESULT hr = S_OK;
if(m_pInstance)
{
m_pInstance->SinkSmtpServerStopHintFunc();
}
return hr;
}
STDMETHODIMP CSMTPServer::ReadMetabaseData(DWORD MetabaseId, BYTE *Buffer, DWORD *BufferSize)
{
HRESULT hr = S_FALSE;
if(m_pInstance)
{
hr = m_pInstance->SinkReadMetabaseData(MetabaseId, Buffer, BufferSize);
}
return hr;
}
//---[ CSMTPServer::AllocBoundMessage ]----------------------------------------
//
//
// Description:
// Creates a message and binds it to an ATQ Context
// Parameters:
// ppMsg Message to allocate
// phContent Content handle for message
// Returns:
// HRESULT from alloc message event
// E_POINTER if ppMsg or phContent is NULL
// E_FAIL if m_pIstance is NULL
// History:
// 7/11/98 - MikeSwa Created
//
//-----------------------------------------------------------------------------
STDMETHODIMP CSMTPServer::AllocBoundMessage(
OUT IMailMsgProperties **ppMsg,
OUT PFIO_CONTEXT *phContent)
{
TraceFunctEnterEx((LPARAM) this, "CSMTPServer::AllocBoundMessage");
HRESULT hr = S_OK;
SMTP_ALLOC_PARAMS AllocParams;
IMailMsgBind *pBindInterface = NULL;
if (!phContent || !ppMsg)
{
hr = E_POINTER;
goto Exit;
}
//we cannot bind the message without m_pInstance
if (!m_pInstance)
{
hr = E_FAIL;
goto Exit;
}
//CoCreate unbound message object
hr = CoCreateInstance(
CLSID_MsgImp,
NULL,
CLSCTX_INPROC_SERVER,
IID_IMailMsgProperties,
(LPVOID *)ppMsg);
if (FAILED(hr))
goto Exit;
hr = (*ppMsg)->QueryInterface(IID_IMailMsgBind, (void **) &pBindInterface);
if (FAILED(hr))
goto Exit;
AllocParams.BindInterfacePtr = (PVOID) pBindInterface;
AllocParams.IMsgPtr = (PVOID) (*ppMsg);
AllocParams.hContent = NULL;
AllocParams.hr = S_OK;
AllocParams.m_pNotify = NULL;
//For client context pass in something that will stay around the lifetime of the
//atqcontext -
AllocParams.pAtqClientContext = m_pInstance;
if(m_pInstance->AllocNewMessage(&AllocParams))
{
hr = AllocParams.hr;
if (SUCCEEDED(hr) && (AllocParams.hContent != NULL))
*phContent = AllocParams.hContent;
else
hr = E_FAIL;
}
else
{
hr = E_FAIL;
}
Exit:
if (FAILED(hr) && ppMsg && (*ppMsg))
{
(*ppMsg)->Release();
*ppMsg = NULL;
}
if (pBindInterface)
pBindInterface->Release();
TraceFunctLeave();
return hr;
}
//---[ CSMTPSvr::ResetRoutes ]-------------------------------------------------
//
//
// Description:
// Implements IMailTransportRouterReset::ResetRoutes. Acts as a buffer
// between AQ and the routers. On shutdown... AQ can safely destroy
// it's heap by telling ISMTPServer to release its pointer to AQ's
// IMailTransportRouterReset interface
// Parameters:
// dwResetType The type of route reset to perform.
// Returns:
// S_OK on success (or if no m_pIRouterReset)
// Error code from AQUEUE if error occurs.
// History:
// 11/8/98 - MikeSwa Created
//
//-----------------------------------------------------------------------------
STDMETHODIMP CSMTPServer::ResetRoutes(IN DWORD dwResetType)
{
HRESULT hr = S_OK;
m_slRouterReset.ShareLock();
if (m_pIRouterReset)
hr = m_pIRouterReset->ResetRoutes(dwResetType);
m_slRouterReset.ShareUnlock();
return hr;
}
//---[ CSMTPSvr::RegisterResetInterface ]---------------------------------------
//
//
// Description:
// Implements IMailTransportSetRouterReset::RegisterResetInterface. Used
// by AQ to set its IMailTransportRouterReset ptr. Also used at shutdown
// to set its pointer to NULL.
// Parameters:
// IN dwVirtualServerID Virtual server ID
// IN pIRouterReset AQ's IMailTransportRouterReset
// Returns:
// S_OK on success
// History:
// 11/8/98 - MikeSwa Created
// 1/9/99 - MikeSwa Modified to include IMailTransportRouterSetLinkState
//
//-----------------------------------------------------------------------------
STDMETHODIMP CSMTPServer::RegisterResetInterface(
IN DWORD dwVirtualServerID,
IN IMailTransportRouterReset *pIRouterReset)
{
HRESULT hr = S_OK;
_ASSERT(!m_pInstance || (m_pInstance->QueryInstanceId() == dwVirtualServerID));
if (m_pInstance && (m_pInstance->QueryInstanceId() != dwVirtualServerID))
return E_INVALIDARG;
//Grab exclsuive lock so we don't release out from under anyone
m_slRouterReset.ExclusiveLock();
if (m_pIRouterReset)
m_pIRouterReset->Release();
if (m_pIRouterSetLinkState)
{
m_pIRouterSetLinkState->Release();
m_pIRouterSetLinkState = NULL;
}
m_pIRouterReset = pIRouterReset;
if (m_pIRouterReset)
{
m_pIRouterReset->AddRef();
//Get new SetLinkState interface
m_pIRouterReset->QueryInterface(IID_IMailTransportRouterSetLinkState,
(VOID **) &m_pIRouterSetLinkState);
}
m_slRouterReset.ExclusiveUnlock();
return S_OK;
}
STDMETHODIMP CSMTPServer::WriteLog( LPMSG_TRACK_INFO pMsgTrackInfo,
IMailMsgProperties *pMsgProps,
LPEVENT_LOG_INFO pEventLogInfo ,
LPSTR pszProtocolLog )
{
HRESULT hr = S_OK;
if(m_pInstance)
{
m_pInstance->WriteLog( pMsgTrackInfo, pMsgProps, pEventLogInfo, pszProtocolLog );
}
return hr;
}
//---[ CSMTPServer::SetLinkState ]----------------------------------------------
//
//
// Description:
// Acts as a buffer between AQ and the routers. On shutdown... AQ can
// safely destroy it's heap by telling ISMTPServer to release its pointer
// to AQ's IMailTransportRouterSetLinkState interface
// Parameters:
// IN szLinkDomainName The Domain Name of the link (next hop)
// IN guidRouterGUID The GUID ID of the router
// IN dwScheduleID The schedule ID link
// IN szConnectorName The connector name given by the router
// IN dwSetLinkState The link state to set
// IN dwUnsetLinkState The link state to unset
// Returns:
// S_OK always
// History:
// 1/9/99 - MikeSwa Created
//
//-----------------------------------------------------------------------------
STDMETHODIMP CSMTPServer::SetLinkState(
IN LPSTR szLinkDomainName,
IN GUID guidRouterGUID,
IN DWORD dwScheduleID,
IN LPSTR szConnectorName,
IN DWORD dwSetLinkState,
IN DWORD dwUnsetLinkState,
IN FILETIME *pftNextScheduled,
IN IMessageRouter *pMessageRouter)
{
HRESULT hr = S_OK;
m_slRouterReset.ShareLock();
if (m_pIRouterSetLinkState)
hr = m_pIRouterSetLinkState->SetLinkState(szLinkDomainName,
guidRouterGUID,
dwScheduleID,
szConnectorName,
dwSetLinkState,
dwUnsetLinkState,
pftNextScheduled,
pMessageRouter);
m_slRouterReset.ShareUnlock();
return hr;
}
STDMETHODIMP CSMTPServer::TriggerLogEvent(
IN DWORD idMessage,
IN WORD idCategory,
IN WORD cSubstrings,
IN LPCSTR *rgszSubstrings,
IN WORD wType,
IN DWORD errCode,
IN WORD iDebugLevel,
IN LPCSTR szKey,
IN DWORD dwOptions,
IN DWORD iMessageString,
IN HMODULE hModule)
{
HRESULT hr = S_OK;
if(m_pInstance)
{
m_pInstance->TriggerLogEvent(
idMessage,
idCategory,
cSubstrings,
rgszSubstrings,
wType,
errCode,
iDebugLevel,
szKey,
dwOptions,
iMessageString,
hModule);
}
return hr;
}
//---[ CSMTPServer::ResetLogEvent ]------------------------------------------
//
//
// Description:
// Reset any history about events using this message and key,
// so that the next TriggerLogEvent with one-time or periodic logging
// will cause the event to be logged.
// Parameters:
// idMessage :
// szKey :
// Returns:
// S_OK on success
// History:
// 7/20/2000 - created, dbraun
//
//-----------------------------------------------------------------------------
STDMETHODIMP CSMTPServer::ResetLogEvent(
IN DWORD idMessage,
IN LPCSTR szKey)
{
HRESULT hr = S_OK;
if(m_pInstance)
{
m_pInstance->ResetLogEvent(
idMessage,
szKey);
}
return hr;
}
//---[ CSMTPServer::HrTriggerGetAuxDomainInfoFlagsEvent ]----------------------
//
//
// Description:
// Triggers the Get Aux Domain Info Flags event - this is to be used by aqueue to
// query for additional domain info config stored outside the metabase
// Parameters:
// pszDomainName : Name of domain to query flags for
// pdwDomainInfoFlags : DWORD to return domain flags
// Returns:
// S_OK on success
// S_FALSE if no domain found
// History:
// 10/6/2000 - created, dbraun
//
//-----------------------------------------------------------------------------
STDMETHODIMP CSMTPServer::HrTriggerGetAuxDomainInfoFlagsEvent(
IN LPCSTR pszDomainName,
OUT DWORD *pdwDomainInfoFlags )
{
HRESULT hr = S_OK;
if(m_pInstance)
{
hr = m_pInstance->HrTriggerGetAuxDomainInfoFlagsEvent(
pszDomainName,
pdwDomainInfoFlags);
}
return hr;
}