Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

2323 lines
79 KiB

/*
* 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);
}