ABCTBL2.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-1995 Microsoft Corporation.  All Rights Reserved. 
 * 
 ***********************************************************************/ 
 
#include "abp.h" 
#include "abctbl.h" 
#include "sampabp.rh" 
 
/************************************************************************* 
 * 
 -  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 
     */ 
 
    IVTABC_ValidateObject(SeekRow, lpIVTAbc); 
 
    Validate_IMAPITable_SeekRow(lpIVTAbc, bkOrigin, lRowCount, lplRowsSought); 
 
 
    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 
     */ 
 
    IVTABC_ValidateObject(SeekRowApprox, lpIVTAbc); 
 
    Validate_IMAPITable_SeekRowApprox(lpIVTAbc, ulNumerator, ulDenominator); 
 
 
    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 
     */ 
 
    IVTABC_ValidateObject(GetRowCount, lpIVTAbc); 
 
    Validate_IMAPITable_GetRowCount(lpIVTAbc, ulFlags, lpulCount); 
 
 
    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 
     */ 
 
    IVTABC_ValidateObject(QueryPosition, lpIVTAbc); 
 
    Validate_IMAPITable_QueryPosition(lpIVTAbc, lpulRow, lpulNumerator, 
                                        lpulDenominator); 
 
    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; 
    LPSTR szPrefix; 
    int nCmpResult; 
 
    ULONG ulCurMin; 
    ULONG ulCurMac; 
    ULONG ulPosT; 
 
    /* 
     *  Validate parameters 
     */ 
 
    IVTABC_ValidateObject(FindRow, lpIVTAbc); 
 
    Validate_IMAPITable_FindRow(lpIVTAbc, lpRestriction, bkOrigin, ulFlags); 
 
 
    /* 
     *  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 prefix search on display name 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.lpszA; 
 
    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_SAB_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) 
{ 
    LPSTR szT = NULL; 
    LPSTR lpszTNew = NULL; 
    ULONG cbTB = 0; 
    BYTE bFilter = 0; 
    SCODE scode; 
    HRESULT hResult = hrSuccess; 
 
    /* 
     *  Validate parameters 
     */ 
 
    IVTABC_ValidateObject(Restrict, lpIVTAbc); 
 
    Validate_IMAPITable_Restrict(lpIVTAbc, lpRestriction, ulFlags); 
 
 
    /* 
     *  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.lpszA) 
    { 
        hResult = ResultFromScode(E_INVALIDARG); 
         
        goto out; 
    } 
 
 
    szT = lpRestriction->res.resProperty.lpProp->Value.lpszA; 
 
    /* 
     *  Skip over leading spaces 
     */ 
 
    while (*szT == ' ') 
        szT++; 
 
    /* 
     *  Empty string is not defined - it's a bad restriction 
     */ 
    if (*szT == '\0') 
    { 
        hResult = ResultFromScode(E_INVALIDARG); 
        goto out; 
    } 
 
 
    /* 
     *  Copy the string for the partial name 
     */ 
 
    scode = lpIVTAbc->lpAllocBuff(lstrlenA(szT) + 1, (LPVOID *) &lpszTNew); 
    if (FAILED(scode)) 
    { 
        /* 
         *  Memory error 
         */ 
 
        hResult = ResultFromScode(scode); 
        goto out; 
    } 
    lstrcpyA(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 .SAB 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 
     */ 
 
    IVTABC_ValidateObject(QueryRows, lpIVTAbc); 
 
    Validate_IMAPITable_QueryRows(lpIVTAbc, lRowCount, ulFlags, lppRows); 
 
 
    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_SAB_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_SAB_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: 
                { 
 
                    lpRow[cCols].ulPropTag = PR_DISPLAY_NAME_A; 
                    scode = lpIVTAbc->lpAllocMore (lstrlenA(abcrec.rgchDisplayName) + 1, 
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 
                    { 
 
                        lstrcpyA(lpRow[cCols].Value.lpszA, 
                            abcrec.rgchDisplayName); 
                    } 
 
                } 
                break; 
 
            case PR_EMAIL_ADDRESS_A: 
                { 
 
                    lpRow[cCols].ulPropTag = PR_EMAIL_ADDRESS_A; 
                    scode = lpIVTAbc->lpAllocMore ( 
                                lstrlenA(abcrec.rgchEmailAddress) + 1, 
                                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 
                    { 
 
                        lstrcpyA(lpRow[cCols].Value.lpszA, 
                            abcrec.rgchEmailAddress); 
                    } 
 
                } 
                break; 
 
            case PR_ADDRTYPE: 
                { 
                    /* 
                     *  AddrType is always "MSPEER" for the SAB 
                     */ 
 
                    lpRow[cCols].ulPropTag = PR_ADDRTYPE_A; 
                    scode = lpIVTAbc->lpAllocMore (lstrlenA(lpszEMT) + 1, 
                                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 
                    { 
 
                        lstrcpyA(lpRow[cCols].Value.lpszA, lpszEMT); 
                    } 
 
                } 
                break; 
 
            case PR_ENTRYID: 
                { 
                    /* 
                     *  Fixed sized entryid.  Basically just the .SAB 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; 
 
                        ZeroMemory(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 = muidABSample; 
                        lpUsrEid->ulVersion = SAMP_VERSION; 
                        lpUsrEid->ulType = SAMP_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; 
                    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; 
 
}