|
|
/*
* ABCONT.C * * Generic IMAPIContainer implementation. * * Copyright 1992 - 1996 Microsoft Corporation. All Rights Reserved. */
#include "_apipch.h"
#ifdef WIN16
#undef GetLastError
#endif
static HRESULT HrGetFirstRowInTad(LPTABLEDATA lpTableData, LPTABLEINFO lpTableInfo, ULONG ulcTableInfo, ULONG uliTable, ULONG * puliRow);
static HRESULT HrGetLastRowInTad(LPTABLEDATA lpTableData, LPTABLEINFO lpTableInfo, ULONG ulcTableInfo, ULONG uliTable, ULONG * puliRow);
OlkContInfo *FindContainer(LPIAB lpIAB, ULONG cbEntryID, LPENTRYID lpEID);
NOTIFCALLBACK lHierarchyNotifCallBack;
extern CONTAINER_Vtbl vtblROOT; extern CONTAINER_Vtbl vtblLDAPCONT;
extern HRESULT HrSmartResolve(LPIAB lpIAB, LPABCONT lpContainer, ULONG ulFlags, LPADRLIST lpAdrList, LPFlagList lpFlagList, LPAMBIGUOUS_TABLES lpAmbiguousTables);
// extern CONTAINER_Vtbl vtblDISTLIST;
CONTAINER_Vtbl vtblCONTAINER = { VTABLE_FILL // (CONTAINER_QueryInterface_METHOD *) IAB_QueryInterface, //bug 2707:this crashes
CONTAINER_QueryInterface, (CONTAINER_AddRef_METHOD *) WRAP_AddRef, CONTAINER_Release, (CONTAINER_GetLastError_METHOD *) IAB_GetLastError, (CONTAINER_SaveChanges_METHOD *) WRAP_SaveChanges, (CONTAINER_GetProps_METHOD *) WRAP_GetProps, (CONTAINER_GetPropList_METHOD *) WRAP_GetPropList, CONTAINER_OpenProperty, (CONTAINER_SetProps_METHOD *) WRAP_SetProps, (CONTAINER_DeleteProps_METHOD *) WRAP_DeleteProps, (CONTAINER_CopyTo_METHOD *) WRAP_CopyTo, (CONTAINER_CopyProps_METHOD *) WRAP_CopyProps, (CONTAINER_GetNamesFromIDs_METHOD *) WRAP_GetNamesFromIDs, CONTAINER_GetIDsFromNames, CONTAINER_GetContentsTable, CONTAINER_GetHierarchyTable, CONTAINER_OpenEntry, CONTAINER_SetSearchCriteria, CONTAINER_GetSearchCriteria, CONTAINER_CreateEntry, CONTAINER_CopyEntries, CONTAINER_DeleteEntries, CONTAINER_ResolveNames };
//
// Interfaces supported by this object
//
#define CONTAINER_cInterfaces 3
LPIID CONTAINER_LPIID[CONTAINER_cInterfaces] = { (LPIID) &IID_IABContainer, (LPIID) &IID_IMAPIContainer, (LPIID) &IID_IMAPIProp };
#define DISTLIST_cInterfaces 4
LPIID DISTLIST_LPIID[DISTLIST_cInterfaces] = { (LPIID) &IID_IDistList, (LPIID) &IID_IABContainer, (LPIID) &IID_IMAPIContainer, (LPIID) &IID_IMAPIProp };
SizedSSortOrderSet(1, sosPR_ENTRYID) = { 1, 0, 0, { PR_ENTRYID } };
SizedSSortOrderSet(1, sosPR_ROWID) = { 1, 0, 0, { PR_ROWID } };
SizedSPropTagArray(2, tagaInsKey) = { 2, { PR_INSTANCE_KEY, PR_NULL // Space for PR_ROWID
} };
//
// container default properties
// Put essential props first
//
enum { icdPR_DISPLAY_NAME, icdPR_OBJECT_TYPE, icdPR_CONTAINER_FLAGS, icdPR_DISPLAY_TYPE, icdPR_ENTRYID, // optional
icdPR_DEF_CREATE_MAILUSER, // optional
icdPR_DEF_CREATE_DL, // optional
icdMax };
/***************************************************************************
Name : HrSetCONTAINERAccess
Purpose : Sets access flags on a container object
Parameters: lpCONTAINER -> Container object ulOpenFlags = MAPI flags: MAPI_MODIFY | MAPI_BEST_ACCESS
Returns : HRESULT
Comment : Set the access flags on the container.
***************************************************************************/ HRESULT HrSetCONTAINERAccess(LPCONTAINER lpCONTAINER, ULONG ulFlags) { ULONG ulAccess = IPROP_READONLY;
switch (ulFlags& (MAPI_MODIFY | MAPI_BEST_ACCESS)) { case MAPI_MODIFY: case MAPI_BEST_ACCESS: ulAccess = IPROP_READWRITE; break;
case 0: break;
default: Assert(FALSE); }
return(lpCONTAINER->lpPropData->lpVtbl->HrSetObjAccess(lpCONTAINER->lpPropData, ulAccess)); }
/***************************************************************************
Name : HrNewCONTAINER
Purpose : Creates a container object
Parameters: lpIAB -> addrbook object ulType = {AB_ROOT, AB_WELL, AB_DL, AB_CONTAINER} lpInterface -> requested interface ulOpenFlags = flags cbEID = size of lpEID lpEID -> optional entryid of this object lpulObjType -> returned object type lppContainer -> returned IABContainer object
Returns : HRESULT
Comment :
***************************************************************************/ HRESULT HrNewCONTAINER(LPIAB lpIAB, ULONG ulType, LPCIID lpInterface, ULONG ulOpenFlags, ULONG cbEID, LPENTRYID lpEID, ULONG *lpulObjType, LPVOID *lppContainer) { HRESULT hResult = hrSuccess; LPCONTAINER lpCONTAINER = NULL; SCODE sc; LPSPropValue lpProps = NULL; LPPROPDATA lpPropData = NULL; ULONG ulObjectType; BYTE bEntryIDType; ULONG cProps; TCHAR szDisplayName[MAX_PATH] = TEXT(""); LPTSTR lpDisplayName = szDisplayName; BOOL fLoadedLDAP = FALSE; OlkContInfo *polkci; LPPTGDATA lpPTGData=GetThreadStoragePointer();
EnterCriticalSection(&lpIAB->cs);
if (lpInterface != NULL) { if (memcmp(lpInterface, &IID_IABContainer, sizeof(IID)) && memcmp(lpInterface, &IID_IDistList, sizeof(IID)) && memcmp(lpInterface, &IID_IMAPIContainer, sizeof(IID)) && memcmp(lpInterface, &IID_IMAPIProp, sizeof(IID))) { hResult = ResultFromScode(MAPI_E_INTERFACE_NOT_SUPPORTED);
goto exit; } }
//
// Allocate space for the CONTAINER structure
//
if ((sc = MAPIAllocateBuffer(sizeof(CONTAINER), (LPVOID *)&lpCONTAINER)) != SUCCESS_SUCCESS) { return(ResultFromScode(sc)); }
// [PaulHi] 12/16/98
// We don't set all structure variables so zero out first!
ZeroMemory(lpCONTAINER, sizeof(CONTAINER));
lpCONTAINER->pmbinOlk = NULL;
switch (ulType) { case AB_ROOT: // Root container object
ulObjectType = MAPI_ABCONT; lpCONTAINER->lpVtbl = &vtblROOT; lpCONTAINER->cIID = CONTAINER_cInterfaces; lpCONTAINER->rglpIID = CONTAINER_LPIID; bEntryIDType = WAB_ROOT; #ifdef NEW_STUFF
if (! LoadString(hinstMapiX, idsRootName, szDisplayName, ARRAYSIZE(szDisplayName))) { DebugTrace(TEXT("Can't load root name from resource\n")); } #else
StrCpyN(szDisplayName, TEXT("WAB Root Container"), ARRAYSIZE(szDisplayName)); #endif
MAPISetBufferName(lpCONTAINER, TEXT("AB Root Container Object")); break;
case AB_WELL: // What the heck is this supposed to be?
Assert(FALSE); hResult = ResultFromScode(MAPI_E_INTERFACE_NOT_SUPPORTED); goto exit; break;
case AB_DL: // Distribution List container
ulObjectType = MAPI_DISTLIST; lpCONTAINER->lpVtbl = &vtblDISTLIST; lpCONTAINER->cIID = DISTLIST_cInterfaces; lpCONTAINER->rglpIID = DISTLIST_LPIID; bEntryIDType = WAB_DISTLIST; MAPISetBufferName(lpCONTAINER, TEXT("AB DISTLIST Container Object")); break;
case AB_PAB: // "Default" PAB Container
ulObjectType = MAPI_ABCONT; lpCONTAINER->lpVtbl = &vtblCONTAINER; lpCONTAINER->cIID = CONTAINER_cInterfaces; lpCONTAINER->rglpIID = CONTAINER_LPIID; bEntryIDType = WAB_PAB; if (pt_bIsWABOpenExSession) { // if this is an Outlook Session, then the container is the
// first one in the list of Outlook containers
Assert(lpIAB->lpPropertyStore->rgolkci); lpDisplayName = lpIAB->lpPropertyStore->rgolkci->lpszName; } else if(WAB_PABSHARED == IsWABEntryID(cbEID, lpEID, NULL, NULL, NULL, NULL, NULL)) { // WAB's "shared contacts" container
if(FAILED(hResult = MAPIAllocateMore( sizeof(SBinary) + cbEID, lpCONTAINER, (LPVOID *)&lpCONTAINER->pmbinOlk))) goto exit; // The shared contacts container has a special entryid of 0 bytes
// and NULL entryid to distinguish it from other entryids
lpCONTAINER->pmbinOlk->cb = 0; lpCONTAINER->pmbinOlk->lpb = NULL; LoadString(hinstMapiX, idsSharedContacts, szDisplayName, ARRAYSIZE(szDisplayName)); } else if(bAreWABAPIProfileAware(lpIAB) && bIsThereACurrentUser(lpIAB)) { // if calling client asked for profile support and logging into the
// identity manager was successful and returned a valid profile, then
// we need to return the user's default folder as the PAB
//
if(FAILED(hResult = MAPIAllocateMore( sizeof(SBinary) + cbEID, lpCONTAINER, (LPVOID *)&lpCONTAINER->pmbinOlk))) goto exit; lpDisplayName = lpIAB->lpWABCurrentUserFolder->lpFolderName; lpCONTAINER->pmbinOlk->cb = lpIAB->lpWABCurrentUserFolder->sbEID.cb;//cbEID;
lpCONTAINER->pmbinOlk->lpb = (LPBYTE)(lpCONTAINER->pmbinOlk + 1); CopyMemory(lpCONTAINER->pmbinOlk->lpb, lpIAB->lpWABCurrentUserFolder->sbEID.lpb, lpCONTAINER->pmbinOlk->cb);//lpEID, cbEID);
} else // old style "Contacts" container
if (! LoadString(hinstMapiX, idsContacts, szDisplayName, ARRAYSIZE(szDisplayName))) { DebugTrace(TEXT("Can't load pab name from resource\n")); } MAPISetBufferName(lpCONTAINER, TEXT("AB PAB Container Object")); break;
case AB_CONTAINER: // regular container/folder - we have an identifying entryid
ulObjectType = MAPI_ABCONT; lpCONTAINER->lpVtbl = &vtblCONTAINER; lpCONTAINER->cIID = CONTAINER_cInterfaces; lpCONTAINER->rglpIID = CONTAINER_LPIID; bEntryIDType = WAB_CONTAINER; if (pt_bIsWABOpenExSession || bIsWABSessionProfileAware(lpIAB)) { // If this is an outlook session or if this is an identity-aware
// session, look for the specified container and use it
polkci = FindContainer(lpIAB, cbEID, lpEID); if (!polkci) { hResult = ResultFromScode(MAPI_E_NOT_FOUND); goto exit; } lpDisplayName = polkci->lpszName; hResult = MAPIAllocateMore( sizeof(SBinary) + cbEID, lpCONTAINER, (LPVOID *)&lpCONTAINER->pmbinOlk); if (FAILED(hResult)) goto exit; lpCONTAINER->pmbinOlk->cb = cbEID; lpCONTAINER->pmbinOlk->lpb = (LPBYTE)(lpCONTAINER->pmbinOlk + 1); CopyMemory(lpCONTAINER->pmbinOlk->lpb, lpEID, cbEID); } MAPISetBufferName(lpCONTAINER, TEXT("AB Container Object")); break;
case AB_LDAP_CONTAINER: // LDAP container
ulObjectType = MAPI_ABCONT; lpCONTAINER->lpVtbl = &vtblLDAPCONT; lpCONTAINER->cIID = CONTAINER_cInterfaces; lpCONTAINER->rglpIID = CONTAINER_LPIID; bEntryIDType = WAB_LDAP_CONTAINER; // Extract the server name from the LDAP entryid
IsWABEntryID(cbEID, lpEID,&lpDisplayName, NULL,NULL, NULL, NULL); fLoadedLDAP = InitLDAPClientLib(); MAPISetBufferName(lpCONTAINER, TEXT("AB LDAP Container Object")); break;
default: // shouldnt' hit this one.
MAPISetBufferName(lpCONTAINER, TEXT("AB Container Object")); Assert(FALSE); }
lpCONTAINER->lcInit = 1; lpCONTAINER->hLastError = hrSuccess; lpCONTAINER->idsLastError = 0; lpCONTAINER->lpszComponent = NULL; lpCONTAINER->ulContext = 0; lpCONTAINER->ulLowLevelError = 0; lpCONTAINER->ulErrorFlags = 0; lpCONTAINER->lpMAPIError = NULL;
lpCONTAINER->ulType = ulType; lpCONTAINER->lpIAB = lpIAB; lpCONTAINER->fLoadedLDAP = fLoadedLDAP;
// Addref our parent IAB object
UlAddRef(lpIAB);
//
// Create IPropData
//
if (FAILED(sc = CreateIProp(&IID_IMAPIPropData, (ALLOCATEBUFFER FAR * ) MAPIAllocateBuffer, (ALLOCATEMORE FAR *) MAPIAllocateMore, MAPIFreeBuffer, NULL, &lpPropData))) { hResult = ResultFromScode(sc);
goto exit; }
MAPISetBufferName(lpPropData, TEXT("lpPropData in HrNewCONTAINER"));
if (sc = MAPIAllocateBuffer(icdMax * sizeof(SPropValue), &lpProps)) { hResult = ResultFromScode(sc); }
// Set the basic set of properties on this container object such as
// display-name etc
lpProps[icdPR_OBJECT_TYPE].ulPropTag = PR_OBJECT_TYPE; lpProps[icdPR_OBJECT_TYPE].Value.l = ulObjectType;
lpProps[icdPR_DISPLAY_NAME].ulPropTag = PR_DISPLAY_NAME; lpProps[icdPR_DISPLAY_NAME].Value.LPSZ = lpDisplayName;
lpProps[icdPR_CONTAINER_FLAGS].ulPropTag = PR_CONTAINER_FLAGS; lpProps[icdPR_CONTAINER_FLAGS].Value.l = (ulType == AB_ROOT) ? AB_UNMODIFIABLE : AB_MODIFIABLE;
lpProps[icdPR_DISPLAY_TYPE].ulPropTag = PR_DISPLAY_TYPE; lpProps[icdPR_DISPLAY_TYPE].Value.l = DT_LOCAL;
cProps = 4;
// in addition to the above properties, add some additional ones depending
// on what type of container this is...
switch (ulType) { case AB_PAB: lpProps[icdPR_ENTRYID].ulPropTag = PR_ENTRYID; if(lpCONTAINER->pmbinOlk) { // if we have an entryid for the container, just reuse it
lpProps[icdPR_ENTRYID].Value.bin.cb = lpCONTAINER->pmbinOlk->cb; //cbEID;
lpProps[icdPR_ENTRYID].Value.bin.lpb = lpCONTAINER->pmbinOlk->lpb;//(LPBYTE)lpEID;
} else // create a wab entryid that we can hand about
if (HR_FAILED(hResult = CreateWABEntryID(bEntryIDType, NULL, NULL, NULL,0, 0, (LPVOID) lpProps, (LPULONG) (&lpProps[icdPR_ENTRYID].Value.bin.cb), (LPENTRYID *)&lpProps[icdPR_ENTRYID].Value.bin.lpb))) { goto exit; } cProps++;
// Add the default template IDs used for creating new users
lpProps[icdPR_DEF_CREATE_MAILUSER].ulPropTag = PR_DEF_CREATE_MAILUSER; if (HR_FAILED(hResult = CreateWABEntryID(WAB_DEF_MAILUSER, NULL, NULL, NULL, 0, 0, (LPVOID) lpProps, // lpRoot
(LPULONG) (&lpProps[icdPR_DEF_CREATE_MAILUSER].Value.bin.cb), (LPENTRYID *)&lpProps[icdPR_DEF_CREATE_MAILUSER].Value.bin.lpb))) { goto exit; } cProps++;
lpProps[icdPR_DEF_CREATE_DL].ulPropTag = PR_DEF_CREATE_DL; if (HR_FAILED(hResult = CreateWABEntryID(WAB_DEF_DL, NULL, NULL, NULL, 0, 0, (LPVOID) lpProps, // lpRoot
(LPULONG) (&lpProps[icdPR_DEF_CREATE_DL].Value.bin.cb), (LPENTRYID *)&lpProps[icdPR_DEF_CREATE_DL].Value.bin.lpb))) { goto exit; } cProps++; break;
case AB_CONTAINER: lpProps[icdPR_ENTRYID].ulPropTag = PR_ENTRYID; lpProps[icdPR_ENTRYID].Value.bin.cb = cbEID; lpProps[icdPR_ENTRYID].Value.bin.lpb = (LPBYTE)lpEID; cProps++;
lpProps[icdPR_DEF_CREATE_MAILUSER].ulPropTag = PR_DEF_CREATE_MAILUSER; if (HR_FAILED(hResult = CreateWABEntryID(WAB_DEF_MAILUSER, NULL, NULL, NULL, 0, 0, (LPVOID) lpProps, // lpRoot
(LPULONG) (&lpProps[icdPR_DEF_CREATE_MAILUSER].Value.bin.cb), (LPENTRYID *)&lpProps[icdPR_DEF_CREATE_MAILUSER].Value.bin.lpb))) { goto exit; } cProps++;
lpProps[icdPR_DEF_CREATE_DL].ulPropTag = PR_DEF_CREATE_DL; if (HR_FAILED(hResult = CreateWABEntryID(WAB_DEF_DL, NULL, NULL, NULL, 0, 0, (LPVOID) lpProps, // lpRoot
(LPULONG) (&lpProps[icdPR_DEF_CREATE_DL].Value.bin.cb), (LPENTRYID *)&lpProps[icdPR_DEF_CREATE_DL].Value.bin.lpb))) { goto exit; } cProps++; break;
case AB_ROOT: lpProps[icdPR_ENTRYID].ulPropTag = PR_ENTRYID; lpProps[icdPR_ENTRYID].Value.bin.cb = 0; lpProps[icdPR_ENTRYID].Value.bin.lpb = NULL; cProps++;
lpProps[icdPR_DEF_CREATE_MAILUSER].ulPropTag = PR_DEF_CREATE_MAILUSER; if (HR_FAILED(hResult = CreateWABEntryID(WAB_DEF_MAILUSER, NULL, NULL, NULL, 0, 0, (LPVOID) lpProps, // lpRoot
(LPULONG) (&lpProps[icdPR_DEF_CREATE_MAILUSER].Value.bin.cb), (LPENTRYID *)&lpProps[icdPR_DEF_CREATE_MAILUSER].Value.bin.lpb))) { goto exit; } cProps++;
lpProps[icdPR_DEF_CREATE_DL].ulPropTag = PR_DEF_CREATE_DL; if (HR_FAILED(hResult = CreateWABEntryID(WAB_DEF_DL, NULL, NULL, NULL, 0, 0, (LPVOID) lpProps, // lpRoot
(LPULONG) (&lpProps[icdPR_DEF_CREATE_DL].Value.bin.cb), (LPENTRYID *)&lpProps[icdPR_DEF_CREATE_DL].Value.bin.lpb))) { goto exit; } cProps++; break;
case AB_LDAP_CONTAINER: lpProps[icdPR_ENTRYID].ulPropTag = PR_ENTRYID; lpProps[icdPR_ENTRYID].Value.bin.cb = cbEID; lpProps[icdPR_ENTRYID].Value.bin.lpb = (LPBYTE)lpEID;
cProps++;
// Hack! Don't need PR_DEF_CREATE_* so use those slots for
// PR_WAB_LDAP_SERVER.
lpProps[icdPR_DEF_CREATE_MAILUSER].ulPropTag = PR_WAB_LDAP_SERVER; lpProps[icdPR_DEF_CREATE_MAILUSER].Value.LPSZ = lpDisplayName;
cProps++; break; }
//
// Set the default properties
//
if (HR_FAILED(hResult = lpPropData->lpVtbl->SetProps(lpPropData, cProps, lpProps, NULL))) { LPMAPIERROR lpMAPIError = NULL;
lpPropData->lpVtbl->GetLastError(lpPropData, hResult, 0, // Ansi only
&lpMAPIError);
goto exit; }
// default object access is ReadOnly (means the container object can't
// be modified but it's data can be modified)
lpPropData->lpVtbl->HrSetObjAccess(lpPropData, IPROP_READONLY);
lpCONTAINER->lpPropData = lpPropData;
// All we want to do is initialize the Root container's critical section
InitializeCriticalSection(&lpCONTAINER->cs);
*lpulObjType = ulObjectType; *lppContainer = (LPVOID)lpCONTAINER;
exit: FreeBufferAndNull(&lpProps);
if (HR_FAILED(hResult)) { if (fLoadedLDAP) { DeinitLDAPClientLib(); } FreeBufferAndNull(&lpCONTAINER); UlRelease(lpPropData); }
LeaveCriticalSection(&lpIAB->cs);
return(hResult); }
/***************************************************
* * ABContainer methods */
/*
* IUnknown */
/***************************************************************************
Name : CONTAINER::QueryInterface
Purpose : Calls the IAB_QueryInterface correctly
Parameters:
Returns :
***************************************************************************/ STDMETHODIMP CONTAINER_QueryInterface(LPCONTAINER lpContainer, REFIID lpiid, LPVOID * lppNewObj) {
// Check to see if it has a jump table
if (IsBadReadPtr(lpContainer, sizeof(LPVOID))) { // No jump table found
return(ResultFromScode(E_INVALIDARG)); }
// Check to see if the jump table has at least sizeof IUnknown
if (IsBadReadPtr(lpContainer->lpVtbl, 3*sizeof(LPVOID))) { // Jump table not derived from IUnknown
return(ResultFromScode(E_INVALIDARG)); }
// Check to see that it's IAB_QueryInterface
if (lpContainer->lpVtbl->QueryInterface != CONTAINER_QueryInterface) { // Not my jump table
return(ResultFromScode(E_INVALIDARG)); }
// default to the IAB QueryInterface method
return lpContainer->lpIAB->lpVtbl->QueryInterface(lpContainer->lpIAB, lpiid, lppNewObj); }
/***************************************************************************
Name : CONTAINER::Release
Purpose : Releases the container object
Parameters: lpCONTAINER -> Container object
Returns : current reference count
Comment : Decrememnt lpInit When lcInit == 0, release the parent objects and free up the lpCONTAINER structure
***************************************************************************/ STDMETHODIMP_(ULONG) CONTAINER_Release(LPCONTAINER lpCONTAINER) { #ifdef PARAMETER_VALIDATION
// Check to see if it has a jump table
if (IsBadReadPtr(lpCONTAINER, sizeof(LPVOID))) { // No jump table found
return(1); } #endif // PARAMETER_VALIDATION
EnterCriticalSection(&lpCONTAINER->cs);
--lpCONTAINER->lcInit;
if (lpCONTAINER->lcInit == 0) { // Remove this object from the objects currently on this session.
// Not yet implemented...
// Remove the associated lpPropData
UlRelease(lpCONTAINER->lpPropData);
// Set the Jump table to NULL. This way the client will find out
// real fast if it's calling a method on a released object. That is,
// the client will crash. Hopefully, this will happen during the
// development stage of the client.
lpCONTAINER->lpVtbl = NULL;
// Free error string if allocated from MAPI memory.
FreeBufferAndNull(&(lpCONTAINER->lpMAPIError));
// Release the IAB since we addref'd it in root object creation.
UlRelease(lpCONTAINER->lpIAB);
if (lpCONTAINER->fLoadedLDAP) { DeinitLDAPClientLib(); }
LeaveCriticalSection(&lpCONTAINER->cs); DeleteCriticalSection(&lpCONTAINER->cs); // Need to free the object
FreeBufferAndNull(&lpCONTAINER); return(0); }
LeaveCriticalSection(&lpCONTAINER->cs); return(lpCONTAINER->lcInit); }
/*
* IMAPIProp */
/***************************************************************************
Name : CONTAINER::OpenProperty
Purpose : Opens an object interface on a particular property
Parameters: lpCONTAINER -> Container object ulPropTag = property to open lpiid -> requested interface ulInterfaceOptions = ulFlags = lppUnk -> returned object
Returns : HRESULT
Comment :
***************************************************************************/ STDMETHODIMP CONTAINER_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
hr = ResultFromScode(MAPI_E_INVALID_PARAMETER); return(hr); }
if ((ulInterfaceOptions & ~(MAPI_UNICODE)) || (ulFlags & ~(MAPI_DEFERRED_ERRORS))) { return(hr = ResultFromScode(MAPI_E_UNKNOWN_FLAGS)); }
if (FBadOpenProperty(lpCONTAINER, ulPropTag, lpiid, ulInterfaceOptions, ulFlags, lppUnk)) { return(ResultFromScode(MAPI_E_INVALID_PARAMETER)); }
#endif // PARAMETER_VALIDATION
#ifdef IABCONTAINER_OPENPROPERTY_SUPPORT // ??Were we supporting this? - vm 3/25/97??
EnterCriticalSection(&lpCONTAINER->cs);
lpIAB = lpCONTAINER->lpIAB;
//
// Check to see if I need a display table
//
if (ulPropTag == PR_CREATE_TEMPLATES) { //
// Looking for the display table
//
//
// 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; }
// Check to see if we already have a table
EnterCriticalSection(&lpIAB->cs);
//
// Get a view from the TAD
//
hr = lpIAB->lpOOData->lpVtbl->HrGetView( lpIAB->lpOOData, (LPSSortOrderSet)&sosPR_ROWID, NULL, 0, (LPMAPITABLE *)lppUnk);
// Leave the critical section after we get our view.
LeaveCriticalSection(&lpIAB->cs);
#ifdef DEBUG
if (hr == hrSuccess) { MAPISetBufferName(*lppUnk, TEXT("OneOff Data VUE1 Object")); } #endif
goto err; // Maybe error, maybe not...
} 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 = lpCONTAINER->lpVtbl->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 = lpCONTAINER->lpVtbl->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);
#else // IABCONTAINER_OPENPROPERTY_SUPPORT
hr = ResultFromScode(MAPI_E_NO_SUPPORT);
#endif // IABCONTAINER_OPENPROPERTY_SUPPORT
DebugTraceResult(CONTAINER_OpenProperty, hr); return(hr); }
/***************************************************************************
Name : CONTAINER_GetGetIDsFromNames
Returns : HRESULT
Comment : Just default this to the standard GetIdsFromNames that we use everywhere
***************************************************************************/ STDMETHODIMP CONTAINER_GetIDsFromNames(LPCONTAINER lpRoot, ULONG cPropNames, LPMAPINAMEID * lppPropNames, ULONG ulFlags, LPSPropTagArray * lppPropTags) { return HrGetIDsFromNames(lpRoot->lpIAB, cPropNames, lppPropNames, ulFlags, lppPropTags); }
/*
- - HrDupeOutlookContentsTable * * Since Outlook is unable to provide a Unicode contents table and we can't fo into the * outlook contents table to modify it's data, we have to recreate the contentstable to * create a WAB version of it .. * This is likely to be a big performance issue .. :-( * */ HRESULT HrDupeOutlookContentsTable(LPMAPITABLE lpOlkTable, LPMAPITABLE * lppTable) { HRESULT hr = S_OK; ULONG ulCount = 0, iRow = 0; DWORD dwIndex = 0; LPSRowSet lpsRow = 0, lpSRowSet = NULL; ULONG ulCurrentRow = (ULONG)-1; ULONG ulNum, ulDen, lRowsSeeked; LPTABLEDATA lpTableData = NULL; SCODE sc = 0; // Create a table object
if (FAILED(sc = CreateTable( NULL, // LPCIID
(ALLOCATEBUFFER FAR *) MAPIAllocateBuffer, (ALLOCATEMORE FAR *) MAPIAllocateMore, MAPIFreeBuffer, NULL, // lpvReserved,
TBLTYPE_DYNAMIC, // ulTableType,
PR_ENTRYID, // ulPropTagIndexCol,
(LPSPropTagArray)&ITableColumnsRoot, // LPSPropTagArray lpptaCols,
&lpTableData))) { DebugTrace(TEXT("CreateTable failed %x\n"), sc); hr = ResultFromScode(sc); goto out; } Assert(lpTableData);
((TAD *)lpTableData)->bMAPIUnicodeTable = TRUE; //this is only called for retreiving unicode tables so the flag is true
// How big is the outlook table?
if(HR_FAILED(hr = lpOlkTable->lpVtbl->GetRowCount(lpOlkTable, 0, &ulCount))) goto out;
DebugTrace( TEXT("Table contains %u rows\n"), ulCount);
// Allocate the SRowSet
if (FAILED(sc = MAPIAllocateBuffer(sizeof(SRowSet) + ulCount * sizeof(SRow),&lpSRowSet))) { DebugTrace(TEXT("Allocation of SRowSet -> %x\n"), sc); hr = ResultFromScode(sc); goto out; }
MAPISetBufferName(lpSRowSet, TEXT("Outlook_ContentsTable_Copy SRowSet")); ZeroMemory( lpSRowSet, (UINT) (sizeof(SRowSet) + ulCount * sizeof(SRow)));
lpSRowSet->cRows = ulCount; iRow = 0;
// Copy UNICODE versions of all the properties from the Outlook table
for (dwIndex = 0; dwIndex < ulCount; dwIndex++) { // Get the next row
if(HR_FAILED(hr = lpOlkTable->lpVtbl->QueryRows(lpOlkTable, 1, 0, &lpsRow))) goto out;
if (lpsRow) { LPSPropValue lpSPVNew = NULL;
Assert(lpsRow->cRows == 1); // should have exactly one row
///****INVESTIGATE if we can reuse this prop array without duplicating***/
if(HR_FAILED(hr = HrDupeOlkPropsAtoWC(lpsRow->aRow[0].cValues, lpsRow->aRow[0].lpProps, &lpSPVNew))) goto out;
// Attach the props to the SRowSet
lpSRowSet->aRow[iRow].lpProps = lpSPVNew; lpSRowSet->aRow[iRow].cValues = lpsRow->aRow[0].cValues; lpSRowSet->aRow[iRow].ulAdrEntryPad = 0;
FreeProws(lpsRow);
iRow++; } }
// Add all this data we just created to the the Table.
if (hr = lpTableData->lpVtbl->HrModifyRows(lpTableData, 0, lpSRowSet)) { DebugTraceResult( TEXT("ROOT_GetContentsTable:HrModifyRows"), hr); goto out; }
hr = lpTableData->lpVtbl->HrGetView(lpTableData, NULL, ContentsViewGone, 0, lppTable);
out:
FreeProws(lpSRowSet);
// Cleanup table if failure
if (HR_FAILED(hr)) { if (lpTableData) { UlRelease(lpTableData); } } return hr; }
/***************************************************************************
Name : CONTAINER::GetContentsTable
Purpose : Opens a table of the contents of the container.
Parameters: lpCONTAINER -> Container object
ulFlags = WAB_PROFILE_CONTENTS - When caller opens the PAB container and want's to get the complete set of contents for the current identity without wanting to enumerate each sub-container seperately - they can specify this flag and we'll return everything corresponding to the current identity all in the same table WAB_CONTENTTABLE_NODATA - Internal only flag .. GetContentsTable normally loads a full contents table and if this is followed by SetColumns, SetColumns also loads a full contents table .. so we basically do the same work twice - to reduce this wasted work, caller can specify not to load data the first time but caller must call SetColumns immediately (or this will probably fault) lppTable -> returned table object
Returns : HRESULT
Comment :
***************************************************************************/ STDMETHODIMP CONTAINER_GetContentsTable (LPCONTAINER lpCONTAINER, ULONG ulFlags, LPMAPITABLE * lppTable) {
HRESULT hResult; LPPTGDATA lpPTGData=GetThreadStoragePointer();
#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|WAB_PROFILE_CONTENTS|WAB_CONTENTTABLE_NODATA)) { DebugTraceArg(CONTAINER_GetContentsTable, TEXT("Unknown flags")); //return(ResultFromScode(MAPI_E_UNKNOWN_FLAGS));
}
if (IsBadWritePtr(lppTable, sizeof(LPMAPITABLE))) { DebugTraceArg(CONTAINER_GetContentsTable, TEXT("Invalid Flags")); return(ResultFromScode(MAPI_E_INVALID_PARAMETER)); }
#endif // PARAMETER_VALIDATION
if(pt_bIsWABOpenExSession) { ULONG ulOlkFlags = ulFlags;
// This is a WABOpenEx session using outlooks storage provider
if(!lpCONTAINER->lpIAB->lpPropertyStore->hPropertyStore) return MAPI_E_NOT_INITIALIZED;
// Since the Outlook store doesn't understand the private flags, these
// flags need to be filtered out otherwise the outlook store
// provider will fail with E_INVALIDARG or something
//
if(ulOlkFlags & WAB_PROFILE_CONTENTS) ulOlkFlags &= ~WAB_PROFILE_CONTENTS; if(ulOlkFlags & WAB_CONTENTTABLE_NODATA) ulOlkFlags &= ~WAB_CONTENTTABLE_NODATA;
if(ulFlags & MAPI_UNICODE && !pt_bIsUnicodeOutlook) { // This version of Outlook can't handle Unicode so don't tell it to else it'll barf
ulOlkFlags &= ~MAPI_UNICODE; } // Outlook provides it's own implementation of GetContentsTable for
// efficiencies sake otherwise recreating the table going through the
// WAB layer would be just too darned slow ...
{ LPWABSTORAGEPROVIDER lpWSP = (LPWABSTORAGEPROVIDER) lpCONTAINER->lpIAB->lpPropertyStore->hPropertyStore;
Assert((lpCONTAINER->ulType == AB_PAB) || (lpCONTAINER->ulType == AB_CONTAINER));
hResult = lpWSP->lpVtbl->GetContentsTable(lpWSP, lpCONTAINER->pmbinOlk, ulOlkFlags, lppTable);
DebugPrintTrace((TEXT("WABStorageProvider::GetContentsTable returned:%x\n"),hResult));
if( ulFlags & MAPI_UNICODE && !pt_bIsUnicodeOutlook && *lppTable && !HR_FAILED(hResult)) { // This version of Outlook can't handle Unicode
// but caller wants unicode, so now we have to go in and tweak this data
// manually ..
LPMAPITABLE lpWABTable = NULL;
if(!HR_FAILED(hResult = HrDupeOutlookContentsTable(*lppTable, &lpWABTable))) { (*lppTable)->lpVtbl->Release(*lppTable); *lppTable = lpWABTable; }
}
return hResult; } }
// Create a new contents table object
hResult = NewContentsTable((LPABCONT)lpCONTAINER, lpCONTAINER->lpIAB, ulFlags, NULL, lppTable);
if(!(HR_FAILED(hResult)) && *lppTable && (ulFlags & WAB_PROFILE_CONTENTS) && !(ulFlags & WAB_CONTENTTABLE_NODATA)) { // There is a problem with searching multiple subfolders in that the data does not
// come back sorted when it is collated across multiple folders.
// We need to sort the table before we return it .. it's somewhat inefficient to do this
// sort at this point .. ideally the data should be added to the table sorted...
LPSSortOrderSet lpSortCriteria = NULL; SCODE sc = MAPIAllocateBuffer(sizeof(SSortOrderSet)+sizeof(SSortOrder), &lpSortCriteria); if(!sc) { lpSortCriteria->cCategories = lpSortCriteria->cExpanded = 0; lpSortCriteria->cSorts = 1; lpSortCriteria->aSort[0].ulPropTag = PR_DISPLAY_NAME; if(!(((LPTAD)(*lppTable))->bMAPIUnicodeTable)) lpSortCriteria->aSort[0].ulPropTag = CHANGE_PROP_TYPE( lpSortCriteria->aSort[0].ulPropTag, PT_STRING8); lpSortCriteria->aSort[0].ulOrder = TABLE_SORT_ASCEND; hResult = (*lppTable)->lpVtbl->SortTable((*lppTable), lpSortCriteria, 0); FreeBufferAndNull(&lpSortCriteria); } else { hResult = MAPI_E_NOT_ENOUGH_MEMORY; } } return(hResult); }
/***************************************************************************
Name : CONTAINER::GetHierarchyTable
Purpose : Returns the merge of all the root hierarchy tables
Parameters: lpCONTAINER -> Container object ulFlags = lppTable -> returned table object
Returns : HRESULT
Comment :
***************************************************************************/ STDMETHODIMP CONTAINER_GetHierarchyTable (LPCONTAINER lpCONTAINER, ULONG ulFlags, LPMAPITABLE * lppTable) { LPTSTR lpszMessage = NULL; ULONG ulLowLevelError = 0; HRESULT hr = hrSuccess;
#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))) { return(ResultFromScode(MAPI_E_INVALID_PARAMETER)); }
// Check flags:
// The only valid flags are CONVENIENT_DEPTH and MAPI_DEFERRED_ERRORS
if (ulFlags & ~(CONVENIENT_DEPTH|MAPI_DEFERRED_ERRORS|MAPI_UNICODE)) { DebugTraceArg(CONTAINER_GetHierarchyTable, TEXT("Invalid Flags")); // return(ResultFromScode(MAPI_E_UNKNOWN_FLAGS));
}
#endif
EnterCriticalSection(&lpCONTAINER->cs);
if (lpCONTAINER->ulType != AB_ROOT) { //
// Wrong version of this object. Pretend this object doesn't exist.
//
hr = ResultFromScode(MAPI_E_NO_SUPPORT); goto out; }
//
// Get a view from the TAD
//
hr = lpCONTAINER->lpIAB->lpTableData->lpVtbl->HrGetView( lpCONTAINER->lpIAB->lpTableData, (LPSSortOrderSet) &sosPR_ROWID, NULL, 0, lppTable);
if (HR_FAILED(hr)) { 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);
DebugTraceResult(CONTAINER_GetHierarchyTable, hr); return(hr); }
/***************************************************************************
Name : HrMergeTableRows
Purpose : Creates a merged hierarchy r of all the root level hierarchies from the AB providers installed.
Parameters: lptadDst -> TABLEDATA object lpmtSrc -> source hierarchy table ulProviderNum =
Returns : HRESULT
Comment : NOTE: This may be irrelevant for WAB.
***************************************************************************/ HRESULT HrMergeTableRows(LPTABLEDATA lptadDst, LPMAPITABLE lpmtSrc, ULONG ulProviderNum) { HRESULT hResult = hrSuccess; SCODE sc; ULONG ulRowID = ulProviderNum * ((LONG)IAB_PROVIDER_HIERARCHY_MAX + 1); LPSRowSet lpsRowSet = NULL; LPSRow lprowT;
if (hResult = HrQueryAllRows(lpmtSrc, NULL, NULL, NULL, 0, &lpsRowSet)) { DebugTrace(TEXT("HrMergeTableRows() - Could not query provider rows.\n")); goto ret; }
if (lpsRowSet->cRows >= IAB_PROVIDER_HIERARCHY_MAX) { DebugTrace(TEXT("HrMergeTableRows() - Provider has too many rows.\n")); hResult = ResultFromScode(MAPI_E_TABLE_TOO_BIG); goto ret; }
// Set the ROWID to the end since will be looping in reverse order.
ulRowID = ulProviderNum * ((LONG) IAB_PROVIDER_HIERARCHY_MAX + 1) + lpsRowSet->cRows; for (lprowT = lpsRowSet->aRow + lpsRowSet->cRows; --lprowT >= lpsRowSet->aRow;) { ULONG cbInsKey; LPBYTE lpbNewKey = NULL;
// Make ulRowID zero based
ulRowID--;
//
// Munge the PR_INSTANCE_KEY
//
if ((lprowT->lpProps[0].ulPropTag != PR_INSTANCE_KEY) || !(cbInsKey = lprowT->lpProps[0].Value.bin.cb) || ((cbInsKey + sizeof(ULONG)) > UINT_MAX) || IsBadReadPtr(lprowT->lpProps[0].Value.bin.lpb, (UINT) cbInsKey)) { // Can't create our INSTANCE_KEY without a valid provider
// INSTANCE_KEY
DebugTrace(TEXT("HrMergeTableRows - Provider row has no valid PR_INSTANCE_KEY")); continue; }
// Allocate a new buffer for munging the instance key
if (FAILED(sc = MAPIAllocateMore(cbInsKey + sizeof(ULONG), lprowT->lpProps, &lpbNewKey))) { hResult = ResultFromScode(sc); DebugTrace(TEXT("HrMergeTableRows() - MAPIAllocMore Failed")); goto ret; }
*((LPULONG) lpbNewKey) = ulProviderNum; CopyMemory(lpbNewKey + sizeof(ULONG), lprowT->lpProps[0].Value.bin.lpb, cbInsKey); lprowT->lpProps[0].ulPropTag = PR_INSTANCE_KEY; lprowT->lpProps[0].Value.bin.lpb = lpbNewKey; lprowT->lpProps[0].Value.bin.cb = cbInsKey + sizeof(ULONG);
// Add the ROWID so that the original order of the providers is
// preserved
Assert((PROP_ID(lprowT->lpProps[1].ulPropTag) == PROP_ID(PR_ROWID)) || (PROP_ID(lprowT->lpProps[1].ulPropTag) == PROP_ID(PR_NULL))); lprowT->lpProps[1].ulPropTag = PR_ROWID; lprowT->lpProps[1].Value.l = ulRowID; }
// Now put them into the TAD all at once.
// Note! We now rely on PR_ROWID to keep the rows in order
if (HR_FAILED(hResult = lptadDst->lpVtbl->HrModifyRows(lptadDst, 0, lpsRowSet))) { DebugTrace(TEXT("HrMergeTableRows() - Failed to modify destination TAD.\n")); }
ret: //
// Free up the row set
//
FreeProws(lpsRowSet);
return(hResult); }
/***************************************************************************
Name : CONTAINER::OpenEntry
Purpose : Opens an entry
Parameters: lpCONTAINER -> Container object cbEntryID = size of entryid lpEntryID -> EntryID to open lpInterface -> requested interface or NULL for default. ulFlags = lpulObjType -> returned object type lppUnk -> returned object
Returns : HRESULT
Comment : Calls up to IAB's OpenEntry.
***************************************************************************/ STDMETHODIMP CONTAINER_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, CONTAINER_, 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(CONTAINER_OpenEntry, TEXT("lpEntryID fails address check")); return(ResultFromScode(MAPI_E_INVALID_ENTRYID)); }
NFAssertSz(FValidEntryIDFlags(lpEntryID->abFlags), TEXT("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(CONTAINER_OpenEntry, TEXT("lpInterface fails address check")); return(ResultFromScode(MAPI_E_INVALID_PARAMETER)); }
if (ulFlags & ~(MAPI_MODIFY | MAPI_DEFERRED_ERRORS | MAPI_BEST_ACCESS)) { DebugTraceArg(CONTAINER_OpenEntry, TEXT("Unknown flags used")); // return(ResultFromScode(MAPI_E_UNKNOWN_FLAGS));
}
if (IsBadWritePtr((LPVOID)lpulObjType, sizeof(ULONG))) { DebugTraceArg(CONTAINER_OpenEntry, TEXT("lpulObjType")); return(ResultFromScode(MAPI_E_INVALID_PARAMETER)); }
if (IsBadWritePtr((LPVOID)lppUnk, sizeof(LPUNKNOWN))) { DebugTraceArg(CONTAINER_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 CONTAINER_SetSearchCriteria(LPCONTAINER lpCONTAINER, LPSRestriction lpRestriction, LPENTRYLIST lpContainerList, ULONG ulSearchFlags) {
#ifdef PARAMETER_VALIDATION
// Validate the object.
if (BAD_STANDARD_OBJ(lpCONTAINER, CONTAINER_, SetSearchCriteria, lpVtbl)) { // jump table not large enough to support this method
DebugTraceArg(CONTAINER_SetSearchCriteria, TEXT("Bad object/vtble")); return(ResultFromScode(MAPI_E_INVALID_PARAMETER)); }
// ensure we can read the restriction
if (lpRestriction && IsBadReadPtr(lpRestriction, sizeof(SRestriction))) { DebugTraceArg(CONTAINER_SetSearchCriteria, TEXT("Bad Restriction parameter")); return(ResultFromScode(MAPI_E_INVALID_PARAMETER)); }
if (FBadEntryList(lpContainerList)) { DebugTraceArg(CONTAINER_SetSearchCriteria, TEXT("Bad ContainerList parameter")); return(ResultFromScode(MAPI_E_INVALID_PARAMETER)); }
if (ulSearchFlags & ~(STOP_SEARCH | RESTART_SEARCH | RECURSIVE_SEARCH | SHALLOW_SEARCH | FOREGROUND_SEARCH | BACKGROUND_SEARCH)) { DebugTraceArg(CONTAINER_GetSearchCriteria, TEXT("Unknown flags used")); // return(ResultFromScode(MAPI_E_UNKNOWN_FLAGS));
} #endif // PARAMETER_VALIDATION
return(ResultFromScode(MAPI_E_NO_SUPPORT)); }
/***************************************************************************
Name : CONTAINER::GetSearchCriteria
Purpose :
Parameters: lpCONTAINER -> Container object ulFlags = lppRestriction -> Restriction to apply to searches lppContainerList -> lpulSearchState -> returned state
Returns : HRESULT
Comment : Not implemented in WAB.
***************************************************************************/ STDMETHODIMP CONTAINER_GetSearchCriteria(LPCONTAINER lpCONTAINER, ULONG ulFlags, LPSRestriction FAR * lppRestriction, LPENTRYLIST FAR * lppContainerList, ULONG FAR * lpulSearchState) { #ifdef PARAMETER_VALIDATION
// Validate the object.
if (BAD_STANDARD_OBJ(lpCONTAINER, CONTAINER_, GetSearchCriteria, lpVtbl)) { // jump table not large enough to support this method
DebugTraceArg(CONTAINER_GetSearchCriteria, TEXT("Bad object/vtble")); return(ResultFromScode(MAPI_E_INVALID_PARAMETER)); }
if (ulFlags & ~(MAPI_UNICODE)) { DebugTraceArg(CONTAINER_GetSearchCriteria, TEXT("Unknown Flags")); // return(ResultFromScode(MAPI_E_UNKNOWN_FLAGS));
}
// ensure we can write the restriction
if (lppRestriction && IsBadWritePtr(lppRestriction, sizeof(LPSRestriction))) { DebugTraceArg(CONTAINER_GetSearchCriteria, TEXT("Bad Restriction write parameter")); return(ResultFromScode(MAPI_E_INVALID_PARAMETER)); }
// ensure we can read the container list
if (lppContainerList && IsBadWritePtr(lppContainerList, sizeof(LPENTRYLIST))) { DebugTraceArg(CONTAINER_GetSearchCriteria, TEXT("Bad ContainerList parameter")); return(ResultFromScode(MAPI_E_INVALID_PARAMETER)); }
if (lpulSearchState && IsBadWritePtr(lpulSearchState, sizeof(ULONG))) { DebugTraceArg(CONTAINER_GetSearchCriteria, TEXT("lpulSearchState fails address check")); return(ResultFromScode(MAPI_E_INVALID_PARAMETER)); }
#endif // PARAMETER_VALIDATION
return(ResultFromScode(MAPI_E_NO_SUPPORT)); }
/***************************************************************************
Name : CONTAINER::CreateEntry
Purpose : Creates an entry in the container
Parameters: lpCONTAINER -> Container object cbEntryID = size of entryid lpEntryID -> entryID of template [ cbEID and lpEID are the Template Entryids In reality, these are actually flags that just tell us internally what kind of object to create ]
ulCreateFlags = lppMAPIPropEntry -> returned MAPIProp object
Returns : HRESULT
Comment :
***************************************************************************/ STDMETHODIMP CONTAINER_CreateEntry(LPCONTAINER lpCONTAINER, ULONG cbEntryID, LPENTRYID lpEntryID, ULONG ulCreateFlags, LPMAPIPROP FAR * lppMAPIPropEntry) { BYTE bType;
#ifdef PARAMETER_VALIDATION
// Validate the object.
if (BAD_STANDARD_OBJ(lpCONTAINER, CONTAINER_, CreateEntry, lpVtbl)) { // jump table not large enough to support this method
DebugTraceArg(CONTAINER_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(CONTAINER_CreateEntry, TEXT("lpEntryID fails address check")); return(ResultFromScode(MAPI_E_INVALID_ENTRYID)); }
//NFAssertSz(FValidEntryIDFlags(lpEntryID->abFlags),
// TEXT("Undefined bits set in EntryID flags\n"));
} else { DebugTraceArg(CONTAINER_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(CONTAINER_CreateEntry, TEXT("Unknown flags used")); // return(ResultFromScode(MAPI_E_UNKNOWN_FLAGS));
}
if (IsBadWritePtr(lppMAPIPropEntry, sizeof(LPMAPIPROP))) { DebugTraceArg(CONTAINER_CreateEntry, TEXT("Bad MAPI Property write parameter")); return(ResultFromScode(MAPI_E_INVALID_PARAMETER)); } #endif // PARAMETER_VALIDATION
#ifdef NEVER
if (lpCONTAINER->ulType == AB_ROOT) return ResultFromScode(MAPI_E_NO_SUPPORT); #endif // NEVER
// What kind of entry are we creating?
// Default is MailUser
// The passed in entryid is the Tempalte entry ID
bType = IsWABEntryID(cbEntryID, lpEntryID, NULL, NULL, NULL, NULL, NULL);
if (bType == WAB_DEF_MAILUSER || cbEntryID == 0) { //
// Create a new (in memory) entry and return it's mapiprop
//
return(HrNewMAILUSER(lpCONTAINER->lpIAB, lpCONTAINER->pmbinOlk, MAPI_MAILUSER, ulCreateFlags, lppMAPIPropEntry)); } else if (bType == WAB_DEF_DL) { //
// Create a new (in memory) distribution list and return it's mapiprop?
return(HrNewMAILUSER(lpCONTAINER->lpIAB, lpCONTAINER->pmbinOlk, MAPI_DISTLIST, ulCreateFlags, lppMAPIPropEntry)); } else { DebugTrace(TEXT("CONTAINER_CreateEntry got unknown template entryID\n")); return(ResultFromScode(MAPI_E_INVALID_ENTRYID)); } }
/***************************************************************************
Name : CONTAINER::CopyEntries
Purpose : Copies a list of entries into this container.
Parameters: lpCONTAINER -> Container object lpEntries -> List of entryid's to copy ulUIParam = HWND lpPropgress -> progress dialog structure ulFlags =
Returns : HRESULT
Comment : Not implemented in WAB.
***************************************************************************/ STDMETHODIMP CONTAINER_CopyEntries(LPCONTAINER lpCONTAINER, LPENTRYLIST lpEntries, ULONG_PTR ulUIParam, LPMAPIPROGRESS lpProgress, ULONG ulFlags) { #ifdef PARAMETER_VALIDATION
if (BAD_STANDARD_OBJ(lpCONTAINER, CONTAINER_, CopyEntries, lpVtbl)) { // jump table not large enough to support this method
DebugTraceArg(CONTAINER_CopyEntries, TEXT("Bad object/vtbl")); return(ResultFromScode(MAPI_E_INVALID_PARAMETER)); }
// ensure we can read the container list
if (FBadEntryList(lpEntries)) { DebugTraceArg(CONTAINER_CopyEntries, TEXT("Bad Entrylist parameter")); return(ResultFromScode(MAPI_E_INVALID_PARAMETER)); }
if (ulUIParam && ! IsWindow((HWND)ulUIParam)) { DebugTraceArg(CONTAINER_CopyEntries, TEXT("Invalid window handle")); return(ResultFromScode(MAPI_E_INVALID_PARAMETER)); }
if (lpProgress && IsBadReadPtr(lpProgress, sizeof(IMAPIProgress))) { DebugTraceArg(CONTAINER_CopyEntries, TEXT("Bad MAPI Progress parameter")); return(ResultFromScode(MAPI_E_INVALID_PARAMETER)); }
if (ulFlags & ~(AB_NO_DIALOG | CREATE_CHECK_DUP_LOOSE)) { DebugTraceArg(CONTAINER_CreateEntry, TEXT("Unknown flags used")); // return(ResultFromScode(MAPI_E_UNKNOWN_FLAGS));
} #endif // PARAMETER_VALIDATION
return(ResultFromScode(MAPI_E_NO_SUPPORT)); }
/***************************************************************************
Name : CONTAINER::DeleteEntries
Purpose : Delete entries from this container.
Parameters: lpCONTAINER -> Container object lpEntries -> list of entryid's to delete ulFlags =
Returns : HRESULT
Comment :
***************************************************************************/ STDMETHODIMP CONTAINER_DeleteEntries(LPCONTAINER lpCONTAINER, LPENTRYLIST lpEntries, ULONG ulFlags) { ULONG i; HRESULT hResult = hrSuccess; ULONG cDeleted = 0; ULONG cToDelete;
#ifndef DONT_ADDREF_PROPSTORE
{ SCODE sc; if ((FAILED(sc = OpenAddRefPropertyStore(NULL, lpCONTAINER->lpIAB->lpPropertyStore)))) { hResult = ResultFromScode(sc); goto exitNotAddRefed; } } #endif
#ifdef PARAMETER_VALIDATION
if (BAD_STANDARD_OBJ(lpCONTAINER, CONTAINER_, DeleteEntries, lpVtbl)) { // jump table not large enough to support this method
DebugTraceArg(CONTAINER_DeleteEntries, TEXT("Bad object/vtbl")); return(ResultFromScode(MAPI_E_INVALID_PARAMETER)); }
// ensure we can read the container list
if (FBadEntryList(lpEntries)) { DebugTraceArg(CONTAINER_DeleteEntries, TEXT("Bad Entrylist parameter")); return(ResultFromScode(MAPI_E_INVALID_PARAMETER)); }
if (ulFlags) { DebugTraceArg(CONTAINER_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.
cToDelete = lpEntries->cValues;
// Delete each entry
for (i = 0; i < cToDelete; i++) { if(0 != IsWABEntryID(lpEntries->lpbin[i].cb, (LPENTRYID) lpEntries->lpbin[i].lpb, NULL, NULL, NULL, NULL, NULL)) { DebugTrace(TEXT("CONTAINER_DeleteEntries got bad entryid of size %u\n"), lpEntries->lpbin[i].cb); continue; }
hResult = DeleteCertStuff((LPADRBOOK)lpCONTAINER->lpIAB, (LPENTRYID)lpEntries->lpbin[i].lpb, lpEntries->lpbin[i].cb);
hResult = HrSaveHotmailSyncInfoOnDeletion((LPADRBOOK) lpCONTAINER->lpIAB, &(lpEntries->lpbin[i]));
if (HR_FAILED(hResult = DeleteRecord(lpCONTAINER->lpIAB->lpPropertyStore->hPropertyStore, &(lpEntries->lpbin[i])))) { DebugTraceResult( TEXT("DeleteEntries: DeleteRecord"), hResult); continue; } cDeleted++; }
if (! hResult) { if (cDeleted != cToDelete) { hResult = ResultFromScode(MAPI_W_PARTIAL_COMPLETION); DebugTrace(TEXT("DeleteEntries deleted %u of requested %u\n"), cDeleted, cToDelete); } }
#ifndef DONT_ADDREF_PROPSTORE
ReleasePropertyStore(lpCONTAINER->lpIAB->lpPropertyStore); exitNotAddRefed: #endif
return(hResult); }
/***************************************************************************
Name : CONTAINER::ResolveNames
Purpose : Resolve names from this container.
Parameters: lpCONTAINER -> Container object lptagColSet -> Set of property tags to get from each resolved match. ulFlags = flags (none valid) WAB_IGNORE_PROFILES means that even if this is a profile enabled session, search the whole WAB, not just the current container WAB_RESOLVE_ALL_EMAILS - valid if trying to resolve an e-mail address and we want to search across all e-mail addresses not just the default. Should be used sparingly since it's a labor intensive search MAPI_UNICODE - Adrlist strings are in UNICODE and should return them in Unicode lpAdrList -> [in] set of addresses to resolve, [out] resolved addresses. lpFlagList -> [in/out] resolve flags.
Returns : HRESULT
Comment :
***************************************************************************/ STDMETHODIMP CONTAINER_ResolveNames(LPCONTAINER lpRoot, LPSPropTagArray lptagaColSet, ULONG ulFlags, LPADRLIST lpAdrList, LPFlagList lpFlagList) { LPADRENTRY lpAdrEntry; ULONG i, j; ULONG ulCount = 1; LPSBinary rgsbEntryIDs = NULL; HRESULT hResult = hrSuccess; LPMAPIPROP lpMailUser = NULL; LPSPropTagArray lpPropTags; LPSPropValue lpPropArray = NULL; LPSPropValue lpPropArrayNew = NULL; ULONG ulObjType, cPropsNew; ULONG cValues; SCODE sc = SUCCESS_SUCCESS; LPTSTR lpsz = NULL;
#ifndef DONT_ADDREF_PROPSTORE
if ((FAILED(sc = OpenAddRefPropertyStore(NULL, lpRoot->lpIAB->lpPropertyStore)))) { hResult = ResultFromScode(sc); goto exitNotAddRefed; } #endif
#ifdef PARAMETER_VALIDATION
if (BAD_STANDARD_OBJ(lpRoot, CONTAINER_, ResolveNames, lpVtbl)) { // jump table not large enough to support this method
DebugTraceArg(CONTAINER_ResolveNames, TEXT("Bad object/vtbl")); return(ResultFromScode(MAPI_E_INVALID_PARAMETER)); }
// BUGBUG: Should also check lptagColSet, lpAdrList and lpFlagList!
if (ulFlags&(~(WAB_IGNORE_PROFILES|WAB_RESOLVE_ALL_EMAILS|MAPI_UNICODE))) { DebugTraceArg(CONTAINER_ResolveNames, TEXT("Unknown flags used")); // return(ResultFromScode(MAPI_E_UNKNOWN_FLAGS));
}
#endif // PARAMETER_VALIDATION
// if no set of props to return is specified, return the default set
lpPropTags = lptagaColSet ? lptagaColSet : (LPSPropTagArray)&ptaResolveDefaults;
if(ulFlags & WAB_RESOLVE_ALL_EMAILS) { hResult = HrSmartResolve(lpRoot->lpIAB, (LPABCONT)lpRoot, WAB_RESOLVE_ALL_EMAILS | (ulFlags & MAPI_UNICODE ? WAB_RESOLVE_UNICODE : 0), lpAdrList, lpFlagList, NULL); // If it's too complex, then just search normally
if (MAPI_E_TOO_COMPLEX != hResult) { goto exit; } else { hResult = hrSuccess; } }
// search for each name in the lpAdrList
for (i = 0; i < lpAdrList->cEntries; i++) {
// Make sure we don't resolve an entry which is already resolved.
if (lpFlagList->ulFlag[i] == MAPI_RESOLVED) { continue; }
lpAdrEntry = &(lpAdrList->aEntries[i]);
// Search for this address
// BUGBUG: For now, we only resolve perfect matches in the PR_DISPLAY_NAME or PR_EMAIL_ADDRESS
// all other properties in ADRLIST are ignored
// Look through the ADRENTRY for a PR_DISPLAY_NAME and create an SPropRestriction
// to pass down to the property store.
for (j = 0; j < lpAdrEntry->cValues; j++) { ULONG ulPropTag = lpAdrEntry->rgPropVals[j].ulPropTag; if(!(ulFlags & MAPI_UNICODE) && PROP_TYPE(ulPropTag)==PT_STRING8) ulPropTag = CHANGE_PROP_TYPE(ulPropTag, PT_UNICODE);
if ( ulPropTag == PR_DISPLAY_NAME || ulPropTag == PR_EMAIL_ADDRESS) { ULONG Flags = AB_FUZZY_FAIL_AMBIGUOUS | AB_FUZZY_FIND_ALL;
if(!(ulFlags & WAB_IGNORE_PROFILES)) { // if we didn't ask to surpress profile awareness,
// and profile awareness is enabled, restrict this search to
// the single folder
if(bAreWABAPIProfileAware(lpRoot->lpIAB)) Flags |= AB_FUZZY_FIND_PROFILEFOLDERONLY; }
ulCount = 1;
// Search the property store
Assert(lpRoot->lpIAB->lpPropertyStore->hPropertyStore);
if(ulFlags & MAPI_UNICODE) { lpsz = lpAdrEntry->rgPropVals[j].Value.lpszW; } else { LocalFreeAndNull(&lpsz); lpsz = ConvertAtoW(lpAdrEntry->rgPropVals[j].Value.lpszA); } if (HR_FAILED(hResult = HrFindFuzzyRecordMatches(lpRoot->lpIAB->lpPropertyStore->hPropertyStore, lpRoot->pmbinOlk, lpsz, Flags, &ulCount, // IN: number of matches to find, OUT: number found
&rgsbEntryIDs))) { if (ResultFromScode(hResult) == MAPI_E_AMBIGUOUS_RECIP) { lpFlagList->ulFlag[i] = MAPI_AMBIGUOUS; continue; } else { DebugTraceResult( TEXT("HrFindFuzzyRecordMatches"), hResult); goto exit; } }
if (ulCount) { // Was a match found?
Assert(rgsbEntryIDs); if (rgsbEntryIDs) { if (ulCount == 1) { // Open the entry and read the properties you care about.
if (HR_FAILED(hResult = lpRoot->lpVtbl->OpenEntry(lpRoot, rgsbEntryIDs[0].cb, // cbEntryID
(LPENTRYID)(rgsbEntryIDs[0].lpb), // entryid of first match
NULL, // interface
0, // ulFlags
&ulObjType, // returned object type
(LPUNKNOWN *)&lpMailUser))) { // Failed! Hmmm.
DebugTraceResult( TEXT("ResolveNames OpenEntry"), hResult); goto exit; }
Assert(lpMailUser);
if (HR_FAILED(hResult = lpMailUser->lpVtbl->GetProps(lpMailUser, lpPropTags, // lpPropTagArray
(ulFlags & MAPI_UNICODE) ? MAPI_UNICODE : 0, &cValues, // how many properties were there?
&lpPropArray))) { DebugTraceResult( TEXT("ResolveNames GetProps"), hResult); goto exit; }
UlRelease(lpMailUser); lpMailUser = NULL;
// Now, construct the new ADRENTRY
// (Allocate a new one, free the old one.
Assert(lpPropArray);
// Merge the new props with the ADRENTRY props
if (sc = ScMergePropValues(lpAdrEntry->cValues, lpAdrEntry->rgPropVals, // source1
cValues, lpPropArray, // source2
&cPropsNew, &lpPropArrayNew)) { goto exit; }
// [PaulHi] 2/1/99 GetProps now returns the requested tag string
// types. So if our client is non-UNICODE make sure we convert any
// UNICODE string properties to ANSI.
if (!(ulFlags & MAPI_UNICODE)) { if(sc = ScConvertWPropsToA((LPALLOCATEMORE) (&MAPIAllocateMore), (LPSPropValue ) lpPropArrayNew, (ULONG) cPropsNew, 0)) goto exit; }
// Free the original prop value array
FreeBufferAndNull((LPVOID *) (&(lpAdrEntry->rgPropVals)));
lpAdrEntry->cValues = cPropsNew; lpAdrEntry->rgPropVals = lpPropArrayNew;
FreeBufferAndNull(&lpPropArray);
// Mark this entry as found.
lpFlagList->ulFlag[i] = MAPI_RESOLVED; } else { DebugTrace(TEXT("ResolveNames found more than 1 match... MAPI_AMBIGUOUS\n")); lpFlagList->ulFlag[i] = MAPI_AMBIGUOUS; }
FreeEntryIDs(lpRoot->lpIAB->lpPropertyStore->hPropertyStore, ulCount, rgsbEntryIDs); } }
break; } } }
exit: #ifndef DONT_ADDREF_PROPSTORE
ReleasePropertyStore(lpRoot->lpIAB->lpPropertyStore); exitNotAddRefed: #endif
FreeBufferAndNull(&lpPropArray);
UlRelease(lpMailUser);
if(!(ulFlags & MAPI_UNICODE)) LocalFreeAndNull(&lpsz);
return(hResult); }
#ifdef NOTIFICATION // save for notifications
/***************************************************************************
Name : lTableNotifyCallBack
Purpose : Callback function for notifications
Parameters: lpvContext -> cNotif = lpNotif ->
Returns :
Comment :
***************************************************************************/ long STDAPICALLTYPE lTableNotifyCallBack(LPVOID lpvContext, ULONG cNotif, LPNOTIFICATION lpNotif) { LPTABLEINFO lpTableInfo = (LPTABLEINFO)lpvContext; HRESULT hResult; LPSRowSet lpsrowsetProv = NULL; LPIAB lpIAB = lpTableInfo->lpIAB; LPTABLEDATA lpTableData; ULONG ulcTableInfo; LPTABLEINFO pargTableInfo;
Assert(lpvContext); Assert(lpNotif); Assert(lpTableInfo->lpTable); Assert(lpTableInfo->lpIAB); Assert(! IsBadWritePtr(lpTableInfo->lpIAB, sizeof(IAB)));
// To avoid deadlock we will NOT enter the Address Books critical
// section. The Address Book must enter our critical section BEFORE
// it modifies anything our callback needs
// if the container is null then the tableinfo structure is being
// used to keep track of the open one off tables otherwise its
// being used to keep track of the open hierarchy tables.
if (lpTableInfo->lpContainer == NULL) { // open one off table data
lpTableData = lpIAB->lpOOData; ulcTableInfo = lpIAB->ulcOOTableInfo; pargTableInfo = lpIAB->pargOOTableInfo; } else { // open hierarchy table data
lpTableData =lpIAB->lpTableData; ulcTableInfo =lpIAB->ulcTableInfo; pargTableInfo =lpIAB->pargTableInfo;
// While we here, blow away the SearchPath cache
#if defined (WIN32) && !defined (MAC)
if (fGlobalCSValid) { EnterCriticalSection(&csMapiSearchPath); } else { DebugTrace(TEXT("lTableNotifyCallback: WAB32.DLL already detached.\n")); } #endif
FreeBufferAndNull(&(lpIAB->lpspvSearchPathCache)); lpIAB->lpspvSearchPathCache = NULL;
#if defined (WIN32) && !defined (MAC)
if (fGlobalCSValid) { LeaveCriticalSection(&csMapiSearchPath); } else { DebugTrace(TEXT("lTableNotifyCallback: WAB32.DLL got detached.\n")); } #endif
}
switch (lpNotif->info.tab.ulTableEvent) { case TABLE_ROW_ADDED: case TABLE_ROW_DELETED: case TABLE_ROW_MODIFIED: case TABLE_CHANGED: { ULONG uliTable;
// table has changed. We need to delete all the rows of
// this table in the tad and then add all the rows currently
// in that table to the tad. We need to find the start and
// end row indexes of the tables data in the tad.
// get the index of the given table in the table info array
for (uliTable=0; uliTable < ulcTableInfo; uliTable++) { if (pargTableInfo[uliTable].lpTable==lpTableInfo->lpTable) { break; } }
Assert(uliTable < ulcTableInfo);
// Delete all the rows of the table in the tad by querying
// all the rows from the TEXT("restricted") view for this provider
// and then calling HrDeleteRows.
// We'll add all the new rows back later
if (HR_FAILED(hResult = HrQueryAllRows(lpTableInfo->lpmtRestricted, NULL, NULL, NULL, 0, &lpsrowsetProv))) { DebugTrace(TEXT("lTableNotifyCallBack() - Can't query rows from restricted view.\n")); goto ret; }
if (lpsrowsetProv->cRows) { // Only call HrDeleteRows if there are rows to delete
if (HR_FAILED(hResult = lpTableData->lpVtbl->HrDeleteRows(lpTableData, 0, lpsrowsetProv, NULL))) { DebugTrace(TEXT("lTableNotifyCallBack() - Can't delete rows.\n")); goto ret; } }
// Add the contents of the provider table back to the TAD.
// Seek to the beginning of the input table
if (HR_FAILED(hResult = lpTableInfo->lpTable->lpVtbl->SeekRow(lpTableInfo->lpTable , BOOKMARK_BEGINNING, 0, NULL))) { // table must be empty
goto ret; }
// Add all rows from the given provider back to the merged table.
// NOTE! HrMergeTableRows takes a 1 based provider NUMBER not
// a provider index.
if (HR_FAILED(hResult = HrMergeTableRows(lpTableData, lpTableInfo->lpTable, uliTable + 1))) { //$BUG Handle per provider errors.
DebugTrace(TEXT("lTableNotifyCallBack() - HrMergeTableRows returns (hResult = 0x%08lX)\n"), hResult); }
break; } } ret: // free the row set returned from MAPITABLE::QueryRows
FreeProws(lpsrowsetProv);
return(0); }
/***************************************************************************
Name : HrGetBookmarkInTad
Purpose : Returns the row number in the tabledata object of the row that corresponds to the row at the bookmark in the given table.
Parameters: lpTableData -> lpTable -> Bookmark = puliRow ->
Returns : HRESULT
Comment :
***************************************************************************/ static HRESULT HrGetBookmarkInTad(LPTABLEDATA lpTableData, LPMAPITABLE lpTable, BOOKMARK Bookmark, ULONG * puliRow) { LPSRowSet lpsRowSet = NULL; LPSRow lpsRow; ULONG uliProp; HRESULT hResult = hrSuccess;
Assert(lpTableData); Assert(lpTable); Assert(puliRow);
// seek to the bookmark in the given table
if (HR_FAILED(hResult=lpTable->lpVtbl->SeekRow( lpTable, Bookmark, 0, NULL))) { goto err; }
// get the row
if (HR_FAILED(hResult=lpTable->lpVtbl->QueryRows( lpTable, (Bookmark==BOOKMARK_END ? -1 : 1), TBL_NOADVANCE, &lpsRowSet))) { goto err; }
// find the entryid in the property value array
for (uliProp = 0; uliProp < lpsRowSet->aRow[0].cValues; uliProp++) { if (lpsRowSet->aRow[0].lpProps[uliProp].ulPropTag == PR_ENTRYID) { break; } }
Assert(uliProp < lpsRowSet->aRow[0].cValues);
// Look for the row in the tad with the same entryid.
if (HR_FAILED(hResult=lpTableData->lpVtbl->HrQueryRow( lpTableData, lpsRowSet->aRow[0].lpProps+uliProp, &lpsRow, puliRow))) { // can't find the row in the table data should never happen
goto err; }
// free the row set returned from QueryRows on the tad
FreeBufferAndNull(&lpsRow);
err: // free the row set returned from MAPITABLE::QueryRows
FreeProws(lpsRowSet); return(hResult); } #endif
/*
- FindContainer - * Given an entryid, searches in the cached list of containers for * the structure containing the container so that we can get * additional container properties out of the strucutre painlessly * * Returns a pointer to an OlkContInfo structure so don't need to free * the returned value */ OlkContInfo *FindContainer(LPIAB lpIAB, ULONG cbEID, LPENTRYID lpEID) { ULONG iolkci, colkci; BOOL ul=FALSE; OlkContInfo *rgolkci;
Assert(lpIAB); Assert(lpIAB->lpPropertyStore);
// If the WAB session is Profile Aware, then the WAB's list of containers
// is cached on the IAB object
if(bIsWABSessionProfileAware(lpIAB)) { colkci = lpIAB->cwabci; rgolkci = lpIAB->rgwabci; } else // it's in the list of the Outlook containers
{ colkci = lpIAB->lpPropertyStore->colkci; rgolkci = lpIAB->lpPropertyStore->rgolkci; }
// if we didn't find any cached info, nothing more to do
if(!colkci || !rgolkci) return NULL;
for (iolkci = 1; iolkci < colkci; iolkci++) { Assert(rgolkci[iolkci].lpEntryID); if (rgolkci[iolkci].lpEntryID && (cbEID == rgolkci[iolkci].lpEntryID->cb)) { // Look for the match and return that item
Assert(rgolkci[iolkci].lpEntryID->lpb); if(cbEID && rgolkci[iolkci].lpEntryID->lpb && (0 == memcmp((LPVOID) lpEID,(LPVOID)rgolkci[iolkci].lpEntryID->lpb, cbEID))) { ul = TRUE; break; } } } return(ul ? &(rgolkci[iolkci]) : NULL); }
|