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

  1. /*
  2.  *  M S P M S . C
  3.  *
  4.  *  Code for the MAPI Sample Store Provider implementation of the
  5.  *  IMsgStore object.
  6.  *
  7.  *  Copyright 1992-1995 Microsoft Corporation.  All Rights Reserved.
  8.  */
  9.  
  10. #include "msp.h"
  11. #include <stdarg.h>
  12.  
  13. #define MS_ValidateParameters(pobj, eMethod)        \
  14.         OBJ_ValidateParameters(pobj, eMethod, sizeof(IMS), &vtblIMS)
  15.  
  16. static HRESULT HrGetSequenceNum(PEID peid, ULONG *pulSequenceNum);
  17. static HRESULT HrGetSMSStandardNotifKey(PIMS pims, PEID peid,
  18.     LPNOTIFKEY * lppKey);
  19.  
  20. /* Dispatch table for IMsgStore objects */
  21. IMS_Vtbl vtblIMS =
  22. {
  23.     (IMS_QueryInterface_METHOD *)   OBJ_QueryInterface,
  24.     (IMS_AddRef_METHOD *)           OBJ_AddRef,
  25.     (IMS_Release_METHOD *)          OBJ_Release,
  26.     IMS_GetLastError,
  27.     IMS_SaveChanges,
  28.     IMS_GetProps,
  29.     IMS_GetPropList,
  30.     IMS_OpenProperty,
  31.     IMS_SetProps,
  32.     IMS_DeleteProps,
  33.     IMS_CopyTo,
  34.     IMS_CopyProps,
  35.     IMS_GetNamesFromIDs,
  36.     IMS_GetIDsFromNames,
  37.  
  38.     IMS_Advise,
  39.     IMS_Unadvise,
  40.     IMS_CompareEntryIDs,
  41.     IMS_OpenEntry,
  42.     IMS_SetReceiveFolder,
  43.     IMS_GetReceiveFolder,
  44.     IMS_GetReceiveFolderTable,
  45.     IMS_StoreLogoff,
  46.     IMS_AbortSubmit,
  47.  
  48.     IMS_GetOutgoingQueue,
  49.     IMS_SetLockState,
  50.     IMS_FinishedMsg,
  51.     IMS_NotifyNewMail,
  52. };
  53.  
  54. /* definitions for outgoing queues */
  55. CALLERRELEASE OutgoingViewRelease;
  56.  
  57. /*
  58.  *  Object methods
  59.  */
  60.  
  61. /*
  62.  *  IMS_GetLastError [also called by IMSLogon, IMAPIFolder, IMessage, and IAttach]
  63.  *
  64.  *  Purpose:
  65.  *      Returns a localized text error message associated with the
  66.  *      last error which occurred on a specific object (in
  67.  *      actuality, the SCODE used is associated with the HRESULT
  68.  *      passed in, and it is not checked that this HRESULT matches
  69.  *      that of the last error on this object -- providing a
  70.  *      different HRESULT will very likely return an inconsistent
  71.  *      error message, though).
  72.  *
  73.  *  Arguments:
  74.  *      pobj            Pointer to the object.
  75.  *      hError          HRESULT containing the error code returned
  76.  *                      by the last failed call on this object.
  77.  *      ulFlags         MAPI_UNICODE, string8 is default
  78.  *      pulLLErr        location to place the low level error code
  79.  *                      (may be NULL)
  80.  *      pszMessage      Location in which to return an address to
  81.  *                      an allocated buffer containing the
  82.  *                      localized text error message.
  83.  *      pszComponent    Location in which to return an address to
  84.  *                      an allocated buffer containing the
  85.  *                      name of the component producing the error.
  86.  *      lpulContext     Location in which to return a context number
  87.  *                      for finding help within the Component's help file.
  88.  *
  89.  *  Returns:
  90.  *      HRESULT
  91.  *
  92.  *  Side effects:
  93.  *      None.
  94.  *
  95.  *  Errors:
  96.  *      MAPI_E_NOT_ENOUGH_MEMORY    Unable to allocate memory for
  97.  *                                  the return parameter.
  98.  *      MAPI_E_INVALID_PARAMETER    hError contains an unknown
  99.  *                                  SCODE.
  100.  */
  101. STDMETHODIMP IMS_GetLastError(PIMS pobj, HRESULT hError, ULONG ulFlags,
  102.     LPMAPIERROR * lppMapiError)
  103. {
  104.     HRESULT hr = hrSuccess;
  105.     SCODE   sc;
  106.     PIMS pims;
  107.     LPTSTR pszMessage   = NULL;
  108.     
  109.     #ifdef VALIDATE
  110.     if (IsBadWritePtr(pobj, sizeof(OBJ))
  111.         || (pobj->lpVtbl != (IMS_Vtbl *) &vtblIMS
  112.             && pobj->lpVtbl != (IMS_Vtbl *) &vtblMSL
  113.             && pobj->lpVtbl != (IMS_Vtbl *) &vtblIFLD
  114.             && pobj->lpVtbl != (IMS_Vtbl *) &vtblIMSG
  115.             && pobj->lpVtbl != (IMS_Vtbl *) &vtblIATCH))
  116.         return ResultFromScode(MAPI_E_INVALID_PARAMETER);
  117.         
  118.     ValidateParameters(IMAPIProp_GetLastError, &pobj);                          \
  119.  
  120.     if (ulFlags & MAPI_UNICODE)
  121.         return ResultFromScode(MAPI_E_BAD_CHARWIDTH);
  122.     #endif
  123.  
  124.     OBJ_EnterCriticalSection((POBJ) pobj);
  125.  
  126.     pims = pobj->pims;
  127.  
  128.     /* //$ Add param checking and correctly return Component & Context */
  129.     *lppMapiError = NULL;
  130.     
  131.     sc = LMAlloc( &pims->lmr, sizeof( MAPIERROR ), lppMapiError );
  132.     if ( FAILED( sc ) )
  133.     {
  134.         hr = ResultFromScode( sc );
  135.         goto ret;
  136.     }
  137.     
  138.     memset( *lppMapiError, 0, sizeof( MAPIERROR ) );
  139.     
  140.     (*lppMapiError)->ulVersion = MAPI_ERROR_VERSION;    
  141.  
  142.     hr = MapScodeSz(GetScode(hError), pims, &pszMessage);
  143.     if ( HR_FAILED( hr ) )
  144.         goto ret;
  145.     
  146.     sc = LMAllocMore( &pims->lmr, Cbtszsize( pszMessage ), *lppMapiError,
  147.             &(*lppMapiError)->lpszError );
  148.     
  149.     if ( FAILED( sc ) )
  150.     {
  151.         hr = ResultFromScode( sc );
  152.         goto ret;
  153.     }
  154.     
  155.     lstrcpy( (*lppMapiError)->lpszError, pszMessage );
  156.  
  157. ret:
  158.     
  159.     if ( hr )   
  160.     {
  161.         LMFree( &pims->lmr, *lppMapiError );
  162.         *lppMapiError = NULL;
  163.     }
  164.     
  165.     LMFree( &pims->lmr, pszMessage );
  166.     
  167.     OBJ_LeaveCriticalSection(pobj);
  168.  
  169.     DebugTraceResult(IMS_GetLastError, hr);
  170.     return HrCheckHr(hr, IUnknown_GetLastError);
  171. }
  172.  
  173. /*
  174.  *  IMS_SaveChanges [Also used by IMAPIFolder]
  175.  *
  176.  *  Purpose:
  177.  *      Saves changes made to the message store object properties
  178.  *      (does not propagate to sub-objects).  Because changes to
  179.  *      message store object properties show up immediately,
  180.  *      however, this call does nothing (but returns success).
  181.  *
  182.  *  Arguments:
  183.  *      pims        Pointer to the object.
  184.  *      ulFlags     Flags.  The following are defined:
  185.  *                  KEEP_OPEN_READONLY  Do not invalidate the
  186.  *                                      object, make it read-only.
  187.  *                  KEEP_OPEN_READWRITE Don't invalidate the
  188.  *                                      object, keep it open
  189.  *                                      read/write.
  190.  *                  FORCE_SAVE          Overwrite any changes made by
  191.  *                                      others since store was opened
  192.  *
  193.  *  Returns:
  194.  *      HRESULT
  195.  *
  196.  *  Side effects:
  197.  *      None.
  198.  *
  199.  *  Errors:
  200.  *      None.
  201.  */
  202. STDMETHODIMP IMS_SaveChanges(PIMS pims, ULONG ulFlags)
  203. {
  204.     #ifdef VALIDATE
  205.     if (    IsBadWritePtr(pims, sizeof(OBJ))
  206.         ||  (   pims->lpVtbl != (IMS_Vtbl *) &vtblIMS
  207.             &&  pims->lpVtbl != (IMS_Vtbl *) &vtblIFLD))
  208.         return ResultFromScode(MAPI_E_INVALID_PARAMETER);
  209.  
  210.     ValidateParameters(IMAPIProp_SaveChanges, &pims);
  211.     #endif
  212.  
  213.     return hrSuccess;
  214. }
  215.  
  216. /*
  217.  *  IMS_GetProps
  218.  *
  219.  *  Purpose:
  220.  *      Returns to the caller the value(s) of one or more
  221.  *      properties existent on an IMS object.  The order of the
  222.  *      properties in the returned ppval structure exactly
  223.  *      matches the order in which the properties were requested in
  224.  *      ptaga.  The caller must free the returned
  225.  *      structure by calling MAPIFreeBuffer(*ppval), but
  226.  *      only if the function returns zero or the error
  227.  *      MAPI_W_ERRORS_RETURNED.  Uses the IMessage on IStorage
  228.  *      property interface implementation.
  229.  *
  230.  *  Arguments:
  231.  *      pims            Pointer to the object.
  232.  *      ptaga           Pointer to a counted array of property tags
  233.  *                      ("names") that identify the values to be
  234.  *                      returned.
  235.  *      ulFlags         UNICODE / String8
  236.  *      pcval       Location in which to return the count of
  237.  *                      elements in *ppval.
  238.  *      ppval   Location in which to return an allocated
  239.  *                      array of property values (the caller frees
  240.  *                      by calling MAPIFreeBuffer).
  241.  *
  242.  *  Returns:
  243.  *      HRESULT
  244.  *
  245.  *  Side effects:
  246.  *      None.
  247.  *
  248.  *  Errors:
  249.  *      If the call succeeded overall but access to one or more
  250.  *      properties failed, the function returns the warning
  251.  *      MAPI_W_ERRORS_RETURNED.  The calling application should
  252.  *      then check the Property Tag of each of the returned
  253.  *      properties to determine which ones failed.  Those that fail
  254.  *      have their Property Type set to PT_ERROR and their value (a
  255.  *      ULONG) indicates which error occurred.
  256.  *
  257.  *      MAPI_E_NO_ACCESS    The caller does not have access
  258.  *                                  to the requested properties.
  259.  *      MAPI_W_ERRORS_RETURNED      See above.
  260.  *      MAPI_E_CALL_FAILED          The mechanism for making the
  261.  *                                  call to the service provider
  262.  *                                  failed.
  263.  */
  264. STDMETHODIMP IMS_GetProps(PIMS pims, LPSPropTagArray ptaga, ULONG ulFlags,
  265.     ULONG *pcval, LPSPropValue *ppval)
  266. {
  267.     HRESULT hr = hrSuccess;
  268.     LPMESSAGE lpmsg = NULL;
  269.  
  270.     MS_ValidateParameters(pims, IMAPIProp_GetProps);
  271.  
  272.     #ifdef VALIDATE
  273.     if (ulFlags & MAPI_UNICODE)
  274.         return ResultFromScode(MAPI_E_BAD_CHARWIDTH);
  275.     #endif
  276.         
  277.     IMS_EnterCriticalSection(pims);
  278.  
  279.     /* If input parameters are okay, make GetProps call on lpmsgProps. */
  280.  
  281.     *pcval = 0L;
  282.     *ppval = NULL;
  283.  
  284.     hr = HrOpenIMSPropsFileRetry(pims->pmsgsess, pims->szProps, &pims->lmr,
  285.         pims->psup, FALSE, &lpmsg);
  286.     if (hr != hrSuccess)
  287.         goto exit;
  288.  
  289.     hr = lpmsg->lpVtbl->GetProps(lpmsg, ptaga, ulFlags, pcval, ppval);
  290.  
  291.     /* Wrap the store entryids. Note that this function takes as an */
  292.     /* argument the HRESULT from the previous GetProps call. */
  293.     /* We aren't ignoring the error. */
  294.  
  295.     hr = HrWrap_GetProps(hr, pims, 0, NULL, pcval, ppval, TRUE,
  296.         (ptaga != NULL));
  297.  
  298. exit:
  299.     UlRelease(lpmsg);
  300.  
  301.     IMS_LeaveCriticalSection(pims);
  302.  
  303.     #ifdef DEBUG
  304.     if (GetScode(hr) != MAPI_W_ERRORS_RETURNED)
  305.         DebugTraceResult(IMS_GetProps, hr);
  306.     #endif
  307.  
  308.     return HrCheckHr(hr, IMAPIProp_GetProps);
  309. }
  310.  
  311. /*
  312.  *  IMS_GetPropList
  313.  *
  314.  *  Purpose:
  315.  *      Returns a list of all the properties currently accessible.
  316.  *      Uses the IMessage on IStorage property implementation.
  317.  *
  318.  *  Arguments:
  319.  *      pims        Pointer to the object.
  320.  *      ulFlags     UNICODE / String8
  321.  *      pptaga      Location in which to return a pointer
  322.  *                  to a counted array of property tags.
  323.  *
  324.  *  Returns:
  325.  *      HRESULT
  326.  *
  327.  *  Side effects:
  328.  *      None.
  329.  *
  330.  *  Errors:
  331.  *      MAPI_E_NO_ACCESS    The caller does not have access
  332.  *                          to the requested properties.
  333.  *      MAPI_E_CALL_FAILED  The mechanism for making the
  334.  *                          call to the service provider
  335.  *                          failed.
  336.  */
  337. STDMETHODIMP IMS_GetPropList(PIMS pims, ULONG ulFlags, LPSPropTagArray * pptaga)
  338. {
  339.     HRESULT hr = hrSuccess;
  340.     LPMESSAGE lpmsg = NULL;
  341.  
  342.     MS_ValidateParameters(pims, IMAPIProp_GetPropList);
  343.  
  344.     #ifdef VALIDATE
  345.     if (ulFlags & MAPI_UNICODE)
  346.         return ResultFromScode(MAPI_E_BAD_CHARWIDTH);
  347.     #endif
  348.         
  349.     IMS_EnterCriticalSection(pims);
  350.  
  351.     /* If input parameters are okay, make GetPropList call on lpmsgProps. */
  352.  
  353.     hr = HrOpenIMSPropsFileRetry(pims->pmsgsess, pims->szProps, &pims->lmr,
  354.         pims->psup, FALSE, &lpmsg);
  355.     if (hr != hrSuccess)
  356.         goto exit;
  357.  
  358.     hr = lpmsg->lpVtbl->GetPropList(lpmsg, ulFlags, pptaga);
  359.     /* if ( hr ) fall through to exit */
  360.  
  361. exit:
  362.     UlRelease(lpmsg);
  363.  
  364.     IMS_LeaveCriticalSection(pims);
  365.  
  366.     DebugTraceResult(IMS_GetPropList, hr);
  367.     return HrCheckHr(hr, IMAPIProp_GetPropList);
  368. }
  369.  
  370. /*
  371.  *  IMS_OpenProperty
  372.  *
  373.  *  Purpose:
  374.  *      Open a requested interface on a property for further
  375.  *      access.  Commonly used for stream access to a large binary
  376.  *      or text property.  This is the only way to access a
  377.  *      property of type PT_OBJECT, and may be used on other
  378.  *      properties depending on the implementation.  Uses the
  379.  *      IMessage on IStorage property implementation, but since the
  380.  *      transaction model for IMsgOnIStg does not match that for
  381.  *      IMsgStore, we fail this call.  (We could do a lot of work
  382.  *      to wrap the interface that IMsgOnIStg returns to us before
  383.  *      returning it to the client, but we don't.)
  384.  *
  385.  *  Arguments:
  386.  *      pims        Pointer to the object.
  387.  *      ulPropTag   Property tag for the desired property.  Only
  388.  *                  the ID bits of the tag are used; the type bits
  389.  *                  are ignored.
  390.  *      lpiid       Pointer to the GUID identifying which interface
  391.  *                  is desired.
  392.  *      lppUnk      Location in which to return a pointer to the
  393.  *                  newly created interface pointer.
  394.  *
  395.  *  Returns:
  396.  *      HRESULT
  397.  *
  398.  *  Errors:
  399.  *      MAPI_E_INVALID_PARAMETER
  400.  *      MAPI_E_NO_SUPPORT   The requested interface is not
  401.  *                              available on the given property.
  402.  */
  403. STDMETHODIMP IMS_OpenProperty(PIMS pims, ULONG ulPropTag, LPCIID lpiid,
  404.     ULONG ulInterfaceOptions, ULONG ulFlags, LPUNKNOWN * lppUnk)
  405. {
  406.     SCODE sc;
  407.  
  408.     MS_ValidateParameters(pims, IMAPIProp_OpenProperty);
  409.  
  410.     sc = MAPI_E_NO_SUPPORT;
  411.     
  412.     DebugTraceSc(IFLD_OpenProperty, sc);
  413.     return ResultFromScode(sc);
  414. }
  415.  
  416. /*
  417.  *  IMS_SetProps
  418.  *
  419.  *  Purpose:
  420.  *      Sets the value of one or more properties.  This call passes
  421.  *      a number of Property Value structures.  The Property Tag in
  422.  *      each indicates which property is having its values set and
  423.  *      the value indicates what should be stored.  The caller must
  424.  *      free the returned property problem structure by calling
  425.  *      MAPIFreeBuffer(*lppProblems), but only if the call
  426.  *      succeeded overall.  Uses the IMessage on IStorage property
  427.  *      implementation.
  428.  *
  429.  *  Arguments:
  430.  *      pims            Pointer to the object.
  431.  *      cValues         Number of values in lpPropArray.
  432.  *      lpPropArray     Pointer to a Property Value array.
  433.  *      lppProblems     Location in which to return a pointer to a
  434.  *                      counted array of property problem
  435.  *                      structures.
  436.  *
  437.  *  Returns:
  438.  *      HRESULT.  If the call succeeds overall, a zero is returned.
  439.  *      If there are problems with setting some or all of the
  440.  *      selected values, and a non-NULL is passed for lppProblems,
  441.  *      then a SPropProblemArray structure is returned with details
  442.  *      about each problem.  The value returned in lppProblems is
  443.  *      only valid if zero is returned in the HRESULT.  If an error
  444.  *      occurs on the call such that a non-zero value is returned
  445.  *      for the HRESULT then the contents of *lppProblems are
  446.  *      undefined.  In particular, do not use or free the structure
  447.  *      if an error occurs on the call.
  448.  *
  449.  *  Side effects:
  450.  *      None.
  451.  *
  452.  *  Errors:
  453.  *      MAPI_E_NO_ACCESS    The caller does not have access
  454.  *                                  to the requested properties.
  455.  *      MAPI_E_CALL_FAILED      A general problem affecting
  456.  *                                  access to all of the object's
  457.  *                                  properties occurred.
  458.  *      MAPI_E_CALL_FAILED          The mechanism for making the
  459.  *                                  call to the service provider
  460.  *                                  failed.
  461.  */
  462. STDMETHODIMP IMS_SetProps(PIMS pims, ULONG cValues, LPSPropValue lpPropArray,
  463.     LPSPropProblemArray * lppProblems)
  464. {
  465.     HRESULT hr = hrSuccess;
  466.     LPMESSAGE lpmsg = NULL;
  467.  
  468.     MS_ValidateParameters(pims, IMAPIProp_SetProps);
  469.  
  470.     IMS_EnterCriticalSection(pims);
  471.  
  472.     if (!OBJ_TestFlag(pims, OBJF_MODIFY))
  473.     {
  474.         hr = ResultFromScode(MAPI_E_NO_ACCESS);
  475.         goto exit;
  476.     }
  477.  
  478.     /* If input parameters are okay, make SetProps call on lpmsgProps. */
  479.  
  480.     hr = HrOpenIMSPropsFileRetry(pims->pmsgsess, pims->szProps, &pims->lmr,
  481.         pims->psup, TRUE, &lpmsg);
  482.     if (hr != hrSuccess)
  483.         goto exit;
  484.  
  485.     hr = lpmsg->lpVtbl->SetProps(lpmsg, cValues, lpPropArray, lppProblems);
  486.     if (hr != hrSuccess)
  487.         goto exit;
  488.  
  489.     hr = lpmsg->lpVtbl->SaveChanges(lpmsg, KEEP_OPEN_READWRITE);
  490.     /* if ( hr ), fall through to exit */
  491.  
  492. exit:
  493.     UlRelease(lpmsg);
  494.  
  495.     IMS_LeaveCriticalSection(pims);
  496.  
  497.     DebugTraceResult(IMS_SetProps, hr);
  498.     return HrCheckHr(hr, IMAPIProp_SetProps);
  499. }
  500.  
  501. /*
  502.  *  IMS_DeleteProps
  503.  *
  504.  *  Purpose:
  505.  *      Deletes the list of properties given in ptaga.
  506.  *      The caller must free the returned property problem
  507.  *      structure by calling MAPIFreeBuffer(*pprba), but only
  508.  *      if the call succeeded overall.  Uses the IMessage on
  509.  *      IStorage property implementation.
  510.  *
  511.  *  Arguments:
  512.  *      pims    Pointer to the object.
  513.  *      ptaga   Pointer to an array of Property Tags
  514.  *              identifying the properties to delete.
  515.  *      pprba   Location in which to return a pointer to a
  516.  *              counted array of property problem
  517.  *              structures.
  518.  *
  519.  *  Returns:
  520.  *      HRESULT.  If the call succeeds overall, a zero is returned.
  521.  *      If there are problems with deleting some or all of the
  522.  *      selected values, and a non-NULL is passed for pprba,
  523.  *      then a SPropProblemArray structure is returned with details
  524.  *      about each problem.  The value returned in pprba is
  525.  *      only valid if zero is returned in the HRESULT.  If an error
  526.  *      occurs on the call such that a non-zero value is returned
  527.  *      for the HRESULT then the contents of *pprba are
  528.  *      undefined.  In particular, do not use or free the structure
  529.  *      if an error occurs on the call.
  530.  *
  531.  *  Side effects:
  532.  *      None.
  533.  *
  534.  *  Errors:
  535.  *      MAPI_E_NO_ACCESS    The caller does not have access
  536.  *                                  to the requested properties.
  537.  *      MAPI_E_CALL_FAILED      A general problem affecting
  538.  *                                  access to all of the object's
  539.  *                                  properties occurred.
  540.  *      MAPI_E_CALL_FAILED          The mechanism for making the
  541.  *                                  call to the service provider
  542.  *                                  failed.
  543.  */
  544. STDMETHODIMP IMS_DeleteProps(PIMS pims, LPSPropTagArray ptaga,
  545.     LPSPropProblemArray *pprba)
  546. {
  547.     HRESULT hr = hrSuccess;
  548.     LPMESSAGE lpmsg = NULL;
  549.  
  550.     MS_ValidateParameters(pims, IMAPIProp_DeleteProps);
  551.  
  552.     IMS_EnterCriticalSection(pims);
  553.  
  554.     if (!OBJ_TestFlag(pims, OBJF_MODIFY))
  555.     {
  556.         hr = ResultFromScode(MAPI_E_NO_ACCESS);
  557.         goto exit;
  558.     }
  559.  
  560.     /* If input parameters are okay, make DeleteProps call on lpmsg. */
  561.  
  562.     hr = HrOpenIMSPropsFileRetry(pims->pmsgsess, pims->szProps, &pims->lmr,
  563.         pims->psup, TRUE, &lpmsg);
  564.     if (hr != hrSuccess)
  565.         goto exit;
  566.  
  567.     hr = lpmsg->lpVtbl->DeleteProps(lpmsg, ptaga, pprba);
  568.     if (hr != hrSuccess)
  569.         goto exit;
  570.  
  571.     hr = lpmsg->lpVtbl->SaveChanges(lpmsg, KEEP_OPEN_READWRITE);
  572.     /* if ( hr ), fall through to exit */
  573.  
  574. exit:
  575.     UlRelease(lpmsg);
  576.  
  577.     IMS_LeaveCriticalSection(pims);
  578.  
  579.     DebugTraceResult(IMS_DeleteProps, hr);
  580.     return HrCheckHr(hr, IMAPIProp_DeleteProps);
  581. }
  582.  
  583. /*
  584.  *  IMS_CopyTo
  585.  *
  586.  *  Purpose:
  587.  *      Copies the contents of the current object to a destination
  588.  *      object.  The entire contents, including contained objects,
  589.  *      are copied, or optionally the caller can provide a list of
  590.  *      properties that are not to be copied.  Previous information
  591.  *      in the destination object which is not overwritten by
  592.  *      copied data is neither deleted nor modified.  It is not a
  593.  *      requirement in MAPI 1.0, however, that CopyTo semantics
  594.  *      understood by the message store object or folder objects,
  595.  *      and so this method always returns MAPI_E_NO_SUPPORT.
  596.  *
  597.  *  Arguments:
  598.  *      pims            Pointer to the source object.
  599.  *      ciidExclude     Count of the excluded interfaces in
  600.  *                      rgiidExclude.
  601.  *      rgiidExclude    Array of interface IDs specifying
  602.  *                      interfaces not to be attempted in trying to
  603.  *                      copy supplemental information to the
  604.  *                      destination object.
  605.  *      ptagaExcl   Counted array of property tags of
  606.  *                      properties that are not to be copied to the
  607.  *                      destination object.  NULL indicates all
  608.  *                      properties are to be copied.
  609.  *      ulUIParam       Handle of parent window cast to ULONG.
  610.  *      lpProgress      Callback for doing progress UI.
  611.  *      piidDst     Interface ID of the interface of lpDestObj,
  612.  *                      the destination object.
  613.  *      lpDestObj       Pointer to the open destination object.
  614.  *      ulFlags         Flags.  Defined as follows:
  615.  *                      MAPI_MOVE       Indicates a move operation.
  616.  *                                      The default is to copy.
  617.  *                      MAPI_NOREPLACE  Indicates that existing
  618.  *                                      properties should not be
  619.  *                                      overridden.  The default is
  620.  *                                      to overwrite existing
  621.  *                                      properties.
  622.  *                      MAPI_DIALOG     Display a progress dialog
  623.  *                                      as the operation proceeds.
  624.  *      pprba       Pointer to a variable that is filled in
  625.  *                      with a pointer to a set of property
  626.  *                      problems.  If NULL, no problem set is
  627.  *                      returned on an error.
  628.  *
  629.  *  Returns:
  630.  *      HRESULT
  631.  *
  632.  *  Side effects:
  633.  *      None.
  634.  *
  635.  *  Errors:
  636.  *      MAPI_E_NO_SUPPORT   This method is not supported by
  637.  *                              this type of object.
  638.  */
  639. STDMETHODIMP IMS_CopyTo(PIMS pims, ULONG ciidExcl, LPCIID rgiidExcl,
  640.     LPSPropTagArray ptagaExcl, ULONG ulUIParam, LPMAPIPROGRESS
  641.     lpProgress, LPCIID piidDst, LPVOID lpDestObj, ULONG ulFlags,
  642.     LPSPropProblemArray *pprba)
  643. {
  644.     SCODE sc;
  645.  
  646.     MS_ValidateParameters(pims, IMAPIProp_CopyTo);
  647.  
  648.     sc = MAPI_E_NO_SUPPORT;
  649.  
  650.     DebugTraceSc(IMS_CopyTo, sc);
  651.     return ResultFromScode(sc);
  652. }
  653.  
  654. /*
  655.  *  IMS_CopyProps
  656.  *
  657.  *  Purpose:
  658.  *      Copies the specified properties of the current object to a destination
  659.  *      object.
  660.  *
  661.  *  Arguments:
  662.  *      pims            Pointer to the source object.
  663.  *      ptagaIncl       Counted array of property tags of
  664.  *                      properties that are to be copied to the
  665.  *                      destination object.
  666.  *      ulUIParam       Handle of parent window cast to ULONG.
  667.  *      lpProgress      Callback for doing progress UI.
  668.  *      piidDst         Interface ID of the interface of lpDestObj,
  669.  *                      the destination object.
  670.  *      lpDestObj       Pointer to the open destination object.
  671.  *      ulFlags         Flags.  Defined as follows:
  672.  *                      MAPI_MOVE       Indicates a move operation.
  673.  *                                      The default is to copy.
  674.  *                      MAPI_NOREPLACE  Indicates that existing
  675.  *                                      properties should not be
  676.  *                                      overridden.  The default is
  677.  *                                      to overwrite existing
  678.  *                                      properties.
  679.  *                      MAPI_DIALOG     Display a progress dialog
  680.  *                                      as the operation proceeds.
  681.  *                      MAPI_DECLINE_OK
  682.  *      pprba       Pointer to a variable that is filled in
  683.  *                      with a pointer to a set of property
  684.  *                      problems.  If NULL, no problem set is
  685.  *                      returned on an error.
  686.  *
  687.  *  Returns:
  688.  *      HRESULT
  689.  *
  690.  *  Side effects:
  691.  *      None.
  692.  *
  693.  *  Errors:
  694.  *      MAPI_E_NO_SUPPORT   This method is not supported by
  695.  *                              this type of object.
  696.  */
  697. STDMETHODIMP IMS_CopyProps(PIMS pims,
  698.     LPSPropTagArray ptagaIncl, ULONG ulUIParam, LPMAPIPROGRESS
  699.     lpProgress, LPCIID piidDst, LPVOID lpDestObj, ULONG ulFlags,
  700.     LPSPropProblemArray *pprba)
  701. {
  702.     SCODE sc;
  703.  
  704.     MS_ValidateParameters(pims, IMAPIProp_CopyProps);
  705.  
  706.     sc = MAPI_E_NO_SUPPORT;
  707.  
  708.     DebugTraceSc(IMS_CopyProps, sc);
  709.     return ResultFromScode(sc);
  710. }
  711.  
  712. /*
  713.  *  IMS_GetNamesFromIDs [also used by IFLD, IMSG, IATCH]
  714.  *
  715.  *  Purpose:
  716.  *
  717.  *  Arguments:
  718.  *
  719.  *  Returns:
  720.  *      HRESULT
  721.  *
  722.  *  Side effects:
  723.  *
  724.  *  Errors:
  725.  *      MAPI_E_NO_SUPPORT   This method is not yet supported in the sample ms.
  726.  */
  727. STDMETHODIMP IMS_GetNamesFromIDs(PIMS pobj, LPSPropTagArray * pptaga,
  728.     LPGUID lpguid, ULONG ulFlags, ULONG * pcNames, LPMAPINAMEID ** pppNames)
  729. {
  730.     HRESULT hr = hrSuccess;
  731.     LPMAPIPROP pmp = NULL;
  732.     BOOL fReleasePMP = FALSE;
  733.  
  734.     /* Check input parameters. */
  735.  
  736.     #ifdef VALIDATE
  737.     if (    IsBadWritePtr(pobj, sizeof(OBJ))
  738.         || (    pobj->lpVtbl != (IMS_Vtbl *) &vtblIMS
  739.             &&  pobj->lpVtbl != (IMS_Vtbl *) &vtblIFLD
  740.             &&  pobj->lpVtbl != (IMS_Vtbl *) &vtblIMSG
  741.             &&  pobj->lpVtbl != (IMS_Vtbl *) &vtblIATCH))
  742.         return ResultFromScode(MAPI_E_INVALID_PARAMETER);
  743.  
  744.     ValidateParameters(IMAPIProp_GetNamesFromIDs, &pobj);
  745.     #endif
  746.  
  747.     OBJ_EnterCriticalSection(pobj);
  748.  
  749.     switch(pobj->wType)
  750.     {
  751.         case OT_MSGSTORE:
  752.         {
  753.             PIMS pims = pobj->pims;
  754.     
  755.             hr = HrOpenIMSPropsFileRetry(pims->pmsgsess, pims->szProps,
  756.                 &pims->lmr, pims->psup, FALSE, (LPMESSAGE *) &pmp);
  757.             if (hr != hrSuccess)
  758.                 goto exit;
  759.     
  760.             fReleasePMP = TRUE;
  761.             break;
  762.         }
  763.     
  764.         case OT_FOLDER:
  765.         {
  766.             PIFLD pifld = (PIFLD) pobj;
  767.     
  768.             hr = HrOpenPropertyMessageRetry(pifld->peid, pifld->pims, FALSE,
  769.                 (LPMESSAGE *) &pmp);
  770.             if (hr != hrSuccess)
  771.                 goto exit;
  772.     
  773.             fReleasePMP = TRUE;
  774.             break;
  775.         }
  776.     
  777.         case OT_MESSAGE:
  778.             pmp = (LPMAPIPROP) ((PIMSG) pobj)->lpmsg;
  779.             break;
  780.     
  781.         case OT_ATTACH:
  782.             pmp = (LPMAPIPROP) ((PIATCH) pobj)->lpattach;
  783.             break;
  784.     
  785.         default:
  786.             TrapSz1("Invalid Object Type %08lX found", pobj->wType);
  787.             hr = ResultFromScode(MAPI_E_CALL_FAILED);
  788.             break;
  789.     }
  790.  
  791.     hr = pmp->lpVtbl->GetNamesFromIDs(pmp, pptaga, lpguid, ulFlags, pcNames,
  792.         pppNames);
  793.  
  794. exit:
  795.     if (fReleasePMP)
  796.         UlRelease(pmp);
  797.  
  798.     OBJ_LeaveCriticalSection(pobj);
  799.  
  800.     DebugTraceResult(IMS_GetNamesFromIDs, hr);
  801.     return hr;
  802. }
  803.  
  804. /*
  805.  *  IMS_GetIDsFromNames [also used by IFLD, IMSG, IATCH]
  806.  *
  807.  *  Purpose:
  808.  *
  809.  *  Arguments:
  810.  *
  811.  *  Returns:
  812.  *      HRESULT
  813.  *
  814.  *  Side effects:
  815.  *      None.
  816.  *
  817.  *  Errors:
  818.  */
  819. STDMETHODIMP IMS_GetIDsFromNames(PIMS pobj, ULONG cNames,
  820.     LPMAPINAMEID * ppNames, ULONG ulFlags, LPSPropTagArray * pptaga)
  821. {
  822.     HRESULT hr = hrSuccess;
  823.     LPMAPIPROP pmp = NULL;
  824.     BOOL fSaveReleasePMP = FALSE;
  825.     BOOL fModifyAccess;
  826.  
  827.     /* Check input parameters. */
  828.     #ifdef VALIDATE
  829.     if (    IsBadWritePtr(pobj, sizeof(OBJ))
  830.         || (    pobj->lpVtbl != (IMS_Vtbl *) &vtblIMS
  831.             &&  pobj->lpVtbl != (IMS_Vtbl *) &vtblIFLD
  832.             &&  pobj->lpVtbl != (IMS_Vtbl *) &vtblIMSG
  833.             &&  pobj->lpVtbl != (IMS_Vtbl *) &vtblIATCH))
  834.         return ResultFromScode(MAPI_E_INVALID_PARAMETER);
  835.  
  836.     ValidateParameters(IMAPIProp_GetIDsFromNames, &pobj);
  837.     #endif
  838.  
  839.     OBJ_EnterCriticalSection(pobj);
  840.  
  841.     fModifyAccess = !!(ulFlags & MAPI_CREATE);
  842.  
  843.     // Check for correct access mode
  844.     if (    fModifyAccess
  845.         &&  !OBJ_TestFlag(pobj, OBJF_MODIFY))
  846.     {
  847.         hr = ResultFromScode(MAPI_E_NO_ACCESS);
  848.         goto exit;
  849.     }
  850.  
  851.     switch(pobj->wType)
  852.     {
  853.         case OT_MSGSTORE:
  854.         {
  855.             PIMS pims = pobj->pims;
  856.     
  857.             hr = HrOpenIMSPropsFileRetry(pims->pmsgsess, pims->szProps,
  858.                 &pims->lmr, pims->psup, fModifyAccess, (LPMESSAGE *) &pmp);
  859.             if (hr != hrSuccess)
  860.                 goto exit;
  861.     
  862.             fSaveReleasePMP = TRUE;
  863.             break;
  864.         }
  865.     
  866.         case OT_FOLDER:
  867.         {
  868.             PIFLD pifld = (PIFLD) pobj;
  869.     
  870.             hr = HrOpenPropertyMessageRetry(pifld->peid, pifld->pims,
  871.                 fModifyAccess, (LPMESSAGE *) &pmp);
  872.             if (hr != hrSuccess)
  873.                 goto exit;
  874.     
  875.             fSaveReleasePMP = TRUE;
  876.             break;
  877.         }
  878.     
  879.         case OT_MESSAGE:
  880.             pmp = (LPMAPIPROP) ((PIMSG) pobj)->lpmsg;
  881.             break;
  882.     
  883.         case OT_ATTACH:
  884.             pmp = (LPMAPIPROP) ((PIATCH) pobj)->lpattach;
  885.             break;
  886.     
  887.         default:
  888.             TrapSz1("Invalid Object Type %08lX found", pobj->wType);
  889.             hr = ResultFromScode(MAPI_E_CALL_FAILED);
  890.             break;
  891.     }
  892.  
  893.     // CAN RETURN WARNINGS!!! Should still continue even when a warning
  894.     // is returned.
  895.  
  896.     hr = pmp->lpVtbl->GetIDsFromNames(pmp, cNames, ppNames, ulFlags, pptaga);
  897.     if (HR_FAILED(hr))
  898.         goto exit;
  899.  
  900.     if (fSaveReleasePMP && fModifyAccess)
  901.     {
  902.         HRESULT hrT;
  903.  
  904.         hrT = pmp->lpVtbl->SaveChanges(pmp, 0);
  905.         if (HR_FAILED(hrT))
  906.         {
  907.             LMFree(&pobj->lmr, *pptaga);
  908.             *pptaga = NULL;
  909.             hr = hrT;
  910.         }
  911.     }
  912.  
  913. exit:
  914.     if (fSaveReleasePMP)
  915.         UlRelease(pmp);
  916.  
  917.     OBJ_LeaveCriticalSection(pobj);
  918.  
  919.     #ifdef DEBUG
  920.     if (GetScode(hr) != MAPI_W_ERRORS_RETURNED)
  921.         DebugTraceResult(IMS_GetIDsFromNames, hr);
  922.     #endif
  923.  
  924.     return hr;
  925. }
  926.  
  927. /*
  928.  *  IMS_Advise [Also used by IMSLogon]
  929.  *
  930.  *  Purpose:
  931.  *      Register a client's interest in a set of events that could
  932.  *      occur to an object in this store.  The client's particular
  933.  *      interest is expressed in a ulEventMask, and he is told of
  934.  *      changes through an Advise object which he gives us.
  935.  *      The Sample Store uses the MAPI
  936.  *      Notification Engine to handle notifications, so the
  937.  *      Advise call is translated into a notification
  938.  *      subscription with MAPI.  When events occur in the store
  939.  *      which would cause interested clients to be notified, the
  940.  *      store calls back to MAPI to request that the occurrence of
  941.  *      an event be broadcast.
  942.  *
  943.  *  Arguments:
  944.  *      pims                Pointer to the message store object.
  945.  *      cbEntryID           Size of lpEntryID.
  946.  *      lpEntryID           Pointer to the ID for the object for
  947.  *                          which interest is being registered.
  948.  *                          if NULL then registration is for all changes.
  949.  *      ulEventMask         Indicates the events of interest and
  950.  *                          how to see them.
  951.  *      lpAdviseSink        Pointer to client's Advise Sink object.
  952.  *      lpulConnection      Pointer to a variable in which the
  953.  *                          client gets a cookie for cancelling
  954.  *                          the notifications.
  955.  *
  956.  *  Returns:
  957.  *      HRESULT
  958.  *
  959.  *  Side effects:
  960.  *      None.
  961.  *
  962.  *  Errors:
  963.  *      MAPI_E_INVALID_ENTRYID      The EntryID is not recognized
  964.  *                                  as belonging to this store.
  965.  *      MAPI_E_NO_SUPPORT       The implementation does not
  966.  *                                  support notification on this
  967.  *                                  object.
  968.  *      MAPI_E_NOT_ENOUGH_MEMORY    Could not allocate space for a
  969.  *                                  needed buffer.
  970.  */
  971. STDMETHODIMP IMS_Advise(PIMS pobj, ULONG cbEntryID, LPENTRYID lpEntryID,
  972.     ULONG ulEventMask, LPMAPIADVISESINK lpAdviseSink,
  973.     ULONG *lpulConnection)
  974. {
  975.     HRESULT hr = hrSuccess;
  976.     LPNOTIFKEY lpnotifkey = NULL;
  977.     PIMS pims;
  978.     PEID peid;
  979.  
  980.     /* Check input parameters. */
  981.  
  982.     #ifdef VALIDATE
  983.     if (    IsBadWritePtr(pobj, sizeof(OBJ))
  984.         || (    pobj->lpVtbl != (IMS_Vtbl *)&vtblIMS
  985.             &&  pobj->lpVtbl != (IMS_Vtbl *)&vtblMSL))
  986.         return ResultFromScode(MAPI_E_INVALID_PARAMETER);
  987.  
  988.     ValidateParameters(IMsgStore_Advise, &pobj);
  989.     #endif
  990.  
  991.     /* If this is an EntryID for which we support notifications, call the */
  992.     /* MAPI registration function and return the notification object.     */
  993.  
  994.     OBJ_EnterCriticalSection(pobj);
  995.  
  996.     pims = pobj->pims;
  997.     peid = (PEID) lpEntryID;
  998.     *lpulConnection = 0;
  999.  
  1000.     if (cbEntryID && FIsInvalidEID(cbEntryID, peid, pims))
  1001.     {
  1002.         hr = ResultFromScode(MAPI_E_INVALID_ENTRYID);
  1003.         goto exit;
  1004.     }
  1005.  
  1006.     if (cbEntryID && !FIsFolder(peid) && !FIsMessage(peid))
  1007.     {
  1008.         hr = ResultFromScode(MAPI_E_NO_SUPPORT);
  1009.         goto exit;
  1010.     }
  1011.  
  1012.     if (cbEntryID == 0)
  1013.         peid = NULL;
  1014.  
  1015.     hr = HrGetSMSStandardNotifKey(pims, peid, &lpnotifkey);
  1016.     if (hr != hrSuccess)
  1017.         goto exit;
  1018.  
  1019.     if (pims->psup)
  1020.     {
  1021.         hr = pims->psup->lpVtbl->Subscribe(pims->psup,
  1022.             lpnotifkey, ulEventMask, 0L, lpAdviseSink, lpulConnection);
  1023.         if (hr != hrSuccess)
  1024.             goto exit;
  1025.     }
  1026.     else
  1027.     {
  1028.         hr = ResultFromScode(MAPI_E_CALL_FAILED);
  1029.         /* fall through to exit */
  1030.     }
  1031.  
  1032. exit:
  1033.     OBJ_LeaveCriticalSection(pobj);
  1034.  
  1035.     FreeNull(lpnotifkey);
  1036.  
  1037.     DebugTraceResult(IMS_Advise, hr);
  1038.     return HrCheckHr(hr, IMsgStore_Advise);
  1039. }
  1040.  
  1041. /*
  1042.  *  IMS_Unadvise [Also used by IMSLogon]
  1043.  *
  1044.  *  Purpose:
  1045.  *      Deregister a previous notification.
  1046.  *
  1047.  *  Arguments:
  1048.  *      pims                Pointer to the message store object.
  1049.  *      ulConnection        Cookie given out at Advise time.
  1050.  *
  1051.  *  Returns:
  1052.  *      HRESULT
  1053.  *
  1054.  *  Side effects:
  1055.  *      None.
  1056.  *
  1057.  *  Errors:
  1058.  */
  1059. STDMETHODIMP IMS_Unadvise(PIMS pobj, ULONG ulConnection)
  1060. {
  1061.     HRESULT hr = hrSuccess;
  1062.     LPMAPISUP psup;
  1063.  
  1064.     /* Check input parameters. */
  1065.  
  1066.     #ifdef VALIDATE
  1067.     if (    IsBadWritePtr(pobj, sizeof(OBJ))
  1068.         ||  (   pobj->lpVtbl != (IMS_Vtbl *)&vtblIMS
  1069.             &&  pobj->lpVtbl != (IMS_Vtbl *)&vtblMSL))
  1070.         return ResultFromScode(MAPI_E_INVALID_PARAMETER);
  1071.  
  1072.     ValidateParameters(IMsgStore_Unadvise, &pobj);
  1073.     #endif
  1074.  
  1075.     OBJ_EnterCriticalSection(pobj);
  1076.  
  1077.     psup = pobj->pims->psup;
  1078.  
  1079.     if (psup)
  1080.         hr = psup->lpVtbl->Unsubscribe(psup, ulConnection);
  1081.     else
  1082.         hr = ResultFromScode(MAPI_E_CALL_FAILED);
  1083.  
  1084.     OBJ_LeaveCriticalSection(pobj);
  1085.  
  1086.     DebugTraceResult(IMS_Unadvise, hr);
  1087.     return HrCheckHr(hr, IMsgStore_Unadvise);
  1088. }
  1089.  
  1090. /*
  1091.  *  IMS_CompareEntryIDs
  1092.  *
  1093.  *  Purpose:
  1094.  *      Compares two EntryIDs to determine if they refer to the
  1095.  *      same object.  This is useful because, in general, an object
  1096.  *      may have more than one valid EntryID.  For the Sample
  1097.  *      Store, however, an object only has one valid EntryID at any
  1098.  *      time and so this function reduces to a check for binary
  1099.  *      equality of the EntryIDs.
  1100.  *
  1101.  *  Arguments:
  1102.  *      pims        Pointer to the Message Store Object.
  1103.  *      cbEntryID1  Size of first EntryID.
  1104.  *      lpEntryID1  Pointer to the first EntryID.
  1105.  *      cbEntryID2  Size of second EntryID.
  1106.  *      lpEntryID2  Pointer to the second EntryID.
  1107.  *      ulFlags     Flags.  Reserved.  Must be zero.
  1108.  *      lpulResult  Pointer to a variable in which the result of
  1109.  *                  the comparison (TRUE or FALSE) is placed.
  1110.  *
  1111.  *  Returns:
  1112.  *      HRESULT
  1113.  *
  1114.  *  Side effects:
  1115.  *      None.
  1116.  *
  1117.  *  Errors:
  1118.  *      MAPI_E_INVALID_ENTRYID  An EntryID is not recognized as
  1119.  *                              belonging to this store.
  1120.  */
  1121. STDMETHODIMP IMS_CompareEntryIDs(PIMS pobj, ULONG cbEntryID1,
  1122.     LPENTRYID lpEntryID1, ULONG cbEntryID2, LPENTRYID lpEntryID2, ULONG ulFlags,
  1123.     ULONG *lpulResult)
  1124. {
  1125.     HRESULT hr = hrSuccess;
  1126.     PEID peid1;
  1127.     PEID peid2;
  1128.     PIMS pims;
  1129.     BOOL fEID1IsRoot = FALSE;
  1130.     BOOL fEID2IsRoot = FALSE;
  1131.  
  1132.     /* Check input parameters. */
  1133.  
  1134.     #ifdef VALIDATE
  1135.     if (    IsBadWritePtr(pobj, sizeof(OBJ))
  1136.         || (    pobj->lpVtbl != (IMS_Vtbl *)&vtblIMS
  1137.             &&  pobj->lpVtbl != (IMS_Vtbl *)&vtblMSL))
  1138.         return ResultFromScode(MAPI_E_INVALID_PARAMETER);
  1139.  
  1140.     ValidateParameters(IMsgStore_CompareEntryIDs, &pobj);
  1141.     #endif
  1142.  
  1143.     OBJ_EnterCriticalSection(pobj);
  1144.  
  1145.     /* Do a binary comparison of the EIDs, if they're the same size AND */
  1146.     /* if we recognize one of them as belonging to this store.          */
  1147.  
  1148.     peid1 = (PEID) lpEntryID1;
  1149.     peid2 = (PEID) lpEntryID2;
  1150.     pims = pobj->pims;
  1151.  
  1152.     if ((cbEntryID1 && FIsInvalidEID(cbEntryID1, peid1, pims))
  1153.         || (cbEntryID2 && FIsInvalidEID(cbEntryID2, peid2, pims)))
  1154.     {
  1155.         hr = ResultFromScode(MAPI_E_INVALID_ENTRYID);
  1156.         goto exit;
  1157.     }
  1158.  
  1159.     if (cbEntryID1 == 0 || FIsRoot(peid1))
  1160.         fEID1IsRoot = TRUE;
  1161.  
  1162.     if (cbEntryID2 == 0 || FIsRoot(peid2))
  1163.         fEID2IsRoot = TRUE;
  1164.  
  1165.     *lpulResult = FALSE;
  1166.  
  1167.     if (fEID1IsRoot == fEID2IsRoot && fEID1IsRoot == TRUE)
  1168.         *lpulResult = TRUE;
  1169.     else if (cbEntryID1 == cbEntryID2
  1170.             && memcmp(peid1, peid2, offsetof(EID, szPath)) == 0
  1171.             && peid1->bVersion == SMPMS_VERSION
  1172.         && lstrcmpi(peid1->szPath, peid2->szPath) == 0)
  1173.         *lpulResult = TRUE;
  1174.  
  1175. exit:
  1176.     OBJ_LeaveCriticalSection(pobj);
  1177.  
  1178.     DebugTraceResult(IMS_CompareEntryIDs, hr);
  1179.     return hr;
  1180. }
  1181.  
  1182. /*
  1183.  *  IMS_OpenEntry [Also used by IMSLogon and IMAPIFolder]
  1184.  *
  1185.  *  Purpose:
  1186.  *      Opens an object in this message store.
  1187.  *
  1188.  *  Arguments:
  1189.  *      pobj            Message store on which this function was
  1190.  *                      called.
  1191.  *      cbEntryID       Size of lpEntryID.
  1192.  *      lpEntryID       EntryID of object to open.
  1193.  *      piid            IID of interface requested for the
  1194.  *                      newly-opened object.  NULL or IID_IMAPIProp
  1195.  *                      means to open the object using the standard
  1196.  *                      MAPI 1.0 interface for the object.
  1197.  *                      IID_IUnknown means to open it using
  1198.  *                      the easiest interface you can open.
  1199.  *      ulFlags         Flags.  The following are defined:
  1200.  *                      MAPI_MODIFY             Write access desired.
  1201.  *                      MAPI_DEFERRED_ERRORS    Delayed "open" errors OKAY.
  1202.  *                      MAPI_BEST_ACCESS        Open for writing if possible,
  1203.  *                                              otherwise, open for reading.
  1204.  *      lpulObjType     Address in which to place the type of the
  1205.  *                      opened object.
  1206.  *      lppUnk          Address in which to place a pointer to the
  1207.  *                      opened object.
  1208.  *
  1209.  *  Returns:
  1210.  *      HRESULT
  1211.  *
  1212.  *  Side effects:
  1213.  *      None.
  1214.  *
  1215.  *  Errors:
  1216.  *      MAPI_E_NOT_ENOUGH_MEMORY    Could not allocate memory for
  1217.  *                                  the to-be-opened object.
  1218.  *      MAPI_E_INVALID_ENTRYID      This message store does not
  1219.  *                                  recognize this EntryID.
  1220.  *      MAPI_E_UNKNOWN_FLAGS
  1221.  *      MAPI_E_INVALID_PARAMETER
  1222.  */
  1223. STDMETHODIMP IMS_OpenEntry(PIMS pobj, ULONG cbEntryID, LPENTRYID lpEntryID,
  1224.     LPCIID piid, ULONG ulFlags, ULONG *lpulObjType, LPUNKNOWN *lppUnk)
  1225. {
  1226.     HRESULT hr = hrSuccess;
  1227.     PIMSG pimsg = NULL;
  1228.     PIFLD pifld = NULL;
  1229.     PEID peidParent = NULL;
  1230.     BOOL fEIDIsRoot = FALSE;
  1231.     BOOL fModify;
  1232.     BOOL fBestAcc;
  1233.     PIMS pims;
  1234.     PEID peid;
  1235.  
  1236.     /* Check input parameters. */
  1237.  
  1238.     #ifdef VALIDATE
  1239.     if (    IsBadWritePtr(pobj, sizeof(OBJ))
  1240.         ||  (   pobj->lpVtbl != (IMS_Vtbl *)&vtblIFLD
  1241.              && pobj->lpVtbl != (IMS_Vtbl *)&vtblIMS
  1242.              && pobj->lpVtbl != (IMS_Vtbl *)&vtblMSL))
  1243.         return ResultFromScode(MAPI_E_INVALID_PARAMETER);
  1244.  
  1245.     ValidateParameters(IMAPIContainer_OpenEntry, &pobj);
  1246.     #endif
  1247.  
  1248.     OBJ_EnterCriticalSection(pobj);
  1249.  
  1250.     /* Get the real pims object in case pobj is a PIFLD or PMSL */
  1251.     pims = pobj->pims;
  1252.  
  1253.     peid = (PEID) lpEntryID;
  1254.  
  1255.     /* If parameters are okay, see if this is an EntryID we understand. */
  1256.  
  1257.     if (cbEntryID && FIsInvalidEID(cbEntryID, peid, pims))
  1258.     {
  1259.         hr = ResultFromScode(MAPI_E_INVALID_ENTRYID);
  1260.         goto exit;
  1261.     }
  1262.  
  1263.     if (cbEntryID == 0 || FIsRoot(peid))
  1264.         fEIDIsRoot = TRUE;
  1265.  
  1266.     /* determine if the caller wants modification access */
  1267.     fModify = (ulFlags & (MAPI_MODIFY | MAPI_BEST_ACCESS)) != 0;
  1268.     fBestAcc = (ulFlags & MAPI_BEST_ACCESS) != 0;
  1269.  
  1270.     /* Fail if attempting to open an object for */
  1271.     /* modification in a read-only store.       */
  1272.  
  1273.     if (fModify
  1274.         && !OBJ_TestFlag(pims, OBJF_MODIFY))
  1275.     {
  1276.         if (fBestAcc)
  1277.             fModify = FALSE;
  1278.         else
  1279.         {
  1280.             hr = ResultFromScode(MAPI_E_NO_ACCESS);
  1281.             goto exit;
  1282.         }
  1283.     }
  1284.  
  1285.     /* Open the object */
  1286.  
  1287.     if (fEIDIsRoot)
  1288.     {
  1289.         PEID peidRoot = NULL;
  1290.         CHAR ch = '\0';
  1291.         MAPIUID uid;
  1292.  
  1293.         if (piid && !FQueryInterface(OT_FOLDER, piid))
  1294.         {
  1295.             hr = ResultFromScode(E_NOINTERFACE);
  1296.             goto exit;
  1297.         }
  1298.  
  1299.         GetResourceUID(pims, &uid);
  1300.  
  1301.         hr = HrConstructEID(&uid, &pims->lmr, (LPSTR) &ch, &peidRoot);
  1302.         if (hr != hrSuccess)
  1303.             goto exit;
  1304.  
  1305.         hr = HrNewIFLD(peidRoot, pims, fModify, &pifld);
  1306.  
  1307.         if (hr == hrSuccess)
  1308.             hr = HrSetInternalProps(&pims->lmr, cpropIFLDInternal,
  1309.                 &(pifld->pval), &(pifld->cval), peidRoot, peidRoot, 0);
  1310.  
  1311.         LMFree(&pims->lmr, peidRoot);
  1312.  
  1313.         if (hr != hrSuccess)
  1314.             goto exit;
  1315.  
  1316.         *lppUnk = (LPUNKNOWN) pifld;
  1317.         *lpulObjType = MAPI_FOLDER;
  1318.     }
  1319.     else
  1320.     {
  1321.         hr = HrGetParentEID(&pims->lmr, peid, &peidParent);
  1322.         if (hr != hrSuccess)
  1323.             goto exit;
  1324.  
  1325.         if (FIsMessage(peid))
  1326.         {
  1327.             ULONG ulSeqNum;
  1328.  
  1329.             if (piid && !FQueryInterface(OT_MESSAGE, piid))
  1330.             {
  1331.                 hr = ResultFromScode(E_NOINTERFACE);
  1332.                 goto exit;
  1333.             }
  1334.  
  1335.             hr = HrGetSequenceNum(peid, &ulSeqNum);
  1336.  
  1337.             hr = HrNewIMSG(peid, pims, FALSE, fModify, ulSeqNum, NULL, &pimsg);
  1338.  
  1339.             if (GetScode(hr) == MAPI_E_SUBMITTED && fBestAcc && fModify)
  1340.             {
  1341.                 fModify = FALSE;
  1342.                 hr = HrNewIMSG(peid, pims, FALSE, fModify, ulSeqNum, NULL, &pimsg);
  1343.             }
  1344.  
  1345.             if (hr != hrSuccess)
  1346.                 goto exit;
  1347.  
  1348.             *lppUnk = (LPUNKNOWN) pimsg;
  1349.             *lpulObjType = MAPI_MESSAGE;
  1350.         }
  1351.         else /* a folder */
  1352.         {
  1353.             if (!FIsFolder(peid))
  1354.             {
  1355.                 TrapSz("Logic error");
  1356.                 hr = ResultFromScode(MAPI_E_INVALID_ENTRYID);
  1357.                 goto exit;
  1358.             }
  1359.  
  1360.             if (piid && !FQueryInterface(OT_FOLDER, piid))
  1361.             {
  1362.                 hr = ResultFromScode(E_NOINTERFACE);
  1363.                 goto exit;
  1364.             }
  1365.  
  1366.             hr = HrNewIFLD(peid, pims, fModify, &pifld);
  1367.             if (hr != hrSuccess)
  1368.                 goto exit;
  1369.  
  1370.             hr = HrSetInternalProps(&pims->lmr, cpropIFLDInternal,
  1371.                 &(pifld->pval), &(pifld->cval), peid, peidParent, 0);
  1372.             if (hr != hrSuccess)
  1373.                 goto exit;
  1374.  
  1375.             *lppUnk = (LPUNKNOWN) pifld;
  1376.             *lpulObjType = MAPI_FOLDER;
  1377.         }
  1378.     }
  1379.  
  1380. exit:
  1381.     AssertSz(hr == hrSuccess || HR_FAILED(hr), "No Warnings expected");
  1382.  
  1383.     LMFree(&pims->lmr, peidParent);
  1384.  
  1385.     if (hr != hrSuccess)
  1386.     {
  1387.         UlRelease(pimsg);
  1388.         UlRelease(pifld);
  1389.     }
  1390.  
  1391.     OBJ_LeaveCriticalSection(pobj);
  1392.  
  1393.     DebugTraceResult(IMS_OpenEntry, hr);
  1394.     return HrCheckHr(hr, IMsgStore_OpenEntry);
  1395. }
  1396.  
  1397. /*
  1398.  *  IMS_SetReceiveFolder
  1399.  *
  1400.  *  Purpose:
  1401.  *      Sets the receive folder for a particular message class.  A
  1402.  *      message class is a string with "." delimiters, e.g
  1403.  *      "IPM.Note".  This method also removes a setting if the
  1404.  *      EntryID parameter (see below) is NULL.  Because there must
  1405.  *      be only one set of receive folder settings per store (NOT
  1406.  *      per logon), the settings are stored on disk in an OLE2
  1407.  *      docfile, and all access to them is done on disk, not in
  1408.  *      memory (see recfldr.c, recfldr.h for details).
  1409.  *
  1410.  *  Arguments:
  1411.  *      pims                Pointer to the object.
  1412.  *      szMessageClass  String identifying a message class.  If
  1413.  *                          NULL, then the default receive folder
  1414.  *                          is set.
  1415.  *      ulFlags             Flags.
  1416.  *      cbEntryID           Size of lpEntryID.
  1417.  *      lpEntryID           Pointer to the identifier of a
  1418.  *                          particular folder in the store.  If
  1419.  *                          this pointer is NULL, the receive
  1420.  *                          folder setting is removed.
  1421.  *
  1422.  *  Returns:
  1423.  *      HRESULT
  1424.  *
  1425.  *  Side effects:
  1426.  *      IMS_SetReceiveFolder will not actually check to see if the
  1427.  *      EntryID it is given exists in the store at this time, so
  1428.  *      will go ahead and create an invalid receive folder setting
  1429.  *      for that particular message class.
  1430.  *
  1431.  *  Errors:
  1432.  *      MAPI_E_INVALID_ENTRYID  The store doesn't recognize this
  1433.  *                              EntryID as belonging to it.
  1434.  */
  1435. STDMETHODIMP IMS_SetReceiveFolder(PIMS pims, LPTSTR szMessageClass,
  1436.     ULONG ulFlags, ULONG cbEntryID, LPENTRYID lpEntryID)
  1437. {
  1438.     SCODE sc;
  1439.     HRESULT hr = hrSuccess;
  1440.     TCHAR rgchDefMsgClass[] = TEXT("");
  1441.     LPTSTR szNormalizedClass = NULL;
  1442.     RFN rfn;
  1443.     PEID peid;
  1444.  
  1445.     /* Check input parameters. */
  1446.  
  1447.     MS_ValidateParameters(pims, IMsgStore_SetReceiveFolder);
  1448.  
  1449.     #ifdef VALIDATE
  1450.     if (ulFlags & MAPI_UNICODE)
  1451.         return ResultFromScode(MAPI_E_BAD_CHARWIDTH);
  1452.     #endif
  1453.  
  1454.     IMS_EnterCriticalSection(pims);
  1455.  
  1456.     if (!OBJ_TestFlag(pims, OBJF_MODIFY))
  1457.     {
  1458.         hr = ResultFromScode(MAPI_E_NO_ACCESS);
  1459.         goto exit;
  1460.     }
  1461.  
  1462.     peid = (PEID) lpEntryID;
  1463.  
  1464.     /* don't allow removal of the default settings */
  1465.     if (peid == NULL &&
  1466.         (szMessageClass == NULL || *szMessageClass == '\0'))
  1467.     {
  1468.         hr = ResultFromScode(MAPI_E_CALL_FAILED);
  1469.         goto exit;
  1470.     }
  1471.  
  1472.     /* If parameters are okay, see if this is an EntryID we understand. */
  1473.  
  1474.     if (cbEntryID && FIsInvalidEID(cbEntryID, peid, pims))
  1475.     {
  1476.         hr = ResultFromScode(MAPI_E_INVALID_ENTRYID);
  1477.         goto exit;
  1478.     }
  1479.  
  1480.     /* The RFS module always expects a valid string */
  1481.     if (!szMessageClass)
  1482.         szMessageClass = rgchDefMsgClass;
  1483.  
  1484.     /* Make a copy of the szMessageClass that is normalized */
  1485.  
  1486.     sc = LMAlloc(&pims->lmr, Cbtszsize(szMessageClass), &szNormalizedClass);
  1487.     if (sc != S_OK)
  1488.     {
  1489.         hr = ResultFromScode(sc);
  1490.         goto exit;
  1491.     }
  1492.     lstrcpy (szNormalizedClass, szMessageClass);
  1493.     CharUpper (szNormalizedClass);
  1494.         
  1495.     if (cbEntryID)
  1496.     {
  1497.         PRFN prfnExisting = NULL;
  1498.  
  1499.         rfn.szClass = szNormalizedClass;
  1500.         rfn.szName = peid->szPath;
  1501.  
  1502.         hr = GetRFN(pims->prfs, szNormalizedClass, &prfnExisting);
  1503.         if (hr != hrSuccess)
  1504.         {
  1505.             if (GetScode(hr) == MAPI_E_NOT_FOUND)
  1506.                 hr = hrSuccess;
  1507.             else
  1508.                 goto exit;
  1509.         }
  1510.         else
  1511.         {
  1512.             /* Remove the existing receive folder setting, but only if it */
  1513.             /* _exactly_ matches the one that we're adding.               */
  1514.             /*  //$ Are message classes case-sensitive? */
  1515.  
  1516.             if (!lstrcmp(szMessageClass, prfnExisting->szClass))
  1517.                 hr = DeleteRFN(pims->prfs, szNormalizedClass);
  1518.  
  1519.             FreeRFN(prfnExisting);
  1520.  
  1521.             if (hr != hrSuccess)
  1522.                 goto exit;
  1523.         }
  1524.  
  1525.         /* WARNING:  If the addition fails, we can't easily  */
  1526.         /* revert to a previous version of the RFS settings. */
  1527.  
  1528.         hr = AddRFN(pims->prfs, &rfn);
  1529.         /* if ( hr ), fall through to exit */
  1530.     }
  1531.     else
  1532.     {
  1533.         hr = DeleteRFN(pims->prfs, szNormalizedClass);
  1534.         /* if ( hr ), fall through to exit */
  1535.     }
  1536.  
  1537. exit:
  1538.     LMFree(&pims->lmr, szNormalizedClass);
  1539.     IMS_LeaveCriticalSection(pims);
  1540.  
  1541.     DebugTraceResult(IMS_SetReceiveFolder, hr);
  1542.     return HrCheckHr(hr, IMsgStore_SetReceiveFolder);
  1543. }
  1544.  
  1545. /*
  1546.  *  IMS_GetReceiveFolder
  1547.  *
  1548.  *  Purpose:
  1549.  *      Obtains the receive folder setting for a particular message
  1550.  *      class and other information about the receive behavior of
  1551.  *      that message class.  This function obtains the EntryID of
  1552.  *      the folder where messages of a specific class are placed.
  1553.  *      If szMessageClass does not explicitly set a receive
  1554.  *      folder, then the receive folder of the first superclass of
  1555.  *      szMessageClass which does explicitly set a receive folder
  1556.  *      is returned.  Whichever message class that explicitly sets
  1557.  *      the receive folder is returned in pszExplicitClass.  For
  1558.  *      example, if the receive folder of the message class
  1559.  *      "IPM.Note" has been set to the EntryID of the Inbox and an
  1560.  *      application calls GetReceiveFolder() on the message class
  1561.  *      "IPM.Note.Phone," the EntryID of the Inbox is returned as
  1562.  *      the lppEntryID, and "IPM.Note" is retuned in
  1563.  *      pszExplicitClass.  The converse is not true:  if the
  1564.  *      receive folder setting of "IPM.Note.Phone" is the Inbox and
  1565.  *      the client asks for the setting of "IPM.Note", NULL is
  1566.  *      returned.
  1567.  *
  1568.  *  Arguments:
  1569.  *      pims                Pointer to the object.
  1570.  *      szMessageClass  Identifies the particular message
  1571.  *                          class.  If this pointer is NULL, then
  1572.  *                          the default is returned.
  1573.  *      ulFlags             Flags.
  1574.  *      lpcbEntryID         Address of the location in which to
  1575.  *                          return the size of the EntryID in
  1576.  *                          *lppEntryID.
  1577.  *      lppEntryID          Address of the location in which to
  1578.  *                          return a pointer to an EntryID which is
  1579.  *                          the identifier of the receive folder.
  1580.  *      pszExplicitClass    Address of the location in which to
  1581.  *                          return a pointer a buffer containing
  1582.  *                          the message class that explicitly sets
  1583.  *                          its receive folder to *lppEntryID.  If
  1584.  *                          NULL indicates that no class name
  1585.  *                          should be returned.  If it is exactly
  1586.  *                          equal to szMessageClass, nothing is
  1587.  *                          returned (*pszExplicitClass == NULL).
  1588.  *
  1589.  *  Returns:
  1590.  *      HRESULT
  1591.  *
  1592.  *  Side effects:
  1593.  *      None.
  1594.  *
  1595.  *  Errors:
  1596.  *      None.
  1597.  */
  1598. STDMETHODIMP IMS_GetReceiveFolder(PIMS pims, LPTSTR szMessageClass,
  1599.     ULONG ulFlags, ULONG *lpcbEntryID, LPENTRYID *lppEntryID,
  1600.     LPTSTR *pszExplicitClass)
  1601. {
  1602.     HRESULT hr = hrSuccess;
  1603.     ULONG cbeid = 0L;
  1604.     PEID peid = NULL;
  1605.     LPTSTR szExCls = NULL;
  1606.     PRFN prfn = NULL;
  1607.     TCHAR rgchDefMsgClass[] = TEXT("");
  1608.     LPTSTR szNormalizedClass = NULL;
  1609.     MAPIUID uid;
  1610.     SCODE sc = S_OK;
  1611.  
  1612.     /* Check input parameters. */
  1613.  
  1614.     MS_ValidateParameters(pims, IMsgStore_GetReceiveFolder);
  1615.  
  1616.     #ifdef VALIDATE
  1617.     if (ulFlags & MAPI_UNICODE)
  1618.         return ResultFromScode(MAPI_E_BAD_CHARWIDTH);
  1619.     #endif
  1620.  
  1621.     IMS_EnterCriticalSection(pims);
  1622.  
  1623.     *lpcbEntryID = 0L;
  1624.     *lppEntryID = NULL;
  1625.  
  1626.     if (pszExplicitClass)
  1627.         *pszExplicitClass = NULL;
  1628.  
  1629.     /* The RFS module always expects a valid string */
  1630.  
  1631.     if (!szMessageClass)
  1632.         szMessageClass = rgchDefMsgClass;
  1633.  
  1634.     /* Make a copy of the szMessageClass that is normalized */
  1635.  
  1636.     sc = LMAlloc(&pims->lmr, Cbtszsize(szMessageClass), &szNormalizedClass);
  1637.     if (sc != S_OK)
  1638.     {
  1639.         hr = ResultFromScode(sc);
  1640.         goto exit;
  1641.     }
  1642.     lstrcpy (szNormalizedClass, szMessageClass);
  1643.     CharUpper (szNormalizedClass);
  1644.  
  1645.     hr = GetRFN(pims->prfs, szNormalizedClass, &prfn);
  1646.     if (hr != hrSuccess)
  1647.         goto exit;
  1648.  
  1649.     /* Allocate and set return variables. */
  1650.  
  1651.     GetResourceUID(pims, &uid);
  1652.  
  1653.     hr = HrConstructEID(&uid, &pims->lmr, prfn->szName, &peid);
  1654.     if (hr != hrSuccess)
  1655.         goto exit;
  1656.  
  1657.     cbeid = CbEID(peid);
  1658.  
  1659.     if (pszExplicitClass)
  1660.     {
  1661.         sc = LMAlloc(&pims->lmr, Cbtszsize(prfn->szClass), &szExCls);
  1662.         if (sc != S_OK)
  1663.         {
  1664.             hr = ResultFromScode(sc);
  1665.             goto exit;
  1666.         }
  1667.  
  1668.         lstrcpy(szExCls, prfn->szClass);
  1669.         *pszExplicitClass = szExCls;
  1670.     }
  1671.  
  1672.     *lpcbEntryID = cbeid;
  1673.     *lppEntryID = (LPENTRYID) peid;
  1674.  
  1675. exit:
  1676.     FreeRFN(prfn);
  1677.     LMFree(&pims->lmr, szNormalizedClass);
  1678.     if (hr != hrSuccess)
  1679.     {
  1680.         LMFree(&pims->lmr, peid);
  1681.         LMFree(&pims->lmr, szExCls);
  1682.     }
  1683.  
  1684.     IMS_LeaveCriticalSection(pims);
  1685.  
  1686.     DebugTraceResult(IMS_GetReceiveFolder, hr);
  1687.     return HrCheckHr(hr, IMsgStore_GetReceiveFolder);
  1688. }
  1689.  
  1690. STDMETHODIMP IMS_GetReceiveFolderTable(PIMS pims, ULONG ulFlags,
  1691.     LPMAPITABLE *lppTable)
  1692. {
  1693.     MS_ValidateParameters(pims, IMsgStore_GetReceiveFolderTable);
  1694.  
  1695.     #ifdef VALIDATE
  1696.     if (ulFlags & MAPI_UNICODE)
  1697.         return ResultFromScode(MAPI_E_BAD_CHARWIDTH);
  1698.     #endif
  1699.  
  1700.     DebugTraceSc(IMS_GetReceiveFolderTable, MAPI_E_NO_SUPPORT);
  1701.     return ResultFromScode(MAPI_E_NO_SUPPORT);
  1702. }
  1703.  
  1704. /*
  1705.  *  IMS_StoreLogoff
  1706.  *
  1707.  *  Purpose:
  1708.  *      Allows the orderly release of a store under client control.
  1709.  *      Use of this function to release a store allows some client
  1710.  *      control over what MAPI will do about transport activity.
  1711.  *      The client can either put itself in the loop by setting the
  1712.  *      appropriate flags, or it can allow MAPI to either abort the
  1713.  *      sending of mail or to complete it prior to invalidating the
  1714.  *      object.  This behavior will only occur when the client is
  1715.  *      the only application which is using the message store, and 
  1716.  *      will happen during release of the store object.  If
  1717.  *      another client is still using the store, the store object
  1718.  *      will remember the flags and will issue the call during the 
  1719.  *      final release.
  1720.  *
  1721.  *  Arguments:
  1722.  *      pims        Pointer to the object.
  1723.  *      pulFlags    Flags.  The following are defined as input:
  1724.  *                  LOGOFF_NO_WAIT  Don't wait for the transports.
  1725.  *                                  All outboutnd mail that is
  1726.  *                                  ready to be sent will be sent.
  1727.  *                                  Control is returned to the
  1728.  *                                  client immediately.
  1729.  *                  LOGOFF_ORDERLY  Don't wait for the transports.
  1730.  *                                  Any currently in-process
  1731.  *                                  message on the store is
  1732.  *                                  completed; no new ones are
  1733.  *                                  started.  Control is returned
  1734.  *                                  to the client immediately.
  1735.  *                  LOGOFF_PURGE    Same as LOGOFF_NO_WAIT but
  1736.  *                                  PurgeQueues() called for
  1737.  *                                  appropriate transports and
  1738.  *                                  client waits for completion.
  1739.  *                  LOGOFF_ABORT    Any transport activity on this
  1740.  *                                  store should be aborted.
  1741.  *                                  Control is returned to the
  1742.  *                                  client when abort completes.
  1743.  *                  LOGOFF_QUIET    If any transport activity is
  1744.  *                                  taking place, the logoff will
  1745.  *                                  not occur.
  1746.  *                  The following are defined as output flags:
  1747.  *                  LOGOFF_COMPLETE         All resources
  1748.  *                                          associated with the
  1749.  *                                          store have been
  1750.  *                                          released and the object
  1751.  *                                          invalidated.
  1752.  *                  LOGOFF_INBOUND          A message is currently
  1753.  *                                          coming into the store
  1754.  *                                          from one or more
  1755.  *                                          transports.
  1756.  *                  LOGOFF_OUTBOUND         A message is currently
  1757.  *                                          being sent from the
  1758.  *                                          store by one or more
  1759.  *                                          transports.
  1760.  *                  LOGOFF_OUTBOUND_QUEUE   Messages are currently
  1761.  *                                          in the outbound queue
  1762.  *                                          for the store.
  1763.  *
  1764.  *  Returns:
  1765.  *      HRESULT
  1766.  *
  1767.  *  Side effects:
  1768.  *      See flag description for possible side effects.
  1769.  *
  1770.  *  Errors:
  1771.  *      Various.
  1772.  */
  1773.  
  1774. STDMETHODIMP IMS_StoreLogoff(PIMS pims, ULONG * pulFlags)
  1775. {
  1776.     HRESULT hr = 0;
  1777.     LPMAPISUP psup = NULL;
  1778.  
  1779.     MS_ValidateParameters(pims, IMsgStore_StoreLogoff);
  1780.  
  1781.     IMS_EnterCriticalSection(pims);
  1782.  
  1783.     pims->ulFlagsSLT = *pulFlags;
  1784.     *pulFlags = LOGOFF_COMPLETE;
  1785.  
  1786.     IMS_LeaveCriticalSection(pims);
  1787.  
  1788.     DebugTraceResult(IMS_StoreLogoff, hr);
  1789.     return HrCheckHr(hr, IMsgStore_StoreLogoff);
  1790. }
  1791.  
  1792. /*
  1793.  *  IMS_AbortSubmit
  1794.  *
  1795.  *  Purpose:
  1796.  *      Removes the current message from the submission queue.
  1797.  *      Since this is not implemented in IMessage on IStorage, we
  1798.  *      must do it ourselves.
  1799.  *
  1800.  *  Arguments:
  1801.  *      lpMS        Pointer to the message store.
  1802.  *      cbEntryID   the size of the entry ID
  1803.  *      lpEntryID   the entry ID of the message to abort
  1804.  *      ulFlags     Flags.  Reserved for future use.  Must be zero.
  1805.  *
  1806.  *  Returns:
  1807.  *      HRESULT
  1808.  *
  1809.  *  Side effects:
  1810.  *      None.
  1811.  *
  1812.  *  Errors:
  1813.  *      MAPI_E_NOT_IN_QUEUE     The message was never successfully
  1814.  *                              submitted (and is thus not in the
  1815.  *                              outgoing queue).
  1816.  *      MAPI_E_UNABLE_TO_ABORT  The underlying messaging system no
  1817.  *                              longer allows the submission to be
  1818.  *                              cancelled.
  1819.  */
  1820. STDMETHODIMP IMS_AbortSubmit(PIMS pims, ULONG cbEntryID, LPENTRYID lpEntryID,
  1821.     ULONG ulFlags)
  1822. {
  1823.     HRESULT hr = hrSuccess;
  1824.     PIMSG pimsg = NULL;
  1825.     ULONG ulObjType;
  1826.     BOOL fClearSpooler = FALSE;
  1827.     ULONG ulSF;
  1828.     PEID peid;
  1829.  
  1830.     MS_ValidateParameters(pims, IMsgStore_AbortSubmit);
  1831.  
  1832.     IMS_EnterCriticalSection(pims);
  1833.  
  1834.     peid = (PEID) lpEntryID;
  1835.  
  1836.     /* Note that we don't allow a NULL entryid here, because the root */
  1837.     /* folder is not a valid input to AbortSubmit. */
  1838.  
  1839.     if (FIsInvalidEID(cbEntryID, peid, pims)
  1840.         && !FIsMessage(peid))
  1841.     {
  1842.         hr = ResultFromScode(MAPI_E_INVALID_ENTRYID);
  1843.         goto exit;
  1844.     }
  1845.  
  1846.     /* unlock the message */
  1847.     /* make this store look like the spooler so we can open it if locked */
  1848.  
  1849.     if (!OBJ_TestFlag(pims, MSF_SPOOLER))
  1850.     {
  1851.         OBJ_SetFlag(pims, MSF_SPOOLER);
  1852.         fClearSpooler = TRUE;
  1853.     }
  1854.  
  1855.     hr = pims->lpVtbl->OpenEntry(pims, cbEntryID, lpEntryID,
  1856.         NULL, MAPI_MODIFY, &ulObjType, (LPUNKNOWN *) &pimsg);
  1857.     if (hr != hrSuccess)
  1858.         goto exit;
  1859.  
  1860.     /* If we can't get PR_SUBMIT_FLAGS from the message, then either */
  1861.     /* the message hasn't been submitted, or something else is broken. */
  1862.     /* In any case, we can't abort the submit. */
  1863.     /* If the message is locked already by the spooler, then we also */
  1864.     /* can't abort the submit. */
  1865.  
  1866.     hr = HrGetSingleProp((LPMAPIPROP) pimsg, &pims->lmr, PR_SUBMIT_FLAGS, &ulSF);
  1867.     if ((hr != hrSuccess) || (ulSF & SUBMITFLAG_LOCKED))
  1868.     {
  1869.         hr = ResultFromScode(MAPI_E_UNABLE_TO_ABORT);
  1870.         goto exit;
  1871.     }
  1872.  
  1873.     hr = HrSetFlags(pimsg, UNSET, PR_MESSAGE_FLAGS, MSGFLAG_SUBMIT);
  1874.     if (hr != hrSuccess)
  1875.         goto exit;
  1876.  
  1877.     hr = HrSetFlags(pimsg, UNSET, PR_SUBMIT_FLAGS, SUBMITFLAG_LOCKED);
  1878.     if (hr != hrSuccess)
  1879.         goto exit;
  1880.  
  1881.     hr = pimsg->lpVtbl->SaveChanges(pimsg, KEEP_OPEN_READWRITE);
  1882.     if (hr != hrSuccess)
  1883.         goto exit;
  1884.  
  1885.     hr = HrUpdateOutgoingQueue(pims, NULL, (PEID) lpEntryID,
  1886.         TABLE_ROW_DELETED);
  1887.  
  1888. exit:
  1889.     UlRelease(pimsg);
  1890.  
  1891.     if (fClearSpooler)
  1892.         OBJ_ClearFlag(pims, MSF_SPOOLER);
  1893.  
  1894.     IMS_LeaveCriticalSection(pims);
  1895.  
  1896.     DebugTraceResult(IMS_AbortSubmit, hr);
  1897.     return HrCheckHr(hr, IMsgStore_AbortSubmit);
  1898. }
  1899.  
  1900. /*
  1901.  *  IMS_GetOutgoingQueue
  1902.  *
  1903.  *  Purpose:
  1904.  *      Returns a MAPI Table Object of the queue of messages
  1905.  *      waiting to be sent.
  1906.  *
  1907.  *  Arguments:
  1908.  *      pims        Pointer to a Spooler Message Store Object.
  1909.  *      ulFlags     Reserved for future use.  Must be zero.
  1910.  *      lppTable    Location to return the new table object.
  1911.  *
  1912.  *  Returns:
  1913.  *      HRESULT
  1914.  *
  1915.  *  Side effects:
  1916.  *      None.
  1917.  *
  1918.  *  Errors:
  1919.  *      None.
  1920.  */
  1921. STDMETHODIMP IMS_GetOutgoingQueue(PIMS pims, ULONG ulFlags,
  1922.     LPMAPITABLE *lppTable)
  1923. {
  1924.     SCODE sc = S_OK;
  1925.     HRESULT hr = hrSuccess;
  1926.     LPMAPITABLE ptbl = NULL;
  1927.     BOOL fInMutex = FALSE;
  1928.  
  1929.     MS_ValidateParameters(pims, IMsgStore_GetOutgoingQueue);
  1930.  
  1931.     IMS_EnterCriticalSection(pims);
  1932.  
  1933.     if (!OBJ_TestFlag(pims, MSF_SPOOLER))
  1934.     {
  1935.         hr = ResultFromScode(MAPI_E_NO_SUPPORT);
  1936.         goto exit;
  1937.     }
  1938.  
  1939.     /* If the file mutex doesn't yet exist on this process, create it. */
  1940.  
  1941.     if (pims->hOGQueueMutex == NULL)
  1942.     {
  1943.         hr = HrCreateOGQueueMutex(&pims->hOGQueueMutex);
  1944.         if (hr != hrSuccess)
  1945.             goto exit;
  1946.     }
  1947.  
  1948.     /* Get the file mutex so that we can use the file (and change it) */
  1949.     /* without crossing paths with another process. */
  1950.  
  1951.     WaitForSingleObject(pims->hOGQueueMutex, INFINITE);
  1952.     fInMutex = TRUE;
  1953.  
  1954.     /* Create a new table if there currently is none */
  1955.     if (pims->lptblOutgoing == NULL)
  1956.     {
  1957.         hr = HrNewOutgoingTableData(pims);
  1958.         if (hr != hrSuccess)
  1959.             goto exit;
  1960.     }
  1961.  
  1962.     /* open a view on the table */
  1963.     hr = pims->lptblOutgoing->lpVtbl->HrGetView(pims->lptblOutgoing,
  1964.         NULL, OutgoingViewRelease, (ULONG) pims, &ptbl);
  1965.     if (hr != hrSuccess)
  1966.         goto exit;
  1967.  
  1968.     pims->cOutgoingViews++;
  1969.  
  1970.     *lppTable = ptbl;
  1971.  
  1972.     Assert(hrSuccess == hr);
  1973.  
  1974. exit:
  1975.     AssertSz(hr == hrSuccess || HR_FAILED(hr),
  1976.         "Unexpected warning return");
  1977.  
  1978.     if (fInMutex)
  1979.         ReleaseMutex(pims->hOGQueueMutex);
  1980.  
  1981.     IMS_LeaveCriticalSection(pims);
  1982.  
  1983.     DebugTraceResult(IMS_GetOutgoingQueue, hr);
  1984.     return HrCheckHr(hr, IMsgStore_GetOutgoingQueue);
  1985. }
  1986.  
  1987. /*
  1988.  *  IMS_SetLockState
  1989.  *
  1990.  *  Purpose:
  1991.  *      Allows the spooler to lock a message so that no one else
  1992.  *      can modify it while the spooler processes it.
  1993.  *
  1994.  *  Arguments:
  1995.  *      pims        Pointer to the Message Store Object.
  1996.  *      lpMessage   The message object to be locked
  1997.  *      ulFlags     control flags
  1998.  *
  1999.  *  Returns:
  2000.  *      HRESULT
  2001.  *
  2002.  *  Side effects:
  2003.  *      None.
  2004.  *
  2005.  *  Errors:
  2006.  *      None.
  2007.  */
  2008. STDMETHODIMP IMS_SetLockState(PIMS pims, LPMESSAGE lpMessage, ULONG ulFlags)
  2009. {
  2010.     SCODE sc = S_OK;
  2011.     HRESULT hr = hrSuccess;
  2012.     PIMSG pimsg = (PIMSG) lpMessage;
  2013.     ULONG ulSF;
  2014.     LPSPropValue pval = NULL;
  2015.  
  2016.     MS_ValidateParameters(pims, IMsgStore_SetLockState);
  2017.  
  2018.     IMS_EnterCriticalSection(pims);
  2019.  
  2020.     if (!OBJ_TestFlag(pims, MSF_SPOOLER))
  2021.     {
  2022.         hr = ResultFromScode(MAPI_E_NO_SUPPORT);
  2023.         goto exit;
  2024.     }
  2025.  
  2026.     hr = HrGetSingleProp((LPMAPIPROP) pimsg, &pims->lmr, PR_SUBMIT_FLAGS, &ulSF);
  2027.     if (hr != hrSuccess)
  2028.     {
  2029.         if (GetScode(hr) == MAPI_E_NOT_FOUND)
  2030.         {
  2031.             ULONG ulMF;
  2032.  
  2033.             hr = HrGetSingleProp((LPMAPIPROP) pimsg, &pims->lmr, PR_MESSAGE_FLAGS, &ulMF);
  2034.             if (hr != hrSuccess)
  2035.             {
  2036.                 if (GetScode(hr) == MAPI_E_NOT_FOUND)
  2037.                     hr = ResultFromScode(MAPI_E_CORRUPT_STORE);
  2038.  
  2039.                 goto exit;
  2040.             }
  2041.  
  2042.             if (ulMF & MSGFLAG_SUBMIT)
  2043.                 hr = ResultFromScode(MAPI_E_CORRUPT_STORE);
  2044.             else
  2045.                 hr = ResultFromScode(MAPI_E_NOT_IN_QUEUE);
  2046.         }
  2047.         goto exit;
  2048.     }
  2049.  
  2050.     /* set the lock state, if the message is already in the correct state */
  2051.     /* just get outta here */
  2052.  
  2053.     if (ulFlags & MSG_LOCKED)
  2054.     {
  2055.         if (!(ulSF & SUBMITFLAG_LOCKED))
  2056.             ulSF |= SUBMITFLAG_LOCKED;
  2057.         else
  2058.             goto exit;
  2059.     }
  2060.     else
  2061.         /* unlock */
  2062.     {
  2063.         if (ulSF & SUBMITFLAG_LOCKED)
  2064.             ulSF &= ~SUBMITFLAG_LOCKED;
  2065.         else
  2066.             goto exit;
  2067.     }
  2068.  
  2069.     hr = HrSetSingleProp((LPMAPIPROP) pimsg, &pims->lmr, PR_SUBMIT_FLAGS, &ulSF);
  2070.     if (hr != hrSuccess)
  2071.         goto exit;
  2072.  
  2073.     hr = pimsg->lpVtbl->SaveChanges(pimsg, KEEP_OPEN_READWRITE);
  2074.     if (hr != hrSuccess)
  2075.         goto exit;
  2076.  
  2077.     /* No need to call ChangeTable to update tables because the SaveChanges
  2078.      * call above just did that.
  2079.      */
  2080.  
  2081. exit:
  2082.     IMS_LeaveCriticalSection(pims);
  2083.  
  2084.     DebugTraceResult(IMS_SetLockState, hr);
  2085.     return HrCheckHr(hr, IMsgStore_SetLockState);
  2086. }
  2087.  
  2088. /*
  2089.  *  IMS_FinishedMsg
  2090.  *
  2091.  *  Purpose:
  2092.  *      Allows the Spooler to inform the message store that it has
  2093.  *      finished processing a message (cancels a previous
  2094.  *      MDBLockMsg).
  2095.  *
  2096.  *  Arguments:
  2097.  *      pims        Pointer to a Message Store Object.
  2098.  *      ulFlags     Reserved for future use.  Ignored.
  2099.  *      lpEntryID   EntryID of message that was locked.
  2100.  *
  2101.  *  Returns:
  2102.  *      HRESULT
  2103.  *
  2104.  *  Side effects:
  2105.  *      None.
  2106.  *
  2107.  *  Errors:
  2108.  *      None.
  2109.  */
  2110. STDMETHODIMP IMS_FinishedMsg(PIMS pims, ULONG ulFlags, ULONG cbEntryID,
  2111.     LPENTRYID lpEntryID)
  2112. {
  2113.     PIMSG pimsg = NULL;         /* opened message */
  2114.     PIFLD pifldParent = NULL;   /* parent folder of this message */
  2115.     ULONG ulObjectType;
  2116.     HRESULT hr = hrSuccess;
  2117.     SCODE sc = S_OK;
  2118.     PEID peid = (PEID) lpEntryID;
  2119.  
  2120.  
  2121.     MS_ValidateParameters(pims, IMsgStore_FinishedMsg);
  2122.  
  2123.     IMS_EnterCriticalSection(pims);
  2124.  
  2125.     if (!OBJ_TestFlag(pims, MSF_SPOOLER))
  2126.     {
  2127.         hr = ResultFromScode(MAPI_E_NO_SUPPORT);
  2128.         goto exit;
  2129.     }
  2130.  
  2131.     if (FIsInvalidEID(cbEntryID, peid, pims))
  2132.     {
  2133.         hr = ResultFromScode(MAPI_E_INVALID_ENTRYID);
  2134.         goto exit;
  2135.     }
  2136.  
  2137.     hr = pims->lpVtbl->OpenEntry(pims, cbEntryID, lpEntryID,
  2138.         NULL, MAPI_MODIFY, &ulObjectType, (LPUNKNOWN *) &pimsg);
  2139.     if (hr != hrSuccess)
  2140.         goto exit;
  2141.  
  2142.     Assert(ulObjectType == MAPI_MESSAGE);
  2143.  
  2144.     /* update the parent folder */
  2145.     hr = HrOpenParent(pims, peid, MAPI_MODIFY, &pifldParent);
  2146.     if (hr != hrSuccess)
  2147.         goto exit;
  2148.  
  2149.     /* unlock the message */
  2150.     hr = HrSetFlags(pimsg, UNSET, PR_MESSAGE_FLAGS,
  2151.         MSGFLAG_UNSENT | MSGFLAG_SUBMIT);
  2152.     if (hr != hrSuccess)
  2153.         goto exit;
  2154.  
  2155.     /* Mark the message read */
  2156.     hr = HrSetFlags(pimsg, SET, PR_MESSAGE_FLAGS, MSGFLAG_READ);
  2157.     if (hr != hrSuccess)
  2158.         goto exit;
  2159.  
  2160.     /* Clear submitflag_locked and save the message */
  2161.     hr = HrSetFlags(pimsg, UNSET, PR_SUBMIT_FLAGS, SUBMITFLAG_LOCKED);
  2162.     if (hr != hrSuccess)
  2163.         goto exit;
  2164.  
  2165.     hr = pimsg->lpVtbl->SaveChanges(pimsg, KEEP_OPEN_READWRITE);
  2166.     if (hr != hrSuccess)
  2167.         goto exit;
  2168.  
  2169.     hr = pims->psup->lpVtbl->DoSentMail(pims->psup, 0L, (LPMESSAGE) pimsg);
  2170.     if (hr != hrSuccess)
  2171.         goto exit;
  2172.     pimsg = NULL;
  2173.  
  2174.     Assert(pims->lptblOutgoing);
  2175.  
  2176.     hr = HrUpdateOutgoingQueue(pims, NULL, (PEID) lpEntryID,
  2177.         TABLE_ROW_DELETED);
  2178.  
  2179. exit:
  2180.     UlRelease(pifldParent);
  2181.     UlRelease(pimsg);
  2182.  
  2183.     IMS_LeaveCriticalSection(pims);
  2184.  
  2185.     DebugTraceResult(IMS_FinishedMsg, hr);
  2186.     return HrCheckHr(hr, IMsgStore_FinishedMsg);
  2187. }
  2188.  
  2189. /*
  2190.  *  IMS_NotifyNewMail
  2191.  *
  2192.  *  Purpose:
  2193.  *      Spooler tells us when to tell clients about a new message.
  2194.  *      Passed in on the call is the exact notification structure
  2195.  *      we need to give the client.
  2196.  *
  2197.  *      Stubbed for now.
  2198.  *
  2199.  *  Arguments:
  2200.  *      pims        Pointer to the object.
  2201.  *      pntf        Pointer to the newmail notification structure.
  2202.  *                                      read/write.
  2203.  *
  2204.  *  Returns:
  2205.  *      HRESULT
  2206.  *
  2207.  *  Side effects:
  2208.  *      None.
  2209.  *
  2210.  *  Errors:
  2211.  *      None.
  2212.  */
  2213. STDMETHODIMP IMS_NotifyNewMail(PIMS pims, LPNOTIFICATION pntf)
  2214. {
  2215.     HRESULT hr = hrSuccess;
  2216.     LPNOTIFKEY lpKey = NULL;
  2217.     ULONG ulFlags = 0;
  2218.     PEID peidMsg;
  2219.     PEID peidFld;
  2220.     ULONG cbEIDMsg;
  2221.     ULONG cbEIDFld;
  2222.  
  2223.     MS_ValidateParameters(pims, IMsgStore_NotifyNewMail);
  2224.  
  2225.     IMS_EnterCriticalSection(pims);
  2226.  
  2227.     if (!OBJ_TestFlag(pims, MSF_SPOOLER))
  2228.     {
  2229.         hr = ResultFromScode(MAPI_E_NO_SUPPORT);
  2230.         goto exit;
  2231.     }
  2232.  
  2233.     if (!pims->psup)
  2234.     {
  2235.         hr = ResultFromScode(MAPI_E_CALL_FAILED);
  2236.         goto exit;
  2237.     }
  2238.  
  2239.     cbEIDMsg = pntf->info.newmail.cbEntryID;
  2240.     peidMsg = (PEID) pntf->info.newmail.lpEntryID;
  2241.  
  2242.     cbEIDFld = pntf->info.newmail.cbParentID;
  2243.     peidFld = (PEID) pntf->info.newmail.lpParentID;
  2244.  
  2245.     if (    cbEIDMsg == 0
  2246.         ||  FIsInvalidEID(cbEIDMsg, peidMsg, pims)
  2247.         ||  !FIsMessage(peidMsg)
  2248.         ||  cbEIDFld == 0
  2249.         ||  FIsInvalidEID(cbEIDFld, peidFld, pims)
  2250.         ||  !FIsFolder(peidFld))
  2251.     {
  2252.         TraceSz("SMS: Bad entryid given to NotifyNewMail");
  2253.         hr = ResultFromScode(MAPI_E_INVALID_ENTRYID);
  2254.         goto exit;
  2255.     }
  2256.  
  2257.     /* Generate the key we use for notifications. First, get the key */
  2258.     /* for the folder that the message arrived into. */
  2259.  
  2260.     hr = HrGetSMSStandardNotifKey(pims, peidFld, &lpKey);
  2261.     if (hr != hrSuccess)
  2262.         goto exit;
  2263.  
  2264.     hr = pims->psup->lpVtbl->Notify(pims->psup, lpKey, 1, pntf, &ulFlags);
  2265.     if (hr != hrSuccess)
  2266.         goto exit;
  2267.     
  2268.     FreeNull(lpKey);
  2269.     lpKey = NULL;
  2270.     ulFlags = 0;
  2271.  
  2272.     /* Now, get the key for the entire store, and send to that key also. */
  2273.  
  2274.     hr = HrGetSMSStandardNotifKey(pims, NULL, &lpKey);
  2275.     if (hr != hrSuccess)
  2276.         goto exit;
  2277.  
  2278.     hr = pims->psup->lpVtbl->Notify(pims->psup, lpKey, 1, pntf, &ulFlags);
  2279.     if (hr != hrSuccess)
  2280.         goto exit;
  2281.  
  2282. exit:
  2283.     FreeNull(lpKey);
  2284.  
  2285.     IMS_LeaveCriticalSection(pims);
  2286.  
  2287.     DebugTraceResult(IMS_NotifyNewMail, hr);
  2288.     return HrCheckHr(hr, IMsgStore_NotifyNewMail);
  2289. }
  2290.  
  2291. /* Internal Functions */
  2292.  
  2293. BOOL IMS_IsInvalid(PIMS pims)
  2294. {
  2295.     return (IsBadWritePtr(pims, sizeof(IMS)) || pims->lpVtbl != &vtblIMS);
  2296. }
  2297.  
  2298. /***************************************************************************
  2299.  -  OutgoingViewRelease
  2300.  -
  2301.  *  Purpose:
  2302.  *      Call back function from itable on release of a view
  2303.  *      removes the view from the list of open views
  2304.  *      releases the table if there are no more open views on it
  2305.  *
  2306.  *  Arguments:
  2307.  *       ulCallerData   pointer to folder object
  2308.  *       lptbl      pointer to the table on which this is a view
  2309.  *       lpvtView       pointer to the view that was released
  2310.  *
  2311.  *
  2312.  */
  2313. STDAPI_(void) OutgoingViewRelease(ULONG ulCallerData, LPTABLEDATA lptbl,
  2314.     LPMAPITABLE lpvtView)
  2315. {
  2316.     PIMS pims;                  /* store who owns this view */
  2317.     ULONG ulViewsLeft;          /* number of open views left */
  2318.  
  2319.     pims = (PIMS) ulCallerData;
  2320.  
  2321.     /* do nothing if the message store is gone */
  2322.     if (IMS_IsInvalid(pims))
  2323.         return;
  2324.  
  2325.     IMS_EnterCriticalSection(pims);
  2326.  
  2327.     AssertSz(pims->lptblOutgoing == lptbl,
  2328.         "Different table data given to OutgoingViewRelease");
  2329.  
  2330.     ulViewsLeft = --(pims->cOutgoingViews);
  2331.  
  2332.     /* release the table data if the viewlist is empty */
  2333.     if (ulViewsLeft == 0)
  2334.     {
  2335.         UlRelease(lptbl);
  2336.         pims->lptblOutgoing = NULL;
  2337.     }
  2338.  
  2339.     IMS_LeaveCriticalSection(pims);
  2340.  
  2341.     return;
  2342. }
  2343.  
  2344. /*
  2345.  *  HrNewIMS
  2346.  *
  2347.  *  Purpose:
  2348.  *      Allocates and initializes an IMS object (internal
  2349.  *      implementation of IMsgStore).
  2350.  *
  2351.  *  Arguments:
  2352.  *      szStorePath         Path name of directory which is the
  2353.  *                          "root" of this message store.
  2354.  *      szStoreProps        Filename of IMsgStore properties
  2355.  *                          docfile in the store root.
  2356.  *      pmsp                pointer to the MS provider object.
  2357.  *      pmsl                Pointer to the MS logon object given to
  2358.  *                          MAPI when this store is created.
  2359.  *      prfs                Pointer to a context for accessing
  2360.  *                          receive folder settings.
  2361.  *      pps                 pointer to our profile section.
  2362.  *      psup                Pointer to MAPI Support Object.
  2363.  *      fCreate             TRUE if the function should create the docfile
  2364.  *                          containing IMS properties (FALSE opens existing).
  2365.  *      ppims               Location to return the address of the
  2366.  *                          newly created IMS object.
  2367.  *
  2368.  *  Returns:
  2369.  *      HRESULT
  2370.  *
  2371.  *  Side effects:
  2372.  *      Does AddRef() of support object.
  2373.  *
  2374.  *  Errors:
  2375.  *      MAPI_E_NOT_ENOUGH_MEMORY    Could not allocate memory for
  2376.  *                                  the object.
  2377.  */
  2378. HRESULT HrNewIMS(LPTSTR szStorePath, LPTSTR szStoreProps, PMSP pmsp, PMSL pmsl,
  2379.     PRFS prfs, LPPROFSECT pps, LPMAPISUP psup, BOOL fCreate, PIMS *ppims)
  2380. {
  2381.     SCODE sc = S_OK;
  2382.     HRESULT hr;
  2383.     HRESULT hrStg = hrSuccess;
  2384.     LPTSTR szPropFull = NULL;
  2385.     PIMS pimsNew = NULL;
  2386.     PEID peid = NULL;
  2387.     LPMESSAGE lpmsg = NULL;
  2388.     BOOL fDoneCreate = FALSE;
  2389.     LPMSGSESS pmsgsess = NULL;
  2390.     LPSPropValue pvalDLLName = NULL;
  2391.  
  2392.     AssertSz(szStorePath, "Bad szStorePath");
  2393.     AssertSz(szStoreProps, "Bad szStoreProps");
  2394.     AssertSz(pmsl, "Bad pmsl");
  2395.     AssertSz(prfs, "Bad prfs");
  2396.     AssertSz(ppims, "Bad ppims");
  2397.  
  2398.     *ppims = NULL;
  2399.  
  2400.     /* Begin by creating or opening the message store's property file. */
  2401.     /* This implementation of the sample message store puts its message */
  2402.     /* store properties in a file called MSGSTORE.PRP in the root folder */
  2403.     /* of the store. If we're opening an existing store, then we'll read */
  2404.     /* PR_RECORD_KEY from this file below. If we're creating the file, we */
  2405.     /* don't actually use it in this function; however, we still need to */
  2406.     /* create the file. */
  2407.  
  2408.     hr = HrOpenIMsgSession(&pmsgsess);
  2409.     if (hr != hrSuccess)
  2410.         goto hr_err;
  2411.  
  2412.     hr = HrAppendPath(szStorePath, szStoreProps, &szPropFull);
  2413.     if (hr != hrSuccess)
  2414.         goto hr_err;
  2415.     
  2416.     hr = HrOpenIMsg(pmsgsess, szPropFull, &pmsp->lmr, psup, fCreate, FALSE,
  2417.         TRUE, &lpmsg);
  2418.     if (hr != hrSuccess)
  2419.         goto hr_err;
  2420.  
  2421.     if (fCreate)
  2422.         fDoneCreate = TRUE;
  2423.  
  2424.     /* Allocate and fill in the new object. */
  2425.  
  2426.     sc = LMAllocZ(&pmsp->lmr, sizeof(IMS), &pimsNew);
  2427.     if (sc != S_OK)
  2428.         goto sc_err;
  2429.  
  2430.     OBJ_Initialize(pimsNew, &vtblIMS, OT_MSGSTORE, pimsNew, &pmsl->cs);
  2431.  
  2432.     pimsNew->pmsl = pmsl;
  2433.     pimsNew->pmsp = pmsp;
  2434.     pimsNew->prfs = prfs;
  2435.     pimsNew->psup = psup;
  2436.     pimsNew->lmr = pmsl->lmr;
  2437.     pimsNew->eidStore.cb = 0L;
  2438.     pimsNew->eidStore.lpb = NULL;
  2439.     pimsNew->lptblOutgoing = NULL;
  2440.     pimsNew->cOutgoingViews = 0L;
  2441.     pimsNew->ulOQConn = 0L;
  2442.     pimsNew->ulTblConn = 0L;
  2443.     pimsNew->pmsgsess = pmsgsess;
  2444.     pimsNew->ulFlagsSLT = LOGOFF_ABORT;
  2445.  
  2446.     sc = ScAlloc(Cbtszsize(szStorePath), (PPV) &pimsNew->szStorePath);
  2447.     if (sc != S_OK)
  2448.         goto sc_err;
  2449.  
  2450.     lstrcpy(pimsNew->szStorePath, szStorePath);
  2451.  
  2452.     pimsNew->szProps = szPropFull;
  2453.  
  2454.     /* Fill in the uidResource.
  2455.      * This is used as the PR_STORE_RECORD_KEY and
  2456.      * as the UID contained in EntryIDs.
  2457.      */
  2458.     if (fCreate)
  2459.     {
  2460.         hr = psup->lpVtbl->NewUID(psup, &pimsNew->uidResource);
  2461.         if (hr != hrSuccess)
  2462.             goto hr_err;
  2463.     }
  2464.     else
  2465.     {
  2466.         LPSPropValue pval;
  2467.  
  2468.         /* Read out the PR_RECORD_KEY from the store.   */
  2469.         /* DO NOT READ THE PR_STORE_RECORD_KEY as that  */
  2470.         /* gets wrapped back to pimsNew->uidResource and    */
  2471.         /* HAS NOT BEEN FILLED IN YET!                      */
  2472.  
  2473.         hr = HrGetOneProp((LPMAPIPROP) lpmsg, PR_RECORD_KEY, &pval);
  2474.         if (hr != hrSuccess)
  2475.             goto hr_err;
  2476.  
  2477.         AssertSz(pval[0].Value.bin.cb == sizeof(MAPIUID),
  2478.             "Corrupted data returned from GetProps");
  2479.  
  2480.         pimsNew->uidResource = *((LPMAPIUID) pval[0].Value.bin.lpb);
  2481.  
  2482.         LMFree(&pmsp->lmr, pval);
  2483.     }
  2484.  
  2485.     /* Generate the PR_STORE_ENTRYID property in memory. */
  2486.  
  2487.     hr = HrConstructEID(&pimsNew->uidResource, &pmsp->lmr,
  2488.             pimsNew->szStorePath, &peid);
  2489.     if (hr != hrSuccess)
  2490.         goto hr_err;
  2491.  
  2492.     hr = HrGetOneProp((LPMAPIPROP)pps, PR_PROVIDER_DLL_NAME, &pvalDLLName);
  2493.     if (hr != hrSuccess)
  2494.         goto hr_err;
  2495.  
  2496.     hr = WrapStoreEntryID(0, pvalDLLName->Value.lpszA, CbEID(peid),
  2497.             (LPENTRYID)peid, &pimsNew->eidStore.cb,
  2498.             (LPENTRYID *) &pimsNew->eidStore.lpb);
  2499.     if (hr != hrSuccess)
  2500.         goto hr_err;
  2501.  
  2502. sc_err:
  2503.     if (sc != S_OK)
  2504.         hr = ResultFromScode(sc);
  2505.  
  2506. hr_err:
  2507.     LMFree(&pmsp->lmr, pvalDLLName);
  2508.     UlRelease(lpmsg);
  2509.     LMFree(&pmsp->lmr, peid);
  2510.  
  2511.     if (hr != hrSuccess)
  2512.     {
  2513.         if (fDoneCreate)
  2514.             DeleteFile(szPropFull);
  2515.  
  2516.         FreeNull(szPropFull);
  2517.         if (pimsNew)
  2518.         {
  2519.             FreeNull(pimsNew->szStorePath);
  2520.             LMFree(&pmsp->lmr, pimsNew->eidStore.lpb);
  2521.             LMFree(&pmsp->lmr, pimsNew);
  2522.         }
  2523.  
  2524.         if (pmsgsess)
  2525.             CloseIMsgSession(pmsgsess);
  2526.     }
  2527.     else
  2528.     {
  2529.         /* SUCCESS! */
  2530.         *ppims = pimsNew;
  2531.     }
  2532.  
  2533.     DebugTraceResult(HrNewIMS, hr);
  2534.     return hr;
  2535. }
  2536.  
  2537. /*
  2538.  *  HrInitIMSProps
  2539.  *
  2540.  *  Purpose:
  2541.  *      Sets the initial (and for read-only properties, the only)
  2542.  *      values for the base properties of the Message Store Object:
  2543.  *      takes as input parameters the values of those properties
  2544.  *      that are specific to this store and calculates (hard-coded)
  2545.  *      the values of those properties that are the same for all
  2546.  *      stores created by the Microsoft Sample Store Provider.
  2547.  *      Also sets attributes.
  2548.  *
  2549.  *  Arguments:
  2550.  *      pims        Internal IMsgStore object instance.
  2551.  *      szPswd      Logon Account Password.
  2552.  *
  2553.  *  Returns:
  2554.  *      HRESULT
  2555.  *
  2556.  *  Side effects:
  2557.  *      None.
  2558.  *
  2559.  *  Errors:
  2560.  *      MAPI_E_NOT_ENOUGH_MEMORY    Could not allocate space for
  2561.  *                                  the property arrays.
  2562.  */
  2563. HRESULT HrInitIMSProps(PIMS pims, LPTSTR szPswd)
  2564. {
  2565.     HRESULT hr;
  2566.     LPMESSAGE lpmsg = NULL;
  2567.     LPSPropValue pval = NULL;
  2568.     LPSPropProblemArray pprba = NULL;
  2569.     LPSPropTagArray ptaga = NULL;
  2570.     LPSPropAttrArray patra = NULL;
  2571.     SCODE sc = S_OK;
  2572.  
  2573. #define cInitIMSProps       10
  2574. #define grfInitIMSProps     ( PROPATTR_MANDATORY | PROPATTR_READABLE )
  2575.  
  2576.     AssertSz(pims, "Bad pims");
  2577.     NFAssertSz(pims->psup, "Bad support object");
  2578.     AssertSz(szPswd, "Bad szPswd");
  2579.  
  2580.     hr = HrOpenIMSPropsFileRetry(pims->pmsgsess, pims->szProps, &pims->lmr,
  2581.         pims->psup, TRUE, &lpmsg);
  2582.     if (hr != hrSuccess)
  2583.         goto exit;
  2584.  
  2585.     /* Allocate the property arrays. */
  2586.     hr = HrAllocPropArrays(cInitIMSProps, &pval, &ptaga, &patra);
  2587.     if (hr != hrSuccess)
  2588.         goto exit;
  2589.  
  2590.     /* Initialize property value array and all property tags. */
  2591.  
  2592.     ptaga->cValues = patra->cValues = cInitIMSProps;
  2593.  
  2594.     pval[0].ulPropTag = ptaga->aulPropTag[0] = PR_STORE_ENTRYID;
  2595.     pval[0].Value.bin.cb = pims->eidStore.cb;
  2596.     pval[0].Value.bin.lpb = pims->eidStore.lpb;
  2597.     pval[1].ulPropTag = ptaga->aulPropTag[1] = PR_STORE_RECORD_KEY;
  2598.     pval[1].Value.bin.cb = sizeof(pims->uidResource);
  2599.     pval[1].Value.bin.lpb = (LPBYTE) &pims->uidResource;
  2600.     pval[2].ulPropTag = ptaga->aulPropTag[2] = PR_ENTRYID;
  2601.     pval[2].Value.bin.cb = pims->eidStore.cb;
  2602.     pval[2].Value.bin.lpb = pims->eidStore.lpb;
  2603.     pval[3].ulPropTag = ptaga->aulPropTag[3] = PR_RECORD_KEY;
  2604.     pval[3].Value.bin.cb = sizeof(pims->uidResource);
  2605.     pval[3].Value.bin.lpb = (LPBYTE) &pims->uidResource;
  2606.     pval[4].ulPropTag = ptaga->aulPropTag[4] = PR_DISPLAY_NAME;
  2607.     pval[4].Value.LPSZ = pims->szStorePath;
  2608.     pval[5].ulPropTag = ptaga->aulPropTag[5] = PR_SMS_PASSWORD;
  2609.     pval[5].Value.LPSZ = szPswd;
  2610.  
  2611.     /* We don't set support properties that are changed by READONLY */
  2612.     /* when the store is open. Those are or'ed in during GetProps. */
  2613.     /* See HrWrap_GetProps for details. */
  2614.  
  2615.     pval[6].ulPropTag = ptaga->aulPropTag[6] = PR_STORE_SUPPORT_MASK;
  2616.     pval[6].Value.ul =
  2617.         STORE_ENTRYID_UNIQUE |
  2618.         STORE_ATTACH_OK |
  2619.         STORE_OLE_OK |
  2620.         STORE_NOTIFY_OK |
  2621.         STORE_MV_PROPS_OK |
  2622.         STORE_RESTRICTION_OK |
  2623.         STORE_SORT_OK;
  2624.  
  2625.     pval[7].ulPropTag = ptaga->aulPropTag[7] = PR_OBJECT_TYPE;
  2626.     pval[7].Value.l = MAPI_STORE;
  2627.     pval[8].ulPropTag = ptaga->aulPropTag[8] = PR_FILENAME_SEQUENCE_NUMBER;
  2628.     pval[8].Value.ul = 0x10000000;
  2629.     pval[9].ulPropTag = ptaga->aulPropTag[9] = PR_MDB_PROVIDER;
  2630.     pval[9].Value.bin.cb = sizeof(MAPIUID);
  2631.     pval[9].Value.bin.lpb = (LPBYTE) &uidProvider;
  2632.  
  2633.     /* Initialize the property attribute array. */
  2634.  
  2635.     patra->aPropAttr[0] = grfInitIMSProps;
  2636.     patra->aPropAttr[1] = grfInitIMSProps;
  2637.     patra->aPropAttr[2] = grfInitIMSProps;
  2638.     patra->aPropAttr[3] = grfInitIMSProps;
  2639.     patra->aPropAttr[4] = grfInitIMSProps | PROPATTR_WRITEABLE;
  2640.     patra->aPropAttr[5] = grfInitIMSProps;
  2641.     patra->aPropAttr[6] = grfInitIMSProps;
  2642.     patra->aPropAttr[7] = grfInitIMSProps;
  2643.     patra->aPropAttr[8] = grfInitIMSProps;
  2644.     patra->aPropAttr[9] = grfInitIMSProps;
  2645.  
  2646.     /* Set the property values. */
  2647.  
  2648.     hr = lpmsg->lpVtbl->SetProps(lpmsg, cInitIMSProps, pval, &pprba);
  2649.     if (hr != hrSuccess || pprba)
  2650.         goto exit;
  2651.  
  2652.     /* Set the property attributes. */
  2653.  
  2654.     hr = SetAttribIMsgOnIStg(lpmsg, ptaga, patra, &pprba);
  2655.     if (hr != hrSuccess || pprba)
  2656.         goto exit;
  2657.  
  2658.     /* If we succeeded up to this point, commit the properties. */
  2659.  
  2660.     hr = lpmsg->lpVtbl->SaveChanges(lpmsg, KEEP_OPEN_READWRITE);
  2661.     if (hr != hrSuccess)
  2662.         goto exit;
  2663.  
  2664. exit:
  2665.     AssertSz(hr == hrSuccess || HR_FAILED(hr), "No Warnings expected");
  2666.  
  2667.     if (pprba)
  2668.     {
  2669.         LMFree(&pims->lmr, pprba);
  2670.         hr = ResultFromScode(MAPI_E_CALL_FAILED);
  2671.     }
  2672.  
  2673.     FreePropArrays(&pval, &ptaga, &patra);
  2674.  
  2675.     UlRelease(lpmsg);
  2676.  
  2677.     DebugTraceResult(InitIMSProps, hr);
  2678.     return hr;
  2679. }
  2680.  
  2681. /*
  2682.  *  GetResourceUID
  2683.  *
  2684.  *  Purpose:
  2685.  *      Returns the one UID that identifies this MAPI resource
  2686.  *      (message store).
  2687.  *
  2688.  *  Arguments:
  2689.  *      pims    Internal IMsgStore object instance.
  2690.  *      lpuid   Location in which to return the value of the
  2691.  *              Resource UID.
  2692.  *
  2693.  *  Returns:
  2694.  *      VOID
  2695.  *
  2696.  *  Side effects:
  2697.  *      None.
  2698.  *
  2699.  *  Errors:
  2700.  *      None.
  2701.  */
  2702. VOID GetResourceUID(PIMS pims, LPMAPIUID lpuid)
  2703. {
  2704.     AssertSz(pims, "Bad pims");
  2705.     AssertSz(lpuid, "Bad lpuid");
  2706.  
  2707.     *lpuid = pims->uidResource;
  2708.  
  2709.     return;
  2710. }
  2711.  
  2712. /*********************************************************
  2713.  * FIsInvalidEID
  2714.  *
  2715.  *  Purpose         check if the peid points to an invalid EID
  2716.  *                  Returns TRUE if it is invalid. This routine
  2717.  *                  considers EIDs of length 0 invalid.
  2718.  *
  2719.  *  Parameter
  2720.  *      cb          number of bytes believed to be in peid
  2721.  *      peid        pointer to the entryid
  2722.  *      pims        store in which the object should be. May be NULL,
  2723.  *                  in which case, no check of the uid is performed.
  2724.  */
  2725. BOOL FIsInvalidEID(ULONG cb, PEID peid, PIMS pims)
  2726. {
  2727.     BOOL fInvalid;
  2728.  
  2729.     fInvalid = (cb < CbNewEID(0)
  2730.         || cb > CbNewEID(MAX_PATH)
  2731.         || IsBadReadPtr(peid, (UINT) cb)
  2732.         || IsBadStringPtr(peid->szPath, (UINT) -1)
  2733.         || cb != CbEID(peid)
  2734.         || peid->bVersion != SMPMS_VERSION);
  2735.  
  2736.     /* If the eid still looks good, and we were given the message store */
  2737.     /* object, then do one final check of the uid in the eid versus the */
  2738.     /* uid of the store. */
  2739.  
  2740.     if (!fInvalid && pims)
  2741.     {
  2742.         MAPIUID uid;
  2743.  
  2744.         GetResourceUID(pims, &uid);
  2745.         fInvalid = !IsEqualMAPIUID(&uid, &peid->uidResource);
  2746.     }
  2747.  
  2748.     return fInvalid;
  2749. }
  2750.  
  2751. /*
  2752.  *  HrUniqueFileName
  2753.  *
  2754.  *  Purpose:
  2755.  *      Returns a unique file name base that can be used by other
  2756.  *      parts of the store when a file needs to be created.  Gets
  2757.  *      the PR_FILENAME_SEQUENCE_NUMBER property out of the message
  2758.  *      store object, uses its textized form as the unique name,
  2759.  *      increments it, and stores it back in the object.  Sequence
  2760.  *      numbers begin at 0x10000000 and increment so that every
  2761.  *      file name returned is the same 8-character length.  (See
  2762.  *      HrInitIMSProps.)
  2763.  *
  2764.  *  Arguments:
  2765.  *      pims            Message Store Object.
  2766.  *      lpulSeqNumber   pointer to sequence number of this file name
  2767.  *      lppstrNewName   Location in which to return a pointer to a
  2768.  *                      buffer containing the unique file name.
  2769.  *
  2770.  *  Returns:
  2771.  *      HRESULT
  2772.  *
  2773.  *  Side effects:
  2774.  *      Increments the PR_FILENAME_SEQUENCE_NUMBER property of the
  2775.  *      message store object.
  2776.  *
  2777.  *  Errors:
  2778.  *      All SetProps and SaveChanges errors.  Also:
  2779.  *
  2780.  *      MAPI_E_NOT_ENOUGH_MEMORY    Could not allocate space for
  2781.  *                                  the return parameter.
  2782.  */
  2783. HRESULT HrUniqueFileName(PIMS pims, ULONG *lpulSeqNumber,
  2784.     LPTSTR *pszNewName)
  2785. {
  2786.     HRESULT hr = hrSuccess;
  2787.     LPTSTR szFileName = NULL;
  2788.     ULONG ulSeq = 0L;
  2789.     LPMESSAGE lpmsg = NULL;
  2790.  
  2791.     AssertSz(pims, "Bad pims");
  2792.     AssertSz(pszNewName, "Bad pszNewName");
  2793.  
  2794.     /* Allocate space for the return string */
  2795.  
  2796.     hr = HrAlloc((CCH_NAME - CCH_EXT) * sizeof(TCHAR), (PPV) &szFileName);
  2797.     if (hr != hrSuccess)
  2798.         goto exit;
  2799.  
  2800.     /* Get sequence number out of object, increment */
  2801.     /* sequence number, and turn it into a string.  */
  2802.  
  2803.     hr = HrGetSingleProp((LPMAPIPROP) pims, &pims->lmr,
  2804.         PR_FILENAME_SEQUENCE_NUMBER, &ulSeq);
  2805.     if (hr != hrSuccess)
  2806.         goto exit;
  2807.  
  2808.     ulSeq++;
  2809.  
  2810.     hr = HrOpenIMSPropsFileRetry(pims->pmsgsess, pims->szProps, &pims->lmr,
  2811.         pims->psup, TRUE, &lpmsg);
  2812.     if (hr != hrSuccess)
  2813.         goto exit;
  2814.  
  2815.     hr = HrSetOneROProp(lpmsg, &pims->lmr, PR_FILENAME_SEQUENCE_NUMBER, &ulSeq);
  2816.     if (hr != hrSuccess)
  2817.         goto exit;
  2818.  
  2819.     hr = lpmsg->lpVtbl->SaveChanges(lpmsg, KEEP_OPEN_READWRITE);
  2820.     if (hr != hrSuccess)
  2821.         goto exit;
  2822.  
  2823.     /* If this wsprintf statement changes, fix HrConvertSzToHex below. */
  2824.  
  2825.     wsprintf(szFileName, TEXT("%08lx"), ulSeq);
  2826.  
  2827.     *pszNewName = szFileName;
  2828.     *lpulSeqNumber = ulSeq;
  2829.  
  2830. exit:
  2831.     UlRelease(lpmsg);
  2832.  
  2833.     if (hr != hrSuccess)
  2834.         FreeNull(szFileName);
  2835.  
  2836.     DebugTraceResult(HrUniqueFileName, hr);
  2837.     return hr;
  2838. }
  2839.  
  2840. /*
  2841.  * HrConvertSzToHex
  2842.  *
  2843.  * Converts the string given into an equivalent number. The string must
  2844.  * contain characters in the range 0-9, A-F, or a-f. If the routine finds
  2845.  * characters outside these ranges in the string, it will terminate with
  2846.  * the error MAPI_E_CALL_FAILED. The string must be at least 8 characters
  2847.  * long (a 32-bit number is fully-specified by a 8 hex characters). The
  2848.  * routine will use only the first 8 characters in the string, even if the
  2849.  * string is longer than 8 characters. Note that only the first 8 characters
  2850.  * must be within the proper range. Characters after the first 8 will be
  2851.  * ignored.
  2852.  *
  2853.  * Parameters:
  2854.  *  szName: The string to convert.
  2855.  *  pulAnswer: A pointer to the location to return the converted answer.
  2856.  *
  2857.  * Errors:
  2858.  *  MAPI_E_CALL_FAILED -- when a character is out of range.
  2859.  */
  2860. static HRESULT HrConvertSzToHex(LPSTR szName, ULONG *pulAnswer)
  2861. {
  2862.     HRESULT hr = hrSuccess;
  2863.     CHAR *pch;
  2864.     CHAR *pchMax;
  2865.     ULONG ulAns = 0;
  2866.     ULONG ichConv = 0;
  2867.  
  2868.     /* String must be at least 8 hex chars long. It should have come from */
  2869.     /* the HrUniqueFileName function above, which uses wsprintf to generate */
  2870.     /* the string. */
  2871.  
  2872.     if (    IsBadStringPtr(szName, (UINT) -1)
  2873.         ||  lstrlen(szName) < 8)
  2874.     {
  2875.         TrapSz("Bad input to function");
  2876.         hr = ResultFromScode(MAPI_E_CALL_FAILED);
  2877.         goto exit;
  2878.     }
  2879.  
  2880.     pch = szName;
  2881.     pchMax = szName + lstrlen(szName);
  2882.  
  2883.     /* Only convert the first 8 characters, no matter how long the string is. */
  2884.     while(pch < pchMax && ichConv < 8)
  2885.     {
  2886.         ulAns <<= 4;
  2887.  
  2888.         if (*pch >= '0' && *pch <= '9')
  2889.             ulAns += (*pch - '0');
  2890.         else if (*pch >= 'a' && *pch <= 'f')
  2891.             ulAns += (*pch - 'a' + 0xA);
  2892.         else if (*pch >= 'A' && *pch <= 'F')
  2893.             ulAns += (*pch - 'A'+ 0xA);
  2894.         else
  2895.         {
  2896.             TraceSz2("SampleMS: HrConvertSztoHex: char %c(%#x) out of range.\n",
  2897.                 *pch, *pch);
  2898.             hr = ResultFromScode(MAPI_E_CALL_FAILED);
  2899.             goto exit;
  2900.         }
  2901.  
  2902.         ++pch;
  2903.         ++ichConv;
  2904.     }
  2905.  
  2906.     *pulAnswer = ulAns;
  2907.  
  2908. exit:
  2909.     DebugTraceResult(HrConvertSzToHex, hr);
  2910.     return hr;
  2911. }
  2912.  
  2913. /*
  2914.  * HrGetSequenceNum
  2915.  *
  2916.  * This routine takes a message eid and gets the
  2917.  * numerical equivalent of the base file name in the entryid. So, if the
  2918.  * base name of the message was "00000005.msg", the function would return
  2919.  * 0x00000005.
  2920.  *
  2921.  * Parameters:
  2922.  *  pimsg: the message object to update.
  2923.  *  pulSequenceNum: a pointer to the location to place the generated number.
  2924.  *
  2925.  */
  2926. static HRESULT HrGetSequenceNum(PEID peid, ULONG *pulSequenceNum)
  2927. {
  2928.     HRESULT hr;
  2929.     LPSTR szBaseName;
  2930.     ULONG ulSeqNum;
  2931.  
  2932.     szBaseName = SzBaseName(peid);
  2933.  
  2934.     hr = HrConvertSzToHex(szBaseName, &ulSeqNum);
  2935.     if (hr != hrSuccess)
  2936.         goto exit;
  2937.  
  2938.     *pulSequenceNum = ulSeqNum;
  2939.  
  2940. exit:
  2941.     DebugTraceResult(HrGetSequenceNum, hr);
  2942.     return hr;
  2943. }
  2944.  
  2945. /*
  2946.  *  IMS_NeuterChildren, IMS_Neuter
  2947.  *
  2948.  *  Purpose:
  2949.  *      Free all memory and resources associated with a logon.  We
  2950.  *      cannot, however, remove the critical section:  that must be
  2951.  *      done by the caller of this routine.
  2952.  *
  2953.  *  Arguments:
  2954.  *      pims            Pointer to the MS object.
  2955.  *
  2956.  *  Returns:
  2957.  *      None.
  2958.  *
  2959.  *  Side effects:
  2960.  *      None.
  2961.  *
  2962.  *  Errors:
  2963.  *      None.
  2964.  */
  2965. void IMS_NeuterChildren(POBJ pobj, int iLevel)
  2966. {
  2967. #ifdef DEBUG
  2968.     int i;
  2969.  
  2970.     DebugTrace("SMS:   ");
  2971.     for (i = 0; i < iLevel; ++i)
  2972.         DebugTrace("  ");
  2973.  
  2974.     switch (pobj->wType)
  2975.     {
  2976.     case OT_MSGSTORE:
  2977.         DebugTrace("IMsgStore (%s)", ((PIMS) pobj)->szStorePath);
  2978.         break;
  2979.     case OT_FOLDER:
  2980.         DebugTrace("IMAPIFolder");
  2981.         break;
  2982.     case OT_MESSAGE:
  2983.         DebugTrace("IMessage");
  2984.         break;
  2985.     case OT_ATTACH:
  2986.         DebugTrace("IAttach");
  2987.         break;
  2988.     case OT_STREAM:
  2989.         DebugTrace("IStream");
  2990.         break;
  2991.     }
  2992.     DebugTrace(" (@%08lX,cRef=%ld)\n", pobj, pobj->cRef);
  2993. #endif
  2994.  
  2995.     while (TRUE)
  2996.     {
  2997.         POBJ pobjChild;
  2998.  
  2999.         pobjChild = pobj->pobjHead;
  3000.  
  3001.         if (pobjChild == NULL)
  3002.             break;
  3003.  
  3004.         pobj->pobjHead = pobjChild->pobjNext;
  3005.         IMS_NeuterChildren(pobjChild, iLevel + 1);
  3006.     }
  3007.  
  3008.     if (pobj->wType != OT_MSGSTORE)
  3009.     {
  3010.         LPFNNEUTER lpfnNeuter;
  3011.  
  3012.         lpfnNeuter = rgfnNeuter[pobj->wType];
  3013.  
  3014.         if (lpfnNeuter != 0)
  3015.             lpfnNeuter(pobj);
  3016.  
  3017.         pobj->lpVtbl = 0;
  3018.         LMFree(&pobj->pims->lmr, pobj);
  3019.     }
  3020. }
  3021.  
  3022. void IMS_Neuter(PIMS pims)
  3023. {
  3024.     HRESULT hr;
  3025.     ULONG ulFlags;
  3026.  
  3027.     ulFlags = pims->ulFlagsSLT;
  3028.  
  3029.     hr = pims->psup->lpVtbl->StoreLogoffTransports(pims->psup, &ulFlags);
  3030.  
  3031. #ifdef DEBUG
  3032.     /* The support object given us during config doesn't support */
  3033.     /* StoreLogoffTransports. It isn't an error to get no support */
  3034.     /* in that case. */
  3035.     if (hr != hrSuccess && GetScode(hr) != MAPI_E_NO_SUPPORT)
  3036.         TraceSz1("SMS: IMS_Neuter: StoreLogoffTransports(LOGOFF_ABORT) "
  3037.             "returned unexpected error %s", SzDecodeScode(GetScode(hr)));
  3038. #endif
  3039.  
  3040.     if (pims->cRef != 0 || pims->pobjHead != 0)
  3041.     {
  3042.         TraceSz("\n---------------------------------------------------------"
  3043.             "-------");
  3044.         TraceSz("SMS: The following objects were not released before Logoff:");
  3045.         IMS_NeuterChildren((POBJ) pims, 0);
  3046.         TraceSz("-----------------------------------------------------------"
  3047.             "-----\n");
  3048.     }
  3049.  
  3050.     /* Free MS object's resources */
  3051.     FreeNull(pims->szStorePath);
  3052.     FreeNull(pims->szProps);
  3053.     LMFree(&pims->lmr, pims->eidStore.lpb);
  3054.     CloseRFS(pims->prfs);
  3055.  
  3056.     if (pims->lptblOutgoing)
  3057.     {
  3058.         if (pims->cOutgoingViews)
  3059.         {
  3060.             TraceSz1("Sample MS: IMS_Neuter: Leaked outgoing queue table "
  3061.                 "(# views left = %08lX)\n", pims->cOutgoingViews);
  3062.             pims->cOutgoingViews = 0;
  3063.         }
  3064.  
  3065.         UlRelease(pims->lptblOutgoing);
  3066.     }
  3067.  
  3068.     if (pims->ulOQConn)
  3069.     {
  3070.         pims->psup->lpVtbl->Unsubscribe(pims->psup, pims->ulOQConn);
  3071.         pims->ulOQConn = 0;
  3072.     }
  3073.  
  3074.     if (pims->ulTblConn)
  3075.     {
  3076.         pims->psup->lpVtbl->Unsubscribe(pims->psup, pims->ulTblConn);
  3077.         pims->ulTblConn = 0;
  3078.     }
  3079.  
  3080.     CloseIMsgSession(pims->pmsgsess);
  3081.     pims->pmsgsess = NULL;
  3082.  
  3083.     /* Make the logon object forget about us */
  3084.     if (pims->pmsl)
  3085.         pims->pmsl->pims = NULL;
  3086. }
  3087.  
  3088. /*
  3089.  *  HrOpenIMSPropsFileRetry
  3090.  *
  3091.  *  Purpose:
  3092.  *      Open the IMsgStore properties docfile as an IMessage
  3093.  *      instance to get/set properties.
  3094.  *      This retries up to NUM_RETRIES times on MAPI_E_NO_ACCESS
  3095.  *
  3096.  *  Arguments:
  3097.  *      szFile      The file to open.
  3098.  *      plmr        a pointer to the linked memory routines.
  3099.  *      psup        a pointer to the MAPI support object.
  3100.  *      fModify     TRUE means the caller wants read/write access.
  3101.  *                  FALSE means read-only access.
  3102.  *      lppmsg      Address of a location in which to return a
  3103.  *                  pointer to the newly opened IMessage instance.
  3104.  *
  3105.  *  Returns:
  3106.  *      HRESULT
  3107.  *
  3108.  *  Side effects:
  3109.  *      None.
  3110.  *
  3111.  *  Errors:
  3112.  *      IMessage on IStorage opening errors.
  3113.  */
  3114. HRESULT HrOpenIMSPropsFileRetry(LPMSGSESS pmsgsess, LPTSTR szFile, PLMR plmr,
  3115.     LPMAPISUP psup, BOOL fModify, LPMESSAGE * lppmsg)
  3116. {
  3117.     UINT iRetry;                /* number of attempts to open */
  3118.     HRESULT hr;
  3119.  
  3120.     iRetry = 0;
  3121.  
  3122.     while (TRUE)
  3123.     {
  3124.         hr = HrOpenIMsg(pmsgsess, szFile, plmr, psup, FALSE, fModify, TRUE,
  3125.             lppmsg);
  3126.  
  3127.         if (GetScode(hr) != MAPI_E_NO_ACCESS || ++iRetry >= NUM_RETRIES)
  3128.             break;
  3129.  
  3130.         Sleep(500);
  3131.     }
  3132.  
  3133.     #ifdef DEBUG
  3134.     if (iRetry >= NUM_RETRIES)
  3135.         TraceSz("HrOpenIMSPropsFileRetry: Failing open. Too many tries.");
  3136.     #endif
  3137.  
  3138.     DebugTraceResult(HrOpenIMSPropsFileRetry, hr);
  3139.     return hr;
  3140. }
  3141.  
  3142. /*
  3143.  * HrGetSMSStandardNotifKey
  3144.  *
  3145.  * Purpose
  3146.  *
  3147.  * return the notification key for standard notifications (everything
  3148.  * except outgoing queue notifications).
  3149.  * memory should be freed with FreeNull
  3150.  *
  3151.  * In order to call the MAPI registration function, we need to turn
  3152.  * an EntryID into a "notification key" (something unique to an
  3153.  * object in the store that will remain constant throughout this
  3154.  * logon session).  In the case of the Sample Store, we can just
  3155.  * use the local file name of the object (folder or message).
  3156.  * If the user is interested in notifications about all objects in the
  3157.  * store, we use the store's uid for the key.
  3158.  *
  3159.  * Parameters
  3160.  * pims         pointer to the message store object
  3161.  * peid         the entryid of the object 
  3162.  * lppKey       pointer to the location to return the key
  3163.  */
  3164. static HRESULT HrGetSMSStandardNotifKey(PIMS pims, PEID peid,
  3165.     LPNOTIFKEY * lppKey)
  3166. {
  3167.     HRESULT hr;
  3168.     LPNOTIFKEY lpKey;
  3169.     ULONG cb;           /* number of bytes in the key */
  3170.  
  3171.     if (peid)
  3172.     {
  3173.         LPMAPIUID lpuidEID = NULL;
  3174.         LPTSTR szPathEID = NULL;
  3175.         LPTSTR szFileEID = NULL;
  3176.  
  3177.         hr = HrDeconstructEID(peid, &lpuidEID, &szPathEID, &szFileEID);
  3178.         if (hr == hrSuccess)
  3179.         {
  3180.             cb = CbNewNOTIFKEY(Cbtszsize(szFileEID));
  3181.             hr = HrAlloc(cb, (PPV) &lpKey);
  3182.         }
  3183.  
  3184.         if (hr == hrSuccess)
  3185.         {
  3186.             lstrcpy((LPTSTR) &lpKey->ab, szFileEID);
  3187.             lpKey->cb = Cbtszsize(szFileEID);
  3188.         }
  3189.  
  3190.         FreeNull(lpuidEID);
  3191.         FreeNull(szPathEID);
  3192.         FreeNull(szFileEID);
  3193.  
  3194.         if (hr != hrSuccess)
  3195.             goto exit;
  3196.     }
  3197.     else
  3198.     {
  3199.         /* The caller is interested in notifications on all objects in the */
  3200.         /* store. Generate a key from our uid. */
  3201.  
  3202.         cb = CbNewNOTIFKEY(sizeof(MAPIUID));
  3203.         hr = HrAlloc(cb, (PPV) &lpKey);
  3204.         if (hr != hrSuccess)
  3205.             goto exit;
  3206.  
  3207.         GetResourceUID(pims, (MAPIUID *) &(lpKey->ab[0]));
  3208.         lpKey->cb = sizeof(MAPIUID);
  3209.     }
  3210.  
  3211. exit:
  3212.     if (hr != hrSuccess)
  3213.         FreeNull(lpKey);
  3214.     else
  3215.         *lppKey = lpKey;
  3216.  
  3217.     DebugTraceResult(HrGetSMSStandardNotifKey, hr);
  3218.     return hr;
  3219. }
  3220.  
  3221.  
  3222.