//#define INCL_INETSRV_INCS //#include "smtpinc.h" #include #include #include #include #include #include #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 #include #include #include #include #include #define MAX_RULE_LENGTH 4096 // // Message object // #define MAILMSG_PROGID L"Exchange.MailMsg" #define INITGUID #include "initguid.h" #include "smtpguid.h" #ifdef PLATINUM #include "ptntguid.h" #endif #include "wildmat.h" #include "smtpdisp.h" #include "seodisp.h" #include "evntwrap.h" #include "address.hxx" #include "mailmsgprops.h" #include "cdosys_i.c" // {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); #ifdef PHATQ // These are GUIDs which are normally defined in uuid.lib. wrapmb.lib // incorrectly defines many of those GUIDs, so we need to define these // ones ourselves. Yes, this is stupid. // 00020400-0000-0000-C000-000000000046 DEFINE_GUID(IID_IDispatch, 0x00020400, 0x0000, 0x0000, 0xc0, 0x00, 0x0, 0x0, 0x0, 0x0, 0x0, 0x46); // 00020404-0000-0000-C000-000000000046 DEFINE_GUID(IID_IEnumVARIANT, 0x00020404, 0x0000, 0x0000, 0xc0, 0x00, 0x0, 0x0, 0x0, 0x0, 0x0, 0x46); // 0002E000-0000-0000-C000-000000000046 DEFINE_GUID(IID_IEnumGUID, 0x0002E000, 0x0000, 0x0000, 0xc0, 0x00, 0x0, 0x0, 0x0, 0x0, 0x0, 0x46); // 55272A00-42CB-11CE-8135-00AA004BB851 DEFINE_GUID(IID_IPropertyBag, 0x55272A00, 0x42CB, 0x11CE, 0x81, 0x35, 0x00, 0xaa, 0x00, 0x4b, 0xb8, 0x51); // 1CF2B120-547D-101B-8E65-08002B2BD119 DEFINE_GUID(IID_IErrorInfo, 0x1CF2B120, 0x547D, 0x101B, 0x8E, 0x65, 0x08, 0x00, 0x2B, 0x2B, 0xD1, 0x19); // B196B284-BAB4-101A-B69C-00AA00341D07 DEFINE_GUID(IID_IConnectionPointContainer, 0xB196B284, 0xBAB4, 0x101A, 0xB6, 0x9C, 0x00, 0xAA, 0x00, 0x34, 0x1D, 0x07); // 37D84F60-42CB-11CE-8135-00AA004BB851 DEFINE_GUID(IID_IPersistPropertyBag, 0x37D84F60, 0x42CB, 0x11CE, 0x81, 0x35, 0x00, 0xAA, 0x00, 0x4B, 0xB8, 0x51); DEFINE_OLEGUID(IID_IPersistStream, 0x00000109, 0, 0); #endif extern VOID ServerEventCompletion( PVOID pvContext, DWORD cbWritten, DWORD dwCompletionStatus, OVERLAPPED * lpo ); #define SKIPSINK_CALL_NO_MORE_SINKS 0xffffffff class CStoreCreateOptions : public CEventCreateOptionsBase { public: CStoreCreateOptions( AQ_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: AQ_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(((AQ_ALLOC_PARAMS *) pContext)->m_EventSmtpServer, ((AQ_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_GET_DSN_RECIPIENT_ITERATOR_EVENT: *ppCParams = new CDSNRecipientIteratorParams(); break; case SMTP_GENERATE_DSN_EVENT: *ppCParams = new CDSNGenerateParams(); break; case SMTP_POST_DSN_EVENT: *ppCParams = new CDSNPostGenerateParams(); break; default: _ASSERT(0 && "Unknown server event"); *ppCParams = NULL; break; } if(*ppCParams == NULL) { return E_OUTOFMEMORY; } hr = (*ppCParams)->InitParamData( pContext, dwEventType, pINotify, 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; } //+------------------------------------------------------------ // // 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, 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; 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 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 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 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; 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; hrRes = pBindInterface->BindToStore(pStream, pSink, m_pContext->hContent); if (pStream) { pStream->Release(); pStream = NULL; } 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); } pSink->Release(); } break; case SMTP_STOREDRV_DELIVERY_EVENT: { ISMTPStoreDriver *pSink; hrRes = punkObject->QueryInterface(IID_ISMTPStoreDriver, (void **)&pSink); if (FAILED(hrRes)) return(hrRes); DebugTrace((LPARAM)this, "Calling local delivery sink sink ..."); hrRes = pSink->LocalDelivery( (IMailMsgProperties *) m_pContext->IMsgPtr, m_pContext->m_RecipientCount, m_pContext->pdwRecipIndexes, (IMailMsgNotify *) m_pContext->m_pNotify); pSink->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; } // // 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_GET_DSN_RECIPIENT_ITERATOR_EVENT: case SMTP_GENERATE_DSN_EVENT: case SMTP_POST_DSN_EVENT: return CATID_SMTP_DSN; } } // // this function performs instance level server events registration // HRESULT RegisterPlatSEOInstance(DWORD dwInstanceID) { HRESULT hr; // // find the SMTP source type in the event manager // CComPtr pEventManager; hr = CoCreateInstance(CLSID_CEventManager, NULL, CLSCTX_ALL, IID_IEventManager, (LPVOID *) &pEventManager); if (hr != S_OK) return hr; CComPtr pSourceTypes; hr = pEventManager->get_SourceTypes(&pSourceTypes); if (FAILED(hr)) return hr; CComPtr 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 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 pEventSources; hr = pSourceType->get_Sources(&pEventSources); if (FAILED(hr)) return hr; CComPtr 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 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 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 pEventManager; hr = CoCreateInstance(CLSID_CEventManager, NULL, CLSCTX_ALL, IID_IEventManager, (LPVOID *) &pEventManager); if (hr != S_OK) return hr; CComPtr pSourceTypes; hr = pEventManager->get_SourceTypes(&pSourceTypes); if (FAILED(hr)) return hr; CComPtr 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 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 pEventSources; hr = pSourceType->get_Sources(&pEventSources); if (FAILED(hr)) return hr; CComPtr 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; } // // 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 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 ) { IDnsResolverRecordSink *pSink = NULL; HRESULT 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; } ////////////////////////////////////////////////////////////////////////////// //+------------------------------------------------------------ // // Function: CStoreDispatcher::CDSNCreateOptions::Init // // Synopsis: // // Arguments: // iidDesired: not used // ppUnkObject: IUnknown of newly created sink object // IEventBinding: not used // IUnknown: not used // // Returns: // S_OK: Success // // History: // jstamerj 2000/12/12 15:38:40: Created. // //------------------------------------------------------------- HRESULT CStoreDispatcher::CDSNCreateOptions::Init( REFIID iidDesired, IUnknown **ppUnkObject, IEventBinding *, IUnknown *) { HRESULT hr = S_OK; IDSNGenerationSink *pSink = NULL; TraceFunctEnterEx((LPARAM)this, "CStoreDispatcher::CDSNCreateOptions::Init"); hr = (*ppUnkObject)->QueryInterface( IID_IDSNGenerationSink, (PVOID *)&pSink); if(FAILED(hr)) { ErrorTrace((LPARAM)this, "QI for IDSNGenerationSink failed with hr %08lx", hr); goto CLEANUP; } DebugTrace((LPARAM)this, "Calling Init"); hr = pSink->OnSyncSinkInit( m_dwVSID); if(FAILED(hr) && (hr != E_NOTIMPL)) { // // A real failure occured // ErrorTrace((LPARAM)this, "Init failed with hr %08lx", hr); goto CLEANUP; } CLEANUP: if(pSink) pSink->Release(); DebugTrace((LPARAM)this, "returning %08lx", hr); TraceFunctLeaveEx((LPARAM)this); // // Return E_NOTIMPL so the real work of Init will be done // return SUCCEEDED(hr) ? E_NOTIMPL : hr; } // CStoreDispatcher::CDSNCreateOptions::Init //+------------------------------------------------------------ // // Function: CStoreDispatcher::CDSNBaseParams::CallObject // // Synopsis: Create/call the event sink // // Arguments: // pManager: SEO's IEventManager // bBinding: event binding // // Returns: // S_OK: Success // // History: // jstamerj 2000/12/12 15:35:35: Created. // //------------------------------------------------------------- HRESULT CStoreDispatcher::CDSNBaseParams::CallObject( IEventManager *pManager, CBinding& bBinding) { HRESULT hr = S_OK; CDSNCreateOptions opt(GetVSID()); CComPtr pUnkSink; TraceFunctEnterEx((LPARAM)this, "CStoreDispatcher::CDSNBaseParams::CallObject"); if (pManager == NULL) { ErrorTrace((LPARAM)this, "Invalid (NULL) pManager"); hr = E_POINTER; goto CLEANUP; } hr = pManager->CreateSink(bBinding.m_piBinding,&opt,&pUnkSink); if (FAILED(hr)) { ErrorTrace((LPARAM)this, "CreateSink returned error hr %08lx", hr); goto CLEANUP; } hr = CallObject(bBinding,pUnkSink); DebugTrace((LPARAM)this, "CallObject child returned error %08lx", hr); CLEANUP: DebugTrace((LPARAM)this, "returning %08lx", hr); TraceFunctLeaveEx((LPARAM)this); return hr; } // CStoreDispatcher::CDSNBaseParams::CallObject //+------------------------------------------------------------ // // Function: CStoreDispatcher::CDSNRecipientIteratorParams::CallObject // // Synopsis: Call the OnSyncGetDSNRecipientIterator method of a sink // // Arguments: // bBinding: event binding // punkObject: IUnknown of the sink // // Returns: // Return value from sink // // History: // jstamerj 2000/12/11 15:14:41: Created. // //------------------------------------------------------------- HRESULT CStoreDispatcher::CDSNRecipientIteratorParams::CallObject( CBinding& bBinding, IUnknown *punkObject) { HRESULT hr = S_OK; IDSNGenerationSink *pSink = NULL; IDSNRecipientIterator *pIRecipIter = NULL; TraceFunctEnterEx((LPARAM)this, "CStoreDispatcher::CDSNRecipientIteratorParams::CallObject"); hr = punkObject->QueryInterface( IID_IDSNGenerationSink, (LPVOID *)&pSink); if(FAILED(hr)) { pSink = NULL; ErrorTrace((LPARAM)this, "QI for IDSNGenerationSink failed hr %08lx", hr); goto CLEANUP; } hr = pSink->OnSyncGetDSNRecipientIterator( m_pContext->pISMTPServer, m_pContext->pIMsg, m_pContext->pDSNProperties, m_pContext->dwStartDomain, m_pContext->dwDSNActions, m_pContext->pRecipIter, &pIRecipIter); _ASSERT(hr != MAILTRANSPORT_S_PENDING); DebugTrace((LPARAM)this, "sink returned hr %08lx", hr); if(SUCCEEDED(hr) && (pIRecipIter != NULL)) { // // Capture the new interface // if(m_pContext->pRecipIter) m_pContext->pRecipIter->Release(); // // Transfer refcount // m_pContext->pRecipIter = pIRecipIter; pIRecipIter = NULL; } CLEANUP: if(pSink) pSink->Release(); DebugTrace((LPARAM)this, "returning %08lx", hr); TraceFunctLeaveEx((LPARAM)this); return hr; } // CStoreDispatcher::CDSNRecipientIteratorParams::CallObject //+------------------------------------------------------------ // // Function: CStoreDispatcher::CDSNGenerateParams::CallObject // // Synopsis: Call the OnSyncGenerateDSN method of a sink // // Arguments: // bBinding: event binding // punkObject: IUnknown of the sink // // Returns: // Return value from sink // // History: // jstamerj 2000/12/11 15:15:04: Created. // //------------------------------------------------------------- HRESULT CStoreDispatcher::CDSNGenerateParams::CallObject( CBinding& bBinding, IUnknown *punkObject) { HRESULT hr = S_OK; IDSNGenerationSink *pSink = NULL; TraceFunctEnterEx((LPARAM)this, "CStoreDispatcher::CDSNGenerateParams::CallObject"); hr = punkObject->QueryInterface( IID_IDSNGenerationSink, (LPVOID *)&pSink); if(FAILED(hr)) { pSink = NULL; ErrorTrace((LPARAM)this, "QI for IDSNGenerationSink failed hr %08lx", hr); goto CLEANUP; } hr = pSink->OnSyncGenerateDSN( m_pContext->pISMTPServer, m_pContext->pIDSNSubmission, m_pContext->pIMsg, m_pContext->pDSNProperties, m_pContext->pRecipIter); _ASSERT(hr != MAILTRANSPORT_S_PENDING); DebugTrace((LPARAM)this, "sink returned hr %08lx", hr); CLEANUP: if(pSink) pSink->Release(); DebugTrace((LPARAM)this, "returning %08lx", hr); TraceFunctLeaveEx((LPARAM)this); return hr; } // CStoreDispatcher::CDSNGenerateParams::CallObject //+------------------------------------------------------------ // // Function: CStoreDispatcher::CDSNGenerateparams::CallDefault // // Synopsis: Call the OnSyncGenerateDSN method on the default sink // // Arguments: None // // Returns: // Return value from default sink // // History: // jstamerj 2000/12/11 15:15:21: Created. // //------------------------------------------------------------- HRESULT CStoreDispatcher::CDSNGenerateParams::CallDefault() { HRESULT hr = S_OK; TraceFunctEnterEx((LPARAM)this, "CStoreDispatcher::CDSNGenerateparams::CallDefault"); if(m_pContext->pDefaultSink) { hr = m_pContext->pDefaultSink->OnSyncGenerateDSN( m_pContext->pISMTPServer, m_pContext->pIDSNSubmission, m_pContext->pIMsg, m_pContext->pDSNProperties, m_pContext->pRecipIter); _ASSERT(hr != MAILTRANSPORT_S_PENDING); } DebugTrace((LPARAM)this, "returning %08lx", hr); TraceFunctLeaveEx((LPARAM)this); return hr; } // CStoreDispatcher::CDSNGenerateparams::CallDefault //+------------------------------------------------------------ // // Function: CStoreDispatcher::CDSNPostGenerateParams::CallObject // // Synopsis: Calls the OnSyncPostGenerateDSN method of a sink // // Arguments: // bBinding: event binding // punkObject: IUnknown of the sink // // Returns: // Return value from sink // // History: // jstamerj 2000/12/11 15:15:40: Created. // //------------------------------------------------------------- HRESULT CStoreDispatcher::CDSNPostGenerateParams::CallObject( CBinding& bBinding, IUnknown *punkObject) { HRESULT hr = S_OK; IDSNGenerationSink *pSink = NULL; TraceFunctEnterEx((LPARAM)this, "CStoreDispatcher::CDSNPostGenerateParams::CallObject"); hr = punkObject->QueryInterface( IID_IDSNGenerationSink, (LPVOID *)&pSink); if(FAILED(hr)) { pSink = NULL; ErrorTrace((LPARAM)this, "QI for IDSNGenerationSink failed hr %08lx", hr); goto CLEANUP; } hr = pSink->OnSyncPostGenerateDSN( m_pContext->pISMTPServer, m_pContext->pIMsgOrig, m_pContext->dwDSNAction, m_pContext->cRecipsDSNd, m_pContext->pIMsgDSN, m_pContext->pIDSNProperties); _ASSERT(hr != MAILTRANSPORT_S_PENDING); DebugTrace((LPARAM)this, "sink returned hr %08lx", hr); CLEANUP: if(pSink) pSink->Release(); DebugTrace((LPARAM)this, "returning %08lx", hr); TraceFunctLeaveEx((LPARAM)this); return hr; } // CStoreDispatcher::CDSNPostGenerateParams::CallObject ////////////////////////////////////////////////////////////////////////////// //+------------------------------------------------------------ // // 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 pData; LPVOID pvServer; DWORD dwServerInstance; pData = pUnkPrevious; _ASSERT(pData); if (pData) { hrRes = pData->GetData(&pvServer,&dwServerInstance); // bugbug dbraun : removing this assert because it does not help us - we // need to put some code in to get more meaningful data when this problem // occurs //_ASSERT(SUCCEEDED(hrRes)); 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; AQ_ALLOC_PARAMS AllocParams; hrResTmp = GetData(&pvServer,&dwServerInstance); if (SUCCEEDED(hrResTmp)) { 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 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