Platform SDK: SMTP Server Events

Sink.cpp

[This is preliminary documentation and subject to change.]

This file contains the implementation for all the exposed CSink interfaces.

#include "stdafx.h"
#include "ShieldsUp.h"
#include "Sink.h"
#define DEFAULT_RESPONSE "Please Try Again Later."

/////////////////////////////////////////////////////////////////////////////
// CSink


/*
** ISmtpInCommandSink
*/
STDMETHODIMP CSink::OnSmtpInCommand( 
            IUnknown *pServer,
            IUnknown *pSession,
            IMailMsgProperties *pMsg,
            ISmtpInCommandContext *pContext)
{

    HRESULT hr = S_OK;
    if(pContext == NULL)
        return E_POINTER;
    
    char*    pszResponse        = NULL;
    long    lResponseLength = strlen(g_szResponseText);
    pszResponse = (char*) CoTaskMemAlloc(g_dwResponseSize);
    strcpy(pszResponse,g_szResponseText);
    pszResponse[g_dwResponseSize-1] = '\0';
    hr = pContext->SetResponse(pszResponse, g_dwResponseSize);
    if(FAILED(hr))
        return hr;

    hr = pContext->SetCommandStatus(EXPE_DROP_SESSION);

    if(FAILED(hr))
        return hr;

    // Success.
    // Notify the dispatcher that we have
    // consummed the event.
    // No other sinks will run, and
    // the connection will be dropped.

    return EXPE_S_CONSUMED;
}


/*
** IPersistPropertyBag : IPersist
*/
STDMETHODIMP CSink::GetClassID(CLSID *pClassID)
{
    return S_OK;
}

STDMETHODIMP CSink::InitNew(void)
{

    return S_OK;
}

STDMETHODIMP CSink::Load(IPropertyBag* pBag,IErrorLog *pErrorLog)
{
    if(pBag == NULL)
        return E_POINTER;

    if(g_fHaveCustomText)
        return S_OK;

    ATLASSERT(pBag);
    HRESULT hr = S_OK;
    CComVariant varVal;
    hr = pBag->Read(L"ResponseText",&varVal,pErrorLog);
    if(FAILED(hr)) 
        return S_OK;        // There's no custom text


    /* 
    ** We have some custom text 
    */
    
    UINT uiResponseLength = SysStringLen(varVal.bstrVal);
    char* temp = NULL;
    temp = new char[uiResponseLength + 1];
    if(temp == NULL)
        return E_OUTOFMEMORY;    


    if(wcstombs(temp,varVal.bstrVal,uiResponseLength+1) == NULL) {
        delete [] temp;
        return E_OUTOFMEMORY;
    }

    if(g_szResponseText != NULL) 
        delete [] g_szResponseText;
    
    g_szResponseText = temp;
    g_szResponseText[uiResponseLength] = '\0';
    g_dwResponseSize = uiResponseLength + 1;
    g_fHaveCustomText = true;
    
    return S_OK;
}


STDMETHODIMP CSink::Save(
                IPropertyBag *pPropBag,
                BOOL fClearDirty,
                BOOL fSaveAllProperties)
{

    return S_OK;
}

