Microsoft Chat Server Development Guide

MessageFilter.cpp

// MessageFilter.cpp : Implementation of CMessageFilter
#include "stdafx.h"
#include "MsgFilter.h"
#include "MessageFilter.h"

// CHATSDK: Include the definition for the chat interface GUID
#include "..\inc\chatsvc_i.h"


/////////////////////////////////////////////////////////////////////////////
// CMessageFilter::IChatMsgFilter
//

// Retrieve a word from our list of filtered words
STDMETHODIMP CMessageFilter::get_Item(int index, BSTR * pVal)
{
    if( index < m_FilteredWords.size() ) {
        *pVal = SysAllocString(m_FilteredWords[index]) ;
        return S_OK;
    } else {
        return E_INVALIDARG;
    }
}

// Retrieve a count of our filtered words
STDMETHODIMP CMessageFilter::get_Count(int * pVal)
{
    *pVal = m_FilteredWords.size();
    return S_OK;
}

// Add a new word to our list of filtered words
STDMETHODIMP CMessageFilter::Add(BSTR Message)
{    
    // Store all words as lower case
    for(wchar_t *p = Message; *p; p++)    
        *p = towlower(*p);

    // Add the Message filter text to our list of filtered words
    m_FilteredWords.push_back(Message);
    return S_OK;
}


/////////////////////////////////////////////////////////////////////////////
// CMessageFilter::IChatExtensionCallBack Implementations
//

// All extensions need a short-name, as used by /extmsg and administration
STDMETHODIMP CMessageFilter::get_Name(BSTR *pbstrName)
{
    *pbstrName = SysAllocString(L"MsgFilter");
    return S_OK;
}

// Init is called to allow us to initialize and to receive a reference to the ChatRegistrar
STDMETHODIMP CMessageFilter::Init(IChatServer *pServer, IChatRegistrar* pRegistrar, long *Result)
{
    // Maintain a reference to the chat registrar
    m_pRegistrar = pRegistrar;    // 'smart' pointer doesn't need to addref()

    // Bind to the OnNewUser message, return Init() as OK if we bind OK
    m_pRegistrar->AddServerEvent( (_bstr_t)L"OnNewChannel", Result);    

    // Add some default 4 letter words
    Add((_bstr_t)L"CHAT");
    Add((_bstr_t)L"WORK");
    Add((_bstr_t)L"MAIL");
    return S_OK;
}

// Allows the administration program (MMC) to query for the CLSID of any property pages we have
STDMETHODIMP CMessageFilter::OnGetPropertyPageClass(PPAGE Class, BSTR *pbstrCLSID)
{
    // return the PROGID for our a component (in this case the extension object)
    // that supports the ISpecifyPropertyPages that names our property pages
    if( Class == PPAGE_SERVER ) {
        *pbstrCLSID = SysAllocString(L"MessageFilter.MessageFilter.1");
    }
    return S_OK;
}


////////////////////////////////////////////////////////////////////////////
// CMessageFilter::IChatServerCallBack Implementations
//

// Notification that a new channel is/has been created
STDMETHODIMP CMessageFilter::OnNewChannel(IChatChannel *pChannel, VARIANT_BOOL varbPostUpdate, long *pCancel) 
{    
    if( varbPostUpdate == VARIANT_TRUE ) {
        // if we have a post-update to a new channel, bind to its OnChannelText events
        m_pRegistrar->AddChannelEvent( (_bstr_t)L"OnChannelText", pChannel, pCancel);
    }

    *pCancel = 0;    // don't cancel the event
    return S_OK;
}


/////////////////////////////////////////////////////////////////////////////
// CMessageFilter::IChatChannelCallBack Implementations
//

// Notification that some text is/has been sent to a channel
STDMETHODIMP CMessageFilter::OnChannelText(IChatChannel *pChannel, IChatUser *pUser, IRCCMDTYPE Type, BSTR *Message, VARIANT_BOOL varbPostUpdate, long *pCancel)
{
    if( varbPostUpdate == VARIANT_FALSE ) { // Pre-Update message, allows us to modify its intent
        WORDLIST::iterator it;
        bool badUser = false;

        // Iterate though each word, checking for a substring match, change to *'s
        for(it = m_FilteredWords.begin(); it != m_FilteredWords.end(); it++) {
            wchar_t *p = *Message;  
            while( p && (p = wcsstr(p, it->m_str)) != NULL ) {
                badUser = true;
                for(wchar_t *q = it->m_str; *q; q++, p++)
                    *p = '*';
            }            
        }

        // Send a message to the user if we filtered any of their text
        if( badUser )
        {
            WCHAR wszReply[128];
            BSTR Nick;
            BSTR Ident;
            
            pUser->get_Nick(&Nick);
            pUser->get_Identity(&Ident);

            swprintf(wszReply, L"%s!%s PRIVMSG %s : You really should not use that language\r\n", Nick, Ident, Nick);
            
            pUser->ProtocolMessageOut( (_bstr_t)wszReply);            

            SysFreeString(Nick);
            SysFreeString(Ident);
        }
    }

    *pCancel = 0;
    return S_OK;
}


/////////////////////////////////////////////////////////////////////////////
// CMessageFilter::ISpecifyPropertyPages Implementation
// - you can copy this routine as-is for your pages

// Override the ISpecifyPropertyPages::GetPages with some 'cut-paste' code that returns
// the list of property pages as defined by the PROPERTY_MAP in the class .H
HRESULT CMessageFilter::ISpecifyPropertyPages_GetPages(CAUUID* pPages, ATL_PROPMAP_ENTRY* pMap)
{
    int nCnt = 0;

    // Get count of unique pages
    for(int i = 0; pMap[i].pclsidPropPage != NULL; i++)
    {
        if (!InlineIsEqualGUID(*pMap[i].pclsidPropPage, CLSID_NULL))
            nCnt++;
    }

    pPages->pElems = NULL;
    pPages->pElems = (GUID*) CoTaskMemAlloc(sizeof(CLSID)*nCnt);
    if (pPages->pElems == NULL)
        return E_OUTOFMEMORY;

    nCnt = 0;
    for(i = 0; pMap[i].pclsidPropPage != NULL; i++) {
        if (!InlineIsEqualGUID(*pMap[i].pclsidPropPage, CLSID_NULL)) {
            BOOL bMatch = FALSE;
            for (int j=0;j<nCnt;j++) {
                if (InlineIsEqualGUID(*(pMap[i].pclsidPropPage), pPages->pElems[j])) {
                    bMatch = TRUE;
                    break;
                }
            }
            if (!bMatch)
                pPages->pElems[nCnt++] = *pMap[i].pclsidPropPage;
        }
    }
    pPages->cElems = nCnt;
    return S_OK;
}

© 1998 Microsoft Corporation. All rights reserved.