// --rulecls.cpp-------------------------------------------------------------
//
// API entry points into the Rule Class Library (rulecls).
//
// Copyright (C) Microsoft Corp. 1986-1996. All rights reserved.
//
// ---------------------------------------------------------------------------
#include "edk.h"
#include <errno.h>
#include "srowlst.h"
#include "ruleclsf.h"
#include "proptag.h"// temporary location for GetPropTag* functions.
#include "toktypes.h"
#include "rulecls.chk"
//
// Manifest constants.
//
#defineRES_UNINITIALIZED((ULONG) 0xffffffff)
//
// Macros
//
// ISNONTERMINALRESTRICTION() returns TRUE if lpRes is a nonterminal restriction
#define ISNONTERMINALRESTRICTION(lpRes)(((lpRes)->rt == RES_AND)||\
((lpRes)->rt == RES_OR)||\
((lpRes)->rt == RES_NOT))
// Forward function declarations.
static
HRESULT
HrAdrListDisplayNamesToString(
INLPADRLISTlpAdrList,
IN OUTLPSTR FAR *lppszString,
IN OUTLPULONGlpcbString,
IN OUTLPULONGlpcbBuffer
);
static
HRESULT
HrAndRestrictionToString(
INLPSRestrictionlpRes,
IN OUTLPSTR FAR *lppszString,
IN OUTLPULONGlpcbString,
IN OUTLPULONGlpcbBuffer
);
static
HRESULT
HrContentRestrictionToString(
INLPSRestrictionlpRes,
IN OUTLPSTR FAR *lppszString,
IN OUTLPULONGlpcbString,
IN OUTLPULONGlpcbBuffer
);
static
HRESULT
HrCopyProps(
INintcprop,
INLPSPropValuergprop,
OUTLPVOIDpvDst,
OUTULONG FAR * pcb
);
static
HRESULT
HrCopyRestrictionArray(
INLPSRestrictionlpResSrc,
INLPVOIDlpObject,
INULONGcRes,
OUTLPSRestrictionlpResDest
);
static
HRESULT
HrCountProps(
INint cprop,
INLPSPropValuergprop,
OUTULONG FAR *pcb
);
static
HRESULT
HrCreateReplyMsg(
INLPMAPIFOLDERlpFolder,
INLPSTRlpszReplyText,
INLPVOIDlpObject,
OUTULONG FAR *lpcbentryid,
OUTLPENTRYID FAR *lppentryid
);
static
HRESULT
HrDupPropset(
INintcprop,
INLPSPropValuergprop,
INLPVOIDlpObject,
OUTLPSPropValue FAR *prgprop
);
static
HRESULT
HrGetExplicitTag(
IN OUTTOKENINFO *pti
);
static
HRESULT
HrGetExpressionToken(
IN OUTTOKENINFO *pti
);
static
HRESULT
HrGetFolderPath(
INLPMDBlpMDB,
INULONGcbentryid,
INLPENTRYIDlpentryid,
OUTLPSTR FAR *lppszFolderPath
);
static
HRESULT
HrGetMoveCopyArgs(
INLPMAPISESSIONlpSession,
INLPSTRpszFolder,
INLPVOIDlpObject,
IN OUTLPACTIONlpAction
);
static
HRESULT
HrGetNamedTag(
IN OUTTOKENINFO *pti
);
static
HRESULT
HrGetNumericLiteral(
IN OUTTOKENINFO *pti
);
static
HRESULT
HrGetStoreName(
INLPMDBlpMDB,
OUTLPSTR FAR *lppszName
);
static
HRESULT
HrGetStringLiteral(
IN OUTTOKENINFO *pti
);
static
HRESULT
HrGetTimeLiteral(
IN OUTTOKENINFO *pti
);
static
HRESULT
HrNotRestrictionToString(
INLPSRestrictionlpRes,
IN OUTLPSTR FAR *lppszString,
IN OUTLPULONGlpcbString,
IN OUTLPULONGlpcbBuffer
);
static
HRESULT
HrOrRestrictionToString(
INLPSRestrictionlpRes,
IN OUTLPSTR FAR *lppszString,
IN OUTLPULONGlpcbString,
IN OUTLPULONGlpcbBuffer
);
static
HRESULT
HrParseAction(
INLPMAPISESSIONlpSession,
INLPMAPIFOLDERlpFolder,
INLPVOIDlpObject,
INCHAR *pch,
IN OUTLPACTIONlpAction
);
static
HRESULT
HrParseCondition(
INLPVOIDlpObject,
IN OUTCHAR **ppch,
IN OUTLPSRestrictionlpRes
);
static
HRESULT
HrPrintToString(
IN OUTLPSTR FAR *lppszString,
IN OUTLPULONGlpcbString,
IN OUTLPULONGlpcbBuffer,
INLPSTRFormat
...
);
static
HRESULT
HrPrivateRestrictionToString(
INLPSRestrictionlpRes,
IN OUTLPSTR FAR *lppszString,
IN OUTLPULONGlpcbString,
IN OUTLPULONGlpcbBuffer
);
static
HRESULT
HrPropertyRestrictionToString(
INLPSRestrictionlpRes,
IN OUTLPSTR FAR *lppszString,
IN OUTLPULONGlpcbString,
IN OUTLPULONGlpcbBuffer
);
static
HRESULT
HrPropValueToString(
INLPSPropValuelpProp,
IN OUTLPSTR FAR *lppszString,
IN OUTLPULONGlpcbString,
IN OUTLPULONGlpcbBuffer
);
inline
CHAR *
lpszSkipNonWhiteSpace(
INCHAR *pch
);
inline
CHAR *
lpszSkipWhiteSpace(
INCHAR *pch
);
//
// Public functions
//
// $--HrCopyActions------------------------------------------------------------
//
// DESCRIPTION:Make a copy of an ACTIONS structure and all its subelements.
//
// INPUT:
//
//[lpActsSrc]-- Ptr to ACTIONS structure to be copied.
//[lpObject]-- Ptr to an existing MAPI buffer allocated by
// MAPIAllocateBuffer(), or NULL if the returned structure
// is to be allocated using MAPIAllocateBuffer().
// OUTPUT:
//
//[lppActsDest]-- Ptr to be set to copy of ACTIONS structure.
//
// RETURNS: NOERRORif successful;
// E_INVALIDARGif bad input;
//E_OUTOFMEMORYif out of memory;
// E_FAILotherwise.
//-----------------------------------------------------------------------------
STDAPI
HrCopyActions(// RETURNS: HRESULT
INLPACTIONSlpActsSrc, // source action ptr
INLPVOIDlpObject,// ptr to existing MAPI buffer
OUTLPACTIONS FAR *lppActsDest // ptr to destination ACTIONS buffer
)
{
BOOLfNullObject =(lpObject == NULL);
HRESULThr =NOERROR;
ULONGi =0;
LPACTIONlpActDest =NULL;
LPACTIONlpActSrc =NULL;
LPACTIONSlpActsDest =NULL;
DEBUGPUBLIC("HrCopyActions()\n");
hr = CHK_HrCopyActions(lpActsSrc, lpObject, lppActsDest);
if (FAILED(hr))
RETURN(hr);
*lppActsDest = NULL;
if (lpActsSrc->cActions <= 0 || lpActsSrc->lpAction == NULL)
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}
if (lpObject != NULL)
{
hr = MAPIAllocateMore(sizeof(ACTIONS),
lpObject,
(LPVOID FAR *)lppActsDest);
}
else
{
hr = MAPIAllocateBuffer(sizeof(ACTIONS),
(LPVOID FAR *)lppActsDest);
lpObject = *lppActsDest;
}
if (FAILED(hr))
goto cleanup;
lpActsDest = *lppActsDest;
*lpActsDest = *lpActsSrc;
lpActsDest->lpAction = NULL;
hr = MAPIAllocateMore(sizeof(ACTION) * lpActsDest->cActions,
lpObject,
(LPVOID FAR *)&(lpActsDest->lpAction));
if (FAILED(hr))
goto cleanup;
// Initialize acttype values for all members of the array to a value
// that will not cause deallocation errors should the copy fail.
for (i = 0; i < lpActsDest->cActions; i++)
lpActsDest->lpAction[i].acttype = OP_BOUNCE;
// Now actually copy all the members of the array. The number of
// actions should be small, so we don't worry about a more efficient
// loop implementation (getting rid of i and just using ptrs).
for (i = 0; i < lpActsDest->cActions; i++)
{
lpActDest =&(lpActsDest->lpAction[i]);
lpActSrc =&(lpActsSrc->lpAction[i]);
*lpActDest = *lpActSrc;
// Note -Any 0 source allocations (ie. cb==0 or ptr==NULL) cause
//the function to fail. If there are instances in which
//such input is valid, we should evaluate them case by
//case.
switch (lpActSrc->acttype)
{
case OP_MOVE:// actMoveCopy
case OP_COPY:
{
if (lpActDest->actMoveCopy.cbStoreEntryId == 0||
lpActDest->actMoveCopy.lpStoreEntryId == NULL||
lpActDest->actMoveCopy.cbFldEntryId == 0||
lpActDest->actMoveCopy.lpFldEntryId == NULL)
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}
hr = MAPIAllocateMore(lpActDest->actMoveCopy.cbStoreEntryId,
lpObject,
(LPVOID FAR *)
&(lpActDest->actMoveCopy.lpStoreEntryId));
if (FAILED(hr))
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}
memcpy(lpActDest->actMoveCopy.lpStoreEntryId,
lpActSrc->actMoveCopy.lpStoreEntryId,
lpActSrc->actMoveCopy.cbStoreEntryId);
hr = MAPIAllocateMore(lpActDest->actMoveCopy.cbFldEntryId,
lpObject,
(LPVOID FAR *)
&(lpActDest->actMoveCopy.lpFldEntryId));
if (FAILED(hr))
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}
memcpy(lpActDest->actMoveCopy.lpFldEntryId,
lpActSrc->actMoveCopy.lpFldEntryId,
lpActSrc->actMoveCopy.cbFldEntryId);
break;
}
case OP_REPLY:// actReply
case OP_OOF_REPLY:
{
if (lpActDest->actReply.cbEntryId == 0||
lpActDest->actReply.lpEntryId == NULL)
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}
hr = MAPIAllocateMore(lpActDest->actReply.cbEntryId,
lpObject,
(LPVOID FAR *)
&(lpActDest->actReply.lpEntryId));
if (FAILED(hr))
goto cleanup;
memcpy(lpActDest->actReply.lpEntryId,
lpActSrc->actReply.lpEntryId,
lpActSrc->actReply.cbEntryId);
break;
}
case OP_DEFER_ACTION:// actDeferAction
{
if (lpActSrc->actDeferAction.pbData == NULL||
lpActSrc->actDeferAction.cbData == 0)
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}
hr = MAPIAllocateMore(lpActDest->actDeferAction.cbData,
lpObject,
(LPVOID FAR *)
&(lpActDest->actDeferAction.pbData));
if (FAILED(hr))
goto cleanup;
memcpy(lpActDest->actDeferAction.pbData,
lpActSrc->actDeferAction.pbData,
lpActDest->actDeferAction.cbData);
break;
}
case OP_BOUNCE:// scBounceCode
{
// Nothing to do!
break;
}
case OP_FORWARD:// lpadrlist
case OP_DELEGATE:
{
ULONGcEntries =0;
ULONGi =0;
LPADRLISTlpAdrListSrc =lpActSrc->lpadrlist;
LPADRLISTlpAdrListDest =NULL;
lpActDest->lpadrlist = NULL;
if (lpAdrListSrc == NULL || lpAdrListSrc->cEntries == 0)
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}
hr = MAPIAllocateMore(CbADRLIST(lpAdrListSrc),
lpObject,
(LPVOID FAR *)&(lpActDest->lpadrlist));
if (FAILED(hr))
goto cleanup;
cEntries = lpAdrListSrc->cEntries;
lpAdrListDest = lpActDest->lpadrlist;
lpAdrListDest->cEntries = cEntries;
// Initialize the new ADRENTRY's and validate cValues.
for (i = 0; i < cEntries; i++)
{
lpAdrListDest->aEntries[i] = lpAdrListSrc->aEntries[i];
lpAdrListDest->aEntries[i].rgPropVals = NULL;
if (lpAdrListDest->aEntries[i].cValues == 0)
hr = HR_LOG(E_FAIL);
}
if (FAILED(hr))
goto cleanup;
// Copy the rgPropVals.
for (i = 0; i < cEntries; i++)
{
hr = HrDupPropset(lpAdrListDest->aEntries[i].cValues,
lpAdrListSrc->aEntries[i].rgPropVals,
lpObject,
&lpAdrListDest->aEntries[i].rgPropVals);
if (FAILED(hr))
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}
}
break;
}
case OP_TAG:// propTag
{
hr = PropCopyMore(&lpActDest->propTag,
&lpActSrc->propTag,
MAPIAllocateMore,
lpObject);
if (FAILED(hr))
{
if (hr != MAPI_E_NOT_ENOUGH_MEMORY)
hr = HR_LOG(E_FAIL);
goto cleanup;
}
break;
}
case OP_DELETE:// union not used
case OP_MARK_AS_READ:
{
// Nothing to do!
break;
}
default:// error!
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}
}
}
cleanup:
if (FAILED(hr))
{
if (fNullObject)
MAPIFREEBUFFER(*lppActsDest);
}
RETURN(hr);
}
// $--HrCopyRestriction--------------------------------------------------------
//
// DESCRIPTION:Make a copy of an SRestriction structure and all its
//subelements.
//
// INPUT:
//
//[lpResSrc]-- Ptr to restriction to be copied.
//[lpObject]-- Ptr to an existing MAPI buffer allocated by
// MAPIAllocateBuffer(), or NULL if the returned structure
// is to be allocated using MAPIAllocateBuffer().
//
// OUTPUT:
//
//[lppResDest]-- Ptr to be set to copy of restriction.
//
// RETURNS: NOERRORif successful;
//E_INVALIDARGif bad input;
//E_OUTOFMEMORYif out of memory;
// E_FAILotherwise.
//-----------------------------------------------------------------------------
STDAPI
HrCopyRestriction(// RETURNS: HRESULT
INLPSRestrictionlpResSrc, // source restriction ptr
INLPVOIDlpObject,// ptr to existing MAPI buffer
OUTLPSRestriction FAR *lppResDest // dest restriction buffer ptr
)
{
BOOLfNullObject =(lpObject == NULL);
HRESULThr =NOERROR;
DEBUGPUBLIC("HrCopyRestriction()\n");
hr = CHK_HrCopyRestriction(lpResSrc, lpObject, lppResDest);
if (FAILED(hr))
RETURN(hr);
*lppResDest = NULL;
if (lpObject != NULL)
{
hr = MAPIAllocateMore(sizeof(SRestriction),
lpObject,
(LPVOID FAR *)lppResDest);
}
else
{
hr = MAPIAllocateBuffer(sizeof(SRestriction),
(LPVOID FAR *)lppResDest);
lpObject = *lppResDest;
}
if (FAILED(hr))
goto cleanup;
hr = HrCopyRestrictionArray(lpResSrc, lpObject, 1, *lppResDest);
if (FAILED(hr))
{
if (fNullObject)
MAPIFREEBUFFER(*lppResDest);
}
cleanup:
RETURN(hr);
}
// $--HrFolderRulesGetProviders------------------------------------------------
//
// DESCRIPTION:Get an array of rules provider names for a given folder.
//
// INPUT:
//
//[lpMDB]-- Pointer to message store containing folder.
// [cbentryid]-- Number of bytes in folder's entry identifier.
// [lpentryid]-- Folder's entry identifier.
//
// OUTPUT:
//
// [lpcProviders]-- Pointer to ulong that will be set to count of
// providers on successful return.
//[lpppszProviders]-- Pointer to array of string pointers that will be set
// to point at an array of provider name string pointers
// on successful return.
//
// RETURNS: NOERRORif successful;
//E_INVALIDARGif bad input;
//E_OUTOFMEMORYif not enough memory;
//E_NOINTERFACEif rules table does not exist on folder;
// E_FAIL otherwise.
//
//-----------------------------------------------------------------------------
STDAPI
HrFolderRulesGetProviders(// RETURNS: HRESULT
INLPMDBlpMDB,// MAPI MDB store ptr
INULONGcbentryid,// # bytes in entry ID
INLPENTRYIDlpentryid,// entry ID ptr
OUTLPULONGlpcProviders,// count of providers
OUTLPSTR FAR * FAR *lpppszProviders// ptr to array of providers
)
{
HRESULThr =NOERROR;
CFolderRules FAR *pFolderRules =NULL;
DEBUGPUBLIC("HrFolderRulesGetProviders()\n");
hr = CHK_HrFolderRulesGetProviders(cbentryid,
lpentryid,
lpcProviders,
lpppszProviders);
if (FAILED(hr))
RETURN(hr);
// Initialize controlling class object.
pFolderRules = new CFolderRules();
if (pFolderRules == NULL)
{
hr = HR_LOG(E_OUTOFMEMORY);
goto cleanup;
}
// Open the folder in the controlling class object.
hr = pFolderRules->HrOpen(lpMDB, cbentryid, lpentryid, NULL);
if (FAILED(hr))
goto cleanup;
hr = pFolderRules->HrGetProviders(lpcProviders, lpppszProviders);
if (FAILED(hr))
goto cleanup;
cleanup:
// Release our copy of the CFolderRules object.
ULRELEASE(pFolderRules);// Ref count now 1.
RETURN(hr);
}
// $--HrFolderRulesOpen--------------------------------------------------------
//
// DESCRIPTION:Get a pointer to an object which implements the
//IExchangeFolderRules interface defined in rulecls.h.
//
// INPUT:
//
//[lpMDB]-- Pointer to message store containing folder.
// [cbentryid]-- Number of bytes in folder's entry identifier.
// [lpentryid]-- Folder's entry identifier.
// [lpszProvider]-- Provider for rules. Multiple providers may have
// rules on a folder. The IExchangeFolderRules interface
// provides access to the rules associated with a
// single specified provider.
//
// OUTPUT:
//
// [lppFolderRules]-- Pointer to object which supports interface.
//
// RETURNS: NOERRORif successful;
//E_INVALIDARGif bad input;
//E_OUTOFMEMORYif not enough memory;
//E_NOINTERFACEif rules table does not exist on folder;
// E_FAIL otherwise.
//
//-----------------------------------------------------------------------------
STDAPI
HrFolderRulesOpen(// RETURNS: HRESULT
INLPMDBlpMDB,// MAPI MDB store ptr
INULONGcbentryid,// # bytes in entry ID
INLPENTRYIDlpentryid,// entry ID ptr
INLPSTRlpszProvider,// provider name
OUTLPFOLDERRULES FAR *lppFolderRules // ptr to folder rules buffer
)
{
HRESULThr =NOERROR;
CFolderRules FAR *pFolderRules =NULL;
DEBUGPUBLIC("HrFolderRulesOpen()\n");
hr = CHK_HrFolderRulesOpen(cbentryid,
lpentryid,
lpszProvider,
lppFolderRules);
if (FAILED(hr))
RETURN(hr);
*lppFolderRules = NULL;
// Initialize controlling class object.
pFolderRules = new CFolderRules();
if (pFolderRules == NULL)
{
hr = HR_LOG(E_OUTOFMEMORY);
goto cleanup;
}
// Open the folder in the controlling class object.
hr = pFolderRules->HrOpen(lpMDB, cbentryid, lpentryid, lpszProvider);
if (FAILED(hr))
goto cleanup;
// Give the user access to the programmer interface (CIExchangeFolderRules)
// on the controlling CFolderRules object.
hr = pFolderRules->QueryInterface(IID_IExchangeFolderRules,
(LPVOID FAR *)lppFolderRules);
// Ref count now 2.
if (FAILED(hr))
goto cleanup;
ASSERT_READ_PTR_OR_NULL(*lppFolderRules, sizeof(LPFOLDERRULES),
"Bad lppFolderRules.");
cleanup:
// Release our copy of the CFolderRules object.
ULRELEASE(pFolderRules);// Ref count now 1.
RETURN(hr);
}
// $--HrActionToString---------------------------------------------------------
//
// DESCRIPTION:Get a string representation of an ACTION.
//
// INPUT:
//
// [lpSession]-- MAPI session ptr.
//[lpAction]-- Ptr to ACTION.
//
// OUTPUT:
//
//[lppszString]-- Ptr to ptr that will be set to point at generated
// string representation on successful return.
//
// RETURNS: NOERROR if successful;
// E_INVALIDARG if bad input;
// E_OUTOFMEMORYif not enough memory;
// E_FAILotherwise.
//
//-----------------------------------------------------------------------------
STDAPI
HrActionToString(// RETURNS: HRESULT
INLPMAPISESSIONlpSession, // MAPI session ptr
INLPACTIONlpAction,// action ptr
OUTLPSTR FAR *lppszString// string ptr ptr
)
{
ULONGcbBuffer =0;
ULONGcbString =0;
HRESULThr =NOERROR;
LPSTRlpszActType =NULL;
DEBUGPUBLIC("HrActionToString()\n");
hr = CHK_HrActionToString(lpSession, lpAction, lppszString);
if (FAILED(hr))
RETURN(hr);
*lppszString = NULL;
switch (lpAction->acttype)
{
case OP_MOVE:
lpszActType = "Move to ";
break;
case OP_COPY:
lpszActType = "Copy to ";
break;
case OP_REPLY:
lpszActType = "Reply";
break;
case OP_OOF_REPLY:
lpszActType = "Out-of-Office Reply";
break;
case OP_DEFER_ACTION:
lpszActType = "Provider-specific deferred action";
break;
case OP_BOUNCE:
lpszActType = "Bounce with error code ";
break;
case OP_FORWARD:
lpszActType = "Forward to ";
break;
case OP_DELEGATE:
lpszActType = "Delegate to ";
break;
case OP_TAG:
lpszActType = "Tag ";
break;
case OP_DELETE:
lpszActType = "Delete";
break;
case OP_MARK_AS_READ:
lpszActType = "Mark as Read";
break;
default:
lpszActType = "Invalid action type";
break;
}
hr = HrPrintToString(lppszString, &cbString, &cbBuffer, lpszActType);
if (FAILED(hr))
goto cleanup;
switch (lpAction->acttype)
{
case OP_MOVE:
case OP_COPY:
{
LPMDBlpMDB =NULL;
LPSTRlpszFolderPath =NULL;
LPSTRlpszStoreName = NULL;
// Open the message store.
hr = lpSession->OpenMsgStore(0,
lpAction->actMoveCopy.cbStoreEntryId,
lpAction->actMoveCopy.lpStoreEntryId,
NULL,
MAPI_DEFERRED_ERRORS,
&lpMDB);
if (FAILED(hr))
goto cleanup;
hr = HrGetStoreName(lpMDB, &lpszStoreName);
if (FAILED(hr))
{
ULRELEASE(lpMDB);
goto cleanup;
}
hr = HrGetFolderPath(lpMDB,
lpAction->actMoveCopy.cbFldEntryId,
lpAction->actMoveCopy.lpFldEntryId,
&lpszFolderPath);
if (FAILED(hr))
{
MAPIFREEBUFFER(lpszStoreName);
ULRELEASE(lpMDB);
goto cleanup;
}
hr = HrPrintToString(lppszString,
&cbString,
&cbBuffer,
"%s\\%s", lpszStoreName, lpszFolderPath);
MAPIFREEBUFFER(lpszFolderPath);
MAPIFREEBUFFER(lpszStoreName);
ULRELEASE(lpMDB);
if (FAILED(hr))
goto cleanup;
break;
}
case OP_REPLY:
case OP_OOF_REPLY:
{
;// Nothing more to do.
break;
}
case OP_DEFER_ACTION:
{
;// Nothing more to do.
break;
}
case OP_BOUNCE:
{
LPSTRlpszBounceCode = NULL;
if (lpAction->scBounceCode == BOUNCE_MESSAGE_SIZE_TOO_LARGE)
lpszBounceCode = "BOUNCE_MESSAGE_SIZE_TOO_LARGE";
else if (lpAction->scBounceCode == BOUNCE_FORMS_MISMATCH)
lpszBounceCode = "BOUNCE_FORMS_MISMATCH";
else if (lpAction->scBounceCode == BOUNCE_ACCESS_DENIED)
lpszBounceCode = "BOUNCE_ACCESS_DENIED";
if (lpszBounceCode != NULL)
{
hr = HrPrintToString(lppszString,
&cbString,
&cbBuffer,
lpszBounceCode);
}
else
{
hr = HrPrintToString(lppszString,
&cbString,
&cbBuffer,
"%#x (invalid bounce code)",
lpAction->scBounceCode);
}
if (FAILED(hr))
goto cleanup;
break;
}
case OP_FORWARD:
case OP_DELEGATE:
{
hr = HrAdrListDisplayNamesToString(lpAction->lpadrlist,
lppszString,
&cbString,
&cbBuffer);
if (FAILED(hr))
goto cleanup;
break;
}
case OP_TAG:
{
LPSTRlpszPropTag =NULL;
LPSTRlpszPropValue =NULL;
hr = HrGetPropTagName(lpAction->propTag.ulPropTag,
&lpszPropTag);
if (FAILED(hr))
goto cleanup;
{
ULONGcbString =0;
ULONGcbBuffer =0;
hr = HrPropValueToString(&lpAction->propTag,
&lpszPropValue,
&cbString,
&cbBuffer);
}
if (FAILED(hr))
{
MAPIFREEBUFFER(lpszPropTag);
goto cleanup;
}
hr = HrPrintToString(lppszString,
&cbString,
&cbBuffer,
"%s = %s", lpszPropTag, lpszPropValue);
MAPIFREEBUFFER(lpszPropTag);
MAPIFREEBUFFER(lpszPropValue);
if (FAILED(hr))
goto cleanup;
break;
}
case OP_DELETE:
{
;// Nothing more to do.
break;
}
case OP_MARK_AS_READ:
{
;// Nothing more to do.
break;
}
default:
{
;// Nothing more to do.
break;
}
}
cleanup:
if (FAILED(hr))
{
MAPIFREEBUFFER(*lppszString);
}
else
{
// If buffer is longer than necessary, reallocate.
if (cbBuffer > cbString)
{
LPSTRlpszString = NULL;
hr = MAPIAllocateBuffer(cbString, (LPVOID FAR *)&lpszString);
if (FAILED(hr))
{
MAPIFREEBUFFER(*lppszString);
}
else
{
memcpy(lpszString, *lppszString, cbString);
MAPIFREEBUFFER(*lppszString);
*lppszString = lpszString;
}
}
}
RETURN(hr);
}
// $--HrRestrictionToString----------------------------------------------------
//
// DESCRIPTION:Get a string representation of an SRestriction.
//
// INPUT:
//
//[lpRestriction]-- Ptr to restriction.
//
// OUTPUT:
//
//[lppszString]-- Ptr to ptr that will be set to point at generated
// string representation on successful return.
//
// RETURNS: NOERROR if successful;
// E_INVALIDARG if bad input;
// E_OUTOFMEMORYif not enough memory;
// E_FAILotherwise.
//
//-----------------------------------------------------------------------------
STDAPI
HrRestrictionToString(// RETURNS: HRESULT
INLPSRestrictionlpRestriction,// restriction ptr
OUTLPSTR FAR *lppszString// string ptr ptr
)
{
ULONGcbBuffer =0;
ULONGcbString =0;
HRESULThr =NOERROR;
DEBUGPUBLIC("HrRestrictionToString()\n");
hr = CHK_HrRestrictionToString(lpRestriction, lppszString);
if (FAILED(hr))
RETURN(hr);
*lppszString = NULL;
hr = HrPrivateRestrictionToString(lpRestriction,
lppszString,
&cbString,
&cbBuffer);
if (FAILED(hr))
goto cleanup;
cleanup:
if (FAILED(hr))
{
MAPIFREEBUFFER(*lppszString);
}
else
{
// If buffer is longer than necessary, reallocate.
if (cbBuffer > cbString)
{
LPSTRlpszString = NULL;
hr = MAPIAllocateBuffer(cbString, (LPVOID FAR *)&lpszString);
if (FAILED(hr))
{
MAPIFREEBUFFER(*lppszString);
}
else
{
memcpy(lpszString, *lppszString, cbString);
MAPIFREEBUFFER(*lppszString);
*lppszString = lpszString;
}
}
}
RETURN(hr);
};
// $--HrStringToAction---------------------------------------------------------
//
// DESCRIPTION:Generate an ACTION structure that describes the action
//provided in *lpszString.
//
// INPUT:
//
//[lpSession]-- Ptr to MAPI session.
//[lpFolder]-- Ptr to MAPI folder action applies to. MUST have been
// opened with MAPI_MODIFY access.
//[lpszString]-- Action string specifying ACTION to be generated.
//[lpObject]-- Ptr to an existing MAPI buffer allocated by
// MAPIAllocateBuffer(). NULL is not permitted. Ideally,
// this is a ptr to the parent ACTIONS structure.
//
// INPUT/OUTPUT:
//
//[lpAction]-- Ptr to ACTION structure that will be filled in. This
// is allocated by the caller. Ideally, this is a ptr to
// an ACTION array element that was allocated by the caller
// using a MAPIAllocateMore() that referenced the parent
// ACTIONS structure.
//
// RETURNS: NOERRORif successful;
//E_INVALIDARGif bad input;
// E_OUTOFMEMORYif out of memory;
// E_FAILotherwise.
//-----------------------------------------------------------------------------
STDAPI
HrStringToAction(// RETURNS: HRESULT
INLPMAPISESSIONlpSession,// ptr to MAPI session
INLPMAPIFOLDERlpFolder,// ptr to MAPI folder
INLPSTRlpszString,// string ptr
INLPVOIDlpObject,// ptr to existing MAPI buf
IN OUTLPACTIONlpAction // ACTION ptr
)
{
HRESULThr =NOERROR;
LPSTRlpszStringCopy =NULL;
DEBUGPUBLIC("HrStringToAction()\n");
hr = CHK_HrStringToAction(lpSession,
lpFolder,
lpszString,
lpObject,
lpAction);
if (FAILED(hr))
RETURN(hr);
// Make copy of lpszString so you can write to it safely.
hr = MAPIAllocateBuffer(strlen(lpszString) + 1,
(LPVOID FAR *)&lpszStringCopy);
if (FAILED(hr))
goto cleanup;
strcpy(lpszStringCopy, lpszString);
hr = HrParseAction(lpSession, lpFolder, lpObject, lpszStringCopy, lpAction);
if (FAILED(hr))
goto cleanup;
cleanup:
MAPIFREEBUFFER(lpszStringCopy);
RETURN(hr);
}
// $--HrStringToRestriction----------------------------------------------------
//
// DESCRIPTION:Generate an SRestriction structure that describes the
//restriction condition provided in *lpszString. The
//grammar for *lpszString is given in the header file
//rulecls.h.
//
// INPUT:
//
//[lpszString]-- Condition string specifying restriction to be generated.
//[lpObject]-- Ptr to an existing MAPI buffer allocated by
// MAPIAllocateBuffer(), or NULL if the returned structure
// is to be allocated using MAPIAllocateBuffer().
//
// OUTPUT:
//
//[lppRestriction]-- Ptr to ptr that will be set to point at generated
// restriction on successful return.
//
// RETURNS: NOERRORif successful;
//E_INVALIDARGif bad input;
// E_OUTOFMEMORYif out of memory;
// E_FAILotherwise.
//-----------------------------------------------------------------------------
STDAPI
HrStringToRestriction(// RETURNS: HRESULT
INLPSTRlpszString,// string
INLPVOIDlpObject,// ptr to existing MAPI buf
OUTLPSRestriction FAR *lppRestriction // restriction buffer ptr
)
{
BOOLfNullObject =(lpObject == NULL);
HRESULThr =NOERROR;
LPSTRlpszStringCopy =NULL;
CHAR *pch =NULL;
DEBUGPUBLIC("HrStringToRestriction()\n");
hr = CHK_HrStringToRestriction(lpszString, lpObject, lppRestriction);
if (FAILED(hr))
RETURN(hr);
// Make copy of lpszString so you can write to it safely.
hr = MAPIAllocateBuffer(strlen(lpszString) + 1,
(LPVOID FAR *)&lpszStringCopy);
if (FAILED(hr))
goto cleanup;
strcpy(lpszStringCopy, lpszString);
if (lpObject != NULL)
{
hr = MAPIAllocateMore(sizeof(SRestriction),
lpObject,
(LPVOID FAR *)lppRestriction);
}
else
{
hr = MAPIAllocateBuffer(sizeof(SRestriction),
(LPVOID FAR *)lppRestriction);
lpObject = *lppRestriction;
}
if (FAILED(hr))
goto cleanup;
(*lppRestriction)->rt = RES_UNINITIALIZED;
pch = lpszStringCopy;
hr = HrParseCondition(lpObject, &pch, *lppRestriction);
if (*pch != '\0')
hr = HR_LOG(E_INVALIDARG);
if (FAILED(hr))
{
if (fNullObject)
MAPIFREEBUFFER(*lppRestriction);
goto cleanup;
}
cleanup:
MAPIFREEBUFFER(lpszStringCopy);
RETURN(hr);
}
//
// Private functions
//
// $--HrAdrListDisplayNamesToString--------------------------------------------
//
// DESCRIPTION:Get a string representation of the display names in an ADRLIST.
//
// INPUT:
//
//[lpAdrList]-- Ptr to ADRLIST, the display names of which are to be
// represented as a string.
//
// INPUT/OUTPUT:
//
//[lppszString]-- Output string ptr ptr. If *lppszString == NULL, then
// a string will be allocated by this routine.
//[lpcbString]-- Ptr to count of bytes in input string on input (including
// terminating '\0'); count of bytes in string after
// appending formatted string on output.
//[lpcbBuffer]-- Ptr to count of bytes in input string buffer on input;
// count of bytes in string buffer after appending formatted
// string on output (buffer size may increase if allocation
// was necessary).
//
// RETURNS: NOERRORif successful;
// E_INVALIDARGif bad input;
// E_FAILotherwise.
//-----------------------------------------------------------------------------
HRESULT
HrAdrListDisplayNamesToString( // RETURNS: HRESULT
INLPADRLISTlpAdrList,// address list ptr
IN OUTLPSTR FAR *lppszString,// output string ptr ptr
IN OUTLPULONGlpcbString,// ptr to count of bytes in string
IN OUTLPULONGlpcbBuffer// ptr to count of bytes in buffer
)
{
HRESULThr =NOERROR;
ULONGi =0;
ULONGj =0;
LPADRENTRYlpAdrEntry =NULL;
LPSTRlpszFormat ="\"%s\"";
DEBUGPRIVATE("HrAdrListDisplayNamesToString()\n");
for (i = 0; i < lpAdrList->cEntries; i++)
{
lpAdrEntry = &lpAdrList->aEntries[i];
for (j = 0; j < lpAdrEntry->cValues; j++)
{
if (lpAdrEntry->rgPropVals[j].ulPropTag == PR_DISPLAY_NAME)
{
hr = HrPrintToString(lppszString,
lpcbString,
lpcbBuffer,
lpszFormat,
lpAdrEntry->rgPropVals[j].Value.lpszA);
if (FAILED(hr))
goto cleanup;
lpszFormat = ", \"%s\"";
break;
}
}
}
cleanup:
RETURN(hr);
}
// $--HrAndRestrictionToString-------------------------------------------------
//
// DESCRIPTION:Get a string representation of an SAndRestriction.
//
// INPUT:
//
//[lpRes]-- Ptr to and restriction to be represented as a string.
//
// INPUT/OUTPUT:
//
//[lppszString]-- Output string ptr ptr. If *lppszString == NULL, then
// a string will be allocated by this routine.
//[lpcbString]-- Ptr to count of bytes in input string on input (including
// terminating '\0'); count of bytes in string after
// appending formatted string on output.
//[lpcbBuffer]-- Ptr to count of bytes in input string buffer on input;
// count of bytes in string buffer after appending formatted
// string on output (buffer size may increase if allocation
// was necessary).
//
// RETURNS: NOERRORif successful;
// E_INVALIDARGif bad input;
// E_FAILotherwise.
//-----------------------------------------------------------------------------
HRESULT
HrAndRestrictionToString( // RETURNS: HRESULT
INLPSRestrictionlpRes,// restriction ptr
IN OUTLPSTR FAR *lppszString,// output string ptr ptr
IN OUTLPULONGlpcbString,// ptr to count of bytes in string
IN OUTLPULONGlpcbBuffer// ptr to count of bytes in buffer
)
{
HRESULThr =NOERROR;
ULONGi =0;
SAndRestriction *presAnd=NULL;
DEBUGPRIVATE("HrAndRestrictionToString()\n");
presAnd = &lpRes->res.resAnd;
if (presAnd->cRes < 2)
{
hr = HrPrintToString(lppszString,
lpcbString,
lpcbBuffer,
"<Invalid SAndRestriction>");
if (FAILED(hr))
goto cleanup;
}
else
{
hr = HrPrivateRestrictionToString(presAnd->lpRes,
lppszString,
lpcbString,
lpcbBuffer);
if (FAILED(hr))
goto cleanup;
for (i = 1; i < presAnd->cRes; i++)
{
hr = HrPrintToString(lppszString, lpcbString, lpcbBuffer, " & ");
if (FAILED(hr))
goto cleanup;
if (ISNONTERMINALRESTRICTION(presAnd->lpRes + i))
{
hr = HrPrintToString(lppszString,
lpcbString,
lpcbBuffer,
"(");
if (FAILED(hr))
goto cleanup;
hr = HrPrivateRestrictionToString(presAnd->lpRes + i,
lppszString,
lpcbString,
lpcbBuffer);
if (FAILED(hr))
goto cleanup;
hr = HrPrintToString(lppszString,
lpcbString,
lpcbBuffer,
")");
if (FAILED(hr))
goto cleanup;
}
else
{
hr = HrPrivateRestrictionToString(presAnd->lpRes + i,
lppszString,
lpcbString,
lpcbBuffer);
if (FAILED(hr))
goto cleanup;
}
}
}
cleanup:
RETURN(hr);
}
// $--HrContentRestrictionToString---------------------------------------------
//
// DESCRIPTION:Get a string representation of an SContentRestriction.
//
// INPUT:
//
//[lpRes]-- Ptr to content restriction to be represented as a string.
//
// INPUT/OUTPUT:
//
//[lppszString]-- Output string ptr ptr. If *lppszString == NULL, then
// a string will be allocated by this routine.
//[lpcbString]-- Ptr to count of bytes in input string on input (including
// terminating '\0'); count of bytes in string after
// appending formatted string on output.
//[lpcbBuffer]-- Ptr to count of bytes in input string buffer on input;
// count of bytes in string buffer after appending formatted
// string on output (buffer size may increase if allocation
// was necessary).
//
// RETURNS: NOERRORif successful;
// E_INVALIDARGif bad input;
// E_FAILotherwise.
//-----------------------------------------------------------------------------
HRESULT
HrContentRestrictionToString( // RETURNS: HRESULT
INLPSRestrictionlpRes,// restriction ptr
IN OUTLPSTR FAR *lppszString,// output string ptr ptr
IN OUTLPULONGlpcbString,// ptr to count of bytes in string
IN OUTLPULONGlpcbBuffer// ptr to count of bytes in buffer
)
{
HRESULThr = NOERROR;
LPSTRlpszPropName =NULL;
DEBUGPRIVATE("HrContentRestrictionToString()\n");
hr = HrGetPropTagName(lpRes->res.resContent.ulPropTag,
&lpszPropName);
if (FAILED(hr))
goto cleanup;
hr = HrPrintToString(lppszString,
lpcbString,
lpcbBuffer,
"%s } ",
lpszPropName);
if (FAILED(hr))
goto cleanup;
hr = HrPropValueToString(lpRes->res.resProperty.lpProp,
lppszString,
lpcbString,
lpcbBuffer);
if (FAILED(hr))
goto cleanup;
cleanup:
MAPIFREEBUFFER(lpszPropName);
RETURN(hr);
}
// $--HrCopyRestrictionArray---------------------------------------------------
//
// DESCRIPTION: Copy an SRestriction array.
//
// INPUT:
//
//[lpResSrc]-- Ptr to restriction array to be copied.
//[lpObject]-- Ptr to an existing MAPI buffer allocated by
// MAPIAllocateBuffer(). NULL is not permitted!
//[cRes]-- Count of array elements.
//
// OUTPUT:
//
//[lpResDest]-- Ptr to destination restriction array (allocated by caller).
//
// RETURNS: NOERRORif successful;
// E_INVALIDARGif bad input;
//E_OUTOFMEMORYif out of memory;
// E_FAILotherwise.
//-----------------------------------------------------------------------------
HRESULT
HrCopyRestrictionArray(// RETURNS: HRESULT
INLPSRestrictionlpResSrc, // source restriction
INLPVOIDlpObject,// ptr to existing MAPI buffer
INULONGcRes, // # elements in array
OUTLPSRestrictionlpResDest // destination restriction
)
{
HRESULThr =NOERROR;
ULONGi;
DEBUGPRIVATE("HrCopyRestrictionArray()\n");
for (i = 0; i < cRes; i++)
{
lpResDest[i] = lpResSrc[i];
switch (lpResSrc[i].rt)
{
case RES_AND:
{
ULONGcRes =lpResSrc[i].res.resAnd.cRes;
LPSRestrictionlpRes =lpResSrc[i].res.resAnd.lpRes;
if (cRes == 0 || lpRes == NULL)
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}
hr = MAPIAllocateMore(sizeof(SRestriction) * cRes,
lpObject,
(LPVOID FAR *)
&lpResDest[i].res.resAnd.lpRes);
if (FAILED(hr))
goto cleanup;
hr = HrCopyRestrictionArray(lpRes,
lpObject,
cRes,
lpResDest[i].res.resAnd.lpRes);
if (FAILED(hr))
goto cleanup;
break;
}
case RES_OR:
{
ULONGcRes =lpResSrc[i].res.resOr.cRes;
LPSRestrictionlpRes =lpResSrc[i].res.resOr.lpRes;
if (cRes == 0 || lpRes == NULL)
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}
hr = MAPIAllocateMore(sizeof(SRestriction) * cRes,
lpObject,
(LPVOID FAR *)
&lpResDest[i].res.resOr.lpRes);
if (FAILED(hr))
goto cleanup;
hr = HrCopyRestrictionArray(lpRes,
lpObject,
cRes,
lpResDest[i].res.resOr.lpRes);
if (FAILED(hr))
goto cleanup;
break;
}
case RES_NOT:
{
LPSRestrictionlpRes = lpResSrc[i].res.resNot.lpRes;
if (lpRes == NULL)
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}
hr = MAPIAllocateMore(sizeof(SRestriction),
lpObject,
(LPVOID FAR *)
&lpResDest[i].res.resNot.lpRes);
if (FAILED(hr))
goto cleanup;
hr = HrCopyRestrictionArray(lpRes,
lpObject,
1,
lpResDest[i].res.resNot.lpRes);
if (FAILED(hr))
goto cleanup;
break;
}
case RES_CONTENT:
{
if (lpResSrc[i].res.resContent.lpProp == NULL)
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}
hr = HrDupPropset(1,
lpResSrc[i].res.resContent.lpProp,
lpObject,
&lpResDest[i].res.resContent.lpProp);
if (FAILED(hr))
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}
break;
}
case RES_PROPERTY:
{
if (lpResSrc[i].res.resProperty.lpProp == NULL)
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}
hr = HrDupPropset(1,
lpResSrc[i].res.resProperty.lpProp,
lpObject,
&lpResDest[i].res.resProperty.lpProp);
if (FAILED(hr))
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}
break;
}
case RES_COMPAREPROPS:
case RES_BITMASK:
case RES_SIZE:
case RES_EXIST:
{
// Nothing to do.
break;
}
case RES_SUBRESTRICTION:
{
LPSRestrictionlpRes = lpResSrc[i].res.resSub.lpRes;
if (lpRes == NULL)
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}
hr = MAPIAllocateMore(sizeof(SRestriction),
lpObject,
(LPVOID FAR *)
&lpResDest[i].res.resSub.lpRes);
if (FAILED(hr))
goto cleanup;
hr = HrCopyRestrictionArray(lpRes,
lpObject,
1,
lpResDest[i].res.resSub.lpRes);
if (FAILED(hr))
goto cleanup;
break;
}
case RES_COMMENT:
{
LPSRestrictionlpRes = lpResSrc[i].res.resComment.lpRes;
if (lpRes == NULL)
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}
hr = MAPIAllocateMore(sizeof(SRestriction),
lpObject,
(LPVOID FAR *)
&lpResDest[i].res.resComment.lpRes);
if (FAILED(hr))
goto cleanup;
hr = HrCopyRestrictionArray(lpRes,
lpObject,
1,
lpResDest[i].res.resComment.lpRes);
if (FAILED(hr))
goto cleanup;
break;
}
default:
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}
}
}
cleanup:
RETURN(hr);
}
// $--HrCreateReplyMsg---------------------------------------------------------
//
// DESCRIPTION:Create a reply message for the reply action.
//
// INPUT:
//
//[lpFolder]-- Ptr to MAPI folder action applies to.
//[lpszReplyText]-- Ptr to message text.
//[lpObject]-- Ptr to an existing MAPI buffer allocated by
// MAPIAllocateBuffer(). NULL is not permitted.
//
// OUTPUT:
//
// [lpcbentryid]-- Number of bytes in message's entry identifier.
// [lppentryid]-- Ptr to message entry identifier.
//
//
// RETURNS: NOERRORif successful;
// E_FAILotherwise.
//-----------------------------------------------------------------------------
HRESULT
HrCreateReplyMsg(// RETURNS:HRESULT
INLPMAPIFOLDERlpFolder,// ptr to MAPI folder
INLPSTRlpszReplyText,// ptr to message text
INLPVOIDlpObject,// ptr to existing MAPI buf
OUTULONG FAR *lpcbentryid, // ptr to message entry ID size
OUTLPENTRYID FAR *lppentryid// message entry ID buffer ptr
)
{
static
SizedSPropTagArray(1, PropTagArray) ={1, {PR_ENTRYID}};
SPropValueaPropVals[5] ={0};
ULONGcValues = 0;
HRESULThr =NOERROR;
LPMESSAGElpMsg =NULL;
LPSPropProblemArraylpProblems =NULL;
LPSPropValuergPropVals =NULL;
ULONGulOldStatus =0;
DEBUGPRIVATE("HrCreateReplyMsg()\n");
hr = lpFolder->CreateMessage(NULL, MAPI_ASSOCIATED, &lpMsg);
if (FAILED(hr))
goto cleanup;
aPropVals[0].ulPropTag =PR_MESSAGE_CLASS;
aPropVals[0].Value.lpszA ="IPM.Note.Rules.ReplyTemplate.Microsoft";
aPropVals[1].ulPropTag =PR_DELETE_AFTER_SUBMIT;
aPropVals[1].Value.b =FALSE;
aPropVals[2].ulPropTag =PR_ORIGINATOR_DELIVERY_REPORT_REQUESTED;
aPropVals[2].Value.b =FALSE;
aPropVals[3].ulPropTag =PR_MESSAGE_FLAGS;
aPropVals[3].Value.l =MSGFLAG_READ | MSGFLAG_UNSENT;
aPropVals[4].ulPropTag =PR_BODY;
aPropVals[4].Value.lpszA =lpszReplyText;
hr = lpMsg->SetProps(5, aPropVals, &lpProblems);
if (FAILED(hr))
goto cleanup;
if (lpProblems != NULL)
{
hr = HR_LOG(E_FAIL);
MAPIFREEBUFFER(lpProblems);
goto cleanup;
}
hr = lpMsg->SaveChanges(KEEP_OPEN_READWRITE);
if (FAILED(hr))
goto cleanup;
// Now get the entryid for the newly created msg.
hr = lpMsg->GetProps((LPSPropTagArray)&PropTagArray,
0,
&cValues,
&rgPropVals);
if (FAILED(hr))
goto cleanup;
if (cValues != 1||
rgPropVals[0].ulPropTag != PR_ENTRYID)
{
hr = HR_LOG(EDK_E_NOT_FOUND);
goto cleanup;
}
// Allocate space for entryid and store it.
*lpcbentryid = rgPropVals[0].Value.bin.cb;
hr = MAPIAllocateMore(*lpcbentryid,
lpObject,
(LPVOID FAR *)lppentryid);
if (FAILED(hr))
goto cleanup;
memcpy(*lppentryid, rgPropVals[0].Value.bin.lpb, *lpcbentryid);
cleanup:
ULRELEASE(lpMsg);
RETURN(hr);
}
// $--HrGetExplicitTag---------------------------------------------------------
//
// DESCRIPTION:Parse an explicit property tag token, returning results in
//*pti. A value for ulPropTag is returned in pti->dwValue.
//
// INPUT/OUTPUT:
//
//[pti]-- Ptr to token information structure.
//
// RETURNS: NOERRORif successful;
// E_INVALIDARGif bad input;
// E_FAILotherwise.
//-----------------------------------------------------------------------------
HRESULT
HrGetExplicitTag( // RETURNS: HRESULT
IN OUTTOKENINFO *pti// ptr to token information
)
{
HRESULT hr =NOERROR;
CHARchtmp =0;
CHAR *pchDigit =NULL;
CHAR *pch =NULL;
ULONGulPropTag =0;
DEBUGPRIVATE("HrGetExplicitTag()\n");
pch = pti->pch + 1;
if (*pch != 'B' && *pch != 'b'&&
*pch != 'N' && *pch != 'n'&&
*pch != 'S' && *pch != 's'&&
*pch != 'T' && *pch != 't')
{
hr = HR_LOG(E_INVALIDARG);
goto cleanup;
}
pch++;
pch = lpszSkipWhiteSpace(pch);
pchDigit = pch;
if (!isxdigit(*pch))
{
hr = HR_LOG(E_INVALIDARG);
goto cleanup;
}
while (isxdigit(*pch))
{
pch++;
}
// We temporarily terminate the hex number string, just to be absolutely
// certain that the following character is not used.
chtmp =*pch;
*pch ='\0';
errno = 0; // initialize it
ulPropTag = strtoul(pchDigit, (CHAR **)NULL, 16);
*pch = chtmp;
if (ulPropTag == ULONG_MAX && errno == ERANGE)
{
hr = HR_LOG(E_INVALIDARG);
goto cleanup;
}
pch = lpszSkipWhiteSpace(pch);
if (*pch != ']')
{
hr = HR_LOG(E_INVALIDARG);
goto cleanup;
}
if (*(pti->pch + 1) == 'B' || *(pti->pch + 1) == 'b')
{
if (PROP_TYPE(ulPropTag) != PT_BOOLEAN)
{
pti->tt = InvalidTag;
hr = HR_LOG(E_INVALIDARG);
goto cleanup;
}
pti->tt = BooleanTag;
}
else if (*(pti->pch + 1) == 'N' || *(pti->pch + 1) == 'n')
{
if (PROP_TYPE(ulPropTag) != PT_LONG)
{
pti->tt = InvalidTag;
hr = HR_LOG(E_INVALIDARG);
goto cleanup;
}
pti->tt = NumericTag;
}
else if (*(pti->pch + 1) == 'S' || *(pti->pch + 1) == 's')
{
if (PROP_TYPE(ulPropTag) != PT_STRING8&&
PROP_TYPE(ulPropTag) != PT_UNICODE)
{
pti->tt = InvalidTag;
hr = HR_LOG(E_INVALIDARG);
goto cleanup;
}
pti->tt = StringTag;
}
else if (*(pti->pch + 1) == 'T' || *(pti->pch + 1) == 't')
{
if (PROP_TYPE(ulPropTag) != PT_SYSTIME)
{
pti->tt = InvalidTag;
hr = HR_LOG(E_INVALIDARG);
goto cleanup;
}
pti->tt = TimeTag;
}
else
{
// We should not have gotten past the preliminary input check, but
// we include this to prevent maintenance headaches.
hr = HR_LOG(E_INVALIDARG);
goto cleanup;
}
pti->cch =pch - pti->pch + 1;
pti->dwValue =ulPropTag;
cleanup:
RETURN(hr);
}
// $--HrGetExpressionToken-----------------------------------------------------
//
// DESCRIPTION:Parse a token in a condition expression, returning results in
//*pti. The types of token that may be parsed are defined by the
//TOKENTYPE enumeration.
//
// INPUT/OUTPUT:
//
//[pti]-- Ptr to token information structure.
//
// RETURNS: NOERRORif successful;
//E_INVALIDARGif bad input;
//E_*otherwise.
//-----------------------------------------------------------------------------
HRESULT
HrGetExpressionToken( // RETURNS: HRESULT
IN OUTTOKENINFO *pti // token information ptr
)
{
HRESULThr =NOERROR;
CHAR *pch =NULL;
DEBUGPRIVATE("HrGetExpressionToken()\n");
pch = lpszSkipWhiteSpace(pti->pch);
pti->pch =pch;
pti->cch =0;
pti->tt =NotRecognized;
pti->dwValue =0;// Only valid if otherwise assigned below.
switch (*pch)
{
case '&':
pti->cch =1;
pti->tt =AndOp;
break;
case '}':
pti->cch =1;
pti->tt =ContainsOp;
break;
case '\0':
pti->cch =1;
pti->tt =EndOfString;
break;
case '=':
pti->cch =1;
pti->tt =EqualOp;
break;
case '>':
pti->cch =1;
pti->tt =GreaterThanOp;
break;
case '(':
pti->cch =1;
pti->tt =LeftParen;
break;
case '<':
pti->cch =1;
pti->tt =LessThanOp;
break;
case '#':
pti->cch =1;
pti->tt =NotEqualOp;
break;
case '!':
pti->cch =1;
pti->tt =NotOp;
break;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
// We try to match a time first; if this fails, we then try to
// just match a number. This order is important; a correct
// time format will always match a number format.
hr = HrGetTimeLiteral(pti);
if (FAILED(hr))
hr = HrGetNumericLiteral(pti);
break;
case '-':
case '+':
hr = HrGetNumericLiteral(pti);
break;
case 'P':
case 'p':
hr = HrGetNamedTag(pti);
break;
case '[':
hr = HrGetExplicitTag(pti);
break;
case '|':
pti->cch =1;
pti->tt =OrOp;
break;
case ')':
pti->cch =1;
pti->tt =RightParen;
break;
case '"':
hr = HrGetStringLiteral(pti);
break;
default:
hr = HR_LOG(E_INVALIDARG);
break;
}
RETURN(hr);
}
// $--HrGetFolderPath----------------------------------------------------------
//
// DESCRIPTION:Given the ENTRYID for a folder and a ptr to its store,
//get its path name.
//
// INPUT:
//
// [lpMDB]-- MAPI store ptr.
// [cbentryid]-- Count of bytes in folder's entry identifier.
// [lpentryid]-- Ptr to folder entry identifier.
//
// OUTPUT:
//
//[lppszFolderPath]-- Ptr to ptr that will be set to point at folder path
// on successful return.
//
// RETURNS: NOERROR if successful;
//E_INVALIDARGif bad input;
//E_OUTOFMEMORYif out of memory;
//EDK_E_NOT_FOUNDif specified store not found;
// E_FAILotherwise.
//-----------------------------------------------------------------------------
HRESULT
HrGetFolderPath( // RETURNS: HRESULT
INLPMDBlpMDB,// MAPI store ptr
INULONGcbentryid,// count of bytes in folder entry ID
INLPENTRYIDlpentryid,// folder entry ID ptr
OUTLPSTR FAR *lppszFolderPath // folder path ptr ptr
)
{
static
SizedSPropTagArray(3, PropTagArray) ={3, {PR_DISPLAY_NAME,
PR_PARENT_ENTRYID,
PR_FOLDER_TYPE}};
ULONGcValues = 0;
HRESULThr =NOERROR;
LPMAPIFOLDERlpFolder =NULL;
LPSTRlpszParentFolderPath =NULL;
LPSPropValuergPropVals =NULL;
ULONGulObjType =0;
DEBUGPRIVATE("HrGetFolderPath()\n");
// Get the folder object;
hr = lpMDB->OpenEntry(cbentryid,
lpentryid,
NULL,
MAPI_DEFERRED_ERRORS,
&ulObjType,
(LPUNKNOWN FAR *)&lpFolder);
if (FAILED(hr))
goto cleanup;
if (ulObjType != MAPI_FOLDER)
{
hr = HR_LOG(EDK_E_NOT_FOUND);
goto cleanup;
}
// Get the needed properties.
hr = lpFolder->GetProps((LPSPropTagArray)&PropTagArray,
0,
&cValues,
&rgPropVals);
if (FAILED(hr))
goto cleanup;
if (cValues != 3||
rgPropVals[0].ulPropTag != PR_DISPLAY_NAME||
rgPropVals[1].ulPropTag != PR_PARENT_ENTRYID||
rgPropVals[2].ulPropTag != PR_FOLDER_TYPE)
{
hr = HR_LOG(EDK_E_NOT_FOUND);
goto cleanup;
}
if (rgPropVals[2].Value.l == FOLDER_ROOT)
{
// We protect ourselves from various possible implementations of the
// root folder name by covering all possibilities.
if (rgPropVals[0].Value.lpszA != NULL)
{
hr = MAPIAllocateBuffer(strlen(rgPropVals[0].Value.lpszA) + 1,
(LPVOID FAR *)lppszFolderPath);
if (FAILED(hr))
goto cleanup;
strcpy(*lppszFolderPath, rgPropVals[0].Value.lpszA);
}
else
{
hr = MAPIAllocateBuffer(1, (LPVOID FAR *)lppszFolderPath);
if (FAILED(hr))
goto cleanup;
*lppszFolderPath[0] = '\0';
}
}
else
{
hr = HrGetFolderPath(lpMDB,
rgPropVals[1].Value.bin.cb,
(LPENTRYID)rgPropVals[1].Value.bin.lpb,
&lpszParentFolderPath);
if (FAILED(hr))
goto cleanup;
hr = MAPIAllocateBuffer(strlen(lpszParentFolderPath) +
strlen(rgPropVals[0].Value.lpszA) + 2,
(LPVOID FAR *)lppszFolderPath);
if (FAILED(hr))
goto cleanup;
strcpy(*lppszFolderPath, lpszParentFolderPath);
if (*lppszFolderPath[0] != '\0')
strcat(*lppszFolderPath, "\\");
strcat(*lppszFolderPath, rgPropVals[0].Value.lpszA);
}
cleanup:
MAPIFREEBUFFER(lpszParentFolderPath);
MAPIFREEBUFFER(rgPropVals);
ULRELEASE(lpFolder);
RETURN(hr);
}
//$--HrGetMoveCopyArgs---------------------------------------------------------
//
// DESCRIPTION:Parse the parenthetical expression following a move or copy
//action argument. The results are stored in the ACTION struct
//passed in as an argument.
//
// INPUT:
//
//[lpSession]-- Ptr to MAPI session.
//[pszFolder]-- Target folder path for move or copy.
//[lpObject]-- Ptr to an existing MAPI buffer allocated by
// MAPIAllocateBuffer(). NULL is not permitted!
//
// INPUT/OUTPUT:
//
//[lpAction]-- Action structure to set up.
//
// RETURNS: NOERRORif successful;
//E_INVALIDARGif bad input;
//E_*otherwise.
//-----------------------------------------------------------------------------
HRESULT
HrGetMoveCopyArgs(// RETURNS: HRESULT
INLPMAPISESSIONlpSession,// ptr to MAPI session
INLPSTRpszFolder,// target folder path
INLPVOIDlpObject,// ptr to existing MAPI buffer
IN OUTLPACTIONlpAction// ACTION structure to set up
)
{
ULONGcbEIDActsFolder =0;
ULONGcbEIDActsStore =0;
HRESULT hr =NOERROR;
LPMDBlpActsStore =NULL;
LPENTRYIDlpEIDActsFolder =NULL;
LPENTRYIDlpEIDActsStore =NULL;
LPENTRYIDlpEIDTmp =NULL;
CHAR *pch =NULL;
CHARszActsFolder[MAX_PATH + 1];
CHARszActsStore[MAX_PATH + 1];
DEBUGPRIVATE("HrGetMoveCopyArgs()\n");
pch = strchr(pszFolder, '\\');
if (pch == NULL||
pch - pszFolder == 0||
pch - pszFolder + 1 > sizeof(szActsStore))
{
hr = HR_LOG(E_INVALIDARG);
goto cleanup;
}
memcpy(szActsStore, pszFolder, pch - pszFolder);
szActsStore[pch - pszFolder] = '\0';
pch++;
if (*pch == '\0'||
strlen(pch) + 1 > sizeof(szActsFolder))
{
hr = HR_LOG(E_INVALIDARG);
goto cleanup;
}
strcpy(szActsFolder, pch);
hr = HrMAPIFindStore(lpSession, szActsStore, &cbEIDActsStore, &lpEIDTmp);
if (FAILED(hr))
goto cleanup;
hr = MAPIAllocateMore(cbEIDActsStore,
lpObject,
(LPVOID FAR *)&lpEIDActsStore);
if (FAILED(hr))
goto cleanup;
memcpy(lpEIDActsStore, lpEIDTmp, cbEIDActsStore);
MAPIFREEBUFFER(lpEIDTmp);
hr = lpSession->OpenMsgStore(0,
cbEIDActsStore,
lpEIDActsStore,
NULL,
MAPI_DEFERRED_ERRORS,
&lpActsStore);
if (FAILED(hr))
goto cleanup;
hr = HrMAPIFindFolderEx(lpActsStore,
'\\',
szActsFolder,
&cbEIDActsFolder,
&lpEIDTmp);
if (FAILED(hr))
goto cleanup;
hr = MAPIAllocateMore(cbEIDActsFolder,
lpObject,
(LPVOID FAR *)&lpEIDActsFolder);
if (FAILED(hr))
goto cleanup;
memcpy(lpEIDActsFolder, lpEIDTmp, cbEIDActsFolder);
MAPIFREEBUFFER(lpEIDTmp);
lpAction->actMoveCopy.cbStoreEntryId =cbEIDActsStore;
lpAction->actMoveCopy.lpStoreEntryId =lpEIDActsStore;
lpAction->actMoveCopy.cbFldEntryId =cbEIDActsFolder;
lpAction->actMoveCopy.lpFldEntryId =lpEIDActsFolder;
cleanup:
ULRELEASE(lpActsStore);
RETURN(hr);
}
// $--HrGetNamedTag------------------------------------------------------------
//
// DESCRIPTION:Parse a named property tag token (PR_*), returning results in
//*pti. A value for ulPropTag is returned in pti->dwValue.
//
// INPUT/OUTPUT:
//
//[pti]-- Ptr to token information structure.
//
// RETURNS: NOERRORif successful;
// E_INVALIDARGif bad input;
// E_FAILotherwise.
//-----------------------------------------------------------------------------
HRESULT
HrGetNamedTag( // RETURNS: HRESULT
IN OUTTOKENINFO *pti // ptr to token information
)
{
HRESULThr =NOERROR;
CHARchtmp =0;
CHAR *pch =NULL;
ULONGulPropTag =0;
DEBUGPRIVATE("HrGetNamedTag()\n");
pch = pti->pch + 1;
while (isalnum(*pch) || *pch == '_')
pch++;
// Terminate the putative PR_ string so we can look it up in the PropTbl.
chtmp =*pch;
*pch ='\0';
hr = HrGetPropTagValue(pti->pch, &ulPropTag);
*pch = chtmp;
if (FAILED(hr))
goto cleanup;
if (PROP_TYPE(ulPropTag) == PT_BOOLEAN)
{
pti->tt = BooleanTag;
}
else if (PROP_TYPE(ulPropTag) == PT_LONG)
{
pti->tt = NumericTag;
}
else if (PROP_TYPE(ulPropTag) == PT_STRING8||
PROP_TYPE(ulPropTag) == PT_UNICODE)
{
pti->tt = StringTag;
}
else if (PROP_TYPE(ulPropTag) == PT_SYSTIME)
{
pti->tt = TimeTag;
}
else
{
pti->tt = InvalidTag;
hr = HR_LOG(E_INVALIDARG);
}
pti->cch =pch - pti->pch;
pti->dwValue =ulPropTag;
cleanup:
RETURN(hr);
}
// $--HrGetNumericLiteral------------------------------------------------------
//
// DESCRIPTION:Parse a numeric literal token, returning results in
//*pti. A value for the numeric literal is returned in
//pti->dwValue.
//
// INPUT/OUTPUT:
//
//[pti]-- Ptr to token information structure.
//
// RETURNS: NOERRORif successful;
// E_INVALIDARGif bad input;
// E_FAILotherwise.
//-----------------------------------------------------------------------------
HRESULT
HrGetNumericLiteral( // RETURNS: HRESULT
IN OUTTOKENINFO *pti// ptr to token info structure
)
{
HRESULThr = NOERROR;
CHARchtmp =0;
LONGlValue =0;
CHAR *pch =NULL;
ULONGulValue = 0;
DEBUGPRIVATE("HrGetNumericLiteral()\n");
pch = pti->pch + 1;
while (isdigit(*pch))
pch++;
// If there is only 1 CHAR, it better be a digit rather than a sign.
if (pch == pti->pch + 1&& !isdigit(*(pti->pch)))
{
hr = HR_LOG(E_INVALIDARG);
goto cleanup;
}
// We temporarily terminate the number string, just to be absolutely
// certain that the following character is not used.
chtmp =*pch;
*pch ='\0';
errno = 0; // initialize it
// Use strtol() if the number is negative; otherwise use strtoul().
if (*(pti->pch) == '-')
{
lValue = strtol(pti->pch, (CHAR **)NULL, 10);
*pch = chtmp;
if ((lValue == LONG_MAX || lValue == LONG_MIN) && errno == ERANGE)
{
hr = HR_LOG(E_INVALIDARG);
goto cleanup;
}
pti->dwValue = lValue;
}
else
{
ulValue = strtoul(pti->pch, (CHAR **)NULL, 10);
*pch = chtmp;
if (ulValue == ULONG_MAX && errno == ERANGE)
{
hr = HR_LOG(E_INVALIDARG);
goto cleanup;
}
pti->dwValue =ulValue;
}
pti->cch =pch - pti->pch;
pti->tt =NumericLiteral;
cleanup:
RETURN(hr);
}
// $--HrGetStoreName-----------------------------------------------------------
//
// DESCRIPTION:Given a ptr to a store, get its display name.
//
// INPUT:
//
// [lpMDB]-- MAPI store ptr.
//
// OUTPUT:
//
//[lppszName]-- Ptr to ptr that will be set to point at store display
// name on successful return.
//
// RETURNS: NOERROR if successful;
//E_INVALIDARGif bad input;
//E_OUTOFMEMORYif out of memory;
//EDK_E_NOT_FOUNDif specified store not found;
// E_FAILotherwise.
//-----------------------------------------------------------------------------
HRESULT
HrGetStoreName( // RETURNS: HRESULT
INLPMDBlpMDB,// MAPI store ptr
OUTLPSTR FAR *lppszName // store name ptr ptr
)
{
static
SizedSPropTagArray(1, PropTagArray) ={1, {PR_DISPLAY_NAME}};
ULONGcValues = 0;
HRESULThr =NOERROR;
LPSPropValuelpProp = NULL;
DEBUGPRIVATE("HrGetStoreName()\n");
// Get the display name property.
hr = lpMDB->GetProps((LPSPropTagArray)&PropTagArray, 0, &cValues, &lpProp);
if (FAILED(hr))
goto cleanup;
if (cValues != 1 || lpProp->ulPropTag != PR_DISPLAY_NAME)
{
hr = HR_LOG(EDK_E_NOT_FOUND);
goto cleanup;
}
hr = MAPIAllocateBuffer(strlen(lpProp->Value.lpszA) + 1,
(LPVOID FAR *)lppszName);
if (FAILED(hr))
goto cleanup;
strcpy(*lppszName, lpProp->Value.lpszA);
cleanup:
MAPIFREEBUFFER(lpProp);
RETURN(hr);
}
// $--HrGetStringLiteral-------------------------------------------------------
//
// DESCRIPTION:Parse a string literal token, returning results in
//*pti. The user should allocate separate storage to save the
//string literal if it is to be converted to a MAPI property
//value.
// INPUT/OUTPUT:
//
//[pti]-- Ptr to token information structure.
//
// RETURNS: NOERRORif successful;
// E_INVALIDARGif bad input;
// E_FAILotherwise.
//
// Notes:pti->pch is left pointing at the opening quote and the value
//returned for pti->cch includes the leading and trailing quotes
//(ie. pti->cch >= 2).
//-----------------------------------------------------------------------------
HRESULT
HrGetStringLiteral(// RETURNS: HRESULT
IN OUTTOKENINFO *pti // ptr to token information
)
{
HRESULT hr =NOERROR;
CHAR *pch = NULL;
DEBUGPRIVATE("HrGetStringLiteral()\n");
pch = pti->pch + 1;
while (*pch != '"' && *pch != '\0')
pch++;
if (*pch != '"')
{
hr = HR_LOG(E_INVALIDARG);
goto cleanup;
}
pti->cch =pch - pti->pch + 1;
pti->tt =StringLiteral;
cleanup:
RETURN(hr);
}
// $--HrGetTimeLiteral---------------------------------------------------------
//
// DESCRIPTION:Parse a time literal token, returning results in *pti.
//A value for the time literal is returned in pti->ftValue.
//
// INPUT/OUTPUT:
//
//[pti]-- Ptr to token information structure.
//
// RETURNS: NOERRORif successful;
// E_INVALIDARGif bad input;
// E_FAILotherwise.
//-----------------------------------------------------------------------------
HRESULT
HrGetTimeLiteral( // RETURNS: HRESULT
IN OUTTOKENINFO *pti// ptr to token info structure
)
{
static CHARDateTemplate[] ="dddd-dd-dd";
CHARchtmp =0;
FILETIMEftLocal ={0};
LONGHour =0;
HRESULThr = NOERROR;
INTi =0;
LONGMinute =0;
LONGSecond =0;
CHAR *pch =pti->pch;
SYSTEMTIMEst ={0};
DEBUGPRIVATE("HrGetTimeLiteral()\n");
if (!isdigit(*pch)||
!isdigit(*(pch + 1))||
*(pch + 2) != ':')
{
hr = HR_LOG(E_INVALIDARG);
goto cleanup;
}
Hour = atol(pch);
if (Hour > 23)
{
hr = HR_LOG(E_INVALIDARG);
goto cleanup;
}
st.wHour = (WORD)Hour;
pch += 3;
if (!isdigit(*pch)||
!isdigit(*(pch + 1))||
(*(pch + 2) != ':' && !isspace(*(pch + 2))))
{
hr = HR_LOG(E_INVALIDARG);
goto cleanup;
}
Minute = atol(pch);
if (Minute > 59)
{
hr = HR_LOG(E_INVALIDARG);
goto cleanup;
}
st.wMinute = (WORD)Minute;
if (*(pch + 2) == ':')
{
pch += 3;
if (!isdigit(*pch)||
!isdigit(*(pch + 1))||
!isspace(*(pch + 2)))
{
hr = HR_LOG(E_INVALIDARG);
goto cleanup;
}
Second = atol(pch);
if (Second > 59)
{
hr = HR_LOG(E_INVALIDARG);
goto cleanup;
}
st.wSecond = (WORD)Second;
}
pch += 2;
pch = lpszSkipWhiteSpace(pch);
for (i = 0; i < sizeof(DateTemplate) - 1; i++)
{
if (DateTemplate[i] == 'd')
{
if (!isdigit(*(pch + i)))
{
hr = HR_LOG(E_INVALIDARG);
goto cleanup;
}
}
else
{
if (DateTemplate[i] != *(pch + i))
{
hr = HR_LOG(E_INVALIDARG);
goto cleanup;
}
}
}
// We let SystemTimeToFileTime() worry about range checking the date values.
st.wYear =(WORD)atol(pch);
st.wMonth =(WORD)atol(pch + 5);
// We terminate the day value just in case (insures correct day
// interpretation even if the rest of the expression is not well formed).
chtmp = *(pch + sizeof(DateTemplate) - 1);
*(pch + sizeof(DateTemplate) - 1) = '\0';
st.wDay =(WORD)atol(pch + 8);
*(pch + sizeof(DateTemplate) - 1) = chtmp;
pch += (sizeof(DateTemplate) - 1);
// Convert SYSTEMTIME to FILETIME.
if (!SystemTimeToFileTime(&st, &ftLocal))
{
hr = HR_LOG(E_INVALIDARG);
goto cleanup;
}
// We now presumably have a local FILETIME. Convert to UTC.
if (!LocalFileTimeToFileTime(&ftLocal, &pti->ftValue))
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}
pti->cch =pch - pti->pch;
pti->tt =TimeLiteral;
cleanup:
RETURN(hr);
}
// $--HrNotRestrictionToString-------------------------------------------------
//
// DESCRIPTION:Get a string representation of an SNotRestriction.
//
// INPUT:
//
//[lpRes]-- Ptr to not restriction to be represented as a string.
//
// INPUT/OUTPUT:
//
//[lppszString]-- Output string ptr ptr. If *lppszString == NULL, then
// a string will be allocated by this routine.
//[lpcbString]-- Ptr to count of bytes in input string on input (including
// terminating '\0'); count of bytes in string after
// appending formatted string on output.
//[lpcbBuffer]-- Ptr to count of bytes in input string buffer on input;
// count of bytes in string buffer after appending formatted
// string on output (buffer size may increase if allocation
// was necessary).
//
// RETURNS: NOERRORif successful;
// E_INVALIDARGif bad input;
// E_FAILotherwise.
//-----------------------------------------------------------------------------
HRESULT
HrNotRestrictionToString(// RETURNS: HRESULT
INLPSRestrictionlpRes,// restriction ptr
IN OUTLPSTR FAR *lppszString,// output string ptr ptr
IN OUTLPULONGlpcbString,// ptr to count of bytes in string
IN OUTLPULONGlpcbBuffer// ptr to count of bytes in buffer
)
{
HRESULThr =NOERROR;
SNotRestriction *presNot=NULL;
DEBUGPRIVATE("HrNotRestrictionToString()\n");
presNot=&lpRes->res.resNot;
hr = HrPrintToString(lppszString, lpcbString, lpcbBuffer, "!");
if (FAILED(hr))
goto cleanup;
if (ISNONTERMINALRESTRICTION(presNot->lpRes))
{
hr = HrPrintToString(lppszString, lpcbString, lpcbBuffer, "(");
if (FAILED(hr))
goto cleanup;
hr = HrPrivateRestrictionToString(presNot->lpRes,
lppszString,
lpcbString,
lpcbBuffer);
if (FAILED(hr))
goto cleanup;
hr = HrPrintToString(lppszString, lpcbString, lpcbBuffer, ")");
if (FAILED(hr))
goto cleanup;
}
else
{
hr = HrPrivateRestrictionToString(presNot->lpRes,
lppszString,
lpcbString,
lpcbBuffer);
if (FAILED(hr))
goto cleanup;
}
cleanup:
RETURN(hr);
}
// $--HrOrRestrictionToString--------------------------------------------------
//
// DESCRIPTION:Get a string representation of an SOrRestriction.
//
// INPUT:
//
//[lpRes]-- Ptr to or restriction to be represented as a string.
//
// INPUT/OUTPUT:
//
//[lppszString]-- Output string ptr ptr. If *lppszString == NULL, then
// a string will be allocated by this routine.
//[lpcbString]-- Ptr to count of bytes in input string on input (including
// terminating '\0'); count of bytes in string after
// appending formatted string on output.
//[lpcbBuffer]-- Ptr to count of bytes in input string buffer on input;
// count of bytes in string buffer after appending formatted
// string on output (buffer size may increase if allocation
// was necessary).
//
// RETURNS: NOERRORif successful;
// E_INVALIDARGif bad input;
// E_FAILotherwise.
//-----------------------------------------------------------------------------
HRESULT
HrOrRestrictionToString(// RETURNS: HRESULT
INLPSRestrictionlpRes,// restriction ptr
IN OUTLPSTR FAR *lppszString,// output string ptr ptr
IN OUTLPULONGlpcbString,// ptr to count of bytes in string
IN OUTLPULONGlpcbBuffer// ptr to count of bytes in buffer
)
{
HRESULThr = NOERROR;
ULONGi =0;
SOrRestriction *presOr =NULL;
DEBUGPRIVATE("HrOrRestrictionToString()\n");
presOr = &lpRes->res.resOr;
if (presOr->cRes < 2)
{
hr = HrPrintToString(lppszString,
lpcbString,
lpcbBuffer,
"<Invalid SOrRestriction>");
if (FAILED(hr))
goto cleanup;
}
else
{
hr = HrPrivateRestrictionToString(presOr->lpRes,
lppszString,
lpcbString,
lpcbBuffer);
if (FAILED(hr))
goto cleanup;
for (i = 1; i < presOr->cRes; i++)
{
hr = HrPrintToString(lppszString, lpcbString, lpcbBuffer, " | ");
if (FAILED(hr))
goto cleanup;
if (ISNONTERMINALRESTRICTION(presOr->lpRes + i))
{
hr = HrPrintToString(lppszString, lpcbString, lpcbBuffer, "(");
if (FAILED(hr))
goto cleanup;
hr = HrPrivateRestrictionToString(presOr->lpRes + i,
lppszString,
lpcbString,
lpcbBuffer);
if (FAILED(hr))
goto cleanup;
hr = HrPrintToString(lppszString, lpcbString, lpcbBuffer, ")");
if (FAILED(hr))
goto cleanup;
}
else
{
hr = HrPrivateRestrictionToString(presOr->lpRes + i,
lppszString,
lpcbString,
lpcbBuffer);
if (FAILED(hr))
goto cleanup;
}
}
}
cleanup:
RETURN(hr);
}
// $--HrParseAction------------------------------------------------------------
//
// DESCRIPTION:Parse an action string.
//
// INPUT:
//
//[lpSession]-- Ptr to MAPI session.
//
//[lpFolder]-- Ptr to MAPI folder action applies to.
//
//[lpObject]-- Ptr to an existing MAPI buffer allocated by
// MAPIAllocateBuffer(). NULL is not permitted!
//
//[pch]-- Ptr to string to be parsed.
//
// INPUT/OUTPUT:
//
//[lpAction]-- Ptr to uninitialized ACTION structure on input;
// It will be appropriately initialized on output.
//
// RETURNS: NOERRORif successful;
// E_INVALIDARGif bad input;
// E_OUTOFMEMORYif out of memory;
//E_UNEXPECTEDif there is an internal error;
// E_*otherwise.
//-----------------------------------------------------------------------------
HRESULT
HrParseAction(// RETURNS: HRESULT
INLPMAPISESSIONlpSession,// ptr to MAPI session
INLPMAPIFOLDERlpFolder,// ptr to MAPI folder
INLPVOIDlpObject,// ptr to existing MAPI buffer
INCHAR *pch, // string ptr
IN OUTLPACTIONlpAction // action ptr
)
{
static CHARszBounceKeyword[] ="bounce";
static CHARszCopyKeyword[] ="copy";
static CHARszDelegateKeyword[] ="delegate";
static CHARszDeleteKeyword[] ="delete";
static CHARszForwardKeyword[] ="forward";
static CHARszMarkReadKeyword[] ="markread";
static CHARszMoveKeyword[] ="move";
static CHARszMsgIdKeyword[] ="msgid";
static CHARszReplyKeyword[] ="reply";
static CHARszTagKeyword[] ="tag";
CHARchtmp =0;
HRESULThr =NOERROR;
LPADRBOOKlpAdrBook =NULL;
LPADRLISTlpAdrList =NULL;
CHAR *pchEnd =pch;
// Set all fields in ACTION struct to 0.
memset(lpAction, 0, sizeof(*lpAction));
// Find the start of the action keyword.
pch = lpszSkipWhiteSpace(pch);
pchEnd = lpszSkipNonWhiteSpace(pch);
// Terminate the action keyword so we can parse it.
chtmp =*pchEnd;
*pchEnd ='\0';
// Identify the action keyword.
if (!stricmp(pch, szBounceKeyword))
{
lpAction->acttype = OP_BOUNCE;
}
else if (!stricmp(pch, szCopyKeyword))
{
lpAction->acttype = OP_COPY;
}
else if (!stricmp(pch, szDelegateKeyword))
{
lpAction->acttype = OP_DELEGATE;
}
else if (!stricmp(pch, szDeleteKeyword))
{
lpAction->acttype = OP_DELETE;
}
else if (!stricmp(pch, szForwardKeyword))
{
lpAction->acttype = OP_FORWARD;
}
else if (!stricmp(pch, szMarkReadKeyword))
{
lpAction->acttype = OP_MARK_AS_READ;
}
else if (!stricmp(pch, szMoveKeyword))
{
lpAction->acttype = OP_MOVE;
}
else if (!stricmp(pch, szReplyKeyword))
{
lpAction->acttype = OP_REPLY;
}
else if (!stricmp(pch, szTagKeyword))
{
lpAction->acttype = OP_TAG;
}
else
{
*pchEnd = chtmp;
hr = HR_LOG(E_INVALIDARG);
goto cleanup;
}
*pchEnd = chtmp;
pch = lpszSkipWhiteSpace(pchEnd);
switch (lpAction->acttype)
{
case OP_BOUNCE:
{
pchEnd = lpszSkipNonWhiteSpace(pch);
// Terminate the bounce code so we can parse it.
chtmp =*pchEnd;
*pchEnd ='\0';
if (!strcmp(pch, "BOUNCE_MESSAGE_SIZE_TOO_LARGE"))
{
lpAction->scBounceCode = BOUNCE_MESSAGE_SIZE_TOO_LARGE;
}
else if (!strcmp(pch, "BOUNCE_FORMS_MISMATCH"))
{
lpAction->scBounceCode = BOUNCE_FORMS_MISMATCH;
}
else if (!strcmp(pch, "BOUNCE_ACCESS_DENIED"))
{
lpAction->scBounceCode = BOUNCE_ACCESS_DENIED;
}
else
{
*pchEnd = chtmp;
hr = HR_LOG(E_INVALIDARG);
goto cleanup;
}
*pchEnd = chtmp;
pch = lpszSkipWhiteSpace(pchEnd);
if (*pch != '\0')
{
hr = HR_LOG(E_INVALIDARG);
goto cleanup;
}
break;
}
case OP_COPY:
case OP_MOVE:
{
hr = HrGetMoveCopyArgs(lpSession, pch, lpObject, lpAction);
if (FAILED(hr))
goto cleanup;
break;
}
case OP_DELEGATE:
case OP_FORWARD:
{
ULONGcRecips =0;
ULONGcQuotes =0;
CHAR *pQuote =pch;
// Count quotation mark pairs to arrive at a count of recipients.
// This is more reliable than counting comma's since a comma may
// be embedded in a recipient name.
while ((pQuote = strchr(pQuote, '"')) != NULL)
{
cQuotes++;
pQuote++;
}
if (cQuotes == 0 || (cQuotes & 1) != 0)
{
hr = HR_LOG(E_INVALIDARG);
goto cleanup;
}
cRecips = cQuotes >> 1;
hr = MAPIAllocateBuffer(CbNewADRLIST(cRecips), (LPVOID *)&lpAdrList);
if (FAILED(hr))
goto cleanup;
{
ULONGi = 0;
LPADRENTRYlpAdrEntry = NULL;
LPSTRlpszName = NULL;
lpAdrList->cEntries = cRecips;
// Init the ADRENTRY's prior to actually allocating the SPropValue
// arrays. This makes cleanup possible if there is an error.
for (i = 0; i < cRecips; i++)
{
lpAdrList->aEntries[i].ulReserved1 =0;
lpAdrList->aEntries[i].cValues =1;
lpAdrList->aEntries[i].rgPropVals =NULL;
}
// Now allocate and initialize the SPropValue arrays.
for (i = 0; i < cRecips; i++)
{
hr = MAPIAllocateBuffer(sizeof(SPropValue),
(LPVOID *)&lpAdrList->aEntries[i].rgPropVals);
if (FAILED(hr))
goto cleanup;
lpAdrList->aEntries[i].rgPropVals->ulPropTag = PR_DISPLAY_NAME;
lpAdrList->aEntries[i].rgPropVals->Value.lpszA = NULL;
}
lpAdrEntry = lpAdrList->aEntries;
// Parse the recipient names.
// Note that the index used below is 1-based (ie., don't use it
// for a 0-based array!).
for (i = 1; i <= cRecips; i++)
{
if (*pch != '"')
{
hr = HR_LOG(E_INVALIDARG);
goto cleanup;
}
pch++;
lpszName = pch;
while (*pch != '"' && *pch != '\0')
pch++;
if (*pch == '\0')
{
hr = HR_LOG(E_INVALIDARG);
goto cleanup;
}
*pch = '\0';
hr = MAPIAllocateMore(strlen(lpszName) + 1,
lpAdrEntry->rgPropVals,
(LPVOID *)&lpAdrEntry->
rgPropVals[0].Value.lpszA);
if (FAILED(hr))
goto cleanup;
strcpy(lpAdrEntry->rgPropVals[0].Value.lpszA, lpszName);
lpAdrEntry++;
*pch = '"';
pch++;
pch = lpszSkipWhiteSpace(pch);
if (i != cRecips)
{
if (*pch != ',')
{
hr = HR_LOG(E_INVALIDARG);
goto cleanup;
}
pch++;
pch = lpszSkipWhiteSpace(pch);
}
else
{
if (*pch != '\0')
{
hr = HR_LOG(E_INVALIDARG);
goto cleanup;
}
}
}
hr = lpSession->OpenAddressBook(0, NULL, AB_NO_DIALOG, &lpAdrBook);
if (FAILED(hr))
goto cleanup;
hr = lpAdrBook->ResolveName(0, 0, NULL, lpAdrList);
if (FAILED(hr))
goto cleanup;
// Now look for problems reported in the returned ADRLIST.
for (i = 0; i < cRecips; i++)
{
ULONGj;
lpAdrEntry = &lpAdrList->aEntries[i];
for (j = 0; j < lpAdrEntry->cValues; j++)
{
LPSPropValuepPropVal;
pPropVal = &lpAdrEntry->rgPropVals[j];
if (PROP_TYPE(pPropVal->ulPropTag == PT_ERROR))
{
hr = pPropVal->Value.err;
break;
}
}
if (FAILED(hr))
goto cleanup;
}
// Now reallocate the ADRLIST using linked allocation; we did
// not do this at first to avoid problems in ResolveName().
lpAction->lpadrlist = NULL;
hr = MAPIAllocateMore(CbNewADRLIST(cRecips),
lpObject,
(LPVOID *)&lpAction->lpadrlist);
if (FAILED(hr))
goto cleanup;
memcpy(lpAction->lpadrlist, lpAdrList, CbNewADRLIST(cRecips));
for (i = 0; i < cRecips; i++)
{
hr = HrDupPropset(lpAdrList->aEntries[i].cValues,
lpAdrList->aEntries[i].rgPropVals,
lpObject,
&lpAction->lpadrlist->aEntries[i].rgPropVals);
if (FAILED(hr))
goto cleanup;
}
}
break;
}
case OP_DELETE:
case OP_MARK_AS_READ:
{
if (*pch != '\0')
{
hr = HR_LOG(E_INVALIDARG);
goto cleanup;
}
break;
}
case OP_REPLY:
{
if (*pch == '"')
{
pch++;
pchEnd = pch;
while (*pchEnd != '"' && *pchEnd != '\0')
pchEnd++;
if (*pchEnd == '\0')
{
hr = HR_LOG(E_INVALIDARG);
goto cleanup;
}
*pchEnd = '\0';
// Make a message from *pch.
hr = HrCreateReplyMsg(lpFolder,
pch,
lpObject,
&lpAction->actReply.cbEntryId,
&lpAction->actReply.lpEntryId);
if (FAILED(hr))
goto cleanup;
*pchEnd = '"';
pchEnd++;
}
else
{
ULONGcNibbles =0;
pchEnd = lpszSkipNonWhiteSpace(pch);
// Terminate the keyword so we can parse it.
chtmp =*pchEnd;
*pchEnd ='\0';
if (stricmp(pch, szMsgIdKeyword))
{
hr = HR_LOG(E_INVALIDARG);
goto cleanup;
}
*pchEnd = chtmp;
pch = lpszSkipWhiteSpace(pchEnd);
if (*pch == '0' && (*(pch + 1) == 'x' || *(pch + 1) == 'X'))
pch += 2;
pchEnd = pch;
while (isxdigit(*pchEnd))
pchEnd++;
cNibbles = pchEnd - pch;
if (cNibbles == 0 || (cNibbles & 1) != 0)
{
hr = HR_LOG(E_INVALIDARG);
goto cleanup;
}
lpAction->actReply.cbEntryId = cNibbles >> 1;
// Allocate space for entryid.
hr = MAPIAllocateMore(lpAction->actReply.cbEntryId,
lpObject,
(LPVOID FAR *)&lpAction->actReply.lpEntryId);
if (FAILED(hr))
goto cleanup;
// Determine it's value and store it.
BYTEloNibble =0;
BYTEhiNibble =0;
BYTE *pByte =(BYTE *)lpAction->actReply.lpEntryId;
while (pch < pchEnd)
{
if (*pch >= '0' && *pch <= '9')
hiNibble = *pch - '0';
else if (*pch >= 'a' && *pch <= 'f')
hiNibble = *pch - ('a' - 0xa);
else
hiNibble = *pch - ('A' - 0xa);
pch++;
if (*pch >= '0' && *pch <= '9')
loNibble = *pch - '0';
else if (*pch >= 'a' && *pch <= 'f')
loNibble = *pch - ('a' - 0xa);
else
loNibble = *pch - ('A' - 0xa);
pch++;
*pByte = (hiNibble << 4) + loNibble;
pByte++;
}
}
// Finish parsing line.
pch = lpszSkipWhiteSpace(pchEnd);
if (*pch != '\0')
{
hr = HR_LOG(E_INVALIDARG);
goto cleanup;
}
break;
}
case OP_TAG:
{
TOKENINFOti ={pch, 0, NotRecognized, 0};
ULONGpt =PT_UNSPECIFIED;
if (*pch == 'P' || *pch == 'p')
hr = HrGetNamedTag(&ti);
else if (*pch == '[')
hr = HrGetExplicitTag(&ti);
else
hr = HR_LOG(E_INVALIDARG);
if (FAILED(hr))
goto cleanup;
pch = ti.pch + ti.cch;
pt = PROP_TYPE(ti.dwValue);
pch = lpszSkipWhiteSpace(pch);
if (*pch != ',')
{
hr = HR_LOG(E_INVALIDARG);
goto cleanup;
}
pch++;// Skip over the comma.
pch = lpszSkipWhiteSpace(pch);
lpAction->propTag.ulPropTag = ti.dwValue;
ti.pch = pch;
ti.cch = 0;
ti.tt =NotRecognized;
ti.dwValue =0;
if (pt == PT_BOOLEAN)
{
hr = HrGetExpressionToken(&ti);
if (FAILED(hr))
goto cleanup;
pch = ti.pch + ti.cch;
// A boolean literal is essentially a numeric literal with
// a restricted range, so...
if (ti.tt != NumericLiteral|| ti.dwValue > 1)
{
hr = HR_LOG(E_INVALIDARG);
goto cleanup;
}
lpAction->propTag.Value.b = (USHORT)ti.dwValue;
}
else if (pt == PT_LONG)
{
hr = HrGetExpressionToken(&ti);
if (FAILED(hr))
goto cleanup;
pch = ti.pch + ti.cch;
if (ti.tt != NumericLiteral)
{
hr = HR_LOG(E_INVALIDARG);
goto cleanup;
}
lpAction->propTag.Value.l = ti.dwValue;
}
else if (pt == PT_STRING8)
{
hr = HrGetExpressionToken(&ti);
if (FAILED(hr))
goto cleanup;
pch = ti.pch + ti.cch;
if (ti.tt != StringLiteral)
{
hr = HR_LOG(E_INVALIDARG);
goto cleanup;
}
hr = MAPIAllocateMore(ti.cch + 1 - 2, lpObject,
(LPVOID FAR *)&lpAction->propTag.Value.lpszA);
if (FAILED(hr))
goto cleanup;
memcpy(lpAction->propTag.Value.lpszA, ti.pch + 1, ti.cch - 2);
*(lpAction->propTag.Value.lpszA + ti.cch - 2) = '\0';
}
else if (pt == PT_SYSTIME)
{
hr = HrGetExpressionToken(&ti);
if (FAILED(hr))
goto cleanup;
pch = ti.pch + ti.cch;
if (ti.tt != TimeLiteral)
{
hr = HR_LOG(E_INVALIDARG);
goto cleanup;
}
lpAction->propTag.Value.ft = ti.ftValue;
}
else if (pt == PT_UNICODE)
{
INTcch = 0;
hr = HrGetExpressionToken(&ti);
if (FAILED(hr))
goto cleanup;
pch = ti.pch + ti.cch;
if (ti.tt != StringLiteral)
{
hr = HR_LOG(E_INVALIDARG);
goto cleanup;
}
if (ti.cch > 2)
{
cch = MultiByteToWideChar(CP_ACP,
0,
ti.pch + 1,
ti.cch - 2,
NULL,
0);
if (cch == 0)
{
hr = HR_LOG(E_INVALIDARG);
goto cleanup;
}
}
hr = MAPIAllocateMore((cch + 1) * sizeof(WCHAR), lpObject,
(LPVOID FAR *)&lpAction->propTag.Value.lpszW);
if (FAILED(hr))
goto cleanup;
if (ti.cch > 2)
{
if (!MultiByteToWideChar(CP_ACP,
0,
ti.pch + 1,
ti.cch - 2,
lpAction->propTag.Value.lpszW,
cch))
{
hr = HR_LOG(E_INVALIDARG);
goto cleanup;
}
}
*(lpAction->propTag.Value.lpszW + cch) = 0;
}
else
{
hr = HR_LOG(E_UNEXPECTED);// There is an internal error.
goto cleanup;
}
pch = lpszSkipWhiteSpace(pch);
if (*pch != '\0')
{
hr = HR_LOG(E_INVALIDARG);
goto cleanup;
}
break;
}
default:
{
hr = HR_LOG(E_UNEXPECTED);// There is an internal error.
goto cleanup;
break;
}
}
cleanup:
ULRELEASE(lpAdrBook);
FREEPADRLIST(lpAdrList);
return hr;
}
// $--HrParseCondition---------------------------------------------------------
//
// DESCRIPTION:Parse a restriction condition expression or parenthetical
//subexpression.
//
// INPUT:
//
//[lpObject]-- Ptr to an existing MAPI buffer allocated by
// MAPIAllocateBuffer(). NULL is not permitted!
//
// INPUT/OUTPUT:
//
//[ppch]-- Ptr to ptr to string to be parsed on input;
// ptr to ptr to first unparsed CHAR on output.
//
//[lpRes]-- Ptr to uninitialized SRestriction structure on input;
// It will be appropriately initialized and may include
// other allocated SRestrictions on output.
//
// RETURNS: NOERRORif successful;
// E_INVALIDARGif bad input;
//E_OUTOFMEMORYif out of memory;
// E_FAILotherwise.
//-----------------------------------------------------------------------------
HRESULT
HrParseCondition(// RETURNS: HRESULT
INLPVOIDlpObject,// ptr to existing MAPI buffer
IN OUTCHAR **ppch, // string
IN OUTLPSRestrictionlpRes // restriction ptr
)
{
HRESULThr =NOERROR;
LPSRestrictionlpNxtRes =lpRes;
LPSPropValuelpProp = NULL;
CHAR *pch =NULL;
TOKENINFOti ={0};
DEBUGPRIVATE("HrParseCondition()\n");
pch = *ppch;
while (TRUE)
{
ti.pch = pch;
hr = HrGetExpressionToken(&ti);
if (FAILED(hr))
goto cleanup;
pch = ti.pch + ti.cch;// Now pch points to next token.
switch (ti.tt)
{
case LeftParen:
{
hr = HrParseCondition(lpObject, &pch, lpNxtRes);
if (FAILED(hr))
goto cleanup;
ti.pch = pch;
hr = HrGetExpressionToken(&ti);
if (FAILED(hr))
goto cleanup;
pch = ti.pch + ti.cch;
if (ti.tt != RightParen)
{
hr = HR_LOG(E_INVALIDARG);
goto cleanup;
}
break;
}
case NotOp:
{
lpNxtRes->rt = RES_NOT;
lpNxtRes->res.resNot.ulReserved =0;
lpNxtRes->res.resNot.lpRes =NULL;
hr = MAPIAllocateMore(sizeof(SRestriction),
lpObject,
(LPVOID FAR *)
&lpNxtRes->res.resNot.lpRes);
if (FAILED(hr))
goto cleanup;
lpNxtRes->res.resNot.lpRes->rt = RES_UNINITIALIZED;
lpNxtRes = lpNxtRes->res.resNot.lpRes;
continue;
}
case BooleanTag:
{
TOKENINFOtiBooleanTag =ti;
TOKENINFOtiBooleanOp;
TOKENINFOtiBooleanLiteral;
tiBooleanOp.pch = pch;
hr = HrGetExpressionToken(&tiBooleanOp);
if (FAILED(hr))
goto cleanup;
pch = tiBooleanOp.pch + tiBooleanOp.cch;
tiBooleanLiteral.pch = pch;
hr = HrGetExpressionToken(&tiBooleanLiteral);
if (FAILED(hr))
goto cleanup;
pch = tiBooleanLiteral.pch + tiBooleanLiteral.cch;
// A boolean literal is essentially a numeric literal with
// a restricted range, so...
if (tiBooleanLiteral.tt != NumericLiteral||
tiBooleanLiteral.dwValue > 1)
{
hr = HR_LOG(E_INVALIDARG);
goto cleanup;
}
if (tiBooleanOp.tt != EqualOp)
{
hr = HR_LOG(E_INVALIDARG);
goto cleanup;
}
lpNxtRes->rt = RES_PROPERTY;
lpNxtRes->res.resProperty.relop =RELOP_EQ;
lpNxtRes->res.resProperty.ulPropTag =tiBooleanTag.dwValue;
lpNxtRes->res.resProperty.lpProp =NULL;
hr = MAPIAllocateMore(sizeof(SPropValue),
lpObject,
(LPVOID FAR *)&lpProp);
if (FAILED(hr))
goto cleanup;
lpProp->ulPropTag =tiBooleanTag.dwValue;
lpProp->Value.b =(USHORT)tiBooleanLiteral.dwValue;
lpNxtRes->res.resProperty.lpProp = lpProp;
break;
}
case NumericTag:
{
ULONGrelop;
TOKENINFOtiNumericTag =ti;
TOKENINFOtiNumericOp;
TOKENINFOtiNumericLiteral;
tiNumericOp.pch = pch;
hr = HrGetExpressionToken(&tiNumericOp);
if (FAILED(hr))
goto cleanup;
pch = tiNumericOp.pch + tiNumericOp.cch;
tiNumericLiteral.pch = pch;
hr = HrGetExpressionToken(&tiNumericLiteral);
if (FAILED(hr))
goto cleanup;
pch = tiNumericLiteral.pch + tiNumericLiteral.cch;
if (tiNumericLiteral.tt != NumericLiteral)
{
hr = HR_LOG(E_INVALIDARG);
goto cleanup;
}
switch (tiNumericOp.tt)
{
case NotEqualOp:
relop = RELOP_NE;
break;
case EqualOp:
relop = RELOP_EQ;
break;
case GreaterThanOp:
relop = RELOP_GT;
break;
case LessThanOp:
relop = RELOP_LT;
break;
default:
hr = HR_LOG(E_INVALIDARG);
goto cleanup;
}
lpNxtRes->rt = RES_PROPERTY;
lpNxtRes->res.resProperty.relop =relop;
lpNxtRes->res.resProperty.ulPropTag =tiNumericTag.dwValue;
lpNxtRes->res.resProperty.lpProp =NULL;
hr = MAPIAllocateMore(sizeof(SPropValue),
lpObject,
(LPVOID FAR *)&lpProp);
if (FAILED(hr))
goto cleanup;
lpProp->ulPropTag = tiNumericTag.dwValue;
lpProp->Value.l =tiNumericLiteral.dwValue;
lpNxtRes->res.resProperty.lpProp = lpProp;
break;
}
case StringTag:
{
ULONGrelop;
ULONGrt;
TOKENINFOtiStringTag =ti;
TOKENINFOtiStringOp;
TOKENINFOtiStringLiteral;
tiStringOp.pch = pch;
hr = HrGetExpressionToken(&tiStringOp);
if (FAILED(hr))
goto cleanup;
pch = tiStringOp.pch + tiStringOp.cch;
tiStringLiteral.pch = pch;
hr = HrGetExpressionToken(&tiStringLiteral);
if (FAILED(hr))
goto cleanup;
// Note that the string literal returned includes the
// opening and closing quotes (hence all the strange mods
// to pch and cch).
pch = tiStringLiteral.pch + tiStringLiteral.cch;
if (tiStringLiteral.tt != StringLiteral)
{
hr = HR_LOG(E_INVALIDARG);
goto cleanup;
}
switch (tiStringOp.tt)
{
case NotEqualOp:
relop = RELOP_NE;
rt =RES_PROPERTY;
break;
case EqualOp:
relop = RELOP_EQ;
rt =RES_PROPERTY;
break;
case ContainsOp:
rt =RES_CONTENT;
break;
default:
hr = HR_LOG(E_INVALIDARG);
goto cleanup;
}
lpNxtRes->rt = rt;
if (rt == RES_PROPERTY)
{
lpNxtRes->res.resProperty.relop = relop;
lpNxtRes->res.resProperty.ulPropTag = tiStringTag.dwValue;
lpNxtRes->res.resProperty.lpProp = NULL;
}
else// rt == RES_CONTENT
{
lpNxtRes->res.resContent.ulFuzzyLevel =FL_SUBSTRING|
FL_IGNORECASE;
lpNxtRes->res.resContent.ulPropTag = tiStringTag.dwValue;
lpNxtRes->res.resContent.lpProp = NULL;
}
hr = MAPIAllocateMore(sizeof(SPropValue),
lpObject,
(LPVOID FAR *)&lpProp);
if (FAILED(hr))
goto cleanup;
if (rt == RES_PROPERTY)
{
lpNxtRes->res.resProperty.lpProp =lpProp;
}
else// rt == RES_CONTENT
{
lpNxtRes->res.resContent.lpProp =lpProp;
}
lpProp->ulPropTag =tiStringTag.dwValue;
if (PROP_TYPE(lpProp->ulPropTag) == PT_STRING8)
{
lpProp->Value.lpszA =NULL;
hr = MAPIAllocateMore(tiStringLiteral.cch + 1 - 2, lpObject,
(LPVOID FAR *)&lpProp->Value.lpszA);
if (FAILED(hr))
goto cleanup;
memcpy(lpProp->Value.lpszA,
tiStringLiteral.pch + 1,
tiStringLiteral.cch - 2);
*(lpProp->Value.lpszA + tiStringLiteral.cch - 2) = '\0';
}
else// it is UNICODE
{
INTcch = 0;
lpProp->Value.lpszW =NULL;
if (tiStringLiteral.cch > 2)
{
cch = MultiByteToWideChar(CP_ACP,
0,
tiStringLiteral.pch + 1,
tiStringLiteral.cch - 2,
NULL,
0);
if (cch == 0)
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}
}
hr = MAPIAllocateMore((cch + 1) * sizeof(WCHAR), lpObject,
(LPVOID FAR *)&lpProp->Value.lpszW);
if (FAILED(hr))
goto cleanup;
if (tiStringLiteral.cch > 2)
{
if (!MultiByteToWideChar(CP_ACP,
0,
tiStringLiteral.pch + 1,
tiStringLiteral.cch - 2,
lpProp->Value.lpszW,
cch))
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}
}
*(lpProp->Value.lpszW + cch) = 0;
}
break;
}
case TimeTag:
{
ULONGrelop;
TOKENINFOtiTimeTag =ti;
TOKENINFOtiTimeOp;
TOKENINFOtiTimeLiteral;
tiTimeOp.pch = pch;
hr = HrGetExpressionToken(&tiTimeOp);
if (FAILED(hr))
goto cleanup;
pch = tiTimeOp.pch + tiTimeOp.cch;
tiTimeLiteral.pch = pch;
hr = HrGetExpressionToken(&tiTimeLiteral);
if (FAILED(hr))
goto cleanup;
pch = tiTimeLiteral.pch + tiTimeLiteral.cch;
if (tiTimeLiteral.tt != TimeLiteral)
{
hr = HR_LOG(E_INVALIDARG);
goto cleanup;
}
switch (tiTimeOp.tt)
{
case NotEqualOp:
relop = RELOP_NE;
break;
case EqualOp:
relop = RELOP_EQ;
break;
case GreaterThanOp:
relop = RELOP_GT;
break;
case LessThanOp:
relop = RELOP_LT;
break;
default:
hr = HR_LOG(E_INVALIDARG);
goto cleanup;
}
lpNxtRes->rt = RES_PROPERTY;
lpNxtRes->res.resProperty.relop =relop;
lpNxtRes->res.resProperty.ulPropTag =tiTimeTag.dwValue;
lpNxtRes->res.resProperty.lpProp =NULL;
hr = MAPIAllocateMore(sizeof(SPropValue),
lpObject,
(LPVOID FAR *)&lpProp);
if (FAILED(hr))
goto cleanup;
lpProp->ulPropTag = tiTimeTag.dwValue;
lpProp->Value.ft =tiTimeLiteral.ftValue;
lpNxtRes->res.resProperty.lpProp = lpProp;
break;
}
default:
{
hr = HR_LOG(E_INVALIDARG);
goto cleanup;
}
}
ti.pch = pch;
hr = HrGetExpressionToken(&ti);
if (FAILED(hr))
goto cleanup;
pch = ti.pch + ti.cch;// Now pch points to next token.
switch (ti.tt)
{
case AndOp:
{
LPSRestrictionlpResArray =NULL;
hr = MAPIAllocateMore(sizeof(SRestriction) * 2,
lpObject,
(LPVOID FAR *)&lpResArray);
if (FAILED(hr))
goto cleanup;
lpResArray[0] = *lpRes;
lpResArray[1].rt = RES_UNINITIALIZED;
lpRes->rt = RES_AND;
lpRes->res.resAnd.cRes =2;
lpRes->res.resAnd.lpRes =lpResArray;
lpNxtRes = &lpResArray[1];
break;
}
case OrOp:
{
LPSRestrictionlpResArray =NULL;
hr = MAPIAllocateMore(sizeof(SRestriction) * 2,
lpObject,
(LPVOID FAR *)&lpResArray);
if (FAILED(hr))
goto cleanup;
lpResArray[0] = *lpRes;
lpResArray[1].rt = RES_UNINITIALIZED;
lpRes->rt = RES_OR;
lpRes->res.resOr.cRes =2;
lpRes->res.resOr.lpRes =lpResArray;
lpNxtRes = &lpResArray[1];
break;
}
case EndOfString:
case RightParen:
{
pch = ti.pch;// Push this token back and return to caller.
if (lpRes->rt == RES_UNINITIALIZED)
hr = HR_LOG(E_INVALIDARG);
goto cleanup;// Done!
}
default:
{
hr = HR_LOG(E_INVALIDARG);
goto cleanup;
}
}
}
cleanup:
*ppch = pch;
RETURN(hr);
}
// $--HrPrintToString----------------------------------------------------------
//
// DESCRIPTION:Write the formatted string to the end of the supplied
//output string.
//
// INPUT/OUTPUT:
//
//[lppszString]-- Output string ptr ptr. If *lppszString == NULL, then
// a string will be allocated by this routine.
//[lpcbString]-- Ptr to count of bytes in input string on input (including
// terminating '\0'); count of bytes in string after
// appending formatted string on output.
//[lpcbBuffer]-- Ptr to count of bytes in input string buffer on input;
// count of bytes in string buffer after appending formatted
// string on output (buffer size may increase if allocation
// was necessary).
//
// INPUT:
//
//[Format]-- A printf style format string.
//[...]-- Format arguments.
//
// RETURNS: NOERRORif successful;
//E_OUTOFMEMORYif out of memory;
// E_*otherwise.
//
// Notes:This routine appends the formatted string to the end of an
//existing string. If the existing string is NULL, (ie.
//*lppszString == NULL) then this routine will do the initial
//allocation. Note that *lppszString may be reallocated as
//necessary to grow the buffer, and the old copy will be released.
//The routine uses MAPIAllocateBuffer() and MAPIFreeBuffer().
//
//-----------------------------------------------------------------------------
#defineHRPRINTTOSTRING_BUFINCR1024
HRESULT
HrPrintToString(// RETURNS: HRESULT
IN OUTLPSTR FAR *lppszString,// output string ptr ptr
IN OUTLPULONGlpcbString,// ptr to count of bytes in string
IN OUTLPULONGlpcbBuffer,// ptr to count of bytes in buffer
INLPSTRFormat // message format
... // variable arguments
)
{
va_listargs;
LONGcb =0;
HRESULThr =NOERROR;
LPSTRlpszStringCopy =NULL;
DEBUGPRIVATE("HrPrintToString()\n");
if (*lppszString == NULL)
{
hr = MAPIAllocateBuffer(HRPRINTTOSTRING_BUFINCR,
(LPVOID FAR *)lppszString);
if (FAILED(hr))
goto cleanup;
*lpcbBuffer =HRPRINTTOSTRING_BUFINCR;
*lpcbString =1;
*lppszString[0] ='\0';
}
va_start(args, Format);
while (TRUE)
{
cb = _vsnprintf(*lppszString + *lpcbString - 1,
*lpcbBuffer - *lpcbString + 1,
Format,
args);
if (cb >= 0)
{
*lpcbString += cb;
break;
}
hr = MAPIAllocateBuffer(*lpcbBuffer + HRPRINTTOSTRING_BUFINCR,
(LPVOID FAR *)&lpszStringCopy);
if (FAILED(hr))
goto cleanup;
*lpcbBuffer += HRPRINTTOSTRING_BUFINCR;
memcpy(lpszStringCopy, *lppszString, *lpcbString);
MAPIFREEBUFFER(*lppszString);
*lppszString = lpszStringCopy;
}
cleanup:
va_end(args);
RETURN(hr);
}
// $--HrPrivateRestrictionToString---------------------------------------------
//
// DESCRIPTION:Get a string representation of an SRestriction.
//
// INPUT:
//
//[lpRes]-- Ptr to restriction to be represented as a string.
//
// INPUT/OUTPUT:
//
//[lppszString]-- Output string ptr ptr. If *lppszString == NULL, then
// a string will be allocated by this routine.
//[lpcbString]-- Ptr to count of bytes in input string on input (including
// terminating '\0'); count of bytes in string after
// appending formatted string on output.
//[lpcbBuffer]-- Ptr to count of bytes in input string buffer on input;
// count of bytes in string buffer after appending formatted
// string on output (buffer size may increase if allocation
// was necessary).
//
// RETURNS: NOERRORif successful;
// E_INVALIDARGif bad input;
// E_FAILotherwise.
//-----------------------------------------------------------------------------
HRESULT
HrPrivateRestrictionToString(
INLPSRestrictionlpRes,// restriction ptr
IN OUTLPSTR FAR *lppszString,// output string ptr ptr
IN OUTLPULONGlpcbString,// ptr to count of bytes in string
IN OUTLPULONGlpcbBuffer// ptr to count of bytes in buffer
)
{
HRESULThr =NOERROR;
DEBUGPRIVATE("HrPrivateRestrictionToString()\n");
if (lpRes == NULL)
{
hr = HrPrintToString(lppszString, lpcbString, lpcbBuffer, "<NULL>");
if (FAILED(hr))
goto cleanup;
}
else
{
switch (lpRes->rt)
{
case RES_AND:
hr = HrAndRestrictionToString(lpRes,
lppszString,
lpcbString,
lpcbBuffer);
break;
case RES_OR:
hr = HrOrRestrictionToString(lpRes,
lppszString,
lpcbString,
lpcbBuffer);
break;
case RES_NOT:
hr = HrNotRestrictionToString(lpRes,
lppszString,
lpcbString,
lpcbBuffer);
break;
case RES_CONTENT:
hr = HrContentRestrictionToString(lpRes,
lppszString,
lpcbString,
lpcbBuffer);
break;
case RES_PROPERTY:
hr = HrPropertyRestrictionToString(lpRes,
lppszString,
lpcbString,
lpcbBuffer);
break;
case RES_COMPAREPROPS:
hr = HrPrintToString(lppszString,
lpcbString,
lpcbBuffer,
"<SComparePropsRestriction>");
break;
case RES_BITMASK:
hr = HrPrintToString(lppszString,
lpcbString,
lpcbBuffer,
"<SBitMaskRestriction>");
break;
case RES_SIZE:
hr = HrPrintToString(lppszString,
lpcbString,
lpcbBuffer,
"<SSizeRestriction>");
break;
case RES_EXIST:
hr = HrPrintToString(lppszString,
lpcbString,
lpcbBuffer,
"<SExistRestriction>");
break;
case RES_SUBRESTRICTION:
hr = HrPrintToString(lppszString,
lpcbString,
lpcbBuffer,
"<SSubRestriction>");
break;
case RES_COMMENT:
hr = HrPrintToString(lppszString,
lpcbString,
lpcbBuffer,
"<SCommentRestriction>");
break;
case RES_UNINITIALIZED:
hr = HrPrintToString(lppszString,
lpcbString,
lpcbBuffer,
"<Uninitialized SRestriction>");
break;
default:
hr = HrPrintToString(lppszString,
lpcbString,
lpcbBuffer,
"<Invalid SRestriction>");
break;
}
if (FAILED(hr))
goto cleanup;
}
cleanup:
RETURN(hr);
}
// $-HrPropertyRestrictionToString---------------------------------------------
//
// DESCRIPTION:Get a string representation of an SPropertyRestriction.
//
// INPUT:
//
//[lpRes]-- Ptr to property restriction to be represented as a
// string.
//
// INPUT/OUTPUT:
//
//[lppszString]-- Output string ptr ptr. If *lppszString == NULL, then
// a string will be allocated by this routine.
//[lpcbString]-- Ptr to count of bytes in input string on input (including
// terminating '\0'); count of bytes in string after
// appending formatted string on output.
//[lpcbBuffer]-- Ptr to count of bytes in input string buffer on input;
// count of bytes in string buffer after appending formatted
// string on output (buffer size may increase if allocation
// was necessary).
//
// RETURNS: NOERRORif successful;
// E_INVALIDARGif bad input;
// E_FAILotherwise.
//-----------------------------------------------------------------------------
HRESULT
HrPropertyRestrictionToString(// RETURNS: HRESULT
INLPSRestrictionlpRes,// restriction ptr
IN OUTLPSTR FAR *lppszString,// output string ptr ptr
IN OUTLPULONGlpcbString,// ptr to count of bytes in string
IN OUTLPULONGlpcbBuffer// ptr to count of bytes in buffer
)
{
HRESULThr = NOERROR;
LPSTRlpszPropName =NULL;
LPSTRlpszRelop = NULL;
DEBUGPRIVATE("HrPropertyRestrictionToString()\n");
switch (lpRes->res.resProperty.relop)
{
case RELOP_LT:
lpszRelop = " < ";
break;
case RELOP_LE:
lpszRelop = " <= ";
break;
case RELOP_GT:
lpszRelop = " > ";
break;
case RELOP_GE:
lpszRelop = " >= ";
break;
case RELOP_EQ:
lpszRelop = " = ";
break;
case RELOP_NE:
lpszRelop = " # ";
break;
case RELOP_RE:
lpszRelop = " <RELOP_RE Operator> ";
break;
default:
lpszRelop = " <Invalid Operator> ";
break;
}
hr = HrGetPropTagName(lpRes->res.resProperty.ulPropTag,
&lpszPropName);
if (FAILED(hr))
goto cleanup;
hr = HrPrintToString(lppszString,
lpcbString,
lpcbBuffer,
"%s%s",
lpszPropName,
lpszRelop);
if (FAILED(hr))
goto cleanup;
hr = HrPropValueToString(lpRes->res.resProperty.lpProp,
lppszString,
lpcbString,
lpcbBuffer);
if (FAILED(hr))
goto cleanup;
cleanup:
MAPIFREEBUFFER(lpszPropName);
RETURN(hr);
}
// $--HrPropValueToString------------------------------------------------------
//
// DESCRIPTION:Get a string representation of an SPropValue..
//
// INPUT:
//
//[lpProp]-- Ptr to property value to be represented as a string.
//
// INPUT/OUTPUT:
//
//[lppszString]-- Output string ptr ptr. If *lppszString == NULL, then
// a string will be allocated by this routine.
//[lpcbString]-- Ptr to count of bytes in input string on input (including
// terminating '\0'); count of bytes in string after
// appending formatted string on output.
//[lpcbBuffer]-- Ptr to count of bytes in input string buffer on input;
// count of bytes in string buffer after appending formatted
// string on output (buffer size may increase if allocation
// was necessary).
//
// RETURNS: NOERRORif successful;
// E_INVALIDARGif bad input;
// E_FAILotherwise.
//-----------------------------------------------------------------------------
HRESULT
HrPropValueToString( // RETURNS: VOID
INLPSPropValuelpProp,// property value ptr
IN OUTLPSTR FAR *lppszString,// output string ptr ptr
IN OUTLPULONGlpcbString,// ptr to count of bytes in string
IN OUTLPULONGlpcbBuffer// ptr to count of bytes in buffer
)
{
HRESULThr =NOERROR;
DEBUGPRIVATE("HrPropValueToString()\n");
if (lpProp == NULL)
{
hr = HrPrintToString(lppszString,
lpcbString,
lpcbBuffer,
"<Undefined SPropValue>");
if (FAILED(hr))
goto cleanup;
}
else
{
ULONGulPropTag =0;
ulPropTag = lpProp->ulPropTag;
switch (PROP_TYPE(ulPropTag))
{
case PT_I2:
{
hr = HrPrintToString(lppszString,
lpcbString,
lpcbBuffer,
"%#hx",
lpProp->Value.i);
break;
}
case PT_LONG:
{
hr = HrPrintToString(lppszString,
lpcbString,
lpcbBuffer,
"%#x",
lpProp->Value.ul);
break;
}
case PT_R4:
{
hr = HrPrintToString(lppszString,
lpcbString,
lpcbBuffer,
"<PT_R4 value dump not supported>");
break;
}
case PT_DOUBLE:
{
hr = HrPrintToString(lppszString,
lpcbString,
lpcbBuffer,
"<PT_DOUBLE value dump not supported>");
break;
}
case PT_BOOLEAN:
{
hr = HrPrintToString(lppszString,
lpcbString,
lpcbBuffer,
lpProp->Value.b ? "TRUE" : "FALSE");
break;
}
case PT_CURRENCY:
{
hr = HrPrintToString(lppszString,
lpcbString,
lpcbBuffer,
"<PT_CURRENCY value dump not supported>");
break;
}
case PT_APPTIME:
{
hr = HrPrintToString(lppszString,
lpcbString,
lpcbBuffer,
"<PT_APPTIME value dump not supported>");
break;
}
case PT_SYSTIME:
{
SYSTEMTIMEst ={0};
FILETIMEftLocal ={0};
// Convert UTC FILETIME to Local FILETIME.
if (!FileTimeToLocalFileTime(&lpProp->Value.ft, &ftLocal))
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}
// Convert Local FILETIME to SYSTEMTIME.
if (!FileTimeToSystemTime(&ftLocal, &st))
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}
hr = HrPrintToString(lppszString,
lpcbString,
lpcbBuffer,
"%02hu:%02hu:%02hu %04hu-%02hu-%02hu",
st.wHour,
st.wMinute,
st.wSecond,
st.wYear,
st.wMonth,
st.wDay);
break;
}
case PT_STRING8:
{
hr = HrPrintToString(lppszString,
lpcbString,
lpcbBuffer,
"\"%s\"",
lpProp->Value.lpszA);
break;
}
case PT_BINARY:
{
hr = HrPrintToString(lppszString,
lpcbString,
lpcbBuffer,
"<PT_BINARY value dump not supported>");
break;
}
case PT_UNICODE:
{
hr = HrPrintToString(lppszString,
lpcbString,
lpcbBuffer,
"\"%S\"",
lpProp->Value.lpszW);
break;
}
case PT_CLSID:
{
hr = HrPrintToString(lppszString,
lpcbString,
lpcbBuffer,
"<PT_CLSID value dump not supported>");
break;
}
case PT_I8:
{
hr = HrPrintToString(lppszString,
lpcbString,
lpcbBuffer,
"<PT_I8 value dump not supported>");
break;
}
case PT_MV_I2:
{
hr = HrPrintToString(lppszString,
lpcbString,
lpcbBuffer,
"<PT_MV_I2 value dump not supported>");
break;
}
case PT_MV_LONG:
{
hr = HrPrintToString(lppszString,
lpcbString,
lpcbBuffer,
"<PT_MV_LONG value dump not supported>");
break;
}
case PT_MV_R4:
{
hr = HrPrintToString(lppszString,
lpcbString,
lpcbBuffer,
"<PT_MV_R4 value dump not supported>");
break;
}
case PT_MV_DOUBLE:
{
hr = HrPrintToString(lppszString,
lpcbString,
lpcbBuffer,
"<PT_MV_DOUBLE value dump not supported>");
break;
}
case PT_MV_CURRENCY:
{
hr = HrPrintToString(lppszString,
lpcbString,
lpcbBuffer,
"<PT_MV_CURRENCY value dump not supported>");
break;
}
case PT_MV_APPTIME:
{
hr = HrPrintToString(lppszString,
lpcbString,
lpcbBuffer,
"<PT_MV_APPTIME value dump not supported>");
break;
}
case PT_MV_SYSTIME:
{
hr = HrPrintToString(lppszString,
lpcbString,
lpcbBuffer,
"<PT_MV_SYSTIME value dump not supported>");
break;
}
case PT_MV_BINARY:
{
hr = HrPrintToString(lppszString,
lpcbString,
lpcbBuffer,
"<PT_MV_BINARY value dump not supported>");
break;
}
case PT_MV_STRING8:
{
hr = HrPrintToString(lppszString,
lpcbString,
lpcbBuffer,
"<PT_MV_STRING8 value dump not supported>");
break;
}
case PT_MV_UNICODE:
{
hr = HrPrintToString(lppszString,
lpcbString,
lpcbBuffer,
"<PT_MV_UNICODE value dump not supported>");
break;
}
case PT_MV_CLSID:
{
hr = HrPrintToString(lppszString,
lpcbString,
lpcbBuffer,
"<PT_MV_CLSID value dump not supported>");
break;
}
case PT_MV_I8:
{
hr = HrPrintToString(lppszString,
lpcbString,
lpcbBuffer,
"<PT_MV_I8 value dump not supported>");
break;
}
case PT_ERROR:
{
hr = HrPrintToString(lppszString,
lpcbString,
lpcbBuffer,
"%x",
lpProp->Value.err);
break;
}
case PT_NULL:
{
hr = HrPrintToString(lppszString,
lpcbString,
lpcbBuffer,
"<PT_NULL value dump not supported>");
break;
}
case PT_OBJECT:
{
hr = HrPrintToString(lppszString,
lpcbString,
lpcbBuffer,
"<PT_OBJECT value dump not supported>");
break;
}
default:
{
hr = HrPrintToString(lppszString,
lpcbString,
lpcbBuffer,
"<Undefined property type value!>");
}
}
if (FAILED(hr))
goto cleanup;
}
cleanup:
RETURN(hr);
}
// $--lpszSkipNonWhiteSpace----------------------------------------------------
//
// DESCRIPTION: Find first whitespace CHAR or '\0' in *pch.
//
// INPUT:
//
//[pch]-- Ptr to string to be examined for whitespace CHAR.
//
// RETURNS: Ptr to first whitespace CHAR or '\0' in *pch.
//
//-----------------------------------------------------------------------------
inline
CHAR *
lpszSkipNonWhiteSpace(// RETURNS CHAR *
INCHAR *pch // input string
)
{
while (!isspace(*pch) && *pch != '\0')
pch++;
return pch;
}
// $--lpszSkipWhiteSpace-------------------------------------------------------
//
// DESCRIPTION: Find first nonwhitespace CHAR in *pch.
//
// INPUT:
//
//[pch]-- Ptr to string to be examined for nonwhitespace CHAR.
//
// RETURNS: Ptr to first nonwhitespace CHAR in *pch.
//
//-----------------------------------------------------------------------------
inline
CHAR *
lpszSkipWhiteSpace(// RETURNS CHAR *
INCHAR *pch // input string
)
{
while (isspace(*pch))
pch++;
return pch;
}
// NOTE NOTE NOTE - Code below here does not yet conform to coding standards
//because we do not yet know if it will be left in the
//product. It will be appropriately munged when and if
//necessary.
HRESULT
HrCountProps(
INint cprop,
INLPSPropValuergprop,
OUTULONG FAR *pcb
)
{
LPSPropValuepprop;
ULONGcb = 0;
ULONGcbMV;
intiValue;
if ((rgprop && !cprop) || IsBadReadPtr(rgprop, cprop*sizeof(SPropValue)))
return E_INVALIDARG;
for (pprop = rgprop; cprop--; ++pprop)
{
ULONGulType = PROP_TYPE(pprop->ulPropTag);
//Check for valid PROP_TYPE and count memory consumed.
cb += sizeof(SPropValue);
switch (PROP_TYPE(pprop->ulPropTag))
{
case PT_UNSPECIFIED:
case PT_OBJECT:
default:
{
return E_INVALIDARG;
}
case PT_I2:
case PT_LONG:
case PT_R4:
case PT_APPTIME:
case PT_DOUBLE:
case PT_BOOLEAN:
case PT_CURRENCY:
case PT_SYSTIME:
case PT_CLSID:
case PT_I8:
case PT_ERROR:
case PT_NULL:
{
break;
}
case PT_BINARY:
{
cb += pprop->Value.bin.cb;
if (pprop->Value.bin.cb&&
IsBadReadPtr(pprop->Value.bin.lpb,
(UINT)(pprop->Value.bin.cb)))
{
goto badProp;
}
break;
}
case PT_STRING8:
{
if (IsBadStringPtrA(pprop->Value.lpszA, INFINITE))
goto badProp;
cb += (lstrlenA( pprop->Value.lpszA ) + 1) * sizeof(CHAR);
break;
}
case PT_UNICODE:
{
if (IsBadStringPtrW(pprop->Value.lpszW, INFINITE))
goto badProp;
cb += (lstrlenW(pprop->Value.lpszW) + 1) * sizeof(WCHAR);
break;
}
//Note!MVxxx.cValues may NOT be zero (DCR 2789).
case PT_MV_I2:
{
if (!(cbMV = pprop->Value.MVi.cValues * sizeof(short int)) ||
IsBadReadPtr(pprop->Value.MVi.lpi, (UINT)cbMV))
{
goto badProp;
}
cb += cbMV;
break;
}
case PT_MV_LONG:
{
if (!(cbMV = pprop->Value.MVl.cValues * sizeof(LONG)) ||
IsBadReadPtr(pprop->Value.MVl.lpl, (UINT)cbMV))
{
goto badProp;
}
cb += cbMV;
break;
}
case PT_MV_R4:
{
if (!(cbMV = pprop->Value.MVflt.cValues * sizeof(float)) ||
IsBadReadPtr(pprop->Value.MVflt.lpflt, (UINT)cbMV))
{
goto badProp;
}
cb += cbMV;
break;
}
case PT_MV_APPTIME:
{
if (!(cbMV = pprop->Value.MVat.cValues * sizeof(double)) ||
IsBadReadPtr(pprop->Value.MVat.lpat, (UINT)cbMV))
{
goto badProp;
}
cb += cbMV;
break;
}
case PT_MV_DOUBLE:
{
if (!(cbMV = pprop->Value.MVdbl.cValues * sizeof(double)) ||
IsBadReadPtr(pprop->Value.MVdbl.lpdbl, (UINT)cbMV))
{
goto badProp;
}
cb += cbMV;
break;
}
case PT_MV_CURRENCY:
{
if (!(cbMV = pprop->Value.MVcur.cValues * sizeof(CURRENCY)) ||
IsBadReadPtr(pprop->Value.MVcur.lpcur, (UINT)cbMV))
{
goto badProp;
}
cb += cbMV;
break;
}
case PT_MV_SYSTIME:
{
if (!(cbMV = pprop->Value.MVft.cValues * sizeof(FILETIME)) ||
IsBadReadPtr(pprop->Value.MVft.lpft, (UINT)cbMV))
{
goto badProp;
}
cb += cbMV;
break;
}
case PT_MV_CLSID:
{
if (!(cbMV = pprop->Value.MVguid.cValues * sizeof(GUID)) ||
IsBadReadPtr(pprop->Value.MVguid.lpguid, (UINT)cbMV))
{
goto badProp;
}
cb += cbMV;
break;
}
case PT_MV_I8:
{
if (!(cbMV =
pprop->Value.MVli.cValues * sizeof(LARGE_INTEGER)) ||
IsBadReadPtr(pprop->Value.MVli.lpli, (UINT)cbMV))
{
goto badProp;
}
cb += cbMV;
break;
}
case PT_MV_BINARY:
{
if (!(cbMV = pprop->Value.MVbin.cValues * sizeof(SBinary)) ||
IsBadReadPtr(pprop->Value.MVbin.lpbin, (UINT)cbMV))
{
goto badProp;
}
for (iValue = 0;
(ULONG)iValue < pprop->Value.MVbin.cValues;
iValue++)
{
if (IsBadReadPtr(pprop->Value.MVbin.lpbin[iValue].lpb,
(UINT)pprop->Value.MVbin.lpbin[iValue].cb))
{
goto badProp;
}
cb += pprop->Value.MVbin.lpbin[iValue].cb;
}
cb += cbMV;
break;
}
case PT_MV_STRING8:
{
if (!(cbMV = pprop->Value.MVszA.cValues * sizeof(LPVOID)) ||
IsBadReadPtr(pprop->Value.MVszA.lppszA, (UINT)cbMV))
{
goto badProp;
}
for (iValue = 0;
(ULONG)iValue < pprop->Value.MVszA.cValues;
iValue++)
{
if (IsBadStringPtrA(pprop->Value.MVszA.lppszA[iValue],
INFINITE))
{
goto badProp;
}
cb += lstrlenA(pprop->Value.MVszA.lppszA[iValue]) + 1;
}
cb += cbMV;
break;
}
case PT_MV_UNICODE:
{
if (!(cbMV = pprop->Value.MVszW.cValues * sizeof(LPVOID)) ||
IsBadReadPtr(pprop->Value.MVszW.lppszW, (UINT)cbMV))
{
goto badProp;
}
for (iValue = 0;
(ULONG)iValue < pprop->Value.MVszW.cValues;
iValue++)
{
if (IsBadStringPtrW(pprop->Value.MVszW.lppszW[iValue],
INFINITE))
{
goto badProp;
}
cb +=(lstrlenW(pprop->Value.MVszW.lppszW[iValue]) + 1) *
sizeof(WCHAR);
}
cb += cbMV;
break;
}
}
}
if (pcb)
*pcb = cb;
return NOERROR;
badProp:
return E_INVALIDARG;
}
HRESULT
HrCopyProps(
INintcprop,
INLPSPropValuergprop,
OUTLPVOIDpvDst,
OUTULONG FAR * pcb
)
{
LPSPropValuepprop;
LPSPropValueppropDst;
ULONGcb;
LPBYTEpb;
UINTcbT;
intiValue;
cb = cprop * sizeof(SPropValue);
memcpy(pvDst, rgprop, (UINT)cb);
pb = (LPBYTE)pvDst + cb;
for (pprop = rgprop, ppropDst = (LPSPropValue)pvDst;
cprop--;
++pprop, ++ppropDst)
{
//Tricky: common code after the switch increments pb and cb
//by the amount copied. If no increment is necessary, the case
//uses 'continue' rather than 'break' to exit the switch, thus
//skipping the increment -- AND any other code which may be
//added after the switch.
switch (PROP_TYPE(pprop->ulPropTag))
{
default:
return E_INVALIDARG;
case PT_I2:
case PT_LONG:
case PT_R4:
case PT_APPTIME:
case PT_DOUBLE:
case PT_BOOLEAN:
case PT_CURRENCY:
case PT_SYSTIME:
case PT_CLSID:
case PT_I8:
case PT_ERROR:
case PT_NULL:
continue;//nothing to add
case PT_BINARY:
ppropDst->Value.bin.lpb = pb;
cbT = (UINT)pprop->Value.bin.cb;
memcpy(pb, pprop->Value.bin.lpb, cbT);
break;
case PT_STRING8:
ppropDst->Value.lpszA = (LPSTR)pb;
cbT = lstrlenA( pprop->Value.lpszA ) + 1;
memcpy(pb, pprop->Value.lpszA, cbT);
break;
case PT_UNICODE:
ppropDst->Value.lpszW = (LPWSTR)pb;
cbT = (lstrlenW( pprop->Value.lpszW ) + 1) * sizeof(WCHAR);
memcpy(pb, pprop->Value.lpszW, cbT);
break;
case PT_MV_I2:
ppropDst->Value.MVi.lpi = (short int FAR *)pb;
cbT = (UINT)pprop->Value.MVi.cValues * sizeof(short int);
memcpy(pb, pprop->Value.MVi.lpi, cbT);
break;
case PT_MV_LONG:
ppropDst->Value.MVl.lpl = (LONG FAR *)pb;
cbT = (UINT)pprop->Value.MVl.cValues * sizeof(LONG);
memcpy(pb, pprop->Value.MVl.lpl, cbT);
break;
case PT_MV_R4:
ppropDst->Value.MVflt.lpflt = (float FAR *)pb;
cbT = (UINT)pprop->Value.MVflt.cValues * sizeof(float);
memcpy(pb, pprop->Value.MVflt.lpflt, cbT);
break;
case PT_MV_APPTIME:
ppropDst->Value.MVat.lpat = (double FAR *)pb;
cbT = (UINT)pprop->Value.MVat.cValues * sizeof(double);
memcpy(pb, pprop->Value.MVat.lpat, cbT);
break;
case PT_MV_DOUBLE:
ppropDst->Value.MVdbl.lpdbl = (double FAR *)pb;
cbT = (UINT)pprop->Value.MVdbl.cValues * sizeof(double);
memcpy(pb, pprop->Value.MVdbl.lpdbl, cbT);
break;
case PT_MV_CURRENCY:
ppropDst->Value.MVcur.lpcur = (CURRENCY FAR *)pb;
cbT = (UINT)pprop->Value.MVcur.cValues * sizeof(CURRENCY);
memcpy(pb, pprop->Value.MVcur.lpcur, cbT);
break;
case PT_MV_SYSTIME:
ppropDst->Value.MVft.lpft = (FILETIME FAR *)pb;
cbT = (UINT)pprop->Value.MVft.cValues * sizeof(FILETIME);
memcpy(pb, pprop->Value.MVft.lpft, cbT);
break;
case PT_MV_CLSID:
ppropDst->Value.MVguid.lpguid = (GUID FAR *)pb;
cbT = (UINT)pprop->Value.MVguid.cValues * sizeof(GUID);
memcpy(pb, pprop->Value.MVguid.lpguid, cbT);
break;
case PT_MV_I8:
ppropDst->Value.MVli.lpli = (LARGE_INTEGER FAR *)pb;
cbT = (UINT)pprop->Value.MVli.cValues * sizeof(LARGE_INTEGER);
memcpy(pb, pprop->Value.MVli.lpli, cbT);
break;
case PT_MV_BINARY:
ppropDst->Value.MVbin.lpbin = (SBinary *) pb;
pb += pprop->Value.MVbin.cValues * sizeof(SBinary);
for (iValue = 0;
(ULONG)iValue < pprop->Value.MVbin.cValues;
iValue++)
{
ppropDst->Value.MVbin.lpbin[iValue].lpb = pb;
cbT = (UINT)pprop->Value.MVbin.lpbin[iValue].cb;
memcpy(pb, pprop->Value.MVbin.lpbin[iValue].lpb, cbT);
cb += cbT;
pb += cbT;
}
continue;//already updated, don't do it again
case PT_MV_STRING8:
ppropDst->Value.MVszA.lppszA = (LPSTR *) pb;
pb += pprop->Value.MVszA.cValues * sizeof(LPSTR);
for (iValue = 0;
(ULONG)iValue < pprop->Value.MVszA.cValues;
iValue++)
{
ppropDst->Value.MVszA.lppszA[iValue] = (LPSTR)pb;
cbT = lstrlenA(pprop->Value.MVszA.lppszA[iValue]) + 1;
memcpy(pb, pprop->Value.MVszA.lppszA[iValue], cbT);
pb += cbT;
cb += cbT;
}
continue;//already updated, don't do it again
case PT_MV_UNICODE:
ppropDst->Value.MVszW.lppszW = (LPWSTR *) pb;
pb += pprop->Value.MVszW.cValues * sizeof(LPWSTR);
for (iValue = 0;
(ULONG)iValue < pprop->Value.MVszW.cValues;
iValue++)
{
ppropDst->Value.MVszW.lppszW[iValue] = (LPWSTR)pb;
cbT = (lstrlenW(pprop->Value.MVszW.lppszW[iValue]) + 1)
* sizeof(WCHAR);
memcpy(pb, pprop->Value.MVszW.lppszW[iValue], cbT);
pb += cbT;
cb += cbT;
}
continue;//already updated, don't do it again
}
//Advance ptr and total count by the amount copied
pb += cbT;
cb += cbT;
}
if (pcb)
*pcb = cb;
return NOERROR;
}
/*
*Wrapper function to just duplicate a property value array
*into a single block of MAPI memory.
*/
HRESULT
HrDupPropset(
INint cprop,
INLPSPropValuergprop,
INLPVOIDlpObject,
OUTLPSPropValue FAR *prgprop
)
{
ULONGcb;
HRESULThr;
//Find out how much memory we need
if (hr = HrCountProps(cprop, rgprop, &cb))
goto ret;
//Obtain memory
if (lpObject != NULL)
hr = MAPIAllocateMore(cb, lpObject, (LPVOID FAR *)prgprop);
else
hr = MAPIAllocateBuffer(cb, (LPVOID FAR *)prgprop);
if (hr)
goto ret;
//Copy the properties
if (hr = HrCopyProps(cprop, rgprop, *prgprop, &cb))
goto ret;
ret:
return hr;
}