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.
1037 lines
34 KiB
1037 lines
34 KiB
/*
|
|
* ABROOT.C
|
|
*
|
|
* IMAPIContainer implementation for the address book's root
|
|
* container.
|
|
*/
|
|
|
|
#include "_apipch.h"
|
|
|
|
extern SPropTagArray sosPR_ROWID;
|
|
|
|
/*
|
|
* Root jump table is defined here...
|
|
*/
|
|
|
|
ROOT_Vtbl vtblROOT =
|
|
{
|
|
VTABLE_FILL
|
|
(ROOT_QueryInterface_METHOD *) CONTAINER_QueryInterface,
|
|
(ROOT_AddRef_METHOD *) WRAP_AddRef,
|
|
(ROOT_Release_METHOD *) CONTAINER_Release,
|
|
(ROOT_GetLastError_METHOD *) IAB_GetLastError,
|
|
(ROOT_SaveChanges_METHOD *) WRAP_SaveChanges,
|
|
(ROOT_GetProps_METHOD *) WRAP_GetProps,
|
|
(ROOT_GetPropList_METHOD *) WRAP_GetPropList,
|
|
(ROOT_OpenProperty_METHOD *) CONTAINER_OpenProperty,
|
|
(ROOT_SetProps_METHOD *) WRAP_SetProps,
|
|
(ROOT_DeleteProps_METHOD *) WRAP_DeleteProps,
|
|
(ROOT_CopyTo_METHOD *) WRAP_CopyTo,
|
|
(ROOT_CopyProps_METHOD *) WRAP_CopyProps,
|
|
(ROOT_GetNamesFromIDs_METHOD *) WRAP_GetNamesFromIDs,
|
|
(ROOT_GetIDsFromNames_METHOD *) WRAP_GetIDsFromNames,
|
|
ROOT_GetContentsTable,
|
|
ROOT_GetHierarchyTable,
|
|
ROOT_OpenEntry,
|
|
ROOT_SetSearchCriteria,
|
|
ROOT_GetSearchCriteria,
|
|
ROOT_CreateEntry,
|
|
ROOT_CopyEntries,
|
|
ROOT_DeleteEntries,
|
|
ROOT_ResolveNames
|
|
};
|
|
|
|
|
|
//
|
|
// Interfaces supported by this object
|
|
//
|
|
#define ROOT_cInterfaces 3
|
|
LPIID ROOT_LPIID[ROOT_cInterfaces] =
|
|
{
|
|
(LPIID)&IID_IABContainer,
|
|
(LPIID)&IID_IMAPIContainer,
|
|
(LPIID)&IID_IMAPIProp
|
|
};
|
|
|
|
// Registry strings
|
|
const LPTSTR szWABKey = TEXT("Software\\Microsoft\\WAB");
|
|
|
|
// PR_AB_PROVIDER_ID for Outlook
|
|
static const MAPIUID muidCAB = {0xfd,0x42,0xaa,0x0a,0x18,0xc7,0x1a,0x10,0xe8,0x85,0x0B,0x65,0x1C,0x24,0x00,0x00};
|
|
|
|
/*
|
|
-
|
|
- SetContainerlpProps
|
|
*
|
|
* The ROOT container will have a bunch of entries with props for each entry
|
|
* The props are set in one place here
|
|
*
|
|
lpProps - LPSPropValue array in which we are storing the props
|
|
lpszName - Container name
|
|
iRow - Row of this entry in the table (?)
|
|
cb, lpb - entryid of the container
|
|
lpEID - alternat way of passing in the EID
|
|
ulContainerFlags - any flags we want to cache on the container
|
|
ulDepth ?
|
|
bProviderID ?
|
|
bLDAP - identifies LDAP containers which need some extra props
|
|
fLDAPResolve - whether the LDAP container is used for name resolution or not
|
|
|
|
*/
|
|
void SetContainerlpProps(LPSPropValue lpProps, LPTSTR lpszName, ULONG iRow,
|
|
ULONG cb, LPBYTE lpb, LPSBinary lpEID,
|
|
ULONG ulContainerFlags,
|
|
ULONG ulDepth, BOOL bProviderID,
|
|
ULONG ulFlags,
|
|
BOOL bLDAP, BOOL fLDAPResolve)
|
|
{
|
|
LPSTR lpszNameA = NULL;
|
|
|
|
if(!(ulFlags & MAPI_UNICODE)) // <note> this assumes UNICODE is defined
|
|
ScWCToAnsiMore((LPALLOCATEMORE) (&MAPIAllocateMore), lpProps, lpszName, &lpszNameA);
|
|
|
|
DebugTrace(TEXT("Adding root-table container:%s\n"),lpszName);
|
|
|
|
lpProps[ircPR_DISPLAY_TYPE].ulPropTag = PR_DISPLAY_TYPE;
|
|
lpProps[ircPR_DISPLAY_TYPE].Value.l = DT_LOCAL;
|
|
|
|
lpProps[ircPR_OBJECT_TYPE].ulPropTag = PR_OBJECT_TYPE;
|
|
lpProps[ircPR_OBJECT_TYPE].Value.l = MAPI_ABCONT;
|
|
|
|
lpProps[ircPR_ROWID].ulPropTag = PR_ROWID;
|
|
lpProps[ircPR_ROWID].Value.l = iRow;
|
|
|
|
lpProps[ircPR_DEPTH].ulPropTag = PR_DEPTH;
|
|
lpProps[ircPR_DEPTH].Value.l = ulDepth;
|
|
|
|
lpProps[ircPR_CONTAINER_FLAGS].ulPropTag = PR_CONTAINER_FLAGS;
|
|
lpProps[ircPR_CONTAINER_FLAGS].Value.l = ulContainerFlags;
|
|
|
|
if(bLDAP)
|
|
{
|
|
if(ulFlags & MAPI_UNICODE) // <note> this assumes UNICODE is defined
|
|
{
|
|
lpProps[ircPR_WAB_LDAP_SERVER].ulPropTag = PR_WAB_LDAP_SERVER;
|
|
lpProps[ircPR_WAB_LDAP_SERVER].Value.lpszW = lpszName;
|
|
}
|
|
else
|
|
{
|
|
lpProps[ircPR_WAB_LDAP_SERVER].ulPropTag = CHANGE_PROP_TYPE( PR_WAB_LDAP_SERVER, PT_STRING8);
|
|
lpProps[ircPR_WAB_LDAP_SERVER].Value.lpszA = lpszNameA;
|
|
}
|
|
|
|
lpProps[ircPR_WAB_RESOLVE_FLAG].ulPropTag = PR_WAB_RESOLVE_FLAG;
|
|
lpProps[ircPR_WAB_RESOLVE_FLAG].Value.b = (USHORT) !!fLDAPResolve;
|
|
}
|
|
else
|
|
{
|
|
lpProps[ircPR_WAB_LDAP_SERVER].ulPropTag = PR_NULL;
|
|
lpProps[ircPR_WAB_RESOLVE_FLAG].ulPropTag = PR_NULL;
|
|
}
|
|
|
|
if(ulFlags & MAPI_UNICODE) // <note> this assumes UNICODE is defined
|
|
{
|
|
lpProps[ircPR_DISPLAY_NAME].ulPropTag = PR_DISPLAY_NAME;
|
|
lpProps[ircPR_DISPLAY_NAME].Value.lpszW = lpszName;
|
|
}
|
|
else
|
|
{
|
|
lpProps[ircPR_DISPLAY_NAME].ulPropTag = CHANGE_PROP_TYPE( PR_DISPLAY_NAME, PT_STRING8);
|
|
lpProps[ircPR_DISPLAY_NAME].Value.lpszA = lpszNameA;
|
|
}
|
|
|
|
if(bProviderID)
|
|
{
|
|
lpProps[ircPR_AB_PROVIDER_ID].ulPropTag = PR_AB_PROVIDER_ID;
|
|
lpProps[ircPR_AB_PROVIDER_ID].Value.bin.cb = sizeof(MAPIUID);
|
|
lpProps[ircPR_AB_PROVIDER_ID].Value.bin.lpb = (LPBYTE)&muidCAB;
|
|
} else
|
|
{
|
|
lpProps[ircPR_AB_PROVIDER_ID].ulPropTag = PR_NULL;
|
|
}
|
|
|
|
lpProps[ircPR_ENTRYID].ulPropTag = PR_ENTRYID;
|
|
if(lpEID)
|
|
lpProps[ircPR_ENTRYID].Value.bin = *lpEID;
|
|
else
|
|
{
|
|
lpProps[ircPR_ENTRYID].Value.bin.cb = cb;
|
|
lpProps[ircPR_ENTRYID].Value.bin.lpb = lpb;
|
|
}
|
|
|
|
// Make certain we have proper indicies.
|
|
// For now, we will equate PR_INSTANCE_KEY and PR_RECORD_KEY to PR_ENTRYID.
|
|
lpProps[ircPR_INSTANCE_KEY].ulPropTag = PR_INSTANCE_KEY;
|
|
lpProps[ircPR_INSTANCE_KEY].Value.bin.cb = lpProps[ircPR_ENTRYID].Value.bin.cb;
|
|
lpProps[ircPR_INSTANCE_KEY].Value.bin.lpb = lpProps[ircPR_ENTRYID].Value.bin.lpb;
|
|
|
|
lpProps[ircPR_RECORD_KEY].ulPropTag = PR_RECORD_KEY;
|
|
lpProps[ircPR_RECORD_KEY].Value.bin.cb = lpProps[ircPR_ENTRYID].Value.bin.cb;
|
|
lpProps[ircPR_RECORD_KEY].Value.bin.lpb = lpProps[ircPR_ENTRYID].Value.bin.lpb;
|
|
|
|
}
|
|
|
|
/*
|
|
- bIsDupeContainerName
|
|
-
|
|
* The Root_GetContentsTable fails badly if there are multiple containers
|
|
* with the same index name because the Table methods can't handle it ..
|
|
*
|
|
* Therefore, to prevent such problems, we double-check if a container name
|
|
* is duplicated before adding it to the container list.
|
|
*
|
|
*/
|
|
BOOL bIsDupeContainerName(LPSRowSet lpsrs, LPTSTR lpszName)
|
|
{
|
|
ULONG i = 0;
|
|
BOOL bRet = FALSE;
|
|
|
|
// walk through the rows one by one
|
|
for(i=0;i<lpsrs->cRows;i++)
|
|
{
|
|
LPSPropValue lpProps = lpsrs->aRow[i].lpProps;
|
|
|
|
if(!lpProps || !lpsrs->aRow[i].cValues)
|
|
continue;
|
|
|
|
if( lpProps[ircPR_DISPLAY_NAME].ulPropTag == PR_DISPLAY_NAME &&
|
|
!lstrcmpi(lpProps[ircPR_DISPLAY_NAME].Value.LPSZ, lpszName))
|
|
{
|
|
DebugTrace(TEXT("Found dupe container name .. skipping ...\n"));
|
|
bRet = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
return bRet;
|
|
}
|
|
|
|
|
|
/***************************************************
|
|
*
|
|
* The actual ABContainer methods
|
|
*/
|
|
|
|
/* ---------
|
|
* IMAPIContainer
|
|
*/
|
|
|
|
/*************************************************************************
|
|
*
|
|
*
|
|
- ROOT_GetContentsTable
|
|
-
|
|
*
|
|
* ulFlags - WAB_LOCAL_CONTAINERS means don't add the LDAP containers to this table
|
|
* Just do the local WAB containers
|
|
* WAB_NO_PROFILE_CONTAINERS means don't add the profile containers
|
|
* Just add a single local container that will have all the contents
|
|
*
|
|
*/
|
|
STDMETHODIMP
|
|
ROOT_GetContentsTable(LPROOT lpROOT, ULONG ulFlags, LPMAPITABLE * lppTable)
|
|
{
|
|
LPTABLEDATA lpTableData = NULL;
|
|
HRESULT hResult = hrSuccess;
|
|
SCODE sc;
|
|
LPSRowSet lpSRowSet = NULL;
|
|
LPSPropValue lpProps = NULL;
|
|
ULONG i;
|
|
ULONG iRow;
|
|
ULONG cProps, cRows, colkci = 0, cwabci = 0;
|
|
ULONG cLDAPContainers = 0;
|
|
TCHAR szBuffer[MAX_PATH];
|
|
IImnAccountManager2 * lpAccountManager = NULL;
|
|
LPSERVER_NAME lpServerNames = NULL, lpNextServer;
|
|
OlkContInfo *rgolkci, *rgwabci;
|
|
LPPTGDATA lpPTGData=GetThreadStoragePointer();
|
|
BOOL bUserProfileContainersOnly = FALSE;
|
|
BOOL bAllContactsContainerOnly = FALSE;
|
|
|
|
// BUGBUG: This routine actually returns the Hierarchy table, not the
|
|
// contents table, but too much code depends on this to change it right
|
|
// now.
|
|
#ifdef PARAMETER_VALIDATION
|
|
// Check to see if it has a jump table
|
|
if (IsBadReadPtr(lpROOT, sizeof(LPVOID))) {
|
|
// No jump table found
|
|
return(ResultFromScode(MAPI_E_INVALID_PARAMETER));
|
|
}
|
|
|
|
// Check to see that it's ROOTs jump table
|
|
if (lpROOT->lpVtbl != &vtblROOT) {
|
|
// Not my jump table
|
|
return(ResultFromScode(MAPI_E_INVALID_PARAMETER));
|
|
}
|
|
|
|
if (ulFlags & ~(MAPI_DEFERRED_ERRORS|MAPI_UNICODE|WAB_LOCAL_CONTAINERS|WAB_NO_PROFILE_CONTAINERS)) {
|
|
DebugTraceArg(ROOT_GetContentsTable, TEXT("Unknown flags"));
|
|
// return(ResultFromScode(MAPI_E_UNKNOWN_FLAGS));
|
|
}
|
|
|
|
if (IsBadWritePtr(lppTable, sizeof(LPMAPITABLE))) {
|
|
DebugTraceArg(ROOT_GetContentsTable, TEXT("Invalid Table parameter"));
|
|
return(ResultFromScode(MAPI_E_INVALID_PARAMETER));
|
|
}
|
|
|
|
#endif // PARAMETER_VALIDATION
|
|
|
|
EnterCriticalSection(&lpROOT->lpIAB->cs);
|
|
|
|
// Create a table object
|
|
// [PaulHi] 4/5/99 Use the Internal CreateTableData() function that takes
|
|
// the ulFlags and will deal with ANSI/UNICODE requests correctly
|
|
sc = CreateTableData(
|
|
NULL,
|
|
(ALLOCATEBUFFER FAR * ) MAPIAllocateBuffer,
|
|
(ALLOCATEMORE FAR *) MAPIAllocateMore,
|
|
MAPIFreeBuffer,
|
|
NULL,
|
|
TBLTYPE_DYNAMIC,
|
|
PR_RECORD_KEY,
|
|
(LPSPropTagArray)&ITableColumnsRoot,
|
|
NULL,
|
|
0,
|
|
NULL,
|
|
ulFlags,
|
|
&lpTableData);
|
|
if ( FAILED(sc) )
|
|
{
|
|
DebugTrace(TEXT("CreateTableData() failed %x\n"), sc);
|
|
hResult = ResultFromScode(sc);
|
|
goto exit;
|
|
}
|
|
Assert(lpTableData);
|
|
|
|
if(ulFlags & WAB_NO_PROFILE_CONTAINERS)
|
|
bAllContactsContainerOnly = TRUE;
|
|
|
|
if(ulFlags & MAPI_UNICODE)
|
|
((TAD *)lpTableData)->bMAPIUnicodeTable = TRUE;
|
|
|
|
// Enumerate the LDAP accounts
|
|
if(!(ulFlags & WAB_LOCAL_CONTAINERS))
|
|
{
|
|
cLDAPContainers = 0;
|
|
if (! HR_FAILED(hResult = InitAccountManager(lpROOT->lpIAB, &lpAccountManager, NULL))) {
|
|
// Count and enumerate LDAP servers to ServerList
|
|
if (hResult = EnumerateLDAPtoServerList(lpAccountManager, &lpServerNames, &cLDAPContainers)) {
|
|
DebugTrace(TEXT("EnumerateLDAPtoServerList -> %x\n"), GetScode(hResult));
|
|
hResult = hrSuccess; // not fatal
|
|
}
|
|
} else {
|
|
DebugTrace(TEXT("InitAccountManager -> %x\n"), GetScode(hResult));
|
|
hResult = hrSuccess;
|
|
}
|
|
}
|
|
|
|
// If this is an outlook session then use the outlook's list of containers
|
|
// as provided by outlook...
|
|
if (pt_bIsWABOpenExSession) {
|
|
colkci = lpROOT->lpIAB->lpPropertyStore->colkci;
|
|
Assert(colkci);
|
|
rgolkci = lpROOT->lpIAB->lpPropertyStore->rgolkci;
|
|
Assert(rgolkci);
|
|
} else
|
|
colkci = 1;
|
|
|
|
// If we have a user profile active, then dont return the virtual PAB folder
|
|
// as part of this table .. only return the actual folders in the user's view
|
|
// The test for this is that (1) Have Profiles enabled (2) Have a current user
|
|
// and (3) The NO_PROFILE_CONTAINERS should not have been specified
|
|
bUserProfileContainersOnly = ( bAreWABAPIProfileAware(lpROOT->lpIAB) &&
|
|
bIsThereACurrentUser(lpROOT->lpIAB) &&
|
|
!bAllContactsContainerOnly);
|
|
|
|
// If we have Profile awareness and no NO_PROFILE flag,
|
|
// use the wab's list of folder
|
|
if (bAreWABAPIProfileAware(lpROOT->lpIAB) && !bAllContactsContainerOnly)
|
|
{
|
|
cwabci = lpROOT->lpIAB->cwabci;
|
|
Assert(cwabci);
|
|
rgwabci = lpROOT->lpIAB->rgwabci;
|
|
Assert(rgwabci);
|
|
} else
|
|
cwabci = 1;
|
|
|
|
// Since outlook and identity_profiles are mutually exclusive, we can
|
|
// do '-1' here to remove whatever container we don't need
|
|
// and if we don't want ldap containers, we can do another -1
|
|
cRows = cwabci + colkci + cLDAPContainers - 1 - (bUserProfileContainersOnly?1:0); // Outlook and Profiles are mutually exclusive
|
|
iRow = 0; // current row
|
|
|
|
// Allocate the SRowSet
|
|
if (FAILED(sc = MAPIAllocateBuffer(sizeof(SRowSet) + cRows * sizeof(SRow),
|
|
&lpSRowSet))) {
|
|
DebugTrace(TEXT("Allocation of SRowSet -> %x\n"), sc);
|
|
hResult = ResultFromScode(sc);
|
|
goto exit;
|
|
}
|
|
MAPISetBufferName(lpSRowSet, TEXT("Root_ContentsTable SRowSet"));
|
|
// Set each LPSRow to NULL so we can easily free on error
|
|
ZeroMemory( lpSRowSet, (UINT) (sizeof(SRowSet) + cRows * sizeof(SRow)));
|
|
|
|
lpSRowSet->cRows = cRows;
|
|
|
|
cProps = ircMax;
|
|
if (FAILED(sc = MAPIAllocateBuffer(ircMax * sizeof(SPropValue), &lpProps))) {
|
|
DebugTrace(TEXT("ROOT_GetContentsTable: Allocation of props -> %x\n"), sc);
|
|
hResult = ResultFromScode(sc);
|
|
goto exit;
|
|
}
|
|
|
|
//
|
|
// Add our PAB container
|
|
//
|
|
if(!bUserProfileContainersOnly)
|
|
{
|
|
// Load the display name from resource string
|
|
if (!LoadString(hinstMapiX, IDS_ADDRBK_CAPTION, szBuffer, ARRAYSIZE(szBuffer)))
|
|
StrCpyN(szBuffer, szEmpty, ARRAYSIZE(szBuffer));
|
|
{
|
|
ULONG cb = 0;
|
|
LPENTRYID lpb = NULL;
|
|
if (HR_FAILED(hResult = CreateWABEntryID(WAB_PAB, NULL, NULL, NULL, 0, 0, lpProps, &cb, &lpb)))
|
|
goto exit;
|
|
|
|
// Set props for the pab object
|
|
SetContainerlpProps(lpProps,
|
|
pt_bIsWABOpenExSession ? lpROOT->lpIAB->lpPropertyStore->rgolkci->lpszName : szBuffer,
|
|
iRow,
|
|
cb, (LPBYTE)lpb, NULL,
|
|
AB_MODIFIABLE | AB_RECIPIENTS,
|
|
pt_bIsWABOpenExSession ? 1 : 0,
|
|
pt_bIsWABOpenExSession ? TRUE : FALSE,
|
|
ulFlags,
|
|
FALSE, FALSE);
|
|
}
|
|
|
|
// Attach the props to the SRowSet
|
|
lpSRowSet->aRow[iRow].lpProps = lpProps;
|
|
lpSRowSet->aRow[iRow].cValues = cProps;
|
|
lpSRowSet->aRow[iRow].ulAdrEntryPad = 0;
|
|
|
|
iRow++;
|
|
}
|
|
|
|
//
|
|
// Next, add any additional containers
|
|
//
|
|
for (i = 1; i < colkci; i++) {
|
|
|
|
if (FAILED(sc = MAPIAllocateBuffer(ircMax * sizeof(SPropValue), &lpProps))) {
|
|
DebugTrace(TEXT("ROOT_GetContentsTable: Allocation of props -> %x\n"), sc);
|
|
hResult = ResultFromScode(sc);
|
|
goto exit;
|
|
}
|
|
|
|
SetContainerlpProps(lpProps,
|
|
rgolkci[i].lpszName, iRow,
|
|
0, NULL, rgolkci[i].lpEntryID,
|
|
AB_MODIFIABLE | AB_RECIPIENTS,
|
|
1, TRUE,
|
|
ulFlags,
|
|
FALSE, FALSE);
|
|
|
|
// Attach the props to the SRowSet
|
|
lpSRowSet->aRow[iRow].lpProps = lpProps;
|
|
lpSRowSet->aRow[iRow].cValues = cProps;
|
|
lpSRowSet->aRow[iRow].ulAdrEntryPad = 0;
|
|
|
|
iRow++;
|
|
}
|
|
|
|
for (i = 1; i < cwabci; i++)
|
|
{
|
|
|
|
if (FAILED(sc = MAPIAllocateBuffer(ircMax * sizeof(SPropValue), &lpProps))) {
|
|
DebugTrace(TEXT("ROOT_GetContentsTable: Allocation of props -> %x\n"), sc);
|
|
hResult = ResultFromScode(sc);
|
|
goto exit;
|
|
}
|
|
|
|
SetContainerlpProps(lpProps,
|
|
rgwabci[i].lpszName, iRow,
|
|
0, NULL, rgwabci[i].lpEntryID,
|
|
AB_MODIFIABLE | AB_RECIPIENTS,
|
|
1, TRUE,
|
|
ulFlags,
|
|
FALSE, FALSE);
|
|
|
|
// Attach the props to the SRowSet
|
|
lpSRowSet->aRow[iRow].lpProps = lpProps;
|
|
lpSRowSet->aRow[iRow].cValues = cProps;
|
|
lpSRowSet->aRow[iRow].ulAdrEntryPad = 0;
|
|
|
|
iRow++;
|
|
}
|
|
|
|
//
|
|
// Now, add the LDAP objects
|
|
//
|
|
lpNextServer = lpServerNames;
|
|
|
|
for (i = 0; i < cLDAPContainers && lpNextServer; i++)
|
|
{
|
|
UNALIGNED WCHAR *lpName = lpNextServer->lpszName;
|
|
|
|
if (lpName)
|
|
{
|
|
LDAPSERVERPARAMS sParams;
|
|
|
|
if(bIsDupeContainerName(lpSRowSet, (LPTSTR) lpName))
|
|
{
|
|
lpSRowSet->cRows--;
|
|
goto endloop;
|
|
}
|
|
|
|
//DebugTrace(TEXT("LDAP Server: %s\n"), lpNextServer->lpszName);
|
|
cProps = ircMax;
|
|
|
|
if (FAILED(sc = MAPIAllocateBuffer(ircMax * sizeof(SPropValue), &lpProps))) {
|
|
DebugTrace(TEXT("ROOT_GetContentsTable: Allocation of props -> %x\n"), sc);
|
|
hResult = ResultFromScode(sc);
|
|
goto exit;
|
|
}
|
|
|
|
GetLDAPServerParams(lpNextServer->lpszName, &sParams);
|
|
|
|
{
|
|
ULONG cb = 0;
|
|
LPENTRYID lpb = NULL;
|
|
LPVOID pv = lpName;
|
|
|
|
if (HR_FAILED(hResult = CreateWABEntryID(WAB_LDAP_CONTAINER,
|
|
pv, // server name
|
|
NULL, NULL, 0, 0,
|
|
lpProps, &cb, &lpb)))
|
|
{
|
|
goto exit;
|
|
}
|
|
|
|
SetContainerlpProps(lpProps,
|
|
(LPTSTR) lpName, iRow,
|
|
cb, (LPBYTE)lpb, NULL,
|
|
AB_FIND_ON_OPEN | AB_UNMODIFIABLE,
|
|
0, FALSE,
|
|
ulFlags,
|
|
TRUE, sParams.fResolve);
|
|
}
|
|
|
|
FreeLDAPServerParams(sParams);
|
|
|
|
// Attach the props to the SRowSet
|
|
lpSRowSet->aRow[iRow].lpProps = lpProps;
|
|
lpSRowSet->aRow[iRow].cValues = cProps;
|
|
lpSRowSet->aRow[iRow].ulAdrEntryPad = 0;
|
|
|
|
iRow++;
|
|
}
|
|
endloop:
|
|
lpNextServer = lpNextServer->lpNext;
|
|
}
|
|
|
|
|
|
// Add all this data we just created to the the Table.
|
|
if (hResult = lpTableData->lpVtbl->HrModifyRows(lpTableData,
|
|
0, // ulFlags
|
|
lpSRowSet)) {
|
|
DebugTraceResult( TEXT("ROOT_GetContentsTable:HrModifyRows"), hResult);
|
|
goto exit;
|
|
}
|
|
|
|
|
|
hResult = lpTableData->lpVtbl->HrGetView(lpTableData,
|
|
NULL, // LPSSortOrderSet lpsos,
|
|
ContentsViewGone, // CALLERRELEASE FAR * lpfReleaseCallback,
|
|
0, // ULONG ulReleaseData,
|
|
lppTable); // LPMAPITABLE FAR * lplpmt)
|
|
|
|
exit:
|
|
|
|
while(lpServerNames)
|
|
{
|
|
lpNextServer = lpServerNames;
|
|
lpServerNames = lpServerNames->lpNext;
|
|
LocalFreeAndNull(&lpNextServer->lpszName);
|
|
LocalFreeAndNull(&lpNextServer);
|
|
}
|
|
|
|
FreeProws(lpSRowSet);
|
|
|
|
// Cleanup table if failure
|
|
if (HR_FAILED(hResult)) {
|
|
if (lpTableData) {
|
|
UlRelease(lpTableData);
|
|
}
|
|
}
|
|
|
|
LeaveCriticalSection(&lpROOT->lpIAB->cs);
|
|
|
|
return(hResult);
|
|
}
|
|
|
|
|
|
/*************************************************************************
|
|
*
|
|
*
|
|
- ROOT_GetHierarchyTable
|
|
-
|
|
* Returns the merge of all the root hierarchy tables
|
|
*
|
|
*
|
|
*
|
|
*/
|
|
|
|
STDMETHODIMP
|
|
ROOT_GetHierarchyTable (LPROOT lpROOT,
|
|
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(lpROOT, sizeof(LPVOID))) {
|
|
// No jump table found
|
|
return(ResultFromScode(MAPI_E_INVALID_PARAMETER));
|
|
}
|
|
|
|
// Check to see that it's ROOTs jump table
|
|
if (lpROOT->lpVtbl != &vtblROOT) {
|
|
// Not my jump table
|
|
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(ROOT_GetHierarchyTable, TEXT("Unknown flags used"));
|
|
// return(ResultFromScode(MAPI_E_UNKNOWN_FLAGS));
|
|
}
|
|
|
|
#endif
|
|
|
|
// BUGBUG: We use the code which is incorrectly in GetContentsTable...
|
|
hr = ROOT_GetContentsTable(lpROOT, ulFlags & ~CONVENIENT_DEPTH, lppTable);
|
|
|
|
DebugTraceResult(ROOT_GetHierarchyTable, hr);
|
|
return(hr);
|
|
}
|
|
|
|
|
|
/*************************************************************************
|
|
*
|
|
*
|
|
- ROOT_OpenEntry
|
|
-
|
|
* Just call ABP_OpenEntry
|
|
*
|
|
*
|
|
*
|
|
*/
|
|
STDMETHODIMP
|
|
ROOT_OpenEntry(LPROOT lpROOT,
|
|
ULONG cbEntryID,
|
|
LPENTRYID lpEntryID,
|
|
LPCIID lpInterface,
|
|
ULONG ulFlags,
|
|
ULONG * lpulObjType,
|
|
LPUNKNOWN * lppUnk)
|
|
{
|
|
#ifdef PARAMETER_VALIDATION
|
|
// Validate the object.
|
|
if (BAD_STANDARD_OBJ(lpROOT, ROOT_, 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(ROOT_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(ROOT_OpenEntry, TEXT("lpInterface fails address check"));
|
|
return(ResultFromScode(MAPI_E_INVALID_PARAMETER));
|
|
}
|
|
|
|
if (ulFlags & ~(MAPI_MODIFY | MAPI_DEFERRED_ERRORS | MAPI_BEST_ACCESS)) {
|
|
DebugTraceArg(ROOT_OpenEntry, TEXT("Unknown flags used"));
|
|
// return(ResultFromScode(MAPI_E_UNKNOWN_FLAGS));
|
|
}
|
|
|
|
if (IsBadWritePtr((LPVOID) lpulObjType, sizeof (ULONG))) {
|
|
DebugTraceArg(ROOT_OpenEntry, TEXT("lpulObjType"));
|
|
return(ResultFromScode(MAPI_E_INVALID_PARAMETER));
|
|
}
|
|
|
|
if (IsBadWritePtr((LPVOID) lppUnk, sizeof (LPUNKNOWN))) {
|
|
DebugTraceArg(ROOT_OpenEntry, TEXT("lppUnk"));
|
|
return(ResultFromScode(MAPI_E_INVALID_PARAMETER));
|
|
}
|
|
|
|
#endif // PARAMETER_VALIDATION
|
|
|
|
// Should just call IAB::OpenEntry()...
|
|
return(lpROOT->lpIAB->lpVtbl->OpenEntry(lpROOT->lpIAB,
|
|
cbEntryID,
|
|
lpEntryID,
|
|
lpInterface,
|
|
ulFlags,
|
|
lpulObjType,
|
|
lppUnk));
|
|
}
|
|
|
|
|
|
STDMETHODIMP
|
|
ROOT_SetSearchCriteria(LPROOT lpROOT,
|
|
LPSRestriction lpRestriction,
|
|
LPENTRYLIST lpContainerList,
|
|
ULONG ulSearchFlags)
|
|
{
|
|
|
|
#ifdef PARAMETER_VALIDATION
|
|
// Validate the object.
|
|
if (BAD_STANDARD_OBJ(lpROOT, ROOT_, SetSearchCriteria, lpVtbl)) {
|
|
// jump table not large enough to support this method
|
|
DebugTraceArg(ROOT_SetSearchCriteria, TEXT("Bad object/vtble"));
|
|
return(ResultFromScode(MAPI_E_INVALID_PARAMETER));
|
|
}
|
|
|
|
// ensure we can read the restriction
|
|
if (lpRestriction && IsBadReadPtr(lpRestriction, sizeof(SRestriction))) {
|
|
DebugTraceArg(ROOT_SetSearchCriteria, TEXT("Bad Restriction parameter"));
|
|
return(ResultFromScode(MAPI_E_INVALID_PARAMETER));
|
|
}
|
|
|
|
if (FBadEntryList(lpContainerList)) {
|
|
DebugTraceArg(ROOT_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(ROOT_GetSearchCriteria, TEXT("Unknown flags used"));
|
|
// return(ResultFromScode(MAPI_E_UNKNOWN_FLAGS));
|
|
}
|
|
|
|
#endif // PARAMETER_VALIDATION
|
|
|
|
return(ResultFromScode(MAPI_E_NO_SUPPORT));
|
|
}
|
|
|
|
|
|
STDMETHODIMP
|
|
ROOT_GetSearchCriteria(LPROOT lpROOT,
|
|
ULONG ulFlags,
|
|
LPSRestriction FAR * lppRestriction,
|
|
LPENTRYLIST FAR * lppContainerList,
|
|
ULONG FAR * lpulSearchState)
|
|
{
|
|
#ifdef PARAMETER_VALIDATION
|
|
|
|
// Validate the object.
|
|
if (BAD_STANDARD_OBJ(lpROOT, ROOT_, GetSearchCriteria, lpVtbl)) {
|
|
// jump table not large enough to support this method
|
|
DebugTraceArg(ROOT_GetSearchCriteria, TEXT("Bad object/vtble"));
|
|
return(ResultFromScode(MAPI_E_INVALID_PARAMETER));
|
|
}
|
|
|
|
if (ulFlags & ~(MAPI_UNICODE)) {
|
|
DebugTraceArg(ROOT_GetSearchCriteria, TEXT("Unknown Flags"));
|
|
// return(ResultFromScode(MAPI_E_UNKNOWN_FLAGS));
|
|
}
|
|
|
|
// ensure we can write the restriction
|
|
if (lppRestriction && IsBadWritePtr(lppRestriction, sizeof(LPSRestriction))) {
|
|
DebugTraceArg(ROOT_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(ROOT_GetSearchCriteria, TEXT("Bad ContainerList parameter"));
|
|
return(ResultFromScode(MAPI_E_INVALID_PARAMETER));
|
|
}
|
|
|
|
|
|
if (lpulSearchState && IsBadWritePtr(lpulSearchState, sizeof(ULONG))) {
|
|
DebugTraceArg(ROOT_GetSearchCriteria, TEXT("lpulSearchState fails address check"));
|
|
return(ResultFromScode(MAPI_E_INVALID_PARAMETER));
|
|
}
|
|
#endif // PARAMETER_VALIDATION
|
|
|
|
return(ResultFromScode(MAPI_E_NO_SUPPORT));
|
|
}
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Synopsis: ROOT_CreateEntry()
|
|
//
|
|
// Description:
|
|
// If called from a OneOff container a OneOff MAIL_USER object
|
|
// is created via the use of any arbitrary template.
|
|
// CreateEntry is not supported from a ROOT container.
|
|
//
|
|
// Parameters:
|
|
// Returns:
|
|
// Effects:
|
|
//
|
|
// Notes: OneOff EntryIDs contain MAPI_UNICODE flag information in
|
|
// the ulDataType member.
|
|
//
|
|
// Revision:
|
|
//----------------------------------------------------------------------------
|
|
STDMETHODIMP
|
|
ROOT_CreateEntry(LPROOT lpROOT,
|
|
ULONG cbEntryID,
|
|
LPENTRYID lpEntryID,
|
|
ULONG ulCreateFlags,
|
|
LPMAPIPROP FAR * lppMAPIPropEntry)
|
|
{
|
|
BYTE bType;
|
|
|
|
#ifdef PARAMETER_VALIDATION
|
|
|
|
// Validate the object.
|
|
if (BAD_STANDARD_OBJ(lpROOT, ROOT_, CreateEntry, lpVtbl)) {
|
|
// jump table not large enough to support this method
|
|
DebugTraceArg(ROOT_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(ROOT_CreateEntry, TEXT("lpEntryID fails address check"));
|
|
return(ResultFromScode(MAPI_E_INVALID_ENTRYID));
|
|
}
|
|
|
|
//NFAssertSz(FValidEntryIDFlags(lpEntryID->abFlags),
|
|
// "Undefined bits set in EntryID flags\n");
|
|
} else {
|
|
DebugTraceArg(ROOT_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(ROOT_CreateEntry, TEXT("Unknown flags used"));
|
|
// return(ResultFromScode(MAPI_E_UNKNOWN_FLAGS));
|
|
}
|
|
|
|
if (IsBadWritePtr(lppMAPIPropEntry, sizeof(LPMAPIPROP))) {
|
|
DebugTraceArg(ROOT_CreateEntry, TEXT("Bad MAPI Property write parameter"));
|
|
return(ResultFromScode(MAPI_E_INVALID_PARAMETER));
|
|
}
|
|
|
|
#endif // PARAMETER_VALIDATION
|
|
|
|
#ifdef NEVER
|
|
if (lpROOT->ulType == AB_ROOT)
|
|
return ResultFromScode(MAPI_E_NO_SUPPORT);
|
|
#endif // NEVER
|
|
|
|
// What kind of entry are we creating?
|
|
// Default is MailUser
|
|
|
|
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(lpROOT->lpIAB, lpROOT->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(lpROOT->lpIAB, lpROOT->pmbinOlk, MAPI_DISTLIST, ulCreateFlags, lppMAPIPropEntry));
|
|
} else {
|
|
DebugTrace(TEXT("ROOT_CreateEntry got unknown template entryID\n"));
|
|
return(ResultFromScode(MAPI_E_INVALID_ENTRYID));
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
- CopyEntries
|
|
-
|
|
* Copies a list of entries into this container... Since you can't
|
|
* do that with this container we just return not supported.
|
|
*/
|
|
|
|
STDMETHODIMP
|
|
ROOT_CopyEntries(LPROOT lpROOT,
|
|
LPENTRYLIST lpEntries,
|
|
ULONG_PTR ulUIParam,
|
|
LPMAPIPROGRESS lpProgress,
|
|
ULONG ulFlags)
|
|
{
|
|
#ifdef PARAMETER_VALIDATION
|
|
|
|
if (BAD_STANDARD_OBJ(lpROOT, ROOT_, CopyEntries, lpVtbl)) {
|
|
// jump table not large enough to support this method
|
|
|
|
DebugTraceArg(ROOT_CopyEntries, TEXT("Bad object/vtbl"));
|
|
return(ResultFromScode(MAPI_E_INVALID_PARAMETER));
|
|
}
|
|
|
|
// ensure we can read the container list
|
|
|
|
if (FBadEntryList(lpEntries)) {
|
|
DebugTraceArg(ROOT_CopyEntries, TEXT("Bad Entrylist parameter"));
|
|
return(ResultFromScode(MAPI_E_INVALID_PARAMETER));
|
|
}
|
|
|
|
if (ulUIParam && !IsWindow((HWND)ulUIParam)) {
|
|
DebugTraceArg(ROOT_CopyEntries, TEXT("Invalid window handle"));
|
|
return(ResultFromScode(MAPI_E_INVALID_PARAMETER));
|
|
}
|
|
|
|
if (lpProgress && IsBadReadPtr(lpProgress, sizeof(IMAPIProgress))) {
|
|
DebugTraceArg(ROOT_CopyEntries, TEXT("Bad MAPI Progress parameter"));
|
|
return(ResultFromScode(MAPI_E_INVALID_PARAMETER));
|
|
}
|
|
|
|
if (ulFlags & ~(AB_NO_DIALOG | CREATE_CHECK_DUP_LOOSE)) {
|
|
DebugTraceArg(ROOT_CreateEntry, TEXT("Unknown flags used"));
|
|
// return(ResultFromScode(MAPI_E_UNKNOWN_FLAGS));
|
|
}
|
|
#endif // PARAMETER_VALIDATION
|
|
|
|
return(ResultFromScode(MAPI_E_NO_SUPPORT));
|
|
}
|
|
|
|
|
|
/*
|
|
- DeleteEntries
|
|
-
|
|
*
|
|
* Deletes entries within this container... Funny that. There really
|
|
* isn't a true container here. Do we just say "Sure, that worked just
|
|
* fine" or "Sorry this operation not supported." I don't think it really
|
|
* matters... For now it's the former.
|
|
*/
|
|
STDMETHODIMP
|
|
ROOT_DeleteEntries (LPROOT lpROOT,
|
|
LPENTRYLIST lpEntries,
|
|
ULONG ulFlags)
|
|
{
|
|
ULONG i;
|
|
HRESULT hResult = hrSuccess;
|
|
ULONG cDeleted = 0;
|
|
ULONG cToDelete;
|
|
SCODE sc;
|
|
|
|
#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, ROOT_, DeleteEntries, lpVtbl)) {
|
|
// jump table not large enough to support this method
|
|
DebugTraceArg(ROOT_DeleteEntries, TEXT("Bad object/vtbl"));
|
|
return(ResultFromScode(MAPI_E_INVALID_PARAMETER));
|
|
}
|
|
|
|
// ensure we can read the container list
|
|
if (FBadEntryList(lpEntries)) {
|
|
DebugTraceArg(ROOT_DeleteEntries, TEXT("Bad Entrylist parameter"));
|
|
return(ResultFromScode(MAPI_E_INVALID_PARAMETER));
|
|
}
|
|
|
|
if (ulFlags) {
|
|
DebugTraceArg(ROOT_DeleteEntries, 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) IntToPtr(lpEntries->lpbin[i].cb),
|
|
NULL, NULL, NULL, NULL, NULL))
|
|
{
|
|
DebugTrace(TEXT("CONTAINER_DeleteEntries got bad entryid of size %u\n"), lpEntries->lpbin[i].cb);
|
|
continue;
|
|
}
|
|
|
|
hResult = DeleteCertStuff((LPADRBOOK)lpROOT->lpIAB, (LPENTRYID)lpEntries->lpbin[i].lpb, lpEntries->lpbin[i].cb);
|
|
|
|
hResult = HrSaveHotmailSyncInfoOnDeletion((LPADRBOOK) lpROOT->lpIAB, &(lpEntries->lpbin[i]));
|
|
|
|
if (HR_FAILED(hResult = DeleteRecord(lpROOT->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(lpROOT->lpIAB->lpPropertyStore);
|
|
exitNotAddRefed:
|
|
#endif
|
|
|
|
return(hResult);
|
|
}
|
|
|
|
|
|
|
|
STDMETHODIMP
|
|
ROOT_ResolveNames( LPROOT lpRoot,
|
|
LPSPropTagArray lptagaColSet,
|
|
ULONG ulFlags,
|
|
LPADRLIST lpAdrList,
|
|
LPFlagList lpFlagList)
|
|
{
|
|
return(ResultFromScode(MAPI_E_NO_SUPPORT));
|
|
}
|
|
|