1739 lines
41 KiB
C
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;
|
||
|
|
||
|
}
|
||
|
|