home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / sdk / dbmsg / mapi / flatfile.ab / abctbl1.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-04-11  |  26.5 KB  |  923 lines

  1. /***********************************************************************
  2.  *
  3.  *  ABCTBL1.C
  4.  *
  5.  *  Contents Table
  6.  *
  7.  *  The contents table associated with this provider.  It's file based.
  8.  *  The format of the .SAB file is in ABP.H.
  9.  *
  10.  *  This implementation of IMAPITable is retrieved by calling the
  11.  *  GetContentsTable() method of the sample ABP's single directory (see
  12.  *  abcont.c).
  13.  *
  14.  *  There are a few interesting features in this implementation.  First
  15.  *  it's implemented on a flat file (.SAB).  Second, it actually supports
  16.  *  an implementation of ANR (Ambiguous Name Resolution).  And lastly, it
  17.  *  supports FindRow (limited to prefix searching on display names).
  18.  *
  19.  *  This is the minimum set of restrictions that your provider MUST support.
  20.  *  It MUST have an ANR implementation and support prefix (downward) searching
  21.  *  on whatever your table is sorted on (in this case PR_DISPLAY_NAME).
  22.  *
  23.  *  The browsing of a flat file is done a record at a time.  It's never
  24.  *  completely read into memory.  It only reads records from the file when
  25.  *  it absolutely has to (like in QueryRows).  The advantage to this is
  26.  *  a low memory footprint and the ability to browse rather large files
  27.  *  with decent performance.
  28.  */
  29. /*
  30.  *  ANR is also supported in this implementation.  In the code will often
  31.  *  be 'if' statements making two different code paths between the restricted
  32.  *  and unrestricted version.  The restrictions rely on a couple of
  33.  *  bit arrays.  Each bit corresponds (in order) to the records in the .SAB
  34.  *  file.  One bit array, rgChecked, says whether or not a record in the
  35.  *  .SAB file has actually been compared to the restriction.  It's initially
  36.  *  set to all 0s - which means that none of the records have been checked.
  37.  *  The second bit array, rgMatched, says whether or not the particular
  38.  *  record matches the current restriction.  This array is initialized to all
  39.  *  1s - which says that all the records in the .SAB file match the current
  40.  *  restriction.  The reason for this is for the fraction returned in
  41.  *  QueryPosition--By assuming that all the rows match and only updating
  42.  *  the array when something doesn't match, the fraction returned in
  43.  *  QueryPosition will get larger and has the effect of making the thumb-bar
  44.  *  on a listbox implemented on top of this table to scroll down as you go
  45.  *  down the list.
  46.  *
  47.  *  As a row is about to be read it is checked to see if it's been compared
  48.  *  to the current restriction.  If it has then to determine whether or not
  49.  *  to actually read the record and build the row we just look at the matched
  50.  *  bit array.  If it doesn't match we go on to the next record and check
  51.  *  again.  If it does match we read the record and build the row.
  52.  *
  53.  *  Only if it hasn't been checked do we actually go and read the row and
  54.  *  compare it to the current restriction, setting the rgChecked and
  55.  *  rgMatched bits accordingly.
  56.  *
  57.  *  In this implementation the ANR comparison rules are as follows:
  58.  *  (See FNameMatch for the actual code to do this)
  59.  *
  60.  *    A 'word' is defined as any substring separated by separators.
  61.  *    The separators are defined as ',', ' ', and '-'.
  62.  *    A restriction is said to match a display name iff all the words
  63.  *    in the restriction are all prefixes of words in the display name.
  64.  *
  65.  *    For example, a restriction of "b d" will match:
  66.  *     "Barney Donovan"
  67.  *     "Donovan, Barney"
  68.  *     "Danielle Blumenthal"
  69.  *    But will not match:
  70.  *     "Darby Opal"
  71.  *     "Ben Masters"
  72.  *
  73.  *  Other providers can do whatever matching they want with the ANR
  74.  *  restriction.  For example, soundex or additional field comparisons (like
  75.  *  email addresses).  A good (and fast) implementation will differentiate
  76.  *  your provider from others in a positive way.
  77.  *
  78.  *  FindRow's implementation effectively handles prefix searching on display
  79.  *  names (PR_DISPLAY_NAME).  It does this by binary searching the .SAB file.
  80.  *  The only tricky part is knowing when to stop.  Basically you want to stop
  81.  *  on the first name in the list that matches the restriction.  It's easy to
  82.  *  do linearly, but a little more trick with a binary search.  This
  83.  *  implementation is a reasonable example.
  84.  *
  85.  *
  86.  *  This table has only the following columns:
  87.  */
  88.  
  89. #include "abp.h"
  90. #include "abctbl.h"
  91. #include "sampabp.rh"
  92.  
  93. const SizedSPropTagArray(cvalvtMax, tagaivtabcColSet) =
  94. {
  95.     cvalvtMax,
  96.     {
  97.         PR_DISPLAY_NAME_A,
  98.         PR_ENTRYID,
  99.         PR_ADDRTYPE_A,
  100.         PR_EMAIL_ADDRESS_A,
  101.         PR_OBJECT_TYPE,
  102.         PR_DISPLAY_TYPE,
  103.         PR_INSTANCE_KEY
  104.     }
  105. };
  106. const LPSPropTagArray ptagaivtabcColSet = (LPSPropTagArray) &tagaivtabcColSet;
  107.  
  108. /*
  109.  *
  110.  *  The following routines are implemented in the files abctbl2.c and abctbl3.c:
  111.  *
  112.  *
  113.  *      IVTABC_Release
  114.  *      IVTABC_GetStatus
  115.  *      IVTABC_SetColumns
  116.  *      IVTABC_QueryColumns
  117.  *      IVTABC_GetRowCount
  118.  *      IVTABC_SeekRow
  119.  *      IVTABC_SeekRowApprox
  120.  *      IVTABC_QueryPosition
  121.  *      IVTABC_FindRow
  122.  *      IVTABC_Restrict
  123.  *      IVTABC_CreateBookmark
  124.  *      IVTABC_FreeBookmark
  125.  *      IVTABC_SortTable
  126.  *      IVTABC_QuerySortOrder
  127.  *      IVTABC_QueryRows
  128.  *      IVTABC_Abort
  129.  *      IVTABC_ExpandRow
  130.  *      IVTABC_CollapseRow
  131.  *      IVTABC_WaitForCompletion
  132.  *      IVTABC_GetCollapseState
  133.  *      IVTABC_SetCollapseState
  134.  *
  135.  *
  136.  *  This file (abctbl1.c) has all the utility functions used throughout this
  137.  *  objects methods.  They are the following:
  138.  *
  139.  *      HrNewIVTAbc()
  140.  *      HrValidateEntry()
  141.  *      FChecked()
  142.  *      FMatched()
  143.  *      FNameMatch()
  144.  *      HrOpenFile()
  145.  *      fIVTAbcIdleRoutine()
  146.  *      FreeANRBitmaps()
  147.  *
  148.  *
  149.  *  Copyright 1992-1995 Microsoft Corporation.  All Rights Reserved.
  150.  *
  151.  ***********************************************************************/
  152.  
  153. /*
  154.  *  vtbl filled in here.
  155.  */
  156.  
  157. const IVTABC_Vtbl vtblIVTABC =
  158. {
  159.  
  160.     IVTABC_QueryInterface,
  161.     (IVTABC_AddRef_METHOD *)        ROOT_AddRef,
  162.     IVTABC_Release,
  163.     (IVTABC_GetLastError_METHOD *)  ROOT_GetLastError,
  164.     IVTABC_Advise,
  165.     IVTABC_Unadvise,
  166.     IVTABC_GetStatus,
  167.     IVTABC_SetColumns,
  168.     IVTABC_QueryColumns,
  169.     IVTABC_GetRowCount,
  170.     IVTABC_SeekRow,
  171.     IVTABC_SeekRowApprox,
  172.     IVTABC_QueryPosition,
  173.     IVTABC_FindRow,
  174.     IVTABC_Restrict,
  175.     IVTABC_CreateBookmark,
  176.     IVTABC_FreeBookmark,
  177.     IVTABC_SortTable,
  178.     IVTABC_QuerySortOrder,
  179.     IVTABC_QueryRows,
  180.     IVTABC_Abort,
  181.     IVTABC_ExpandRow,
  182.     IVTABC_CollapseRow,
  183.     IVTABC_WaitForCompletion,
  184.     IVTABC_GetCollapseState,
  185.     IVTABC_SetCollapseState
  186. };
  187.  
  188.  
  189. /* Idle function */
  190. FNIDLE fIVTAbcIdleRoutine;
  191.  
  192. #define     IVTABC_IDLE_INTERVAL        300L
  193. #define     IVTABC_IDLE_PRIORITY        -2
  194. #define     IVTABC_IDLE_FLAGS           FIROINTERVAL
  195.  
  196. /*************************************************************************
  197.  *
  198.  -  NewIVTAbc
  199.  -
  200.  *  Creates a new IMAPITable on the contents of a .SAB file.
  201.  *
  202.  *
  203.  */
  204. HRESULT 
  205. HrNewIVTAbc(LPMAPITABLE *       lppIVTAbc,
  206.             LPABLOGON           lpABLogon,
  207.             LPABCONT            lpABC,
  208.             HINSTANCE           hLibrary,
  209.             LPALLOCATEBUFFER    lpAllocBuff,
  210.             LPALLOCATEMORE      lpAllocMore,
  211.             LPFREEBUFFER        lpFreeBuff,
  212.             LPMALLOC            lpMalloc )
  213. {
  214.     LPIVTABC lpIVTAbc = NULL;
  215.     SCODE scode;
  216.     HRESULT hResult = hrSuccess;
  217.     ULONG ulBK, ulSize, ulSizeHigh;
  218.  
  219.     /*
  220.      *  Allocate space for the IVTABC structure
  221.      */
  222.  
  223.     scode = lpAllocBuff(sizeof(IVTABC), (LPVOID *) &lpIVTAbc);
  224.     if (FAILED(scode))
  225.     {
  226.         hResult = ResultFromScode(scode);
  227.         goto err;
  228.     }
  229.  
  230.     lpIVTAbc->lpVtbl = &vtblIVTABC;
  231.     lpIVTAbc->lcInit = 1;
  232.     lpIVTAbc->hResult = hrSuccess;
  233.     lpIVTAbc->idsLastError = 0;
  234.  
  235.     lpIVTAbc->hLibrary = hLibrary;
  236.     lpIVTAbc->lpAllocBuff = lpAllocBuff;
  237.     lpIVTAbc->lpAllocMore = lpAllocMore;
  238.     lpIVTAbc->lpFreeBuff = lpFreeBuff;
  239.     lpIVTAbc->lpMalloc = lpMalloc;
  240.     lpIVTAbc->lpABLogon = lpABLogon;
  241.  
  242.     lpIVTAbc->lpszFileName = NULL;
  243.     hResult = HrLpszGetCurrentFileName(lpABLogon, &(lpIVTAbc->lpszFileName));
  244.     if (HR_FAILED(hResult))
  245.     {
  246.         goto err;
  247.     }
  248.  
  249.     lpIVTAbc->lpPTAColSet = (LPSPropTagArray) &tagaivtabcColSet;
  250.  
  251.     /*
  252.      *  Open the .SAB file associated with this logged in session.
  253.      *  Currently it's opened with FILE_SHARED_READ.  This has an
  254.      *  unpleasant side-effect of not being able to modify the .SAB
  255.      *  file while this table is active.
  256.      *
  257.      *  It should be OF_SHARE_DENY_NONE.  I don't have the code to
  258.      *  handle this in this version.
  259.      */
  260.     if ((lpIVTAbc->hFile = CreateFile(
  261.                 lpIVTAbc->lpszFileName,
  262.                 GENERIC_READ,
  263.                 FILE_SHARE_READ|FILE_SHARE_WRITE,
  264.                 NULL,
  265.                 OPEN_EXISTING,
  266.                 FILE_ATTRIBUTE_NORMAL,
  267.                 NULL)) == INVALID_HANDLE_VALUE)
  268.     {
  269.         /*
  270.          *  The file didn't open...
  271.          */
  272.  
  273.         hResult = ResultFromScode(MAPI_E_UNABLE_TO_COMPLETE);
  274.         SetErrorIDS(lpABC, hResult, IDS_CANT_OPEN_SAB);
  275.  
  276.         goto err;
  277.     }
  278.  
  279.     /*
  280.      *  Get the time and date stamp
  281.      *
  282.      */
  283.     (void)GetFileTime(lpIVTAbc->hFile, NULL, NULL, &(lpIVTAbc->filetime));
  284.  
  285.     /*  Get the size of the file */
  286.     if ((ulSize = GetFileSize(lpIVTAbc->hFile, &ulSizeHigh)) == 0xFFFFFFFF)
  287.     {
  288.         /*
  289.          *  MAYBE I have an error
  290.          */
  291.         if (GetLastError() != NO_ERROR)
  292.         {
  293.             hResult = ResultFromScode(MAPI_E_UNABLE_TO_COMPLETE);
  294.             SetErrorIDS(lpABC, hResult, IDS_SAB_FILE_ATTRIB);
  295.             goto err;
  296.         }
  297.  
  298.         hResult = ResultFromScode(MAPI_E_UNABLE_TO_COMPLETE);
  299.         SetErrorIDS(lpABC, hResult, IDS_SAB_TOO_LARGE);
  300.         goto err;
  301.     }
  302.  
  303.     /*
  304.      *  Actual number of valid positions
  305.      */
  306.     lpIVTAbc->ulMaxPos = (ulSize / sizeof(ABCREC));
  307.  
  308.     /*
  309.      *  Check to see if it's an exact multiple of sizeof(ABCREC)
  310.      */
  311.     if (lpIVTAbc->ulMaxPos * sizeof(ABCREC) != ulSize)
  312.     {
  313.         /*
  314.          *  Nope.
  315.          */
  316.  
  317.         hResult = ResultFromScode(MAPI_E_UNABLE_TO_COMPLETE);
  318.         SetErrorIDS(lpABC, hResult, IDS_SAB_CORRUPT);
  319.         goto err;
  320.     }
  321.  
  322.     lpIVTAbc->ulPosition = 0;
  323.  
  324.     /*  Setup bookmarks  */
  325.     for (ulBK = 0; ulBK < MAX_BOOKMARKS; lpIVTAbc->rglpABCBK[ulBK++] = NULL);
  326.  
  327.     /*
  328.      *  Restriction stuff
  329.      */
  330.  
  331.     lpIVTAbc->rgChecked = NULL;
  332.     lpIVTAbc->rgMatched = NULL;
  333.     lpIVTAbc->lpszPartialName = NULL;
  334.  
  335.     /*
  336.      *  Registered notification stuff
  337.      */
  338.  
  339.     lpIVTAbc->cAdvise = 0;
  340.     lpIVTAbc->parglpAdvise = NULL;
  341.     lpIVTAbc->ulConnectMic = (ULONG) lpIVTAbc & 0xffffff;
  342.     InitializeCriticalSection(&lpIVTAbc->cs);
  343.  
  344.     /*
  345.      *  Register the idle function
  346.      */
  347.  
  348.     lpIVTAbc->ftg = FtgRegisterIdleRoutine(
  349.         fIVTAbcIdleRoutine,
  350.         lpIVTAbc,
  351.         IVTABC_IDLE_PRIORITY,
  352.         IVTABC_IDLE_INTERVAL,
  353.         IVTABC_IDLE_FLAGS);
  354.  
  355.     InitializeCriticalSection(&lpIVTAbc->cs);
  356.  
  357.     /*  We must AddRef the lpABLogon object since we will be using it
  358.      */
  359.     lpABLogon->lpVtbl->AddRef(lpABLogon);
  360.  
  361.     *lppIVTAbc = (LPVOID) lpIVTAbc;
  362.  
  363. out:
  364.  
  365.         
  366.     DebugTraceResult(HrNewIVTAbc, hResult);
  367.     return hResult;
  368.  
  369. err:
  370.     if (lpIVTAbc)
  371.     {
  372.         if (lpIVTAbc->hFile != INVALID_HANDLE_VALUE)
  373.         {
  374.             /*
  375.              *  Must've opened the file
  376.              */
  377.             CloseHandle(lpIVTAbc->hFile);
  378.         }
  379.  
  380.         /*  Free the current .SAB file name */
  381.         lpFreeBuff(lpIVTAbc->lpszFileName);
  382.  
  383.         /*  Free the mem */
  384.         lpFreeBuff( lpIVTAbc );
  385.     }
  386.  
  387.     goto out;
  388.  
  389. }
  390.  
  391. /*************************************************************************
  392.  *
  393.  -  HrValidateEntry
  394.  -
  395.  *
  396.  *  Used in restricted lists
  397.  *  Checks to see if a given entry at a particular location matches
  398.  *  the active restriction.  It always modifies rgChecked, and may
  399.  *  modify rgMatched.
  400.  */
  401. HRESULT 
  402. HrValidateEntry(LPIVTABC lpIVTAbc, ULONG ulNewPos)
  403. {
  404.     ABCREC abcrec;
  405.     ULONG cbRead;
  406.     HRESULT hResult;
  407.  
  408.     /*
  409.      *  Open the file
  410.      */
  411.     hResult = HrOpenFile(lpIVTAbc);
  412.     if (HR_FAILED(hResult))
  413.     {
  414.         DebugTraceResult(HrValidateEntry, hResult);
  415.         return hResult;
  416.     }
  417.  
  418.     /*
  419.      *  Set the file position to lNewPos
  420.      */
  421.  
  422.     (void) SetFilePointer(lpIVTAbc->hFile, ulNewPos * sizeof(ABCREC),
  423.                           NULL, FILE_BEGIN);
  424.  
  425.     /*
  426.      *  Read in the record from the file
  427.      */
  428.     if (!ReadFile(lpIVTAbc->hFile, (LPVOID) &abcrec,
  429.             sizeof(ABCREC), &cbRead, NULL))
  430.     {
  431.         DebugTraceSc(HrValidateEntry, MAPI_E_DISK_ERROR);
  432.         return ResultFromScode(MAPI_E_DISK_ERROR);
  433.     }
  434.  
  435.     /*  Second check  */
  436.     if (cbRead != sizeof(ABCREC))
  437.     {
  438.         DebugTraceSc(HrValidateEntry, MAPI_E_DISK_ERROR);
  439.         return ResultFromScode(MAPI_E_DISK_ERROR);
  440.     }
  441.  
  442.     /*
  443.      *  Always set the Checked flag
  444.      */
  445.     lpIVTAbc->rgChecked[ulNewPos / 8] |= (((unsigned char)0x80) >> (ulNewPos % 8));
  446.  
  447.     /*
  448.      *  See if the rgchDisplayName matches the restriction
  449.      */
  450.     if (!FNameMatch(lpIVTAbc, abcrec.rgchDisplayName))
  451.     {
  452.         /*
  453.          *  Apparently not.  Reset the Matched flag
  454.          */
  455.  
  456.         lpIVTAbc->ulRstrDenom--;
  457.  
  458.         lpIVTAbc->rgMatched[ulNewPos / 8] &= ~(((unsigned char)0x80) >> (ulNewPos % 8));
  459.     }
  460.  
  461.     return hrSuccess;
  462. }
  463.  
  464. /*************************************************************************
  465.  *
  466.  -  FChecked
  467.  -
  468.  *
  469.  *  Returns whether or not an entry has ever been checked
  470.  *  Just looks at the bit in the rgChecked array that corresponds with
  471.  *  lNewPos
  472.  *
  473.  */
  474. BOOL
  475. FChecked(LPIVTABC lpIVTAbc, ULONG ulNewPos)
  476. {
  477.     ULONG ulT = (ULONG) (lpIVTAbc->rgChecked[ulNewPos / 8] & (((unsigned char)0x80) >> (ulNewPos % 8)));
  478.  
  479.     return (BOOL) !!ulT;
  480. }
  481.  
  482. /*************************************************************************
  483.  *
  484.  -  FMatched
  485.  -
  486.  *
  487.  *  Returns whether or not an entry has been matched
  488.  *  Just checks the bit in the rgMatched array corresponding with
  489.  *  lNewPos
  490.  *
  491.  */
  492. BOOL
  493. FMatched(LPIVTABC lpIVTAbc, ULONG ulNewPos)
  494. {
  495.     ULONG ulT = (lpIVTAbc->rgMatched[ulNewPos / 8] & (((unsigned char)0x80) >> (ulNewPos % 8)));
  496.  
  497.     return (BOOL) !!ulT;
  498.  
  499. }
  500.  
  501. /*************************************************************************
  502.  *
  503.  -  FNameMatch
  504.  -
  505.  *  Tries to match the rgchDisplayName with the partial name of the
  506.  *  restriction.
  507.  *  It tries to prefix match each partial name component (i.e. word) with
  508.  *  each rgchDisplayName name component (i.e. word).  Only if all of them
  509.  *  match (from the partial name) does this return TRUE.
  510.  */
  511. BOOL
  512. FCharInString(LPSTR lpsz, CHAR ch);
  513.  
  514.  
  515. BOOL
  516. FNameMatch(LPIVTABC lpIVTAbc, LPSTR rgchDisplayName)
  517. {
  518.     LPSTR szANRSep = ", -";
  519.     LPSTR szANR = lpIVTAbc->lpszPartialName;
  520.     LPSTR pchEndSzANR = szANR + lstrlenA(szANR);
  521.     ULONG cchANRName;
  522.     ULONG cchFullNameName;
  523.     LPSTR szFullNameT;
  524.     LPSTR szT;
  525.  
  526.     /*  If someone tries to match more than an iwMOMax-part name, the function
  527.      *  will return fFalse.  But then if someone is trying to match a name
  528.      *  with iwMOMax parts, chances are they weren't going to get it right
  529.      *  anyway....
  530.      */
  531.  
  532. #define iwMOMax 50
  533.  
  534.     WORD rgwMO[iwMOMax];
  535.     int iwMOMac = 0;
  536.  
  537.     while (TRUE)
  538.     {
  539.         /*  Find the end of the partial name we're pointing at  */
  540.  
  541.         szT = szANR;
  542.         while (!FCharInString(szANRSep, *szT))
  543.             ++szT;
  544.         cchANRName = szT - szANR;
  545.  
  546.         /*  Check if it matches any name in the full name  */
  547.  
  548.         szFullNameT = rgchDisplayName;
  549.         while (TRUE)
  550.         {
  551.             szT = szFullNameT;
  552.  
  553.             /*  Find the length of the name in the full name  */
  554.             /*  we're checking against.                       */
  555.  
  556.             while (!FCharInString(szANRSep, *szT))
  557.                 ++szT;
  558.             cchFullNameName = szT - szFullNameT;
  559.  
  560.             if (cchANRName <= cchFullNameName &&
  561.                 CompareStringA( lcidUser,
  562.                                 NORM_IGNORECASE,
  563.                                 szANR,
  564.                                 (int) cchANRName,
  565.                                 szFullNameT,
  566.                                 (int) cchANRName) == 2 )
  567.             {
  568.                 int iwMO;
  569.  
  570.                 for (iwMO = 0; iwMO < iwMOMac; iwMO++)
  571.                     if (rgwMO[iwMO] == (WORD) (szFullNameT - rgchDisplayName))
  572.                         break;
  573.  
  574.                 /*  We found the partial name so check the next ANR part */
  575.                 if (iwMO == iwMOMac)
  576.                 {
  577.                     if (iwMOMac == iwMOMax - 1)
  578.                     {
  579.                         /*  If some user wants to match an iwMOMax part
  580.                          *  name, chances are it wasn't going to match
  581.                          *  anyway...
  582.                          */
  583.                         return FALSE;
  584.                     }
  585.                     rgwMO[iwMOMac++] = szFullNameT - rgchDisplayName;
  586.                     break;
  587.                 }
  588.             }
  589.  
  590.             /*  We didn't find the partial name this time around, so
  591.              *  try to check the next name in the full name.
  592.              */
  593.  
  594.             szFullNameT += cchFullNameName;
  595.  
  596.             while (*szFullNameT && FCharInString(szANRSep, *szFullNameT))
  597.                 ++szFullNameT;
  598.  
  599.             if (*szFullNameT == '\0')
  600.                 return FALSE;   /*  We never found the partial name. */
  601.         }
  602.  
  603.         /* We found the partial name, so check the next ANR part */
  604.  
  605.         szANR += cchANRName;
  606.         while (*szANR && FCharInString(szANRSep, *szANR))
  607.             ++szANR;
  608.  
  609.         if (*szANR == '\0')
  610.             return TRUE;        /* No more ANR to check, so we found `em all  */
  611.     }
  612.  
  613.     /*  Not reached (we hope...)  */
  614.     return FALSE;
  615. }
  616.  
  617. /*
  618.  -  HrOpenFile
  619.  -
  620.  *  Opens the .SAB file associated with the table and
  621.  *  checks whether the .SAB file has changed.
  622.  *  If it has changed, the table bookmarks and ANR bitmaps
  623.  *  are updated and everyone on the advise list is notified.
  624.  */
  625. HRESULT 
  626. HrOpenFile(LPIVTABC lpIVTAbc)
  627. {
  628.     HRESULT hResult = hrSuccess;
  629.     FILETIME filetime;
  630.     ULONG ulSize, ulSizeHigh, ulMaxPos;
  631.     LPSTR lpszFileName = NULL;
  632.  
  633.     /*
  634.      *  If file is not open, open it
  635.      */
  636.     if (lpIVTAbc->hFile == INVALID_HANDLE_VALUE)
  637.     {
  638.  
  639.         if (!FEqualSABFiles(lpIVTAbc->lpABLogon, lpIVTAbc->lpszFileName))
  640.         {
  641.             /*
  642.              *  Get the new file name
  643.              */
  644.             hResult = HrLpszGetCurrentFileName(lpIVTAbc->lpABLogon, &lpszFileName);
  645.             if (HR_FAILED(hResult))
  646.             {
  647.                 goto err;
  648.             }
  649.  
  650.             /*
  651.              *  Replace the old one with this
  652.              */
  653.             lpIVTAbc->lpFreeBuff(lpIVTAbc->lpszFileName);
  654.             lpIVTAbc->lpszFileName = lpszFileName;
  655.  
  656.             lpszFileName = NULL;
  657.         }
  658.  
  659.         
  660.         /*
  661.          *  File is not open so lets try to open it
  662.          */
  663.         lpIVTAbc->hFile = CreateFile(
  664.             lpIVTAbc->lpszFileName,
  665.             GENERIC_READ,
  666.             FILE_SHARE_READ|FILE_SHARE_WRITE,
  667.             NULL,
  668.             OPEN_EXISTING,
  669.             FILE_ATTRIBUTE_NORMAL,
  670.             NULL);
  671.  
  672.         if (lpIVTAbc->hFile == INVALID_HANDLE_VALUE)
  673.         {
  674.             /*
  675.              *  The file didn't open...
  676.              */
  677.             hResult = ResultFromScode(MAPI_E_UNABLE_TO_COMPLETE);
  678.             SetErrorIDS(lpIVTAbc, hResult, IDS_CANT_OPEN_SAB_FILE);
  679.             goto err;
  680.         }
  681.     }
  682.  
  683.     /*
  684.      *  Get the time and date stamp
  685.      */
  686.     if (!GetFileTime(lpIVTAbc->hFile, NULL, NULL, &filetime))
  687.     {
  688.         if (GetLastError() != NO_ERROR)
  689.         {
  690.             hResult = ResultFromScode(MAPI_E_UNABLE_TO_COMPLETE);
  691.             SetErrorIDS(lpIVTAbc, hResult, IDS_SAB_FILE_ATTRIB);
  692.         }
  693.  
  694.         goto err;
  695.     }
  696.  
  697.     /*  Get the size of the file */
  698.     if ((ulSize = GetFileSize(lpIVTAbc->hFile, &ulSizeHigh)) == 0xFFFFFFFF)
  699.     {
  700.         /*
  701.          *  MAYBE I have an error
  702.          */
  703.         if (GetLastError() != NO_ERROR)
  704.         {
  705.             hResult = ResultFromScode(MAPI_E_UNABLE_TO_COMPLETE);
  706.             SetErrorIDS(lpIVTAbc, hResult, IDS_SAB_FILE_ATTRIB);
  707.             goto err;
  708.         }
  709.  
  710.         hResult = ResultFromScode(MAPI_E_UNABLE_TO_COMPLETE);
  711.         SetErrorIDS(lpIVTAbc, hResult, IDS_SAB_TOO_LARGE);
  712.         goto err;
  713.     }
  714.  
  715.     /*
  716.      *  Actual number of valid positions
  717.      */
  718.     ulMaxPos = (ulSize / sizeof(ABCREC));
  719.  
  720.     /*
  721.      *  Check to see if it's an exact multiple of sizeof(ABCREC)
  722.      */
  723.     if (ulMaxPos * sizeof(ABCREC) != ulSize)
  724.     {
  725.         hResult = ResultFromScode(MAPI_E_UNABLE_TO_COMPLETE);
  726.         SetErrorIDS(lpIVTAbc, hResult, IDS_SAB_CORRUPT);
  727.         goto err;
  728.     }
  729.  
  730.     /*
  731.      *  if the file has changed set new position, reset bookmarks etc and
  732.      *  notify everybody one the advise list
  733.      */
  734.     if (CompareFileTime(&filetime, &lpIVTAbc->filetime) || ulMaxPos != lpIVTAbc->ulMaxPos)
  735.     {
  736.         ULONG ulBK;
  737.         ABCREC abcrec;
  738.         ULONG cbT;
  739.         LPMAPIADVISESINK *ppadvise;
  740.         ULONG cAdvises;
  741.         NOTIFICATION notif;
  742.  
  743.         /* save new max position and filetime */
  744.         lpIVTAbc->filetime = filetime;
  745.         lpIVTAbc->ulMaxPos = ulMaxPos;
  746.  
  747.         /* if current position is past the end of file set it to the end */
  748.         if (lpIVTAbc->ulPosition > lpIVTAbc->ulMaxPos)
  749.             lpIVTAbc->ulPosition = lpIVTAbc->ulMaxPos;
  750.  
  751.         if (ulMaxPos)
  752.         {
  753.             SetFilePointer(lpIVTAbc->hFile, (ulMaxPos - 1)*sizeof(ABCREC), NULL, FILE_BEGIN);
  754.  
  755.             /*  Read in the record at that location  */
  756.             if (!ReadFile(lpIVTAbc->hFile, (LPVOID) &abcrec,
  757.                     sizeof(ABCREC), &cbT, NULL))
  758.             {
  759.                 hResult = ResultFromScode(MAPI_E_DISK_ERROR);
  760.                 SetErrorIDS(lpIVTAbc, hResult, IDS_SAB_NO_READ);
  761.  
  762.                 goto err;
  763.             }
  764.  
  765.             /* if any of the bookmarks are past the end of file
  766.              * set the file time to current file time, the position to last
  767.              * record and record to last record
  768.              */
  769.             for (ulBK = 0; ulBK < MAX_BOOKMARKS; ulBK++)
  770.                 if (lpIVTAbc->rglpABCBK[ulBK] &&
  771.                     lpIVTAbc->rglpABCBK[ulBK]->ulPosition > lpIVTAbc->ulMaxPos)
  772.                 {
  773.                     lpIVTAbc->rglpABCBK[ulBK]->ulPosition = ulMaxPos - 1;
  774.                     lpIVTAbc->rglpABCBK[ulBK]->filetime = filetime;
  775.                     lpIVTAbc->rglpABCBK[ulBK]->abcrec = abcrec;
  776.                 }
  777.  
  778.             /*
  779.             *  Reallocate the checked&matched arrays
  780.             */
  781.  
  782.             cbT = (lpIVTAbc->ulMaxPos) / 8 + 1; /* Number of bytes in both arrays */
  783.  
  784.             /* Reallocate ANR bitmaps */
  785.             if (lpIVTAbc->rgChecked)
  786.             {
  787.                 lpIVTAbc->rgChecked = lpIVTAbc->lpMalloc->lpVtbl->Realloc(
  788.                     lpIVTAbc->lpMalloc,
  789.                     lpIVTAbc->rgChecked,
  790.                     cbT);
  791.             }
  792.  
  793.             if (lpIVTAbc->rgMatched)
  794.             {
  795.                 lpIVTAbc->rgMatched = lpIVTAbc->lpMalloc->lpVtbl->Realloc(
  796.                     lpIVTAbc->lpMalloc,
  797.                     lpIVTAbc->rgMatched,
  798.                     cbT);
  799.             }
  800.         }
  801.         else
  802.         {
  803.             /* if any of the bookmarks are past the end of file
  804.              * set the file time to current file time, the position to the
  805.              * beginning of the file.
  806.              */
  807.             for (ulBK = 0; ulBK < MAX_BOOKMARKS; ulBK++)
  808.                 if (lpIVTAbc->rglpABCBK[ulBK] &&
  809.                     lpIVTAbc->rglpABCBK[ulBK]->ulPosition > lpIVTAbc->ulMaxPos)
  810.                 {
  811.                     lpIVTAbc->rglpABCBK[ulBK]->ulPosition = 0;
  812.                     lpIVTAbc->rglpABCBK[ulBK]->filetime = filetime;
  813.                 }
  814.  
  815.             /* free the ANR bitmaps */
  816.             FreeANRBitmaps(lpIVTAbc);
  817.         }
  818.  
  819.         /* initialize the notification */
  820.         ZeroMemory(¬if, sizeof(NOTIFICATION));
  821.         notif.ulEventType = fnevTableModified;
  822.         notif.info.tab.ulTableEvent = TABLE_RELOAD;
  823.  
  824.         /* notify everyone that the table has changed */
  825.         for (ppadvise = lpIVTAbc->parglpAdvise, cAdvises = 0;
  826.             cAdvises < lpIVTAbc->cAdvise;
  827.             ++ppadvise, ++cAdvises)
  828.         {
  829.             Assert(*ppadvise);
  830.             if (ppadvise)
  831.                 (void)(*ppadvise)->lpVtbl->OnNotify(*ppadvise, 1, ¬if);
  832.         }
  833.     }
  834.  
  835. out:
  836.  
  837.     DebugTraceResult(NewIVTAbc, hResult);
  838.     return hResult;
  839. err:
  840.     lpIVTAbc->lpFreeBuff(lpszFileName);
  841.  
  842.     goto out;
  843.  
  844. }
  845.  
  846. /*************************************************************************
  847.  *
  848.  -  fIVTAbcIdleRoutine
  849.  -
  850.  *  This function called during idle time closes the .SAB file and notifies
  851.  *  everyone on the advise list if the file name has changed
  852.  *
  853.  */
  854.  
  855. BOOL STDAPICALLTYPE
  856. fIVTAbcIdleRoutine(LPVOID lpv)
  857. {
  858.     LPIVTABC lpIVTAbc = (LPIVTABC) lpv;
  859.  
  860.     Assert(lpv);
  861.  
  862.     /* if file is open close it  */
  863.     if (lpIVTAbc->hFile != INVALID_HANDLE_VALUE)
  864.     {
  865.         CloseHandle(lpIVTAbc->hFile);
  866.         lpIVTAbc->hFile = INVALID_HANDLE_VALUE;
  867.     }
  868.  
  869.     /* has file name has changed? */
  870.     if (!FEqualSABFiles(lpIVTAbc->lpABLogon, lpIVTAbc->lpszFileName))
  871.     {
  872.         /* file name has changed so call HrOpenFile to reset bookmarks etc */
  873.         if (!HR_FAILED(HrOpenFile(lpIVTAbc)))
  874.         {
  875.             /* close the file */
  876.             CloseHandle(lpIVTAbc->hFile);
  877.             lpIVTAbc->hFile = INVALID_HANDLE_VALUE;
  878.         }
  879.     }
  880.     return TRUE;
  881. }
  882.  
  883. /*************************************************************************
  884.  *
  885.  -  FreeANRBitmaps
  886.  -
  887.  *  Frees the two ANR bitmaps associated with this table
  888.  *
  889.  *
  890.  */
  891. void 
  892. FreeANRBitmaps(LPIVTABC lpIVTAbc)
  893. {
  894.     if (lpIVTAbc->rgChecked)
  895.     {
  896.         lpIVTAbc->lpMalloc->lpVtbl->Free(lpIVTAbc->lpMalloc, lpIVTAbc->rgChecked);
  897.         lpIVTAbc->rgChecked = NULL;
  898.     }
  899.  
  900.     if (lpIVTAbc->rgMatched)
  901.     {
  902.         lpIVTAbc->lpMalloc->lpVtbl->Free(lpIVTAbc->lpMalloc, lpIVTAbc->rgMatched);
  903.         lpIVTAbc->rgMatched = NULL;
  904.     }
  905. }
  906.  
  907.  
  908.  
  909. /*
  910.  *  FCharInString
  911.  *
  912.  *  Finds a character in a string
  913.  */
  914. BOOL
  915. FCharInString(LPSTR lpsz, CHAR ch)
  916. {
  917.  
  918.     while (*lpsz && *lpsz != ch)
  919.         lpsz++;
  920.  
  921.     return (*lpsz == ch);
  922. }
  923.