windows-nt/Source/XPSP1/NT/printscan/fax/exchange/ab/abctbl2.c
2020-09-26 16:20:57 +08:00

1739 lines
41 KiB
C

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