Sink.cpp (Shields Up)

Sink.cpp

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

Important This sample code may not fully verify that strings passed to it are in fact null-terminated, nor that the referenced string buffers are large enough to store the generated contents. Your production code should always verify the validity and size of data passed as null-terminated strings before using, copying or adding to them. Using more-safe versions of the standard C string-handling functions is also recommended.

//------------------------------------------------------------
//
// File: Sink.cpp
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//-------------------------------------------------------------

#include "stdafx.h"
#include "ShieldsUp.h"
#include "Sink.h"
#include "string.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_s(pszResponse,lResponseLength,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;
}