home *** CD-ROM | disk | FTP | other *** search
/ Power GUI Programming with VisualAge C++ / powergui.iso / trialva / ibmcppw / sdk / mapi / win16 / dev / sample.ab / ablogon.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-07-11  |  45.7 KB  |  1,658 lines

  1. /***********************************************************************
  2.  *
  3.  *  ABLOGON.C
  4.  *
  5.  *
  6.  *  The Sample Address Book Provider.
  7.  *
  8.  *  This file has the code to implement the Sample Address Book's logon
  9.  *  object.
  10.  *
  11.  *  The following routines are implemented in this file:
  12.  *  
  13.  *  ABPLOGON_QueryInterface
  14.  *  ABPLOGON_Release
  15.  *  ABPLOGON_Logoff
  16.  *  ABPLOGON_OpenEntry
  17.  *  ABPLOGON_CompareEntryIDs
  18.  *  ABPLOGON_Advise
  19.  *  ABPLOGON_Unadvise
  20.  *  ABPLOGON_OpenStatusEntry
  21.  *  ABPLOGON_OpenTemplateID
  22.  *  ABPLOGON_GetOneOffTable
  23.  *  ABPLOGON_PrepareRecips
  24.  *  
  25.  *  LpMuidFromLogon
  26.  *  HrLpszGetCurrentFileName
  27.  *  HrReplaceCurrentfileName
  28.  *  GenerateContainerDN
  29.  *  HrBuildRootHier
  30.  *  
  31.  *
  32.  *  Copyright 1992-1995 Microsoft Corporation.  All Rights Reserved.
  33.  *
  34.  ***********************************************************************/
  35.  
  36.  
  37. #include "abp.h"
  38. #include "sampabp.rh"
  39. #include <smpab.h>
  40.  
  41.  
  42. /*
  43.  *  Definition of the logon object
  44.  */
  45. typedef struct _ABPLOGON {
  46.  
  47.     ABPLOGON_Vtbl FAR *     lpVtbl;
  48.  
  49.     SAB_IUnknown;
  50.  
  51.     /*
  52.      *  Private structure
  53.      */
  54.     LPABPROVIDER lpABP;
  55.  
  56.     LPSTR lpszFileName;         /* Name of file that is browsed */
  57.     MAPIUID muidID;             /* UID for this logon object */
  58.     LPMAPISUP lpMapiSup;        /* MAPI Support object - gotten via ABP_Logon */
  59.  
  60.     /*
  61.      *  Table Data for canned tables
  62.      */
  63.  
  64.  
  65.     LPTABLEDATA lpTDatRoot;     /*  Root hierarchy  */
  66.     LPTABLEDATA lpTDatOO;       /*  One Off Table  */
  67.  
  68. } ABPLOGON, FAR *LPABPLOGON;
  69.  
  70.  
  71.  
  72. ABPLOGON_Vtbl vtblABPLOGON =
  73. {
  74.     ABPLOGON_QueryInterface,
  75.     (ABPLOGON_AddRef_METHOD *) ROOT_AddRef,
  76.     ABPLOGON_Release,
  77.     (ABPLOGON_GetLastError_METHOD *) ROOT_GetLastError,
  78.     ABPLOGON_Logoff,
  79.     ABPLOGON_OpenEntry,
  80.     ABPLOGON_CompareEntryIDs,
  81.     ABPLOGON_Advise,
  82.     ABPLOGON_Unadvise,
  83.     ABPLOGON_OpenStatusEntry,
  84.     ABPLOGON_OpenTemplateID,
  85.     ABPLOGON_GetOneOffTable,
  86.     ABPLOGON_PrepareRecips
  87. };
  88.  
  89.  
  90.  
  91. /*
  92.  -  HrNewABLogon
  93.  -
  94.  *
  95.  *  Creates a new Sample AB Logon object.
  96.  */
  97.  
  98. HRESULT
  99. HrNewABLogon(   LPABLOGON *         lppABLogon,
  100.                 LPABPROVIDER        lpABP,
  101.                 LPMAPISUP           lpMAPISup,
  102.                 LPSTR               lpszSABFile,
  103.                 LPMAPIUID           lpmuid,
  104.                 HINSTANCE           hLibrary,
  105.                 LPALLOCATEBUFFER    lpAllocBuff,
  106.                 LPALLOCATEMORE      lpAllocMore,
  107.                 LPFREEBUFFER        lpFreeBuff,
  108.                 LPMALLOC            lpMalloc )
  109. {
  110.     SCODE sc;
  111.     HRESULT hResult = hrSuccess;
  112.     SPropValue rgSPVStat[6];
  113.     LPABPLOGON lpABPLogon = NULL;
  114.  
  115.     /*
  116.      *  Allocate space for the lpABPLogon object
  117.      */
  118.  
  119.     sc = lpAllocBuff(sizeof(ABPLOGON), &lpABPLogon);
  120.     if (FAILED(sc))
  121.     {
  122.         hResult = ResultFromScode(sc);
  123.         goto out;
  124.     }
  125.  
  126.     /*
  127.      *  Initialize the ABPLogon object
  128.      */
  129.  
  130.     lpABPLogon->lpVtbl = &vtblABPLOGON;
  131.  
  132.     lpABPLogon->lcInit = 1;
  133.     lpABPLogon->hResult = hrSuccess;
  134.     lpABPLogon->idsLastError = 0;
  135.  
  136.     lpABPLogon->hLibrary = hLibrary;
  137.  
  138.     lpABPLogon->lpMalloc = lpMalloc;
  139.     lpABPLogon->lpAllocBuff = lpAllocBuff;
  140.     lpABPLogon->lpAllocMore = lpAllocMore;
  141.     lpABPLogon->lpFreeBuff = lpFreeBuff;
  142.  
  143.     lpABPLogon->lpMapiSup = lpMAPISup;
  144.     lpABPLogon->lpABP = (LPABPROVIDER) lpABP;
  145.     lpABPLogon->lpszFileName = lpszSABFile;
  146.     lpABPLogon->muidID = *lpmuid;
  147.  
  148.     lpABPLogon->lpTDatRoot = NULL;
  149.     lpABPLogon->lpTDatOO = NULL;
  150.  
  151.     /*
  152.      *  Register my status row...
  153.      */
  154.     rgSPVStat[0].ulPropTag = PR_DISPLAY_NAME_A;
  155.     rgSPVStat[0].Value.lpszA = lpszSABFile;
  156.     rgSPVStat[1].ulPropTag = PR_RESOURCE_METHODS;
  157.     rgSPVStat[1].Value.l = 0;   
  158.     rgSPVStat[2].ulPropTag = PR_RESOURCE_FLAGS;
  159.     rgSPVStat[2].Value.l = 0;
  160.     rgSPVStat[3].ulPropTag = PR_STATUS_CODE;
  161.     rgSPVStat[3].Value.l = STATUS_AVAILABLE;
  162.     rgSPVStat[4].ulPropTag = PR_STATUS_STRING;
  163.     rgSPVStat[4].Value.lpszA = "Available";
  164.     rgSPVStat[5].ulPropTag = PR_PROVIDER_DISPLAY;
  165.     rgSPVStat[5].Value.lpszA = "Sample Address Book Provider";
  166.  
  167.     /*
  168.      *  Set the Status Row for this provider,
  169.      *  but do not allow an error from setting the
  170.      *  status row to cause failure to Logon.
  171.      */
  172.  
  173.     (void)lpMAPISup->lpVtbl->ModifyStatusRow(lpMAPISup,
  174.         sizeof(rgSPVStat) / sizeof(SPropValue), rgSPVStat, 0);
  175.  
  176.     /*
  177.      *  AddRef the support object, because we're keeping
  178.      *  a pointer to it in our Logon object.
  179.      */
  180.     lpMAPISup->lpVtbl->AddRef(lpMAPISup);
  181.  
  182.     /*
  183.      *  AddRef our parent ABInit object
  184.      */
  185.     lpABP->lpVtbl->AddRef(lpABP);
  186.  
  187.     InitializeCriticalSection(&lpABPLogon->cs);
  188.     
  189.     *lppABLogon = (LPABLOGON) lpABPLogon;
  190.  
  191. out:
  192.  
  193.     DebugTraceResult(HrNewABPLogon, hResult);
  194.     return hResult;
  195. }   
  196.  
  197.  
  198. /*************************************************************************
  199.  *
  200.  -  ABPLOGON_QueryInterface
  201.  -
  202.  */
  203. STDMETHODIMP
  204. ABPLOGON_QueryInterface(LPABPLOGON lpABPLogon, REFIID lpiid,
  205.     LPVOID * ppvObj)
  206. {
  207.     if (IsBadReadPtr(lpiid, sizeof(IID))
  208.         || IsBadWritePtr(ppvObj, sizeof(LPVOID)))
  209.     {
  210.         DebugTraceSc(ABPLOGON_QueryInterface, E_INVALIDARG);
  211.         return ResultFromScode(E_INVALIDARG);
  212.     }
  213.  
  214.     /*  See if the requested interface is one of ours */
  215.  
  216.     if (memcmp(lpiid, &IID_IUnknown, sizeof(IID)) &&
  217.         memcmp(lpiid, &IID_IABLogon, sizeof(IID)))
  218.     {
  219.         *ppvObj = NULL;         /* OLE requires zeroing [out] parameter on error */
  220.         DebugTraceSc(ABPLOGON_QueryInterface, E_NOINTERFACE);
  221.         return ResultFromScode(E_NOINTERFACE);
  222.     }
  223.  
  224.     /*  We'll do this one. Bump the usage count and return a new pointer. */
  225.  
  226.     EnterCriticalSection(&lpABPLogon->cs);
  227.     ++lpABPLogon->lcInit;
  228.     LeaveCriticalSection(&lpABPLogon->cs);
  229.     
  230.     *ppvObj = lpABPLogon;
  231.  
  232.     return hrSuccess;
  233. }
  234.  
  235. /*
  236.  *  Use ROOTs AddRef
  237.  */
  238.  
  239. /*************************************************************************
  240.  *
  241.  -  ABPLOGON_Release
  242.  -
  243.  */
  244. STDMETHODIMP_(ULONG)
  245. ABPLOGON_Release(LPABPLOGON lpABPLogon)
  246. {
  247.     LONG lcInit;
  248.  
  249.     EnterCriticalSection(&lpABPLogon->cs);
  250.     lcInit = --lpABPLogon->lcInit;
  251.     LeaveCriticalSection(&lpABPLogon->cs);
  252.  
  253.     if (lcInit == 0)
  254.     {
  255.         /*
  256.          *  Free up the file
  257.          */
  258.         lpABPLogon->lpFreeBuff(lpABPLogon->lpszFileName);
  259.  
  260.         /*
  261.          *  Release the Hierarchy Table Data
  262.          */
  263.         if (lpABPLogon->lpTDatRoot)
  264.             lpABPLogon->lpTDatRoot->lpVtbl->Release(lpABPLogon->lpTDatRoot);
  265.  
  266.         /*
  267.          *  Release the One-Off Table Data
  268.          */
  269.         if (lpABPLogon->lpTDatOO)
  270.             lpABPLogon->lpTDatOO->lpVtbl->Release(lpABPLogon->lpTDatOO);
  271.  
  272.         /*
  273.          *  No longer need to be holding on to our parent
  274.          */
  275.         lpABPLogon->lpABP->lpVtbl->Release(lpABPLogon->lpABP);
  276.     
  277.         /*
  278.          *  Release the support object last.
  279.          */
  280.         lpABPLogon->lpMapiSup->lpVtbl->Release(lpABPLogon->lpMapiSup);
  281.  
  282.         DeleteCriticalSection(&lpABPLogon->cs);
  283.         lpABPLogon->lpVtbl = NULL;
  284.         lpABPLogon->lpFreeBuff(lpABPLogon);
  285.         return (0);
  286.     }
  287.     return lcInit;
  288. }
  289.  
  290. /*************************************************************************
  291.  *
  292.  -  ABPLOGON_Logoff
  293.  -
  294.  *  Logoff from this logon object.  Clean up any resources/objects that
  295.  *  our logon object has accumulated.
  296.  *
  297.  *
  298.  */
  299. STDMETHODIMP
  300. ABPLOGON_Logoff(LPABPLOGON lpABPLogon, ULONG ulFlags)
  301. {
  302.  
  303.     /*
  304.      *  Remove this logon object from the list of known
  305.      *  logon objects associated with this initialization
  306.      *  of this provider.
  307.      */
  308.     (void) RemoveLogonObject(lpABPLogon->lpABP, lpABPLogon, lpABPLogon->lpFreeBuff);
  309.  
  310.     return hrSuccess;
  311. }
  312.  
  313. /*************************************************************************
  314.  *
  315.  -  ABPLOGON_OpenEntry
  316.  -
  317.  *  Creates an object with (at least) the IMAPIProp interface from an
  318.  *  entryID.
  319.  *
  320.  *  There are four valid types of entryIDs handled:
  321.  *
  322.  *    NULL          <- return back the root container object
  323.  *    DIR_ENTRYID   <- return back the directory container object
  324.  *    USR_ENTRYID   <- return back the MAILUSER object
  325.  *    OOUSR_ENTRYID <- return back the OneOff MAILUSER object
  326.  *
  327.  *  Note:  This call is reused for all other internal objects that support OpenEntry().
  328.  *    Those other calls *must* check their parameters before calling this method.
  329.  *    The only other way this method is called is via MAPI which does parameter checking
  330.  *    for us.  The most we'll do here is assert our parameters.
  331.  */
  332. STDMETHODIMP
  333. ABPLOGON_OpenEntry(LPABPLOGON lpABPLogon,
  334.     ULONG cbEntryID,
  335.     LPENTRYID lpEntryID,
  336.     LPCIID lpInterface,
  337.     ULONG ulFlags,
  338.     ULONG * lpulObjType,
  339.     LPUNKNOWN * lppUnk)
  340. {
  341.  
  342.     LPDIR_ENTRYID lpSampEID = (LPDIR_ENTRYID) lpEntryID;
  343.     HRESULT hResult = hrSuccess;
  344.  
  345.     /*
  346.      *  Check the EntryID
  347.      */
  348.  
  349.     if (!cbEntryID)
  350.     {
  351.         LPABCONT lpABCont = NULL;
  352.  
  353.         /*
  354.          *  Special case:  the root level object
  355.          */
  356.  
  357.         NFAssertSz(!lpEntryID, "Non-NULL entry id passed with 0 cb to OpenEntry()\n");
  358.         
  359.         /*  Make this new object  */
  360.  
  361.         hResult = HrNewROOT((LPABCONT *) lppUnk,
  362.                             lpulObjType,
  363.                             (LPABLOGON) lpABPLogon,
  364.                             lpInterface,
  365.                             lpABPLogon->hLibrary,
  366.                             lpABPLogon->lpAllocBuff,
  367.                             lpABPLogon->lpAllocMore,
  368.                             lpABPLogon->lpFreeBuff,
  369.                             lpABPLogon->lpMalloc);
  370.         goto out;
  371.     }
  372.  
  373.     /*
  374.      *  There's an entryID there, is it mine??
  375.      *  I need to check because I'm reusing this routine for
  376.      *  my Container->OpenEntry call, and I can't be sure the
  377.      *  client will always be well behaved.
  378.      *
  379.      *  When this routine is called from MAPI, this call is redundant.  But
  380.      *  because I'm reusing this routine, I gotta check.
  381.      */
  382.  
  383.     /*  Compare MAPIUIDs  */
  384.     if (memcmp(&(((LPDIR_ENTRYID) lpEntryID)->muid), &muidABSample,
  385.             sizeof(MAPIUID)))
  386.     {
  387.         /*
  388.          *  Not mine!
  389.          */
  390.  
  391.         hResult = ResultFromScode(MAPI_E_INVALID_ENTRYID);
  392.         goto out;
  393.     }
  394.  
  395.     /*
  396.      *  What object does this correspond to??
  397.      */
  398.  
  399.     /*  I've only got two types: containers and users  */
  400.  
  401.     if (lpSampEID->ulType == SAMP_DIRECTORY)
  402.     {
  403.         LPABLOGON lpABPLogonT = NULL;
  404.  
  405.         /* entry id must have the same verson number */
  406.         if (lpSampEID->ulVersion != SAMP_VERSION)
  407.         {
  408.             hResult = ResultFromScode(MAPI_E_UNKNOWN_ENTRYID);
  409.             SetErrorIDS(lpABPLogon, hResult, IDS_OLD_EID);
  410.  
  411.             goto out;
  412.         }
  413.  
  414.         /*
  415.          *  find the correct logon object for this entryid
  416.          */
  417.  
  418.         (void) FindLogonObject(lpABPLogon->lpABP, &lpSampEID->muidID, &lpABPLogonT);
  419.  
  420.         /* did we find the corresponding logon object */
  421.         if (!lpABPLogonT)
  422.         {
  423.             hResult = ResultFromScode(MAPI_E_UNKNOWN_ENTRYID);
  424.             goto out;
  425.         }
  426.  
  427.         hResult = HrNewSampDirectory( (LPABCONT *) lppUnk,
  428.                                     lpulObjType,
  429.                                     (LPABLOGON) lpABPLogonT,
  430.                                     lpInterface,
  431.                                     lpABPLogon->hLibrary,
  432.                                     lpABPLogon->lpAllocBuff,
  433.                                     lpABPLogon->lpAllocMore,
  434.                                     lpABPLogon->lpFreeBuff,
  435.                                     lpABPLogon->lpMalloc);
  436.         goto out;
  437.  
  438.     }
  439.  
  440.     if (lpSampEID->ulType == SAMP_USER)
  441.         if (cbEntryID == (ULONG) sizeof(USR_ENTRYID))
  442.         {
  443.             hResult = HrNewSampUser( (LPMAILUSER *) lppUnk,
  444.                                     lpulObjType,
  445.                                     cbEntryID,
  446.                                     lpEntryID,
  447.                                     (LPABLOGON) lpABPLogon,
  448.                                     lpInterface,
  449.                                     lpABPLogon->hLibrary,
  450.                                     lpABPLogon->lpAllocBuff,
  451.                                     lpABPLogon->lpAllocMore,
  452.                                     lpABPLogon->lpFreeBuff,
  453.                                     lpABPLogon->lpMalloc);
  454.  
  455.             goto out;
  456.         }
  457.  
  458.     if (lpSampEID->ulType == SAMP_OOUSER)
  459.         if (cbEntryID == (ULONG) sizeof(OOUSR_ENTRYID))
  460.         {
  461.             hResult = HrNewSampOOUser( (LPMAILUSER *) lppUnk,
  462.                                         lpulObjType,
  463.                                         cbEntryID,
  464.                                         lpEntryID,
  465.                                         (LPABLOGON) lpABPLogon,
  466.                                         lpInterface,
  467.                                         lpABPLogon->hLibrary,
  468.                                         lpABPLogon->lpAllocBuff,
  469.                                         lpABPLogon->lpAllocMore,
  470.                                         lpABPLogon->lpFreeBuff,
  471.                                         lpABPLogon->lpMalloc);
  472.  
  473.  
  474.             goto out;
  475.         }
  476.  
  477.     hResult = ResultFromScode(MAPI_E_UNKNOWN_ENTRYID);
  478.  
  479. out:
  480.     DebugTraceResult(ABPLOGON_OpenEntry, hResult);
  481.  
  482.     return hResult;
  483.  
  484. }
  485.  
  486. /*************************************************************************
  487.  *
  488.  -  ABPLOGON_CompareEntryIDs
  489.  -
  490.  *  If the two entryids are mine and they're of the same type, then
  491.  *  just do a binary comparison to see if they're equal.
  492.  *
  493.  */
  494. STDMETHODIMP
  495. ABPLOGON_CompareEntryIDs(LPABPLOGON lpABPLogon,
  496.     ULONG cbEntryID1,
  497.     LPENTRYID lpEntryID1,
  498.     ULONG cbEntryID2,
  499.     LPENTRYID lpEntryID2,
  500.     ULONG ulFlags,
  501.     ULONG * lpulResult)
  502. {
  503.  
  504.     LPDIR_ENTRYID lpSampEID1 = (LPDIR_ENTRYID) lpEntryID1;
  505.     LPDIR_ENTRYID lpSampEID2 = (LPDIR_ENTRYID) lpEntryID2;
  506.     HRESULT hResult = hrSuccess;
  507.  
  508.     /*
  509.      *  Check to see if their MUID is mine
  510.      */
  511.     if (memcmp(&(lpSampEID1->muid), &muidABSample, sizeof(MAPIUID)) ||
  512.         memcmp(&(lpSampEID2->muid), &muidABSample, sizeof(MAPIUID)))
  513.     {
  514.         /*
  515.          *  No recognition of these entryids.
  516.          */
  517.  
  518.         *lpulResult = (ULONG) FALSE;
  519.         hResult = ResultFromScode(MAPI_E_UNKNOWN_ENTRYID);
  520.         goto out;
  521.     }
  522.  
  523.     /*
  524.      *  See if the type of entryids are the same
  525.      */
  526.     if (lpSampEID1->ulType != lpSampEID2->ulType)
  527.     {
  528.         /*
  529.          *  They're not, so they don't match
  530.          */
  531.  
  532.         *lpulResult = (ULONG) FALSE;
  533.         goto out;
  534.  
  535.     }
  536.  
  537.     /*
  538.      *  See if the entryids are the same size.  They'd better be
  539.      *  if they're the same type.
  540.      */
  541.     if (cbEntryID1 != cbEntryID2)
  542.     {
  543.         /*
  544.          *  They're not?!?  Then I don't know these...
  545.          */
  546.  
  547.         *lpulResult = (ULONG) FALSE;
  548.         hResult = ResultFromScode(MAPI_E_UNKNOWN_ENTRYID);
  549.  
  550.         goto out;
  551.     }
  552.  
  553.     /*
  554.      *  Check for Directory entryids
  555.      */
  556.     if (lpSampEID1->ulType == SAMP_DIRECTORY)
  557.     {
  558.         /*
  559.          *  Ok, I'm dealing with directory entryids
  560.          */
  561.  
  562.         /*
  563.          *  Better make sure it's the right size
  564.          */
  565.         if (cbEntryID1 != sizeof(DIR_ENTRYID))
  566.         {
  567.             /*
  568.              *  This doesn't make sense.  I don't recognize this entryid.
  569.              */
  570.  
  571.             *lpulResult = (ULONG) FALSE;
  572.             hResult = ResultFromScode(MAPI_E_UNKNOWN_ENTRYID);
  573.  
  574.             goto out;
  575.         }
  576.  
  577.         /*
  578.          *  At this point it's just a memcmp
  579.          */
  580.         if (memcmp(lpSampEID1, lpSampEID2, sizeof(DIR_ENTRYID)))
  581.         {
  582.             /*
  583.              *  They're not equal
  584.              */
  585.  
  586.             *lpulResult = (ULONG) FALSE;
  587.  
  588.             goto out;
  589.         }
  590.  
  591.         /*
  592.          *  They must be the same
  593.          */
  594.  
  595.         *lpulResult = (ULONG) TRUE;
  596.  
  597.         goto out;
  598.     }
  599.  
  600.     if (lpSampEID1->ulType == SAMP_USER)
  601.     {
  602.         /*
  603.          *  Ok, I'm dealing with user entryids
  604.          */
  605.  
  606.         /*
  607.          *  Better make sure it's the right size
  608.          */
  609.         if (cbEntryID1 != sizeof(USR_ENTRYID))
  610.         {
  611.             /*
  612.              *  This doesn't make sense.  I don't recognize this entryid.
  613.              */
  614.  
  615.             *lpulResult = (ULONG) FALSE;
  616.             hResult = ResultFromScode(MAPI_E_UNKNOWN_ENTRYID);
  617.  
  618.             goto out;
  619.         }
  620.  
  621.         /*
  622.          *  At this point it's just a memcmp
  623.          */
  624.         if (memcmp(lpSampEID1, lpSampEID2, sizeof(USR_ENTRYID)))
  625.         {
  626.             /*
  627.              *  They're not equal
  628.              */
  629.  
  630.             *lpulResult = (ULONG) FALSE;
  631.  
  632.             goto out;
  633.         }
  634.  
  635.         /*
  636.          *  They must be the same
  637.          */
  638.  
  639.         *lpulResult = (ULONG) TRUE;
  640.  
  641.         goto out;
  642.     }
  643.  
  644.     if (lpSampEID1->ulType == SAMP_OOUSER)
  645.     {
  646.         /*
  647.          *  Ok, I'm dealing with oneoff user entryids
  648.          */
  649.  
  650.         /*
  651.          *  Better make sure it's the right size
  652.          */
  653.         if (cbEntryID1 != sizeof(OOUSR_ENTRYID))
  654.         {
  655.             /*
  656.              *  This doesn't make sense.  I don't recognize this entryid.
  657.              */
  658.  
  659.             *lpulResult = (ULONG) FALSE;
  660.             hResult = ResultFromScode(MAPI_E_UNKNOWN_ENTRYID);
  661.  
  662.             goto out;
  663.         }
  664.  
  665.         /*
  666.          *  At this point it's just a memcmp
  667.          */
  668.         if (memcmp(lpSampEID1, lpSampEID2, sizeof(OOUSR_ENTRYID)))
  669.         {
  670.             /*
  671.              *  They're not equal
  672.              */
  673.  
  674.             *lpulResult = (ULONG) FALSE;
  675.  
  676.             goto out;
  677.         }
  678.  
  679.         /*
  680.          *  They must be the same
  681.          */
  682.  
  683.         *lpulResult = (ULONG) TRUE;
  684.  
  685.         goto out;
  686.     }
  687.  
  688.     /*
  689.      *  It's no entryid I know of
  690.      */
  691.  
  692.     *lpulResult = (ULONG) FALSE;
  693.     hResult = ResultFromScode(MAPI_E_UNKNOWN_ENTRYID);
  694.  
  695. out:
  696.  
  697.     DebugTraceResult(ABPLOGON_CompareEntryIDs, hResult);
  698.     return hResult;
  699.  
  700. }
  701.  
  702. /*************************************************************************
  703.  *
  704.  -  ABPLOGON_OpenStatusEntry
  705.  -
  706.  *
  707.  *
  708.  *
  709.  */
  710. STDMETHODIMP
  711. ABPLOGON_OpenStatusEntry(LPABPLOGON lpABPLogon,
  712.     LPCIID lpIID,
  713.     ULONG ulFlags,
  714.     ULONG FAR * lpulObjType,
  715.     LPMAPISTATUS FAR * lppEntry)
  716. {
  717.     HRESULT hr;
  718.  
  719.     /*
  720.      *  Validate Parameters
  721.      */
  722.     if (IsBadReadPtr(lpABPLogon, (UINT) sizeof(ABPLOGON))
  723.         || (lpIID && IsBadReadPtr(lpIID, (UINT) sizeof(IID)))
  724.         || IsBadWritePtr(lpulObjType, (UINT) sizeof(ULONG FAR *))
  725.         || IsBadWritePtr(lppEntry, (UINT) sizeof(LPMAPISTATUS)))
  726.     {
  727.         DebugTraceSc(ABPLogon_OpenStatusEntry, E_INVALIDARG);
  728.         return ResultFromScode(E_INVALIDARG);
  729.     }
  730.  
  731.  
  732.     hr = HrNewStatusObject( lppEntry,
  733.                             lpulObjType,
  734.                             ulFlags,
  735.                             (LPABLOGON) lpABPLogon,
  736.                             lpIID,
  737.                             lpABPLogon->hLibrary,
  738.                             lpABPLogon->lpAllocBuff,
  739.                             lpABPLogon->lpAllocMore,
  740.                             lpABPLogon->lpFreeBuff,
  741.                             lpABPLogon->lpMalloc);
  742.  
  743.     DebugTraceResult(ABPLOGON_OpenStatusEntry, hr);
  744.     return hr;
  745. }
  746.  
  747. /*************************************************************************
  748.  *
  749.  -  ABPLOGON_OpenTemplateID
  750.  -
  751.  *
  752.  *
  753.  *
  754.  */
  755. STDMETHODIMP
  756. ABPLOGON_OpenTemplateID(LPABPLOGON lpABPLogon,
  757.     ULONG cbTemplateId,
  758.     LPENTRYID lpTemplateId,
  759.     ULONG ulTemplateFlags,
  760.     LPMAPIPROP lpMAPIPropData,
  761.     LPCIID lpInterface,
  762.     LPMAPIPROP * lppMAPIPropNew,
  763.     LPMAPIPROP lpMAPIPropSibling)
  764. {
  765.     HRESULT hResult;
  766.  
  767.     /*
  768.      *  Validate Parameters
  769.      */
  770.     if (IsBadReadPtr(lpABPLogon, (UINT) sizeof(ABPLOGON))
  771.         || IsBadReadPtr(lpTemplateId, (UINT) cbTemplateId)
  772.         || IsBadReadPtr(lpMAPIPropData, (UINT) sizeof(LPVOID))
  773.         || (lpInterface && IsBadReadPtr(lpInterface, (UINT) sizeof(IID)))
  774.         || IsBadWritePtr(lppMAPIPropNew, (UINT) sizeof(LPMAPIPROP))
  775.         || (lpMAPIPropSibling && IsBadReadPtr(lpMAPIPropSibling, (UINT) sizeof(LPVOID))))
  776.     {
  777.         DebugTraceSc(ABPLogon_OpenTemplateID, E_INVALIDARG);
  778.         return ResultFromScode(E_INVALIDARG);
  779.     }
  780.  
  781.     /* //$ need stronger checking here... */
  782.     /* entryid better be right size */
  783.     if (cbTemplateId != sizeof(OOUSR_ENTRYID) && cbTemplateId != sizeof(USR_ENTRYID))
  784.     {
  785.         hResult = ResultFromScode(MAPI_E_INVALID_ENTRYID);
  786.         goto out;
  787.     }
  788.  
  789.     /*  is it my entry id compare MAPIUIDs  */
  790.     if (memcmp(&(((LPUSR_ENTRYID) lpTemplateId)->muid), &muidABSample,
  791.             sizeof(MAPIUID)))
  792.     {
  793.         hResult = ResultFromScode( MAPI_E_INVALID_ENTRYID );
  794.         goto out;
  795.     }
  796.  
  797.     /* better be a oneoff user entryid or a user entry id */
  798.     if (((LPUSR_ENTRYID) lpTemplateId)->ulType == SAMP_OOUSER)
  799.     {
  800.  
  801.         hResult = HrNewOOTID(   lppMAPIPropNew,
  802.                                 cbTemplateId,
  803.                                 lpTemplateId,
  804.                                 ulTemplateFlags,
  805.                                 lpMAPIPropData,
  806.                                 (LPABLOGON) lpABPLogon,
  807.                                 lpInterface,
  808.                                 lpABPLogon->hLibrary,
  809.                                 lpABPLogon->lpAllocBuff,
  810.                                 lpABPLogon->lpAllocMore,
  811.                                 lpABPLogon->lpFreeBuff,
  812.                                 lpABPLogon->lpMalloc);
  813.             
  814.     }
  815.     else if (((LPUSR_ENTRYID) lpTemplateId)->ulType == SAMP_USER)
  816.     {
  817.         hResult = HrNewTID( lppMAPIPropNew,
  818.                             cbTemplateId,
  819.                             lpTemplateId,
  820.                             ulTemplateFlags,
  821.                             lpMAPIPropData,
  822.                             (LPABLOGON) lpABPLogon,
  823.                             lpInterface,
  824.                             lpABPLogon->hLibrary,
  825.                             lpABPLogon->lpAllocBuff,
  826.                             lpABPLogon->lpAllocMore,
  827.                             lpABPLogon->lpFreeBuff,
  828.                             lpABPLogon->lpMalloc);
  829.     }
  830.     else
  831.     {
  832.         hResult = MakeResult(MAPI_E_INVALID_ENTRYID);
  833.     }
  834.  
  835. out:
  836.  
  837.     DebugTraceResult(ABPLOGON_OpenTemplateID, hResult);
  838.     return hResult;
  839. }
  840.  
  841. /*
  842.  -  ABPLOGON_GetOneOffTable
  843.  -
  844.  *  Returns the lists of one-offs that this providers can support creation of.
  845.  *  This list is added to the entries gathered from all the other AB logon objects
  846.  *  and exposed to the user as the list of things that can be created on a 
  847.  *  message.  Also this total list is available to other providers through the
  848.  *  support method GetOneOffTable().
  849.  *  
  850.  *  Note:  There's a bug here that if there are more than one Sample Address Books
  851.  *  installed on a particular profile, then there will be multiple entries in the
  852.  *  one-off table from this provider.  This can be changed to only have one one-off
  853.  *  entry, no matter how many SABs are configured in a profile, if the one-off table
  854.  *  was associated with the ABInit object.
  855.  */
  856.  
  857. /*
  858.  *  Column set for the oneoff table
  859.  */
  860. enum {  ivalootPR_DISPLAY_NAME_A = 0,
  861.         ivalootPR_ENTRYID,
  862.         ivalootPR_DEPTH,
  863.         ivalootPR_SELECTABLE,
  864.         ivalootPR_ADDRTYPE_A,
  865.         ivalootPR_DISPLAY_TYPE,
  866.         ivalootPR_INSTANCE_KEY,
  867.         ivalootMax };
  868.  
  869. static const SizedSPropTagArray(ivalootMax, tagaColSetOOTable) =
  870. {
  871.     ivalootMax,
  872.     {
  873.         PR_DISPLAY_NAME_A,
  874.         PR_ENTRYID,
  875.         PR_DEPTH,
  876.         PR_SELECTABLE,
  877.         PR_ADDRTYPE_A,
  878.         PR_DISPLAY_TYPE,
  879.         PR_INSTANCE_KEY
  880.     }
  881. };
  882.  
  883. STDMETHODIMP
  884. ABPLOGON_GetOneOffTable(
  885.     LPABPLOGON lpABPLogon,
  886.     ULONG ulFlags,
  887.     LPMAPITABLE * lppTable)
  888. {
  889.     SCODE sc;
  890.     HRESULT hResult;
  891.     SRow sRow;
  892.     SPropValue rgsPropValue[ivalootMax];
  893.     ULONG ulInstanceKey = 1;
  894.     OOUSR_ENTRYID EntryID;
  895.  
  896.     /*
  897.      *  Validate Parameters
  898.      */
  899.      
  900.     if ( ulFlags & ~(MAPI_UNICODE) )    
  901.     {
  902.         DebugTraceArg( APBLOGON_GetOneOffTable, "Unknown Flags" );
  903.         return ResultFromScode( MAPI_E_UNKNOWN_FLAGS );
  904.     }
  905.     
  906.     if ( ulFlags & MAPI_UNICODE )
  907.     {
  908.         DebugTraceArg( APBLOGON_GetOneOffTable, "UNICODE not supported" );
  909.         return ResultFromScode( MAPI_E_BAD_CHARWIDTH );
  910.     }
  911.     
  912.     if (IsBadReadPtr(lpABPLogon, (UINT) sizeof(ABPLOGON))
  913.         || IsBadWritePtr(lppTable, (UINT) sizeof(LPMAPITABLE)))
  914.     {
  915.         DebugTraceSc(ABPLogon_GetOneOffTable, E_INVALIDARG);
  916.         return ResultFromScode(E_INVALIDARG);
  917.     }
  918.  
  919.  
  920.     EnterCriticalSection(&lpABPLogon->cs);
  921.     
  922.     /*
  923.      * If there's not one already associated with this logon object,
  924.      * then create one.
  925.      */
  926.     if (!lpABPLogon->lpTDatOO)
  927.     {
  928.         /* Create a Table data object */
  929.         sc = CreateTable(
  930.             (LPIID) &IID_IMAPITableData,
  931.             lpABPLogon->lpAllocBuff,
  932.             lpABPLogon->lpAllocMore,
  933.             lpABPLogon->lpFreeBuff,
  934.             lpABPLogon->lpMalloc,
  935.             0,
  936.             PR_DISPLAY_NAME_A,
  937.             (LPSPropTagArray) &tagaColSetOOTable,
  938.             &(lpABPLogon->lpTDatOO));
  939.  
  940.         if (FAILED(sc))
  941.         {
  942.             hResult = ResultFromScode(sc);
  943.             goto out;
  944.         }
  945.  
  946.         /* Constants*/
  947.  
  948.         sRow.cValues = ivalootMax;
  949.         sRow.lpProps = rgsPropValue;
  950.  
  951.         /* The Display Name */
  952.         rgsPropValue[ivalootPR_DISPLAY_NAME_A].ulPropTag = PR_DISPLAY_NAME_A;
  953.         rgsPropValue[ivalootPR_DISPLAY_NAME_A].Value.lpszA = "Sample Address Book Recipient";
  954.  
  955.         /* the Entry ID*/
  956.         ZeroMemory(&EntryID, sizeof(OOUSR_ENTRYID));
  957.  
  958.         EntryID.muid = muidABSample;
  959.         EntryID.ulVersion = SAMP_VERSION;
  960.         EntryID.ulType = SAMP_OOUSER;
  961.  
  962.         rgsPropValue[ivalootPR_ENTRYID].ulPropTag = PR_ENTRYID;
  963.         rgsPropValue[ivalootPR_ENTRYID].Value.bin.cb = sizeof(OOUSR_ENTRYID);
  964.         rgsPropValue[ivalootPR_ENTRYID].Value.bin.lpb = (LPVOID) &EntryID;
  965.  
  966.         /* the depth property */
  967.         rgsPropValue[ivalootPR_DEPTH].ulPropTag = PR_DEPTH;
  968.         rgsPropValue[ivalootPR_DEPTH].Value.l = 0;
  969.  
  970.         /* the selectable property */
  971.         rgsPropValue[ivalootPR_SELECTABLE].ulPropTag = PR_SELECTABLE;
  972.         rgsPropValue[ivalootPR_SELECTABLE].Value.b = TRUE;
  973.  
  974.         /*
  975.          *  The address type that would be generated by an entry
  976.          *  created from this template
  977.          */
  978.         rgsPropValue[ivalootPR_ADDRTYPE_A].ulPropTag = PR_ADDRTYPE;
  979.         rgsPropValue[ivalootPR_ADDRTYPE_A].Value.lpszA = lpszEMT;
  980.  
  981.         /*
  982.          *  The display type associated with a recipient built with this template
  983.          */
  984.         rgsPropValue[ivalootPR_DISPLAY_TYPE].ulPropTag = PR_DISPLAY_TYPE;
  985.         rgsPropValue[ivalootPR_DISPLAY_TYPE].Value.lpszA = DT_MAILUSER;
  986.  
  987.  
  988.         /*
  989.          *  The instance key of this row in this one-off table.  Since there's only one
  990.          *  row in this one-off table, just default it to a value of 1.
  991.          */
  992.         rgsPropValue[ivalootPR_INSTANCE_KEY].ulPropTag = PR_INSTANCE_KEY;
  993.         rgsPropValue[ivalootPR_INSTANCE_KEY].Value.bin.cb = sizeof(ULONG);
  994.         rgsPropValue[ivalootPR_INSTANCE_KEY].Value.bin.lpb = (LPBYTE) &ulInstanceKey;
  995.  
  996.         (void) lpABPLogon->lpTDatOO->lpVtbl->HrModifyRow(
  997.                             lpABPLogon->lpTDatOO,
  998.                             &sRow);
  999.  
  1000.     }
  1001.  
  1002.     /*
  1003.      *  Get a view to return to the caller
  1004.      */
  1005.     hResult = lpABPLogon->lpTDatOO->lpVtbl->HrGetView(
  1006.         lpABPLogon->lpTDatOO,
  1007.         NULL,
  1008.         NULL,
  1009.         0,
  1010.         (LPMAPITABLE *) lppTable);
  1011.  
  1012. out:
  1013.  
  1014.     LeaveCriticalSection(&lpABPLogon->cs);
  1015.  
  1016.     DebugTraceResult(ABPLogon_GetOneOffTable, hResult);
  1017.     return hResult;
  1018. }
  1019.  
  1020. /*************************************************************************
  1021.  *
  1022.  -  ABPLOGON_Advise
  1023.  -
  1024.  *  NYI
  1025.  *
  1026.  *
  1027.  */
  1028. STDMETHODIMP
  1029. ABPLOGON_Advise(LPABPLOGON lpABPLogon,
  1030.     ULONG cbEntryID,
  1031.     LPENTRYID lpEntryID,
  1032.     ULONG ulEventMask,
  1033.     LPMAPIADVISESINK lpAdviseSink,
  1034.     ULONG FAR * lpulConnection)
  1035. {
  1036.     DebugTraceSc(ABPLOGON_Advise, MAPI_E_NO_SUPPORT);
  1037.     return ResultFromScode(MAPI_E_NO_SUPPORT);
  1038. }
  1039.  
  1040. /*************************************************************************
  1041.  *
  1042.  -  ABPLOGON_Unadvise
  1043.  -
  1044.  *  NYI
  1045.  *
  1046.  *
  1047.  */
  1048. STDMETHODIMP
  1049. ABPLOGON_Unadvise(LPABPLOGON lpABPLogon, ULONG ulConnection)
  1050. {
  1051.     DebugTraceSc(ABPLOGON_Unadvise, MAPI_E_NO_SUPPORT);
  1052.     return ResultFromScode(MAPI_E_NO_SUPPORT);
  1053. }
  1054.  
  1055. /*************************************************************************
  1056.  *
  1057.  -  ABPLOGON_PrepareRecips
  1058.  -
  1059.  *
  1060.  *
  1061.  *
  1062.  */
  1063. STDMETHODIMP
  1064. ABPLOGON_PrepareRecips(LPABPLOGON lpABPLogon,
  1065.     ULONG ulFlags,
  1066.     LPSPropTagArray lpPropTagArray,
  1067.     LPADRLIST lpRecipList)
  1068. {
  1069.     HRESULT         hResult         = hrSuccess;
  1070.     UINT            iRecip;
  1071.     UINT            iProp;
  1072.     ULONG           cValues;
  1073.     LPSPropValue    lpspvUser       = NULL;
  1074.     LPSPropValue    lpNewRecip      = NULL;
  1075.     LPMAPIPROP      lpMAPIPropEntry = NULL;
  1076.     SCODE           sc              = S_OK;
  1077.     ULONG           ulObjType;
  1078.     BOOL            fUselpspvUser;
  1079.  
  1080.     /* loop through all the recipients */
  1081.     
  1082.     if (!lpPropTagArray)
  1083.     {
  1084.         /*
  1085.          *  They only want us to update our entryID from ephemeral to
  1086.          *  permanent.  Since ours are already permanent, we don't need to
  1087.          *  do anything.
  1088.          */
  1089.         goto out;
  1090.     }
  1091.  
  1092.     for (iRecip = 0; iRecip < lpRecipList->cEntries; iRecip++)
  1093.     {
  1094.         LPUSR_ENTRYID   lpEntryID   = NULL;
  1095.         ULONG           cbEntryID;
  1096.         LPSPropValue    lpPropVal       = NULL;
  1097.         LPSPropValue    rgpropvalsRecip = lpRecipList->aEntries[iRecip].rgPropVals;
  1098.         ULONG           cPropsRecip     = lpRecipList->aEntries[iRecip].cValues;
  1099.  
  1100.         /* For each recipient, find its entryid */
  1101.         
  1102.         lpPropVal = PpropFindProp( rgpropvalsRecip, cPropsRecip, PR_ENTRYID );
  1103.         
  1104.         if ( lpPropVal )
  1105.         {
  1106.             lpEntryID = (LPUSR_ENTRYID)lpPropVal->Value.bin.lpb;
  1107.             cbEntryID = lpPropVal->Value.bin.cb;
  1108.         }
  1109.         else
  1110.             continue;
  1111.                 
  1112.         /* Is it one of ours? */
  1113.          
  1114.         if ( cbEntryID < CbNewENTRYID(0)
  1115.             || IsBadReadPtr( (LPVOID) lpEntryID, (UINT) cbEntryID ) )
  1116.         {
  1117.             continue;   /* no */
  1118.         }
  1119.          
  1120.         if ( memcmp( &(lpEntryID->muid), &muidABSample, sizeof(MAPIUID) ) )
  1121.             continue;   /* no */
  1122.  
  1123.         /* Try and open it. */
  1124.          
  1125.         hResult = HrNewSampUser((LPMAILUSER *)&lpMAPIPropEntry,
  1126.                                 &ulObjType, 
  1127.                                 cbEntryID, 
  1128.                                 (LPENTRYID) lpEntryID, 
  1129.                                 (LPABLOGON) lpABPLogon,
  1130.                                 NULL, 
  1131.                                 lpABPLogon->hLibrary,
  1132.                                 lpABPLogon->lpAllocBuff,
  1133.                                 lpABPLogon->lpAllocMore,
  1134.                                 lpABPLogon->lpFreeBuff,
  1135.                                 lpABPLogon->lpMalloc );
  1136.  
  1137.         if ( HR_FAILED(hResult) )
  1138.         {
  1139.              /* Couldn't open it...; Ignore it and keep looking */
  1140.  
  1141.             hResult = hrSuccess;
  1142.             DebugTrace( "ABPLOGON_PrepareRecips sees a bad user entry ID\n" );
  1143.             continue;
  1144.         }
  1145.  
  1146.         /* Get the properties requested */
  1147.  
  1148.         hResult = lpMAPIPropEntry->lpVtbl->GetProps( lpMAPIPropEntry, 
  1149.                 lpPropTagArray, 0, /* ansi */
  1150.                 &cValues, &lpspvUser );
  1151.  
  1152.         /* No longer need lpMAPIPropEntry  */
  1153.         
  1154.         lpMAPIPropEntry->lpVtbl->Release(lpMAPIPropEntry);
  1155.         lpMAPIPropEntry = NULL;
  1156.  
  1157.         if (HR_FAILED(hResult))
  1158.         {
  1159.             /* Failed getting properties. Cleanup and ignore this entry */
  1160.  
  1161.             hResult = hrSuccess;
  1162.             continue;
  1163.         }
  1164.         
  1165.         hResult = hrSuccess;
  1166.  
  1167.         Assert(cValues == lpPropTagArray->cValues);
  1168.  
  1169.         /*
  1170.          *  This is the hard part.
  1171.          *  Merge the two property sets: lpspvUser and lpsPropVal.  Note that
  1172.          *  both of these sets may have the same property - chances are they do.
  1173.          *  for these conflicts, lpspvUser should be the one we get the property
  1174.          *  from.
  1175.          *
  1176.          *  Guess how big the resultant SPropValue array is, and allocate one of that
  1177.          *  size.
  1178.          */
  1179.  
  1180.         sc = lpABPLogon->lpAllocBuff( (cValues + cPropsRecip) * sizeof( SPropValue ), 
  1181.                 &lpNewRecip);
  1182.         if (FAILED(sc))
  1183.         {
  1184.             /*
  1185.              *  Ok, to fail the call here.  If we're running into out of memory conditions
  1186.              *  we're all in trouble.
  1187.              */
  1188.  
  1189.             hResult = ResultFromScode( sc );
  1190.             goto err;
  1191.         }
  1192.  
  1193.         /*
  1194.          *  Copy lpspvUser properties over to lpNewRecip
  1195.          *  Check each property in lpsvUser to ensure that it isn't PT_ERROR, if so
  1196.          *  find the propval in rgpropvalsRecip ( the [in] recip prop val array ), 
  1197.          *  if it exists and use that property.
  1198.          */
  1199.         
  1200.         for (iProp = 0; iProp < cValues; iProp++)
  1201.         {
  1202.             fUselpspvUser = TRUE;
  1203.             
  1204.             if ( PROP_TYPE( lpspvUser[iProp].ulPropTag ) == PT_ERROR )
  1205.             {
  1206.                 lpPropVal = PpropFindProp( rgpropvalsRecip, cPropsRecip,
  1207.                          lpPropTagArray->aulPropTag[iProp] );
  1208.                          
  1209.                 if ( lpPropVal )
  1210.                 {
  1211.                     sc = PropCopyMore(  lpNewRecip + iProp, lpPropVal,
  1212.                             lpABPLogon->lpAllocMore, lpNewRecip );
  1213.                             
  1214.                     fUselpspvUser = FALSE;      
  1215.                 }
  1216.             }
  1217.                 
  1218.             if ( fUselpspvUser )
  1219.             {
  1220.                 sc = PropCopyMore(  lpNewRecip + iProp, lpspvUser + iProp,
  1221.                         lpABPLogon->lpAllocMore, lpNewRecip );
  1222.             }
  1223.             
  1224.             if (FAILED(sc))
  1225.             {
  1226.                 if (sc == MAPI_E_NOT_ENOUGH_MEMORY)
  1227.                 {
  1228.                     hResult = MakeResult(sc);
  1229.                     goto err;
  1230.                 }
  1231.                 
  1232.                 /*
  1233.                  *   Otherwise we've run into something wierd in the prop value array
  1234.                  *   like PT_UNSPECIFIED, PT_NULL, or PT_OBJECT.  In which case continue
  1235.                  *   on.
  1236.                  */
  1237.             }
  1238.         }
  1239.         
  1240.         /* Done with lpspvUser */
  1241.         
  1242.         lpABPLogon->lpFreeBuff( lpspvUser );
  1243.         lpspvUser = NULL;
  1244.  
  1245.         /*
  1246.          *  Copy those properties that aren't already in lpNewRecip
  1247.          *  from rgpropvalsRecip.  Don't copy over the PT_ERROR prop vals
  1248.          */
  1249.         for ( iProp = 0; iProp < cPropsRecip; iProp++ )
  1250.         {
  1251.         
  1252.             if ( PpropFindProp( lpNewRecip, cValues, rgpropvalsRecip[iProp].ulPropTag ) 
  1253.                 || PROP_TYPE( rgpropvalsRecip[iProp].ulPropTag ) == PT_ERROR )
  1254.                 continue;
  1255.  
  1256.             sc = PropCopyMore(  lpNewRecip + cValues, rgpropvalsRecip + iProp,
  1257.                     lpABPLogon->lpAllocMore, lpNewRecip );
  1258.             if ( FAILED( sc ) )
  1259.             {
  1260.                 if (sc == MAPI_E_NOT_ENOUGH_MEMORY)
  1261.                 {
  1262.                      
  1263.                     hResult = ResultFromScode( sc );
  1264.                     goto err;
  1265.                 }
  1266.                 
  1267.                 /*
  1268.                  *  Otherwise we've run into something wierd in the prop value array
  1269.                  *  like PT_UNSPECIFIED, PT_NULL, or PT_OBJECT.  In which case continue
  1270.                  *  on.
  1271.                  */
  1272.             }
  1273.             
  1274.             cValues++;
  1275.         }
  1276.  
  1277.         /*
  1278.          *  Replace the AdrEntry in the AdrList with this new lpNewRecip.  And
  1279.          *  don't forget the cValues!
  1280.          */
  1281.  
  1282.         lpRecipList->aEntries[iRecip].rgPropVals = lpNewRecip;
  1283.         lpRecipList->aEntries[iRecip].cValues    = cValues;
  1284.  
  1285.         /* Finally, free up the old AdrEntry. */
  1286.  
  1287.         lpABPLogon->lpFreeBuff( rgpropvalsRecip );
  1288.  
  1289.     }
  1290. out:
  1291.  
  1292.     DebugTraceResult( ABPLOGON_PrepareRecips, hResult );
  1293.     return hResult;
  1294.  
  1295. err:
  1296.  
  1297.     lpABPLogon->lpFreeBuff( lpspvUser );
  1298.     goto out;
  1299. }
  1300.  
  1301.  
  1302. /*
  1303.  *  LpMuidFromLogon -
  1304.  *    Returns the particular ABPLOGON object's unique identifier.
  1305.  *
  1306.  */  
  1307.  
  1308. LPMAPIUID
  1309. LpMuidFromLogon(LPABLOGON lpABLogon)
  1310. {
  1311.     LPABPLOGON lpABPLogon = (LPABPLOGON) lpABLogon;
  1312.  
  1313.     AssertSz(!IsBadReadPtr(lpABPLogon, sizeof(ABPLOGON)), "Bad logon object!\n");
  1314.  
  1315.     return (&(lpABPLogon->muidID));
  1316. }
  1317.  
  1318.  
  1319. /*
  1320.  *  HrLpszGetCurrentFileName -
  1321.  *    Returns a copy of the current .SAB file pointed to by this logon object.
  1322.  *
  1323.  */
  1324.  
  1325. HRESULT
  1326. HrLpszGetCurrentFileName(LPABLOGON lpABLogon, LPSTR * lppszFileName)
  1327. {
  1328.     LPABPLOGON lpABPLogon = (LPABPLOGON) lpABLogon;
  1329.     SCODE sc;
  1330.     HRESULT hResult = hrSuccess;
  1331.  
  1332.     AssertSz(!IsBadReadPtr(lpABPLogon, sizeof(ABPLOGON)), "SAB: Bad logon object!\n");
  1333.     AssertSz(!IsBadWritePtr(lppszFileName, sizeof(LPSTR)), "SAB: Bad dest string!\n");
  1334.  
  1335.     EnterCriticalSection(&lpABPLogon->cs);
  1336.     
  1337.     sc = lpABPLogon->lpAllocBuff (lstrlenA(lpABPLogon->lpszFileName)+1, lppszFileName);
  1338.     if (FAILED(sc))
  1339.     {
  1340.         hResult = ResultFromScode(sc);
  1341.         goto ret;
  1342.     }
  1343.  
  1344.     lstrcpyA( *lppszFileName, lpABPLogon->lpszFileName);
  1345.     
  1346. ret:
  1347.     LeaveCriticalSection(&lpABPLogon->cs);
  1348.  
  1349.     DebugTraceResult(HrLpszGetCurrentFileName, hResult);
  1350.     return hResult;
  1351. }
  1352.  
  1353. /*
  1354.  *  HrReplaceCurrentFileName -
  1355.  *    Replaces the current file name associated with this logon object and tries
  1356.  *    to save it all away in the profile.
  1357.  */
  1358.  
  1359. HRESULT
  1360. HrReplaceCurrentFileName(LPABLOGON lpABLogon, LPSTR lpszNewFile)
  1361. {
  1362.     LPABPLOGON lpABPLogon = (LPABPLOGON) lpABLogon;
  1363.     HRESULT hResult = hrSuccess;
  1364.     LPPROFSECT lpProfSect = NULL;
  1365.     LPSTR lpstrT;
  1366.     SCODE sc;
  1367.     SPropValue rgspv[1];
  1368.  
  1369.     AssertSz(!IsBadReadPtr(lpABPLogon, sizeof(ABPLOGON)), "Bad logon object!\n");
  1370.     
  1371.     EnterCriticalSection(&lpABPLogon->cs);
  1372.  
  1373.     /*
  1374.      *  SAB file name has changed have to update profile and objects
  1375.      */
  1376.     if (lstrcmpA(lpszNewFile, lpABPLogon->lpszFileName))
  1377.     {
  1378.  
  1379.         /*
  1380.          *  Open the private profile section...
  1381.          */
  1382.         hResult = lpABPLogon->lpMapiSup->lpVtbl->OpenProfileSection(
  1383.             lpABPLogon->lpMapiSup,
  1384.             NULL,
  1385.             MAPI_MODIFY,
  1386.             &lpProfSect);
  1387.         if (HR_FAILED(hResult))
  1388.         {
  1389.             /*
  1390.              *  Shouldn't get here, but in case I do, just...
  1391.              */
  1392.             goto ret;
  1393.         }
  1394.  
  1395.         /*
  1396.          *  Save the new name back into the profile
  1397.          */
  1398.         rgspv[0].ulPropTag = PR_SAB_FILE;
  1399.         rgspv[0].Value.lpszA = lpszNewFile;
  1400.  
  1401.         /*
  1402.          *  Don't care if I can save it in the profile or not.
  1403.          *  Saving it's a nice to have, but absolutely required
  1404.          *  for operation of this particular provider.
  1405.          */
  1406.         (void) lpProfSect->lpVtbl->SetProps(
  1407.             lpProfSect,
  1408.             1,
  1409.             rgspv,
  1410.             NULL);
  1411.  
  1412.         lpProfSect->lpVtbl->Release(lpProfSect);
  1413.  
  1414.         /*
  1415.          *  Allocate and copy this new one
  1416.          */
  1417.  
  1418.         sc = lpABPLogon->lpAllocBuff (lstrlenA(lpszNewFile)+1, &lpstrT);
  1419.         if (FAILED(sc))
  1420.         {
  1421.             hResult = ResultFromScode(sc);
  1422.             goto ret;
  1423.         }
  1424.  
  1425.         lstrcpyA( lpstrT, lpszNewFile );
  1426.  
  1427.         /*
  1428.          *  Free up the old one...
  1429.          */
  1430.         lpABPLogon->lpFreeBuff(lpABPLogon->lpszFileName);
  1431.  
  1432.         /*
  1433.          *  Put in the new one.
  1434.          */
  1435.         lpABPLogon->lpszFileName = lpstrT;
  1436.  
  1437.         /*
  1438.          *  Update the hierarchy table
  1439.          */
  1440.         hResult = HrBuildRootHier((LPABLOGON)lpABPLogon, NULL);
  1441.     }
  1442.  
  1443. ret:
  1444.     LeaveCriticalSection(&lpABPLogon->cs);
  1445.  
  1446.     DebugTraceResult(HrReplaceCurrentFileName, hResult);
  1447.     return hResult;
  1448. }
  1449.  
  1450. /*
  1451.  *  GenerateContainerDN -
  1452.  *      Common code for generating the display name of the single
  1453.  *      container exposed from this logon object.
  1454.  */
  1455. void
  1456. GenerateContainerDN(LPABLOGON lpABLogon, LPSTR lpszName)
  1457. {
  1458.     LPABPLOGON lpABPLogon = (LPABPLOGON) lpABLogon;
  1459.     LPSTR lpszFileName;
  1460.     int ich;
  1461.  
  1462.     AssertSz(!IsBadReadPtr(lpABPLogon, sizeof(ABPLOGON)), "Bad logon object!\n");
  1463.     
  1464.  
  1465.     EnterCriticalSection(&lpABPLogon->cs);
  1466.  
  1467.     lpszFileName = lpABPLogon->lpszFileName;
  1468.  
  1469.     /* get the filename without the path */
  1470.     for (ich = lstrlenA(lpszFileName) - 1; ich >= 0; ich--)
  1471.     {
  1472.         if (lpszFileName[ich] == '\\')
  1473.             break;
  1474.     }
  1475.  
  1476.     /* skip past the backslash */
  1477.     ich++;
  1478.  
  1479.     wsprintfA(lpszName, "SAB using %s", lpszFileName + ich);
  1480.  
  1481.     LeaveCriticalSection(&lpABPLogon->cs);
  1482. }
  1483.  
  1484. /*
  1485.  -  HrBuildRootHier
  1486.  -
  1487.  *
  1488.  *  Builds up the root hierarchy for the Sample Address Book.  
  1489.  *
  1490.  *
  1491.  */
  1492. enum {  ivalPR_DISPLAY_NAME_A = 0,
  1493.         ivalPR_ENTRYID,
  1494.         ivalPR_DEPTH,
  1495.         ivalPR_OBJECT_TYPE,
  1496.         ivalPR_DISPLAY_TYPE,
  1497.         ivalPR_CONTAINER_FLAGS,
  1498.         ivalPR_INSTANCE_KEY,
  1499.         ivalPR_AB_PROVIDER_ID,
  1500.         cvalMax };
  1501.  
  1502. static const SizedSPropTagArray(cvalMax, tagaRootColSet) =
  1503. {
  1504.     cvalMax,
  1505.     {
  1506.         PR_DISPLAY_NAME_A,
  1507.         PR_ENTRYID,
  1508.         PR_DEPTH,
  1509.         PR_OBJECT_TYPE,
  1510.         PR_DISPLAY_TYPE,
  1511.         PR_CONTAINER_FLAGS,
  1512.         PR_INSTANCE_KEY,
  1513.         PR_AB_PROVIDER_ID
  1514.     }
  1515. };
  1516.  
  1517. HRESULT
  1518. HrBuildRootHier(LPABLOGON lpABLogon, LPMAPITABLE * lppMAPITable)
  1519. {
  1520.     HRESULT hResult;
  1521.     SCODE sc;
  1522.     SRow sRow;
  1523.     SPropValue rgsPropValue[cvalMax];
  1524.     ULONG ulInstanceKey = 1;
  1525.     char szBuf[MAX_PATH];
  1526.     LPABPLOGON lpABPLogon = (LPABPLOGON) lpABLogon;
  1527.     DIR_ENTRYID eidRoot =   {   {0, 0, 0, 0},
  1528.                                 MUIDABSAMPLE,
  1529.                                 SAMP_VERSION,
  1530.                                 SAMP_DIRECTORY };
  1531.     
  1532.  
  1533.     EnterCriticalSection(&lpABPLogon->cs);
  1534.  
  1535.     /*
  1536.      *  See if we have a TaD yet
  1537.      */
  1538.     if (!lpABPLogon->lpTDatRoot)
  1539.     {
  1540.         /* Create a Table Data object */
  1541.         if (sc = CreateTable((LPIID) &IID_IMAPITableData,
  1542.                     lpABPLogon->lpAllocBuff,
  1543.                     lpABPLogon->lpAllocMore,
  1544.                     lpABPLogon->lpFreeBuff,
  1545.                     lpABPLogon->lpMalloc,
  1546.                     0,
  1547.                     PR_ENTRYID,
  1548.                     (LPSPropTagArray) &tagaRootColSet,
  1549.                     &(lpABPLogon->lpTDatRoot)))
  1550.         {
  1551.             hResult = ResultFromScode(sc);
  1552.             goto out;
  1553.         }
  1554.     }
  1555.     /* Constants */
  1556.  
  1557.     sRow.cValues = cvalMax;
  1558.     sRow.lpProps = rgsPropValue;
  1559.  
  1560.  
  1561.     /* First, the Display Name stuff*/
  1562.  
  1563.     rgsPropValue[ivalPR_DISPLAY_NAME_A].ulPropTag   = PR_DISPLAY_NAME_A;
  1564.     GenerateContainerDN((LPABLOGON) lpABPLogon, szBuf);
  1565.     rgsPropValue[ivalPR_DISPLAY_NAME_A].Value.lpszA = szBuf;
  1566.  
  1567.     /*
  1568.      *  For each SAB logon object associated with it's init object,
  1569.      *  we have a unique MAPIUID.  It's the only thing that distinguishes
  1570.      *  one SAB entryid from another in the merged hierarchy table that
  1571.      *  MAPI generates.
  1572.      */
  1573.  
  1574.     rgsPropValue[ivalPR_ENTRYID].ulPropTag          = PR_ENTRYID;
  1575.     eidRoot.muidID = lpABPLogon->muidID;
  1576.     rgsPropValue[ivalPR_ENTRYID].Value.bin.cb       = sizeof(DIR_ENTRYID);
  1577.     rgsPropValue[ivalPR_ENTRYID].Value.bin.lpb      = (LPVOID) &eidRoot;
  1578.  
  1579.  
  1580.     rgsPropValue[ivalPR_DEPTH].ulPropTag            = PR_DEPTH;
  1581.     rgsPropValue[ivalPR_DEPTH].Value.l              = 0;
  1582.  
  1583.  
  1584.     rgsPropValue[ivalPR_OBJECT_TYPE].ulPropTag      = PR_OBJECT_TYPE;
  1585.     rgsPropValue[ivalPR_OBJECT_TYPE].Value.l        = MAPI_ABCONT;
  1586.  
  1587.  
  1588.     rgsPropValue[ivalPR_DISPLAY_TYPE].ulPropTag     = PR_DISPLAY_TYPE;
  1589.     rgsPropValue[ivalPR_DISPLAY_TYPE].Value.l       = DT_NOT_SPECIFIC;
  1590.  
  1591.  
  1592.     rgsPropValue[ivalPR_CONTAINER_FLAGS].ulPropTag  = PR_CONTAINER_FLAGS;
  1593.     rgsPropValue[ivalPR_CONTAINER_FLAGS].Value.l    = AB_RECIPIENTS | AB_UNMODIFIABLE;
  1594.  
  1595.  
  1596.     rgsPropValue[ivalPR_INSTANCE_KEY].ulPropTag     = PR_INSTANCE_KEY;
  1597.     rgsPropValue[ivalPR_INSTANCE_KEY].Value.bin.cb  = sizeof(ULONG);
  1598.     rgsPropValue[ivalPR_INSTANCE_KEY].Value.bin.lpb = (LPBYTE) &ulInstanceKey;
  1599.  
  1600.  
  1601.     rgsPropValue[ivalPR_AB_PROVIDER_ID].ulPropTag   = PR_AB_PROVIDER_ID;
  1602.     rgsPropValue[ivalPR_AB_PROVIDER_ID].Value.bin.cb= sizeof(MAPIUID);
  1603.     rgsPropValue[ivalPR_AB_PROVIDER_ID].Value.bin.lpb= (LPBYTE) &muidSABProviderID;
  1604.  
  1605.     hResult = lpABPLogon->lpTDatRoot->lpVtbl->HrModifyRow(
  1606.         lpABPLogon->lpTDatRoot, &sRow);
  1607.  
  1608.     if (HR_FAILED(hResult))
  1609.         goto out;
  1610.  
  1611.  
  1612.     /*
  1613.      *  Check to see if they want a view returned as well
  1614.      */
  1615.     if (lppMAPITable)
  1616.     {
  1617.         /* Get a view from the Table data object */
  1618.         hResult =
  1619.             lpABPLogon->lpTDatRoot->lpVtbl->HrGetView(
  1620.             lpABPLogon->lpTDatRoot,
  1621.             NULL,
  1622.             NULL,
  1623.             0,
  1624.             lppMAPITable);
  1625.     }
  1626.  
  1627. out:
  1628.  
  1629.     LeaveCriticalSection(&lpABPLogon->cs);
  1630.     
  1631.     DebugTraceResult(HrBuildRootHier, hResult);
  1632.     return hResult;
  1633. }
  1634.  
  1635.  
  1636.  
  1637. /*
  1638.  *  Checks to see if the file passed in is still the actual file that
  1639.  *  should be browsed.
  1640.  */
  1641. BOOL
  1642. FEqualSABFiles( LPABLOGON lpABLogon,
  1643.                 LPSTR lpszFileName)
  1644. {
  1645.     LPABPLOGON lpABPLogon = (LPABPLOGON) lpABLogon;
  1646.     BOOL fEqual;
  1647.  
  1648.     AssertSz(!IsBadReadPtr(lpABPLogon, sizeof(ABPLOGON)), "Bad logon object!\n");
  1649.     
  1650.     EnterCriticalSection(&lpABPLogon->cs);
  1651.  
  1652.     fEqual = !lstrcmpA( lpszFileName, lpABPLogon->lpszFileName );
  1653.  
  1654.     LeaveCriticalSection(&lpABPLogon->cs);
  1655.  
  1656.     return fEqual;
  1657. }
  1658.