Windows2003-3790/inetcore/outlookexpress/wabw/wabapi/distlist.c
2020-09-30 16:53:55 +02:00

1472 lines
46 KiB
C

/*
* DistList.C - Implement the IDistList object
*
*
*/
#include "_apipch.h"
STDMETHODIMP DISTLIST_OpenProperty(LPCONTAINER lpCONTAINER,
ULONG ulPropTag,
LPCIID lpiid,
ULONG ulInterfaceOptions,
ULONG ulFlags,
LPUNKNOWN * lppUnk);
STDMETHODIMP DISTLIST_GetContentsTable(LPCONTAINER lpCONTAINER,
ULONG ulFlags,
LPMAPITABLE * lppTable);
STDMETHODIMP DISTLIST_GetHierarchyTable(LPCONTAINER lpCONTAINER,
ULONG ulFlags,
LPMAPITABLE * lppTable);
STDMETHODIMP DISTLIST_OpenEntry(LPCONTAINER lpCONTAINER,
ULONG cbEntryID,
LPENTRYID lpEntryID,
LPCIID lpInterface,
ULONG ulFlags,
ULONG * lpulObjType,
LPUNKNOWN * lppUnk);
STDMETHODIMP DISTLIST_SetSearchCriteria(LPCONTAINER lpCONTAINER,
LPSRestriction lpRestriction,
LPENTRYLIST lpContainerList,
ULONG ulSearchFlags);
STDMETHODIMP DISTLIST_GetSearchCriteria(LPCONTAINER lpCONTAINER,
ULONG ulFlags,
LPSRestriction FAR * lppRestriction,
LPENTRYLIST FAR * lppContainerList,
ULONG FAR * lpulSearchState);
STDMETHODIMP DISTLIST_CreateEntry(LPCONTAINER lpCONTAINER,
ULONG cbEntryID,
LPENTRYID lpEntryID,
ULONG ulCreateFlags,
LPMAPIPROP FAR * lppMAPIPropEntry);
STDMETHODIMP DISTLIST_CopyEntries(LPCONTAINER lpCONTAINER,
LPENTRYLIST lpEntries,
ULONG ulUIParam,
LPMAPIPROGRESS lpProgress,
ULONG ulFlags);
STDMETHODIMP DISTLIST_DeleteEntries(LPCONTAINER lpCONTAINER,
LPENTRYLIST lpEntries,
ULONG ulFlags);
STDMETHODIMP DISTLIST_ResolveNames(LPCONTAINER lpCONTAINER,
LPSPropTagArray lptagaColSet,
ULONG ulFlags,
LPADRLIST lpAdrList,
LPFlagList lpFlagList);
HRESULT HrNewDLENTRY(LPCONTAINER lpCONTAINER,
LPMAPIPROP lpOldEntry, // Old entry to copy from
ULONG ulCreateFlags,
LPVOID *lppDLENTRY);
/*
* Root jump table is defined here...
*/
CONTAINER_Vtbl vtblDISTLIST =
{
VTABLE_FILL
(CONTAINER_QueryInterface_METHOD *) IAB_QueryInterface,
(CONTAINER_AddRef_METHOD *) WRAP_AddRef,
(CONTAINER_Release_METHOD *) CONTAINER_Release,
(CONTAINER_GetLastError_METHOD *) IAB_GetLastError,
(CONTAINER_SaveChanges_METHOD *) MailUser_SaveChanges,
(CONTAINER_GetProps_METHOD *) WRAP_GetProps,
(CONTAINER_GetPropList_METHOD *) WRAP_GetPropList,
(CONTAINER_OpenProperty_METHOD *) DISTLIST_OpenProperty,
(CONTAINER_SetProps_METHOD *) WRAP_SetProps,
(CONTAINER_DeleteProps_METHOD *) WRAP_DeleteProps,
(CONTAINER_CopyTo_METHOD *) WRAP_CopyTo,
(CONTAINER_CopyProps_METHOD *) WRAP_CopyProps,
(CONTAINER_GetNamesFromIDs_METHOD *) MailUser_GetNamesFromIDs,
(CONTAINER_GetIDsFromNames_METHOD *) MailUser_GetIDsFromNames,
(CONTAINER_GetContentsTable_METHOD *) DISTLIST_GetContentsTable,
(CONTAINER_GetHierarchyTable_METHOD *) DISTLIST_GetHierarchyTable,
(CONTAINER_OpenEntry_METHOD *) DISTLIST_OpenEntry,
(CONTAINER_SetSearchCriteria_METHOD *) DISTLIST_SetSearchCriteria,
(CONTAINER_GetSearchCriteria_METHOD *) DISTLIST_GetSearchCriteria,
(CONTAINER_CreateEntry_METHOD *) DISTLIST_CreateEntry,
(CONTAINER_CopyEntries_METHOD *) DISTLIST_CopyEntries,
(CONTAINER_DeleteEntries_METHOD *) DISTLIST_DeleteEntries,
(CONTAINER_ResolveNames_METHOD *) DISTLIST_ResolveNames
};
enum {
iwdePR_WAB_DL_ENTRIES, // Very important - keep DL_ENTRIES and DL_ONEOFFS togethor .. we use them as contiguous loop indexes somewhere
iwdePR_WAB_DL_ONEOFFS,
iwdePR_ENTRYID,
iwdeMax
};
SizedSPropTagArray(iwdeMax, tagaWabDLEntries) =
{
iwdeMax,
{
PR_WAB_DL_ENTRIES,
PR_NULL, // should be PR_WAB_DL_ONEOFFS
PR_ENTRYID,
}
};
/***************************************************
*
* The actual ABContainer methods
*/
/* ---------
* IMAPIProp
*/
STDMETHODIMP
DISTLIST_OpenProperty(LPCONTAINER lpCONTAINER,
ULONG ulPropTag,
LPCIID lpiid,
ULONG ulInterfaceOptions,
ULONG ulFlags,
LPUNKNOWN * lppUnk)
{
LPIAB lpIAB;
LPSTR lpszMessage = NULL;
ULONG ulLowLevelError = 0;
HRESULT hr;
#ifdef PARAMETER_VALIDATION
// Validate parameters
// Check to see if it has a jump table
if (IsBadReadPtr(lpCONTAINER, sizeof(LPVOID))) {
// No jump table found
return(ResultFromScode(MAPI_E_INVALID_PARAMETER));
}
if ((ulInterfaceOptions & ~(MAPI_UNICODE)) || (ulFlags & ~(MAPI_DEFERRED_ERRORS))) {
return(ResultFromScode(MAPI_E_UNKNOWN_FLAGS));
}
if (FBadOpenProperty(lpRoot, ulPropTag, lpiid, ulInterfaceOptions, ulFlags, lppUnk)) {
return(ResultFromScode(MAPI_E_INVALID_PARAMETER));
}
#endif // PARAMETER_VALIDATION
EnterCriticalSection(&lpCONTAINER->cs);
lpIAB = lpCONTAINER->lpIAB;
//
// Check to see if I need a display table
//
if (ulPropTag == PR_CREATE_TEMPLATES) {
Assert(FALSE); // Not implemented
hr = ResultFromScode(MAPI_E_INTERFACE_NOT_SUPPORTED);
goto err;
} else if (ulPropTag == PR_CONTAINER_CONTENTS) {
//
// Check to see if they're expecting a table interface
//
if (memcmp(lpiid, &IID_IMAPITable, sizeof(IID))) {
hr = ResultFromScode(MAPI_E_INTERFACE_NOT_SUPPORTED);
goto err;
}
hr = DISTLIST_GetContentsTable(lpCONTAINER, ulInterfaceOptions, (LPMAPITABLE *)lppUnk);
goto err;
} else if (ulPropTag == PR_CONTAINER_HIERARCHY) {
//
// Check to see if they're expecting a table interface
//
if (memcmp(lpiid, &IID_IMAPITable, sizeof(IID))) {
hr = ResultFromScode(MAPI_E_INTERFACE_NOT_SUPPORTED);
goto err;
}
hr = DISTLIST_GetHierarchyTable(lpCONTAINER, ulInterfaceOptions, (LPMAPITABLE *) lppUnk);
goto err;
}
//
// Don't recognize the property they want opened.
//
hr = ResultFromScode(MAPI_E_NO_SUPPORT);
err:
LeaveCriticalSection(&lpCONTAINER->cs);
DebugTraceResult(DISTLIST_OpenProperty, hr);
return(hr);
}
/*************************************************************************
*
*
- DISTLIST_GetContentsTable
-
*
*
* ulFlags - 0 or MAPI_UNICODE
*
*/
STDMETHODIMP
DISTLIST_GetContentsTable(LPCONTAINER lpCONTAINER,
ULONG ulFlags,
LPMAPITABLE * lppTable)
{
LPTABLEDATA lpTableData = NULL;
HRESULT hResult = hrSuccess;
SCODE sc;
LPSRowSet lpSRowSet = NULL;
LPSPropValue lpSPropValue = NULL;
LPTSTR lpTemp = NULL;
ULONG ulCount = 0;
ULONG i,j;
ULONG ulcProps;
SBinaryArray MVbin;
LPSPropValue lpspv = NULL;
ULONG cbEID, cbNewKey;
LPBYTE lpbNewKey;
LPSPropTagArray lpTableColumnsTemplate;
#ifdef PARAMETER_VALIDATION
// Check to see if it has a jump table
if (IsBadReadPtr(lpCONTAINER, sizeof(LPVOID))) {
// No jump table found
return(ResultFromScode(MAPI_E_INVALID_PARAMETER));
}
if (ulFlags & ~(MAPI_DEFERRED_ERRORS|MAPI_UNICODE)) {
DebugTraceArg(DISTLIST_GetContentsTable, TEXT("Unknown flags"));
// return(ResultFromScode(MAPI_E_UNKNOWN_FLAGS));
}
if (IsBadWritePtr(lppTable, sizeof(LPMAPITABLE))) {
DebugTraceArg(DISTLIST_GetContentsTable, TEXT("Invalid Table parameter"));
return(ResultFromScode(MAPI_E_INVALID_PARAMETER));
}
#endif // PARAMETER_VALIDATION
// [PaulHi] 2/25/99 Raid 73170 Honor the MAPI_UNICODE bit in
// ulFlags. If this bit isn't set then use the ANSI version of
// the ITableColumns so ANSI property strings are returned to
// the user.
if (ulFlags & MAPI_UNICODE)
lpTableColumnsTemplate = (LPSPropTagArray)&ITableColumns;
else
lpTableColumnsTemplate = (LPSPropTagArray)&ITableColumns_A;
sc = CreateTableData(
NULL, // LPIID
(ALLOCATEBUFFER FAR *) MAPIAllocateBuffer,
(ALLOCATEMORE FAR *) MAPIAllocateMore,
MAPIFreeBuffer,
NULL, // lpvReserved
TBLTYPE_DYNAMIC, // ulTableType
PR_RECORD_KEY, // ulPropTagIndexCol
lpTableColumnsTemplate, // LPSPropTagArray lpptaCols
NULL, // lpvDataSource
0, // cbDataSource
NULL, // pbinContEID
ulFlags, // ulFlags
&lpTableData); // lplptad
if ( FAILED(sc) )
{
DebugTrace(TEXT("DISTLIST_GetContentsTable:CreateTableData -> %x\n"), sc);
hResult = ResultFromScode(sc);
goto exit;
}
if (lpTableData)
{
tagaWabDLEntries.aulPropTag[iwdePR_WAB_DL_ONEOFFS] = PR_WAB_DL_ONEOFFS;
// Get the index to the distribution list from PR_WAB_DL_ENTRIES
if (HR_FAILED(hResult = lpCONTAINER->lpPropData->lpVtbl->GetProps(lpCONTAINER->lpPropData,
(LPSPropTagArray)&tagaWabDLEntries,
MAPI_UNICODE, &ulcProps, &lpspv)))
{
DebugTraceResult( TEXT("DISTLIST_GetContentsTable:GetProps"), hResult);
goto exit;
}
if (lpspv[iwdePR_WAB_DL_ENTRIES].ulPropTag == PR_WAB_DL_ENTRIES)
ulCount += lpspv[iwdePR_WAB_DL_ENTRIES].Value.MVbin.cValues;
if (lpspv[iwdePR_WAB_DL_ONEOFFS].ulPropTag == PR_WAB_DL_ONEOFFS)
ulCount += lpspv[iwdePR_WAB_DL_ONEOFFS].Value.MVbin.cValues;
if(ulCount)
{
// DL has contents.
// Now we need to move the information from the DL to
// the SRowSet. In the process, we need to create a few computed
// properties:
// PR_INSTANCE_KEY
// PR_RECORD_KEY
// Allocate the SRowSet
if (FAILED(sc = MAPIAllocateBuffer(sizeof(SRowSet) + ulCount * sizeof(SRow), &lpSRowSet)))
{
DebugTrace(TEXT("Allocation of SRowSet failed\n"));
hResult = ResultFromScode(sc);
goto exit;
}
lpSRowSet->cRows = 0;
// Look at each entry in the PR_WAB_DL_ENTRIES
for(j=iwdePR_WAB_DL_ENTRIES;j<=iwdePR_WAB_DL_ONEOFFS;j++)
{
if( (lpspv[j].ulPropTag != PR_WAB_DL_ENTRIES && lpspv[j].ulPropTag != PR_WAB_DL_ONEOFFS) ||
lpspv[j].Value.MVbin.cValues == 0)
continue;
MVbin = lpspv[j].Value.MVbin;
for (i = 0; i < MVbin.cValues; i++)
{
if (HR_FAILED(hResult = GetEntryProps((LPABCONT)lpCONTAINER, // container object
MVbin.lpbin[i].cb,
(LPENTRYID)MVbin.lpbin[i].lpb,
lpTableColumnsTemplate, // default columns
lpSRowSet, // allocate more on here
ulFlags, // 0 or MAPI_UNICODE
&ulcProps, // return count here
&lpSPropValue))) // return props here
{
DebugTraceResult( TEXT("DISTLIST_GetContentsTable:GetEntryProps\n"), hResult);
hResult = hrSuccess;
continue;
}
Assert(ulcProps == itcMax);
// Make certain we have proper indicies.
// PR_INSTANCE_KEY and PR_RECORD_KEY must be unique within the table!
// They can be the same, though.
// Append the index onto the entryid.
cbEID = lpSPropValue[itcPR_ENTRYID].Value.bin.cb;
cbNewKey = cbEID + sizeof(i);
if (FAILED(sc = MAPIAllocateMore(cbNewKey, lpSRowSet, &lpbNewKey))) {
hResult = ResultFromScode(sc);
DebugTrace(TEXT("GetContentsTable:MAPIAllocMore -> %x"), sc);
goto exit;
}
memcpy(lpbNewKey, lpSPropValue[itcPR_ENTRYID].Value.bin.lpb, cbEID);
memcpy(lpbNewKey + cbEID, &i, sizeof(i));
lpSPropValue[itcPR_INSTANCE_KEY].ulPropTag = PR_INSTANCE_KEY;
lpSPropValue[itcPR_INSTANCE_KEY].Value.bin.cb = cbNewKey;
lpSPropValue[itcPR_INSTANCE_KEY].Value.bin.lpb = lpbNewKey;
lpSPropValue[itcPR_RECORD_KEY].ulPropTag = PR_RECORD_KEY;
lpSPropValue[itcPR_RECORD_KEY].Value.bin.cb = cbNewKey;
lpSPropValue[itcPR_RECORD_KEY].Value.bin.lpb = lpbNewKey;
// Put it in the RowSet
lpSRowSet->aRow[lpSRowSet->cRows].cValues = ulcProps; // number of properties
lpSRowSet->aRow[lpSRowSet->cRows].lpProps = lpSPropValue; // LPSPropValue
lpSRowSet->cRows++;
} // i
}// j
hResult = lpTableData->lpVtbl->HrModifyRows(lpTableData, 0, lpSRowSet);
}
hResult = lpTableData->lpVtbl->HrGetView(lpTableData,
NULL, // LPSSortOrderSet lpsos,
ContentsViewGone, // CALLERRELEASE FAR * lpfReleaseCallback,
0, // ULONG ulReleaseData,
lppTable); // LPMAPITABLE FAR * lplpmt)
}
exit:
FreeBufferAndNull(&lpspv);
FreeBufferAndNull(&lpSRowSet);
// Cleanup table if failure
if (HR_FAILED(hResult)) {
UlRelease(lpTableData);
}
return(hResult);
}
/*************************************************************************
*
*
- DISTLIST_GetHierarchyTable
-
* Returns the merge of all the root hierarchy tables
*
*
*
*/
STDMETHODIMP
DISTLIST_GetHierarchyTable (LPCONTAINER lpCONTAINER,
ULONG ulFlags,
LPMAPITABLE * lppTable)
{
LPTSTR lpszMessage = NULL;
ULONG ulLowLevelError = 0;
HRESULT hr = hrSuccess;
#ifdef OLD_STUFF
#ifdef PARAMETER_VALIDATION
// Validate parameters
// Check to see if it has a jump table
if (IsBadReadPtr(lpCONTAINER, sizeof(LPVOID))) {
// No jump table found
return(ResultFromScode(MAPI_E_INVALID_PARAMETER));
}
// See if I can set the return variable
if (IsBadWritePtr (lppTable, sizeof (LPMAPITABLE))) {
hr = ResultFromScode(MAPI_E_INVALID_PARAMETER);
return(hr);
}
// Check flags:
// The only valid flags are CONVENIENT_DEPTH and MAPI_DEFERRED_ERRORS
if (ulFlags & ~(CONVENIENT_DEPTH | MAPI_DEFERRED_ERRORS | MAPI_UNICODE)) {
DebugTraceArg(DISTLIST_GetHierarchyTable , TEXT("Unknown flags used"));
// return ResultFromScode(MAPI_E_UNKNOWN_FLAGS);
}
#endif
EnterCriticalSection(&lpCONTAINER->cs);
if (lpCONTAINER->ulType != AB_DL) {
//
// Wrong version of this object. Pretend this object doesn't exist.
//
hr = ResultFromScode(MAPI_E_NO_SUPPORT);
SetMAPIError(lpCONTAINER, hr, IDS_NO_HIERARCHY_TABLE, NULL, 0,
0, 0, NULL);
goto out;
}
//
// Check to see if we already have a table
//
EnterCriticalSection(&lpCONTAINER->lpIAB->cs);
if (! lpCONTAINER->lpIAB->lpTableData) {
//
// Open all the root level containers and merge their
// root level hierarchies.
hr = MergeHierarchy(lpCONTAINER, lpCONTAINER->lpIAB, ulFlags);
if (hr != hrSuccess) {
LeaveCriticalSection(&lpCONTAINER->lpIAB->cs);
goto out;
}
}
LeaveCriticalSection(&lpCONTAINER->lpIAB->cs);
//
// Get a view from the TAD
//
if (HR_FAILED(hr = lpCONTAINER->lpIAB->lpTableData->lpVtbl->HrGetView(
lpCONTAINER->lpIAB->lpTableData,
(LPSSortOrderSet)&sosPR_ROWID,
NULL,
0,
lppTable))) {
DebugTrace(TEXT("IAB_GetHierarchyTable Get Tad View failed\n"));
goto out;
}
#ifdef DEBUG
if (hr == hrSuccess) {
MAPISetBufferName(*lppTable, TEXT("MergeHier VUE Object"));
}
#endif
// If the convenient depth flag was not specified we restrict on
// PR_DEPTH == 1.
if (! (ulFlags & CONVENIENT_DEPTH)) {
SRestriction restrictDepth;
SPropValue spvDepth;
spvDepth.ulPropTag = PR_DEPTH;
spvDepth.Value.l = 0;
restrictDepth.rt = RES_PROPERTY;
restrictDepth.res.resProperty.relop = RELOP_EQ;
restrictDepth.res.resProperty.ulPropTag = PR_DEPTH;
restrictDepth.res.resProperty.lpProp = &spvDepth;
if (HR_FAILED(hr = (*lppTable)->lpVtbl->Restrict(*lppTable, &restrictDepth, 0))) {
DebugTrace(TEXT("IAB_GetHierarchyTable restriction failed\n"));
goto out;
}
}
out:
LeaveCriticalSection(&lpCONTAINER->cs);
#endif // OLD_STUFF
hr = ResultFromScode(MAPI_E_NO_SUPPORT);
DebugTraceResult(DISTLIST_GetHierarchyTable, hr);
return(hr);
}
/*************************************************************************
*
*
- DISTLIST_OpenEntry
-
* Just call ABP_OpenEntry
*
*
*
*/
STDMETHODIMP
DISTLIST_OpenEntry(LPCONTAINER lpCONTAINER,
ULONG cbEntryID,
LPENTRYID lpEntryID,
LPCIID lpInterface,
ULONG ulFlags,
ULONG * lpulObjType,
LPUNKNOWN * lppUnk)
{
#ifdef PARAMETER_VALIDATION
// Validate the object.
if (BAD_STANDARD_OBJ(lpCONTAINER, DISTLIST_, OpenEntry, lpVtbl)) {
// jump table not large enough to support this method
return(ResultFromScode(MAPI_E_INVALID_PARAMETER));
}
// Check the entryid parameter. It needs to be big enough to hold an entryid.
// Null entryids are valid
/*
if (lpEntryID) {
if (cbEntryID < offsetof(ENTRYID, ab) || IsBadReadPtr((LPVOID)lpEntryID, (UINT)cbEntryID)) {
DebugTraceArg(DISTLIST_OpenEntry, TEXT("lpEntryID fails address check"));
return(ResultFromScode(MAPI_E_INVALID_ENTRYID));
}
//NFAssertSz(FValidEntryIDFlags(lpEntryID->abFlags),
// "Undefined bits set in EntryID flags\n");
}
*/
// Don't check the interface parameter unless the entry is something
// MAPI itself handles. The provider should return an error if this
// parameter is something that it doesn't understand.
// At this point, we just make sure it's readable.
if (lpInterface && IsBadReadPtr(lpInterface, sizeof(IID))) {
DebugTraceArg(DISTLIST_OpenEntry, TEXT("lpInterface fails address check"));
return(ResultFromScode(MAPI_E_INVALID_PARAMETER));
}
if (ulFlags & ~(MAPI_MODIFY | MAPI_DEFERRED_ERRORS | MAPI_BEST_ACCESS)) {
DebugTraceArg(DISTLIST_OpenEntry, TEXT("Unknown flags used"));
/// return(ResultFromScode(MAPI_E_UNKNOWN_FLAGS));
}
if (IsBadWritePtr((LPVOID)lpulObjType, sizeof(ULONG))) {
DebugTraceArg(DISTLIST_OpenEntry, TEXT("lpulObjType"));
return(ResultFromScode(MAPI_E_INVALID_PARAMETER));
}
if (IsBadWritePtr((LPVOID)lppUnk, sizeof(LPUNKNOWN))) {
DebugTraceArg(DISTLIST_OpenEntry, TEXT("lppUnk"));
return(ResultFromScode(MAPI_E_INVALID_PARAMETER));
}
#endif // PARAMETER_VALIDATION
// Should just call IAB::OpenEntry()...
return lpCONTAINER->lpIAB->lpVtbl->OpenEntry(lpCONTAINER->lpIAB,
cbEntryID,
lpEntryID,
lpInterface,
ulFlags,
lpulObjType,
lppUnk);
}
STDMETHODIMP
DISTLIST_SetSearchCriteria(LPCONTAINER lpCONTAINER,
LPSRestriction lpRestriction,
LPENTRYLIST lpContainerList,
ULONG ulSearchFlags)
{
return(ResultFromScode(MAPI_E_NO_SUPPORT));
}
STDMETHODIMP
DISTLIST_GetSearchCriteria(LPCONTAINER lpCONTAINER,
ULONG ulFlags,
LPSRestriction FAR * lppRestriction,
LPENTRYLIST FAR * lppContainerList,
ULONG FAR * lpulSearchState)
{
return(ResultFromScode(MAPI_E_NO_SUPPORT));
}
/***************************************************************************
Name : DISTLIST_CreateEntry
Purpose : Add an entry in this Distribution List container
Parameters: cbEntryID = size of lpEntryID
lpEntryID -> EntryID to add to distribution list.
ulCreateFlags = {CREATE_CHECK_DUP_STRICT,
CREATE_CHECK_DUP_LOOSE,
CREATE_REPLACE,
CREATE_MERGE}
lppEntry -> Returned lpMAPIPROP object containing
the properties of the added entry.
Returns : HRESULT
Comment : Caller MUST SaveChanges on the returned IMAPIPROP object before
this change will be saved.
Caller has no ability to SetProps the properties in the returned
object.
Caller must Release the returned object.
Unlike the PAB, the WAB stores Distribution Lists by reference.
The contents of the container are stored in PR_WAB_DL_ENTRIES.
***************************************************************************/
STDMETHODIMP
DISTLIST_CreateEntry(LPCONTAINER lpCONTAINER,
ULONG cbEntryID,
LPENTRYID lpEntryID,
ULONG ulCreateFlags,
LPMAPIPROP FAR * lppEntry)
{
HRESULT hResult;
LPMAILUSER lpOldEntry = NULL;
ULONG ulObjectType;
#ifdef PARAMETER_VALIDATION
// Validate the object.
if (BAD_STANDARD_OBJ(lpCONTAINER, DISTLIST_, CreateEntry, lpVtbl)) {
// jump table not large enough to support this method
DebugTraceArg(DISTLIST_CreateEntry, TEXT("Bad object/Vtbl"));
return(ResultFromScode(MAPI_E_INVALID_PARAMETER));
}
// Check the entryid parameter. It needs to be big enough to hold an entryid.
// Null entryid are bad
/*
if (lpEntryID) {
if (cbEntryID < offsetof(ENTRYID, ab) || IsBadReadPtr((LPVOID)lpEntryID, (UINT)cbEntryID)) {
DebugTraceArg(DISTLIST_CreateEntry, TEXT("lpEntryID fails address check"));
return(ResultFromScode(MAPI_E_INVALID_ENTRYID));
}
//NFAssertSz(FValidEntryIDFlags(lpEntryID->abFlags),
// "Undefined bits set in EntryID flags\n");
} else {
DebugTraceArg(DISTLIST_CreateEntry, TEXT("lpEntryID NULL"));
return(ResultFromScode(MAPI_E_INVALID_ENTRYID));
}
*/
if (ulCreateFlags & ~(CREATE_CHECK_DUP_STRICT | CREATE_CHECK_DUP_LOOSE | CREATE_REPLACE | CREATE_MERGE)) {
DebugTraceArg(DISTLIST_CreateEntry, TEXT("Unknown flags used"));
// return(ResultFromScode(MAPI_E_UNKNOWN_FLAGS));
}
if (IsBadWritePtr(lppEntry, sizeof(LPMAPIPROP))) {
DebugTraceArg(DISTLIST_CreateEntry, TEXT("Bad MAPI Property write parameter"));
return(ResultFromScode(MAPI_E_INVALID_PARAMETER));
}
#endif // PARAMETER_VALIDATION
*lppEntry = NULL;
if (cbEntryID == 0 || lpEntryID == NULL) {
DebugTrace(TEXT("DISTLIST_CreateEntry: NULL EntryID passed in\n"));
hResult = ResultFromScode(MAPI_E_INVALID_ENTRYID);
goto exit;
}
// Open and validate the entry. Should NOT allow default entryid's,
// root entryid, etc. Must be a one-off, mailuser or distlist.
if (hResult = lpCONTAINER->lpVtbl->OpenEntry(lpCONTAINER,
cbEntryID,
lpEntryID,
NULL,
0, // ulFlags: Read only
&ulObjectType,
(LPUNKNOWN *)&lpOldEntry)) {
DebugTrace(TEXT("DISTLIST_CreateEntry: OpenEntry -> %x\n"), GetScode(hResult));
goto exit;
}
if (ulObjectType != MAPI_MAILUSER && ulObjectType != MAPI_DISTLIST) {
DebugTrace(TEXT("DISTLIST_CreateEntry: bad object type passed in\n"));
hResult = ResultFromScode(MAPI_E_INVALID_ENTRYID);
goto exit;
}
if (hResult = HrNewDLENTRY(lpCONTAINER,
(LPMAPIPROP)lpOldEntry, // Old entry to copy from
ulCreateFlags,
(LPVOID *)lppEntry)) {
goto exit;
}
exit:
UlRelease(lpOldEntry);
if (HR_FAILED(hResult) && *lppEntry) {
UlRelease(*lppEntry);
*lppEntry = NULL;
}
return(hResult);
}
/*
- CopyEntries
-
* Copies a list of entries into this container... Since you can't
* do that with this container we just return not supported.
*/
STDMETHODIMP
DISTLIST_CopyEntries(LPCONTAINER lpCONTAINER,
LPENTRYLIST lpEntries,
ULONG ulUIParam,
LPMAPIPROGRESS lpProgress,
ULONG ulFlags)
{
return(ResultFromScode(MAPI_E_NO_SUPPORT));
}
/*
- DeleteEntries
-
*
* Deletes entries within this container.
*/
STDMETHODIMP
DISTLIST_DeleteEntries(LPCONTAINER lpCONTAINER,
LPENTRYLIST lpEntries,
ULONG ulFlags)
{
ULONG i, iEntries = (ULONG)-1, iOneOffs = (ULONG)-1;
HRESULT hResult = hrSuccess;
ULONG cDeleted = 0;
ULONG cToDelete;
ULONG cValues;
LPSPropValue lpspv = NULL;
SizedSPropTagArray(1, tagaDLOneOffsProp) =
{
1, PR_WAB_DL_ONEOFFS,
};
#ifdef PARAMETER_VALIDATION
if (BAD_STANDARD_OBJ(lpCONTAINER, DISTLIST_, DeleteEntries, lpVtbl)) {
// jump table not large enough to support this method
DebugTraceArg(DISTLIST_DeleteEntries, TEXT("Bad object/vtbl"));
return(ResultFromScode(MAPI_E_INVALID_PARAMETER));
}
// ensure we can read the container list
if (FBadEntryList(lpEntries)) {
DebugTraceArg(DISTLIST_DeleteEntries, TEXT("Bad Entrylist parameter"));
return(ResultFromScode(MAPI_E_INVALID_PARAMETER));
}
if (ulFlags) {
DebugTraceArg(DISTLIST_CreateEntry, TEXT("Unknown flags used"));
// return(ResultFromScode(MAPI_E_UNKNOWN_FLAGS));
}
#endif // PARAMETER_VALIDATION
// List of entryids is in lpEntries. This is a counted array of
// entryid SBinary structs.
if (! (cToDelete = lpEntries->cValues)) {
goto exit; // nothing to delete
}
if (HR_FAILED(hResult = lpCONTAINER->lpPropData->lpVtbl->GetProps(lpCONTAINER->lpPropData,
NULL,
MAPI_UNICODE,
&cValues,
&lpspv))) {
DebugTraceResult( TEXT("DISTLIST_DeleteEntries:GetProps"), hResult);
goto exit;
}
// Find the PR_WAB_DL_ENTRIES
for (i = 0; i < cValues; i++)
{
if (lpspv[i].ulPropTag == PR_WAB_DL_ENTRIES)
iEntries = i;
else if(lpspv[i].ulPropTag == PR_WAB_DL_ONEOFFS)
iOneOffs = i;
}
// If there is no PR_WAB_DL_ENTRIES, then this DL contains no entries and we can't delete them.
if (iEntries == (ULONG)-1 && iOneOffs == (ULONG)-1)
{
hResult = ResultFromScode(MAPI_W_PARTIAL_COMPLETION);
goto exit;
}
// Delete each entry
if(iEntries != (ULONG)-1)
{
for (i = 0; i < cToDelete; i++)
{
if (! RemovePropFromMVBin(lpspv, cValues, iEntries, lpEntries->lpbin[i].lpb, lpEntries->lpbin[i].cb))
{
cDeleted++;
if (lpspv[iEntries].ulPropTag == PR_NULL)
{
// remove the property
if (HR_FAILED(hResult = lpCONTAINER->lpPropData->lpVtbl->DeleteProps(lpCONTAINER->lpPropData, (LPSPropTagArray)&tagaDLEntriesProp, NULL)))
{
DebugTraceResult( TEXT("DISTLIST_DeleteEntries: DeleteProps on IProp"), hResult);
goto exit;
}
break;
}
}
}
}
if(iOneOffs != (ULONG)-1)
{
for (i = 0; i < cToDelete; i++)
{
if (! RemovePropFromMVBin(lpspv, cValues, iOneOffs, lpEntries->lpbin[i].lpb, lpEntries->lpbin[i].cb))
{
cDeleted++;
if (lpspv[iOneOffs].ulPropTag == PR_NULL)
{
// remove the property
if (HR_FAILED(hResult = lpCONTAINER->lpPropData->lpVtbl->DeleteProps(lpCONTAINER->lpPropData, (LPSPropTagArray)&tagaDLOneOffsProp, NULL)))
{
DebugTraceResult( TEXT("DISTLIST_DeleteEntries: DeleteProps on IProp"), hResult);
goto exit;
}
break;
}
}
}
}
// Set the properties back
if (HR_FAILED(hResult = lpCONTAINER->lpPropData->lpVtbl->SetProps(lpCONTAINER->lpPropData, cValues, lpspv, NULL)))
{
DebugTraceResult( TEXT("DISTLIST_DeleteEntries: SetProps on IProp"), hResult);
goto exit;
}
// Save the Distribution list to disk
if (hResult = lpCONTAINER->lpVtbl->SaveChanges(lpCONTAINER, KEEP_OPEN_READWRITE))
{
DebugTraceResult( TEXT("DISTLIST_DeleteEntries:SaveChanges"), hResult);
}
if (! hResult)
{
if (cDeleted != cToDelete)
{
hResult = ResultFromScode(MAPI_W_PARTIAL_COMPLETION);
DebugTrace(TEXT("DeleteEntries deleted %u of requested %u\n"), cDeleted, cToDelete);
}
}
exit:
FreeBufferAndNull(&lpspv);
return(hResult);
}
STDMETHODIMP
DISTLIST_ResolveNames(LPCONTAINER lpCONTAINER,
LPSPropTagArray lptagaColSet,
ULONG ulFlags,
LPADRLIST lpAdrList,
LPFlagList lpFlagList)
{
return(ResultFromScode(MAPI_E_NO_SUPPORT));
}
//
//
// DLENTRY Object - Distribution List entry.
//
// Returned by CreateEntry in Distribution List.
//
// Most of this object is implemented by the MailUser object.
//
//
DLENTRY_Vtbl vtblDLENTRY= {
VTABLE_FILL
DLENTRY_QueryInterface,
(DLENTRY_AddRef_METHOD *) WRAP_AddRef,
DLENTRY_Release,
(DLENTRY_GetLastError_METHOD *) IAB_GetLastError,
DLENTRY_SaveChanges,
(DLENTRY_GetProps_METHOD *) MailUser_GetProps,
(DLENTRY_GetPropList_METHOD *) MailUser_GetPropList,
(DLENTRY_OpenProperty_METHOD *) MailUser_OpenProperty,
DLENTRY_SetProps,
DLENTRY_DeleteProps,
(DLENTRY_CopyTo_METHOD *) MailUser_CopyTo,
(DLENTRY_CopyProps_METHOD *) MailUser_CopyProps,
(DLENTRY_GetNamesFromIDs_METHOD *) MailUser_GetNamesFromIDs,
(DLENTRY_GetIDsFromNames_METHOD *) MailUser_GetIDsFromNames
};
//
// Interfaces supported by this object
//
#define DLENTRY_cInterfaces 1
LPIID DLENTRY_LPIID[DLENTRY_cInterfaces] =
{
(LPIID) &IID_IMAPIProp
};
/***************************************************************************
Name : HrNewDLENTRY
Purpose : Creates a new DLENTRY object
Parameters: lpCONTAINER -> DL Container
ulCreateFlags = CreateEntry flags
lppDLENTRY -> Returned DLENTRY object.
Returns : HRESULT
Comment :
***************************************************************************/
HRESULT HrNewDLENTRY(LPCONTAINER lpCONTAINER,
LPMAPIPROP lpOldEntry, // Old entry to copy from
ULONG ulCreateFlags,
LPVOID *lppDLENTRY)
{
LPDLENTRY lpDLENTRY = NULL;
SCODE sc;
HRESULT hResult = hrSuccess;
LPPROPDATA lpPropData = NULL;
ULONG cValues;
LPSPropValue lpspv = NULL;
//
// Allocate space for the DLENTRY structure
//
if (FAILED(sc = MAPIAllocateBuffer(sizeof(DLENTRY), (LPVOID *) &lpDLENTRY))) {
hResult = ResultFromScode(sc);
goto exit;
}
ZeroMemory(lpDLENTRY, sizeof(DLENTRY));
lpDLENTRY->cIID = DLENTRY_cInterfaces;
lpDLENTRY->rglpIID = DLENTRY_LPIID;
lpDLENTRY->lpVtbl = &vtblDLENTRY;
lpDLENTRY->lcInit = 1; // Caller is a reference
lpDLENTRY->hLastError = hrSuccess;
lpDLENTRY->idsLastError = 0;
lpDLENTRY->lpszComponent = NULL;
lpDLENTRY->ulContext = 0;
lpDLENTRY->ulLowLevelError = 0;
lpDLENTRY->ulErrorFlags = 0;
lpDLENTRY->ulCreateFlags = ulCreateFlags;
lpDLENTRY->lpMAPIError = NULL;
lpDLENTRY->ulObjAccess = IPROP_READWRITE;
lpDLENTRY->lpEntryID = NULL;
lpDLENTRY->lpIAB = lpCONTAINER->lpIAB;
lpDLENTRY->lpCONTAINER = lpCONTAINER;
//
// Create IPropData
//
if (FAILED(sc = CreateIProp((LPIID)&IID_IMAPIPropData,
(ALLOCATEBUFFER FAR *) MAPIAllocateBuffer,
(ALLOCATEMORE FAR *) MAPIAllocateMore,
MAPIFreeBuffer,
NULL,
&lpPropData))) {
hResult = ResultFromScode(sc);
goto exit;
}
//
// Copy the properties from the entry into the DLENTRY.
//
if (hResult = lpOldEntry->lpVtbl->GetProps(lpOldEntry,
NULL, // lpPropTagArray
MAPI_UNICODE, // ulFlags
&cValues,
&lpspv)) {
DebugTrace(TEXT("HrNewDLENTRY: GetProps on old object -> %x\n"), GetScode(hResult));
goto exit;
}
if (hResult = lpPropData->lpVtbl->SetProps(lpPropData,
cValues,
lpspv,
NULL)) {
DebugTrace(TEXT("HrNewDLENTRY: SetProps on IProp -> %x\n"), GetScode(hResult));
goto exit;
}
// Done setting props, now make it read only.
lpPropData->lpVtbl->HrSetObjAccess(lpPropData, IPROP_READONLY);
lpDLENTRY->lpPropData = lpPropData;
// Keep this container open since we need it in SaveChanges. Will Release in DLENTRY_Release.
UlAddRef(lpCONTAINER);
// initialize the DLENTRYs critical section
InitializeCriticalSection(&lpDLENTRY->cs);
*lppDLENTRY = (LPVOID)lpDLENTRY;
exit:
FreeBufferAndNull(&lpspv);
if (HR_FAILED(hResult)) {
FreeBufferAndNull(&lpDLENTRY);
UlRelease(lpPropData);
*lppDLENTRY = (LPVOID)NULL;
}
return(hResult);
}
/***************************************************************************
Name : CheckForCycle
Purpose : Does adding this entry to a DL generate a cycle?
Parameters: lpAdrBook -> ADRBOOK object
lpEIDChild -> EntryID of entry to be added to DL
cbEIDChild = sizeof lpEIDChild
lpEIDParent -> EntryID of distribution list that is being added to.
cbEIDParent = sizeof lpEIDParent
Returns : TRUE if a cycle is detected.
Comment : This is a recursive routine.
***************************************************************************/
BOOL CheckForCycle(LPADRBOOK lpAdrBook,
LPENTRYID lpEIDChild,
ULONG cbEIDChild,
LPENTRYID lpEIDParent,
ULONG cbEIDParent)
{
BOOL fCycle = FALSE;
LPMAPIPROP lpDistList = NULL;
ULONG ulcPropsDL;
ULONG ulObjType;
ULONG i;
LPSPropValue lpPropArrayDL = NULL;
if (cbEIDChild == cbEIDParent && ! memcmp(lpEIDChild, lpEIDParent, cbEIDChild))
{
return(TRUE); // This is a cycle
}
if (lpAdrBook->lpVtbl->OpenEntry(lpAdrBook,
cbEIDChild,
lpEIDChild,
NULL,
0,
&ulObjType,
(LPUNKNOWN *)&lpDistList))
{
goto exit; // Can't open child, it must not be a DL
}
if (ulObjType == MAPI_DISTLIST) {
// Get the DL property
if ( FAILED(lpDistList->lpVtbl->GetProps(
lpDistList,
(LPSPropTagArray)&tagaWabDLEntries,
MAPI_UNICODE, // ulFlags,
&ulcPropsDL,
&lpPropArrayDL)) )
{
// No property, no entries in this DL.
goto exit;
}
// Note we don't need to look for PR_WAB_DL_ONEOFFS since they won't be cycling ..
if (lpPropArrayDL[iwdePR_WAB_DL_ENTRIES].ulPropTag != PR_WAB_DL_ENTRIES)
{
goto exit;
}
// Look at each entry in the PR_WAB_DL_ENTRIES and recursively check it.
for (i = 0; i < lpPropArrayDL[iwdePR_WAB_DL_ENTRIES].Value.MVbin.cValues; i++)
{
if ( fCycle = CheckForCycle(lpAdrBook,
(LPENTRYID)lpPropArrayDL[iwdePR_WAB_DL_ENTRIES].Value.MVbin.lpbin[i].lpb,
lpPropArrayDL[iwdePR_WAB_DL_ENTRIES].Value.MVbin.lpbin[i].cb,
(LPENTRYID)lpEIDParent,
cbEIDParent) )
{
DebugTrace(TEXT("CheckForCycle found cycle\n"));
goto exit;
}
}
}
exit:
FreeBufferAndNull(&lpPropArrayDL);
UlRelease(lpDistList);
return(fCycle);
}
// --------
// IUnknown
STDMETHODIMP
DLENTRY_QueryInterface(LPDLENTRY lpDLENTRY,
REFIID lpiid,
LPVOID * lppNewObj)
{
ULONG iIID;
#ifdef PARAMETER_VALIDATION
// Check to see if it has a jump table
if (IsBadReadPtr(lpDLENTRY, sizeof(LPVOID))) {
// No jump table found
return(ResultFromScode(E_INVALIDARG));
}
// Check to see if the jump table has at least sizeof IUnknown
if (IsBadReadPtr(lpDLENTRY->lpVtbl, 3 * sizeof(LPVOID))) {
// Jump table not derived from IUnknown
return(ResultFromScode(E_INVALIDARG));
}
// Check to see that it's DLENTRY_QueryInterface
if (lpDLENTRY->lpVtbl->QueryInterface != DLENTRY_QueryInterface) {
// Not my jump table
return(ResultFromScode(E_INVALIDARG));
}
// Is there enough there for an interface ID?
if (IsBadReadPtr(lpiid, sizeof(IID))) {
DebugTraceSc(DLENTRY_QueryInterface, E_INVALIDARG);
return(ResultFromScode(E_INVALIDARG));
}
// Is there enough there for a new object?
if (IsBadWritePtr(lppNewObj, sizeof(LPDLENTRY))) {
DebugTraceSc(DLENTRY_QueryInterface, E_INVALIDARG);
return(ResultFromScode(E_INVALIDARG));
}
#endif // PARAMETER_VALIDATION
EnterCriticalSection(&lpDLENTRY->cs);
// See if the requested interface is one of ours
// First check with IUnknown, since we all have to support that one...
if (! memcmp(lpiid, &IID_IUnknown, sizeof(IID))) {
goto goodiid; // GROSS! Jump into a for loop!
}
// Now look through all the iids associated with this object, see if any match
for(iIID = 0; iIID < lpDLENTRY->cIID; iIID++)
if (! memcmp(lpDLENTRY->rglpIID[iIID], lpiid, sizeof(IID))) {
goodiid:
//
// It's a match of interfaces, we support this one then...
//
++lpDLENTRY->lcInit;
*lppNewObj = lpDLENTRY;
LeaveCriticalSection(&lpDLENTRY->cs);
return(0);
}
//
// No interface we've heard of...
//
LeaveCriticalSection(&lpDLENTRY->cs);
*lppNewObj = NULL; // OLE requires NULLing out parm on failure
DebugTraceSc(DLENTRY_QueryInterface, E_NOINTERFACE);
return(ResultFromScode(E_NOINTERFACE));
}
STDMETHODIMP_(ULONG)
DLENTRY_Release(LPDLENTRY lpDLENTRY)
{
#if !defined(NO_VALIDATION)
//
// Make sure the object is valid.
//
if (BAD_STANDARD_OBJ(lpDLENTRY, DLENTRY_, Release, lpVtbl)) {
return(1);
}
#endif
EnterCriticalSection(&lpDLENTRY->cs);
--lpDLENTRY->lcInit;
if (lpDLENTRY->lcInit == 0) {
UlRelease(lpDLENTRY->lpPropData);
UlRelease(lpDLENTRY->lpCONTAINER); // parent DL container
//
// Need to free the object
//
LeaveCriticalSection(&lpDLENTRY->cs);
DeleteCriticalSection(&lpDLENTRY->cs);
FreeBufferAndNull(&lpDLENTRY);
return(0);
}
LeaveCriticalSection(&lpDLENTRY->cs);
return(lpDLENTRY->lcInit);
}
//
// IProperty
//
STDMETHODIMP
DLENTRY_SaveChanges(LPDLENTRY lpDLENTRY,
ULONG ulFlags)
{
HRESULT hResult = hrSuccess;
LPSPropValue lpPropArrayDL = NULL;
LPSPropValue lpPropArrayEntry = NULL;
ULONG ulcPropsDL, ulcPropsEntry;
LPCONTAINER lpCONTAINER = NULL;
LPENTRYID lpEIDAdd;
ULONG cbEIDAdd;
BOOL bUseOneOffProp = FALSE;
LPPTGDATA lpPTGData=GetThreadStoragePointer();
#if !defined(NO_VALIDATION)
// Make sure the object is valid.
if (BAD_STANDARD_OBJ(lpDLENTRY, DLENTRY_, SaveChanges, lpVtbl)) {
return(ResultFromScode(MAPI_E_INVALID_PARAMETER));
}
#endif
//
// check read write access ...
//
if (lpDLENTRY->ulObjAccess == IPROP_READONLY) {
// error - cant save changes
hResult = MAPI_E_NO_ACCESS;
goto exit;
}
// Get the ENTRYID of this entry
if (hResult = lpDLENTRY->lpPropData->lpVtbl->GetProps(lpDLENTRY->lpPropData,
(LPSPropTagArray)&ptaEid, // also include PR_DISPLAYNAME
MAPI_UNICODE, // ulFlags,
&ulcPropsEntry,
&lpPropArrayEntry))
{
DebugTrace(TEXT("DLENTRY_SaveChanges: GetProps(DLENTRY) -> %x\n"), GetScode(hResult));
goto exit;
}
Assert(lpPropArrayEntry && lpPropArrayEntry[ieidPR_ENTRYID].ulPropTag == PR_ENTRYID);
cbEIDAdd = lpPropArrayEntry[ieidPR_ENTRYID].Value.bin.cb;
lpEIDAdd = (LPENTRYID)lpPropArrayEntry[ieidPR_ENTRYID].Value.bin.lpb;
lpCONTAINER = lpDLENTRY->lpCONTAINER;
// Merge it into PR_WAB_DL_ENTRIES of the DL unless it's a ONEOFF in which case merge it into the OneOffs
tagaWabDLEntries.aulPropTag[iwdePR_WAB_DL_ONEOFFS] = PR_WAB_DL_ONEOFFS;
if (hResult = lpCONTAINER->lpVtbl->GetProps(lpCONTAINER,
(LPSPropTagArray)&tagaWabDLEntries,
MAPI_UNICODE, // ulFlags,
&ulcPropsDL,
&lpPropArrayDL))
{
DebugTrace(TEXT("DLENTRY_SaveChanges: GetProps(DL) -> %x\n"), GetScode(hResult));
// No property, not fatal.
}
else
{
// Check for duplicates. In DISTLIST, we only support duplicate ENTRYID checking,
// so CREATE_CHECK_DUP_STRICT is the same as CREATE_CHECK_DUP_LOOSE.
if (lpDLENTRY->ulCreateFlags & (CREATE_CHECK_DUP_STRICT | CREATE_CHECK_DUP_LOOSE))
{
SBinaryArray MVbin;
ULONG ulCount;
ULONG i,j;
for(j=iwdePR_WAB_DL_ENTRIES;j<=iwdePR_WAB_DL_ONEOFFS;j++)
{
if(lpPropArrayDL[j].ulPropTag == PR_NULL || !lpPropArrayDL[j].Value.MVbin.cValues)
continue;
// Yes, check for duplicates
MVbin = lpPropArrayDL[j].Value.MVbin;
ulCount = MVbin.cValues;
for (i = 0; i < ulCount; i++)
{
if ((cbEIDAdd == MVbin.lpbin[i].cb) &&
!memcmp(lpEIDAdd, MVbin.lpbin[i].lpb, cbEIDAdd))
{
// This EntryID is already in the list.
// Handle duplicate.
// Since we are only checking against ENTRYID, we don't have to
// actually REPLACE. We just pretend we did something and don't fail.
if (! (lpDLENTRY->ulCreateFlags & CREATE_REPLACE))
{
hResult = ResultFromScode(MAPI_E_COLLISION);
goto exit;
}
goto nosave;
}
} // i
}// j
}
}
if (CheckForCycle((LPADRBOOK)lpDLENTRY->lpCONTAINER->lpIAB,
lpEIDAdd, cbEIDAdd,
(LPENTRYID)lpPropArrayDL[iwdePR_ENTRYID].Value.bin.lpb,
lpPropArrayDL[iwdePR_ENTRYID].Value.bin.cb))
{
DebugTrace(TEXT("DLENTRY_SaveChanges found cycle\n"));
hResult = ResultFromScode(MAPI_E_FOLDER_CYCLE);
goto exit;
}
if(WAB_ONEOFF == IsWABEntryID(cbEIDAdd, lpEIDAdd, NULL, NULL, NULL, NULL, NULL))
bUseOneOffProp = TRUE;
if(pt_bIsWABOpenExSession)
bUseOneOffProp = FALSE;
if (hResult = AddPropToMVPBin(lpPropArrayDL,
(bUseOneOffProp ? iwdePR_WAB_DL_ONEOFFS : iwdePR_WAB_DL_ENTRIES),
(LPBYTE)lpEIDAdd,
cbEIDAdd,
TRUE)) // no duplicates
{
DebugTrace(TEXT("DLENTRY_SaveChanges: AddPropToMVPBin -> %x\n"), GetScode(hResult));
goto exit;
}
if (hResult = lpCONTAINER->lpVtbl->SetProps(lpCONTAINER, ulcPropsDL, lpPropArrayDL, NULL))
{
DebugTrace(TEXT("DLENTRY_SaveChanges: SetProps(DL) -> %x\n"), GetScode(hResult));
goto exit;
}
// Save the modified DL, keeping it open/writable.
if (HR_FAILED(hResult = lpCONTAINER->lpVtbl->SaveChanges(lpCONTAINER, FORCE_SAVE | KEEP_OPEN_READWRITE)))
{
DebugTrace(TEXT("DLENTRY_SaveChanges: container SaveChanges -> %x\n"), GetScode(hResult));
goto exit;
}
nosave:
if (ulFlags & KEEP_OPEN_READWRITE) {
lpDLENTRY->ulObjAccess = IPROP_READWRITE;
} else {
//$REVIEW
// whether the flag was READONLY or there was no flag,
// we'll make the future access now READONLY
//
lpDLENTRY->ulObjAccess = IPROP_READONLY;
}
exit:
FreeBufferAndNull(&lpPropArrayDL);
FreeBufferAndNull(&lpPropArrayEntry);
if ((HR_FAILED(hResult)) && (ulFlags & MAPI_DEFERRED_ERRORS)) {
//$REVIEW : this is a grossly trivial handling of MAPI_DEFERRED_ERRORS ..
// BUGBUG: In fact, it isn't handling the errors at all!
//
hResult = hrSuccess;
}
return(hResult);
}
STDMETHODIMP
DLENTRY_SetProps(LPDLENTRY lpDLENTRY,
ULONG cValues,
LPSPropValue lpPropArray,
LPSPropProblemArray * lppProblems)
{
return(ResultFromScode(MAPI_E_NO_SUPPORT));
}
STDMETHODIMP
DLENTRY_DeleteProps(LPDLENTRY lpDLENTRY,
LPSPropTagArray lpPropTagArray,
LPSPropProblemArray * lppProblems)
{
return(ResultFromScode(MAPI_E_NO_SUPPORT));
}