MSPFLD.C
上传用户:bangxh
上传日期:2007-01-31
资源大小:42235k
文件大小:151k
源码类别:

Windows编程

开发平台:

Visual C++

  1. /*
  2.  *  M S P F L D . C
  3.  *
  4.  *  Code that implements the object methods of IMAPIFolder.
  5.  *
  6.  *  Copyright 1992-1995 Microsoft Corporation.  All Rights Reserved.
  7.  */
  8. #include "msp.h"
  9. #define FLD_ValidateParameters(pobj, intf, method, arglist)     
  10.         OBJ_ValidateParameters(pobj, intf, method, sizeof(IFLD), &vtblIFLD, arglist)
  11. static BOOL IFLD_IsInvalid(PIFLD pifld);
  12. static HRESULT HrCreateContTblMutex(HANDLE *phCTMutex);
  13. static BOOL FFoldInSameStore(PIFLD pifld, PIFLD lpDestFld);
  14. static BOOL FIsAncestor(PIFLD pifldAncestor, PIFLD pifldDescendent);
  15. static HRESULT HrGetSortOrder(PIFLD pifld, LPSSortOrderSet *lppsSortOrder);
  16. static HRESULT HrFillHierarchyTable(PIFLD pifld, LPTABLEDATA lptbl);
  17. static HRESULT HrIsRead(PIFLD pifld, PEID peidMsg, BOOL *pfRead);
  18. static HRESULT HrCreateFolder(PIFLD pifldParent, LPSTR szName, LPSTR szComment,
  19.     BOOL fOpenIfExists, PIFLD *ppifldNew, BOOL *pfCreated);
  20. static HRESULT HrDeleteSubDirectory(PIFLD pifldParent, PEID peidToDelete,
  21.     ULONG ulFlags, BOOL fContentsOnly);
  22. static HRESULT HrCopyContents(PIFLD pifldSrc, PIFLD pifldDst, ULONG ulFlags,
  23.     LPSPropTagArray ptagaExcl);
  24. static BOOL FFolderExists(PEID peid, PIMS pims);
  25. static HRESULT HrSetSubFolderProp(PIFLD pifld, BOOL fSubFolder);
  26. static HRESULT HrSetOneROFolderProp(PIFLD pifld, LONG lValue, ULONG ulPT);
  27. static HRESULT HrEIDFromDisplayName(LPMAPITABLE pmt, LPSTR szName, PLMR plmr,
  28.     PEID *ppeid);
  29. static HRESULT HrCreateMessageList(PIFLD pifld, LPENTRYLIST *lppEntryList);
  30. static void DestroyMessageList(PLMR plmr, LPENTRYLIST *lppEntryList);
  31. #define NUM_RW_FOLDER_PROPS      2  /* number read write initial folder props */
  32. #define IFLD_EnterCriticalSection(pifld)    OBJ_EnterCriticalSection((POBJ)pifld)
  33. #define IFLD_LeaveCriticalSection(pifld)    OBJ_LeaveCriticalSection((POBJ)pifld)
  34. CALLERRELEASE ViewRelease;
  35. TCHAR szSubfolderPropFile[] = TEXT("subfoldr.prp");
  36. TCHAR szAllFilesTemplate[] = TEXT("*.*");
  37. /* properties excluded on a copy of folders' .prp file */
  38. const static SizedSPropTagArray(13, sptaExclFldProps) =
  39. {
  40.     13,
  41.     {
  42.         PR_CONTENT_COUNT,
  43.         PR_CONTENT_UNREAD,
  44.         PR_ENTRYID,
  45.         PR_INSTANCE_KEY,
  46.         PR_PARENT_ENTRYID,
  47.         PR_OBJECT_TYPE,
  48.         PR_STORE_ENTRYID,
  49.         PR_STORE_RECORD_KEY,
  50.         PR_RECORD_KEY,
  51.         PR_FOLDER_TYPE,
  52.         PR_SUBFOLDERS,
  53.         PR_MESSAGE_RECIPIENTS,
  54.         PR_MESSAGE_ATTACHMENTS
  55.     }
  56. };
  57. /* read only property proptags */
  58. /* order must match order initialized on CreateFolderStorage */
  59. #define NUM_RO_FOLDER_PROPS     11  /* number read only initial folder props */
  60. const static SizedSPropTagArray(NUM_RO_FOLDER_PROPS, sptaReadOnly) =
  61. {
  62.     NUM_RO_FOLDER_PROPS,
  63.     {
  64.         PR_OBJECT_TYPE,
  65.         PR_RECORD_KEY,
  66.         PR_FOLDER_TYPE,
  67.         PR_CONTENT_COUNT,
  68.         PR_CONTENT_UNREAD,
  69.         PR_STORE_ENTRYID,
  70.         PR_STORE_RECORD_KEY,
  71.         PR_SUBFOLDERS,
  72.         PR_ENTRYID,
  73.         PR_PARENT_ENTRYID,
  74.         PR_INSTANCE_KEY
  75.     }
  76. };
  77. /* read only property attributes */
  78. const static SizedSPropAttrArray(NUM_RO_FOLDER_PROPS, spaReadOnly) =
  79. {
  80.     NUM_RO_FOLDER_PROPS,
  81.     {
  82.         PROPATTR_READABLE,
  83.         PROPATTR_READABLE,
  84.         PROPATTR_READABLE,
  85.         PROPATTR_READABLE,
  86.         PROPATTR_READABLE,
  87.         PROPATTR_READABLE,
  88.         PROPATTR_READABLE,
  89.         PROPATTR_READABLE,
  90.         PROPATTR_READABLE,
  91.         PROPATTR_READABLE,
  92.         PROPATTR_READABLE
  93.     }
  94. };
  95. /* initial sort order set for a contents table */
  96. static SizedSSortOrderSet(1, sSortOrderContentsDefault) =
  97. {
  98.     1,
  99.     0,
  100.     0,
  101.     {
  102.         PR_INSTANCE_KEY,                /* the index column */
  103.         TABLE_SORT_ASCEND
  104.     }
  105. };
  106. /* message status property array */
  107. static SPropTagArray sptaMessageStatus =
  108. {
  109.     1,
  110.     {
  111.         PR_MESSAGE_FLAGS
  112.     }
  113. };
  114. /* DISPATCH TABLE */
  115. IFLD_Vtbl vtblIFLD =
  116. {
  117.     (IFLD_QueryInterface_METHOD *)  OBJ_QueryInterface,
  118.     (IFLD_AddRef_METHOD *)          OBJ_AddRef,
  119.     IFLD_Release,
  120.     (IFLD_GetLastError_METHOD *)    IMS_GetLastError,
  121.     (IFLD_SaveChanges_METHOD *)     IMS_SaveChanges,
  122.     IFLD_GetProps,
  123.     IFLD_GetPropList,
  124.     IFLD_OpenProperty,
  125.     IFLD_SetProps,
  126.     IFLD_DeleteProps,
  127.     IFLD_CopyTo,
  128.     IFLD_CopyProps,
  129.     (IFLD_GetNamesFromIDs_METHOD *) IMS_GetNamesFromIDs,
  130.     (IFLD_GetIDsFromNames_METHOD *) IMS_GetIDsFromNames,
  131.     IFLD_GetContentsTable,
  132.     IFLD_GetHierarchyTable,
  133.     (IFLD_OpenEntry_METHOD *)       IMS_OpenEntry,
  134.     IFLD_SetSearchCriteria,
  135.     IFLD_GetSearchCriteria,
  136.     IFLD_CreateMessage,
  137.     IFLD_CopyMessages,
  138.     IFLD_DeleteMessages,
  139.     IFLD_CreateFolder,
  140.     IFLD_CopyFolder,
  141.     IFLD_DeleteFolder,
  142.     IFLD_SetReadFlags,
  143.     IFLD_GetMessageStatus,
  144.     IFLD_SetMessageStatus,
  145.     IFLD_SaveContentsSort,
  146.     IFLD_EmptyFolder
  147. };
  148. /****************************************************
  149. *           Methods on IMAPIFolder                  *
  150. *****************************************************/
  151. /****************************************************************
  152.     Folder properties are all implemented by creating a file
  153.     (FOLDER.PRP) inside each folder and using message properties
  154.     on it.
  155. *************************************************************/
  156. /***************************************************************************
  157.  -  IFLD_Release
  158.  -
  159.  *  Purpose:
  160.  *      Given a valid folder object, decrements the reference count, and if
  161.  *      zero, NULLS out the lpVtbl. If no child objects of the folder remain
  162.  *      open, and no contents or hierarchy tables remain open, the routine
  163.  *      also destroys the object (see OBJ_Destroy for details of that action).
  164.  *
  165.  *      This release method is very similar to the standard one found in
  166.  *      mspobj.c. The only difference is that this one also checks for any
  167.  *      open contents or hierarchy tables, and doesn't actually destroy
  168.  *      the folder until they are gone. See ViewRelease() for the other side
  169.  *      of this implementation.
  170.  *
  171.  *  Parameters
  172.  *       pifld      The folder object to release
  173.  *
  174.  *  Returns:
  175.  *       ULONG: The value of the reference count on the whole object. When
  176.  *              fully released, it is zero. This information can be used for
  177.  *              diagnostic and testing purposes only. It CANNOT be used by
  178.  *              shipping code. See the OLE 2.0 programmers reference for more
  179.  *              details. Note that this function will also return zero when
  180.  *              the identity of the object has been destroyed. Therefore,
  181.  *              clients may not rely on zero having any special significance
  182.  *              other than for debugging purposes.
  183.  */
  184. STDMETHODIMP_(ULONG) IFLD_Release(PIFLD pifld)
  185. {
  186.     LONG cRef;
  187.     POBJ pobj;
  188.     if (IFLD_IsInvalid(pifld))
  189.     {
  190.         TraceSz1("SampleMS: IFLD_Release(pifld=%08lX): Folder is invalid and is "
  191.             "being ignored", pifld);
  192.         return (0);
  193.     }
  194.     IFLD_EnterCriticalSection(pifld);
  195.     pobj = (POBJ) pifld;
  196.     AssertSz(pobj->cRef > 0, "IFLD_Release(): Too many releases");
  197.     cRef = --pobj->cRef;
  198.     if (cRef == 0)
  199.     {
  200.         pobj->lpVtbl = 0;   /* should prevent being called again. */
  201.         if (    pobj->pobjHead == 0
  202.             &&  pifld->lptblContents == NULL
  203.             &&  pifld->lptblHierarchy == NULL)
  204.         {
  205.             OBJ_Destroy(pobj);  /* will leave the critical section */
  206.             return (0);
  207.         }
  208.     }
  209.     IFLD_LeaveCriticalSection(pifld);
  210.     return (cRef);
  211. }
  212. /***************************************************************************
  213.  -  IFLD_GetProps
  214.  -
  215.  *  Purpose:
  216.  *      Returns in pcval and ppval the values of the properties
  217.  *      in ptaga.  If the latter is NULL, all properties in the folder
  218.  *      are returned.
  219.  *
  220.  *  Parameters
  221.  *       pifld      The folder object whose properties are requested
  222.  *       ptaga      Pointer to a counted array of property tags of
  223.  *                  properties requested
  224.  *       ulFlags    UNICODE / String8
  225.  *       pcval      Pointer to number of values returned
  226.  *       ppval      Pointer to a variable in which the address of the
  227.  *                  returned property values is placed
  228.  *
  229.  *  Returns:
  230.  *       HRESULT
  231.  *
  232.  */
  233. STDMETHODIMP IFLD_GetProps(PIFLD pifld, LPSPropTagArray ptaga, ULONG ulFlags,
  234.     ULONG *pcval, LPSPropValue *ppval)
  235. {
  236.     LPMESSAGE lpmsg = NULL;     /* open property message */
  237.     HRESULT hr = hrSuccess;
  238.     FLD_ValidateParameters(
  239.             pifld, 
  240.             IMAPIProp,
  241.             GetProps,
  242.             (pifld, 
  243.             ptaga, 
  244.             ulFlags,
  245.             pcval, 
  246.             ppval));
  247.     #ifdef VALIDATE
  248.     if (ulFlags & MAPI_UNICODE)
  249.         return ResultFromScode(MAPI_E_BAD_CHARWIDTH);
  250.     #endif
  251.         
  252.     IFLD_EnterCriticalSection(pifld);
  253.     /* open the property message */
  254.     hr = HrOpenPropertyMessageRetry(pifld->peid, pifld->pims, FALSE, &lpmsg);
  255.     if (hr != hrSuccess)
  256.         goto exit;
  257.     /* Pass the call off to IMessage */
  258.     hr = lpmsg->lpVtbl->GetProps(lpmsg, ptaga, ulFlags, pcval, ppval);
  259.     UlRelease(lpmsg);
  260.     {if(HR_SUCCEEDED(hr))
  261.     {
  262.         LPSPropValue pvalStoreSupMask = PpropFindProp(*ppval, *pcval, 
  263.                     PROP_TAG(PT_UNSPECIFIED, PROP_ID(PR_STORE_SUPPORT_MASK)));
  264.         if(pvalStoreSupMask)
  265.         {
  266.             pvalStoreSupMask->ulPropTag = PR_STORE_SUPPORT_MASK;
  267.             pvalStoreSupMask->Value.l = SMS_SUPPORTMASK;
  268.             /* fix up hr */
  269.             if(ptaga->cValues == 1)
  270.                 hr = hrSuccess;
  271.         }
  272.     }
  273.     }
  274.     /* Wrap internal properties. Note that this function takes as an */
  275.     /* argument the HRESULT from the previous IMessage::GetProps call. */
  276.     /* We aren't ignoring the error. */
  277.     hr = HrWrap_GetProps(hr, pifld->pims, pifld->cval, pifld->pval, pcval,
  278.         ppval, FALSE, (ptaga != NULL), (POBJ)pifld);
  279. exit:
  280.     IFLD_LeaveCriticalSection(pifld);
  281.     #ifdef DEBUG
  282.     if (GetScode(hr) != MAPI_W_ERRORS_RETURNED)
  283.         DebugTraceResult(IFLD_GetProps, hr);
  284.     #endif
  285.     return HrCheckHr(hr, IMAPIProp_GetProps);
  286. }
  287. /***************************************************************************
  288.  -  IFLD_GetPropList
  289.  -
  290.  *  Purpose:
  291.  *      Returns in ptaga the list of all currently accessible properties
  292.  *      of pifld.
  293.  *
  294.  *  Parameters
  295.  *       pifld          The folder object whose properties are requested
  296.  *       ulFlags        UNICODE / String8
  297.  *       pptaga         Pointer to a counted array of property tags of
  298.  *                      properties requested
  299.  *  Returns:
  300.  *       hr
  301.  *
  302.  */
  303. STDMETHODIMP IFLD_GetPropList(PIFLD pifld, ULONG ulFlags, LPSPropTagArray *pptaga)
  304. {
  305.     HRESULT hr;
  306.     LPMESSAGE lpmsg = NULL;
  307.     FLD_ValidateParameters(
  308.             pifld, 
  309.             IMAPIProp,
  310.             GetPropList,
  311.             (pifld, 
  312.             ulFlags, 
  313.             pptaga));
  314.     #ifdef VALIDATE
  315.     if (ulFlags & MAPI_UNICODE)
  316.         return ResultFromScode(MAPI_E_BAD_CHARWIDTH);
  317.     #endif
  318.         
  319.     IFLD_EnterCriticalSection(pifld);
  320.     /* open the property message */
  321.     hr = HrOpenPropertyMessageRetry(pifld->peid, pifld->pims, FALSE,
  322.             &lpmsg);
  323.     /* If the property message was successfully opened, then pass the */
  324.     /* call off to IMessage */
  325.     if (hr == hrSuccess)
  326.         hr = lpmsg->lpVtbl->GetPropList(lpmsg, ulFlags, pptaga);
  327.     UlRelease(lpmsg);
  328.     IFLD_LeaveCriticalSection(pifld);
  329.     DebugTraceResult(IFLD_GetPropList, hr);
  330.     return HrCheckHr(hr, IMAPIProp_GetPropList);
  331. }
  332. /***************************************************************************
  333.  -  IFLD_OpenProperty
  334.  -
  335.  *  Purpose:
  336.  *      Returns in *lppUnk a pointer to a newly created interface for the
  337.  *                  propery of pifld in ulPropTag
  338.  *      Not supported on folders.
  339.  *
  340.  *  Parameters
  341.  *       pifld          the folder object whose property interface is requested
  342.  *       ulPropTag          Property tag for the desired property--only ID is used.
  343.  *       lpiid              Pointer to the GUID for the interface
  344.  *       ulInterfaceOptions Specifies interface-specific behavior
  345.  *       ulFlags            MAPI_CREATE, MAPI_MODIFY, MAPI_DEFERRED_ERRORS
  346.  *       lppUnk             Pointer to the newly created interface pointer
  347.  *
  348.  *  Returns:
  349.  *       hr
  350.  *
  351.  */
  352. STDMETHODIMP IFLD_OpenProperty(PIFLD pifld, ULONG ulPropTag, LPCIID lpiid,
  353.     ULONG ulInterfaceOptions, ULONG ulFlags, LPUNKNOWN *lppUnk)
  354. {
  355.     SCODE sc;
  356.     FLD_ValidateParameters(
  357.             pifld, 
  358.             IMAPIProp,
  359.             OpenProperty,
  360.             (pifld, 
  361.             ulPropTag, 
  362.             lpiid, 
  363.             ulInterfaceOptions, 
  364.             ulFlags, 
  365.             lppUnk));
  366.     sc = MAPI_E_NO_SUPPORT;
  367.     
  368.     DebugTraceSc(IFLD_OpenProperty, sc);
  369.     return ResultFromScode(sc);
  370. }
  371. /***************************************************************************
  372.  -  IFLD_SetProps
  373.  -
  374.  *  Purpose:
  375.  *      Sets the properties in pval for pifld.
  376.  *      lppProblems is a pointer to a structure of problems,
  377.  *      NULL If there weren't any.
  378.  *
  379.  *  Parameters
  380.  *       pifld          the folder object whose properties are to be set
  381.  *       cValues            count of properties to be set
  382.  *       pval               Pointer to a an array of property value structures.
  383.  *       ppErr      Pointer to address of a property problem structure
  384.  *                              to be returned.
  385.  *
  386.  *  Returns:
  387.  *       hr         PROP_E_SECURITY_VIOLATION, PROP_E_CALL_FAILED,
  388.  *                          PROP_E_CALL_FAILED
  389.  *
  390.  */
  391. STDMETHODIMP IFLD_SetProps(PIFLD pifld, ULONG cValues, LPSPropValue pval,
  392.     LPSPropProblemArray *ppErr)
  393. {
  394.     LPMESSAGE lpmsgNew = NULL;      /* new instance of property message */
  395.     HRESULT hr;
  396.     FLD_ValidateParameters(
  397.             pifld, 
  398.             IMAPIProp,
  399.             SetProps,
  400.             (pifld, 
  401.             cValues, 
  402.             pval, 
  403.             ppErr));
  404.     IFLD_EnterCriticalSection(pifld);
  405.     if (!OBJ_TestFlag(pifld, OBJF_MODIFY))
  406.     {
  407.         hr = ResultFromScode(MAPI_E_NO_ACCESS);
  408.         goto exit;
  409.     }
  410.     /* open the property message */
  411.     hr = HrOpenPropertyMessageRetry(pifld->peid, pifld->pims,
  412.         TRUE, &lpmsgNew);
  413.     if (hr != hrSuccess)
  414.         goto exit;
  415.     /* set props on the property message */
  416.     hr = lpmsgNew->lpVtbl->SetProps(lpmsgNew, cValues, pval, ppErr);
  417.     if (hr != hrSuccess)
  418.         goto exit;
  419.     hr = lpmsgNew->lpVtbl->SaveChanges(lpmsgNew, KEEP_OPEN_READWRITE);
  420.     if (hr != hrSuccess)
  421.         goto exit;
  422.     /* Must release the message before trying to update the hierarchy */
  423.     /* table. Multiple opens on the internal message are not allowed by */
  424.     /* IStorage. */
  425.     UlRelease(lpmsgNew);
  426.     lpmsgNew = NULL;
  427.     /* If this isn't the root folder, get the parent entryid, and call */
  428.     /* ChangeTable so that any new properties are updated in its */
  429.     /* hierarchy table row. */
  430.     if (FIsRoot(pifld->peid) == FALSE)
  431.     {
  432.         PEID peidParent = NULL;
  433.         PIMS pims = pifld->pims;
  434.         hr = HrGetParentEID(&pims->lmr, pifld->peid, &peidParent);
  435.         if (hr == hrSuccess)
  436.         {
  437.             ChangeTable(pims, peidParent, pifld->peid, MAPI_FOLDER,
  438.                 TABLE_ROW_MODIFIED, TRUE);
  439.             LMFree(&pims->lmr, peidParent);
  440.         }
  441.         else
  442.         {
  443.             TraceSz1("Sample MS: IFLD_SetProps: failed to change hierarchy "
  444.                 "table. sc == %sn", SzDecodeScode(GetScode(hr)));
  445.             hr = hrSuccess;
  446.         }
  447.     }
  448. exit:
  449.     UlRelease(lpmsgNew);
  450.     IFLD_LeaveCriticalSection(pifld);
  451.     DebugTraceResult(IFLD_SetProps, hr);
  452.     return HrCheckHr(hr, IMAPIProp_SetProps);
  453. }
  454. /***************************************************************************
  455.  -  IFLD_DeleteProps
  456.  -
  457.  *  Purpose:
  458.  *      Deletes the properties in ptaga for pifld.  ppErr
  459.  *      is a pointer to a structure of problems, NULL If there weren't any.
  460.  *
  461.  *  Parameters
  462.  *       pifld          the folder object whose properties are to be deleted
  463.  *       ptaga      Pointer to a counted array of property tags of the
  464.  *                          properties to be deleted.  Must not be NULL.
  465.  *       ppErr      Pointer to address of a property problem structure
  466.  *                          to be returned.
  467.  *  Returns:
  468.  *       hr         PROP_E_SECURITY_VIOLATION, PROP_E_CALL_FAILED,
  469.  *                          PROP_E_CALL_FAILED
  470.  */
  471. STDMETHODIMP IFLD_DeleteProps(PIFLD pifld, LPSPropTagArray ptaga,
  472.     LPSPropProblemArray *ppErr)
  473. {
  474.     LPMESSAGE lpmsgNew = NULL;  /* new instance of property message */
  475.     HRESULT hr = hrSuccess;
  476.     FLD_ValidateParameters(
  477.             pifld, 
  478.             IMAPIProp,
  479.             DeleteProps,
  480.             (pifld, 
  481.             ptaga, 
  482.             ppErr));
  483.     IFLD_EnterCriticalSection(pifld);
  484.     if (!OBJ_TestFlag(pifld, OBJF_MODIFY))
  485.     {
  486.         hr = ResultFromScode(MAPI_E_NO_ACCESS);
  487.         goto exit;
  488.     }
  489.     /* open the property message */
  490.     hr = HrOpenPropertyMessageRetry(pifld->peid,
  491.         pifld->pims, TRUE, &lpmsgNew);
  492.     if (hr != hrSuccess)
  493.         goto exit;
  494.     /* Pass the call off to IMessage */
  495.     hr = lpmsgNew->lpVtbl->DeleteProps(lpmsgNew, ptaga, ppErr);
  496.     if (hr != hrSuccess)
  497.         goto exit;
  498.     hr = lpmsgNew->lpVtbl->SaveChanges(lpmsgNew, KEEP_OPEN_READWRITE);
  499.     if (hr != hrSuccess)
  500.         goto exit;
  501.     /* Must release the message before trying to update the hierarchy */
  502.     /* table. Multiple opens on the internal message are not allowed by */
  503.     /* IStorage. */
  504.     UlRelease(lpmsgNew);
  505.     lpmsgNew = NULL;
  506.     /* If this isn't the root folder, get the parent entryid, and call */
  507.     /* ChangeTable so that any new properties are updated in its */
  508.     /* hierarchy table row. */
  509.     if (FIsRoot(pifld->peid) == FALSE)
  510.     {
  511.         PEID peidParent = NULL;
  512.         PIMS pims = pifld->pims;
  513.         hr = HrGetParentEID(&pims->lmr, pifld->peid, &peidParent);
  514.         if (hr == hrSuccess)
  515.         {
  516.             ChangeTable(pims, peidParent, pifld->peid, MAPI_FOLDER,
  517.                 TABLE_ROW_MODIFIED, TRUE);
  518.             LMFree(&pims->lmr, peidParent);
  519.         }
  520.         else
  521.         {
  522.             TraceSz1("Sample MS: IFLD_DeleteProps: failed to change hierarchy "
  523.                 "table. sc == %sn", SzDecodeScode(GetScode(hr)));
  524.             hr = hrSuccess;
  525.         }
  526.     }
  527. exit:
  528.     UlRelease(lpmsgNew);
  529.     IFLD_LeaveCriticalSection(pifld);
  530.     DebugTraceResult(IFLD_DeleteProps, hr);
  531.     return HrCheckHr(hr, IMAPIProp_DeleteProps);
  532. }
  533. /***************************************************************************
  534.  -  IFLD_CopyTo
  535.  -
  536.  *  Purpose:
  537.  *      Copy the properties and/or contents of the current object
  538.  *          to a destination object
  539.  *
  540.  *  Parameters
  541.  *       pifldSrc       current object
  542.  *       ciidExcl       Count of excluded interfaces in rgiidExcl
  543.  *       rgiidExcl      Array of iid's specifying excluded interfaces
  544.  *       ptagaExcl      Pointer to a counted array of property tags of
  545.  *                      properties not to be copied, can be NULL
  546.  *       ulUIParam      Handle of parent window cast to ULONG, NULL if
  547.  *                      no dialog requested
  548.  *       piidDst        Interface ID of the interface of lpDestObj
  549.  *       lpDestObj      destination object
  550.  *       ulFlags        MAPI_MOVE, MAPI_NOREPLACE, MAPI_DIALOG, MAPI_DECLINE_OK
  551.  *       pprba          Pointer to address of a property problem
  552.  *                      structure to be returned.
  553.  *
  554.  *  Returns:
  555.  *       hr
  556.  *
  557.  *  Side effects:
  558.  *
  559.  *  Errors:
  560.  */
  561. STDMETHODIMP IFLD_CopyTo(PIFLD pifldSrc, ULONG ciidExcl, LPCIID rgiidExcl,
  562.     LPSPropTagArray ptagaExcl, ULONG ulUIParam, LPMAPIPROGRESS lpProgress,
  563.     LPCIID piidDst, LPVOID lpDestObj, ULONG ulFlagsIn,
  564.     LPSPropProblemArray *pprba)
  565. {
  566.     HRESULT hr = hrSuccess;
  567.     BOOL fIsIMapiProp = TRUE;   /* TRUE if are to copy as imapiprop */
  568.     BOOL fIsIMAPIFolder = TRUE;     /* TRUE if are to copy as IMAPIFolder */
  569.     SCODE sc = S_OK;
  570.     LPCIID piid;
  571.     LPCIID piidMax;
  572.     ULONG ulFlags;
  573.     FLD_ValidateParameters(
  574.             pifldSrc, 
  575.             IMAPIProp,
  576.             CopyTo,
  577.             (pifldSrc, 
  578.             ciidExcl, 
  579.             rgiidExcl,
  580.             ptagaExcl, 
  581.             ulUIParam, 
  582.             lpProgress,
  583.             piidDst, 
  584.             lpDestObj, 
  585.             ulFlagsIn,
  586.             pprba));
  587.     IFLD_EnterCriticalSection(pifldSrc);
  588.     /* Turn off MAPI_DIALOG flag, since we don't support it. */
  589.     ulFlags = (ulFlagsIn & ~MAPI_DIALOG);
  590.     piid = rgiidExcl;
  591.     piidMax = piid + ciidExcl;
  592.     /* find the interface to copy : IMAPIPROP or IMAPIFOLDER */
  593.     while (piid < piidMax)
  594.     {
  595.         if (IsEqualIID(piid, &IID_IMAPIFolder))
  596.             fIsIMAPIFolder = FALSE;
  597.         else if (IsEqualIID(piid, (LPIID) &IID_IMAPIProp))
  598.             fIsIMapiProp = FALSE;
  599.         piid++;
  600.     }
  601.     /* make sure that the destination can support this */
  602.     if (fIsIMAPIFolder && !IsEqualIID(piidDst, (LPIID) &IID_IMAPIFolder))
  603.     {
  604.         LPMAPIFOLDER pfld = NULL;
  605.         hr = ((LPUNKNOWN) lpDestObj)->lpVtbl->QueryInterface(lpDestObj,
  606.             (LPIID) &IID_IMAPIFolder, (LPVOID *) &pfld);
  607.         if (hr != hrSuccess)
  608.         {
  609.             Assert(GetScode(hr) == MAPI_E_INTERFACE_NOT_SUPPORTED);
  610.             goto exit;
  611.         }
  612.         UlRelease(pfld);
  613.     }
  614.     else if (fIsIMapiProp &&
  615.             !(IsEqualIID(piidDst, (LPIID) &IID_IMAPIProp) ||
  616.             IsEqualIID(piidDst, (LPIID) &IID_IMAPIFolder)))
  617.     {
  618.         LPMAPIPROP pmp = NULL;
  619.         hr = ((LPUNKNOWN) lpDestObj)->lpVtbl->QueryInterface(lpDestObj,
  620.             (LPIID) &IID_IMAPIProp, (LPVOID *) &pmp);
  621.         if (hr != hrSuccess)
  622.         {
  623.             Assert(GetScode(hr) == MAPI_E_INTERFACE_NOT_SUPPORTED);
  624.             goto exit;
  625.         }
  626.         UlRelease(pmp);
  627.     }
  628.     if (!FFoldInSameStore(pifldSrc, (PIFLD) lpDestObj))
  629.     {
  630.         LPMAPISUP psup = pifldSrc->pims->psup;
  631.         /* leave critical section before calling back to MAPI */
  632.         IFLD_LeaveCriticalSection(pifldSrc);
  633.         /* call MAPI's CopyProps */
  634.         hr = psup->lpVtbl->DoCopyTo(psup, (LPIID) &IID_IMAPIFolder, (LPVOID) pifldSrc,
  635.             ciidExcl, rgiidExcl, ptagaExcl, ulUIParam,
  636.             lpProgress, piidDst, lpDestObj, ulFlagsIn, pprba);
  637.         DebugTraceResult(IFLD_CopyTo, hr);
  638.         return (HrCheckHr(hr, IMAPIProp_CopyTo));
  639.     }
  640.     /* copy them as folders */
  641.     if (fIsIMAPIFolder)
  642.     {
  643.         PIFLD pifldDst = (PIFLD) lpDestObj;
  644.         /* make sure we have write access */
  645.         if (!OBJ_TestFlag(pifldDst, OBJF_MODIFY))
  646.         {
  647.             hr = ResultFromScode(MAPI_E_NO_ACCESS);
  648.             goto exit;
  649.         }
  650.         if (!FContainsProp(PR_CONTAINER_HIERARCHY, ptagaExcl))
  651.         {
  652.             /* can not move or copy a folder to a decendant or itself */
  653.             if (FIsAncestor(pifldSrc, pifldDst))
  654.                 hr = ResultFromScode(MAPI_E_NO_ACCESS);
  655.         }
  656.         else if (ulFlags & MAPI_MOVE)
  657.         {
  658.             /* Can't set MAPI_MOVE and also exclude subfolders. */
  659.             hr = ResultFromScode(MAPI_E_INVALID_PARAMETER);
  660.         }
  661.         if (hr != hrSuccess)
  662.             goto exit;
  663.         if (!(ulFlags & MAPI_NOREPLACE))
  664.         {
  665.             /* Empty the destination folder before beginning. */
  666.             hr = pifldDst->lpVtbl->EmptyFolder(pifldDst, 0, NULL, 0);
  667.             if (hr != hrSuccess)
  668.                 goto exit;
  669.         }
  670.         /* copy the contents of the source folder to the destination folder */
  671.         hr = HrCopyContents(pifldSrc, pifldDst, ulFlags, ptagaExcl);
  672.         if (hr != hrSuccess)
  673.             goto exit;
  674.     }
  675.     /* copy the properties */
  676.     if (fIsIMapiProp || fIsIMAPIFolder)
  677.     {
  678.         LPMESSAGE lpmsg;
  679.         BOOL fModify = FALSE;
  680.         if (ulFlags & MAPI_MOVE)
  681.             fModify = TRUE;
  682.         hr = HrOpenPropertyMessageRetry(pifldSrc->peid,
  683.             pifldSrc->pims, fModify, &lpmsg);
  684.         if (hr != hrSuccess)
  685.             goto exit;
  686.         hr = lpmsg->lpVtbl->CopyTo(lpmsg, ciidExcl,
  687.             rgiidExcl, ptagaExcl, ulUIParam, lpProgress,
  688.             (LPIID) &IID_IMAPIProp, lpDestObj, ulFlags, pprba);
  689.         if (hr == hrSuccess && fModify)
  690.             lpmsg->lpVtbl->SaveChanges(lpmsg, KEEP_OPEN_READWRITE);
  691.         UlRelease(lpmsg);
  692.     }
  693. exit:
  694.     IFLD_LeaveCriticalSection(pifldSrc);
  695.     DebugTraceResult(IFLD_CopyTo, hr);
  696.     return HrCheckHr(hr, IMAPIProp_CopyTo);
  697. }
  698. /***************************************************************************
  699.  -  IFLD_CopyProps
  700.  -
  701.  *  Purpose:
  702.  *      Copy the properties and/or contents of the current object
  703.  *          to a destination object
  704.  *
  705.  *  Parameters
  706.  *       pifldSrc       current object
  707.  *       ptagaIncl      Pointer to a counted array of property tags of
  708.  *                      properties to be copied
  709.  *       ulUIParam      Handle of parent window cast to ULONG, NULL if
  710.  *                      no dialog requested
  711.  *       piidDst        Interface ID of the interface of lpDestObj
  712.  *       lpDestObj      destination object
  713.  *       ulFlags        MAPI_MOVE, MAPI_NOREPLACE, MAPI_DIALOG, MAPI_DECLINE_OK
  714.  *       pprba          Pointer to address of a property problem
  715.  *                      structure to be returned.
  716.  *
  717.  *  Returns:
  718.  *       hr
  719.  *
  720.  *  Side effects:
  721.  *
  722.  *  Errors:
  723.  */
  724. STDMETHODIMP IFLD_CopyProps(PIFLD pifldSrc,
  725.     LPSPropTagArray ptagaIncl, ULONG ulUIParam, LPMAPIPROGRESS lpProgress,
  726.     LPCIID piidDst, LPVOID lpDestObj, ULONG ulFlagsIn,
  727.     LPSPropProblemArray *pprba)
  728. {
  729.     HRESULT hr = hrSuccess;
  730. #ifdef WHEN_WORKING
  731.     PIFLD pifldDst = NULL;      /* lpDestObj if it's a folder */
  732.     BOOL fIsIMAPIFolder;        /* TRUE if are to copy as IMAPIFolder */
  733.     SCODE sc = S_OK;
  734.     LPIID piid;
  735.     LPIID piidMax;
  736.     ULONG ulFlags;
  737. #endif /* WHEN_WORKING */
  738.     FLD_ValidateParameters(
  739.             pifldSrc, 
  740.             IMAPIProp,
  741.             CopyProps,
  742.             (pifldSrc,
  743.             ptagaIncl, 
  744.             ulUIParam, 
  745.             lpProgress,
  746.             piidDst, 
  747.             lpDestObj, 
  748.             ulFlagsIn,
  749.             pprba));
  750.     IFLD_EnterCriticalSection(pifldSrc);
  751. #ifdef WHEN_WORKING
  752.     /* Turn off MAPI_DIALOG flag, since we don't support it. */
  753.     ulFlags = (ulFlagsIn & ~MAPI_DIALOG);
  754.     fIsIMAPIFolder =   FContainsProp(PR_CONTAINER_HIERARCHY, ptagaIncl)
  755.                     || FContainsProp(PR_CONTAINER_CONTENTS, ptagaIncl);
  756.     /* make sure that the destination can support this */
  757.     if (fIsIMAPIFolder && !IsEqualIID(piidDst, (LPIID) &IID_IMAPIFolder))
  758.     {
  759.         LPMAPIFOLDER pfld = NULL;
  760.         hr = ((LPUNKNOWN) lpDestObj)->lpVtbl->QueryInterface(lpDestObj,
  761.             (LPIID) &IID_IMAPIFolder, (LPVOID *) &pfld);
  762.         if (hr != hrSuccess)
  763.         {
  764.             Assert(GetScode(hr) == MAPI_E_INTERFACE_NOT_SUPPORTED);
  765.             goto exit;
  766.         }
  767.         UlRelease(pfld);
  768.     }
  769.     else if (!(IsEqualIID(piidDst, (LPIID) &IID_IMAPIProp) ||
  770.             IsEqualIID(piidDst, (LPIID) &IID_IMAPIFolder)))
  771.     {
  772.         LPMAPIPROP pmp = NULL;
  773.         hr = ((LPUNKNOWN) lpDestObj)->lpVtbl->QueryInterface(lpDestObj,
  774.             (LPIID) &IID_IMAPIProp, (LPVOID *) &pmp);
  775.         if (hr != hrSuccess)
  776.         {
  777.             Assert(GetScode(hr) == MAPI_E_INTERFACE_NOT_SUPPORTED);
  778.             goto exit;
  779.         }
  780.         UlRelease(pmp);
  781.     }
  782.     if (!FFoldInSameStore(pifldSrc, (PIFLD) lpDestObj))
  783.     {
  784.         LPMAPISUP psup = pifldSrc->pims->psup;
  785.         /* leave critical section before calling back to MAPI */
  786.         IFLD_LeaveCriticalSection(pifldSrc);
  787.         /* call MAPI's CopyProps */
  788.         hr = psup->lpVtbl->DoCopyProps(psup, (LPIID) &IID_IMAPIFolder,
  789.             (LPVOID) pifldSrc, ptagaIncl, ulUIParam,
  790.             lpProgress, piidDst, lpDestObj, ulFlagsIn, pprba);
  791.         DebugTraceResult(IFLD_CopyProps, hr);
  792.         return (HrCheckHr(hr, IMAPIProp_CopyProps));
  793.     }
  794.     /* copy them as folders */
  795.     if (fIsIMAPIFolder)
  796.     {
  797.         PIFLD pifldDst = (PIFLD) lpDestObj;
  798.         /* make sure we have write access */
  799.         if (!OBJ_TestFlag(pifldDst, OBJF_MODIFY))
  800.         {
  801.             hr = ResultFromScode(MAPI_E_NO_ACCESS);
  802.             goto exit;
  803.         }
  804.         if (FContainsProp(PR_CONTAINER_HIERARCHY, ptagaIncl))
  805.         {
  806.             /* can not move or copy a folder to a decendant or itself */
  807.             if (FIsAncestor(pifldSrc, pifldDst))
  808.                 hr = ResultFromScode(MAPI_E_NO_ACCESS);
  809.         }
  810.         else if (ulFlags & MAPI_MOVE)
  811.         {
  812.             /* Can't set MAPI_MOVE and also exclude subfolders. */
  813.             hr = ResultFromScode(MAPI_E_INVALID_PARAMETER);
  814.         }
  815.         if (hr != hrSuccess)
  816.             goto exit;
  817.         if (!(ulFlags & MAPI_NOREPLACE))
  818.         {
  819.             /* Empty the destination folder before beginning. */
  820.             hr = pifldDst->lpVtbl->EmptyFolder(pifldDst, 0, NULL, 0);
  821.             if (hr != hrSuccess)
  822.                 goto exit;
  823.         }
  824.         if (FContainsProp(PR_CONTAINER_CONTENTS, ptagaIncl))
  825.         {
  826.             /* copy the contents of the source folder to the destination folder */
  827.             hr = HrCopyContents(pifldSrc, pifldDst, ulFlags, NULL);
  828.         }
  829.         if (hr != hrSuccess)
  830.             goto exit;
  831.     }
  832.     /* copy the properties */
  833.     /* //$ Rebuild ptagaIncl without Contents and Hierarchy */
  834.     {
  835.         LPMESSAGE lpmsg;
  836.         BOOL fModify = FALSE;
  837.         if (ulFlags & MAPI_MOVE)
  838.             fModify = TRUE;
  839.         hr = HrOpenPropertyMessageRetry(pifldSrc->peid,
  840.             pifldSrc->pims, fModify, &lpmsg);
  841.         if (hr != hrSuccess)
  842.             goto exit;
  843.         hr = lpmsg->lpVtbl->CopyProps(lpmsg,
  844.             ptagaIncl, ulUIParam, lpProgress,
  845.             (LPIID) &IID_IMAPIProp, lpDestObj, ulFlags, pprba);
  846.         if (hr == hrSuccess && fModify)
  847.             lpmsg->lpVtbl->SaveChanges(lpmsg, KEEP_OPEN_READWRITE);
  848.         UlRelease(lpmsg);
  849.     }
  850. exit:
  851.     IFLD_LeaveCriticalSection(pifldSrc);
  852. #else
  853.     IFLD_LeaveCriticalSection(pifldSrc);
  854.     /* call MAPI's CopyProps */
  855.     hr = pifldSrc->pims->psup->lpVtbl->DoCopyProps(pifldSrc->pims->psup,
  856.         (LPIID) &IID_IMAPIFolder, (LPVOID) pifldSrc, ptagaIncl, ulUIParam,
  857.         lpProgress, piidDst, lpDestObj, ulFlagsIn, pprba);
  858. #endif  /* WHEN_WORKING */
  859.     DebugTraceResult(IFLD_CopyProps, hr);
  860.     return HrCheckHr(hr, IMAPIProp_CopyProps);
  861. }
  862. /***************************************************************************
  863.  -  IFLD_GetContentsTable
  864.  -
  865.  *  Purpose:
  866.  *      Returns a table with the summary information about the messages
  867.  *      in the folder
  868.  *
  869.  *  Parameters
  870.  *       pifld  the folder object
  871.  *       ulFlags    MAPI_DEFERRED_ERRORS, MAPI_ASSOCIATED
  872.  *       lppTable   location to place the table object
  873.  *
  874.  *  Returns:
  875.  *
  876.  *  Side effects:
  877.  *
  878.  *  Errors:
  879.  */
  880. STDMETHODIMP IFLD_GetContentsTable(PIFLD pifld, ULONG ulFlags,
  881.     LPMAPITABLE *lppTable)
  882. {
  883.     HRESULT hr = hrSuccess;
  884.     SCODE sc;
  885.     HANDLE hFindFile = FAILED_SEARCH;
  886.     LPTSTR szMessageTemplate = NULL;    /* template for a message name */
  887.     LPSSortOrderSet lpsSortOrder = NULL;
  888.     BOOL fTableCreated = FALSE;
  889.     BOOL fInMutex = FALSE;
  890.     PIMS pims;
  891.     FLD_ValidateParameters(
  892.             pifld, 
  893.             IMAPIContainer,
  894.             GetContentsTable,
  895.             (pifld, 
  896.             ulFlags,
  897.             lppTable));
  898.     #ifdef VALIDATE
  899.     if (ulFlags & MAPI_ASSOCIATED)
  900.         return ResultFromScode(MAPI_E_NO_SUPPORT);
  901.     
  902.     if (ulFlags & MAPI_UNICODE)
  903.         return ResultFromScode(MAPI_E_BAD_CHARWIDTH);
  904.     #endif
  905.     IFLD_EnterCriticalSection(pifld);
  906.     pims = pifld->pims;
  907.     /* If the table mutex doesn't yet exist on this process, create it. */
  908.     if (pims->hContTblMutex == NULL)
  909.     {
  910.         hr = HrCreateContTblMutex(&pims->hContTblMutex);
  911.         if (hr != hrSuccess)
  912.             goto exit;
  913.     }
  914.     if (pifld->lptblContents == NULL)
  915.     {
  916.         PINST pinst = (PINST) PvGetInstanceGlobals();
  917.         PLMR plmr = &pifld->pims->lmr;
  918.         if (pinst == NULL)
  919.         {
  920.             hr = ResultFromScode(MAPI_E_CALL_FAILED);
  921.             goto exit;
  922.         }
  923.         /* create the data for the table */
  924.         sc = CreateTable((LPIID) &IID_IMAPITableData,
  925.             plmr->lpAllocBuf, plmr->lpAllocMore,
  926.             plmr->lpFreeBuf, pinst->lpmalloc, TBLTYPE_DYNAMIC,
  927.             PR_INSTANCE_KEY, (LPSPropTagArray) &sPropTagsContents,
  928.             &(pifld->lptblContents));
  929.         if (sc != S_OK)
  930.         {
  931.             hr = ResultFromScode(sc);
  932.             goto exit;
  933.         }
  934.         fTableCreated = TRUE;
  935.         /* Get the table mutex so that we can access the file without */
  936.         /* crossing paths with another process. */
  937.         WaitForSingleObject(pims->hContTblMutex, INFINITE);
  938.         fInMutex = TRUE;
  939.         hr = HrReadTableFromDisk(pifld->lptblContents, (POBJ) pifld,
  940.             pifld->peid->szPath, CONTENTS_COLUMNS, szContentsFileName);
  941.         if (hr != hrSuccess)
  942.         {
  943.             /* non-fatal. If the data on disk is missing or invalid, we */
  944.             /* should regenerate the data via HrSyncContentsTable. */
  945.             TraceSz1("SMS: Error %s reading table from disk. Regenerating "
  946.                 "table on disk.", SzDecodeScode(GetScode(hr)));
  947.             hr = hrSuccess;
  948.         }
  949.     }
  950.     /* If we don't already have the mutex, get it so that we can access */
  951.     /* the file without crossing paths with another process. */
  952.     if (!fInMutex)
  953.     {
  954.         WaitForSingleObject(pims->hContTblMutex, INFINITE);
  955.         fInMutex = TRUE;
  956.     }
  957.     hr = HrSyncContentsTable(pifld, TRUE);
  958.     Assert(fInMutex);
  959.     ReleaseMutex(pims->hContTblMutex);
  960.     fInMutex = FALSE;
  961.     if (hr != hrSuccess)
  962.         goto exit;
  963.     /* open a view to the table */
  964.     /* get the sort order from the PR_SMS_CONTENTS_SORT_ORDER property */
  965.     hr = HrGetSortOrder(pifld, &lpsSortOrder);
  966.     if (hr != hrSuccess)
  967.         goto exit;
  968.     /* get the view */
  969.     hr = pifld->lptblContents->lpVtbl->HrGetView(pifld->lptblContents,
  970.         lpsSortOrder, ViewRelease, (ULONG) pifld, lppTable);
  971.     if (hr != hrSuccess)
  972.         goto exit;
  973.     /* record this view in pifld */
  974.     pifld->cContentsViews++;
  975. exit:
  976.     if (fInMutex)
  977.         ReleaseMutex(pims->hContTblMutex);
  978.     /* free the sort order */
  979.     LMFree(&pifld->pims->lmr, lpsSortOrder);
  980.     /* remove the table if it is created in error */
  981.     if (hr != hrSuccess && fTableCreated)
  982.     {
  983.         UlRelease(pifld->lptblContents);
  984.         pifld->cContentsViews = 0;
  985.         pifld->lptblContents = NULL;
  986.     }
  987.     CloseIDSearch(&hFindFile, &szMessageTemplate);
  988.     IFLD_LeaveCriticalSection(pifld);
  989.     DebugTraceResult(IFLD_GetContentsTable, hr);
  990.     return HrCheckHr(hr, IMAPIFolder_GetContentsTable);
  991. }
  992. /***************************************************************************
  993.  -  IFLD_GetHierarchyTable
  994.  -
  995.  *  Purpose:
  996.  *      Returns a table with the summary information about the child
  997.  *      folders of the current folder
  998.  *
  999.  *  Parameters
  1000.  *       pifld      the folder object
  1001.  *       ulFlags    CONVENIENT_DEPTH if set indicates pre-order traversal
  1002.  *                  MAPI_DEFERRED_ERRORS
  1003.  *                  MAPI_UNICODE
  1004.  *       lppTable   location to place the table object
  1005.  *
  1006.  *  Returns:
  1007.  *
  1008.  *  Side effects:
  1009.  *
  1010.  *  Errors:
  1011.  */
  1012. STDMETHODIMP IFLD_GetHierarchyTable(PIFLD pifld, ULONG ulFlags,
  1013.     LPMAPITABLE *lppTable)
  1014. {
  1015.     HRESULT hr;
  1016.     LPTABLEDATA lptad = NULL;
  1017.     FLD_ValidateParameters(
  1018.             pifld, 
  1019.             IMAPIContainer,
  1020.             GetHierarchyTable,
  1021.             (pifld, 
  1022.             ulFlags, 
  1023.             lppTable));
  1024.     #ifdef VALIDATE
  1025.     if (ulFlags & MAPI_UNICODE)
  1026.         return ResultFromScode(MAPI_E_BAD_CHARWIDTH);
  1027.     #endif
  1028.     IFLD_EnterCriticalSection(pifld);
  1029.     /* if table needs refreshing */
  1030.     if (pifld->lptblHierarchy == NULL)
  1031.     {
  1032.         PINST pinst = (PINST) PvGetInstanceGlobals();
  1033.         SCODE sc;
  1034.         PLMR plmr = &pifld->pims->lmr;
  1035.         pifld->cHierarchyViews = 0;
  1036.         if (pinst == NULL)
  1037.         {
  1038.             hr = ResultFromScode(MAPI_E_CALL_FAILED);
  1039.             goto exit;
  1040.         }
  1041.         /* create the table */
  1042.         sc = CreateTable((LPIID) &IID_IMAPITableData,
  1043.             plmr->lpAllocBuf, plmr->lpAllocMore,
  1044.             plmr->lpFreeBuf, pinst->lpmalloc, TBLTYPE_DYNAMIC,
  1045.             PR_INSTANCE_KEY, (LPSPropTagArray) &sPropTagsHierarchy, &lptad);
  1046.         if (sc != S_OK)
  1047.         {
  1048.             hr = ResultFromScode(sc);
  1049.             goto exit;
  1050.         }
  1051.         /* add a row or traversal for each subfolder of pifld */
  1052.         /* Note that the sample store only supports a max depth of 1. */
  1053.         hr = HrFillHierarchyTable(pifld, lptad);
  1054.         if (hr != hrSuccess)
  1055.             goto exit;
  1056.         pifld->lptblHierarchy = lptad;
  1057.         lptad = NULL;
  1058.     }
  1059.     /* open a view to the table */
  1060.     hr = pifld->lptblHierarchy->lpVtbl->HrGetView(pifld->lptblHierarchy,
  1061.         NULL, ViewRelease, (ULONG) pifld, lppTable);
  1062.     if (hr != hrSuccess)
  1063.         goto exit;
  1064.     /* record this view in pifld */
  1065.     pifld->cHierarchyViews++;
  1066. exit:
  1067.     /* remove the table if it is created in error */
  1068.     if (hr != hrSuccess && lptad)
  1069.         UlRelease(lptad);
  1070.     IFLD_LeaveCriticalSection(pifld);
  1071.     DebugTraceResult(IFLD_GetHierarchyTable, hr);
  1072.     return HrCheckHr(hr, IMAPIFolder_GetHierarchyTable);
  1073. }
  1074. /***************************************************************************
  1075.  -  IFLD_CreateMessage
  1076.  -
  1077.  *  Purpose:
  1078.  *      Creates a new message in the store
  1079.  *
  1080.  *  Parameters
  1081.  *      pifld           the folder object
  1082.  *      ulFlags         flags. Valid flags to pass are MAPI_DEFERRED_ERRORS
  1083.  *                      and MAPI_ASSOCIATED. The sample store doesn't support
  1084.  *                      MAPI_ASSOCIATED, so the code returns no support if
  1085.  *                      that flag is passed.
  1086.  *      piid            reserved for future use
  1087.  *      lppMessage      location to place the message object
  1088.  *
  1089.  *  Returns:
  1090.  *
  1091.  *  Side effects:
  1092.  *
  1093.  *  Errors:
  1094.  */
  1095. STDMETHODIMP IFLD_CreateMessage(PIFLD pifld, LPCIID piid, ULONG ulFlags,
  1096.     LPMESSAGE *lppMessage)
  1097. {
  1098.     HRESULT hr;
  1099.     PEID peid = NULL;
  1100.     ULONG ulSeqNumber;
  1101.     PIMSG pimsg = NULL;
  1102.     LPTSTR szFull = NULL;
  1103.     FLD_ValidateParameters(
  1104.             pifld, 
  1105.             IMAPIFolder,
  1106.             CreateMessage,
  1107.             (pifld, 
  1108.             piid, 
  1109.             ulFlags, 
  1110.             lppMessage));
  1111.     #ifdef VALIDATE
  1112.     if (ulFlags & MAPI_ASSOCIATED)
  1113.         return ResultFromScode(MAPI_E_NO_SUPPORT);
  1114.     if (piid && !FQueryInterface(OT_MESSAGE, piid))
  1115.         return ResultFromScode(MAPI_E_INTERFACE_NOT_SUPPORTED);
  1116.     #endif
  1117.     IFLD_EnterCriticalSection(pifld);
  1118.     if (!OBJ_TestFlag(pifld, OBJF_MODIFY))
  1119.     {
  1120.         hr = ResultFromScode(MAPI_E_NO_ACCESS);
  1121.         goto exit;
  1122.     }
  1123.     /* create the message */
  1124.     hr = HrNewEID(pifld, pifld->pims, TEMP_EXT, &ulSeqNumber, &peid);
  1125.     if (hr != hrSuccess)
  1126.         goto exit;
  1127.     hr = HrNewIMSG(peid, pifld->pims, TRUE, TRUE, ulSeqNumber, &szFull, &pimsg);
  1128.     if (hr != hrSuccess)
  1129.         goto exit;
  1130.     hr = InitIMSGProps(pimsg);
  1131.     if (hr != hrSuccess)
  1132.         goto exit;
  1133.     /* folder contents counts and tables are not updated until message */
  1134.     /* has changes saved */
  1135. exit:
  1136.     LMFree(&pifld->pims->lmr, peid);
  1137.     if (hr == hrSuccess)
  1138.         *lppMessage = (LPMESSAGE) pimsg;
  1139.     else if (pimsg)
  1140.     {
  1141.         UlRelease(pimsg);
  1142.         Assert(szFull);
  1143.         DeleteFile(szFull);
  1144.     }
  1145.     FreeNull(szFull);
  1146.     IFLD_LeaveCriticalSection(pifld);
  1147.     DebugTraceResult(IFLD_CreateMessage, hr);
  1148.     return HrCheckHr(hr, IMAPIFolder_CreateMessage);
  1149. }
  1150. /***************************************************************************
  1151.  -  IFLD_CopyMessages
  1152.  -
  1153.  *  Purpose:
  1154.  *      Moves/Copies messages from the source folder to the destination folder
  1155.  *      EntryId's are not changed here since they get stamped in when the
  1156.  *      messages are opened.
  1157.  *
  1158.  *  Parameters
  1159.  *      pifld                   the source folder
  1160.  *      lpMsgList               the list of messages to be moved/copied
  1161.  *      piid                    the interface id of destination folder
  1162.  *      lpfolderDst             the destination folder
  1163.  *      ulUIParam               Handle of parent window,
  1164.  *                                  ignored if MESSAGE_DIALOG not set
  1165.  *      lpProgress              points to progress dialog object
  1166.  *      ulFlags                 MAPI_DECLINE_OK, MESSAGE_MOVE, or MESSAGE_DIALOG
  1167.  */
  1168. STDMETHODIMP IFLD_CopyMessages(PIFLD pifld, LPENTRYLIST lpMsgList,
  1169.     LPCIID piid, LPMAPIFOLDER lpfolderDst, ULONG ulUIParam,
  1170.     LPMAPIPROGRESS lpProgress, ULONG ulFlags)
  1171. {
  1172.     LONG cHandled = 0;          /* number messages copied/moved */
  1173.     LPTSTR szSrcName = NULL;    /* name of file to be moved */
  1174.     LPTSTR szDestName = NULL;   /* name of the file after it is moved */
  1175.     ULONG cbSrcPath = 0;        /* length in bytes of path to src fld */
  1176.     ULONG cbDestPath = 0;       /* length in bytes of path to dest fld */
  1177.     ULONG cbStorePath = 0;      /* length in bytes of path to root of store */
  1178.     TCHAR szBlanks[CCH_NAME] = TEXT("        .   ");
  1179.     HRESULT hr = hrSuccess;
  1180.     PIFLD pifldDst;
  1181.     BOOL fMove;
  1182.     SBinary *psb;
  1183.     SBinary *psbMax;
  1184.     PIMS pims;
  1185.     FLD_ValidateParameters(
  1186.             pifld, 
  1187.             IMAPIFolder,
  1188.             CopyMessages,
  1189.             (pifld, 
  1190.             lpMsgList, 
  1191.             piid, 
  1192.             lpfolderDst, 
  1193.             ulUIParam, 
  1194.             lpProgress, 
  1195.             ulFlags));
  1196.     IFLD_EnterCriticalSection(pifld);
  1197.     pifldDst = (PIFLD) lpfolderDst;
  1198.     pims = pifld->pims;
  1199.     /* if the folders aren't in the same store, call back to MAPI */
  1200.     if (!FFoldInSameStore(pifld, pifldDst))
  1201.     {
  1202.         /* leave critical section before calling back to MAPI */
  1203.         IFLD_LeaveCriticalSection(pifld);
  1204.         return pims->psup->lpVtbl->CopyMessages(pims->psup,
  1205.             (LPIID) &IID_IMAPIFolder, (LPVOID) pifld, lpMsgList, piid,
  1206.             (LPVOID) lpfolderDst, ulUIParam, lpProgress, ulFlags);
  1207.     }
  1208.     fMove   = !!(ulFlags & MESSAGE_MOVE);
  1209.     if (    !OBJ_TestFlag(pifldDst, OBJF_MODIFY)
  1210.         ||  (   fMove
  1211.             &&  !OBJ_TestFlag(pifld, OBJF_MODIFY)))
  1212.     {
  1213.         hr = ResultFromScode(MAPI_E_NO_ACCESS);
  1214.         goto exit;
  1215.     }
  1216.     if (fMove)
  1217.     {
  1218.         /* If moving messages and the source and destination are the same */
  1219.         /* folder, we are done even before we begin. */
  1220.         ULONG ulTheSame;
  1221.         hr = pims->lpVtbl->CompareEntryIDs(pims,
  1222.                 CbEID(pifldDst->peid), (LPENTRYID) pifldDst->peid,
  1223.                 CbEID(pifld->peid), (LPENTRYID) pifld->peid, 0L, &ulTheSame);
  1224.         if (hr != hrSuccess)
  1225.             goto exit;
  1226.         if (ulTheSame)
  1227.         {
  1228.             hr = hrSuccess;
  1229.             goto exit;
  1230.         }
  1231.     }
  1232.     /* get storage for the path names */
  1233.     cbStorePath = Cbtszsize(pims->szStorePath);
  1234.     cbSrcPath = cbStorePath + CbEIDPath(pifld->peid);
  1235.     if (FIsRoot(pifld->peid))
  1236.         cbSrcPath--;
  1237.     cbDestPath = cbStorePath + CbEIDPath(pifldDst->peid);
  1238.     if (FIsRoot(pifldDst->peid))
  1239.         cbDestPath--;
  1240.     hr = HrFullPathName(pims->szStorePath, pifld->peid->szPath,
  1241.         szBlanks, &szSrcName);
  1242.     if (hr != hrSuccess)
  1243.         goto exit;
  1244.     hr = HrFullPathName(pims->szStorePath, pifldDst->peid->szPath,
  1245.         szBlanks, &szDestName);
  1246.     if (hr != hrSuccess)
  1247.         goto exit;
  1248.     psb = lpMsgList->lpbin;
  1249.     psbMax = psb + lpMsgList->cValues;
  1250.     /* move/copy each message */
  1251.     while (psb < psbMax)
  1252.     {
  1253.         ULONG ulMF;
  1254.         ULONG ulObjType;
  1255.         BOOL fLocked;
  1256.         BOOL fRead;
  1257.         PIMSG pimsg;
  1258.         LPSTR szRelativePath;
  1259.         PEID peidNewID;
  1260.         PEID peidToCopy;
  1261.         ULONG cbEntryID;
  1262.         cbEntryID = psb->cb;
  1263.         peidToCopy = (PEID) (psb->lpb);
  1264.         if (    FIsInvalidEID(cbEntryID, peidToCopy, pims)
  1265.             ||  !FIsMessage((PEID) peidToCopy))
  1266.         {
  1267.             hr = ResultFromScode(MAPI_E_INVALID_PARAMETER);
  1268.             goto exit;
  1269.         }
  1270.         /* open the message */
  1271.         hr = pifld->lpVtbl->OpenEntry(pifld, CbEID(peidToCopy),
  1272.                 (LPENTRYID) peidToCopy, NULL, 0L, &ulObjType,
  1273.                 (LPUNKNOWN *) &pimsg);
  1274.         if (hr != hrSuccess)
  1275.             goto exit;
  1276.         Assert(ulObjType == MAPI_MESSAGE);
  1277.         /* retrieve the PR_MESSAGE_FLAGS property */
  1278.         hr = HrGetSingleProp((LPMAPIPROP) pimsg->lpmsg, &pims->lmr,
  1279.                 PR_MESSAGE_FLAGS, &ulMF);
  1280.         UlRelease(pimsg);
  1281.         if (hr != hrSuccess)
  1282.             goto exit;
  1283.         fLocked = !!(ulMF & MSGFLAG_SUBMIT);
  1284.         fRead = !!(ulMF & MSGFLAG_READ);
  1285.         /* if the message is locked then this is an error */
  1286.         if (fLocked)
  1287.         {
  1288.             hr = ResultFromScode(MAPI_E_INVALID_PARAMETER);
  1289.             goto exit;
  1290.         }
  1291.         /* store in szSrcName the root relative path of the message to be moved*/
  1292.         lstrcpy(szSrcName + cbSrcPath, SzBaseName(peidToCopy));
  1293.         /* store in szDestName the store relative path name of */
  1294.         /* destination file */
  1295.         if (fMove)
  1296.             lstrcpy(szDestName + cbDestPath, SzBaseName(peidToCopy));
  1297.         else
  1298.         {
  1299.             /* If we're copying, we need to generate a new filename for the */
  1300.             /* message, or else we will have two messages with the same */
  1301.             /* filename, and copying again (or moving back) will fail. */
  1302.             PEID peidTemp = NULL;
  1303.             hr = HrNewEID(pifld, pims, MESSAGE_EXT, NULL, &peidTemp);
  1304.             if (hr != hrSuccess)
  1305.                 goto exit;
  1306.             lstrcpy(szDestName + cbDestPath, SzBaseName(peidTemp));
  1307.             LMFree(&pims->lmr, peidTemp);
  1308.         }
  1309.         /* either move or copy the message */
  1310.         if (fMove)
  1311.         {
  1312.             if (!MoveFile(szSrcName, szDestName))
  1313.             {
  1314.                 TraceSz1("MoveFile failed: OS error %08lX.", GetLastError());
  1315.                 hr = ResultFromScode(MAPI_E_NO_ACCESS);
  1316.                 goto exit;
  1317.             }
  1318.             /* remove this message from contents tables */
  1319.             (void) HrIncrementOneROProp(pifld, -1, PR_CONTENT_COUNT);
  1320.             if (!fRead)
  1321.                 (void) HrIncrementOneROProp(pifld, -1, PR_CONTENT_UNREAD);
  1322.             ChangeTable(pims, pifld->peid, peidToCopy, MAPI_MESSAGE,
  1323.                 TABLE_ROW_DELETED, TRUE);
  1324.         }
  1325.         else
  1326.         {
  1327.             if (!CopyFile(szSrcName, szDestName, TRUE))
  1328.             {
  1329.                 TraceSz1("CopyFile failed: OS error %08lX.", GetLastError());
  1330.                 hr = ResultFromScode(MAPI_E_NO_ACCESS);
  1331.                 goto exit;
  1332.             }
  1333.         }
  1334.         /* get new entryid for this message */
  1335.         hr = HrFullToRelative(szDestName, pims, &szRelativePath);
  1336.         if (hr != hrSuccess)
  1337.             goto exit;
  1338.         hr = HrConstructEID(&(peidToCopy->uidResource), &pims->lmr,
  1339.                 szRelativePath, &peidNewID);
  1340.         FreeNull(szRelativePath);
  1341.         if (hr != hrSuccess)
  1342.             goto exit;
  1343.         /* If we're copying, then we just used a new name for the file. */
  1344.         /* Note that PR_RECORD_KEY, PR_ENTRYID, PR_INSTANCE_KEY, and */
  1345.         /* PR_PARENT_ENTRYID are now different, but since these are stored */
  1346.         /* in the opened msg, everything should be fine. */
  1347.         /* add a row to the contents table of the destination folder */
  1348.         (void) HrIncrementOneROProp(pifldDst, 1, PR_CONTENT_COUNT);
  1349.         if (!fRead)
  1350.             (void) HrIncrementOneROProp(pifldDst, 1, PR_CONTENT_UNREAD);
  1351.         ChangeTable(pims, pifldDst->peid, peidNewID, MAPI_MESSAGE,
  1352.             TABLE_ROW_ADDED, TRUE);
  1353.         LMFree(&pims->lmr, peidNewID);
  1354.         cHandled++;
  1355.         psb++;
  1356.     }
  1357. exit:
  1358.     FreeNull(szDestName);
  1359.     FreeNull(szSrcName);
  1360.     IFLD_LeaveCriticalSection(pifld);
  1361.     DebugTraceResult(IFLD_CopyMessages, hr);
  1362.     return HrCheckHr(hr, IMAPIFolder_CopyMessages);
  1363. }
  1364. /***************************************************************************
  1365.  -  IFLD_DeleteMessages
  1366.  -
  1367.  *  Purpose:
  1368.  *      Deletes from the folder pifld all messages in the list lpMsgList
  1369.  *
  1370.  *  Parameters
  1371.  *      pifld           the folder from which messages are to be deleted
  1372.  *      lpMsgList       the list of messages to be deleted
  1373.  *      ulUIParam       handle to main window, cast to ULONG
  1374.  *      lpProgress      points to progress dialog information
  1375.  *      ulFlags         MESSAGE_DIALOG
  1376.  *
  1377.  *  Returns:
  1378.  *
  1379.  *  Side effects:
  1380.  *
  1381.  *  Errors:
  1382.  */
  1383. STDMETHODIMP IFLD_DeleteMessages(PIFLD pifld, LPENTRYLIST lpMsgList,
  1384.     ULONG ulUIParam, LPMAPIPROGRESS lpProgress, ULONG ulFlags)
  1385. {
  1386.     PEID peidToDelete = NULL;   /* pointer to next eid to be deleted */
  1387.     LONG cDeleted = 0;          /* number messages deleted */
  1388.     LONG cUnreadDeleted = 0;    /* number of unread messages deleted */
  1389.     LPTSTR szToDeleteName = NULL;   /* name of the next message to be deleted */
  1390.     HRESULT hr = hrSuccess;
  1391.     LPTSTR szBlankName = TEXT("        .   ");
  1392.     ULONG cchPath;              /* length of path to message */
  1393.     BOOL fIsRead;               /* TRUE if deleting a read message */
  1394.     DWORD dwErr;
  1395.     FLD_ValidateParameters(
  1396.             pifld, 
  1397.             IMAPIFolder,
  1398.             DeleteMessages,
  1399.             (pifld, 
  1400.             lpMsgList,
  1401.             ulUIParam, 
  1402.             lpProgress, 
  1403.             ulFlags));
  1404.     IFLD_EnterCriticalSection(pifld);
  1405.     if (!OBJ_TestFlag(pifld, OBJF_MODIFY))
  1406.     {
  1407.         hr = ResultFromScode(MAPI_E_NO_ACCESS);
  1408.         goto exit;
  1409.     }
  1410.     hr = HrFullPathName(pifld->pims->szStorePath, pifld->peid->szPath,
  1411.         szBlankName, &szToDeleteName);
  1412.     if (hr != hrSuccess)
  1413.         goto exit;
  1414.     cchPath = lstrlen(szToDeleteName) - lstrlen(szBlankName);
  1415.     /* delete each message in lpMsgList up until the first error */
  1416.     while ((ULONG) cDeleted < lpMsgList->cValues)
  1417.     {
  1418.         peidToDelete = (PEID) (lpMsgList->lpbin[cDeleted].lpb);
  1419.         /* make sure that this is a message's eid */
  1420.         if (!FIsMessage(peidToDelete))
  1421.         {
  1422.             hr = ResultFromScode(MAPI_E_INVALID_PARAMETER);
  1423.             goto exit;
  1424.         }
  1425.         /* make sure the message is not submitted */
  1426.         if (FIsSubmittedMessage(pifld->pims, peidToDelete))
  1427.         {
  1428.             hr = ResultFromScode(MAPI_E_SUBMITTED);
  1429.             goto exit;
  1430.         }
  1431.         /* See if it has been read */
  1432.         hr = HrIsRead(pifld, peidToDelete, &fIsRead);
  1433.         if (hr != hrSuccess)
  1434.             goto exit;
  1435.         /* remove the message from disk */
  1436.         lstrcpy(szToDeleteName + cchPath, SzBaseName(peidToDelete));
  1437.         if (!DeleteFile(szToDeleteName))
  1438.         {
  1439.             dwErr = GetLastError();
  1440.             if ((dwErr != ERROR_FILE_NOT_FOUND && dwErr != ERROR_PATH_NOT_FOUND)
  1441.                 || lpMsgList->cValues == 1)
  1442.             {
  1443.                 hr = ResultFromScode(MAPI_E_NO_ACCESS);
  1444.                 goto exit;
  1445.             }
  1446.         }
  1447.         /* remove this message from any open tables */
  1448.         ChangeTable(pifld->pims, pifld->peid, peidToDelete, MAPI_MESSAGE,
  1449.             TABLE_ROW_DELETED, TRUE);
  1450.         if (!fIsRead)
  1451.             cUnreadDeleted++;
  1452.         cDeleted++;
  1453.     }
  1454. exit:
  1455.     FreeNull(szToDeleteName);
  1456.     if (cDeleted)
  1457.         (void) HrIncrementOneROProp(pifld, -cDeleted, PR_CONTENT_COUNT);
  1458.     if (cUnreadDeleted)
  1459.         (void) HrIncrementOneROProp(pifld, -cUnreadDeleted, PR_CONTENT_UNREAD);
  1460.     IFLD_LeaveCriticalSection(pifld);
  1461.     DebugTraceResult(IFLD_DeleteMessages, hr);
  1462.     return HrCheckHr(hr, IMAPIFolder_DeleteMessages);
  1463. }
  1464. /***************************************************************************
  1465.  -  IFLD_CreateFolder
  1466.  -
  1467.  *  Purpose:
  1468.  *      Create a new folder within the message store
  1469.  *
  1470.  *  Parameters
  1471.  *      pifld               the parent folder of the newly created folder
  1472.  *      ulFldType           type of folder to be created
  1473.  *      szFldName           name of the new folder
  1474.  *      szComment           comment string for the new folder
  1475.  *      piid                Reserved; must be NULL.
  1476.  *      ulFlags             MAPI_UNICODE and/or MAPI_DEFERRED_ERRORS
  1477.  *      lppfolder           pointer to variable to receive new folder object
  1478.  *
  1479.  */
  1480. STDMETHODIMP IFLD_CreateFolder(PIFLD pifld, ULONG ulFldType, LPSTR szFldName,
  1481.     LPSTR szComment, LPCIID piid, ULONG ulFlags, LPMAPIFOLDER *lppfolder)
  1482. {
  1483.     HRESULT hr;
  1484.     PIFLD pifldNew = NULL;
  1485.     FLD_ValidateParameters(
  1486.             pifld, 
  1487.             IMAPIFolder,
  1488.             CreateFolder,
  1489.             (pifld, 
  1490.             ulFldType, 
  1491.             szFldName, 
  1492.             szComment, 
  1493.             piid, 
  1494.             ulFlags, 
  1495.             lppfolder));
  1496.     #ifdef VALIDATE
  1497.     if (ulFlags & MAPI_UNICODE)
  1498.         return ResultFromScode(MAPI_E_BAD_CHARWIDTH);
  1499.     if (piid && !FQueryInterface(OT_FOLDER, piid))
  1500.         return ResultFromScode(MAPI_E_INTERFACE_NOT_SUPPORTED);
  1501.     #endif
  1502.     /* Sample store can only create generic folders. */
  1503.     if (ulFldType != FOLDER_GENERIC)
  1504.         return ResultFromScode(MAPI_E_NO_SUPPORT);
  1505.     IFLD_EnterCriticalSection(pifld);
  1506.     if (!OBJ_TestFlag(pifld, OBJF_MODIFY))
  1507.     {
  1508.         hr = ResultFromScode(MAPI_E_NO_ACCESS);
  1509.         goto exit;
  1510.     }
  1511.     hr = HrCreateFolder(pifld, szFldName, szComment,
  1512.         !!(ulFlags & OPEN_IF_EXISTS), &pifldNew, NULL);
  1513.     if (hr != hrSuccess)
  1514.         UlRelease(pifldNew);
  1515.     else
  1516.         *lppfolder = (LPMAPIFOLDER) pifldNew;
  1517. exit:
  1518.     IFLD_LeaveCriticalSection(pifld);
  1519.     DebugTraceResult(IFLD_CreateFolder, hr);
  1520.     return HrCheckHr(hr, IMAPIFolder_CreateFolder);
  1521. }
  1522. /***************************************************************************
  1523.  -  IFLD_CopyFolder
  1524.  -
  1525.  *  Purpose:
  1526.  *      Copy my child folder to the specified parent
  1527.  *
  1528.  *  Parameters
  1529.  *      pifld           the parent folder of the newly created folder
  1530.  *      cbEntryID       length of entry ID of folder to copy
  1531.  *      lpEntryID       entry ID of folder to copy
  1532.  *      lpiid           interface to the destination folder
  1533.  *      lpfolder        pointer to destination object
  1534.  *      szNewName       new name to give the copied folder, may be NULL
  1535.  *      ulUIParam       Handle of parent window,
  1536.  *                      ignored if MESSAGE_DIALOG not set
  1537.  *      lpProgress      points to progress dialog information
  1538.  *      ulFlags         control flags
  1539.  *
  1540.  */
  1541. STDMETHODIMP IFLD_CopyFolder(PIFLD pifld, ULONG cbEntryID, LPENTRYID lpEntryID,
  1542.     LPCIID piid, LPVOID lpfolder, LPSTR szNewName,
  1543.     ULONG ulUIParam, LPMAPIPROGRESS lpProgress, ULONG ulFlags)
  1544. {
  1545.     HRESULT hr;
  1546.     FLD_ValidateParameters(
  1547.             pifld, 
  1548.             IMAPIFolder,
  1549.             CopyFolder,
  1550.             (pifld, 
  1551.             cbEntryID, 
  1552.             lpEntryID,
  1553.             piid, 
  1554.             lpfolder, 
  1555.             szNewName, 
  1556.             ulUIParam, 
  1557.             lpProgress, 
  1558.             ulFlags));
  1559.     #ifdef VALIDATE
  1560.     if (ulFlags & MAPI_UNICODE)
  1561.         return ResultFromScode(MAPI_E_BAD_CHARWIDTH);
  1562.     #endif
  1563.     /* For now, all we do is call back to mapi. */
  1564.     hr = pifld->pims->psup->lpVtbl->CopyFolder(pifld->pims->psup,
  1565.         (LPIID) &IID_IMAPIFolder, (LPVOID) pifld, cbEntryID, lpEntryID,
  1566.         piid, lpfolder, szNewName, ulUIParam, lpProgress, ulFlags);
  1567.     DebugTraceResult(IFLD_CopyFolder, hr);
  1568.     return HrCheckHr(hr, IMAPIFolder_CopyFolder);
  1569. }
  1570. /***************************************************************************
  1571.  -  IFLD_DeleteFolder
  1572.  -
  1573.  *  Purpose:
  1574.  *      Deletes a subfolder
  1575.  *
  1576.  *  Parameters
  1577.  *      pifld               the current folder
  1578.  *      cbEntryID           byte count of lpEntryID
  1579.  *      lpEntryID           entryID of subfolder to be deleted
  1580.  *      ulUIParam           handle to main window cast to ULONG
  1581.  *      lpProgress          pointer to progess dialog information
  1582.  *      ulFlags             DEL_MESSAGES and/or DEL_FOLDERS
  1583.  *                                  and/or FOLDER_DIALOG
  1584.  *
  1585.  *  Returns:
  1586.  *
  1587.  *  Errors:
  1588.  */
  1589. STDMETHODIMP IFLD_DeleteFolder(PIFLD pifld, ULONG cbEntryID,
  1590.     LPENTRYID lpEntryID, ULONG ulUIParam, LPMAPIPROGRESS lpProgress,
  1591.     ULONG ulFlags)
  1592. {
  1593.     HRESULT hr = hrSuccess;
  1594.     FLD_ValidateParameters(
  1595.             pifld, 
  1596.             IMAPIFolder,
  1597.             DeleteFolder,
  1598.             (pifld, 
  1599.             cbEntryID,
  1600.             lpEntryID, 
  1601.             ulUIParam, 
  1602.             lpProgress, 
  1603.             ulFlags));
  1604.     IFLD_EnterCriticalSection(pifld);
  1605.     if (FIsInvalidEID(cbEntryID, (PEID) lpEntryID, pifld->pims)
  1606.         || !FIsFolder((PEID) lpEntryID))
  1607.     {
  1608.         hr = ResultFromScode(MAPI_E_INVALID_ENTRYID);
  1609.         goto exit;
  1610.     }
  1611.     if (!OBJ_TestFlag(pifld, OBJF_MODIFY))
  1612.     {
  1613.         hr = ResultFromScode(MAPI_E_NO_ACCESS);
  1614.         goto exit;
  1615.     }
  1616.     /* delete this subdirectory of the current directory */
  1617.     hr = HrDeleteSubDirectory(pifld, (PEID) lpEntryID, ulFlags, FALSE);
  1618. exit:
  1619.     IFLD_LeaveCriticalSection(pifld);
  1620.     DebugTraceResult(IFLD_DeleteFolder, hr);
  1621.     return HrCheckHr(hr, IMAPIFolder_DeleteFolder);
  1622. }
  1623. STDMETHODIMP IFLD_SetSearchCriteria(PIFLD pifld, LPSRestriction lpRestriction,
  1624.     LPENTRYLIST lpentrylist, ULONG ulSearchFlags)
  1625. {
  1626.     DebugTraceSc(IFLD_SetSearchCriteria, MAPI_E_NO_SUPPORT);
  1627.     return ResultFromScode(MAPI_E_NO_SUPPORT);
  1628. }
  1629. STDMETHODIMP IFLD_GetSearchCriteria(PIFLD pifld, ULONG ulFlags,
  1630.     LPSRestriction *lppRestriction, LPENTRYLIST *lppfolderList, 
  1631.     ULONG *lpulSearchState)
  1632. {
  1633.     DebugTraceSc(IFLD_GetSearchCriteria, MAPI_E_NO_SUPPORT);
  1634.     return ResultFromScode(MAPI_E_NO_SUPPORT);
  1635. }
  1636. /***************************************************************************
  1637.  -  IFLD_SetReadFlags
  1638.  -
  1639.  *  Purpose:
  1640.  *      Sets the READ flag for each of the given messages.
  1641.  *
  1642.  *  Parameters
  1643.  *      pifld                   the source folder
  1644.  *      lpMsgList               the list of messages to be moved/copied
  1645.  *      ulUIParam               Handle of parent window,
  1646.  *                                  ignored if MESSAGE_DIALOG not set
  1647.  *      lpProgress              points to progress dialog object
  1648.  *      ulFlags                 SUPPRESS_RECEIPT, CLEAR_READ_FLAG
  1649.  */
  1650. STDMETHODIMP IFLD_SetReadFlags(PIFLD pifld, LPENTRYLIST lpMsgList,
  1651.     ULONG ulUIParam, LPMAPIPROGRESS lpProgress, ULONG ulFlags)
  1652. {
  1653.     HRESULT hr = hrSuccess;
  1654.     LPENTRYLIST pelst = NULL;
  1655.     BOOL fFreeList = FALSE;
  1656.     SBinary *psb;
  1657.     SBinary *psbMax;
  1658.     BOOL fMultipleNotifs = TRUE;
  1659.     FLD_ValidateParameters(
  1660.             pifld, 
  1661.             IMAPIFolder,
  1662.             SetReadFlags,
  1663.             (pifld, 
  1664.             lpMsgList, 
  1665.             ulUIParam, 
  1666.             lpProgress, 
  1667.             ulFlags));
  1668.     IFLD_EnterCriticalSection(pifld);
  1669.     if (!OBJ_TestFlag(pifld, OBJF_MODIFY))
  1670.     {
  1671.         hr = ResultFromScode(MAPI_E_NO_ACCESS);
  1672.         goto exit;
  1673.     }
  1674.     pelst = lpMsgList;
  1675.     if (pelst == NULL)
  1676.     {
  1677.         /* Create the message list if the caller didn't give us one. */
  1678.         hr = HrCreateMessageList(pifld, &pelst);
  1679.         if (hr != hrSuccess)
  1680.             goto exit;
  1681.         fFreeList = TRUE;
  1682.     }
  1683.     if (pelst->cValues > 5)
  1684.         fMultipleNotifs = FALSE;
  1685.     psb = pelst->lpbin;
  1686.     psbMax = psb + pelst->cValues;
  1687.     /* Call IMessage::SetReadFlag on each message */
  1688.     while (psb < psbMax)
  1689.     {
  1690.         ULONG ulObjType;
  1691.         PIMSG pimsg;
  1692.         PEID peid;
  1693.         ULONG cbEntryID;
  1694.         cbEntryID = psb->cb;
  1695.         peid = (PEID) (psb->lpb);
  1696.         if (    FIsInvalidEID(cbEntryID, peid, pifld->pims)
  1697.             ||  !FIsMessage((PEID) peid))
  1698.         {
  1699.             hr = ResultFromScode(MAPI_E_INVALID_PARAMETER);
  1700.             goto exit;
  1701.         }
  1702.         /* open the message */
  1703.         hr = pifld->lpVtbl->OpenEntry(pifld, CbEID(peid),
  1704.                 (LPENTRYID) peid, NULL, 0L, &ulObjType,
  1705.                 (LPUNKNOWN *) &pimsg);
  1706.         if (hr != hrSuccess)
  1707.             goto exit;
  1708.         Assert(ulObjType == MAPI_MESSAGE);
  1709.         hr = pimsg->lpVtbl->SetReadFlag(pimsg, ulFlags);
  1710.         if (hr == hrSuccess && fMultipleNotifs)
  1711.             ChangeTable(pimsg->pims, pifld->peid, pimsg->peid, MAPI_MESSAGE,
  1712.                 TABLE_ROW_MODIFIED, TRUE);
  1713.         UlRelease(pimsg);
  1714.         if (hr != hrSuccess)
  1715.             goto exit;
  1716.         psb++;
  1717.     }
  1718.     /* If several messages changed, then just send one notification to */
  1719.     /* re-sync the entire contents table on other processes. */
  1720.     if (!fMultipleNotifs)
  1721.         ChangeTable(pifld->pims, pifld->peid, NULL, MAPI_MESSAGE,
  1722.             TABLE_CHANGED, TRUE);
  1723. exit:
  1724.     if (fFreeList)
  1725.         DestroyMessageList(&pifld->pims->lmr, &pelst);
  1726.     IFLD_LeaveCriticalSection(pifld);
  1727.     DebugTraceResult(IFLD_SetReadFlags, hr);
  1728.     return HrCheckHr(hr, IMAPIFolder_SetReadFlags);
  1729. }
  1730. /***************************************************************************
  1731.  -  GetMessageStatus
  1732.  -
  1733.  *  Purpose:
  1734.  *      Retrieves the status associated with a message in a folder
  1735.  *
  1736.  *  Parameters
  1737.  *      pifld               the current folder
  1738.  *      cbEntryID           byte count of lpEntryID
  1739.  *      lpEntryID           entryID of the message
  1740.  *      ulFlags             reserved for future use, must be 0
  1741.  *      lpulMessageStatus   pointer to variable to receive the status
  1742.  *
  1743.  */
  1744. STDMETHODIMP IFLD_GetMessageStatus(PIFLD pifld, ULONG cbEntryID,
  1745.     LPENTRYID lpEntryID, ULONG ulFlags, ULONG *lpulMessageStatus)
  1746. {
  1747.     LPMESSAGE lpmsgMsg = NULL;  /* lpEntryID as an open message */
  1748.     ULONG ulObjType;            /* type of object opened */
  1749.     HRESULT hr = hrSuccess;
  1750.     FLD_ValidateParameters(
  1751.             pifld, 
  1752.             IMAPIFolder,
  1753.             GetMessageStatus,
  1754.             (pifld, 
  1755.             cbEntryID, 
  1756.             lpEntryID, 
  1757.             ulFlags, 
  1758.             lpulMessageStatus));
  1759.     IFLD_EnterCriticalSection(pifld);
  1760.     if (FIsInvalidEID(cbEntryID, (PEID) lpEntryID, pifld->pims)
  1761.         || !FIsMessage((PEID) lpEntryID))
  1762.     {
  1763.         hr = ResultFromScode(MAPI_E_INVALID_ENTRYID);
  1764.         goto exit;
  1765.     }
  1766.     /* open up lpEntryID */
  1767.     hr = pifld->lpVtbl->OpenEntry(pifld, cbEntryID,
  1768.         lpEntryID, NULL, 0L, &ulObjType, (LPUNKNOWN *) &lpmsgMsg);
  1769.     if (hr != hrSuccess)
  1770.         goto exit;
  1771.     /* get the property */
  1772.     hr = HrGetSingleProp((LPMAPIPROP) lpmsgMsg, &pifld->pims->lmr,
  1773.         PR_MSG_STATUS, lpulMessageStatus);
  1774.     if (hr != hrSuccess)
  1775.         goto exit;
  1776. exit:
  1777.     UlRelease(lpmsgMsg);
  1778.     IFLD_LeaveCriticalSection(pifld);
  1779.     DebugTraceResult(IFLD_GetMessageStatus, hr);
  1780.     return HrCheckHr(hr, IMAPIFolder_GetMessageStatus);
  1781. }
  1782. /***************************************************************************
  1783.  -  SetMessageStatus
  1784.  -
  1785.  *  Purpose:
  1786.  *      Sets the 32-bit status associated with a message in a folder
  1787.  *
  1788.  *  Parameters
  1789.  *      pifld               the current folder
  1790.  *      cbEntryID           byte count of lpentryID
  1791.  *      lpEntryID           entryID of the message
  1792.  *      ulNewStatus         new status to be assigned
  1793.  *      ulNewStatusMask     mask applied to new status indicating bits to set
  1794.  *      lpulOldStatus       pointer to variable to hold previous status
  1795.  *
  1796.  */
  1797. STDMETHODIMP IFLD_SetMessageStatus(PIFLD pifld, ULONG cbEntryID,
  1798.     LPENTRYID lpEntryID, ULONG ulNewStatus, ULONG ulNewStatusMask,
  1799.     ULONG *lpulOldStatus)
  1800. {
  1801.     PIMSG pimsg = NULL;
  1802.     LPMESSAGE lpmsg;
  1803.     ULONG ulObjType;            /* type of object just opened */
  1804.     HRESULT hr = hrSuccess;
  1805.     ULONG ulStatus;
  1806.     FLD_ValidateParameters(
  1807.             pifld, 
  1808.             IMAPIFolder,
  1809.             SetMessageStatus,
  1810.             (pifld, 
  1811.             cbEntryID, 
  1812.             lpEntryID, 
  1813.             ulNewStatus, 
  1814.             ulNewStatusMask, 
  1815.             lpulOldStatus));
  1816.     IFLD_EnterCriticalSection(pifld);
  1817.     if (FIsInvalidEID(cbEntryID, (PEID) lpEntryID, pifld->pims) ||
  1818.         !FIsMessage((PEID) lpEntryID))
  1819.     {
  1820.         hr = ResultFromScode(MAPI_E_INVALID_ENTRYID);
  1821.         goto exit;
  1822.     }
  1823.     if (    ulNewStatusMask
  1824.         &&  !OBJ_TestFlag(pifld, OBJF_MODIFY))
  1825.     {
  1826.         hr = ResultFromScode(MAPI_E_NO_ACCESS);
  1827.         goto exit;
  1828.     }
  1829.     /* open up lpEntryID */
  1830.     hr = pifld->lpVtbl->OpenEntry(pifld, CbEID((PEID) lpEntryID),
  1831.         lpEntryID, NULL, 0L, &ulObjType, (LPUNKNOWN *) &pimsg);
  1832.     if (hr != hrSuccess)
  1833.         goto exit;
  1834.     lpmsg = pimsg->lpmsg;
  1835.     /* get the old status */
  1836.     hr = HrGetSingleProp((LPMAPIPROP) lpmsg, &pifld->pims->lmr,
  1837.         PR_MSG_STATUS, &ulStatus);
  1838.     if (hr != hrSuccess)
  1839.         goto exit;
  1840.     if (lpulOldStatus)
  1841.         *lpulOldStatus = ulStatus;
  1842.     if (ulNewStatusMask)
  1843.     {
  1844.         ulNewStatus &= ulNewStatusMask;
  1845.         ulStatus &= ~ulNewStatusMask;
  1846.         ulStatus |= ulNewStatus;
  1847.         hr = HrSetOneROProp(lpmsg, &pifld->pims->lmr, PR_MSG_STATUS,
  1848.             &ulStatus);
  1849.         if (hr != hrSuccess)
  1850.             goto exit;
  1851.         hr = lpmsg->lpVtbl->SaveChanges(lpmsg, KEEP_OPEN_READWRITE);
  1852.         UlRelease(pimsg);
  1853.         pimsg = NULL;
  1854.         if (hr != hrSuccess)
  1855.             goto exit;
  1856.         ChangeTable(pifld->pims, pifld->peid, (PEID) lpEntryID, MAPI_MESSAGE,
  1857.             TABLE_ROW_MODIFIED, TRUE);
  1858.     }
  1859. exit:
  1860.     UlRelease(pimsg);
  1861.     IFLD_LeaveCriticalSection(pifld);
  1862.     DebugTraceResult(IFLD_SetMessageStatus, hr);
  1863.     return HrCheckHr(hr, IMAPIFolder_SetMessageStatus);
  1864. }
  1865. /***************************************************************************
  1866.  -  IFLD_SaveContentsSort
  1867.  -
  1868.  *  Purpose:
  1869.  *      set default sort order for contents tables on pifld
  1870.  *
  1871.  *  Parameters
  1872.  *      pifld               the current folder
  1873.  *      lpSortCriteria      points to the sort criteria
  1874.  *      ulFlags             RECURSIVE_SORT
  1875.  *
  1876.  */
  1877. STDMETHODIMP IFLD_SaveContentsSort(PIFLD pifld, LPSSortOrderSet lpSortCriteria,
  1878.     ULONG ulFlags)
  1879. {
  1880.     SPropValue pval;            /* sort order property value */
  1881.     LPSPropProblemArray pprba = NULL;
  1882.     HRESULT hr = hrSuccess;
  1883.     FLD_ValidateParameters(
  1884.             pifld, 
  1885.             IMAPIFolder,
  1886.             SaveContentsSort,
  1887.             (pifld, 
  1888.             lpSortCriteria,
  1889.             ulFlags));
  1890.     IFLD_EnterCriticalSection(pifld);
  1891.     pval.Value.MVl.lpl = NULL;
  1892.     /* store the sort order in pval */
  1893.     pval.ulPropTag = PR_SMS_CONTENTS_SORT_ORDER;
  1894.     pval.Value.MVl.cValues = 2 * lpSortCriteria->cSorts;
  1895.     pval.Value.MVl.lpl = (LONG *) lpSortCriteria->aSort;
  1896.     /*  set the sort order property */
  1897.     hr = pifld->lpVtbl->SetProps(pifld, 1, &pval, &pprba);
  1898.     if (pprba)
  1899.     {
  1900.         LMFree(&pifld->pims->lmr, pprba);
  1901.         hr = ResultFromScode(MAPI_E_CALL_FAILED);
  1902.     }
  1903.     IFLD_LeaveCriticalSection(pifld);
  1904.     DebugTraceResult(IFLD_SaveContentsSort, hr);
  1905.     return HrCheckHr(hr, IMAPIFolder_SaveContentsSort);
  1906. }
  1907. /*
  1908.  *  IFLD_EmptyFolder
  1909.  *
  1910.  *  Purpose:
  1911.  *      This function empties a folder based on the flags given. It will never
  1912.  *      actually delete the folder itself, and will only empty the specified
  1913.  *      items.
  1914.  *
  1915.  *  Parameters
  1916.  *      pifld           The address of the folder object to empty.
  1917.  *      ulUIParam       Handle of the parent window. (for progress). NYI
  1918.  *      lpProgress      Address of progress dialog object
  1919.  *      ulFlags         Control flags. Setting DEL_ASSOCIATED causes FAI
  1920.  *                      to also be deleted. The FOLDER_DIALOG flag is NYI.
  1921.  *                      DEL_ASSOCIATED has no meaning to the sample store.
  1922.  *
  1923.  *  Returns:
  1924.  */
  1925. STDMETHODIMP IFLD_EmptyFolder(PIFLD pifld, ULONG ulUIParam,
  1926.     LPMAPIPROGRESS lpProgress, ULONG ulFlags)
  1927. {
  1928.     HRESULT hr;
  1929.     PIFLD pifldParent = NULL;
  1930.     FLD_ValidateParameters(
  1931.             pifld, 
  1932.             IMAPIFolder,
  1933.             EmptyFolder,
  1934.             (pifld, 
  1935.             ulUIParam, 
  1936.             lpProgress, 
  1937.             ulFlags));
  1938.     IFLD_EnterCriticalSection(pifld);
  1939.     if (!OBJ_TestFlag(pifld, OBJF_MODIFY))
  1940.     {
  1941.         hr = ResultFromScode(MAPI_E_NO_ACCESS);
  1942.         goto exit;
  1943.     }
  1944.     /* Empty the folder. */
  1945.     hr = HrOpenParent(pifld->pims, pifld->peid, MAPI_MODIFY, &pifldParent);
  1946.     if (hr != hrSuccess)
  1947.         goto exit;
  1948.     hr = HrDeleteSubDirectory(pifldParent, pifld->peid,
  1949.         (DEL_MESSAGES | DEL_FOLDERS), TRUE);
  1950.     if (hr != hrSuccess)
  1951.         goto exit;
  1952. exit:
  1953.     UlRelease(pifldParent);
  1954.     IFLD_LeaveCriticalSection(pifld);
  1955.     DebugTraceResult(IFLD_EmptyFolder, hr);
  1956.     return HrCheckHr(hr, IMAPIFolder_EmptyFolder);
  1957. }
  1958. /****************************************************
  1959.  *          Private Functions                       *
  1960.  ****************************************************/
  1961. /*
  1962.  *  IFLD_IsInvalid
  1963.  *
  1964.  *  Purpose         check if pifld points to an invalid folder.
  1965.  *
  1966.  *  Parameter
  1967.  *      pifld       pointer to the folder
  1968.  *
  1969.  *  Returns: BOOL - TRUE means the folder is invalid.
  1970.  */
  1971. static BOOL IFLD_IsInvalid(PIFLD pifld)
  1972. {
  1973.     return (IsBadWritePtr(pifld, sizeof(IFLD)) ||
  1974.         pifld->lpVtbl != &vtblIFLD);
  1975. }
  1976. /* 
  1977.  * HrCreateContTblMutex
  1978.  *
  1979.  *  Purpose
  1980.  *      Create the contents table mutex, and return it to the caller.
  1981.  *
  1982.  *  Arguments
  1983.  *      phCTMutex: Pointer to the location to return the new mutex.
  1984.  *
  1985.  *  Returns:
  1986.  *      HRESULT: Will return an error only if the CreateMutex call fails.
  1987.  */
  1988. static HRESULT HrCreateContTblMutex(HANDLE *phCTMutex)
  1989. {
  1990.     HRESULT hr = hrSuccess;
  1991.     HANDLE hMutex;
  1992.     LPTSTR szMutexName = "SMS_CONTTBLFILE_MUTEX";
  1993.     hMutex = CreateMutex(NULL, FALSE, szMutexName);
  1994.     if (hMutex)
  1995.         *phCTMutex = hMutex;
  1996.     #ifndef WIN16
  1997.     else
  1998.     {
  1999.         TraceSz1("SampleMS: HrCreateContTblMutex: call to"
  2000.             " CreateMutex failed (error %08lX)", GetLastError());
  2001.         
  2002.         hr = ResultFromScode(MAPI_E_CALL_FAILED);
  2003.     }
  2004.     #endif
  2005.     DebugTraceResult(HrCreateContTblMutex, hr);
  2006.     return hr;
  2007. }
  2008. /*
  2009.  *  FFoldInSameStore
  2010.  *
  2011.  *  Purpose
  2012.  *      Given that the source folder is a folder object within
  2013.  *      our store (i.e. it's a PIFLD, not LPMAPIFOLDER), check if the
  2014.  *      destination folder object is also within the same store.
  2015.  *
  2016.  *  Parameters
  2017.  *      pifld: The folder that we already know is within this store.
  2018.  *      lpDestFld: The folder that we are checking. It may not be in this store.
  2019.  *
  2020.  *  Returns: BOOL - TRUE means the folders are both in this store.
  2021.  *
  2022.  */
  2023. static BOOL FFoldInSameStore(PIFLD pifld, PIFLD lpDestFld)
  2024. {
  2025.     if (IsBadWritePtr(lpDestFld, sizeof(IFLD)))
  2026.         return FALSE;
  2027.     if (lpDestFld->lpVtbl != &vtblIFLD)
  2028.         return FALSE;
  2029.     if (pifld->pims != lpDestFld->pims)
  2030.         return FALSE;
  2031.     return TRUE;
  2032. }
  2033. /***************************************************************************
  2034.  *  IFLD_Neuter
  2035.  *
  2036.  *  Purpose     Free all memory allocated inside a folder object, and release
  2037.  *              any objects held inside a folder object. Leaves the object
  2038.  *              itself alone (the caller will free it).
  2039.  *
  2040.  *  Argument    pifld       the folder to be cleaned out.
  2041.  *
  2042.  */
  2043. void IFLD_Neuter(PIFLD pifld)
  2044. {
  2045.     /* free allocated memory */
  2046.     FreeNull(pifld->peid);
  2047.     LMFree(&pifld->pims->lmr, pifld->pval);
  2048.     /* remove any tables */
  2049.     if (pifld->lptblContents)
  2050.     {
  2051.         TraceSz1("SampleMS (IFLD_Neuter): %d contents table views left",
  2052.             pifld->cContentsViews);
  2053.         UlRelease(pifld->lptblContents);
  2054.         pifld->cContentsViews = 0;
  2055.         pifld->lptblContents = NULL;
  2056.     }
  2057.     if (pifld->lptblHierarchy)
  2058.     {
  2059.         TraceSz1("SampleMS (IFLD_Neuter): %d hierarchy table views left",
  2060.             pifld->cHierarchyViews);
  2061.         UlRelease(pifld->lptblHierarchy);
  2062.         pifld->cHierarchyViews = 0;
  2063.         pifld->lptblHierarchy = NULL;
  2064.     }
  2065.     return;
  2066. }
  2067. /*
  2068.  -  ViewRelease
  2069.  -
  2070.  *  Purpose:
  2071.  *      Call back function from itable on release of a view
  2072.  *      removes the view from the list of open views
  2073.  *      releases the table if there are no more open views on it
  2074.  *
  2075.  *  Parameters
  2076.  *       ulCallerData   pointer to folder object
  2077.  *       lptbl          pointer to the table on which this is a view
  2078.  *       lpvtView       pointer to the view that was released
  2079.  *
  2080.  *
  2081.  */
  2082. STDAPI_(void)ViewRelease(ULONG ulCallerData, LPTABLEDATA lptbl,
  2083.     LPMAPITABLE lpvtView)
  2084. {
  2085.     PIFLD pifld;                /* folder object for this view */
  2086.     ULONG *pulViewsLeft;        /* ptr to number of open views left */
  2087.     LPTABLEDATA *pptbl;         /* ptr to folder's internal table data */
  2088.     pifld = (PIFLD) ulCallerData;
  2089.     /* do nothing if the folder is invalid. Don't use IFLD_IsInvalid */
  2090.     /* because the folder may have already been released, and we still */
  2091.     /* want to release the view in that case. */
  2092.     if (IsBadWritePtr(pifld, sizeof(IFLD)))
  2093.         return;
  2094.     IFLD_EnterCriticalSection(pifld);
  2095.     /* find the kind of table this view is on */
  2096.     if (pifld->lptblContents == lptbl)
  2097.     {
  2098.         pulViewsLeft = &(pifld->cContentsViews);
  2099.         pptbl = &(pifld->lptblContents);
  2100.     }
  2101.     else if (pifld->lptblHierarchy == lptbl)
  2102.     {
  2103.         pulViewsLeft = &(pifld->cHierarchyViews);
  2104.         pptbl = &(pifld->lptblHierarchy);
  2105.     }
  2106.     else
  2107.     {
  2108.         /* invalid table */
  2109.         TrapSz("Invalid call to ViewRelease");
  2110.         goto exit;
  2111.     }
  2112.     AssertSz(*pptbl == lptbl, "Different table data given to ViewRelease");
  2113.     /* decrement count of views and release*/
  2114.     /* the table data if the viewlist is empty */
  2115.     if (--(*pulViewsLeft) == 0)
  2116.     {
  2117.         POBJ pobj = (POBJ) pifld;
  2118.         UlRelease(lptbl);
  2119.         *pptbl = NULL;
  2120.         /* These tests are the same as IFLD_Release in this module. That is */
  2121.         /* the release method that folders use. */
  2122.         if (    pobj->cRef == 0
  2123.             &&  pobj->pobjHead == 0
  2124.             &&  pifld->lptblContents == NULL
  2125.             &&  pifld->lptblHierarchy == NULL)
  2126.         {
  2127.             OBJ_Destroy(pobj);  /* will leave the critical section */
  2128.             return;
  2129.         }
  2130.     }
  2131. exit:
  2132.     IFLD_LeaveCriticalSection(pifld);
  2133.     return;
  2134. }
  2135. /*
  2136.  *  HrIsRead
  2137.  *
  2138.  *  Purpose
  2139.  *      Given a parent folder and the entryid of a message, determine
  2140.  *      whether the message has been read (i.e., whether the MSGFLAG_READ
  2141.  *      bit inside the PR_MESSAGE_FLAGS property is set).
  2142.  *
  2143.  *  Parameters
  2144.  *      pifld       A pointer to the parent folder object of the message.
  2145.  *      peidMsg     The entryid of the message.
  2146.  *      pfRead      A pointer to the location to return a BOOL saying
  2147.  *                  whether or not the message was read. Set to TRUE
  2148.  *                  if the message was read, FALSE otherwise.
  2149.  */
  2150. static HRESULT HrIsRead(PIFLD pifld, PEID peidMsg, BOOL *pfRead)
  2151. {
  2152.     HRESULT hr;
  2153.     PIMSG pimsg = NULL;         /* opened version of lpidMsg */
  2154.     ULONG ulObjType;            /* type of object opened */
  2155.     ULONG ulMF;
  2156.     /* open the message */
  2157.     hr = pifld->lpVtbl->OpenEntry(pifld, CbEID(peidMsg), (LPENTRYID) peidMsg,
  2158.         NULL, 0L, &ulObjType, (LPUNKNOWN *) &pimsg);
  2159.     if (hr != hrSuccess)
  2160.         goto exit;
  2161.     Assert(ulObjType == MAPI_MESSAGE);
  2162.     /* retrieve the PR_MESSAGE_FLAGS property */
  2163.     hr = HrGetSingleProp((LPMAPIPROP) pimsg->lpmsg, &pifld->pims->lmr,
  2164.             PR_MESSAGE_FLAGS, &ulMF);
  2165.     /* set pfRead: no PR_MESSAGE_FLAGS means unread */
  2166.     /* The "!!" operator is used to change a bit that is set anywhere in a */
  2167.     /* word to exactly TRUE (only one bit set at the far right of the word). */
  2168.     /* The first "!" is NOT, which makes all zeros in the value into TRUE, */
  2169.     /* and anything else into FALSE. The second "!" reverses that back, so */
  2170.     /* that all zeros become FALSE, and anything else becomes TRUE. */