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 / docfile.ms / msplogon.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-04-11  |  62.5 KB  |  2,197 lines

  1. /*
  2.  *  M S P L O G O N . C
  3.  *
  4.  *  Logon to a MAPI Sample Message Store.
  5.  *
  6.  *  Copyright 1992-1995 Microsoft Corporation.  All Rights Reserved.
  7.  */
  8.  
  9. #include "msp.h"
  10. #include "msprc.h"
  11. #include <stddef.h>
  12.  
  13. #include "..\common\wrap3d.h"
  14.  
  15. #define MSL_CheckParameters(pobj, intf, method, arglist)        \
  16.         OBJ_CheckParameters(pobj, intf, method, sizeof(MSL), &vtblMSL, arglist)
  17. #define MSP_CheckParameters(pobj, intf, method, arglist)        \
  18.         OBJ_CheckParameters(pobj, intf, method, sizeof(MSP), &vtblMSP, arglist)
  19.  
  20. #ifndef MB_SETFOREGROUND
  21. #define MB_SETFOREGROUND 0
  22. #endif
  23.  
  24. #define MSL_EnterCriticalSection(pmsl)  OBJ_EnterCriticalSection((POBJ)pmsl)
  25. #define MSL_LeaveCriticalSection(pmsl)  OBJ_LeaveCriticalSection((POBJ)pmsl)
  26.  
  27. MSL_Vtbl vtblMSL =
  28. {
  29.     (MSL_QueryInterface_METHOD *)       OBJ_QueryInterface,
  30.     (MSL_AddRef_METHOD *)               OBJ_AddRef,
  31.     MSL_Release,
  32.     (MSL_GetLastError_METHOD *)         IMS_GetLastError,
  33.     MSL_Logoff,
  34.     (MSL_OpenEntry_METHOD *)            IMS_OpenEntry,
  35.     (MSL_CompareEntryIDs_METHOD *)      IMS_CompareEntryIDs,
  36.     (MSL_Advise_METHOD *)               IMS_Advise,
  37.     (MSL_Unadvise_METHOD *)             IMS_Unadvise,
  38.     MSL_OpenStatusEntry
  39. };
  40.  
  41. MAPIUID uidProvider = SMPMS_UID_PROVIDER;
  42.  
  43. /* Manifest constants */
  44.  
  45. #define ACCTSIZE    16          /* Our choice for maximum password length. */
  46.  
  47. static SPropTagArray sptaPass =
  48. {
  49.     1, {PR_SMS_PASSWORD}
  50. };
  51.  
  52. TCHAR szPropFileName[] = TEXT("msgstore.prp");
  53. TCHAR szFolderFileName[] = TEXT("recfldr.stg");
  54. TCHAR szProviderDisplayName[] = TEXT("Sample Message Store");
  55. TCHAR szDisplayPrefix[] = TEXT("Sample store at ");
  56.  
  57. /* property tags needed for service creation or configuration */
  58. static  SizedSPropTagArray(4,ptaConfig) = {4, { PR_SMS_PATH,
  59.                                             PR_SMS_PASSWORD,
  60.                                             PR_SMS_REMEMBER_PW,
  61.                                             PR_SMS_CREATE } };
  62.  
  63. /* property tags that should be removed from the profile after */
  64. /* service creation or configuration */
  65. static  SizedSPropTagArray(2,ptaDel)= {2, { PR_SMS_REMEMBER_PW,
  66.                                             PR_SMS_CREATE } };
  67.  
  68. /* service parameter block */
  69. typedef struct _ServicePBLK
  70. {
  71.     PMSP            pmsp;
  72.     LPPROFSECT      pps;
  73.     LPMAPISUP       psup;
  74.     ULONG           ulUIParam;
  75.     ULONG           ulContext;
  76.     ULONG           ulSEFlags;
  77.     ULONG           cvalsProf;
  78.     LPSPropValue    pvalsProf;
  79.     ULONG           cvalsClient;
  80.     LPSPropValue    pvalsClient;
  81. } SERVICEPBLK, FAR * PSERVICEPBLK;
  82.  
  83.  
  84. #define LGNCRED_PATH        ((ULONG) 0x00000001)
  85. #define LGNCRED_PASS        ((ULONG) 0x00000002)
  86. #define LGNCRED_CREATE      ((ULONG) 0x00000004)
  87. #define LGNCRED_REMEMBER    ((ULONG) 0x00000008)
  88.  
  89. /* Typedefs */
  90.  
  91. typedef struct _LGNCRED
  92. {
  93.     ULONG ulFieldMask;
  94.     TCHAR szPath[MAX_PATH];
  95.     TCHAR szPass[ACCTSIZE];
  96.     BOOL fCreate;
  97.     BOOL fRemember;
  98.     BOOL fCancel;
  99.     LPVOID lpCtl3d;
  100. } LGNCRED, * PLGNCRED;
  101.  
  102. typedef struct _DLGPSWD
  103. {
  104.     TCHAR szPath[MAX_PATH];
  105.     TCHAR szPass[ACCTSIZE];
  106.     LPMAPISUP psup;
  107.     PLMR plmr;
  108.     BOOL fRemember;
  109.     BOOL fCancel;
  110.     LPVOID lpCtl3d;
  111. } DLGPSWD, * PDLGPSWD;
  112.  
  113. /* Internal function prototypes */
  114.  
  115. static HRESULT HrOpenSingleProvider(LPPROVIDERADMIN padp,
  116.     LPPROFSECT FAR *lppProfSect);
  117. static SCODE ScCreateOrConfigure(PSERVICEPBLK pspb);
  118. static SCODE ScCreateStore(PSERVICEPBLK pspb, LPTSTR szPath,
  119.     LPTSTR szPass, PMSL * ppmsl, PIMS * ppims);
  120. static BOOL FAlreadyOpenStore(PMSP pmsp, LPTSTR szPath, PIMS * ppims);
  121.  
  122. static HRESULT HrGetLogonDlgCred(HINSTANCE hInst, ULONG ulUIParam, LPTSTR szPath,
  123.     LPTSTR szPass, BOOL *pfCreate, BOOL *pfRemember);
  124. STDAPI_(BOOL) LogonDlgProc(HWND hDlg, UINT message, WPARAM wParam,
  125.     LPARAM lParam);
  126. static HRESULT HrGetPassword(HINSTANCE hInst, LPMAPISUP psup, PLMR plmr,
  127.     ULONG ulUIParam, LPTSTR szPath, LPTSTR szPass, BOOL *pfRemember);
  128. STDAPI_(BOOL) PasswordDlgProc(HWND hDlg, UINT message, WPARAM wParam,
  129.     LPARAM lParam);
  130. static HRESULT HrGetProfileCred(PLMR plmr, LPPROFSECT pps, LPTSTR szPass,
  131.     BOOL *pfFound);
  132. static HRESULT HrSetProfileCred(LPPROFSECT pps, LPTSTR szPass, LPTSTR szPath,
  133.     BOOL fRemember, ULONG cbEntryID, LPBYTE lpEntryID, LPMAPIUID puidRK);
  134. static HRESULT HrConfirmCred(LPTSTR szPath, LPTSTR szPass, LPMAPISUP psup,
  135.     PLMR plmr);
  136. static HRESULT HrFilePathExists(LPTSTR szStorePath, LPTSTR szFileName);
  137. static HRESULT HrCheckStoreIntegrity(LPTSTR szPath);
  138. static BOOL FIsValidPath(LPTSTR szPath, BOOL fCreate);
  139. static void DecodeSpoolSecurity(ULONG cbSpoolSecurity, LPBYTE pbSpoolSecurity,
  140.     LPTSTR szPath, LPTSTR szPass);
  141. static HRESULT HrGetSpoolSecurity(LPTSTR szPath, LPTSTR szPass,
  142.     PLMR plmr, ULONG * lpcbSpoolSecurity, LPBYTE * lppbSpoolSecurity);
  143. static HRESULT HrCheckAndOpenStore(PMSP pmsp, LPMAPISUP psup, BOOL fModify,
  144.     LPPROFSECT pps, LPTSTR szPath, LPTSTR szPass, BOOL fIsSpooler,
  145.     PMSL *ppmsl, PIMS *ppims);
  146. static SCODE ScCreateMSL(PMSP pmsp, PMSL * ppmsl);
  147. static BOOL FFindPropInPSPB(PSERVICEPBLK pspb, ULONG ulPT, LPSPropValue *ppval);
  148. static SCODE ScGetFullFileName(PSERVICEPBLK pspb, BOOL *pfCreate,
  149.     LPSTR pszPath);
  150.  
  151. /*
  152.  *  MSP_Logon
  153.  *
  154.  *  Purpose:
  155.  *      Logs in one user to the message store and returns a logon object
  156.  *      and a message store object.  Gets credentials through the
  157.  *      profile or a dialog.  Prompts if more information is needed.
  158.  *
  159.  *  Arguments:
  160.  *      pmsp                MSPROVIDER object returned at INIT time.
  161.  *      psup                Pointer to MAPI Support object.
  162.  *      ulUIParam           Handle to parent window cast to a ULONG.
  163.  *      szProfileName       String with the name of profile.
  164.  *                          (UNICODE if MAPI_UNICODE flag set in ulFlags)
  165.  *      cbEntryID           Size of lpEntryID.
  166.  *      lpEntryID           Provider component of store resource EntryID.
  167.  *      ulFlags             Flags for access methods:
  168.  *                          MDB_WRITE           Write access.
  169.  *                          MAPI_BEST_ACCESS    Write access if possible.
  170.  *                          MDB_NO_DIALOG       No logon dialog.
  171.  *                          MAPI_UNICODE        If szProfileName UNICODE
  172.  *      piid                Identifies what interface is desired on the
  173.  *                          about-to-be-opened object.
  174.  *      lpcbSpoolSecurity   Address of the variable in which the
  175.  *                          provider returns size of *lppbSpoolSecurity.
  176.  *      lppbSpoolSecurity   Address to return validation data
  177.  *                          necessary for SpoolerLogon to
  178.  *                          piggyback off this logon session.
  179.  *      lpulLowLevelError   Possible low level error to return if
  180.  *                          error or MAPI_W_EXTENDED_WARNING is returned.
  181.  *      pszMessage          Error / Warning string on logon.  If MAPI_UNICODE
  182.  *                          is set in ulFlags then it is UNICODE.
  183.  *      ppmslogon           Address to return a pointer to MSLOGON
  184.  *                          object for use by MAPI.DLL.
  185.  *      ppmdb               Address of a pointer to the message
  186.  *                          store object for use by the client.
  187.  *
  188.  *  Returns:
  189.  *      HRESULT
  190.  *
  191.  *  Side effects:
  192.  *      May put up logon screen to select/open store if
  193.  *      MDB_NO_DIALOG is not set.  For store creation, Logon
  194.  *      creates "hidden" files for MDB management.
  195.  *
  196.  *  Errors:
  197.  *      MAPI_E_NOT_ENOUGH_MEMORY    Could not allocate memory.
  198.  *      MAPI_E_CALL_FAILED          Failure creating a new store.
  199.  *      MAPI_E_CALL_FAILED          Windowing system failure trying
  200.  *                                  to display logon UI.
  201.  *      MAPI_E_CORRUPT_STORE        One of the necessary store
  202.  *                                  files is missing.
  203.  *      MAPI_E_LOGON_FAILED         Insufficient or bad credentials.
  204.  */
  205. STDMETHODIMP
  206. MSP_Logon(PMSP pmsp, LPMAPISUP psup, ULONG ulUIParam, LPSTR szProfileName,
  207.     ULONG cbEntryID, LPENTRYID lpEntryID, ULONG ulFlags, LPCIID piid,
  208.     ULONG * lpcbSpoolSecurity, LPBYTE * lppbSpoolSecurity,
  209.     LPMAPIERROR * lppMapiError, LPMSLOGON * ppmslogon, LPMDB * ppmdb)
  210. {
  211.     HRESULT hr = hrSuccess;
  212.     HRESULT hrT;
  213.     BOOL fRemember = FALSE;     /* Remember password in profile? */
  214.     BOOL fFoundPassword;        /* TRUE if the password was in the profile */
  215.     PIMS pims = NULL;           /* Internal IMsgStore implementation */
  216.     PMSL pmsl = NULL;           /* logon object to give to MAPI */
  217.     TCHAR szPath[MAX_PATH];     /* Path to store root */
  218.     TCHAR szPass[ACCTSIZE];     /* Store account password */
  219.     PEID peid = (PEID) lpEntryID;
  220.     LPPROFSECT pps = NULL;      /* our profile section */
  221.  
  222.     MSP_CheckParameters(
  223.             pmsp, 
  224.             IMSProvider,
  225.             Logon,
  226.             (pmsp, 
  227.             psup, 
  228.             ulUIParam, 
  229.             szProfileName, 
  230.             cbEntryID, 
  231.             lpEntryID, 
  232.             ulFlags, 
  233.             piid, 
  234.             lpcbSpoolSecurity, 
  235.             lppbSpoolSecurity, 
  236.             lppMapiError,
  237.             ppmslogon, 
  238.             ppmdb));
  239.  
  240.     #ifdef VALIDATE
  241.     if (ulFlags & MAPI_UNICODE)
  242.         return ResultFromScode(MAPI_E_BAD_CHARWIDTH);
  243.     #endif
  244.  
  245.     MSP_EnterCriticalSection(pmsp);
  246.  
  247.     AssertSz(!pmsp->fInvalid, "This MSProvider has already been shutdown");
  248.  
  249.     *lpcbSpoolSecurity = 0L;
  250.     *lppbSpoolSecurity = NULL;
  251.     *lppMapiError = NULL;
  252.     *ppmslogon = NULL;
  253.     *ppmdb = NULL;
  254.  
  255.     if (piid && !FQueryInterface(OT_MSGSTORE, piid))
  256.     {
  257.         hr = ResultFromScode(E_NOINTERFACE);
  258.         goto exit;
  259.     }
  260.  
  261.     hr = psup->lpVtbl->OpenProfileSection(psup, NULL, MAPI_MODIFY, &pps);
  262.     if (hr != hrSuccess)
  263.         goto exit;
  264.  
  265.     /* Get the full path to the store out of the EntryID */
  266.  
  267.     if (peid == NULL)
  268.     {
  269.         hr = ResultFromScode(MAPI_E_UNCONFIGURED);
  270.         goto exit;
  271.     }
  272.     else if (FIsInvalidEID(cbEntryID, peid, NULL))
  273.     {
  274.         hr = ResultFromScode(MAPI_E_INVALID_PARAMETER);
  275.         goto exit;
  276.     }
  277.  
  278.     lstrcpy(szPath, peid->szPath);
  279.  
  280.     DebugTrace("\nSMS: MSP_Logon %s\n\n", szPath);
  281.     
  282.     /* If we can piggyback on an existing open message store on this */
  283.     /* session then do so. If we piggyback, then don't return a logon */
  284.     /* object or addref the support object. */
  285.  
  286.     if (FAlreadyOpenStore(pmsp, szPath, &pims))
  287.     {
  288.         DebugTrace("\nSMS: Piggybacking client logon\n");
  289.         Assert(hr == hrSuccess);
  290.         goto exit;
  291.     }
  292.  
  293.     /* Get store credentials from profile. */
  294.  
  295.     hr = HrGetProfileCred(&pmsp->lmr, pps, szPass, &fFoundPassword);
  296.     if (hr != hrSuccess)
  297.         goto exit;
  298.  
  299.     /* If the password was in the profile, then the user wanted us to */
  300.     /* remember it (that's the only way it would be in the profile). */
  301.  
  302.     if (fFoundPassword)
  303.         fRemember = TRUE;
  304.  
  305.     while (TRUE)
  306.     {
  307.         SCODE sc;
  308.  
  309.         hr = HrCheckAndOpenStore(pmsp, psup,
  310.             !!(ulFlags & (MDB_WRITE | MAPI_BEST_ACCESS)), pps, szPath,
  311.             szPass, FALSE, &pmsl, &pims);
  312.         if (hr == hrSuccess)
  313.             break;
  314.  
  315.         sc = GetScode(hr);
  316.  
  317.         /* Preset hr to the value that will cause MAPI to bring up our */
  318.         /* config UI */
  319.  
  320.         hr = ResultFromScode(MAPI_E_UNCONFIGURED);
  321.  
  322.         if (!(ulFlags & MDB_NO_DIALOG))
  323.         {
  324.             if (sc == MAPI_E_LOGON_FAILED)
  325.             {
  326.                 hr = HrGetPassword(pmsp->hInst, psup, &pmsp->lmr, ulUIParam,
  327.                     szPath, szPass, &fRemember);
  328.             }
  329.             else if (sc == MAPI_E_NOT_FOUND)
  330.             {
  331.                 MessageBox(NULL, "The path to the message store is invalid.",
  332.                     "Sample Message Store",
  333.                     MB_OK | MB_TASKMODAL | MB_SETFOREGROUND);
  334.             }
  335.         }
  336.  
  337.         if (hr != hrSuccess)
  338.             goto exit;
  339.     }
  340.  
  341.     /* Complete regular logon tasks. */
  342.  
  343.     /* Update saved credentials if they have changed. */
  344.  
  345.     hrT = HrSetProfileCred(pps, szPass, szPath, fRemember, 
  346.         pims->eidStore.cb, pims->eidStore.lpb, &pims->uidResource);
  347.  
  348.     if (hrT == hrSuccess)
  349.         hrT = pps->lpVtbl->SaveChanges(pps, 0);
  350.  
  351.     /* Make the profile section permanent. */
  352.     if (hrT == hrSuccess)
  353.         hrT = psup->lpVtbl->ModifyProfile(psup, 0);
  354.  
  355.     hr = psup->lpVtbl->SetProviderUID(psup, &pims->uidResource, 0L);
  356.     if (hr != hrSuccess)
  357.         goto exit;
  358.  
  359.     hr = HrSetupPrivateNotifications(pims);
  360.     if (hr != hrSuccess)
  361.         goto exit;
  362.  
  363.     /* This call sets [out] parameters, and should therefore be the last */
  364.     /* call that could fail. */
  365.     hr = HrGetSpoolSecurity(szPath, szPass, &pims->lmr,
  366.         lpcbSpoolSecurity, lppbSpoolSecurity);
  367.  
  368.     if (hr != hrSuccess)
  369.         goto exit;
  370.  
  371.     /* Add this new store to the list of open stores. */
  372.     OBJ_Enqueue((POBJ) pims, (POBJ) pmsp);
  373.  
  374.     UlAddRef(psup);         /* I'm keeping a reference */
  375.  
  376.     Assert(hr == hrSuccess);    /* no error */
  377.  
  378. exit:
  379.     if (hr == hrSuccess)
  380.     {
  381.         /* Fill in [out] parameters. */
  382.         *ppmdb = (LPMDB) pims;
  383.         *ppmslogon = (LPMSLOGON) pmsl;
  384.     }
  385.     else
  386.     {
  387.         UlRelease(pims);
  388.  
  389.         /* Releasing the pmsl must come after releasing the pims. */
  390.         UlRelease(pmsl);
  391.  
  392.         Assert(*lpcbSpoolSecurity == 0L);
  393.         Assert(*lppbSpoolSecurity == NULL);
  394.         Assert(*lppMapiError == NULL);
  395.         Assert(*ppmslogon == NULL);
  396.         Assert(*ppmdb == NULL);
  397.     }
  398.  
  399.     UlRelease(pps);
  400.  
  401.     MSP_LeaveCriticalSection(pmsp);
  402.  
  403.     DebugTraceResult(MSP_Logon, hr);
  404.     return HrCheckHr(hr, IMSProvider_Logon);
  405. }
  406.  
  407. /*
  408.  *  MSP_SpoolerLogon
  409.  *
  410.  *  Purpose:
  411.  *      Logs in the Spooler to this message store.
  412.  *
  413.  *  Arguments:
  414.  *      psup            Pointer to MAPI Support object.
  415.  *      ulUIParam           HWND of parent window
  416.  *      szProfileName       Name of profile
  417.  *      cbEntryID           Size of lpEntryID.
  418.  *      lpEntryID           Provider component of store resource
  419.  *                          EntryID.
  420.  *      ulFlags             Flags.  See Logon above, except
  421.  *                          MDB_NO_DIALOG is normally (always?)
  422.  *                          set on this call.
  423.  *      piid                IID of desired interface for ppmdb
  424.  *      cbSpoolSecurity     Size of data in lpbSpoolSecurity.
  425.  *      lpbSpoolSecurity    Validation data necessary for
  426.  *                          SpoolerLogon to complete.
  427.  *      lpulLowLevelError   Possible low level error to return if
  428.  *                          error or MAPI_W_EXTENDED_WARNING is returned.
  429.  *      pszMessage          Error / Warning string on logon.  If MAPI_UNICODE
  430.  *                          is set in ulFlags then it is UNICODE.
  431.  *      ppmslogon           Address to return a pointer to MSLOGON
  432.  *                          object for use by MAPI.DLL.
  433.  *      ppmdb               Address of a pointer to the Spooler
  434.  *                          Message Store Object.
  435.  *
  436.  *  Returns:
  437.  *      HRESULT
  438.  *
  439.  *  Side effects:
  440.  *      May put up logon screen to select/open store if
  441.  *      MDB_NO_DIALOG is not set.  Calls HrNewIMS to create the
  442.  *      message store object, which allocates memory.
  443.  *
  444.  *  Errors:
  445.  *      MAPI_E_NO_MEMORY        Could not allocate memory.
  446.  *      MAPI_E_LOGON_FAILED     Bad credentials
  447.  */
  448. STDMETHODIMP
  449. MSP_SpoolerLogon(PMSP pmsp, LPMAPISUP psup, ULONG ulUIParam,
  450.     LPTSTR szProfileName, ULONG cbEntryID, LPENTRYID lpEntryID,
  451.     ULONG ulFlags, LPCIID piid, ULONG cbSpoolSecurity,
  452.     LPBYTE lpbSpoolSecurity, LPMAPIERROR * lppMapiError,
  453.     LPMSLOGON * ppmslogon, LPMDB * ppmdb)
  454. {
  455.     TCHAR szPass[ACCTSIZE];     /* Store account password */
  456.     TCHAR szPath[MAX_PATH];     /* path to store root */
  457.     HRESULT hr = hrSuccess;
  458.     PIMS pims = NULL;
  459.     PMSL pmsl = NULL;
  460.     LPPROFSECT pps = NULL;      /* our profile section */
  461.  
  462.     MSP_CheckParameters(
  463.             pmsp, 
  464.             IMSProvider,
  465.             SpoolerLogon,
  466.             (pmsp, 
  467.             psup, 
  468.             ulUIParam, 
  469.             szProfileName, 
  470.             cbEntryID, 
  471.             lpEntryID, 
  472.             ulFlags, 
  473.             piid, 
  474.             cbSpoolSecurity, 
  475.             lpbSpoolSecurity, 
  476.             lppMapiError, 
  477.             ppmslogon, 
  478.             ppmdb));
  479.  
  480.     #ifdef VALIDATE
  481.     if (ulFlags & MAPI_UNICODE)
  482.         return ResultFromScode(MAPI_E_BAD_CHARWIDTH);
  483.     #endif
  484.         
  485.     MSP_EnterCriticalSection(pmsp);
  486.  
  487.     AssertSz(!pmsp->fInvalid, "This MSProvider has already been shutdown");
  488.  
  489.     *lppMapiError = NULL;
  490.     *ppmslogon = NULL;
  491.     *ppmdb = NULL;
  492.  
  493.     if (piid && !FQueryInterface(OT_MSGSTORE, piid))
  494.     {
  495.         hr = ResultFromScode(MAPI_E_INTERFACE_NOT_SUPPORTED);
  496.         goto exit;
  497.     }
  498.  
  499.     hr = psup->lpVtbl->OpenProfileSection(psup, NULL, MAPI_MODIFY, &pps);
  500.     if (hr != hrSuccess)
  501.         goto exit;
  502.  
  503.     DecodeSpoolSecurity(cbSpoolSecurity, lpbSpoolSecurity, szPath, szPass);
  504.  
  505.     DebugTrace("\nSMS: MSP_SpoolerLogon %s\n\n",szPath);
  506.  
  507.     /* If we can piggyback on an existing open message store */
  508.     /* on this session then do so. If we piggyback, then don't return */
  509.     /* a logon object or addref the support object. */
  510.  
  511.     if (FAlreadyOpenStore(pmsp, szPath, &pims))
  512.     {
  513.         DebugTrace("\nSMS: Piggybacking spooler logon\n");
  514.         goto exit;
  515.     }
  516.  
  517.  
  518.     hr = HrCheckAndOpenStore(pmsp, psup, TRUE, pps, szPath, szPass, TRUE,
  519.         &pmsl, &pims);
  520.     if (hr == hrSuccess)
  521.         hr = psup->lpVtbl->SetProviderUID(psup, &pims->uidResource, 0L);
  522.     if (hr == hrSuccess)
  523.         hr = HrSetupPrivateNotifications(pims);
  524.  
  525.     if (hr == hrSuccess)
  526.     {
  527.         /* Add this new store to the list of open stores. */
  528.         OBJ_Enqueue((POBJ) pims, (POBJ) pmsp);
  529.         UlAddRef(psup);
  530.     }
  531.  
  532. exit:
  533.     if (hr == hrSuccess)
  534.     {
  535.         *ppmdb = (LPMDB) pims;
  536.         *ppmslogon = (LPMSLOGON) pmsl;
  537.     }
  538.  
  539.     UlRelease(pps);
  540.  
  541.     MSP_LeaveCriticalSection(pmsp);
  542.  
  543.     DebugTraceResult(MSP_SpoolerLogon, hr);
  544.     return hr;
  545. }
  546.  
  547. /*
  548.  -  MSL_Release
  549.  -
  550.  */
  551.  
  552. STDMETHODIMP_(ULONG) MSL_Release(PMSL pmsl)
  553. {
  554.     LONG cRef;
  555.  
  556.     MSL_EnterCriticalSection(pmsl);
  557.  
  558.     AssertSz1(pmsl->cRef > 0, "MSL_Release(): Bogus cRef (%08lX)", pmsl->cRef);
  559.  
  560.     cRef = --pmsl->cRef;
  561.  
  562.     MSL_LeaveCriticalSection(pmsl);
  563.  
  564.     if (cRef == 0)
  565.     {
  566.         Assert(pmsl->pims == NULL);
  567.         DeleteCriticalSection(&pmsl->cs);
  568.         LMFree(&pmsl->lmr, pmsl);
  569.     }
  570.  
  571.     return (cRef);
  572. }
  573.  
  574. /*
  575.  *  MSL_Logoff()
  576.  */
  577.  
  578. STDMETHODIMP MSL_Logoff(PMSL pmsl, ULONG * pulFlags)
  579. {
  580.     MSL_CheckParameters(
  581.             pmsl, 
  582.             IMSLogon,
  583.             Logoff,
  584.             (pmsl,
  585.             pulFlags));
  586.  
  587.     MSL_EnterCriticalSection(pmsl);
  588.  
  589.     AssertSz(!pmsl->fInvalid, "Logon object already logged off");
  590.  
  591.     if (pmsl->pims)
  592.         OBJ_Destroy((POBJ) pmsl->pims);
  593.     else
  594.         MSL_LeaveCriticalSection(pmsl);
  595.  
  596. #ifdef DEBUG
  597.     pmsl->fInvalid = TRUE;
  598. #endif
  599.  
  600.     return (hrSuccess);
  601. }
  602.  
  603. /*
  604.  *  MSL_OpenStatusEntry()
  605.  *
  606.  *  MAPI has determined that the client call to OpenStatusEntry
  607.  *  is for OUR row in the status table.  Open the Status Object
  608.  *  appropriate for our store.
  609.  *
  610.  *  This object is logically part of the store, and can be made
  611.  *  invalid when the store (either the MSLogon or LPMDB object,
  612.  *  at our choice) goes away.
  613.  */
  614.  
  615. STDMETHODIMP MSL_OpenStatusEntry(PMSL pmsl, LPCIID lpiid, ULONG ulFlags,
  616.     ULONG * lpulObjType, LPVOID * lppEntry)
  617. {
  618.     MSL_CheckParameters(
  619.     pmsl, 
  620.     IMSLogon,
  621.     OpenStatusEntry,
  622.     (pmsl, 
  623.     lpiid, 
  624.     ulFlags, 
  625.     lpulObjType, 
  626.     lppEntry));
  627.  
  628.     AssertSz(!pmsl->fInvalid, "Logon object already logged off");
  629.  
  630.     DebugTraceSc(MSL_OpenStatusEntry, MAPI_E_NO_SUPPORT);
  631.     return ResultFromScode(MAPI_E_NO_SUPPORT);
  632. }
  633.  
  634. STDAPI SMSServiceEntry(HINSTANCE hInst, LPMALLOC lpMalloc, LPMAPISUP psup,
  635.         ULONG ulUIParam, ULONG ulSEFlags, ULONG ulContext, ULONG cvals,
  636.         LPSPropValue pvals, LPPROVIDERADMIN lpAdminProviders,
  637.         LPMAPIERROR FAR *lppMapiError)
  638. {
  639.     HRESULT             hr;
  640.     LPALLOCATEBUFFER    lpAllocBuff;
  641.     LPALLOCATEMORE      lpAllocMore;
  642.     LPFREEBUFFER        lpFreeBuff      = NULL;
  643.     PMSP                pmsp            = NULL;
  644.     LPPROFSECT          pps             = NULL;
  645.     SERVICEPBLK         spb;
  646.     ULONG               ulProvVer;
  647.     ULONG               cvalsProf;
  648.     LPSPropValue        pvalsProf       = NULL;
  649.  
  650.     /* check the array of profile section objects */
  651.     if (IsBadReadPtr(psup, sizeof(LPMAPISUP))
  652.         ||  (cvals && IsBadReadPtr(pvals, (UINT)(sizeof(SPropValue) * cvals))))
  653.         return ResultFromScode(MAPI_E_INVALID_PARAMETER);
  654.  
  655.     if (ulSEFlags & ~(MAPI_UNICODE
  656.                     | MSG_SERVICE_UI_READ_ONLY
  657.                     | SERVICE_UI_ALWAYS     /* Same value as UI_SERVICE */
  658.                     | SERVICE_UI_ALLOWED    /* New */
  659.                     | UI_CURRENT_PROVIDER_FIRST
  660.                     | SERVICE_LOGON_FAILED))
  661.         return ResultFromScode(MAPI_E_UNKNOWN_FLAGS);
  662.  
  663.     if (ulSEFlags & MAPI_UNICODE)
  664.         return ResultFromScode(MAPI_E_BAD_CHARWIDTH);
  665.  
  666.     if (    (ulContext == MSG_SERVICE_INSTALL)
  667.         ||  (ulContext == MSG_SERVICE_UNINSTALL)
  668.         ||  (ulContext == MSG_SERVICE_DELETE))
  669.         return (hrSuccess);
  670.  
  671.     if (ulContext != MSG_SERVICE_CONFIGURE && ulContext != MSG_SERVICE_CREATE)
  672.         return (ResultFromScode(MAPI_E_NO_SUPPORT));
  673.  
  674.     /* get the profile section for the provider */
  675.     hr = HrOpenSingleProvider(lpAdminProviders, &pps);
  676.     if (hr != hrSuccess)
  677.         goto err;
  678.  
  679.     /*  Get the memory allocation routines we'll be needing. */
  680.     hr = psup->lpVtbl->GetMemAllocRoutines(psup, &lpAllocBuff, &lpAllocMore,
  681.             &lpFreeBuff);
  682.     if (hr != hrSuccess)
  683.         goto err;
  684.  
  685.     hr = MSProviderInit(hInst, lpMalloc, lpAllocBuff, lpAllocMore,
  686.             lpFreeBuff, 0, CURRENT_SPI_VERSION, &ulProvVer,
  687.             &(LPMSPROVIDER)pmsp);
  688.     if (hr != hrSuccess)
  689.         goto err;
  690.  
  691.     /* get the properties out of the profile section that we will be */
  692.     /* be needing */
  693.  
  694.     hr = pps->lpVtbl->GetProps(pps, (LPSPropTagArray) &ptaConfig, 0,
  695.             &cvalsProf, &pvalsProf);
  696.     if (HR_FAILED(hr))
  697.         goto err;
  698.  
  699.     Assert (PROP_ID(pvalsProf[0].ulPropTag) == PROP_ID(PR_SMS_PATH));
  700.     Assert (PROP_ID(pvalsProf[1].ulPropTag) == PROP_ID(PR_SMS_PASSWORD));
  701.     Assert (PROP_ID(pvalsProf[2].ulPropTag) == PROP_ID(PR_SMS_REMEMBER_PW));
  702.     Assert (PROP_ID(pvalsProf[3].ulPropTag) == PROP_ID(PR_SMS_CREATE));
  703.  
  704.     /* initialize the service parameter block */
  705.     spb.pmsp            = pmsp;
  706.     spb.pps             = pps;
  707.     spb.psup            = psup;
  708.     spb.ulUIParam       = ulUIParam;
  709.     spb.ulSEFlags       = ulSEFlags;
  710.     spb.ulContext       = ulContext;
  711.     spb.cvalsProf       = cvalsProf;
  712.     spb.pvalsProf       = pvalsProf;
  713.     spb.cvalsClient     = cvals;
  714.     spb.pvalsClient     = pvals;
  715.  
  716.     hr = ResultFromScode(ScCreateOrConfigure(&spb));
  717.  
  718. err:
  719.     if (lpFreeBuff)
  720.         (*lpFreeBuff)(pvalsProf);
  721.  
  722.     UlRelease(pmsp);
  723.     UlRelease(pps);
  724.  
  725.     DebugTraceResult(SMSServiceEntry, hr);
  726.     return hr;
  727. }
  728.  
  729. /*
  730.  *  Module internal functions
  731.  */
  732.  
  733. static HRESULT
  734. HrOpenSingleProvider(LPPROVIDERADMIN padp, LPPROFSECT FAR *lppProfSect)
  735. {
  736.     HRESULT     hr;
  737.     LPMAPITABLE pmt = NULL;
  738.     LPSRowSet   prws = NULL;
  739.     LPSPropValue pval;
  740.     SPropTagArray ptaProvUID = {1, {PR_PROVIDER_UID}};
  741.  
  742.     hr = padp->lpVtbl->GetProviderTable(padp, 0, &pmt);
  743.     if (hr)
  744.         goto err;
  745.  
  746.     hr = pmt->lpVtbl->SetColumns(pmt, &ptaProvUID, 0L);
  747.     if (hr)
  748.         goto err;
  749.  
  750.     hr = pmt->lpVtbl->QueryRows(pmt, 1, 0, &prws);
  751.     if (hr || prws == NULL || prws->cRows == 0)
  752.     {
  753.         hr = ResultFromScode(MAPI_E_NOT_FOUND);
  754.         goto err;
  755.     }
  756.  
  757.     Assert(prws->aRow[0].cValues == 1);
  758.     pval = prws->aRow[0].lpProps;
  759.     if (!pval || pval->ulPropTag != PR_PROVIDER_UID)
  760.     {
  761.         /* The property we need is missing. Error. */
  762.         hr = ResultFromScode(MAPI_E_NOT_FOUND);
  763.         goto err;
  764.     }
  765.  
  766.     /* Found the right property; use it to open our section */
  767.     hr = padp->lpVtbl->OpenProfileSection(padp,
  768.         (LPMAPIUID) pval->Value.bin.lpb, NULL, MAPI_MODIFY, lppProfSect);
  769.  
  770. err:
  771.     FreeProws(prws);
  772.     UlRelease(pmt);
  773.  
  774.     DebugTraceResult(HrOpenSingleProvider, hr);
  775.     return hr;
  776. }
  777.  
  778. static SCODE ScCreateOrConfigure(PSERVICEPBLK pspb)
  779. {
  780.     SCODE           sc              = S_OK;
  781.     LPSPropValue    pval;
  782.     LPSTR           pszFileTitle;
  783.     CHAR            szPath[MAX_PATH];
  784.     CHAR            szPass[ACCTSIZE];
  785.     LPPROFSECT      pps             = pspb->pps;
  786.     BOOL            fNeedUI         = FALSE;
  787.     BOOL            fAllowUI        = FALSE;
  788.     BOOL            fCreate         = FALSE;
  789.     BOOL            fRemember       = FALSE;
  790.  
  791.     /* Check for UI */
  792.  
  793.     if (pspb->ulSEFlags & SERVICE_UI_ALWAYS)
  794.         fAllowUI = fNeedUI = TRUE;
  795.     else    
  796.         if (pspb->ulSEFlags & SERVICE_UI_ALLOWED)
  797.             fAllowUI = TRUE;
  798.         
  799.     if (FFindPropInPSPB(pspb, PR_SMS_PASSWORD, &pval))
  800.     {
  801.         ULONG cbPass;
  802.  
  803.         /* Passwords must fit in ACCTSIZE bytes. Truncate the password if */
  804.         /* it's too long. */
  805.  
  806.         cbPass = lstrlenA(pval->Value.lpszA) + 1;
  807.         if (cbPass > ACCTSIZE)
  808.             cbPass = ACCTSIZE;
  809.  
  810.         memcpy(szPass, pval->Value.lpszA, (UINT) cbPass);
  811.         szPass[cbPass - 1] = '\0';
  812.  
  813.         /* We found the password. Since we found it, assume that the */
  814.         /* user wants us to remember it. Only if PR_SMS_REMEMBER_PW is */
  815.         /* present and FALSE will we remove the password. */
  816.  
  817.         fRemember = TRUE;
  818.     }
  819.     else
  820.         szPass[0] = '\0';
  821.  
  822.     if (FFindPropInPSPB(pspb, PR_SMS_CREATE, &pval))
  823.         fCreate = pval->Value.b;
  824.  
  825.     if (FFindPropInPSPB(pspb, PR_SMS_REMEMBER_PW, &pval))
  826.         fRemember = pval->Value.b;
  827.  
  828.     /* try to find the path in either the properties passed in, or */
  829.     /* the properties in the profile */
  830.  
  831.     if (    FFindPropInPSPB(pspb, PR_SMS_PATH, &pval)
  832.         &&  GetFullPathName(pval->Value.lpszA, MAX_PATH, szPath,
  833.                 &pszFileTitle))
  834.     {
  835.         DWORD   dwFA;
  836.  
  837.         Assert (*(pszFileTitle - 1) == '\\');
  838.  
  839.         dwFA = GetFileAttributes(szPath);
  840.  
  841.         /* If the file isn't there, and we aren't creating, then error. */
  842.         /* If the file is there, and we are creating, then error. */
  843.  
  844.         if (dwFA == 0xFFFFFFFF && fCreate == FALSE)
  845.         {
  846.             sc = MAPI_E_NOT_FOUND;
  847.             fNeedUI = TRUE;
  848.         }
  849.         else if (dwFA != 0xFFFFFFFF && fCreate == TRUE)
  850.         {
  851.             sc = MAPI_E_NO_ACCESS;
  852.             fNeedUI = TRUE;
  853.         }
  854.     }
  855.     else
  856.     {
  857.         szPath[0] = '\0';
  858.         sc = MAPI_E_NOT_FOUND;
  859.         fNeedUI = TRUE;
  860.     }
  861.  
  862.     while (TRUE)
  863.     {
  864.         if (sc == S_OK)
  865.         {
  866.             PMSL pmsl;
  867.             PIMS pims;
  868.  
  869.             /* Verify that everything works before we exit. */
  870.     
  871.             if (fCreate)
  872.                 sc = ScCreateStore(pspb, szPath, szPass, &pmsl, &pims);
  873.             else
  874.                 sc = GetScode(HrCheckAndOpenStore(pspb->pmsp, pspb->psup,
  875.                     TRUE, pspb->pps, szPath, szPass, FALSE, &pmsl, &pims));
  876.             if (sc)
  877.                 fNeedUI = TRUE;
  878.             else
  879.             {
  880.                 HRESULT hrT;
  881.     
  882.                 /* delete the unnecessary properties from the profile */
  883.                 pps->lpVtbl->DeleteProps(pps, (LPSPropTagArray)&ptaDel,
  884.                     NULL);
  885.  
  886.                 /* Update saved credentials if they have changed. */
  887.             
  888.                 hrT = HrSetProfileCred(pps, szPass, szPath, fRemember, 
  889.                     pims->eidStore.cb, pims->eidStore.lpb,
  890.                     &pims->uidResource);
  891.             
  892.                 if (hrT == hrSuccess)
  893.                     hrT = pps->lpVtbl->SaveChanges(pps, 0);
  894.             
  895.                 /* Can't make the profile section permanent because */
  896.                 /* the support object we are given for config doesn't */
  897.                 /* support ModifyProfile. Make it permanent during Logon. */
  898.             
  899.                 /* Addref the support object because we kept a reference */
  900.                 /* in pims, and releasing pims will release psup. We want */
  901.                 /* the refcount on psup to be the same at config exit as */
  902.                 /* it was when we were called. */
  903.  
  904.                 UlAddRef(pspb->psup);
  905.  
  906.                 UlRelease(pims);
  907.                 UlRelease(pmsl);
  908.     
  909.                 if (!fNeedUI)
  910.                     goto ret;   /* SUCCESS! */
  911.             }
  912.         }
  913.         
  914.         if (fNeedUI && !fAllowUI)
  915.         {
  916.             sc = MAPI_E_UNCONFIGURED;
  917.             goto ret;
  918.         }
  919.  
  920.         /* Do the UI */
  921.     
  922.         sc = GetScode(HrGetLogonDlgCred(pspb->pmsp->hInst, pspb->ulUIParam,
  923.             szPath, szPass, &fCreate, &fRemember));
  924.         
  925.         if (sc != S_OK)
  926.             goto ret;
  927.  
  928.         fNeedUI = FALSE;
  929.     }
  930.  
  931. ret:
  932.     DebugTraceSc(ScCreateOrConfigure, sc);
  933.     return sc;
  934. }
  935.  
  936. /*
  937.  -  ScCreateStore
  938.  -
  939.  *  Create a Sample Store out on disk.
  940.  *
  941.  *  Returns the pims which points to the store, and the
  942.  *  pmsl which points to the MSLogon object.
  943.  */
  944. static SCODE ScCreateStore(PSERVICEPBLK pspb, LPTSTR szPath,
  945.     LPTSTR szPass, PMSL * ppmsl, PIMS * ppims)
  946. {
  947.     HRESULT hr = hrSuccess;
  948.     SCODE sc = S_OK;
  949.     PRFS prfs = NULL;           /* Struct for receive folder settings */
  950.     BOOL fCreateDir = FALSE;    /* Was new directory created? */
  951.     BOOL fCreateProp = FALSE;   /* Was new MsgStore props file created? */
  952.     BOOL fCreateFld = FALSE;    /* Was new root folder created? */
  953.     BOOL fCreateRFS = FALSE;    /* Was receive folder file created? */
  954.     PIMS pims = NULL;
  955.     PMSL pmsl = NULL;
  956.  
  957.     /* Create the directory */
  958.  
  959.     if (!CreateDirectory(szPath, NULL))
  960.     {
  961.         sc = MAPI_E_CALL_FAILED;
  962.         goto exit;
  963.     }
  964.  
  965.     fCreateDir = TRUE;
  966.  
  967.     /* Create file to hold receive folder settings */
  968.  
  969.     hr = OpenRFS(szPath, szFolderFileName, RFS_CREATE, &prfs);
  970.     if (hr != hrSuccess)
  971.     {
  972.         sc = GetScode(hr);
  973.         goto exit;
  974.     }
  975.  
  976.     fCreateRFS = TRUE;
  977.  
  978.     /* Create the MSLogon object. */
  979.  
  980.     sc = ScCreateMSL(pspb->pmsp, &pmsl);
  981.     if (sc != S_OK)
  982.         goto exit;
  983.  
  984.     /* Create instance, creates Message Store props file as well */
  985.  
  986.     hr = HrNewIMS(szPath, szPropFileName, pspb->pmsp, pmsl, prfs,
  987.             pspb->pps, pspb->psup, TRUE, &pims);
  988.     if (hr != hrSuccess)
  989.     {
  990.         sc = GetScode(hr);
  991.         goto exit;
  992.     }
  993.  
  994.     OBJ_SetFlag(pims, OBJF_MODIFY);
  995.     pmsl->pims = pims;
  996.  
  997.     fCreateProp = TRUE;
  998.  
  999.     hr = HrInitIMSProps(pims, szPass);
  1000.     if (hr != hrSuccess)
  1001.     {
  1002.         sc = GetScode(hr);
  1003.         goto exit;
  1004.     }
  1005.  
  1006.     /* Create file to hold root folder properties */
  1007.  
  1008.     {
  1009.         PEID peidTmp = NULL;
  1010.  
  1011.         hr = HrCreateFolderStorage(NULL, FOLDER_ROOT, "", "",
  1012.             FALSE, pims, &peidTmp);
  1013.  
  1014.         if (hr != hrSuccess)
  1015.         {
  1016.             sc = GetScode(hr);
  1017.             goto exit;
  1018.         }
  1019.  
  1020.         /* We can throw away the returned EntryID because we know */
  1021.         /* how to construct the EntryID for the root folder when  */
  1022.         /* we need to open it (see pims->OpenEntry()).           */
  1023.  
  1024.         LMFree(&pspb->pmsp->lmr, peidTmp);
  1025.     }
  1026.  
  1027.     fCreateFld = TRUE;
  1028.  
  1029.     *ppmsl = pmsl;
  1030.     *ppims = pims;
  1031.  
  1032. exit:
  1033.     if (sc != S_OK)
  1034.     {
  1035.         TCHAR rgch[MAX_PATH];
  1036.  
  1037.         if (pims)
  1038.         {
  1039.             FreeNull(pims->szStorePath);
  1040.             LMFree(&pspb->pmsp->lmr, pims->eidStore.lpb);
  1041.             LMFree(&pspb->pmsp->lmr, pims);
  1042.         }
  1043.         else if (prfs)
  1044.         {
  1045.             /* If we have an RFS but NO IMS, close RFS manually. */
  1046.             NFSideAssertSz(CloseRFS(prfs) == hrSuccess, "RFS not closed");
  1047.         }
  1048.  
  1049.         if ( pmsl )
  1050.         {
  1051.             pmsl->pims = NULL;
  1052.  
  1053.             /* Releasing the pmsl must come after releasing the IMS. */
  1054.             UlRelease(pmsl);
  1055.         }
  1056.         
  1057.         /* We need to use state flags to know how much work to undo  */
  1058.         /* on a create because otherwise we may accidentally erase   */
  1059.         /* files that we did not create (because they were created   */
  1060.         /* by another Sample Store creation in a different session). */
  1061.  
  1062.         if (fCreateProp == TRUE)
  1063.         {
  1064.             if (FAppendPathNoMem(szPath, szPropFileName, MAX_PATH, rgch))
  1065.                 (void)DeleteFile(rgch);
  1066.             else
  1067.                 TrapSz("Can't clean up create #1!");
  1068.         }
  1069.  
  1070.         if (fCreateRFS == TRUE)
  1071.         {
  1072.             if (FAppendPathNoMem(szPath, szFolderFileName, MAX_PATH, rgch))
  1073.                 (void)DeleteFile(rgch);
  1074.             else
  1075.                 TrapSz("Can't clean up create #2!");
  1076.         }
  1077.  
  1078.         if (fCreateFld == TRUE)
  1079.         {
  1080.             if (FAppendPathNoMem(szPath, szPropertyFileName, MAX_PATH, rgch))
  1081.                 (void)DeleteFile(rgch);
  1082.             else
  1083.                 TrapSz("Can't clean up create #3!");
  1084.         }
  1085.  
  1086.         if (fCreateDir == TRUE)
  1087.             (void)RemoveDirectory(szPath);
  1088.     }
  1089.  
  1090.     DebugTraceSc(ScCreateStore, sc);
  1091.     return sc;
  1092. }
  1093.  
  1094. /*
  1095.  *  FAlreadyOpenStore
  1096.  *
  1097.  *  Purpose:
  1098.  *      Searches the list of stores open in this MAPI session and
  1099.  *      returns the MS object of a store that matches the path
  1100.  *      that's passed in.
  1101.  *
  1102.  *  Arguments:
  1103.  *      pmsp    Pointer to the Message Store Provider (MAPI Session
  1104.  *              context).  This is where the list of open stores
  1105.  *              lives.
  1106.  *      szPath  String containing full path to the store to open.
  1107.  *      ppims   Location in which to return the address of a
  1108.  *              message store object already open (only valid if
  1109.  *              the function returns TRUE).
  1110.  *
  1111.  *  Returns:
  1112.  *      BOOL.  Will be TRUE if the message store is already open,
  1113.  *      FALSE if not.
  1114.  *
  1115.  *  Side effects:
  1116.  *      None.
  1117.  *
  1118.  *  Errors:
  1119.  *      None.
  1120.  */
  1121. static BOOL FAlreadyOpenStore(PMSP pmsp, LPTSTR szPath, PIMS * ppims)
  1122. {
  1123.     PIMS pimsPrev = NULL;
  1124.  
  1125.     for (pimsPrev = (PIMS) pmsp->pobjHead; pimsPrev;
  1126.         pimsPrev = (PIMS) pimsPrev->pobjNext)
  1127.     {
  1128.         if (!lstrcmpi(pimsPrev->szStorePath, szPath))
  1129.         {
  1130.             OBJ_EnterCriticalSection(pimsPrev);
  1131.  
  1132.             if(!OBJ_TestFlag(pimsPrev, MSF_BEINGDESTROYED))
  1133.             {
  1134.                 *ppims = pimsPrev;
  1135.                 UlAddRef(pimsPrev);
  1136.  
  1137.                 OBJ_LeaveCriticalSection(pimsPrev);
  1138.                 return TRUE;
  1139.             }
  1140.             
  1141.             DebugTrace("SMS: Attempt to OpenMsgStore at %s while a another IMsgStore\n"
  1142.                         "object opened on this directory is being released\n", szPath);
  1143.  
  1144.             OBJ_LeaveCriticalSection(pimsPrev);
  1145.         }
  1146.     }
  1147.  
  1148.     return FALSE;
  1149. }
  1150.  
  1151. /*
  1152.  *  HrGetPassword
  1153.  *
  1154.  *  Purpose:
  1155.  *      Get the password for a store interactively by putting up a dialog.
  1156.  *
  1157.  *  Parameters:
  1158.  *      hInst       [in] Instance handle of my DLL
  1159.  *      psup        [in] Pointer to the mapi support object.
  1160.  *      plmr        [in] Pointer to the memory allocation routines.
  1161.  *      ulUIParam   [in] Window handle cast to ULONG.
  1162.  *      szPath      [in] The pathname to the top of the message store.
  1163.  *      szPass      [out] Pointer to a buffer in which to place the password.
  1164.  *      pfRemember  [out] Address of boolean: should the password be saved
  1165.  *                        in profile?
  1166.  *
  1167.  *  Returns:
  1168.  *      HRESULT
  1169.  *
  1170.  *  Side effects:
  1171.  *      Puts up password dialog.
  1172.  *
  1173.  *  Errors:
  1174.  *      None.
  1175.  */
  1176. static HRESULT HrGetPassword(HINSTANCE hInst, LPMAPISUP psup, PLMR plmr,
  1177.     ULONG ulUIParam, LPTSTR szPath, LPTSTR szPass, BOOL *pfRemember)
  1178. {
  1179.     HRESULT hr = hrSuccess;
  1180.     DLGPSWD dlgpswd;
  1181.  
  1182.     NFAssertSz(szPass, "Bad szPass");
  1183.  
  1184.     lstrcpy(dlgpswd.szPath, szPath);
  1185.     dlgpswd.psup = psup;
  1186.     dlgpswd.plmr = plmr;
  1187.     dlgpswd.fRemember = FALSE;
  1188.     dlgpswd.fCancel = FALSE;
  1189.     dlgpswd.lpCtl3d = CTL3D_Initialize(hInst);
  1190.  
  1191.     if (DialogBoxParam(hInst, TEXT("PSWDDIALOGBOX"), (HWND) ulUIParam,
  1192.             (DLGPROC) PasswordDlgProc, (LPARAM) &dlgpswd) == -1)
  1193.     {
  1194.         hr = ResultFromScode(MAPI_E_CALL_FAILED);
  1195.         goto exit;
  1196.     }
  1197.  
  1198.     if (dlgpswd.fCancel)
  1199.     {
  1200.         hr = ResultFromScode(MAPI_E_USER_CANCEL);
  1201.         goto exit;
  1202.     }
  1203.  
  1204.     if (szPass)
  1205.         lstrcpy(szPass, dlgpswd.szPass);
  1206.  
  1207.     if (pfRemember)
  1208.         *pfRemember = dlgpswd.fRemember;
  1209.  
  1210.     Assert(hr == hrSuccess);
  1211.  
  1212. exit:
  1213.     CTL3D_Uninitialize(dlgpswd.lpCtl3d);
  1214.     DebugTraceResult(HrGetPassword, hr);
  1215.     return hr;
  1216. }
  1217.  
  1218. /*
  1219.  *  PasswordDlgProc
  1220.  *
  1221.  *  Purpose:
  1222.  *      Dialog procedure to handle password dialog events.
  1223.  *
  1224.  *  Parameters:
  1225.  *      hDlg        Handle to the dialog.
  1226.  *      message     Message to be handled.
  1227.  *      wParam      Button ID if button is pressed.
  1228.  *      lParam      Context parameter from dialog creation (see
  1229.  *                  HrGetLogonDlgCred).
  1230.  *
  1231.  *  Returns:
  1232.  *      BOOL.  TRUE if handled, FALSE if not
  1233.  *
  1234.  *  Side effects:
  1235.  *      None.
  1236.  *
  1237.  *  Errors:
  1238.  *      None.
  1239.  */
  1240. STDAPI_(BOOL) PasswordDlgProc(HWND hDlg, UINT message, WPARAM wParam,
  1241.     LPARAM lParam)
  1242. {
  1243.     PDLGPSWD pdlgpswd;
  1244.     BOOL fHandled = FALSE;
  1245.  
  1246.     AssertSz(hDlg, "Bad hDlg");
  1247.  
  1248.     switch (message)
  1249.     {
  1250.     case WM_INITDIALOG:
  1251.         {
  1252.             SetWindowLong(hDlg, DWL_USER, lParam);
  1253.             pdlgpswd = (PDLGPSWD) lParam;
  1254.  
  1255.             CTL3D_Subclass(pdlgpswd->lpCtl3d, hDlg, CTL3D_ALL);
  1256.  
  1257. #ifdef _WIN32
  1258.             SetForegroundWindow(hDlg);
  1259. #endif
  1260.             BringWindowToTop(hDlg);
  1261.  
  1262.             SetDlgItemText(hDlg, TEXT_PATH, pdlgpswd->szPath);
  1263.  
  1264.             pdlgpswd->fRemember = FALSE;
  1265.  
  1266.             fHandled = TRUE;
  1267.             break;
  1268.         }
  1269.  
  1270.     case WM_COMMAND:
  1271.         {
  1272.             pdlgpswd = (PDLGPSWD) GetWindowLong(hDlg, DWL_USER);
  1273.  
  1274.             switch (LOWORD(wParam))
  1275.             {
  1276.             case IDOK:
  1277.                 {
  1278.                     GetDlgItemText(hDlg, IDE_ACCOUNT_PASSWORD,
  1279.                         pdlgpswd->szPass, ACCTSIZE * sizeof(TCHAR));
  1280.  
  1281.                     if (HrConfirmCred(pdlgpswd->szPath, pdlgpswd->szPass,
  1282.                         pdlgpswd->psup, pdlgpswd->plmr) != hrSuccess)
  1283.                     {
  1284.                         /* put up a message box */
  1285.                         MessageBox(hDlg, "Password is incorrect.",
  1286.                             "Sample Store Password",
  1287.                             MB_OK | MB_APPLMODAL | MB_SETFOREGROUND);
  1288.  
  1289.                         /* highlight the password field */
  1290.                         SetFocus(hDlg);
  1291.                         break;
  1292.                     }
  1293.  
  1294.                     pdlgpswd->fRemember = 
  1295.                         IsDlgButtonChecked(hDlg, IDC_REMEMBER);
  1296.  
  1297.                     EndDialog(hDlg, 0);
  1298.                     fHandled = TRUE;
  1299.                     break;
  1300.                 }
  1301.             case IDCANCEL:
  1302.                 {
  1303.                     pdlgpswd->fCancel = TRUE;
  1304.                     EndDialog(hDlg, 0);
  1305.                     fHandled = TRUE;
  1306.                     break;
  1307.                 }
  1308.             default:
  1309.                 {
  1310.                     fHandled = FALSE;
  1311.                     break;
  1312.                 }
  1313.             }
  1314.         }
  1315.  
  1316.     default:
  1317.         {
  1318.             fHandled = FALSE;
  1319.             break;
  1320.         }
  1321.     }
  1322.  
  1323.     return fHandled;
  1324. }
  1325.  
  1326. /*
  1327.  *  HrGetLogonDlgCred
  1328.  *
  1329.  *  Purpose:
  1330.  *      Obtain credentials interactively for opening a store by
  1331.  *      putting up a dialog.
  1332.  *
  1333.  *  Parameters:
  1334.  *      hInst       Instance of my DLL
  1335.  *      ulUIParam   Window handle cast to ULONG.
  1336.  *      szPath      Address of buffer in which to place the path to
  1337.  *                  the root directory.
  1338.  *      szPass      Address of buffer in which to place the logon
  1339.  *                  Account Password.
  1340.  *      pfCreate    Address of boolean: should store be created?
  1341.  *      pfRemember  Address of boolean: should password be saved in profile?
  1342.  *
  1343.  *  Returns:
  1344.  *      HRESULT
  1345.  *
  1346.  *  Side effects:
  1347.  *      Puts up dialog.
  1348.  *
  1349.  *  Errors:
  1350.  *      None.
  1351.  */
  1352. static HRESULT HrGetLogonDlgCred(HINSTANCE hInst, ULONG ulUIParam,
  1353.     LPTSTR szPath, LPTSTR szPass, BOOL *pfCreate, BOOL *pfRemember)
  1354. {
  1355.     HRESULT hr = hrSuccess;
  1356.     LGNCRED lgncred;
  1357.  
  1358.     NFAssertSz(szPass, "Bad szPass");
  1359.  
  1360.     lstrcpy(lgncred.szPath, szPath);
  1361.     lstrcpy(lgncred.szPass, szPass);
  1362.     lgncred.fCreate = FALSE;
  1363.     lgncred.fRemember = *pfRemember;
  1364.     lgncred.fCancel = FALSE;
  1365.     lgncred.ulFieldMask = (szPath ? LGNCRED_PATH : 0L)
  1366.                         | (szPass ? LGNCRED_PASS : 0L)
  1367.                         | (pfCreate ? LGNCRED_CREATE : 0L)
  1368.                         | LGNCRED_REMEMBER;
  1369.  
  1370.     lgncred.lpCtl3d = CTL3D_Initialize(hInst);
  1371.  
  1372.     if (DialogBoxParam(hInst, TEXT("LOGONDIALOGBOX"), (HWND) ulUIParam,
  1373.             (DLGPROC) LogonDlgProc, (LPARAM) &lgncred) == -1)
  1374.     {
  1375.         hr = ResultFromScode(MAPI_E_CALL_FAILED);
  1376.         goto exit;
  1377.     }
  1378.  
  1379.     if (lgncred.fCancel)
  1380.     {
  1381.         hr = ResultFromScode(MAPI_E_USER_CANCEL);
  1382.         goto exit;
  1383.     }
  1384.  
  1385.     if (szPath)
  1386.     {
  1387.         DWORD dwPathLength = 0L;
  1388.         LPTSTR szPathName = NULL;
  1389.  
  1390.         dwPathLength = GetFullPathName(lgncred.szPath, MAX_PATH,
  1391.             szPath, &szPathName);
  1392.         if (!dwPathLength || dwPathLength > MAX_PATH)
  1393.         {
  1394.             hr = ResultFromScode(MAPI_E_UNCONFIGURED);
  1395.             goto exit;
  1396.         }
  1397.     }
  1398.  
  1399.     if (szPass)
  1400.         lstrcpy(szPass, lgncred.szPass);
  1401.  
  1402.     if (pfCreate)
  1403.         *pfCreate = lgncred.fCreate;
  1404.  
  1405.     *pfRemember = lgncred.fRemember;
  1406.  
  1407.     Assert(hr == hrSuccess);
  1408.  
  1409. exit:
  1410.     CTL3D_Uninitialize(lgncred.lpCtl3d);
  1411.  
  1412.     DebugTraceResult(HrGetLogonDlgCred, hr);
  1413.     return hr;
  1414. }
  1415.  
  1416. /*
  1417.  *  LogonDlgProc
  1418.  *
  1419.  *  Purpose:
  1420.  *      Dialog procedure to handle logon events.
  1421.  *
  1422.  *  Parameters:
  1423.  *      hDlg        Handle to the dialog.
  1424.  *      message     Message to be handled.
  1425.  *      wParam      Button ID if button is pressed.
  1426.  *      lParam      Context parameter from dialog creation (see
  1427.  *                  HrGetLogonDlgCred).
  1428.  *
  1429.  *  Returns:
  1430.  *      BOOL.  TRUE if handled, FALSE if not
  1431.  *
  1432.  *  Side effects:
  1433.  *      None.
  1434.  *
  1435.  *  Errors:
  1436.  *      None.
  1437.  */
  1438. STDAPI_(BOOL) LogonDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
  1439. {
  1440.     PLGNCRED plgncred;
  1441.     BOOL fHandled = FALSE;
  1442.  
  1443.     AssertSz(hDlg, "Bad hDlg");
  1444.  
  1445.     switch (message)
  1446.     {
  1447.     case WM_INITDIALOG:
  1448.         {
  1449.             SetWindowLong(hDlg, DWL_USER, lParam);
  1450.             plgncred = (PLGNCRED) lParam;
  1451.  
  1452.             CTL3D_Subclass(plgncred->lpCtl3d, hDlg, CTL3D_ALL);
  1453.  
  1454. #ifdef _WIN32
  1455.             SetForegroundWindow(hDlg);
  1456. #endif
  1457.             BringWindowToTop(hDlg);
  1458.  
  1459.             if (plgncred->ulFieldMask & LGNCRED_PATH)
  1460.                 SetDlgItemText(hDlg, IDE_ROOT_PATH, plgncred->szPath);
  1461.             else
  1462.                 EnableWindow(GetDlgItem(hDlg, IDE_ROOT_PATH), FALSE);
  1463.  
  1464.             if (plgncred->ulFieldMask & LGNCRED_PASS)
  1465.                 SetDlgItemText(hDlg, IDE_ACCOUNT_PASSWORD, plgncred->szPass);
  1466.             else
  1467.                 EnableWindow(GetDlgItem(hDlg, IDE_ACCOUNT_PASSWORD), FALSE);
  1468.  
  1469.             if (!(plgncred->ulFieldMask & LGNCRED_CREATE))
  1470.                 EnableWindow(GetDlgItem(hDlg, IDC_CREATE), FALSE);
  1471.  
  1472.             if (plgncred->ulFieldMask & LGNCRED_REMEMBER)
  1473.                 CheckDlgButton(hDlg, IDC_REMEMBER, plgncred->fRemember);
  1474.             else
  1475.                 EnableWindow(GetDlgItem(hDlg, IDC_REMEMBER), FALSE);
  1476.  
  1477.             fHandled = TRUE;
  1478.             break;
  1479.         }
  1480.  
  1481.     case WM_COMMAND:
  1482.         {
  1483.             plgncred = (PLGNCRED) GetWindowLong(hDlg, DWL_USER);
  1484.  
  1485.             switch (LOWORD(wParam))
  1486.             {
  1487.             case IDOK:
  1488.                 {
  1489.                     if (plgncred->ulFieldMask & LGNCRED_CREATE)
  1490.                     {
  1491.                         plgncred->fCreate =
  1492.                             IsDlgButtonChecked(hDlg, IDC_CREATE);
  1493.                     }
  1494.  
  1495.                     if (plgncred->ulFieldMask & LGNCRED_PATH)
  1496.                     {
  1497.                         GetDlgItemText(hDlg, IDE_ROOT_PATH,
  1498.                             plgncred->szPath, MAX_PATH * sizeof(TCHAR));
  1499.                     }
  1500.  
  1501.                     /* check if this is a valid path */
  1502.                     if (!FIsValidPath(plgncred->szPath, plgncred->fCreate))
  1503.                     {
  1504.                         /* put up a message box */
  1505.                         MessageBox(hDlg, (plgncred->fCreate) ?
  1506.                             "Root directory can not be created." :
  1507.                             "Path to root directory not found.",
  1508.                             "Message Store Logon", MB_OK | MB_APPLMODAL | MB_SETFOREGROUND);
  1509.  
  1510.                         /* highlight the path field */
  1511.                         SetFocus(hDlg);
  1512.                         break;
  1513.                     }
  1514.  
  1515.                     if (plgncred->ulFieldMask & LGNCRED_PASS)
  1516.                     {
  1517.                         GetDlgItemText(hDlg, IDE_ACCOUNT_PASSWORD,
  1518.                             plgncred->szPass, ACCTSIZE * sizeof(TCHAR));
  1519.                     }
  1520.  
  1521.                     if (plgncred->ulFieldMask & LGNCRED_REMEMBER)
  1522.                     {
  1523.                         plgncred->fRemember = 
  1524.                             IsDlgButtonChecked(hDlg, IDC_REMEMBER);
  1525.                     }
  1526.  
  1527.                     EndDialog(hDlg, 0);
  1528.                     fHandled = TRUE;
  1529.                     break;
  1530.                 }
  1531.             case IDCANCEL:
  1532.                 {
  1533.                     plgncred->fCancel = TRUE;
  1534.                     EndDialog(hDlg, 0);
  1535.                     fHandled = TRUE;
  1536.                     break;
  1537.                 }
  1538.             default:
  1539.                 {
  1540.                     fHandled = FALSE;
  1541.                     break;
  1542.                 }
  1543.             }
  1544.         }
  1545.  
  1546.     default:
  1547.         {
  1548.             fHandled = FALSE;
  1549.             break;
  1550.         }
  1551.     }
  1552.  
  1553.     return fHandled;
  1554. }
  1555.  
  1556. /*
  1557.  *  HrGetProfileCred
  1558.  *
  1559.  *  Purpose:
  1560.  *      Obtain password programmatically by reading the
  1561.  *      appropriate property out of the profile. If the 
  1562.  *      property isn't there, don't fail the call. Return 
  1563.  *      a NULL for the password, and clear the *pfFound flag.
  1564.  *
  1565.  *  Parameters:
  1566.  *      plmr    Pointer to the MAPI linked memory routines
  1567.  *      psup    Pointer to the MAPI support object (from which
  1568.  *              we can get the current profile section).
  1569.  *      szPass  Address of buffer in which to place the Logon
  1570.  *              Account Password.
  1571.  *      pfFound TRUE if the password was found in the profile.
  1572.  *              FALSE if the password wasn't in the profile.
  1573.  *
  1574.  *  Returns:
  1575.  *      HRESULT
  1576.  *
  1577.  *  Errors:
  1578.  *      None.
  1579.  */
  1580. static HRESULT
  1581. HrGetProfileCred(PLMR plmr, LPPROFSECT pps, LPTSTR szPass, BOOL *pfFound)
  1582. {
  1583.     HRESULT hr;
  1584.     LPSPropValue pval = NULL;
  1585.  
  1586.     AssertSz(szPass, "Bad szPass");
  1587.     AssertSz(pps, "No profile section");
  1588.  
  1589.     hr = HrGetOneProp((LPMAPIPROP) pps, PR_SMS_PASSWORD, &pval);
  1590.  
  1591.     if (hr != hrSuccess)
  1592.     {
  1593.         *pfFound = FALSE;
  1594.         szPass[0] = (TCHAR) 0;
  1595.         hr = hrSuccess;
  1596.     }
  1597.     else
  1598.     {
  1599.         lstrcpy(szPass, pval[0].Value.LPSZ);
  1600.         *pfFound = TRUE;
  1601.     }
  1602.  
  1603.     LMFree(plmr, pval);
  1604.  
  1605.     DebugTraceResult(HrGetProfileCred, hr);
  1606.     return hr;
  1607. }
  1608.  
  1609. /*
  1610.  *  HrSetProfileCred
  1611.  *
  1612.  *  Purpose:
  1613.  *      Save credential information in the profile for future
  1614.  *      programmatic opening.
  1615.  *
  1616.  *  Parameters:
  1617.  *      pps         Pointer to the profile section.
  1618.  *      szPass      Logon Account Password.
  1619.  *      szPath      Path name of root of the store
  1620.  *      fRemember   TRUE means save the password in the store.
  1621.  *      cbEntryID   Number of bytes in lpEntryID
  1622.  *      lpEntryID   Pointer to Wrapped Store EntryID
  1623.  *      puidRK      pointer to PR_RECORD_KEY data (always &pims->uidResource)
  1624.  *
  1625.  *  Returns:
  1626.  *      HRESULT
  1627.  *
  1628.  *  Side effects:
  1629.  *      None.
  1630.  *
  1631.  *  Errors:
  1632.  *      None.
  1633.  */
  1634. static HRESULT HrSetProfileCred(LPPROFSECT pps, LPTSTR szPass, LPTSTR szPath,
  1635.     BOOL fRemember, ULONG cbEntryID, LPBYTE lpEntryID, LPMAPIUID puidRK)
  1636. {
  1637.     HRESULT hr = hrSuccess;
  1638.     LPTSTR szDisplayName = NULL;
  1639.     SPropValue rgProps[7];
  1640.     ULONG cValues;
  1641.  
  1642.     AssertSz(pps, "Bad profile section");
  1643.     AssertSz(szPass, "Bad szPass");
  1644.     AssertSz(lpEntryID, "Bad lpEntryID");
  1645.  
  1646.     /* fill in the Display Name */
  1647.     hr = HrAlloc((lstrlen(szDisplayPrefix) + lstrlen(szPath) + 1)
  1648.             * sizeof(TCHAR), &szDisplayName);
  1649.     if (hr != hrSuccess)
  1650.         goto hr_err;
  1651.  
  1652.     lstrcpy(szDisplayName, szDisplayPrefix);
  1653.     lstrcat(szDisplayName, szPath);
  1654.  
  1655.     rgProps[0].ulPropTag = PR_PROVIDER_DISPLAY;
  1656.     rgProps[0].Value.LPSZ = szProviderDisplayName;
  1657.  
  1658.     rgProps[1].ulPropTag = PR_DISPLAY_NAME;
  1659.     rgProps[1].Value.LPSZ = szDisplayName;
  1660.  
  1661.     rgProps[2].ulPropTag = PR_ENTRYID;
  1662.     rgProps[2].Value.bin.cb = cbEntryID;
  1663.     rgProps[2].Value.bin.lpb = lpEntryID;
  1664.  
  1665.     rgProps[3].ulPropTag = PR_SMS_PATH;
  1666.     rgProps[3].Value.LPSZ = szPath;
  1667.  
  1668.     rgProps[4].ulPropTag = PR_MDB_PROVIDER;
  1669.     rgProps[4].Value.bin.cb = sizeof(MAPIUID);
  1670.     rgProps[4].Value.bin.lpb = (LPBYTE) &uidProvider;
  1671.  
  1672.     rgProps[5].ulPropTag = PR_RECORD_KEY;
  1673.     rgProps[5].Value.bin.cb = sizeof(MAPIUID);
  1674.     rgProps[5].Value.bin.lpb = (LPBYTE) puidRK;
  1675.  
  1676.     cValues = 6;
  1677.  
  1678.     if (fRemember)
  1679.     {
  1680.         rgProps[6].ulPropTag = PR_SMS_PASSWORD;
  1681.         rgProps[6].Value.LPSZ = szPass;
  1682.         ++cValues;
  1683.     }
  1684.     else
  1685.     {
  1686.         /* If the user doesn't want to remember the password, then we */
  1687.         /* should try to remove it from the profile section. */
  1688.  
  1689.         (void) pps->lpVtbl->DeleteProps(pps, &sptaPass, NULL);
  1690.     }
  1691.  
  1692.     hr = pps->lpVtbl->SetProps(pps, cValues, rgProps, NULL);
  1693.     if (hr != hrSuccess)
  1694.         goto hr_err;
  1695.  
  1696. hr_err:
  1697.     FreeNull(szDisplayName);
  1698.  
  1699.     DebugTraceResult(HrSetProfileCred, hr);
  1700.     return hr;
  1701. }
  1702.  
  1703. /*
  1704.  *  HrConfirmCred
  1705.  *
  1706.  *  Purpose:
  1707.  *      Check user's store opening credentials against the account
  1708.  *      information in the store.
  1709.  *
  1710.  *  Arguments:
  1711.  *      szPath      Path to "root" directory of store.
  1712.  *      szPass      Logon Account Password.
  1713.  *      psup        Pointer to a MAPI Support object (passed to IMsgOnIStg).
  1714.  *      plmr        Pointer to the linked mem alloc routines.
  1715.  *
  1716.  *  Returns:
  1717.  *      HRESULT
  1718.  *
  1719.  *  Side effects:
  1720.  *      None.
  1721.  */
  1722. static HRESULT HrConfirmCred(LPTSTR szPath, LPTSTR szPass, LPMAPISUP psup,
  1723.     PLMR plmr)
  1724. {
  1725.     HRESULT hr;
  1726.     LPMESSAGE lpmsg = NULL;
  1727.     LPSPropValue pval = NULL;
  1728.     LPTSTR szT = NULL;
  1729.  
  1730.     AssertSz(szPath, "Bad szPath");
  1731.     AssertSz(szPass, "Bad szPass");
  1732.  
  1733.     /* Open the message store props file as an IMessage instance. */
  1734.  
  1735.     hr = HrAppendPath(szPath, szPropFileName, &szT);
  1736.     if (hr != hrSuccess)
  1737.         goto hr_err;
  1738.  
  1739.     hr = HrOpenIMSPropsFileRetry(NULL, szT, plmr, psup, FALSE, &lpmsg);
  1740.     if (hr != hrSuccess)
  1741.         goto hr_err;
  1742.  
  1743.     /* Get password from the message store props file   */
  1744.     /* and compare against the function parameter.      */
  1745.  
  1746.     hr = HrGetOneProp((LPMAPIPROP) lpmsg, PR_SMS_PASSWORD, &pval);
  1747.  
  1748.     if (hr != hrSuccess)
  1749.         goto hr_err;
  1750.  
  1751.     if (lstrcmp(szPass, pval[0].Value.LPSZ))
  1752.         hr = ResultFromScode(MAPI_E_LOGON_FAILED);
  1753.  
  1754. hr_err:
  1755.     FreeNull(szT);
  1756.     UlRelease(lpmsg);
  1757.     LMFree(plmr, pval);
  1758.  
  1759.     DebugTraceResult(HrConfirmCred, hr);
  1760.     return hr;
  1761. }
  1762.  
  1763. /*
  1764.  * HrFilePathExists
  1765.  *
  1766.  * Purpose:
  1767.  *      Helper function for HrCheckStoreIntegrity. This function creates a
  1768.  *      full pathname to the file given, and attempts to find it on disk.
  1769.  *
  1770.  * Returns:
  1771.  *      HRESULT
  1772.  *
  1773.  *      If the file exists, and no other errors occur, the function returns
  1774.  *      success. If the file doesn't exist, the function returns
  1775.  *      MAPI_E_CORRUPT_STORE. If the file exists, but the find can't be closed,
  1776.  *      the function returns MAPI_E_LOGON_FAILED.
  1777.  */
  1778. static HRESULT HrFilePathExists(LPTSTR szStorePath, LPTSTR szFileName)
  1779. {
  1780.     LPTSTR szT = NULL;
  1781.     WIN32_FIND_DATA filedata;
  1782.     HANDLE hFindFile;
  1783.     HRESULT hr;
  1784.  
  1785.     hr = HrAppendPath(szStorePath, szFileName, &szT);
  1786.     if (hr != hrSuccess)
  1787.         goto exit;
  1788.  
  1789.     hFindFile = FindFirstFile(szT, &filedata);
  1790.     if (hFindFile == INVALID_HANDLE_VALUE)
  1791.     {
  1792.         hr = ResultFromScode(MAPI_E_CORRUPT_STORE);
  1793.         goto exit;
  1794.     }
  1795.  
  1796.     if (!FindClose(hFindFile))
  1797.         hr = ResultFromScode(MAPI_E_LOGON_FAILED);
  1798.  
  1799. exit:
  1800.     FreeNull(szT);
  1801.     return hr;
  1802. }
  1803.  
  1804. /*
  1805.  *  HrCheckStoreIntegrity
  1806.  *
  1807.  *  Purpose:
  1808.  *      Quick check to see that all the necessary store components
  1809.  *      exist in the proper place (store root).  The check of file
  1810.  *      attributes assumes that OLE created its docfiles with
  1811.  *      normal file attributes.
  1812.  *
  1813.  *  Arguments:
  1814.  *      szPath      Path to "root" directory of store.
  1815.  *
  1816.  *  Returns:
  1817.  *      HRESULT
  1818.  *
  1819.  *  Side effects:
  1820.  *      None.
  1821.  *
  1822.  *  Errors:
  1823.  *      MAPI_E_CORRUPT_STORE    A necessary store component was
  1824.  *                              missing.
  1825.  */
  1826. static HRESULT HrCheckStoreIntegrity(LPTSTR szStorePath)
  1827. {
  1828.     HRESULT hr;
  1829.  
  1830.     AssertSz(!IsBadStringPtr(szStorePath, (UINT) -1), "Bad szStorePath");
  1831.  
  1832.     /* Check for the message store properties file */
  1833.  
  1834.     hr = HrFilePathExists(szStorePath, szPropFileName);
  1835.     if (hr != hrSuccess)
  1836.         goto hr_err;
  1837.  
  1838.     /* Check for the root folder properties file */
  1839.  
  1840.     hr = HrFilePathExists(szStorePath, szPropertyFileName);
  1841.     if (hr != hrSuccess)
  1842.         goto hr_err;
  1843.  
  1844.     /* Check for the receive folder settings storage file */
  1845.  
  1846.     hr = HrFilePathExists(szStorePath, szFolderFileName);
  1847.  
  1848. hr_err:
  1849.     DebugTraceResult(HrCheckStoreIntegrity, hr);
  1850.     return hr;
  1851. }
  1852.  
  1853. /*
  1854.  *  FIsValidPath
  1855.  *
  1856.  *  Purpose:
  1857.  *      Returns TRUE if the path in szPath is a valid path to
  1858.  *      to an existing directory if fCreate is FALSE. Or the
  1859.  *      specified directory can be created if fCreate is TRUE.
  1860.  *
  1861.  *  Arguments:
  1862.  *      szPath      Path to "root" directory of store.
  1863.  *      fCreate         TRUE if directory is to be created.
  1864.  *
  1865.  *  Returns:
  1866.  *      BOOL
  1867.  *
  1868.  *  Side effects:
  1869.  *      None.
  1870.  *
  1871.  */
  1872. static BOOL FIsValidPath(LPTSTR szPath, BOOL fCreate)
  1873. {
  1874.     LPTSTR szLastSlash = NULL;  /* pointer to last slash in szPath */
  1875.     DWORD dwAttributes;
  1876.  
  1877.     if (*szPath == '\0')
  1878.         return FALSE;
  1879.  
  1880.     /* if creating a root folder, the folder to check is the parent */
  1881.     /* of the one in szPath */
  1882.     if (fCreate)
  1883.     {
  1884.         /* must not already exist */
  1885.         if (GetFileAttributes(szPath) != -1)
  1886.             return FALSE;
  1887.  
  1888.         /* parent directory must exist */
  1889.         szLastSlash = SzFindLastCh(szPath, '\\');
  1890.         if (szLastSlash && szLastSlash != szPath &&
  1891.             *(szLastSlash - 1) != ':')
  1892.         {
  1893.             *szLastSlash = '\0';
  1894.         }
  1895.         else
  1896.         {
  1897.             /* creating a directory at the root level */
  1898.             return TRUE;
  1899.         }
  1900.     }
  1901.  
  1902.     /* get the attributes of the directory that must exist */
  1903.     dwAttributes = GetFileAttributes(szPath);
  1904.  
  1905.     /* restore szPath */
  1906.     if (szLastSlash)
  1907.         *szLastSlash = '\\';
  1908.  
  1909.     return ((dwAttributes != -1) && (dwAttributes & FILE_ATTRIBUTE_DIRECTORY)) ?
  1910.         TRUE : FALSE;
  1911. }
  1912.  
  1913. /*
  1914.  * HrGetSpoolSecurity
  1915.  *
  1916.  * Purpose
  1917.  *          return the spooler security information for use in SpoolerLogon
  1918.  *
  1919.  * Parameters
  1920.  *  szPath              path to root of store
  1921.  *  szPass              store account password
  1922.  *  plmr                pointer to the MAPI linked allocation routines
  1923.  *  lpcbSpoolSecurity   byte count of the security information
  1924.  *  lppbSpoolSecurity   security information
  1925.  */
  1926. static HRESULT HrGetSpoolSecurity(LPTSTR szPath, LPTSTR szPass,
  1927.     PLMR plmr, ULONG * lpcbSpoolSecurity, LPBYTE * lppbSpoolSecurity)
  1928. {
  1929.     ULONG cbPath = Cbtszsize(szPath);
  1930.     ULONG cbPass = Cbtszsize(szPass);
  1931.     SCODE sc = S_OK;
  1932.  
  1933.     /* allocate memory for the security information */
  1934.     *lpcbSpoolSecurity = cbPass + cbPath;
  1935.     sc = LMAlloc(plmr, *lpcbSpoolSecurity, lppbSpoolSecurity);
  1936.     if (sc)
  1937.     {
  1938.         *lpcbSpoolSecurity = 0;
  1939.         DebugTraceSc(HrGetSpoolSecurity, sc);
  1940.         return ResultFromScode(sc);
  1941.     }
  1942.  
  1943.     /* fill in the  spooler security information */
  1944.     if (cbPath)
  1945.         memcpy(*lppbSpoolSecurity, szPath, (UINT) cbPath);
  1946.     if (cbPass)
  1947.         memcpy(*lppbSpoolSecurity + (UINT) cbPath, szPass, (UINT) cbPass);
  1948.  
  1949.     return hrSuccess;
  1950. }
  1951.  
  1952. /*
  1953.  * DecodeSpoolSecurity
  1954.  *
  1955.  * Purpose
  1956.  *          return the spooler security information for use in SpoolerLogon
  1957.  *
  1958.  * Parameters
  1959.  *  cbSpoolSecurity     byte count of the security information
  1960.  *  pbSpoolSecurity     security information
  1961.  *  szPath              pointer to variable for path to root of store
  1962.  *  szPass              poitner to varaible for store account password
  1963.  */
  1964. static void DecodeSpoolSecurity(ULONG cbSpoolSecurity, LPBYTE pbSpoolSecurity,
  1965.     LPTSTR szPath, LPTSTR szPass)
  1966. {
  1967.     ULONG cbPath = 0;
  1968.  
  1969.     lstrcpy(szPath, pbSpoolSecurity);
  1970.     cbPath = Cbtszsize(szPath);
  1971.  
  1972.     lstrcpy(szPass, pbSpoolSecurity + cbPath);
  1973.  
  1974.     return;
  1975. }
  1976.  
  1977. /*
  1978.  * HrCheckAndOpenStore
  1979.  *
  1980.  * Purpose
  1981.  *          check the integrity of store specified in szPath and return
  1982.  *          an open store if it's OK
  1983.  *
  1984.  * Parameters
  1985.  *  pmsp                pointer to our MSProvider object
  1986.  *  psup                mapi support object
  1987.  *  fModify             TRUE if write access desired
  1988.  *  pps                 pointer to our profile section
  1989.  *  szPath              path name to root of the store
  1990.  *  szPass              password to store
  1991.  *  fIsSpooler          TRUE if this is a spooler logon
  1992.  *  ppmsl               pointer to variable to hold MSLogon object
  1993.  *  ppims               pointer to variable to hold the opened store object
  1994.  */
  1995. static HRESULT HrCheckAndOpenStore(PMSP pmsp, LPMAPISUP psup, BOOL fModify,
  1996.     LPPROFSECT pps, LPTSTR szPath, LPTSTR szPass, BOOL fIsSpooler,
  1997.     PMSL *ppmsl, PIMS *ppims)
  1998. {
  1999.     HRESULT hr;
  2000.     PRFS prfs = NULL;
  2001.     PMSL pmsl = NULL;
  2002.     PIMS pims = NULL;
  2003.     SCODE sc;
  2004.  
  2005.     *ppmsl = NULL;
  2006.  
  2007.     hr = HrConfirmCred(szPath, szPass, psup, &pmsp->lmr);
  2008.     if (hr != hrSuccess)
  2009.         goto exit;
  2010.  
  2011.     hr = HrCheckStoreIntegrity(szPath);
  2012.     if (hr != hrSuccess)
  2013.         goto exit;
  2014.  
  2015.     hr = OpenRFS(szPath, szFolderFileName, 0, &prfs);
  2016.     if (hr != hrSuccess)
  2017.         goto exit;
  2018.  
  2019.     /* Create MSLogon object */
  2020.  
  2021.     sc = ScCreateMSL(pmsp, &pmsl);
  2022.     if (sc != S_OK)
  2023.     {
  2024.         hr = ResultFromScode(sc);
  2025.         goto exit;
  2026.     }
  2027.  
  2028.     /* Create Message Store object */
  2029.  
  2030.     hr = HrNewIMS(szPath, szPropFileName, pmsp, pmsl, prfs, pps, psup,
  2031.             FALSE, &pims);
  2032.     if (hr != hrSuccess)
  2033.         goto exit;
  2034.  
  2035.     if (fIsSpooler)
  2036.         OBJ_SetFlag(pims, MSF_SPOOLER);
  2037.  
  2038.     if (fModify)
  2039.         OBJ_SetFlag(pims, OBJF_MODIFY);
  2040.  
  2041.     pmsl->pims = pims;
  2042.  
  2043.     *ppims = pims;
  2044.     *ppmsl = pmsl;
  2045.  
  2046. exit:
  2047.     if (hr != hrSuccess)
  2048.     {
  2049.         /* If we have an RFS but failed to create the MS, close RFS manually. */
  2050.         if (prfs)
  2051.             NFSideAssertSz(CloseRFS(prfs) == hrSuccess, "RFS not closed");
  2052.  
  2053.         UlRelease(pmsl);
  2054.         pmsl = NULL;
  2055.     }
  2056.  
  2057.     DebugTraceResult(HrCheckAndOpenStore, hr);
  2058.     return hr;
  2059. }
  2060.  
  2061. /*
  2062.  * ScCreateMSL
  2063.  *
  2064.  * Purpose
  2065.  *          returns a new logon object
  2066.  *
  2067.  * Parameters
  2068.  *      pmsp    A pointer to the MS Provider object.
  2069.  *      ppmsl   Location in which to return the address of the
  2070.  *              newly allocated MSL object.
  2071.  *
  2072.  *  Returns:
  2073.  *      SCODE
  2074.  *
  2075.  *  Side effects:
  2076.  *      None.
  2077.  *
  2078.  *  Errors:
  2079.  *      MAPI_E_NOT_ENOUGH_MEMORY    Could not allocate space for
  2080.  *                                  the MSL object.
  2081.  */
  2082. static SCODE ScCreateMSL(PMSP pmsp, PMSL *ppmsl)
  2083. {
  2084.     PMSL pmsl;
  2085.     SCODE sc;
  2086.  
  2087.     sc = LMAllocZ(&pmsp->lmr, sizeof(MSL), &pmsl);
  2088.  
  2089.     if (sc == S_OK)
  2090.     {
  2091.         OBJ_Initialize(pmsl, &vtblMSL, OT_MSLOGON, NULL, &pmsl->cs);
  2092.  
  2093.         InitializeCriticalSection(&pmsl->cs);
  2094.  
  2095.         pmsl->lmr = pmsp->lmr;
  2096.  
  2097.         *ppmsl = pmsl;
  2098.     }
  2099.  
  2100.     DebugTraceSc(ScCreateMSL, sc);
  2101.     return sc;
  2102. }
  2103.  
  2104. /*
  2105.  *  FFindPropInPSPB
  2106.  *
  2107.  *  Purpose:
  2108.  *      Look for the given property in the PSPB structure. Search the
  2109.  *      client prop array before the profile prop array.
  2110.  *
  2111.  *  Arguments:
  2112.  *      pspb    pointer to the service parameter block
  2113.  *      ulPT    the property tag to look for
  2114.  *      ppval   location to place the pointer to the pval
  2115.  *
  2116.  *  Returns:
  2117.  */
  2118. static BOOL FFindPropInPSPB(PSERVICEPBLK pspb, ULONG ulPT, LPSPropValue *ppval)
  2119. {
  2120.     LPSPropValue pval;
  2121.  
  2122.     /* First, look in the client's array. If it's not there, look for */
  2123.     /* it in the profile array. */
  2124.  
  2125.     pval = PpropFindProp(pspb->pvalsClient, pspb->cvalsClient, ulPT);
  2126.  
  2127.     if (!pval)
  2128.         pval = PpropFindProp(pspb->pvalsProf, pspb->cvalsProf, ulPT);
  2129.  
  2130.     if (pval)
  2131.     {
  2132.         *ppval = pval;
  2133.         return TRUE;
  2134.     }
  2135.  
  2136.     return FALSE;
  2137. }
  2138.  
  2139. /*
  2140.  *  ScGetFullFileName
  2141.  *
  2142.  *  Purpose:
  2143.  *      Look for the file path and name in the property list given.  If
  2144.  *      found, convert it to a full (non-relative) path name, and check for
  2145.  *      the existence of the directory. Note that we return values even 
  2146.  *      when an error occurs.
  2147.  *
  2148.  *  Arguments:
  2149.  *
  2150.  *  Returns:
  2151.  */
  2152. static SCODE ScGetFullFileName(PSERVICEPBLK pspb, BOOL *pfCreate,
  2153.     LPSTR pszPath)
  2154. {
  2155.     SCODE           sc  = S_OK;
  2156.     LPSTR           pszFileTitle;
  2157.     LPSPropValue    pval;
  2158.     BOOL            fCreate = FALSE;
  2159.  
  2160.     *pszPath = '\0';
  2161.     *pfCreate = FALSE;
  2162.  
  2163.     /* get the path to the file */
  2164.     if (    FFindPropInPSPB(pspb, PR_SMS_PATH, &pval)
  2165.         &&  GetFullPathName(pval->Value.lpszA, MAX_PATH, pszPath,
  2166.                 &pszFileTitle))
  2167.     {
  2168.         DWORD   dwFA;
  2169.         LPSPropValue pvalT;
  2170.  
  2171.         if (FFindPropInPSPB(pspb, PR_SMS_CREATE, &pvalT))
  2172.             *pfCreate = pvalT->Value.b;
  2173.  
  2174.         Assert (*(pszFileTitle - 1) == '\\');
  2175.  
  2176.         dwFA = GetFileAttributes(pszPath);
  2177.  
  2178.         /* If the file isn't there, and we aren't creating, then error. */
  2179.         /* If the file is there, and we are creating, then error. */
  2180.  
  2181.         if (dwFA == 0xFFFFFFFF && *pfCreate == FALSE)
  2182.             sc = MAPI_E_NOT_FOUND;
  2183.         else if (dwFA != 0xFFFFFFFF && *pfCreate == TRUE)
  2184.             sc = MAPI_E_NO_ACCESS;
  2185.     }
  2186.     else
  2187.     {
  2188.         *pszPath = '\0';
  2189.         sc = MAPI_E_NOT_FOUND;
  2190.     }
  2191.  
  2192.     DebugTraceSc(ScGetFullFileName, sc);
  2193.     return sc;
  2194. }
  2195.  
  2196.  
  2197.