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