// 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;iInit((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; }