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.
 
 
 
 
 
 

619 lines
20 KiB

/*
* CONTABLE.C
*
* Contents table implementation.
*
*/
#include "_apipch.h"
STDMETHODIMP
CONTVUE_SetColumns(
LPVUE lpvue,
LPSPropTagArray lpptaCols,
ULONG ulFlags );
// CONTVUE (table view class)
// Implementes in-memory IMAPITable class on top of TADs
// This is a copy of vtblVUE with FindRow overridden with the LDAP FindRow.
VUE_Vtbl vtblCONTVUE =
{
VTABLE_FILL
(VUE_QueryInterface_METHOD FAR *) UNKOBJ_QueryInterface,
(VUE_AddRef_METHOD FAR *) UNKOBJ_AddRef,
VUE_Release,
(VUE_GetLastError_METHOD FAR *) UNKOBJ_GetLastError,
VUE_Advise,
VUE_Unadvise,
VUE_GetStatus,
(VUE_SetColumns_METHOD FAR *) CONTVUE_SetColumns,
VUE_QueryColumns,
VUE_GetRowCount,
VUE_SeekRow,
VUE_SeekRowApprox,
VUE_QueryPosition,
VUE_FindRow,
VUE_Restrict,
VUE_CreateBookmark,
VUE_FreeBookmark,
VUE_SortTable,
VUE_QuerySortOrder,
VUE_QueryRows,
VUE_Abort,
VUE_ExpandRow,
VUE_CollapseRow,
VUE_WaitForCompletion,
VUE_GetCollapseState,
VUE_SetCollapseState
};
//
// Private functions
//
/***************************************************************************
Name : GetEntryProps
Purpose : Open the entry, get it's props, release the entry
Parameters: lpContainer -> AB Container object
cbEntryID = size of entryid
lpEntryID -> entry id to open
lpPropertyStore -> property store structure
lpSPropTagArray -> prop tags to get
lpAllocMoreHere = buffer to allocate more onto (or NULL for allocbuffer)
ulFlags - 0 or MAPI_UNICODE
lpulcProps -> return count of props here
lppSPropValue -> return props here
Returns : HRESULT
Comment :
***************************************************************************/
HRESULT GetEntryProps(
LPABCONT lpContainer,
ULONG cbEntryID,
LPENTRYID lpEntryID,
LPSPropTagArray lpSPropTagArray,
LPVOID lpAllocMoreHere, // allocate more on here
ULONG ulFlags,
LPULONG lpulcProps, // return count here
LPSPropValue * lppSPropValue) { // return props here
HRESULT hResult = hrSuccess;
SCODE sc;
ULONG ulObjType;
LPMAPIPROP lpObject = NULL;
LPSPropValue lpSPropValue = NULL;
ULONG cb;
if (HR_FAILED(hResult = lpContainer->lpVtbl->OpenEntry(lpContainer,
cbEntryID,
lpEntryID,
NULL,
0, // read only is fine
&ulObjType,
(LPUNKNOWN *)&lpObject))) {
DebugTrace(TEXT("GetEntryProps OpenEntry failed %x\n"), GetScode(hResult));
return(hResult);
}
if (HR_FAILED(hResult = lpObject->lpVtbl->GetProps(lpObject,
lpSPropTagArray,
ulFlags,
lpulcProps,
&lpSPropValue))) {
DebugTrace(TEXT("GetEntryProps GetProps failed %x\n"), GetScode(hResult));
goto exit;
}
// Allocate more for our return buffer
if (FAILED(sc = ScCountProps(*lpulcProps, lpSPropValue, &cb))) {
hResult = ResultFromScode(sc);
goto exit;
}
if (FAILED(sc = MAPIAllocateMore(cb, lpAllocMoreHere, lppSPropValue))) {
hResult = ResultFromScode(sc);
goto exit;
}
if (FAILED(sc = ScCopyProps(*lpulcProps, lpSPropValue, *lppSPropValue, NULL))) {
hResult = ResultFromScode(sc);
goto exit;
}
exit:
FreeBufferAndNull(&lpSPropValue);
UlRelease(lpObject);
return(hResult);
}
/***************************************************************************
Name : FillTableDataFromPropertyStore
Purpose : Fill in a TableData object from the property store
Parameters: lpIAB
lppta -> prop tags to get
lpTableData
Returns : HRESULT
Comment :
***************************************************************************/
HRESULT FillTableDataFromPropertyStore(LPIAB lpIAB,
LPSPropTagArray lppta,
LPTABLEDATA lpTableData)
{
HRESULT hResult = S_OK;
SCODE sc;
LPSRowSet lpSRowSet = NULL;
LPSPropValue lpSPropValue = NULL;
LPTSTR lpTemp = NULL;
ULONG i, j, k;
LPCONTENTLIST * lppContentList = NULL;
LPCONTENTLIST lpContentList = NULL;
ULONG ulContainers = 1;
SPropertyRestriction PropRes = {0};
ULONG nLen = 0;
ULONG ulInvalidPropCount = 0;
ULONG ulcPropCount;
ULONG iToAdd;
ULONG iPR_ENTRYID = (ULONG)-1;
ULONG iPR_RECORD_KEY = (ULONG)-1;
ULONG iPR_INSTANCE_KEY = (ULONG)-1;
LPSPropTagArray lpptaNew = NULL;
LPSPropTagArray lpptaRead;
BOOL bUnicodeData = ((LPTAD)lpTableData)->bMAPIUnicodeTable;
// Make certain that we have required properties:
// PR_ENTRYID
// PR_RECORD_KEY
// PR_INSTANCE_KEY
// walk through pta looking for required props
iToAdd = 3;
for (i = 0; i < lppta->cValues; i++) {
switch (lppta->aulPropTag[i]) {
case PR_ENTRYID:
iPR_ENTRYID = i;
iToAdd--;
break;
case PR_RECORD_KEY:
iPR_RECORD_KEY = i;
iToAdd--;
break;
case PR_INSTANCE_KEY:
iPR_INSTANCE_KEY = i;
iToAdd--;
break;
}
}
if (iToAdd) {
if (lpptaNew = LocalAlloc(LPTR, sizeof(SPropTagArray) + (lppta->cValues + iToAdd) * sizeof(DWORD))) {
// Copy the caller's pta into our new one
lpptaNew->cValues = lppta->cValues;
CopyMemory(lpptaNew->aulPropTag, lppta->aulPropTag, lppta->cValues * sizeof(DWORD));
// Add them on at the end.
if (iPR_ENTRYID == (ULONG)-1) {
iPR_ENTRYID = lpptaNew->cValues++;
lpptaNew->aulPropTag[iPR_ENTRYID] = PR_NULL;
}
if (iPR_RECORD_KEY == (ULONG)-1) {
iPR_RECORD_KEY = lpptaNew->cValues++;
lpptaNew->aulPropTag[iPR_RECORD_KEY] = PR_NULL;
}
if (iPR_INSTANCE_KEY == (ULONG)-1) {
iPR_INSTANCE_KEY = lpptaNew->cValues++;
lpptaNew->aulPropTag[iPR_INSTANCE_KEY] = PR_NULL;
}
lpptaRead = lpptaNew;
} else {
hResult = ResultFromScode(MAPI_E_NOT_ENOUGH_MEMORY);
goto exit;
}
} else {
lpptaRead = lppta;
}
Assert(iPR_ENTRYID != (ULONG)-1);
Assert(iPR_RECORD_KEY!= (ULONG)-1);
Assert(iPR_INSTANCE_KEY != (ULONG)-1);
//
// Set filter criteria if none exists - we'll default to DisplayName
//
PropRes.ulPropTag = PR_DISPLAY_NAME;
PropRes.relop = RELOP_EQ;
PropRes.lpProp = NULL;
{
// The way we want GetContentsTable to behave is:
//
// If no profilesAPI enabled and no override, then GetContentsTable works as before and returns
// full set of contents for the current WAB [This is for the PAB container only]
// In cases where old clients dont know how to invoke the new API, the UI will have new stuff
// but the API should have the old stuff meaning that a GetContentsTable on the PAB
// container should return full WAB contents. To make sure that the GetContentsTable on the
// PAB container doesn't contain full contents, caller can force this by passing in
// WAB_ENABLE_PROFILES into the call to GetContentsTable...
//
// If profilesAPI are enabled, then GetContentsTable only returns the contents of
// the specified folder/container
// unless the folder has a NULL entryid in which case we want to get ALL WAB contents
// so we can pump them into the "All Contacts" ui item ..
//
// If ProfilesAPI and WAB_PROFILE_CONTENTS are specified and it's the PAB container
// then we need to return all the contents pertaining to the current profile
//
//
//
SBinary sbEID = {0};
LPSBinary lpsbEID = ((LPTAD)lpTableData)->pbinContEID;
BOOL bProfileContents = FALSE;
// Is this a 'new' WAB showing folders and stuff ?
if(bIsWABSessionProfileAware(lpIAB))
{
// If this WAB is identity aware or we were asked to
// restrict the contents to a single container, then try to
// get the entryid for that container
if( bAreWABAPIProfileAware(lpIAB) ||
((LPTAD)lpTableData)->bContainerContentsOnly)
{
if(!lpsbEID)
lpsbEID = &sbEID;
}
// if we earlier, during GetContentsTable specified that we
// want the full contents for the current profile (which means
// iterating through all the folders in this profile), we should
// look into this ..
if(((LPTAD)lpTableData)->bAllProfileContents)
{
ulContainers = lpIAB->cwabci;
bProfileContents = TRUE;
}
}
// Allocate a temporary list in which we will get each containers contents
// seperately - later we will collate all these seperate content-lists
// together
lppContentList = LocalAlloc(LMEM_ZEROINIT, sizeof(LPCONTENTLIST)*ulContainers);
if(!lppContentList)
{
hResult = MAPI_E_NOT_ENOUGH_MEMORY;
goto exit;
}
//
// Get the content list
//
if(!bProfileContents)
{
// if we don't care about profile and profile folders,
// just get the bunch'o'contents from the store
if (HR_FAILED(hResult = ReadPropArray(lpIAB->lpPropertyStore->hPropertyStore,
lpsbEID,
&PropRes,
AB_MATCH_PROP_ONLY | (bUnicodeData?AB_UNICODE:0),
lpptaRead->cValues,
(LPULONG)lpptaRead->aulPropTag,
&(lppContentList[0]))))
{
DebugTraceResult( TEXT("NewContentsTable:ReadPropArray"), hResult);
goto exit;
}
}
else
{
// We need to collate together all the contents of all the containers for this profile
//
// The first item is the Virtual PAB "Shared Contacts" folder .. we want the contents of this
// item as part of this ContentsTable by default. This item has a special entryid of 0, NULL so we
// can diffrentiate it from the rest of the pack..
//
for(i=0;i<ulContainers;i++)
{
hResult = ReadPropArray(lpIAB->lpPropertyStore->hPropertyStore,
lpIAB->rgwabci[i].lpEntryID ? lpIAB->rgwabci[i].lpEntryID : &sbEID,
&PropRes,
AB_MATCH_PROP_ONLY | (bUnicodeData?AB_UNICODE:0),
lpptaRead->cValues,
(LPULONG)lpptaRead->aulPropTag,
&(lppContentList[i]));
// ignore MAPI_E_NOT_FOUND errors here ...
if(HR_FAILED(hResult))
{
if(hResult == MAPI_E_NOT_FOUND)
hResult = S_OK;
else
{
DebugTraceResult( TEXT("NewContentsTable:ReadPropArray"), hResult);
goto exit;
}
}
}
}
}
for(k=0;k<ulContainers;k++)
{
lpContentList = lppContentList[k];
if(lpContentList)
{
// Now we need to move the information from the index to
// the SRowSet. In the process, we need to create a few computed
// properties:
// PR_DISPLAY_TYPE ?
// PR_INSTANCE_KEY
// PR_RECORD_KEY
// Allocate the SRowSet
if (FAILED(sc = MAPIAllocateBuffer(sizeof(SRowSet) + lpContentList->cEntries * sizeof(SRow),
&lpSRowSet)))
{
DebugTrace(TEXT("Allocation of SRowSet failed\n"));
hResult = ResultFromScode(sc);
goto exit;
}
lpSRowSet->cRows = lpContentList->cEntries;
for (i = 0; i < lpContentList->cEntries; i++)
{
//
// We look at each of the returned entries - if they dont have a prop
// we set that prop to " "
// (Assuming these are all string props)
//
lpSPropValue = lpContentList->aEntries[i].rgPropVals;
ulcPropCount = lpContentList->aEntries[i].cValues;
// DebugProperties(lpSPropValue, ulcPropCount, "Raw");
for (j = 0; j < ulcPropCount; j++)
{
// Get rid of error valued properties
if (PROP_ERROR(lpSPropValue[j])) {
lpSPropValue[j].ulPropTag = PR_NULL;
}
}
// Make certain we have proper indicies.
// For now, we will equate PR_INSTANCE_KEY and PR_RECORD_KEY to PR_ENTRYID.
if(lpSPropValue[iPR_INSTANCE_KEY].ulPropTag != PR_INSTANCE_KEY)
{
lpSPropValue[iPR_INSTANCE_KEY].ulPropTag = PR_INSTANCE_KEY;
SetSBinary( &lpSPropValue[iPR_INSTANCE_KEY].Value.bin,
lpSPropValue[iPR_ENTRYID].Value.bin.cb,
lpSPropValue[iPR_ENTRYID].Value.bin.lpb);
}
if(lpSPropValue[iPR_RECORD_KEY].ulPropTag != PR_RECORD_KEY)
{
lpSPropValue[iPR_RECORD_KEY].ulPropTag = PR_RECORD_KEY;
SetSBinary( &lpSPropValue[iPR_RECORD_KEY].Value.bin,
lpSPropValue[iPR_ENTRYID].Value.bin.cb,
lpSPropValue[iPR_ENTRYID].Value.bin.lpb);
}
// Put it in the RowSet
lpSRowSet->aRow[i].cValues = ulcPropCount; // number of properties
lpSRowSet->aRow[i].lpProps = lpSPropValue; // LPSPropValue
} //for i
hResult = lpTableData->lpVtbl->HrModifyRows(lpTableData,0,lpSRowSet);
FreeBufferAndNull(&lpSRowSet);
} // for k
}
exit:
for(i=0;i<ulContainers;i++)
{
lpContentList = lppContentList[i];
if (lpContentList) {
FreePcontentlist(lpIAB->lpPropertyStore->hPropertyStore, lpContentList);
}
}
if(lppContentList)
LocalFree(lppContentList);
if(lpptaNew)
LocalFree(lpptaNew);
return(hResult);
}
/***************************************************************************
Name : NewContentsTable
Purpose : Creates a new contents table
Parameters:
lpABContainer - container being opened
lpIAB - AdrBook object
ulFlags - WAB_NO_CONTENTTABLE_DATA
lpInteface ?
lppTble - returned table
Returns : HRESULT
Comment :
***************************************************************************/
HRESULT NewContentsTable(LPABCONT lpABContainer,
LPIAB lpIAB,
ULONG ulFlags,
LPCIID lpInterface,
LPMAPITABLE * lppTable) {
LPTABLEDATA lpTableData = NULL;
HRESULT hResult = hrSuccess;
SCODE sc;
#ifndef DONT_ADDREF_PROPSTORE
if ((FAILED(sc = OpenAddRefPropertyStore(NULL, lpIAB->lpPropertyStore)))) {
hResult = ResultFromScode(sc);
goto exitNotAddRefed;
}
#endif
if (FAILED(sc = CreateTableData(
NULL, // LPCIID
(ALLOCATEBUFFER FAR *) MAPIAllocateBuffer,
(ALLOCATEMORE FAR *) MAPIAllocateMore,
MAPIFreeBuffer,
NULL, // lpvReserved,
TBLTYPE_DYNAMIC, // ulTableType,
PR_RECORD_KEY, // ulPropTagIndexCol,
(LPSPropTagArray)&ITableColumns, // LPSPropTagArray lpptaCols,
lpIAB, // lpvDataSource
0, // cbDataSource
((LPCONTAINER)lpABContainer)->pmbinOlk,
ulFlags,
&lpTableData))) { // LPTABLEATA FAR * lplptad
DebugTrace(TEXT("CreateTable failed %x\n"), sc);
hResult = ResultFromScode(sc);
goto exit;
}
if (lpTableData)
{
if(!(ulFlags & WAB_CONTENTTABLE_NODATA))
{
// Fill in the data from the property store
if (hResult = FillTableDataFromPropertyStore(lpIAB,
(LPSPropTagArray)&ITableColumns, lpTableData)) {
DebugTraceResult( TEXT("NewContentsTable:FillTableFromPropertyStore"), hResult);
goto exit;
}
}
}
if (hResult = lpTableData->lpVtbl->HrGetView(lpTableData,
NULL, // LPSSortOrderSet lpsos,
ContentsViewGone, // CALLERRELEASE FAR * lpfReleaseCallback,
0, // ULONG ulReleaseData,
lppTable)) { // LPMAPITABLE FAR * lplpmt)
goto exit;
}
// Replace the vtable with our new one that overrides SetColumns
(*lppTable)->lpVtbl = (IMAPITableVtbl FAR *)&vtblCONTVUE;
exit:
#ifndef DONT_ADDREF_PROPSTORE
ReleasePropertyStore(lpIAB->lpPropertyStore);
exitNotAddRefed:
#endif
// Cleanup table if failure
if (HR_FAILED(hResult)) {
if (lpTableData) {
UlRelease(lpTableData);
}
}
return(hResult);
}
/*
* This is a callback function, invoked by itable.dll when its
* caller does the last release on a view of the contents table. We
* use it to know when to release the underlying table data.
*/
void STDAPICALLTYPE
ContentsViewGone(ULONG ulContext, LPTABLEDATA lptad, LPMAPITABLE lpVue)
{
#ifdef OLD_STUFF
LPISPAM pispam = (LPISPAM)ulContext;
if (FBadUnknown((LPUNKNOWN) pispam)
|| IsBadWritePtr(pispam, sizeof(ISPAM))
|| pispam->cRefTad == 0
|| FBadUnknown(pispam->ptad))
{
DebugTrace(TEXT("ContentsViewGone: contents table was apparently already released\n"));
return;
}
if (pispam->ptad != lptad)
{
TrapSz( TEXT("ContentsViewGone: TAD mismatch on VUE release!"));
}
else if (--(pispam->cRefTad) == 0)
{
pispam->ptad = NULL;
UlRelease(lptad);
}
#endif // OLD_STUFF
UlRelease(lptad);
return;
IF_WIN32(UNREFERENCED_PARAMETER(ulContext);)
IF_WIN32(UNREFERENCED_PARAMETER(lpVue);)
}
/*============================================================================
- CONTVUE::SetColumns()
-
* Replaces the current column set with a copy of the specified column set
* and frees the old column set.
*/
STDMETHODIMP
CONTVUE_SetColumns(
LPVUE lpvue,
LPSPropTagArray lpptaCols,
ULONG ulFlags )
{
HRESULT hResult = hrSuccess;
#if !defined(NO_VALIDATION)
VALIDATE_OBJ(lpvue,CONTVUE_,SetColumns,lpVtbl);
// Validate_IMAPITable_SetColumns( lpvue, lpptaCols, ulFlags ); // Commented by YST
#endif
Assert(lpvue->lptadParent->lpvDataSource);
// Re-read the table data
if (lpvue->lptadParent && (hResult = FillTableDataFromPropertyStore(
(LPIAB)lpvue->lptadParent->lpvDataSource,
lpptaCols,
(LPTABLEDATA)lpvue->lptadParent))) {
DebugTraceResult( TEXT("CONTVUE_SetColumns:FillTableFromPropertyStore"), hResult);
return(hResult);
}
return(VUE_SetColumns(lpvue, lpptaCols, ulFlags));
}