|
|
/***********************************************************************
* * ABCTBL2.C * * Contents Table - Part 2. * * * The following routines are implemented in this file. * * * IVTABC_SeekRow * IVTABC_SeekRowApprox * IVTABC_GetRowCount * IVTABC_QueryPosition * IVTABC_FindRow * IVTABC_Restrict * IVTABC_QueryRows * * * * Copyright 1992, 1993, 1994 Microsoft Corporation. All Rights Reserved. * * Revision History: * * When Who What * -------- ------------------ --------------------------------------- * 1.1.94 MAPI Original source from MAPI sample AB Provider * 3.7.94 Yoram Yaacovi Update to MAPI build 154 * 3.11.94 Yoram Yaacovi Update to use Fax AB include files * 8.1.94 Yoram Yaacovi Update to MAPI 304 * 11.7.94 Yoram Yaacovi Update to MAPI 318 (PR_INSTANCE_KEY) * ***********************************************************************/
#include "faxab.h"
/*************************************************************************
* - IVTABC_SeekRow - * * Tries to seek an appropriate number of rows. * * */ STDMETHODIMP IVTABC_SeekRow( LPIVTABC lpIVTAbc, BOOKMARK bkOrigin, LONG lRowCount, LONG * lplRowsSought ) { LONG lNewPos; LONG lMoved; LONG lDelta; LONG lLast; HRESULT hResult = hrSuccess;
/*
* Validate parameters */
/*
* Check to see if it's large enough to hold this object */ if (IsBadReadPtr(lpIVTAbc, SIZEOF(IVTABC))) { /*
* Not large enough */ hResult = ResultFromScode(E_INVALIDARG);
DebugTraceResult(IVTABC_SeekRow, hResult); return hResult; }
/*
* Check to see that it's the correct vtbl */ if (lpIVTAbc->lpVtbl != &vtblIVTABC) { /*
* Not my vtbl */ hResult = ResultFromScode(E_INVALIDARG);
DebugTraceResult(IVTABC_SeekRow, hResult); return hResult; }
/*
* Check the out parameter for writability (if requested) */ if (lplRowsSought && IsBadWritePtr(lplRowsSought, SIZEOF(LONG))) { hResult = ResultFromScode(E_INVALIDARG);
DebugTraceResult(IVTABC_SeekRow, hResult); return hResult; }
EnterCriticalSection(&lpIVTAbc->cs);
if (bkOrigin == BOOKMARK_BEGINNING) { lNewPos = 0;
} else if (bkOrigin == BOOKMARK_CURRENT) { lNewPos = lpIVTAbc->ulPosition;
} else if (bkOrigin == BOOKMARK_END) { lNewPos = lpIVTAbc->ulMaxPos;
} else { ULONG ulBK = (ULONG) bkOrigin - 3; LPABCBK lpABCBK = NULL;
/*
* See if it's out of range */ if (ulBK < 0 || ulBK >= MAX_BOOKMARKS) { /*
* bad book mark, it's an error, so... */ hResult = ResultFromScode(E_INVALIDARG);
goto out; }
if (!(lpABCBK = lpIVTAbc->rglpABCBK[ulBK])) { /*
* bookmark has not been allocated */ hResult = ResultFromScode(MAPI_E_INVALID_BOOKMARK);
goto out; }
/* Not validating existing bookmark */ lNewPos = lpABCBK->ulPosition; }
/*
* Figure out what endpoint to use and what direction to go to * get there. */ if (lRowCount < 0) { lLast = 0; lDelta = -1; } else { lLast = lpIVTAbc->ulMaxPos; lDelta = 1; }
/*
* While there's rows to seek ... */ lMoved = 0; while( (lNewPos != lLast) && (lMoved != lRowCount) ) { lNewPos += lDelta;
/*
* Unrestricted list is easy: just seek. Also, if the next * 'row' is the end of the table, just go there; don't want * to check it against any restriction. */ if ( (!lpIVTAbc->lpszPartialName) || (lNewPos == (LONG) lpIVTAbc->ulMaxPos)) { lMoved += lDelta; }
/*
* Otherwise, deal with the restricted list: only count * the row if it's in the restriction. */ else { if (!FChecked(lpIVTAbc, (ULONG) lNewPos)) { hResult = HrValidateEntry(lpIVTAbc, (ULONG) lNewPos);
if (HR_FAILED(hResult)) { goto out; } }
if (FMatched(lpIVTAbc, (ULONG) lNewPos)) { lMoved += lDelta; } } }
if (lplRowsSought) *lplRowsSought = lMoved;
lpIVTAbc->ulPosition = lNewPos;
out: LeaveCriticalSection(&lpIVTAbc->cs);
DebugTraceResult(IVTABC_SeekRow, hResult); return hResult;
}
/*************************************************************************
* - IVTABC_SeekRowApprox - * Tries to set the position of the table according to the approximate * position passed in. * * */ STDMETHODIMP IVTABC_SeekRowApprox( LPIVTABC lpIVTAbc, ULONG ulNumerator, ULONG ulDenominator ) { HRESULT hResult = hrSuccess; ULONG iByte; BYTE bCount; ULONG ulPos = 0; ULONG ulCount = 0;
/*
* Validate parameters */
/*
* Check to see if it's large enough to hold this object */ if (IsBadReadPtr(lpIVTAbc, SIZEOF(IVTABC))) { /*
* Not large enough */ hResult = ResultFromScode(E_INVALIDARG);
DebugTraceResult(IVTABC_SeekRowApprox, hResult); return hResult; }
/*
* Check to see that it's the correct vtbl */ if (lpIVTAbc->lpVtbl != &vtblIVTABC) { /*
* Not my vtbl */ hResult = ResultFromScode(E_INVALIDARG);
DebugTraceResult(IVTABC_SeekRowApprox, hResult); return hResult; }
/*
* 0 denominator is not allowed */ if (!ulDenominator) { hResult = ResultFromScode(E_INVALIDARG);
DebugTraceResult(IVTABC_SeekRowApprox, hResult); return hResult; }
EnterCriticalSection(&lpIVTAbc->cs);
if (ulNumerator >= ulDenominator) { /* We're at the end of the list */ lpIVTAbc->ulPosition = lpIVTAbc->ulMaxPos;
hResult = hrSuccess; goto out; }
/*
* Since I'm using muldiv() which takes ints/longs, I should shift right * so that I don't incorrectly call it. * I'm really just checking to see if the sign bit is set... */
if (((long)ulNumerator < 0) || ((long)ulDenominator < 0)) { ulNumerator >>= 1; ulDenominator >>= 1; }
if (!lpIVTAbc->lpszPartialName) { /*
* The NON-Restriction method */
lpIVTAbc->ulPosition = MULDIV(lpIVTAbc->ulMaxPos, ulNumerator, ulDenominator);
hResult = hrSuccess; goto out; }
/*
* Restriction method */
/* Figure out % of which corresponds with numerator. */ ulCount = MULDIV(lpIVTAbc->ulRstrDenom, ulNumerator, ulDenominator);
/* Count bits in rgMatched until I match numerator */
for (iByte = 0; iByte < (lpIVTAbc->ulMaxPos / 8); iByte++) { CBitsB(lpIVTAbc->rgMatched[iByte], bCount); /* <-- MACRO */ ulPos += (ULONG) bCount;
if (ulPos >= ulCount) { ulPos -= bCount; /* Go back a byte */ break; } }
/* My current position is there. */ lpIVTAbc->ulPosition = iByte * 8;
out: LeaveCriticalSection(&lpIVTAbc->cs);
DebugTraceResult(IVTABC_SeekRowApprox, hResult); return hResult;
}
/*************************************************************************
* - IVTABC_GetRowCount - * * If there's a restriction applied, I don't necessarily know how many * rows there are... */
STDMETHODIMP IVTABC_GetRowCount( LPIVTABC lpIVTAbc, ULONG ulFlags, ULONG * lpulCount ) { HRESULT hResult;
/*
* Validate parameters */
/*
* Check to see if it's large enough to hold this object */ if (IsBadReadPtr(lpIVTAbc, SIZEOF(IVTABC))) { /*
* Not large enough */ hResult = ResultFromScode(E_INVALIDARG);
DebugTraceResult(IVTABC_GetRowCount, hResult); return hResult; }
/*
* Check to see that it's the correct vtbl */ if (lpIVTAbc->lpVtbl != &vtblIVTABC) { /*
* Not my vtbl */ hResult = ResultFromScode(E_INVALIDARG);
DebugTraceResult(IVTABC_GetRowCount, hResult); return hResult; }
/*
* Check the out parameters for writability */ if (IsBadWritePtr(lpulCount, sizeof(ULONG))) { hResult = ResultFromScode(E_INVALIDARG);
DebugTraceResult(IVTABC_GetRowCount, hResult); return hResult; }
if (ulFlags & ~TBL_NOWAIT) { hResult = ResultFromScode(MAPI_E_UNKNOWN_FLAGS);
DebugTraceResult(IVTABC_GetRowCount, hResult); return hResult; }
EnterCriticalSection(&lpIVTAbc->cs);
/*
* If there's no restriction, you can actually calculate this.. */ if (!lpIVTAbc->lpszPartialName) {
/*
* Number of actual rows */ *lpulCount = lpIVTAbc->ulMaxPos; hResult = hrSuccess; goto out; }
/*
* There's no way that I can tell how many actual entries there * are without counting them. That takes way too long, so we give * the client our best guess. */
*lpulCount = lpIVTAbc->ulRstrDenom;
/*
* Then we warn the client that this count may not be accurate */
hResult = ResultFromScode(MAPI_W_APPROX_COUNT);
out: LeaveCriticalSection(&lpIVTAbc->cs);
DebugTraceResult(IVTABC_GetRowCount, hResult); return hResult; }
/*************************************************************************
* - IVTABC_QueryPosition - * Figures out the current fractional position * * * */ STDMETHODIMP IVTABC_QueryPosition( LPIVTABC lpIVTAbc, ULONG * lpulRow, ULONG * lpulNumerator, ULONG * lpulDenominator ) { HRESULT hResult = hrSuccess;
/*
* Validate parameters */
/*
* Check to see if it's large enough to hold this object */ if (IsBadReadPtr(lpIVTAbc, SIZEOF(IVTABC))) { /*
* Not large enough */ hResult = ResultFromScode(E_INVALIDARG);
DebugTraceResult(IVTABC_QueryPosition, hResult); return hResult; }
/*
* Check to see that it's the correct vtbl */ if (lpIVTAbc->lpVtbl != &vtblIVTABC) { /*
* Not my vtbl */ hResult = ResultFromScode(E_INVALIDARG);
DebugTraceResult(IVTABC_QueryPosition, hResult); return hResult; }
/*
* Check the out parameters for writability */ if ( IsBadWritePtr(lpulRow, SIZEOF(ULONG)) || IsBadWritePtr(lpulNumerator, SIZEOF(ULONG)) || IsBadWritePtr(lpulDenominator, SIZEOF(ULONG)) ) { hResult = ResultFromScode(E_INVALIDARG);
DebugTraceResult(IVTABC_QueryPosition, hResult); return hResult; }
EnterCriticalSection(&lpIVTAbc->cs);
/* ...I don't have a restriction */ if (!lpIVTAbc->lpszPartialName) { *lpulRow = lpIVTAbc->ulPosition;
*lpulNumerator = lpIVTAbc->ulPosition; *lpulDenominator = lpIVTAbc->ulMaxPos; } else { BYTE bCount = 0; BYTE bFrag; ULONG iByte;
/*
* Zero out fraction */ *lpulNumerator = 0;
/*
* Set denominator that we've been keeping track of. */ *lpulDenominator = (lpIVTAbc->ulRstrDenom ? lpIVTAbc->ulRstrDenom : 1);
/*
* Handle corner case - we're at the beginning of the list... */ if (lpIVTAbc->ulPosition == 0) { *lpulRow = 0; goto out; }
/*
* Calculate Numerator * We use the rgMatched bit array and count the bits up to * our current position (lpIVTAbc->ulPosition). * */ for (iByte = 0; iByte < (lpIVTAbc->ulPosition / 8); iByte++) { CBitsB(lpIVTAbc->rgMatched[iByte], bCount); /* <-- MACRO */ *lpulNumerator += (ULONG) bCount; } /* Count the fragment */ bFrag = lpIVTAbc->rgMatched[iByte]; bFrag = bFrag >> (8 - (lpIVTAbc->ulPosition % 8));
CBitsB(bFrag, bCount); *lpulNumerator += (ULONG) bCount;
/*
* Good guess here... */ *lpulRow = *lpulNumerator;
}
out:
LeaveCriticalSection(&lpIVTAbc->cs);
DebugTraceResult(IVTABC_QueryPosition, hResult); return hResult; }
/*************************************************************************
* - IVTABC_FindRow - * * Prefix searches to find a row * * */ STDMETHODIMP IVTABC_FindRow( LPIVTABC lpIVTAbc, LPSRestriction lpRestriction, BOOKMARK bkOrigin, ULONG ulFlags ) { HRESULT hResult = hrSuccess;
ULONG cbRead; ABCREC abcrec; LONG lpos; ULONG fFound = FALSE; LPTSTR szPrefix; int nCmpResult;
ULONG ulCurMin; ULONG ulCurMac; ULONG ulPosT;
/*
* Validate parameters */
/*
* Check to see if it's large enough to hold this object */ if (IsBadReadPtr(lpIVTAbc, SIZEOF(IVTABC))) { /*
* Not large enough */ hResult = ResultFromScode(E_INVALIDARG);
DebugTraceResult(IVTABC_FindRow, hResult); return hResult; }
/*
* Check to see that it's the correct vtbl */ if (lpIVTAbc->lpVtbl != &vtblIVTABC) { /*
* Not my vtbl */ hResult = ResultFromScode(E_INVALIDARG);
DebugTraceResult(IVTABC_FindRow, hResult); return hResult; }
/*
* Check flags */ if (ulFlags & ~DIR_BACKWARD) { hResult = ResultFromScode(MAPI_E_UNKNOWN_FLAGS);
DebugTraceResult(IVTABC_FindRow, hResult); return hResult; }
/*
* I don't go backwards, yet. */ if (ulFlags & DIR_BACKWARD) { hResult = ResultFromScode(MAPI_E_NO_SUPPORT);
DebugTraceResult(IVTABC_FindRow, hResult); return hResult; }
EnterCriticalSection(&lpIVTAbc->cs);
/*
* Open the file */ hResult = HrOpenFile(lpIVTAbc); if (HR_FAILED(hResult)) { goto out; }
/*
* initialize */ ulCurMin = lpIVTAbc->ulPosition; ulCurMac = lpIVTAbc->ulMaxPos;
/*
* I handle two type of restrictions: * prefix searching on Display Names * Finding a row based on it's instance key */
/*
* The restriction looks like: * * +----------------- * | RES_PROPERTY * +----------------- * | RELOP_GE * +----------------- * | PR_DISPLAY_NAME * +----------------- * | LPSPropVal -----+ * +----------------- | * | +------------------------- * +-->| PR_DISPLAY_NAME * +------------------------- * | 0 <-- for alignment (don't care) * +------------------------- * | lpszA <-- prefix for display name * +------------------------- * * * -OR- * * Find a row based on it's instance key * * +----------------- * | RES_PROPERTY * +----------------- * | RELOP_EQ * +----------------- * | PR_INSTANCE_KEY * +----------------- * | LPSPropVal -----+ * +----------------- | * | +------------------------- * +-->| PR_INSTANCE_KEY * +------------------------- * | | cbInstanceKey * + bin +------------------- * | | lpbInstanceKey * +------------------------- * * * If it doesn't look like one of these, return MAPI_E_TOO_COMPLEX. */
/*
* Both restrictions require this one */ if (lpRestriction->rt != RES_PROPERTY) { hResult = ResultFromScode(MAPI_E_TOO_COMPLEX);
goto out; }
/*
* Look for Instance Key first - it's easiest to handle */ if (lpRestriction->res.resProperty.relop == RELOP_EQ) { LPABCRecInstance lpABCRecInstance;
if (lpRestriction->res.resProperty.ulPropTag != PR_INSTANCE_KEY) { /*
* Clearly something we don't recognize */ hResult = ResultFromScode(MAPI_E_TOO_COMPLEX);
goto out; }
/*
* Crack the bin part of this restriction and * see if we can still find our way back to this * record - quickly... */ lpABCRecInstance = (LPABCRecInstance) lpRestriction->res.resProperty.lpProp->Value.bin.lpb;
/*
* First check to see that we're browsing the same file */ if (lstrcmp(lpABCRecInstance->rgchzFileName, lpIVTAbc->lpszFileName)) { /*
* Nope, different names, return not found and leave our position alone... */ hResult = ResultFromScode(MAPI_E_NOT_FOUND); goto out; }
/*
* Ok, so we think we're browsing the same file. Has it been modified since the * last time we looked? */ if (memcmp(&(lpABCRecInstance->filetime), &(lpIVTAbc->filetime), SIZEOF(FILETIME))) { /*
* Nope, they're different, so no guarantees here... */ hResult = ResultFromScode(MAPI_E_NOT_FOUND); goto out; }
/*
* Now, I feel pretty confident about this instance key. Just set my current position * and go for it. */ lpIVTAbc->ulPosition = lpABCRecInstance->ulRecordPosition;
/* Done */ goto out;
}
/*
* Now we're looking for prefix searching on display name */ if (lpRestriction->res.resProperty.relop != RELOP_GE) { hResult = ResultFromScode(MAPI_E_TOO_COMPLEX);
goto out; }
if (lpRestriction->res.resProperty.ulPropTag != PR_DISPLAY_NAME_A) { hResult = ResultFromScode(MAPI_E_TOO_COMPLEX);
goto out; }
szPrefix = lpRestriction->res.resProperty.lpProp->Value.LPSZ;
if (bkOrigin == BOOKMARK_BEGINNING) { ulCurMin = 0;
} else if (bkOrigin == BOOKMARK_END) { ulCurMin = lpIVTAbc->ulMaxPos;
} else if (bkOrigin != BOOKMARK_CURRENT) { ULONG ulBK = (ULONG) bkOrigin - 3; LPABCBK lpABCBK = NULL;
/*
* See if it's out of range */ if (ulBK < 0 || ulBK >= MAX_BOOKMARKS) { /*
* bad book mark, it's an error, so... */ hResult = ResultFromScode(E_INVALIDARG);
goto out; }
if (!(lpABCBK = lpIVTAbc->rglpABCBK[ulBK])) { /*
* bookmark has not been allocated */ hResult = ResultFromScode(MAPI_E_INVALID_BOOKMARK);
goto out; }
/* Not validating existing bookmark */ ulCurMin = lpABCBK->ulPosition; }
while (ulCurMin < ulCurMac) { /*
* Look for a row which matches the table restriction (if any). */ ulPosT = (ulCurMin + ulCurMac) / 2;
lpos = (long)((long)ulPosT * (long)SIZEOF(ABCREC));
SetFilePointer(lpIVTAbc->hFile, lpos, NULL, FILE_BEGIN);
/* Read in the record at that location */ if ( !ReadFile(lpIVTAbc->hFile, (LPVOID) &abcrec, SIZEOF(ABCREC), &cbRead, NULL) ) { hResult = ResultFromScode(MAPI_E_DISK_ERROR); SetErrorIDS(lpIVTAbc, hResult, IDS_FAB_NO_READ);
goto out; }
/*
* I want case insensitive comparisons here... */ nCmpResult = lstrcmpi(szPrefix, abcrec.rgchDisplayName);
if (nCmpResult > 0) { ulCurMin = ulPosT + 1; } else { ulCurMac = ulPosT; if ( !lpIVTAbc->lpszPartialName || FNameMatch(lpIVTAbc, abcrec.rgchDisplayName) ) { fFound = TRUE; } } }
/*
* If I didn't find a row, return MAPI_E_NOT_FOUND. */ if (!fFound) { hResult = ResultFromScode(MAPI_E_NOT_FOUND);
goto out; }
/*
* Otherwise, set the current position to the row found. */ lpIVTAbc->ulPosition = ulCurMac;
out: LeaveCriticalSection(&lpIVTAbc->cs);
DebugTraceResult(IVTABC_FindRow, hResult); return hResult; }
/*************************************************************************
* - IVTABC_Restrict - * * Should just support ANR type restrictions... */ STDMETHODIMP IVTABC_Restrict( LPIVTABC lpIVTAbc, LPSRestriction lpRestriction, ULONG ulFlags ) { LPTSTR szT = NULL; LPTSTR lpszTNew = NULL; ULONG cbTB = 0; BYTE bFilter = 0; SCODE scode; HRESULT hResult = hrSuccess;
/*
* Validate parameters */
/*
* Check to see if it's large enough to hold this object */ if (IsBadReadPtr(lpIVTAbc, SIZEOF(IVTABC))) { /*
* Not large enough */ hResult = ResultFromScode(E_INVALIDARG);
goto out; }
/*
* Check to see that it's the correct vtbl */ if (lpIVTAbc->lpVtbl != &vtblIVTABC) { /*
* Not my vtbl */ hResult = ResultFromScode(E_INVALIDARG);
goto out; }
/*
* Check flags */ if (ulFlags & ~(TBL_NOWAIT|TBL_BATCH)) { hResult = ResultFromScode(MAPI_E_UNKNOWN_FLAGS);
goto out; }
/*
* I only handle ANR type restrictions */
/*
* Check to see if they're resetting the restrictions */ if (!lpRestriction) { EnterCriticalSection(&lpIVTAbc->cs);
if (lpIVTAbc->lpszPartialName) (*(lpIVTAbc->lpFreeBuff)) (lpIVTAbc->lpszPartialName); lpIVTAbc->lpszPartialName = NULL;
FreeANRBitmaps(lpIVTAbc);
LeaveCriticalSection(&lpIVTAbc->cs);
return hrSuccess; }
/*
* The restriction must look like: * * * +-------------- * | RES_PROPERTY * +-------------- * | RELOP_EQ * +-------------- * | PR_ANR * +-------------- * | LPSPropVal ---+ * +-------------- | * | +------------------------- * +-->| PR_ANR * +------------------------- * | 0 <-- for alignment (don't care) * +------------------------- * | lpszA <-- string to ANR on * +------------------------- * * * * If it doesn't look like this, return MAPI_E_TOO_COMPLEX. * */
if (lpRestriction->rt != RES_PROPERTY) { hResult = ResultFromScode(MAPI_E_TOO_COMPLEX);
goto out; }
if (lpRestriction->res.resProperty.relop != RELOP_EQ) { hResult = ResultFromScode(MAPI_E_TOO_COMPLEX);
goto out; }
if (lpRestriction->res.resProperty.ulPropTag != PR_ANR) { hResult = ResultFromScode(MAPI_E_TOO_COMPLEX);
goto out; }
/*
* NULL string is not defined - it's a bad restriction */ if (!lpRestriction->res.resProperty.lpProp->Value.LPSZ) { hResult = ResultFromScode(E_INVALIDARG);
goto out; }
szT = lpRestriction->res.resProperty.lpProp->Value.LPSZ;
/*
* Skip over leading spaces */
while (*szT == TEXT(' ')) szT++;
/*
* Empty string is not defined - it's a bad restriction */ if (*szT == TEXT('\0')) { hResult = ResultFromScode(E_INVALIDARG); goto out; }
/*
* Copy the string for the partial name */
scode = lpIVTAbc->lpAllocBuff((lstrlen(szT) + 1)*SIZEOF(TCHAR), (LPVOID *) &lpszTNew); if (FAILED(scode)) { /*
* Memory error */
hResult = ResultFromScode(scode); goto out; } lstrcpy(lpszTNew, szT);
EnterCriticalSection(&lpIVTAbc->cs);
/*
* Clear up any old restriction */
if (lpIVTAbc->lpszPartialName) lpIVTAbc->lpFreeBuff(lpIVTAbc->lpszPartialName);
lpIVTAbc->lpszPartialName = lpszTNew;
FreeANRBitmaps(lpIVTAbc);
/*
* Allocate enough bits for the checked&matched arrays */ cbTB = (lpIVTAbc->ulMaxPos) / 8 + 1; /* Number of bytes in both arrays */
lpIVTAbc->rgChecked = lpIVTAbc->lpMalloc->lpVtbl->Alloc( lpIVTAbc->lpMalloc, cbTB);
if (lpIVTAbc->rgChecked == NULL) { lpIVTAbc->lpFreeBuff(lpIVTAbc->lpszPartialName); lpIVTAbc->lpszPartialName = NULL;
hResult = ResultFromScode(scode);
LeaveCriticalSection(&lpIVTAbc->cs); goto out; }
lpIVTAbc->rgMatched = lpIVTAbc->lpMalloc->lpVtbl->Alloc( lpIVTAbc->lpMalloc, cbTB);
if (lpIVTAbc->rgMatched == NULL) { (*(lpIVTAbc->lpFreeBuff)) (lpIVTAbc->lpszPartialName); lpIVTAbc->lpszPartialName = NULL;
lpIVTAbc->lpMalloc->lpVtbl->Free(lpIVTAbc->lpMalloc, lpIVTAbc->rgChecked); lpIVTAbc->rgChecked = NULL;
hResult = ResultFromScode(scode);
LeaveCriticalSection(&lpIVTAbc->cs); goto out; }
/*
* Initialize the checked array with 0's */
FillMemory(lpIVTAbc->rgChecked, (UINT) cbTB, 0x00);
/*
* Initialize the matched array with 1's * [we assume that if you haven't checked it, it matches] */
FillMemory(lpIVTAbc->rgMatched, (UINT) cbTB, 0xFF);
/*
* Fill in the end bits so we don't have to worry about them * later */ bFilter = (0xFF >> (lpIVTAbc->ulMaxPos % 8));
/* Checked end bits should be 1 */ lpIVTAbc->rgChecked[cbTB - 1] = bFilter;
/* Matched end bits should be 0 */ lpIVTAbc->rgMatched[cbTB - 1] = ~bFilter;
/*
* Set the currenly known total number of rows * that match the restriction. */
lpIVTAbc->ulRstrDenom = lpIVTAbc->ulMaxPos;
LeaveCriticalSection(&lpIVTAbc->cs);
out:
DebugTraceResult(IVTABC_Restrict, hResult); return hResult;
}
/*************************************************************************
* - IVTABC_QueryRows - * Attempts to retrieve ulRowCount rows from the .FAB file. Even in the * restricted case. * * */ STDMETHODIMP IVTABC_QueryRows( LPIVTABC lpIVTAbc, LONG lRowCount, ULONG ulFlags, LPSRowSet * lppRows ) { SCODE scode; HRESULT hResult = hrSuccess; LPSRowSet lpRowSet = NULL; LPSPropValue lpRow = NULL; int cbSizeOfRow; int cRows, iRow; int cCols; DWORD cbRead; ABCREC abcrec; ULONG ulOrigPosition;
/*
* Validate parameters */
/*
* Check to see if it's large enough to hold this object */ if (IsBadReadPtr(lpIVTAbc, SIZEOF(IVTABC))) { /*
* Not large enough */ hResult = ResultFromScode(E_INVALIDARG);
DebugTraceResult(IVTABC_QueryRows, hResult); return hResult; }
/*
* Check to see that it's the correct vtbl */ if (lpIVTAbc->lpVtbl != &vtblIVTABC) { /*
* Not my vtbl */ hResult = ResultFromScode(E_INVALIDARG);
DebugTraceResult(IVTABC_QueryRows, hResult); return hResult; }
/*
* Check the out parameter for writability */ if (IsBadWritePtr(lppRows, SIZEOF(LPSRowSet))) { hResult = ResultFromScode(E_INVALIDARG);
DebugTraceResult(IVTABC_QueryRows, hResult); return hResult; }
/*
* Never valid to ask for 0 rows */ if (!lRowCount) { hResult = ResultFromScode(E_INVALIDARG);
DebugTraceResult(IVTABC_QueryRows, hResult); return hResult; }
/* //$ MM2 Hack! Won't Read backwards for TR2 */ if (lRowCount < 0) { hResult = ResultFromScode(E_INVALIDARG);
DebugTraceResult(IVTABC_QueryRows, hResult); return hResult; }
/*
* Check the flags */ if (ulFlags & ~TBL_NOADVANCE) { hResult = ResultFromScode(MAPI_E_UNKNOWN_FLAGS);
DebugTraceResult(IVTABC_QueryRows, hResult); return hResult; }
EnterCriticalSection(&lpIVTAbc->cs);
/*
* Open the file */ hResult = HrOpenFile(lpIVTAbc); if (HR_FAILED(hResult)) { goto out; }
ulOrigPosition = lpIVTAbc->ulPosition;
/*
* Calculate # of rows that will be read. */ cRows = (int)lpIVTAbc->ulMaxPos - (int)lpIVTAbc->ulPosition; cRows = (cRows < (int)lRowCount ? cRows : (int)lRowCount);
/*
* Allocate array for SRowSet */
scode = lpIVTAbc->lpAllocBuff(sizeof(ULONG) + cRows * SIZEOF(SRow), (LPVOID *) &lpRowSet); if (FAILED(scode)) { hResult = ResultFromScode(scode);
goto out; }
/*
* Initialize - so we can clean up later if we have to... */ lpRowSet->cRows = cRows;
for( iRow = 0; iRow < cRows; iRow++ ) { lpRowSet->aRow[iRow].lpProps = NULL; }
/*
* Seek to correct position in file */ (void) SetFilePointer( lpIVTAbc->hFile, lpIVTAbc->ulPosition * SIZEOF(ABCREC), NULL, FILE_BEGIN );
/*
* Read each row from the file */ for (iRow = 0; iRow < cRows; iRow++) {
/* The only properties available are:
* * PR_DISPLAY_NAME, PR_ENTRYID, PR_ADDRTYPE, PR_EMAIL_ADDRESS, * PR_OBJECT_TYPE, PR_DISPLAY_TYPE */
/*
* Handle restricted lists */ if (lpIVTAbc->lpszPartialName) { ULONG ulPos = lpIVTAbc->ulPosition;
next: if (ulPos == lpIVTAbc->ulMaxPos) { break; }
if (!FChecked(lpIVTAbc, ulPos)) { hResult = HrValidateEntry(lpIVTAbc, ulPos); if (HR_FAILED(hResult)) { goto err; } }
if (!FMatched(lpIVTAbc, ulPos)) { ulPos++; goto next; }
lpIVTAbc->ulPosition = ulPos; (void) SetFilePointer( lpIVTAbc->hFile, lpIVTAbc->ulPosition * SIZEOF(ABCREC), NULL, FILE_BEGIN );
}
lpIVTAbc->ulPosition++;
/*
* Read in the record from the file */ if ( !ReadFile( lpIVTAbc->hFile, (LPVOID) &abcrec, SIZEOF(ABCREC), &cbRead, NULL) ) { hResult = ResultFromScode(MAPI_E_DISK_ERROR); SetErrorIDS(lpIVTAbc, hResult, IDS_FAB_NO_READ);
goto err; } /* Second check */ if ((UINT) cbRead != SIZEOF(ABCREC)) { /*
* Should never get here. */ hResult = ResultFromScode(MAPI_E_DISK_ERROR); SetErrorIDS(lpIVTAbc, hResult, IDS_FAB_NO_READ);
goto err; }
/* Allocate memory to start a row.
*/ cbSizeOfRow = SIZEOF(ULONG) + (int)lpIVTAbc->lpPTAColSet->cValues * SIZEOF(SPropValue);
scode = lpIVTAbc->lpAllocBuff(cbSizeOfRow, (LPVOID *) &lpRow); if (FAILED(scode)) { hResult = ResultFromScode(scode);
goto err; }
/*
* Get all the data */ for (cCols = 0; cCols < (int)lpIVTAbc->lpPTAColSet->cValues; cCols++) { switch (lpIVTAbc->lpPTAColSet->aulPropTag[cCols]) { case PR_DISPLAY_NAME_A: {
INT cch = lstrlen(abcrec.rgchDisplayName) + 1;
lpRow[cCols].ulPropTag = PR_DISPLAY_NAME_A; scode = lpIVTAbc->lpAllocMore( cch, lpRow, (LPVOID *) &(lpRow[cCols].Value.lpszA) );
if (FAILED(scode)) { lpRow[cCols].ulPropTag = PROP_TAG(PT_ERROR, PROP_ID(PR_DISPLAY_NAME_A)); lpRow[cCols].Value.err = scode; } else { #ifdef UNICODE
lpRow[cCols].Value.lpszA[0] = 0; WideCharToMultiByte( CP_ACP, 0, abcrec.rgchDisplayName, -1, lpRow[cCols].Value.lpszA, cch, NULL, NULL ); #else
lstrcpy(lpRow[cCols].Value.LPSZ, abcrec.rgchDisplayName); #endif
}
} break;
case PR_EMAIL_ADDRESS_A: {
INT cch = lstrlen(abcrec.rgchEmailAddress) + 1;
lpRow[cCols].ulPropTag = PR_EMAIL_ADDRESS_A; scode = lpIVTAbc->lpAllocMore( cch, lpRow, (LPVOID *) &(lpRow[cCols].Value.lpszA) );
if (FAILED(scode)) { lpRow[cCols].ulPropTag = PROP_TAG(PT_ERROR, PROP_ID(PR_EMAIL_ADDRESS_A)); lpRow[cCols].Value.err = scode; } else { #ifdef UNICODE
lpRow[cCols].Value.lpszA[0] = 0; WideCharToMultiByte( CP_ACP, 0, abcrec.rgchEmailAddress, -1, lpRow[cCols].Value.lpszA, cch, NULL, NULL ); #else
lstrcpy(lpRow[cCols].Value.LPSZ, abcrec.rgchEmailAddress); #endif
}
} break;
case PR_ADDRTYPE_A: { /*
* AddrType is always "MSPEER" for the FAB */
INT cch = lstrlen(lpszEMT) + 1;
lpRow[cCols].ulPropTag = PR_ADDRTYPE_A; scode = lpIVTAbc->lpAllocMore( cch, lpRow, (LPVOID *) &(lpRow[cCols].Value.lpszA) );
if (FAILED(scode)) { lpRow[cCols].ulPropTag = PROP_TAG(PT_ERROR, PROP_ID(PR_ADDRTYPE_A)); lpRow[cCols].Value.err = scode; } else { #ifdef UNICODE
lpRow[cCols].Value.lpszA[0] = 0; WideCharToMultiByte( CP_ACP, 0, lpszEMT, -1, lpRow[cCols].Value.lpszA, cch, NULL, NULL ); #else
lstrcpy(lpRow[cCols].Value.LPSZ, lpszEMT); #endif
}
} break;
case PR_ENTRYID: { /*
* Fixed sized entryid. Basically just the .FAB file record */ LPUSR_ENTRYID lpUsrEid;
lpRow[cCols].ulPropTag = PR_ENTRYID; scode = lpIVTAbc->lpAllocMore (SIZEOF(USR_ENTRYID), lpRow, (LPVOID *) &(lpRow[cCols].Value.bin.lpb));
if (FAILED(scode)) { lpRow[cCols].ulPropTag = PROP_TAG(PT_ERROR, PROP_ID(PR_ENTRYID)); lpRow[cCols].Value.err = scode; } else { lpUsrEid = (LPUSR_ENTRYID) lpRow[cCols].Value.bin.lpb;
RtlZeroMemory(lpUsrEid, SIZEOF(USR_ENTRYID));
/* Size of entryid */ lpRow[cCols].Value.bin.cb = SIZEOF(USR_ENTRYID);
lpUsrEid->abFlags[0] = 0; /* long-term, recipient */ lpUsrEid->abFlags[1] = 0; lpUsrEid->abFlags[2] = 0; lpUsrEid->abFlags[3] = 0; lpUsrEid->muid = muidABMAWF; lpUsrEid->ulVersion = MAWF_VERSION; lpUsrEid->ulType = MAWF_USER; lpUsrEid->abcrec = abcrec; }
} break;
case PR_OBJECT_TYPE: { /*
* MailUser */
lpRow[cCols].ulPropTag = PR_OBJECT_TYPE; lpRow[cCols].Value.ul = MAPI_MAILUSER; } break;
case PR_DISPLAY_TYPE: { /*
* MailUser */
lpRow[cCols].ulPropTag = PR_DISPLAY_TYPE; lpRow[cCols].Value.ul = DT_MAILUSER;
} break;
case PR_INSTANCE_KEY: { LPABCRecInstance lpABCRecInstance; UINT cbRecInstance; /*
* Instance keys are made up of: * ulRecordPosition - current position in the file * filetime - current date and time stamp of file * lpszFileName - current file that we're browsing */ lpRow[cCols].ulPropTag = PR_INSTANCE_KEY;
cbRecInstance = SIZEOF(ABCRecInstance)+(lstrlen(lpIVTAbc->lpszFileName)+1)*SIZEOF(TCHAR); scode = lpIVTAbc->lpAllocMore(cbRecInstance, lpRow, (LPVOID) &(lpRow[cCols].Value.bin.lpb));
if (FAILED(scode)) { lpRow[cCols].ulPropTag = PROP_TAG(PT_ERROR, PROP_ID(PR_INSTANCE_KEY)); lpRow[cCols].Value.err = scode; } else { lpABCRecInstance = (LPABCRecInstance) lpRow[cCols].Value.bin.lpb;
ZeroMemory(lpABCRecInstance, cbRecInstance);
lpRow[cCols].Value.bin.cb = (ULONG) cbRecInstance;
lpABCRecInstance->ulRecordPosition = lpIVTAbc->ulPosition; lpABCRecInstance->filetime = lpIVTAbc->filetime; lstrcpy(lpABCRecInstance->rgchzFileName, lpIVTAbc->lpszFileName);
} } break;
default: { lpRow[cCols].ulPropTag = PROP_TAG(PT_ERROR, PROP_ID(lpIVTAbc->lpPTAColSet->aulPropTag[cCols])); lpRow[cCols].Value.err = MAPI_E_NOT_FOUND; } break; } }
/* # of columns */ lpRowSet->aRow[iRow].cValues = lpIVTAbc->lpPTAColSet->cValues;
/* Actual row of data */ lpRowSet->aRow[iRow].lpProps = lpRow;
lpRow = NULL;
}
/*
* it's always iRow. */ lpRowSet->cRows = iRow;
/*
* Handle Seeked position stuff */ if (ulFlags & TBL_NOADVANCE) { /*
* Set it back to it's original position */ lpIVTAbc->ulPosition = ulOrigPosition; }
*lppRows = lpRowSet;
out: LeaveCriticalSection(&lpIVTAbc->cs);
DebugTraceResult(IVTABC_QueryRows, hResult); return hResult;
err: /*
* Clean up memory... */
/* Free the row */ lpIVTAbc->lpFreeBuff(lpRow);
/* Clean up the rest of the rows */ FreeProws(lpRowSet);
*lppRows = NULL;
goto out;
}
|