/*
** Oddly enough, the most involved code for this example
** is where we register and unregister the event sink bindings.
** What's going on is very simple. We have to add a binding
** to the appropriate source in the SEO database.
** SEO is ole-automation compatible, so much of this code
** mirrors much simpler code using vbscript.
** The hierarchy of SEO objects is as follows:
** 
** EventManager
**  SourceTypes
**    SourceType
**       Sources
**         Source
**           Bindings
**             Binding <--- Adding another of these
**                SinkProperties
**                SourceProperties
** 
*/
STDMETHODIMP CSink::RegisterSink(long lInstance, BSTR DisplayName, BSTR BindingGUID, BSTR ResponseText, VARIANT_BOOL fEnabled, BSTR* OutBindingGUID)
{

    IEventManager*        pEvtMan        =    NULL;
    IEventUtil*            pEvtUtil    =    NULL;
    IEventSourceTypes*    pSrcTypes    =    NULL;
    IEventSourceType*    pSrcType    =    NULL;
    IEventSources*        pSrcs        =    NULL;
    IEventSource*        pSrc        =    NULL;
    IEventBindingManager* pBindingMan    =    NULL;
    IEventBindings*        pBindings    =    NULL;
    IEventBinding*        pBinding    =    NULL;
    IEventPropertyBag*    pSourceProps    =    NULL;
    IEventPropertyBag*    pSinkProps    =    NULL;
    HRESULT                hr            =    S_OK;
    BSTR                bstrSourceGUID;

    hr = CoCreateInstance(__uuidof(CEventUtil),
                            NULL,
                            CLSCTX_INPROC_SERVER,
                            __uuidof(IEventUtil),
                            (void**)&pEvtUtil);



    // Get the Source GUID for the SMTP Server Instance
    hr = pEvtUtil->GetIndexedGUID(CComBSTR(g_szGuidSmtpSvcSource),lInstance,&bstrSourceGUID);
    if(FAILED(hr)) {
        pEvtUtil->Release();
        return hr;
    }


    // Use the EventManager to create the binding
    hr = CoCreateInstance(__uuidof(CEventManager),
                            NULL,
                            CLSCTX_INPROC_SERVER,
                            __uuidof(IEventManager),
                            (void**)&pEvtMan);

    if(FAILED(hr)) 
        return hr;


        hr = E_FAIL;
    if(SUCCEEDED(pEvtMan->get_SourceTypes(&pSrcTypes))) {
      if(SUCCEEDED(pSrcTypes->Item(&CComVariant(g_szGuidSmtpSourceType),&pSrcType))) {
        if(SUCCEEDED(pSrcType->get_Sources(&pSrcs))) {    
          if(SUCCEEDED(pSrcs->Item(&CComVariant(bstrSourceGUID),&pSrc))) {
            if(SUCCEEDED(pSrc->GetBindingManager(&pBindingMan))) {
              if(SUCCEEDED(pBindingMan->get_Bindings(CComBSTR(g_szcatidSmtpOnInboundCommand),&pBindings))) {
                // BindingGUID was passed by the caller
                hr = pBindings->Add(BindingGUID,&pBinding);
                if(SUCCEEDED(hr)) {
                  // error checking is omitted for clarity.
                  // each result _should_ be checked
                  // but these work most of the time
                  pBinding->put_SinkClass(CComBSTR("ShieldsUp.Sink"));
                  pBinding->put_DisplayName(DisplayName);
                  pBinding->put_Enabled(fEnabled);

                  // Source Properties
                  pBinding->get_SourceProperties(&pSourceProps);
                  // Rule is: EHLO command (all)
                  pSourceProps->Add(CComBSTR("Rule"),&CComVariant("ehlo"));
                  // highest prio
                  pSourceProps->Add(CComBSTR("Priority"),&CComVariant((long) 0));
                  pSourceProps->Release();

                  // Sink Properties
                  pBinding->get_SinkProperties(&pSinkProps);
                  pSinkProps->Add(CComBSTR("ResponseText"),&CComVariant(ResponseText));

                  hr = pBinding->Save();
                  // If the caller did not specify a GUID, we return it.
                  // If they did, we return it anyway
                  hr = pBinding->get_ID(OutBindingGUID);
                  pSinkProps->Release();
                  pBinding->Release();
                }
                pBindings->Release();
              }
              pBindingMan->Release();
            }
            pSrc->Release();
          }
          pSrcs->Release();
        }
        pSrcType->Release();
      }
      pSrcTypes->Release();
    }
    pEvtMan->Release();


    ATLASSERT(SUCCEEDED(hr));


    return S_OK;
}


STDMETHODIMP CSink::UnRegisterSink(long lInstance, BSTR BindingGUID)
{

    IEventManager*        pEvtMan        =    NULL;
    IEventUtil*            pEvtUtil    =    NULL;
    IEventSourceTypes*    pSrcTypes    =    NULL;
    IEventSourceType*    pSrcType    =    NULL;
    IEventSources*        pSrcs        =    NULL;
    IEventSource*        pSrc        =    NULL;
    IEventBindingManager* pBindingMan    =    NULL;
    IEventBindings*        pBindings    =    NULL;
    IEventBinding*        pBinding    =    NULL;
    HRESULT                hr            =    S_OK;
    BSTR                bstrSourceGUID;

    hr = CoCreateInstance(__uuidof(CEventUtil),
                            NULL,
                            CLSCTX_INPROC_SERVER,
                            __uuidof(IEventUtil),
                            (void**)&pEvtUtil);



    // Get the Source GUID for the SMTP Server Instance
    hr = pEvtUtil->GetIndexedGUID(CComBSTR(g_szGuidSmtpSvcSource),lInstance,&bstrSourceGUID);
    if(FAILED(hr)) {
        pEvtUtil->Release();
        return hr;
    }

    pEvtUtil->Release();

    // Use the EventManager to create the binding
    hr = CoCreateInstance(__uuidof(CEventManager),
                            NULL,
                            CLSCTX_INPROC_SERVER,
                            __uuidof(IEventManager),
                            (void**)&pEvtMan);

    if(FAILED(hr)) 
        return hr;

    hr = E_FAIL;
    if(SUCCEEDED(pEvtMan->get_SourceTypes(&pSrcTypes))) {
      if(SUCCEEDED(pSrcTypes->Item(&CComVariant(g_szGuidSmtpSourceType),&pSrcType))) {
        if(SUCCEEDED(pSrcType->get_Sources(&pSrcs))) {    
          if(SUCCEEDED(pSrcs->Item(&CComVariant(bstrSourceGUID),&pSrc))) {
            if(SUCCEEDED(pSrc->GetBindingManager(&pBindingMan))) {
              if(SUCCEEDED(pBindingMan->get_Bindings(CComBSTR(g_szcatidSmtpOnInboundCommand),&pBindings))) {
                hr = pBindings->Remove(&CComVariant(BindingGUID));
                pBindings->Release();
              }
              pBindingMan->Release();
            }
            pSrc->Release();
          }
          pSrcs->Release();
        }
        pSrcType->Release();
      }
      pSrcTypes->Release();
    }
    pEvtMan->Release();

    return hr;
}