📄 sdkemsviewerruleclient.cpp
字号:
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// Use of this source code is subject to the terms of the Microsoft end-user
// license agreement (EULA) under which you licensed this SOFTWARE PRODUCT.
// If you did not accept the terms of the EULA, you are not authorized to use
// this source code. For a copy of the EULA, please see the LICENSE.RTF on your
// install media.
//
/******************************************************************************
File: SDKEMSViewerRuleClient.cpp
Purpose:
Rule client to intercept EMS messages. It parses the header and user data
and writes info to the message for the EMS custom form to read and process.
Remarks:
Must set these reg keys to register the rule client
[HKCR\CLSID\{7D0E1A87-734C-4d46-B715-327A8884D38B}\InProcServer32]
@="SDKEMSViewerRuleClient.dll"
[HKLM\Software\Microsoft\Inbox\Svc\SMS\Rules]
"{7D0E1A87-734C-4d46-B715-327A8884D38B}" = DWORD : 1
For EMS to work we also need to set a reg key (requires a reboot if the
SMS router has been used)
[HKEY_CURRENT_USER\Software\Microsoft\SMS\TextShared]
DWORD : EMSHandlerInstalled = 1
******************************************************************************/
#define INITGUID
#include "SDKEMSViewerRuleClient.h"
//GLOBALS ////////////////////////////////////////////////////////////////////
// {7D0E1A87-734C-4d46-B715-327A8884D38B}
DEFINE_GUID(CLSID_SDKEMSViewerRuleClient,
0x7d0e1a87, 0x734c, 0x4d46, 0xb7, 0x15, 0x32, 0x7a, 0x88, 0x84, 0xd3, 0x8b);
int g_cServerLocks = 0;
HINSTANCE g_hInstance = NULL;
/*List of components handled in this DLL, each component must be listed here
if it wants to able to be loaded by the class factory
*/
CFactoryData g_rgFactoryData[] =
{
{&CLSID_SDKEMSViewerRuleClient, //CLSID
CRuleClient_EMS::CreateInstance} //Creation function ptr
//Add additional component info here...
//i.e. if you want to add another rule client
};
//Total number of registered components
int g_iFactoryDataEntries = sizeof(g_rgFactoryData) / sizeof(CFactoryData);
/******************************************************************************
IsMultiPartEMS - Checks header for multipart info.
Params:
lpHeaderData[in] - Header data from SM
lpEMShi[in/out] - Header info struct to fill
Returns:
TRUE if Multipart IEIs exits in header, FALSE OTW
Remarks:
******************************************************************************/
BOOL IsMultiPartEMS(LPBYTE lpHeaderData, LPEMSHEADERINFO lpEMShi)
{
BOOL bRet = FALSE;
UINT uCount = 0;
//Validate Params
ASSERT((NULL != lpHeaderData) && (NULL != lpEMShi));
CBR(((NULL != lpHeaderData) && (NULL != lpEMShi)), bRet);
//First IEI should be the Multipart ID if it exists
if(IEI_MULTI_8BIT == lpHeaderData[uCount])
{
//Next octet is length of data, should be 3 octets
uCount++;
ASSERT(0x03 == lpHeaderData[uCount]);
//Next octet is the 8-bit reference number
uCount++;
lpEMShi->smRefIDVal.chRefID = lpHeaderData[uCount];
//Next is total parts
uCount++;
lpEMShi->uNumParts = lpHeaderData[uCount];
//Next is current part
uCount++;
lpEMShi->uCurrPart = lpHeaderData[uCount];
lpEMShi->fRef16Bit = FALSE;
bRet = TRUE;
}
else
if(IEI_MULTI_16BIT == lpHeaderData[uCount])
{
//Next octet is length of data, should be 3 octets
uCount++;
ASSERT(0x03 == lpHeaderData[uCount]);
//Next 2 octets are the 16-bit reference number
uCount++;
lpEMShi->smRefIDVal.wRefID = ((lpHeaderData[uCount] << 8) | lpHeaderData[uCount+1]);
//Next is total parts
uCount++;
lpEMShi->uNumParts = lpHeaderData[uCount];
//Next is current part
uCount++;
lpEMShi->uCurrPart = lpHeaderData[uCount];
lpEMShi->fRef16Bit = TRUE;
bRet = TRUE;
}
Exit:
return bRet;
}
/******************************************************************************
ExtractEMSHeaderInfo - Copies header info to struct and fills in ID etc.
Params:
lpEMShi[in\out] - EMSHEADERINFO struct to fill in
lpHeaderData[in] - EMS header data
cbHeader[in] - size of header data buffer
pszUserData[in] - User text with SM, can be NULL
Returns:
Remarks:
******************************************************************************/
HRESULT ExtractEMSHeaderInfo(LPEMSHEADERINFO lpEMShi,
LPBYTE lpHeaderData,
UINT cbHeader,
LPCTSTR pszUserData)
{
HRESULT hr = S_OK;
//Validate params
ASSERT((NULL != pszUserData) && (NULL != lpEMShi) && (0 < cbHeader) && (NULL != lpHeaderData));
CBRH(((NULL != pszUserData) && (NULL != lpEMShi) && (0 < cbHeader) && (NULL != lpHeaderData)), hr);
//Clear the struct
FREE_EMSHEADERINFO((*lpEMShi));
lpEMShi->lpData = (LPBYTE)malloc(cbHeader);
ASSERT(NULL != lpEMShi->lpData);
CBRH((NULL != lpEMShi->lpData), hr);
//Copy header info, check if multipart, etc
lpEMShi->cbData = cbHeader;
memcpy(lpEMShi->lpData, lpHeaderData, cbHeader);
lpEMShi->fMultiPart = IsMultiPartEMS(lpHeaderData, lpEMShi);
//Copy user data if we need to
if(NULL != *pszUserData)
{
lpEMShi->pszUserData = (LPTSTR)malloc(sizeof(TCHAR)*(_tcslen(pszUserData) + 1));
CBRH((NULL != lpEMShi->pszUserData), hr);
_tcscpy(lpEMShi->pszUserData, pszUserData);
}
Exit:
return hr;
}
/******************************************************************************
SortHeaderInfo - BubbleSorts the list of EMS headers. Not the fastest
sorting algorithm, but the number of headers is almost always small.
Params:
lpemshi[in] - pointer to array of header info
uNumHeaders[in] - count of headers stored in the array
Returns:
void
Remarks:
******************************************************************************/
void SortHeaderInfo(LPEMSHEADERINFO lpemshi, UINT uNumHeaders)
{
int iIndex;
int iItem;
EMSHEADERINFO emshi; //Temp storage
//Bubblesort
for(iIndex = uNumHeaders - 1; iIndex >= 0; iIndex--)
{
for(iItem = 1; iItem <= iIndex; iItem++)
{
if(lpemshi[iItem-1].uCurrPart > lpemshi[iItem].uCurrPart)
{
//swap headers
memcpy(&emshi, &(lpemshi[iItem-1]), sizeof(EMSHEADERINFO));
memcpy(&(lpemshi[iItem-1]), &(lpemshi[iItem]), sizeof(EMSHEADERINFO));
memcpy(&(lpemshi[iItem]), &emshi, sizeof(EMSHEADERINFO));
}
}
}
}
/******************************************************************************
ValidateHeaders - Checks if currently collected headers are ok
Params:
lpemshi[in] - pointer to array of headers to validate
uNumHeaders[in] - number of headers collected so far
Returns:
TRUE on success, FALSE OTW
Remarks:
Headers are invalid if we have more than one, and all the IDs don't match
******************************************************************************/
BOOL ValidateHeaders(LPEMSHEADERINFO lpemshi, UINT uNumHeaders)
{
BOOL bRet = TRUE;
WORD wRefID = 0; //stuff 8-bit in here too...
WORD wTemp = 0;
UINT uIndex = 0;
//Validate params
ASSERT(lpemshi);
ASSERT(uNumHeaders);
CBR((lpemshi && uNumHeaders), bRet);
if(1 == uNumHeaders) //Impossible to have a conflict yet
{
goto Exit;
}
//Get the ID from the first element
wRefID = lpemshi[0].fRef16Bit ? lpemshi[0].smRefIDVal.wRefID : lpemshi[0].smRefIDVal.chRefID;
//Multiple case
for(uIndex = 1; uIndex < uNumHeaders; uIndex++)
{
//Every other one better match
wTemp = lpemshi[uIndex].fRef16Bit ? lpemshi[uIndex].smRefIDVal.wRefID : lpemshi[uIndex].smRefIDVal.chRefID;
CBR((wTemp == wRefID), bRet);
}
Exit:
return bRet;
}
/******************************************************************************
DeleteMessage - Deletes a message
Params:
pMsgStore[in] - Store where message exists
pMsg[in] - message to delete
cbMsg[in] - size of message in bytes
lpMsg[in] - entryid of message
cbDestFolder[in] - size of dest folder
lpDestFolder[in] - folder where message resides
pulEventType[in/out] - tracks what's been done to the message
pHandled[in/out] - has rule client handled the message or not?
Returns:
S_OK on success, HRESULT error code OTW
Remarks:
******************************************************************************/
HRESULT DeleteMessage(IMsgStore *pMsgStore,
IMessage *pMsg,
ULONG cbMsg,
LPENTRYID lpMsg,
ULONG cbDestFolder,
LPENTRYID lpDestFolder,
ULONG *pulEventType,
MRCHANDLED *pHandled)
{
HRESULT hr = S_OK;
IMAPIFolder *pFolder = NULL;
ENTRYLIST lst;
SBinary sbin;
UNREFERENCED_PARAMETER(pHandled);
UNREFERENCED_PARAMETER(pMsg);
//Get the folder the message is in
hr = pMsgStore->OpenEntry(cbDestFolder, lpDestFolder, NULL, 0, NULL, (LPUNKNOWN*)&pFolder);
if(FAILED(hr))
{
RETAILMSG(TRUE, (_T("Couldn't get the folder!\r\n")));
goto Exit;
}
//Set up the entry list
lst.cValues = 1; //Just the one item
lst.lpbin = &sbin; //binary entry
sbin.cb = cbMsg; //Size of message in bytes
sbin.lpb = (LPBYTE)lpMsg; //Pointer to message
//Delete the message from the folder
hr = pFolder->DeleteMessages(&lst, NULL, NULL, 0);
if(FAILED(hr))
{
RETAILMSG(TRUE, (_T("Couldn't delete messages!\r\n")));
goto Exit;
}
//Record action taken on the message
*pulEventType = fnevObjectDeleted;
Exit:
//Done using the folder
SAFE_RELEASE(pFolder);
return hr;
}
/******************************************************************************
ProcessEMS - Process each EMS header. Order is assured for this function
Params:
emshi[in] - header info for current part
ppszOut[in/out] - Final string to write to message body, if NULL and return
value is ok, then we're not done processing. If non-NULL and return
value is ok, then we're done
pNumObjects[in/out] - number of objects in EMS, 0 if fail or not done
Returns:
S_OK on success, E_FAIL OTW
Remarks:
output format in string form is...
[Obj Len1][Obj Data1]...[Obj'N' Len][Obj Data'N']
4 4
Bottom number is number of TCHARS...
******************************************************************************/
HRESULT ProcessEMS(EMSHEADERINFO emshi,
LPTSTR* ppszOut,
UINT* pNumObjects)
{
HRESULT hr = S_OK;
BYTE chIEI = 0;
BYTE chIEIDL = 0;
UINT uCount = 0;
TCHAR szBuffer[MAX_PATH] = _T("");
LPTSTR pszTemp = NULL;
UINT uChar = 0;
UINT uLenTemp = 0;
static TCHAR* szBodyOut = NULL;
static UINT uBaseOffset = 0;
static UINT uObjCount = 0;
//Validate params, user data can be NULL
ASSERT(NULL != ppszOut);
ASSERT(NULL != pNumObjects);
if((NULL == ppszOut) || (NULL == pNumObjects))
{
RETAILMSG(TRUE, (_T("ProcessEMS - ERROR!!! invalid argument(s)")));
hr = E_INVALIDARG;
goto Exit;
}
//skip to first IEI if multipart SM
if(emshi.fMultiPart)
{
uCount += 5; //1 for length, 3 for IEID info, 1 to point to next IEI
}
//It's possible a portion of the EMS will contain only text
//picture or other element won't fix so check for that
if(uCount == emshi.cbData)
{
//[ID = IEI_TEXT_ONLY][Text Len][Text]
UINT uConv = 0;
UINT uPos = 0;
UINT uStrLen = 0;
TCHAR szConv[3] = _T("");
//We'd better have text or else the message was empty?
ASSERT(emshi.pszUserData);
uStrLen = _tcslen(emshi.pszUserData);
//Allocate room for the user data
pszTemp = (TCHAR*)malloc(sizeof(TCHAR) * (uStrLen + 5));
ASSERT(pszTemp);
ZeroMemory(pszTemp, sizeof(TCHAR) * (_tcslen(emshi.pszUserData) + 5));
//Add the ID
_tcscat(pszTemp, _T("FF")); //IEI_TEXT_ONLY
//Add the length
szConv[0] = _T('0');
uPos = (uStrLen < 0x10) ? 1 : 0;
_itot(uStrLen, &(szConv[uPos]), BASE_HEX);
_tcscat(pszTemp, szConv);
//Add the data
_tcscat(pszTemp, emshi.pszUserData);
uObjCount++; //Increase object count
uBaseOffset += uStrLen; //Increase offset
}
else
{
//Get each IEI and IED segments
while(uCount < emshi.cbData)
{
//Now we should be pointing to the next IEI
chIEI = emshi.lpData[uCount];
uCount++;
//In all cases the next octet is the length of data IEIDL
chIEIDL = emshi.lpData[uCount];
uCount++;
switch(chIEI)
{
//Only supported objects in the sample
case IEI_LARGE_PICTURE:
case IEI_SMALL_PICTURE:
case IEI_VARIABLE_PICTURE:
{
//This works since the IEIs are in order 0x10, 0x11, 0x12
int iType = chIEI - IEI_LARGE_PICTURE;
ASSERT((iType >= 0) && (iType <= 2));
//Create object to deal with the picture info
CEMSPicture* pPicture = new CEMSPicture(&(emshi.lpData[uCount]),
chIEIDL,
uBaseOffset,
emshi.pszUserData,
iType);
ASSERT(NULL != pPicture);
CBRH((NULL != pPicture), hr);
//Grab the data
CBRH((pPicture->ExtractInfoFromHeader()), hr);
//Do some validation on that data
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -