PostCatReader.cpp
PostCatReader.cpp
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: PostCatReader.cpp, Implementation of CPostCatReader
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// Contents: PostCatReader Class Implements IMailTransportPostCategorize, IEventIsCacheable
//
// Classes: CPostCatReader
//
// Functions:
// CAttrEntry::operator new
// CAttrList::AddEntry
// CPostCatReader::IsCacheable
// CPostCatReader::CheckIfSinkHasInitalised
// CPostCatReader::CheckIfSinkHasInitalised
// CPostCatReader::HrReadRegParams
// CPostCatReader::PrintRequestedAttribsFromMsg
// CPostCatReader::PrintRequestedAttribsFromRecips
// CPostCatReader::PrintAttribVals
// CPostCatReader::GetAttribPropertyOffSet
// CPostCatReader::HrPrintData
// CPostCatReader::GetAttributeValue
// CPostCatReader::PrintAttrList
//
//-------------------------------------------------------------
#include "stdafx.h"
#include "CatReadEx.h"
#include "PostCatReader.h"
#include "errno.h"
/////////////////////////////////////////////////////////////////////////////
// CPostCatReader
//
//
//-------------------------------------------------------------
//
// Function: CPostCatReader::IsCacheable
//
// Synopsis: Implementation of the method for IEventIsCacheable.
// If it returns S_OK, the sink is cacheable and will not
// be loaded and unloaded every time.
//
// Arguments:
// None
//
//
// Returns:
// S_OK if successful
//
//-------------------------------------------------------------
HRESULT CPostCatReader::IsCacheable()
{
return S_OK;
}
//+------------------------------------------------------------
//
// Function: CPostCatReader::CheckIfSinkHasInitalised
//
// Synopsis: Functions that checks the initialization state. If initialization was
// attempted for the first time, it tries to initialize the sink. It remembers
// the state, if it succeeded or not, and returns it.
//
// Arguments:
// None
//
//
// Returns:
// S_OK if successful
//
//-------------------------------------------------------------
HRESULT CPostCatReader::CheckIfSinkHasInitalised()
{
PCFunctEnterEx((LPARAM)this, "CPostCatReader::CheckIfSinkHasInitalised");
HRESULT hr = S_OK;
BOOL fAcquireCS = FALSE;
// Initialization is attempted only once.
if(m_fTrySinkInit == TRUE)
goto CLEANUP;
EnterCriticalSection(&m_cs);
fAcquireCS = TRUE;
if(m_fTrySinkInit == FALSE) {
hr = HrReadRegParams(&m_attrList);
m_fSinkInitSuccess = SUCCEEDED(hr);
m_fTrySinkInit = TRUE;
if(FAILED(hr)) {
PCErrorTraceEx((LPARAM)this,
"CheckIfSinkHasInitalised failed with 0x%08lx",
hr);
goto CLEANUP;
}
}
CLEANUP:
if(fAcquireCS)
LeaveCriticalSection(&m_cs);
PCFunctLeaveEx((LPARAM)this);
return m_fSinkInitSuccess ? S_OK : S_FALSE;
}
//-------------------------------------------------------------
//
// Function: CPostCatReader::OnMessagePostCategorize
//
// Synopsis: This event is fired for every message that is successfully
// categorized. The sink will intercept the message at this point and attempt
// to retrieve the requested attribute's values, which are saved in the mailmsg.
//
// Arguments:
// [in]
// IMailMsgProperties *pIMailMsgProperties,
// IMailTransportNotify *pINotify,
// PVOID pvNotifyContext
//
// - all defined in smtpevent.idl
//
// Returns:
// S_OK if successful
//
//-------------------------------------------------------------
HRESULT CPostCatReader::OnMessagePostCategorize(
IMailMsgProperties *pIMailMsgProperties,
IMailTransportNotify *pINotify,
PVOID pvNotifyContext)
{
HRESULT hr = S_OK;
PCFunctEnterEx((LPARAM)this, "CPostCatReader::HrSinkInitialize");
IMailMsgPropertyManagement * pIMailMsgPropertyManagement = NULL;
if(S_OK != CheckIfSinkHasInitalised()) {
PCErrorTraceEx((LPARAM)this, "Sink Not Initialized. CatReadEx skipping..");
goto CLEANUP;
}
hr = pIMailMsgProperties->QueryInterface(
IID_IMailMsgPropertyManagement,
(PVOID *)&pIMailMsgPropertyManagement);
if (FAILED(hr)) {
PCErrorTraceEx( (LPARAM) this, "Failed pIMailMsgProperties->QueryInterface 0x%08lx",
hr);
goto CLEANUP;
}
ShowMessage("\n\n");
ShowMessage("===================================================================");
ShowMessage("Message");
ShowMessage("*******");
hr = PrintRequestedAttribsFromMsg(
pIMailMsgProperties,
pIMailMsgPropertyManagement);
if(FAILED(hr)) {
ShowMessage("Failed to get requested attributes from message");
// Try to do the same for recipients.
}
hr = PrintRequestedAttribsFromRecips(
pIMailMsgProperties,
pIMailMsgPropertyManagement);
if(FAILED(hr)) {
ShowMessage("Failed to get requested attributes from recipients");
}
ShowMessage("\n\n");
CLEANUP:
if (pIMailMsgPropertyManagement != NULL)
pIMailMsgPropertyManagement->Release();
PCFunctLeaveEx((LPARAM)this);
return SUCCEEDED(hr) ? S_OK : hr;
}
//-------------------------------------------------------------
//
// Function: CPostCatReader::PrintRequestedAttribsFromMsg
//
// Synopsis: Prints the requested attributes found on the sender
//
// Arguments:
// [in]
// IMailMsgProperties * pIMailMsgProperties,
// IMailMsgPropertyManagement * pIMailMsgPropertyManagement
//
// - defined in smtpevent.idl
//
// Returns:
// S_OK if successful
//
//-------------------------------------------------------------
HRESULT CPostCatReader::PrintRequestedAttribsFromMsg(
IMailMsgProperties * pIMailMsgProperties,
IMailMsgPropertyManagement * pIMailMsgPropertyManagement)
{
HRESULT hr = S_OK;
PCFunctEnterEx((LPARAM)this, "CPostCatReader::PrintRequestedAttributesFromMsg");
TCHAR szSenderSmtpAddress[MAX_EMAIL_LENGTH];
hr = pIMailMsgProperties->GetStringA(
IMMPID_MP_SENDER_ADDRESS_SMTP,
MAX_EMAIL_LENGTH,
(TCHAR *)szSenderSmtpAddress);
if(FAILED(hr) && hr != MAILMSG_E_PROPNOTFOUND ) {
PCErrorTraceEx((LPARAM)this, "pIMailMsgProperties->GetStringA failed with 0x%08lx",
hr);
goto CLEANUP;
}
// For debugging, output the sender.
if (SUCCEEDED(hr))
ShowMessage("CatReadEx Detected Sender: %s", szSenderSmtpAddress);
hr = PrintAttrList(
pIMailMsgPropertyManagement,
pIMailMsgProperties,
NULL,
0);
if(FAILED(hr)) {
PCErrorTraceEx((LPARAM)this, "PrintAttrList failed with 0x%08lx",
hr);
goto CLEANUP;
}
CLEANUP:
PCFunctLeaveEx((LPARAM)this);
return hr;
}
//-------------------------------------------------------------
//
// Function: CPostCatReader::PrintRequestedAttribsFromRecips
//
// Synopsis: Prints the requested attributes found on every recipient
//
// Arguments:
// [in]
// IMailMsgProperties * pIMailMsgProperties,
// IMailMsgPropertyManagement * pIMailMsgPropertyManagement
//
// - defined in smtpevent.idl
//
// Returns:
// S_OK if successful
//
//-------------------------------------------------------------
HRESULT CPostCatReader::PrintRequestedAttribsFromRecips(
IMailMsgProperties * pIMailMsgProperties,
IMailMsgPropertyManagement * pIMailMsgPropertyManagement )
{
HRESULT hr = S_OK;
PCFunctEnterEx((LPARAM)this, "CPostCatReader::PrintRequestedAttribsFromRecips");
IMailMsgRecipients * pIMailMsgRecipients = NULL;
DWORD dwcRecipCount;
DWORD dwRecipIndex;
TCHAR szRecipientSmtpAddress[MAX_EMAIL_LENGTH];
// Query the MailMsgRecipients interface.
hr = pIMailMsgProperties->QueryInterface(
IID_IMailMsgRecipients,
(LPVOID *)&pIMailMsgRecipients);
if(FAILED(hr)) {
PCErrorTraceEx((LPARAM)this, "pIMailMsgProperties->QueryInterface failed with 0x%08lx",
hr);
goto CLEANUP;
}
// Get the total count of recipients in pIMailMsgRecipients.
hr = pIMailMsgRecipients->Count(&dwcRecipCount);
if(FAILED(hr)) {
PCErrorTraceEx((LPARAM)this, "pIMailMsgRecipients->Count failed with 0x%08lx",
hr);
goto CLEANUP;
}
// Enumerate through the recipients.
for (dwRecipIndex = 0; dwRecipIndex < dwcRecipCount; dwRecipIndex++) {
CAttrEntry * pCurrent = NULL;
hr = pIMailMsgRecipients->GetStringA(
dwRecipIndex,
IMMPID_RP_ADDRESS_SMTP,
MAX_EMAIL_LENGTH,
(LPTSTR) szRecipientSmtpAddress);
if(FAILED(hr) && hr != MAILMSG_E_PROPNOTFOUND) {
PCErrorTraceEx((LPARAM)this, "pIMailMsgRecipients->GetStringA failed with 0x%08lx",
hr);
goto CLEANUP;
}
ShowMessage("Recipient");
ShowMessage("*******");
// For debugging, output the recipient address.
if (SUCCEEDED(hr))
ShowMessage("\nCatReadEx Detected Recipient #%ld : %s",
dwRecipIndex+1,
szRecipientSmtpAddress);
// Traverse through the list of requested attributes and print out its values.
hr = PrintAttrList(
pIMailMsgPropertyManagement,
NULL,
pIMailMsgRecipients,
dwRecipIndex);
if(FAILED(hr)) {
PCErrorTraceEx((LPARAM)this, "PrintAttrList failed with 0x%08lx",
hr);
goto CLEANUP;
}
}
CLEANUP:
if (pIMailMsgRecipients != NULL)
pIMailMsgRecipients->Release();
PCFunctLeaveEx((LPARAM)this);
return hr;
}
//-------------------------------------------------------------
//
// Function: CPostCatReader::PrintAttrList
//
// Synopsis: Prints the requested attributes from the list
//
// Arguments:
// [in]
// IMailMsgProperties * pIMailMsgProperties,
// IMailMsgPropertyManagement * pIMailMsgPropertyManagement
//
// - defined in smtpevent.idl
//
// Returns:
// S_OK if successful
//
//-------------------------------------------------------------
HRESULT CPostCatReader::PrintAttrList(
IMailMsgPropertyManagement * pIMailMsgPropertyManagement,
IMailMsgProperties *pIMailMsgProperties,
IMailMsgRecipients *pIMailMsgRecipients,
DWORD dwRecipIndex) {
HRESULT hr = S_OK;
CAttrEntry *pCurrent = NULL;
PCFunctEnterEx((LPARAM)this, "CPostCatReader::PrintAttrList");
// Traverse through the list of requested attributes, and print out its values.
pCurrent = m_attrList.GetHeadEntry();
while(NULL != pCurrent) {
hr = PrintAttribVals(
pIMailMsgPropertyManagement,
pIMailMsgProperties,
pIMailMsgRecipients,
dwRecipIndex,
pCurrent);
if(FAILED(hr)) {
PCErrorTraceEx((LPARAM)this, "PrintAttribVals failed with 0x%08lx",
hr);
// Get the next attribute.
hr = S_OK;
}
pCurrent = m_attrList.GetNextEntry(pCurrent);
}
PCFunctLeaveEx((LPARAM)this);
return hr;
}
//-------------------------------------------------------------
//
// Function: CPostCatReader::PrintAttribVals
//
// Synopsis: Prints attribute value
//
// Arguments:
// [in]
// IMailMsgPropertyManagement * pIMailMsgPropertyManagement,
// IMailMsgProperties *pIMailMsgProperties,
// IMailMsgRecipients *pIMailMsgRecipients,
// DWORD dwRecipIndex,
// CAttrEntry * pCurrent
//
// Returns:
// S_OK if successful
//
//-------------------------------------------------------------
HRESULT CPostCatReader::PrintAttribVals(
IMailMsgPropertyManagement * pIMailMsgPropertyManagement,
IMailMsgProperties *pIMailMsgProperties,
IMailMsgRecipients *pIMailMsgRecipients,
DWORD dwRecipIndex,
CAttrEntry * pCurrent)
{
HRESULT hr = S_OK;
PCFunctEnterEx((LPARAM)this, "CPostCatReader::PrintAttribVals");
DWORD dwPropertyID;
DWORD dwcValues;
DWORD dwIndex = 0;
// Finds the allocated property ID requested for this attribute.
hr = GetAttribPropertyOffSet(
pIMailMsgPropertyManagement,
pIMailMsgProperties,
pIMailMsgRecipients,
dwRecipIndex,
pCurrent,
&dwPropertyID,
&dwcValues);
if(FAILED(hr)) {
PCErrorTraceEx( (LPARAM) this, "Failed GetAttribPropertyOffSet 0x%08lx",
hr);
goto CLEANUP;
}
if(dwcValues == 0)
// Check to see if any attribute values were found.
ShowMessage("\tCatReadEx Did Not Find Any Values For Requested Attribute %s",
pCurrent->GetAttrName());
else
ShowMessage("\tCatReadEx Found Requested Attribute %s with %ld values starting from PropId %ld",
pCurrent->GetAttrName(),
dwcValues,
dwPropertyID);
for (dwIndex = 0; dwIndex < dwcValues; dwIndex++) {
hr = GetAttributeValue(pIMailMsgPropertyManagement,
pIMailMsgProperties,
pIMailMsgRecipients,
dwRecipIndex,
pCurrent,
dwPropertyID + dwIndex);
if(FAILED(hr)) {
PCErrorTraceEx( (LPARAM) this, "Failed GetAttributeValue 0x%08lx",
hr);
goto CLEANUP;
}
}
CLEANUP:
PCFunctLeaveEx((LPARAM)this);
return hr;
}
//-------------------------------------------------------------
//
// Function: CPostCatReader::GetAttributeValue
//
// Synopsis: Gets attribute value
//
// Arguments:
// [in]
// IMailMsgPropertyManagement * pIMailMsgPropertyManagement,
// IMailMsgProperties *pIMailMsgProperties,
// IMailMsgRecipients *pIMailMsgRecipients,
// DWORD dwRecipIndex,
// CAttrEntry * pCurrent
// DWORD dwPropertyID
//
// Returns:
// S_OK if successful
//
//-------------------------------------------------------------
HRESULT CPostCatReader::GetAttributeValue(IMailMsgPropertyManagement * pIMailMsgPropertyManagement,
IMailMsgProperties *pIMailMsgProperties,
IMailMsgRecipients *pIMailMsgRecipients,
DWORD dwRecipIndex,
CAttrEntry * pCurrent,
DWORD dwPropertyID) {
HRESULT hr = S_OK;
DWORD dwcbAlloc;
PBYTE pbAttributeValue = NULL;
BYTE bSilly;
DWORD dwcb;
PCFunctEnterEx((LPARAM)this, "CPostCatReader::GetAttributeValue");
// You know the property ID for the value. Do a dummy call on the GetProperty
// to get the length for this value in bytes. You can then allocate memory
// accordingly.
if (pIMailMsgRecipients)
hr = pIMailMsgRecipients->GetProperty(
dwRecipIndex,
dwPropertyID,
0,
&dwcbAlloc,
&bSilly);
else
hr = pIMailMsgProperties->GetProperty(
dwPropertyID,
0,
&dwcbAlloc,
&bSilly);
if(SUCCEEDED(hr) || (hr == MAILMSG_E_PROPNOTFOUND)) {
PCDebugTraceEx((LPARAM)this, "Error Did Not Find Expected Value for Attribute %s - PropId %ld",
pCurrent->GetAttrName(),
dwPropertyID);
ShowMessage("Error Did not find expected Value for Attribute %s - PropId %ld",
pCurrent->GetAttrName(),
dwPropertyID);
hr = MAILMSG_E_PROPNOTFOUND;
goto CLEANUP;
} else if(FAILED(hr) && (hr != HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER))) {
PCErrorTraceEx((LPARAM)this, "GetProperty failed with 0x%08lx",
hr);
goto CLEANUP;
}
// Allocate for the value.
pbAttributeValue = new BYTE[dwcbAlloc];
if(pbAttributeValue == NULL) {
hr = E_OUTOFMEMORY;
PCErrorTraceEx((LPARAM)this, "pbAttributeValue alloc failed for %ld bytes 0x%08lx",
dwcbAlloc,
hr);
goto CLEANUP;
}
// Get the attribute value now (strings are not null terminated).
if (pIMailMsgRecipients) {
hr = pIMailMsgRecipients->GetProperty(
dwRecipIndex,
dwPropertyID,
dwcbAlloc,
&dwcb,
pbAttributeValue);
}
else
hr = pIMailMsgProperties->GetProperty(
dwPropertyID,
dwcbAlloc,
&dwcb,
pbAttributeValue);
if(FAILED(hr)) {
PCErrorTraceEx((LPARAM)this, "GetProperty failed with 0x%08lx",
hr);
goto CLEANUP;
}
_ASSERT(dwcb = dwcbAlloc);
// Dump data.
hr = HrPrintData(dwcbAlloc,
pbAttributeValue);
if(FAILED(hr)){
PCErrorTraceEx((LPARAM)this, "HrPrintData failed with 0x%08lx",
hr);
goto CLEANUP;
}
CLEANUP:
if(pbAttributeValue != NULL)
delete [] pbAttributeValue;
PCFunctLeaveEx((LPARAM)this);
return hr;
}
//-------------------------------------------------------------
//
// Function: CPostCatReader::GetAttribPropertyOffSet
//
// Synopsis: GetAttribPropertyOffSet - Returns the property ID
// offset to where the attribute values are stored
// Arguments:
// [in]
// IMailMsgPropertyManagement * pIMailMsgPropertyManagement,
// IMailMsgProperties *pIMailMsgProperties,
// IMailMsgRecipients *pIMailMsgRecipients,
// DWORD dwRecipIndex,
// CAttrEntry * pCurrent
//
// Returns:
// S_OK if successful
//
//-------------------------------------------------------------
HRESULT CPostCatReader::GetAttribPropertyOffSet(
IMailMsgPropertyManagement * pIMailMsgPropertyManagement,
IMailMsgProperties *pIMailMsgProperties,
IMailMsgRecipients *pIMailMsgRecipients,
DWORD dwRecipIndex,
CAttrEntry * pCurrent,
DWORD *pdwPropertyID,
DWORD *pdwcValues)
{
HRESULT hr = S_OK;
PCFunctEnterEx((LPARAM)this, "CPostCatReader::GetAttribPropertyOffSet");
DWORD dwPropertyID;
DWORD dwcValues;
hr = pIMailMsgPropertyManagement->AllocPropIDRange(
m_attrList.GetAttrGuid(pCurrent),
2,
&dwPropertyID);
if (FAILED(hr)) {
PCErrorTraceEx( (LPARAM) this, "Failed pIMailMsgPropertyManagement->AllocPropIDRange 0x%08lx",
hr);
goto CLEANUP;
}
if(pIMailMsgRecipients)
hr = pIMailMsgRecipients->GetDWORD(
dwRecipIndex,
dwPropertyID,
&dwcValues);
else
hr = pIMailMsgProperties->GetDWORD(
dwPropertyID,
&dwcValues);
if(FAILED(hr)) {
// This is not a fatal error in the case where a recipient or sender is not
// in the directory service (DS).
// Treat this case as if there were no values for the attribute.
dwcValues = 0;
}
*pdwcValues = dwcValues;
if (dwcValues == 0) {
// There were no values for the requested attribute.
hr = S_FALSE;
goto CLEANUP;
}
_ASSERT(SUCCEEDED(hr));
if (dwcValues > 1) {
// This is a multivalued attribute. Get its GUID.
DWORD dwcbAlloc = sizeof(GUID);
DWORD dwcb;
GUID gGuid;
ZeroMemory(&gGuid, sizeof(GUID));
if(pIMailMsgRecipients)
hr = pIMailMsgRecipients->GetProperty(
dwRecipIndex,
dwPropertyID+1,
dwcbAlloc,
&dwcb,
(LPBYTE) &gGuid);
else
hr = pIMailMsgProperties->GetProperty(
dwPropertyID+1,
dwcbAlloc,
&dwcb,
(LPBYTE) &gGuid);
if(FAILED(hr)) {
PCErrorTraceEx((LPARAM)this, "%s->GetProperty failed with 0x%08lx",
pIMailMsgRecipients ? "pIMailMsgRecipients" : "pIMailMsgProperties",
hr);
goto CLEANUP;
}
_ASSERT(dwcb == sizeof(GUID));
// Get the allocated property ID associated with this GUID.
hr = pIMailMsgPropertyManagement->AllocPropIDRange(
gGuid,
dwcValues,
pdwPropertyID);
if (FAILED(hr)) {
PCErrorTraceEx( (LPARAM) this, "Failed pIMailMsgPropertyManagement->AllocPropIDRange 0x%08lx",
hr);
goto CLEANUP;
}
}
else
*pdwPropertyID = dwPropertyID+1;
CLEANUP:
PCFunctLeaveEx((LPARAM)this);
return hr;
}
//-------------------------------------------------------------
//
// Function: CPostCatReader::HrPrintData
//
// Synopsis: Utility function to dump the binary data to the debugger
//
// Arguments:
// [in]
// DWORD dwcbData,
// PBYTE pbData
//
// Returns:
// S_OK if successful
//
//-------------------------------------------------------------
HRESULT CPostCatReader::HrPrintData(
DWORD dwcbData,
PBYTE pbData)
{
PCFunctEnterEx((LPARAM)this, "CPostCatReader::HrPrintData");
HRESULT hr = S_OK;
DWORD dwLineOffset = 0;
DWORD dwHexOffset = 0;
#define MAX_BUFFER 1024
#define PRINTBYTE( byte ) \
*psz++ = szHexDigits[ (byte) >> 4 ]; \
*psz++ = szHexDigits[ (byte) & 0xF ];
OutputDebugString("Offset Data (Hex) ASCII\r\n"
"-----------------------------------------------------------------------------\r\n");
// Print the line offset.
while(dwLineOffset < dwcbData)
{
LONG lCount = 0;
CHAR szHexDigits[] = "0123456789ABCDEF";
CHAR szBuffer[MAX_BUFFER];
LPSTR psz = szBuffer;
for(lCount = sizeof(dwLineOffset) - 1; lCount >= 0; lCount--)
{
PRINTBYTE( ((PBYTE)&dwLineOffset)[lCount] );
}
*psz++ = ' ';
*psz++ = ' ';
*psz++ = ' ';
// Print the hex data.
dwHexOffset = dwLineOffset;
while((dwHexOffset - dwLineOffset) < 16)
{
if(dwHexOffset < dwcbData)
{
PRINTBYTE( pbData[dwHexOffset] );
*psz++ = ' ';
}
else
{
*psz++ = ' ';
*psz++ = ' ';
*psz++ = ' ';
}
dwHexOffset++;
}
*psz++ = ' ';
*psz++ = ' ';
// Print the ASCII data.
dwHexOffset = dwLineOffset;
while((dwHexOffset - dwLineOffset) < 16)
{
if(dwHexOffset < dwcbData)
{
*psz++ = (pbData[dwHexOffset] >= 32) ? pbData[dwHexOffset] : '.';
}
dwHexOffset++;
}
*psz++ = '\r';
*psz++ = '\n';
*psz = '\0';
_ASSERT(lstrlen(szBuffer) < sizeof(szBuffer));
OutputDebugString(szBuffer);
dwLineOffset += 16;
}
OutputDebugString("\r\n");
PCFunctLeaveEx((LPARAM)this);
return hr;
} // HrPrintData