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

Windows编程

开发平台:

Visual C++

  1. /*
  2.  *  M S P R F S . C
  3.  *
  4.  *  Code for implementing Get/SetReceiveFolder for the Message
  5.  *  Store object.
  6.  *
  7.  *  Hungarian shorthand:
  8.  *      To avoid excessively long identifier names, throughout this
  9.  *      file, RFS is used to mean "Receive Folder Settings", and RFN
  10.  *      is used to mean an RFS Node.
  11.  *
  12.  *  Copyright 1992-1995 Microsoft Corporation.  All Rights Reserved.
  13.  */
  14. #include "msp.h"
  15. /* Manifest constants */
  16. TCHAR szRFSStreamName[] = TEXT("RFS_STREAM");
  17. /* GRoup of Flags (grf):
  18.  *
  19.  * grfStorageOpen:      Flags used to open a read/write OLE IStorage object.
  20.  * grfStorageOpenRO:    Flags used to open a read only OLE IStorage object.
  21.  * grfStorageCreate:    Flags used to create an OLE IStorage object.
  22.  * grfStreamOpen:       Flags used to open a read/write OLE IStream object.
  23.  * grfStreamOpenRO:     Flags used to open a read only OLE IStream object.
  24.  * grfStreamCreate:     Flags used to create an OLE IStream object.
  25.  *
  26.  * See the OLE 2 Programmer's Reference for details on these flags.
  27.  */
  28. #define grfStorageOpen      STGM_READWRITE | STGM_SHARE_EXCLUSIVE | 
  29.                                 STGM_TRANSACTED
  30. #define grfStorageOpenRO    STGM_READ | STGM_SHARE_EXCLUSIVE | 
  31.                                 STGM_TRANSACTED
  32. #define grfStorageCreate    grfStorageOpen | STGM_FAILIFTHERE | STGM_CREATE
  33. #define grfStreamOpen       STGM_SHARE_EXCLUSIVE | STGM_READWRITE
  34. #define grfStreamOpenRO     STGM_SHARE_EXCLUSIVE | STGM_READ
  35. #define grfStreamCreate     grfStreamOpen | STGM_FAILIFTHERE
  36. /* Function prototypes */
  37. static HRESULT OpenRFSStream(PRFS prfs, BOOL fModify, IStream **lppstream,
  38.     LPSTORAGE *lppstg);
  39. static void CloseRFSStream(IStream * lpstream, LPSTORAGE lpstg);
  40. /*
  41.  *  Exported functions
  42.  */
  43. /*
  44.  *  FIsValidMessageClass
  45.  *
  46.  *  Purpose:
  47.  *      Checks to see if a message class is valid.  A valid message
  48.  *      class is defined to be a series of one or more
  49.  *      period-delimited tokens with each token being a series of
  50.  *      one or more ASCII characters in the range 32-126
  51.  *      (inclusive) excluding period.  Note that this definition
  52.  *      excludes message classes with a leading or trailing
  53.  *      period, or two or more consecutive periods, because this
  54.  *      would imply the existence of a zero-length token.
  55.  *
  56.  *      We put this function in the RFS module because dealing with
  57.  *      receive folders is the primary place in the Sample Store where we
  58.  *      care about message class.
  59.  *
  60.  *  Arguments:
  61.  *      szMessageClass  String identifying the message class.
  62.  *
  63.  *  Returns:
  64.  *      BOOL.  TRUE if szMessage is valid, FALSE if not.
  65.  *
  66.  *  Side effects:
  67.  *      None.
  68.  *
  69.  *  Errors:
  70.  *      None.
  71.  */
  72. BOOL FIsValidMessageClass(LPTSTR szMessageClass)
  73. {
  74.     TCHAR *pch = szMessageClass;
  75.     BOOL fWasPeriod = TRUE;
  76.     if (szMessageClass && IsBadStringPtr(szMessageClass, (UINT) -1))
  77.         return FALSE;
  78.     /* Handle the default message class */
  79.     if (!szMessageClass || *szMessageClass == '')
  80.         return TRUE;
  81.     /* disallow things:bad chars and cases where */
  82.     /* period is not a delim(.1, 1., and 1. .1 bad) */
  83.     while (*pch)
  84.     {
  85.         if (*pch < 32 || *pch > 126)
  86.             return FALSE;
  87.         if (*pch == '.')
  88.         {
  89.             if (fWasPeriod)
  90.                 return FALSE;
  91.             fWasPeriod = TRUE;
  92.         }
  93.         else
  94.             fWasPeriod = FALSE;
  95.         pch++;
  96.     }
  97.     return !fWasPeriod;
  98. }
  99. /*
  100.  *  OpenRFS
  101.  *
  102.  *  Purpose:
  103.  *      Given an OLE2 storage object, opens a stream on it and
  104.  *      prepares it for handling receive folder settings.  OpenRFS
  105.  *      returns to the caller a pointer to the RFS structure which
  106.  *      is then used for access to the settings.  The stream format
  107.  *      of the receive folder settings is extremely simple:  the
  108.  *      first ULONG is a count of the number of RFNs in the
  109.  *      stream, and the nodes themselves follow sequentially
  110.  *      afterward.  A node on disk is not the same as an RFN in
  111.  *      memory.  On disk, it is a variable-sized structure
  112.  *      containing a ULONG which is the size (in bytes) of the
  113.  *      node not including this field, then a ULONG which is the
  114.  *      length (in bytes) of a
  115.  *      string containing the message class (NULL inclusive), which
  116.  *      immediately follows.  After that is a ULONG which is the
  117.  *      size (in bytes) of a string containing the relative path
  118.  *      name of the receive folder (NULL inclusive), which also
  119.  *      immediately follows.  Visually, a node looks like the
  120.  *      following:
  121.  *
  122.  *          +--------------------+
  123.  *          | ULONG cbNode       |
  124.  *          +--------------------+
  125.  *          | ULONG cbClass      |
  126.  *          +--------------------+
  127.  *          | TCHAR szClass[]    |
  128.  *          |   .                |
  129.  *          |   .                |
  130.  *          |   .                |
  131.  *          +--------------------+
  132.  *          | ULONG cbPath       |
  133.  *          +--------------------+
  134.  *          | TCHAR szPath[]     |
  135.  *          |   .                |
  136.  *          |   .                |
  137.  *          |   .                |
  138.  *          +--------------------+
  139.  *
  140.  *      The size of the message class name, cbClass, will always be
  141.  *      > 0 for "valid" nodes (the default message class will be a
  142.  *      NULL string of size 1 TCHAR).  Thus, a value of 0 for
  143.  *      cbClass will signify a "free" node.  Free nodes are created
  144.  *      in the normal use of the stream by DeleteRFN, which
  145.  *      SetReceiveFolder calls, and are removed at close time (see
  146.  *      CloseRFS, below).
  147.  *
  148.  *      Note that, because string lengths are byte-sized but the
  149.  *      strings themselves are made of TCHARs, translation between
  150.  *      BYTE and TCHAR sizes must be done.
  151.  *
  152.  *  Arguments:
  153.  *      szStoreRoot Full path to the sample store "root"
  154.  *                      directory.
  155.  *      szFile      Relative path name of docfile containing
  156.  *                      receive folder settings.
  157.  *      ulFlags         Flags.  The following are defined:
  158.  *                      RFS_CREATE  Create the docfile containing
  159.  *                                  receive folder settings
  160.  *                                  (default opens existing).
  161.  *      pprfs           Location in which to return a pointer to
  162.  *                      the newly created RFS structure.
  163.  *
  164.  *  Returns:
  165.  *      HRESULT
  166.  *
  167.  *  Side effects:
  168.  *      None.
  169.  *
  170.  *  Errors:
  171.  *      Various.
  172.  */
  173. HRESULT OpenRFS(LPTSTR szStoreRoot, LPTSTR szFile, ULONG ulFlags, PRFS *pprfs)
  174. {
  175.     HRESULT hr = hrSuccess;
  176.     HRESULT hrStg = hrSuccess;
  177.     SCODE sc;
  178.     LPTSTR szFullPath = NULL;
  179.     ULONG cRFN = 0L;
  180.     LPSTORAGE lpstg = NULL;
  181.     IStream *lpstream = NULL;
  182.     PRFS prfs = NULL;
  183. #ifdef _WIN32
  184.     OLE_CHAR szOle[MAX_PATH];
  185.     int cbOle = 0L;
  186. #else
  187.     OLE_CHAR *szOle;
  188. #endif
  189.     LARGE_INTEGER liBeg;
  190.     /* initial default receive folder settings */
  191.     ULONG cInitRFNs = 1;        /* number of default nodes */
  192. #pragma pack(1)
  193.     struct RFN
  194.     {
  195.         ULONG cbNode;
  196.         ULONG cbClass;
  197.         TCHAR szClass;
  198.         ULONG cbFolder;
  199.         TCHAR szFolderPath;
  200.     } DefaultNode =
  201.     {
  202.         (2 * sizeof(ULONG)) + (2 * sizeof(TCHAR)),
  203.         sizeof(TCHAR),
  204.         '',
  205.         sizeof(TCHAR),
  206.         ''
  207.     };
  208. #pragma pack()
  209.     LISet32(liBeg, 0);  /* This is an OLE initializer macro */
  210.     AssertSz(szStoreRoot, "Bad szStoreRoot");
  211.     AssertSz(szFile, "Bad szFile");
  212.     AssertSz(pprfs, "Bad pprfs");
  213.     hr = HrAppendPath(szStoreRoot, szFile, &szFullPath);
  214.     if (hr != hrSuccess)
  215.         goto exit;
  216.     sc = ScAllocZ(sizeof(RFS), &prfs);
  217.     if (sc != S_OK)
  218.     {
  219.         hr = ResultFromScode(sc);
  220.         goto exit;
  221.     }
  222.     prfs->szFile = szFullPath;
  223. #ifdef _WIN32
  224.     cbOle = 1 + lstrlen(szFullPath);
  225.     Assert(cbOle < MAX_PATH);
  226.     MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, szFullPath, cbOle, szOle, cbOle);
  227. #else
  228.     szOle = szFullPath;
  229. #endif
  230.     if (ulFlags & RFS_CREATE)
  231.     {
  232.         hrStg = StgCreateDocfile(szOle, grfStorageCreate, 0, &lpstg);
  233.         if (hrStg != hrSuccess)
  234.             goto stg_err;
  235. #ifdef _WIN32
  236.         cbOle = 1 + lstrlen(szRFSStreamName);
  237.         Assert(cbOle < MAX_PATH);
  238.         MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, szRFSStreamName, cbOle,
  239.                 szOle, cbOle);
  240. #else
  241.         szOle = szRFSStreamName;
  242. #endif
  243.         hrStg = lpstg->lpVtbl->CreateStream(lpstg, szOle, grfStreamCreate,
  244.                 0, 0, &lpstream);
  245.         if (hrStg != hrSuccess)
  246.             goto stg_err;
  247.         /* Initialize the newly created stream */
  248.         hrStg = lpstream->lpVtbl->Seek(lpstream, liBeg, STREAM_SEEK_SET, NULL);
  249.         if (hrStg != hrSuccess)
  250.             goto stg_err;
  251.         /* add the default RFS setting of the root (path = '') */
  252.         hrStg = lpstream->lpVtbl->Write(lpstream, (LPVOID) &cInitRFNs,
  253.                 sizeof cInitRFNs, NULL);
  254.         if (hrStg != hrSuccess)
  255.             goto stg_err;
  256.         hrStg = lpstream->lpVtbl->Write(lpstream, (LPVOID) &DefaultNode,
  257.                 DefaultNode.cbNode + sizeof(ULONG), NULL);
  258.         if (hrStg != hrSuccess)
  259.             goto stg_err;
  260.         /* Commit docfile changes.  If we don't do this now, the file on  */
  261.         /* disk will NOT be a docfile (i.e. OLE2 will not recognize it as */
  262.         /* a docfile) if opened again with no other changes made to it.   */
  263.         hrStg = lpstg->lpVtbl->Commit(lpstg, 0);
  264.         if (hrStg != hrSuccess)
  265.             goto stg_err;
  266.     }
  267.     else        /* Open an existing stream */
  268.     {
  269.         hr = OpenRFSStream(prfs, FALSE, &lpstream, &lpstg);
  270.         if (hr != hrSuccess)
  271.             goto exit;
  272.         hrStg = lpstream->lpVtbl->Seek(lpstream, liBeg, STREAM_SEEK_SET, NULL);
  273.         if (hrStg != hrSuccess)
  274.             goto stg_err;
  275.         hrStg = lpstream->lpVtbl->Read(lpstream, (LPVOID) &cRFN,
  276.                 sizeof cRFN, NULL);
  277.         /* fall through to error handler */
  278.     }
  279. stg_err:
  280.     if (hrStg != hrSuccess)
  281.         hr = ResultFromScode(MapStorageSCode(GetScode(hrStg)));
  282. exit:
  283.     if (lpstream)
  284.     {
  285.         CloseRFSStream(lpstream, lpstg);
  286.         lpstg = NULL;
  287.     }
  288.     if (hr != hrSuccess)
  289.     {
  290.         FreeNull(szFullPath);
  291.         FreeNull(prfs);
  292.         UlRelease(lpstg);
  293.     }
  294.     else
  295.         *pprfs = prfs;
  296.     DebugTraceResult(OpenRFS, hr);
  297.     return hr;
  298. }
  299. /*
  300.  *  GetRFN
  301.  *
  302.  *  Purpose:
  303.  *      Returns an RFN containing the receive folder setting
  304.  *      for the message class that is passed in as a parameter.  If
  305.  *      there is not a receive folder setting for this particular
  306.  *      message class, the "best match" is returned, with best
  307.  *      match being defined in GetReceiveFolder (see msgstobj.c).
  308.  *      the way we measure this best match is to have a match index
  309.  *      which is incremented every time a section of the message
  310.  *      class is matched.  These values begin at 2 because 1 is
  311.  *      reserved for the default message class.  For example, the
  312.  *      message class "IPM.Note.Phone" matches against the
  313.  *      following receive folder settings in the following way:
  314.  *
  315.  *          "" (default)        1
  316.  *          "IPM"               2
  317.  *          "IPM.Note"          3
  318.  *          "IPM.Note.Phone"    4
  319.  *          "IPC"               0
  320.  *
  321.  *  Arguments:
  322.  *      prfs            Pointer to the RFS context.
  323.  *      szClassName     Name of the message class for which to
  324.  *                      search for a receive folder setting.
  325.  *      pprfn           Address of location in which to return a
  326.  *                      pointer to an RFN structure containing
  327.  *                      the message class and folder name of the
  328.  *                      "best match" receive folder setting.
  329.  *
  330.  *  Returns:
  331.  *      HRESULT
  332.  *
  333.  *  Side effects:
  334.  *      None.
  335.  *
  336.  *  Errors:
  337.  *      Various.
  338.  *
  339.  *  Notes:
  340.  *      Use FreeRFN() to release the memory of the returned
  341.  *      RFN structure in *pprfn.
  342.  */
  343. HRESULT GetRFN(PRFS prfs, LPTSTR szClassName, PRFN *pprfn)
  344. {
  345.     HRESULT hr = hrSuccess;
  346.     HRESULT hrStg = hrSuccess;
  347.     SCODE sc = S_OK;
  348.     LPSTORAGE lpstg = NULL;
  349.     LPSTREAM lpstream = NULL;
  350.     PRFN prfn = NULL;
  351.     ULONG ibNextNode = 0L;
  352.     ULONG ibMatchNode = 0L;
  353.     ULONG cbNode = 0L;
  354.     ULONG cbClass = 0L;
  355.     ULONG cRFN = 0L;
  356.     UINT uiMatchLvl = 0;
  357.     UINT ui = 0;
  358.     TCHAR rgch[1024];
  359.     LARGE_INTEGER li;
  360.     ULONG cbCls = 0L;
  361.     ULONG cbName = 0L;
  362.     AssertSz(prfs, "Bad prfs");
  363.     AssertSz(szClassName, "Bad szClassName");
  364.     AssertSz(pprfn, "Bad pprfn");
  365.     hr = OpenRFSStream(prfs, FALSE, &lpstream, &lpstg);
  366.     if (hr != hrSuccess)
  367.         goto exit;
  368.     /* Read the count of RFS nodes from the stream. */
  369.     LISet32(li, 0);     /* This is an OLE initializer macro */
  370.     hrStg = lpstream->lpVtbl->Seek(lpstream, li, STREAM_SEEK_SET, NULL);
  371.     if (hrStg != hrSuccess)
  372.         goto stg_err;
  373.     hrStg = lpstream->lpVtbl->Read(lpstream, (LPVOID) &cRFN,
  374.             sizeof cRFN, NULL);
  375.     if (hrStg != hrSuccess)
  376.         goto stg_err;
  377.     /* Loop over nodes, looking for the best message class match */
  378.     for (ui = 0, ibNextNode = sizeof cRFN; ui < cRFN; ui++)
  379.     {
  380.         /* Set seek pointer to beginning of this node */
  381.         LISet32(li, ibNextNode);
  382.         hrStg = lpstream->lpVtbl->Seek(lpstream, li, STREAM_SEEK_SET, NULL);
  383.         if (hrStg != hrSuccess)
  384.             goto stg_err;
  385.         /* Need to have an absolute index to the NEXT node. */
  386.         /* Remember:  cbNode is not self-inclusive, so the  */
  387.         /* next node is (cbNode + sizeof cbNode) from the   */
  388.         /* current node.                                    */
  389.         hrStg = lpstream->lpVtbl->Read(lpstream, (LPVOID) &cbNode,
  390.                 sizeof cbNode, NULL);
  391.         if (hrStg != hrSuccess)
  392.             goto stg_err;
  393.         ibNextNode += cbNode + sizeof cbNode;
  394.         /* Get and compare message class */
  395.         hrStg = lpstream->lpVtbl->Read(lpstream, (LPVOID) &cbClass,
  396.                 sizeof cbClass, NULL);
  397.         if (hrStg != hrSuccess)
  398.             goto stg_err;
  399.         AssertSz(sizeof rgch >= cbClass, "Message class too big!");
  400.         if (cbClass > 0L)       /* If it's not a free node */
  401.         {
  402.             UINT uiMatchCur = 0;
  403.             hrStg = lpstream->lpVtbl->Read(lpstream, (LPVOID) rgch, 
  404.                     cbClass, NULL);
  405.             if (hrStg != hrSuccess)
  406.                 goto stg_err;
  407.             if (rgch[0] == '')
  408.             {
  409.                 uiMatchCur = 1;
  410.             }
  411.             else
  412.                 /* count the matching message class sections */
  413.             {
  414.                 TCHAR *pch1 = rgch;
  415.                 TCHAR *pch1Ahead = NULL;
  416.                 TCHAR *pch2 = szClassName;
  417.                 TCHAR *pch2Ahead = NULL;
  418.                 /* if matching against a class that is less refined than */
  419.                 /* what we are searching for return 0 */
  420.                 if (lstrlen(szClassName) >= lstrlen(rgch))
  421.                 {
  422.                     while (*pch1 && *pch2)
  423.                     {
  424.                         for (pch1Ahead = pch1 + 1; *pch1Ahead &&
  425.                             *pch1Ahead != '.'; pch1Ahead++)
  426.                             ;
  427.                         for (pch2Ahead = pch2 + 1; *pch2Ahead &&
  428.                             *pch2Ahead != '.'; pch2Ahead++)
  429.                             ;
  430.                         if (pch1Ahead - pch1 == pch2Ahead - pch2 &&
  431.                             !memcmp(pch1, pch2, pch1Ahead - pch1))
  432.                         {
  433.                             uiMatchCur++;
  434.                             pch1 = pch1Ahead;
  435.                             pch2 = pch2Ahead;
  436.                         }
  437.                         else
  438.                             break;
  439.                     }
  440.                 }
  441.                 /* We want to match a "real" setting higher than the */
  442.                 /* default, so we increment a real match to be > 1.  */
  443.                 if (uiMatchCur > 0)
  444.                 {
  445.                     uiMatchCur++;
  446.                 }
  447.             }
  448.             if (uiMatchCur > uiMatchLvl)
  449.             {
  450.                 /* Here we set ibMatchNode to be the absolute index of */
  451.                 /* the cbClass member of the node (NOT the cbNode      */
  452.                 /* member.  When we seek back to this position, we can */
  453.                 /* begin reading the cbClass immediately (see below).  */
  454.                 ibMatchNode = ibNextNode - cbNode;
  455.                 uiMatchLvl = uiMatchCur;
  456.             }
  457.         }
  458.     }
  459.     if (uiMatchLvl == 0)
  460.     {
  461.         hr = ResultFromScode(MAPI_E_NOT_FOUND);
  462.         goto exit;
  463.     }
  464.     /* Set the return variable w/best match */
  465.     sc = ScAllocZ(sizeof(RFN), (PPV) &prfn);
  466.     if (sc != S_OK)
  467.         goto sc_err;
  468.     /* Goto best match node, but seek pointer will be past cbNode */
  469.     LISet32(li, ibMatchNode);
  470.     hrStg = lpstream->lpVtbl->Seek(lpstream, li, STREAM_SEEK_SET, NULL);
  471.     if (hrStg != hrSuccess)
  472.         goto stg_err;
  473.     /* Read in class name */
  474.     hrStg = lpstream->lpVtbl->Read(lpstream, (LPVOID) &cbCls,
  475.             sizeof cbCls, NULL);
  476.     if (hrStg != hrSuccess)
  477.         goto stg_err;
  478.     sc = ScAlloc(cbCls, (PPV) &prfn->szClass);
  479.     if (sc != S_OK)
  480.         goto sc_err;
  481.     hrStg = lpstream->lpVtbl->Read(lpstream,
  482.             (LPVOID) prfn->szClass, cbCls, NULL);
  483.     if (hrStg != hrSuccess)
  484.         goto stg_err;
  485.     /* Read in folder name */
  486.     hrStg = lpstream->lpVtbl->Read(lpstream, (LPVOID) &cbName,
  487.             sizeof cbName, NULL);
  488.     if (hrStg != hrSuccess)
  489.         goto stg_err;
  490.     sc = ScAlloc(cbName, (PPV) &prfn->szName);
  491.     if (sc != S_OK)
  492.         goto sc_err;
  493.     hrStg = lpstream->lpVtbl->Read(lpstream,
  494.             (LPVOID) prfn->szName, cbName, NULL);
  495.     if (hrStg != hrSuccess)
  496.         goto stg_err;
  497. sc_err:
  498.     if (sc != S_OK)
  499.     {
  500.         Assert(hr == hrSuccess);
  501.         Assert(hrStg == hrSuccess);
  502.         hr = ResultFromScode(sc);
  503.     }
  504. stg_err:
  505.     if (hrStg != hrSuccess)
  506.     {
  507.         Assert(sc == S_OK);
  508.         Assert(hr == hrSuccess);
  509.         hr = ResultFromScode(MapStorageSCode(GetScode(hrStg)));
  510.     }
  511. exit:
  512.     if (lpstream)
  513.         CloseRFSStream(lpstream, lpstg);
  514.     if (hr != hrSuccess)
  515.         FreeRFN(prfn);
  516.     else
  517.         *pprfn = prfn;
  518.     DebugTraceResult(GetRFN, hr);
  519.     return hr;
  520. }
  521. /*
  522.  -  FreeRFN
  523.  -
  524.  *  Release the memory of an RFN allocated and returned
  525.  *  by the GetRFN() procedure.
  526.  */
  527. void FreeRFN(PRFN prfn)
  528. {
  529.     if (prfn)
  530.     {
  531.         (void)FreeNull((LPVOID) prfn->szClass);
  532.         (void)FreeNull((LPVOID) prfn->szName);
  533.         (void)FreeNull((LPVOID) prfn);
  534.     }
  535. }
  536. /*
  537.  *  DeleteRFN
  538.  *
  539.  *  Purpose:
  540.  *      Delete the receive folder setting associated with a
  541.  *      particular message class.  We do this by "zeroing out" the
  542.  *      node on disk, rather than actually removing it and
  543.  *      compacting the stream.  We can easily zero out the node
  544.  *      once we've found the right one by setting the length of the
  545.  *      message class string contained in it to be zero (an invalid
  546.  *      value).
  547.  *
  548.  *  Arguments:
  549.  *      prfs            Pointer to the RFS context to use.
  550.  *      szClassName     Buffer containing the name of the message
  551.  *                      class for which to remove the receive
  552.  *                      folder setting.  We do a linear search
  553.  *                      through the stream to find the node on disk
  554.  *                      with a matching message class.
  555.  *
  556.  *  Returns:
  557.  *      HRESULT
  558.  *
  559.  *  Side effects:
  560.  *      None.
  561.  *
  562.  *  Errors:
  563.  *      Various.
  564.  */
  565. HRESULT DeleteRFN(PRFS prfs, LPTSTR szClassName)
  566. {
  567.     HRESULT hr = hrSuccess;
  568.     HRESULT hrStg = hrSuccess;
  569.     LPSTORAGE lpstg = NULL;
  570.     IStream *lpstream = NULL;
  571.     ULONG ibNextNode = 0L;
  572.     ULONG cbNode = 0L;
  573.     ULONG cbClass = 0L;
  574.     ULONG cRFN = 0L;
  575.     UINT ui = 0;
  576.     TCHAR rgch[1024];
  577.     LARGE_INTEGER li;
  578.     AssertSz(prfs, "Bad prfs");
  579.     AssertSz(szClassName, "Bad szClassName");
  580.     hr = OpenRFSStream(prfs, TRUE, &lpstream, &lpstg);
  581.     if (hr != hrSuccess)
  582.         goto exit;
  583.     /* Read the count of RFS nodes from the stream. */
  584.     LISet32(li, 0);     /* This is an OLE initializer macro */
  585.     hrStg = lpstream->lpVtbl->Seek(lpstream, li, STREAM_SEEK_SET, NULL);
  586.     if (hrStg != hrSuccess)
  587.         goto stg_err;
  588.     hrStg = lpstream->lpVtbl->Read(lpstream, (LPVOID) &cRFN,
  589.             sizeof cRFN, NULL);
  590.     if (hrStg != hrSuccess)
  591.         goto stg_err;
  592.     /* Loop over nodes, looking for a message class match */
  593.     for (ui = 0, ibNextNode = sizeof cRFN; ui < cRFN; ui++)
  594.     {
  595.         /* Set seek pointer to beginning of first node */
  596.         LISet32(li, ibNextNode);
  597.         hrStg = lpstream->lpVtbl->Seek(lpstream, li, STREAM_SEEK_SET, NULL);
  598.         if (hrStg != hrSuccess)
  599.             goto stg_err;
  600.         /* Need to have an absolute index to the NEXT node. */
  601.         /* Remember:  cbNode is not self-inclusive, so the  */
  602.         /* next node is (cbNode + sizeof cbNode) from the   */
  603.         /* current node.                                    */
  604.         hrStg = lpstream->lpVtbl->Read(lpstream, (LPVOID) &cbNode,
  605.                 sizeof cbNode, NULL);
  606.         if (hrStg != hrSuccess)
  607.             goto stg_err;
  608.         ibNextNode += cbNode + sizeof cbNode;
  609.         /* Get and compare message class */
  610.         hrStg = lpstream->lpVtbl->Read(lpstream, (LPVOID) &cbClass,
  611.                 sizeof cbClass, NULL);
  612.         if (hrStg != hrSuccess)
  613.             goto stg_err;
  614.         AssertSz(sizeof rgch >= cbClass * sizeof(TCHAR),
  615.             "Message class too big!");
  616.         if (cbClass > 0L)       /* If it's not a free node */
  617.         {
  618.             hrStg = lpstream->lpVtbl->Read(lpstream, (LPVOID) rgch,
  619.                     cbClass, NULL);
  620.             if (hrStg != hrSuccess)
  621.                 goto stg_err;
  622.             if (cbClass == Cbtszsize(szClassName)
  623.                 && !memcmp(szClassName, rgch, (UINT) cbClass))
  624.             {
  625.                 LONG ibClass = 0L;
  626.                 /* Seek back to cbClass */
  627.                 ibClass -= (LONG) (cbClass + sizeof cbClass);
  628.                 LISet32(li, ibClass);
  629.                 hrStg = lpstream->lpVtbl->Seek(lpstream, li,
  630.                         STREAM_SEEK_CUR, NULL);
  631.                 if (hrStg != hrSuccess)
  632.                     goto stg_err;
  633.                 /* Zero out the node */
  634.                 cbClass = 0L;
  635.                 hrStg = lpstream->lpVtbl->Write(lpstream,
  636.                         (LPVOID) &cbClass, sizeof cbClass, NULL);
  637.                 if (hrStg != hrSuccess)
  638.                     goto stg_err;
  639.                 /* Commit the change */
  640.                 hrStg = lpstg->lpVtbl->Commit(lpstg, 0);
  641.                 if (hrStg != hrSuccess)
  642.                     goto stg_err;
  643.                 break;
  644.             }
  645.         }
  646.     }
  647. stg_err:
  648.     if (hrStg)
  649.         hr = ResultFromScode(MapStorageSCode(GetScode(hrStg)));
  650. exit:
  651.     if (lpstream)
  652.         CloseRFSStream(lpstream, lpstg);
  653.     DebugTraceResult(DeleteRFN, hr);
  654.     return hr;
  655. }
  656. /*
  657.  *  AddRFN
  658.  *
  659.  *  Purpose:
  660.  *      Adds a node (on disk) to the stream that holds receive
  661.  *      folder settings for a message store.  Does this by creating
  662.  *      a new node at the current End-Of-Stream (at the end of all
  663.  *      other nodes).
  664.  *
  665.  *  Arguments:
  666.  *      prfs        Pointer to the receive folder storage context.
  667.  *      prfn    Pointer to the new node to add.
  668.  *
  669.  *  Returns:
  670.  *      HRESULT
  671.  *
  672.  *  Side effects:
  673.  *      None.
  674.  *
  675.  *  Errors:
  676.  *      Various.
  677.  */
  678. HRESULT AddRFN(PRFS prfs, PRFN prfn)
  679. {
  680.     HRESULT hr = hrSuccess;
  681.     HRESULT hrStg = hrSuccess;
  682.     LPSTORAGE lpstg = NULL;
  683.     IStream *lpstream = NULL;
  684.     UINT ui = 0;
  685.     ULONG cb = 0L;
  686.     ULONG cbNode = 0L;
  687.     ULONG cbClass = 0L;
  688.     ULONG cbName = 0L;
  689.     ULONG cRFN = 0L;
  690.     LARGE_INTEGER liEOS;
  691.     AssertSz(prfs, "Bad prfs");
  692.     AssertSz(prfn, "Bad prfn");
  693.     AssertSz(prfn->szClass, "Bad prfn->szClass");
  694.     AssertSz(prfn->szName, "Bad prfn->szName");
  695.     hr = OpenRFSStream(prfs, TRUE, &lpstream, &lpstg);
  696.     if (hr != hrSuccess)
  697.         goto exit;
  698.     /* Find the end of the stream.  Strictly speaking, we can't just seek */
  699.     /* the current End-Of-Stream (what the IStream thinks is it's current */
  700.     /* EOS), because we really want to be at the end of the last node,    */
  701.     /* and there may have been stuff written after (from a failed write). */
  702.     /* First, read the count of RFS nodes from the stream. */
  703.     LISet32(liEOS, 0);      /* This is an OLE initializer macro */
  704.     hrStg = lpstream->lpVtbl->Seek(lpstream, liEOS, STREAM_SEEK_SET, NULL);
  705.     if (hrStg != hrSuccess)
  706.         goto stg_err;
  707.     hrStg = lpstream->lpVtbl->Read(lpstream, (LPVOID) &cRFN,
  708.             sizeof cRFN, NULL);
  709.     if (hrStg != hrSuccess)
  710.         goto stg_err;
  711.     for (ui = 0; ui < cRFN; ui++)
  712.     {
  713.         hrStg = lpstream->lpVtbl->Read(lpstream, (LPVOID) &cb,
  714.                 sizeof cb, NULL);
  715.         if (hrStg != hrSuccess)
  716.             goto stg_err;
  717.         LISet32(liEOS, (LONG) cb);
  718.         hrStg = lpstream->lpVtbl->Seek(lpstream, liEOS, STREAM_SEEK_CUR, NULL);
  719.         if (hrStg != hrSuccess)
  720.             goto stg_err;
  721.     }
  722.     /* Write out the node */
  723.     /* Size of node: length of 2 strings + 2 NULL characters + 2 times */
  724.     /* the size of the space needed to hold the string lengths.        */
  725.     cbClass = Cbtszsize(prfn->szClass);
  726.     cbName = Cbtszsize(prfn->szName);
  727.     cbNode = 2 * sizeof(ULONG) + cbClass + cbName;
  728.     hrStg = lpstream->lpVtbl->Write(lpstream, (LPVOID) &cbNode,
  729.             sizeof cbNode, NULL);
  730.     if (hrStg != hrSuccess)
  731.         goto stg_err;
  732.     hrStg = lpstream->lpVtbl->Write(lpstream, (LPVOID) &cbClass,
  733.             sizeof cbClass, NULL);
  734.     if (hrStg != hrSuccess)
  735.         goto stg_err;
  736.     hrStg = lpstream->lpVtbl->Write(lpstream, (LPVOID) prfn->szClass,
  737.             cbClass, NULL);
  738.     if (hrStg != hrSuccess)
  739.         goto stg_err;
  740.     hrStg = lpstream->lpVtbl->Write(lpstream, (LPVOID) &cbName,
  741.             sizeof cbName, NULL);
  742.     if (hrStg != hrSuccess)
  743.         goto stg_err;
  744.     hrStg = lpstream->lpVtbl->Write(lpstream, (LPVOID) prfn->szName,
  745.             cbName, NULL);
  746.     if (hrStg != hrSuccess)
  747.         goto stg_err;
  748.     /* Keep cRFN, the in-memory and on-disk */
  749.     /* copies, in sync with each other.     */
  750.     LISet32(liEOS, 0L);
  751.     hrStg = lpstream->lpVtbl->Seek(lpstream, liEOS, STREAM_SEEK_SET, NULL);
  752.     if (hrStg != hrSuccess)
  753.         goto stg_err;
  754.     cRFN++;
  755.     hrStg = lpstream->lpVtbl->Write(lpstream, (LPVOID) &cRFN,
  756.             sizeof cRFN, NULL);
  757.     if (hrStg != hrSuccess)
  758.     {
  759.         cRFN--;
  760.         goto stg_err;
  761.     }
  762.     /* Commit the change */
  763.     hrStg = lpstg->lpVtbl->Commit(lpstg, 0);
  764.     /* if ( hrStg ), fall through to stg_err */
  765. stg_err:
  766.     if (hrStg)
  767.         hr = ResultFromScode(MapStorageSCode(GetScode(hrStg)));
  768. exit:
  769.     if (lpstream)
  770.         CloseRFSStream(lpstream, lpstg);
  771.     DebugTraceResult(AddRFN, hr);
  772.     return hr;
  773. }
  774. /*
  775.  *  CloseRFS
  776.  *
  777.  *  Purpose:
  778.  *      Frees and invalidates an open context for accessing receive
  779.  *      folder settings.
  780.  *
  781.  *  Arguments:
  782.  *      prfs        Pointer to the object to close.
  783.  *
  784.  *  Returns:
  785.  *      HRESULT
  786.  *
  787.  *  Side effects:
  788.  *      None.
  789.  *
  790.  *  Errors:
  791.  *      Various.
  792.  */
  793. HRESULT CloseRFS(PRFS prfs)
  794. {
  795.     HRESULT hr = hrSuccess;
  796.     AssertSz(prfs, "Bad prfs");
  797.     FreeNull(prfs->szFile);
  798.     FreeNull(prfs);
  799.     DebugTraceResult(CloseRFS, hr);
  800.     return hr;
  801. }
  802. /*
  803.  *  Internal functions
  804.  */
  805. /*
  806.  *  OpenRFSStream
  807.  *
  808.  *  Purpose:
  809.  *      Open the stream within a docfile that contains receive
  810.  *      folder settings.
  811.  *
  812.  *  Arguments:
  813.  *      prfs        Receive folder settings context.
  814.  *      fModify     TRUE indicates the caller wants write access.
  815.  *      lppstream   Address in which to return a pointer to the
  816.  *                  newly opened stream.
  817.  *
  818.  *  Returns:
  819.  *      HRESULT
  820.  *
  821.  *  Side effects:
  822.  *      None.
  823.  *
  824.  *  Errors:
  825.  *      Various storage errors.
  826.  */
  827. static HRESULT OpenRFSStream(PRFS prfs, BOOL fModify, IStream **lppstream,
  828.     LPSTORAGE *lppstg)
  829. {
  830.     HRESULT hr = hrSuccess;
  831.     HRESULT hrStg = hrSuccess;
  832.     DWORD grfMode;
  833. #ifdef _WIN32
  834.     OLE_CHAR szOle[MAX_PATH];
  835.     int cbOle = 0L;
  836. #else
  837.     OLE_CHAR *szOle;
  838. #endif
  839.     LPSTORAGE lpstg = NULL;
  840.     IStream *lpstream = NULL;
  841.     AssertSz(prfs, "Bad prfs");
  842.     AssertSz(lppstream, "Bad lppstream");
  843. #ifdef _WIN32
  844.     cbOle = 1 + lstrlen(prfs->szFile);
  845.     Assert(cbOle < MAX_PATH);
  846.     MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, prfs->szFile, cbOle, szOle, cbOle);
  847. #else
  848.     szOle = prfs->szFile;
  849. #endif
  850.     if (fModify)
  851.         grfMode = STGM_SHARE_EXCLUSIVE | STGM_READWRITE;
  852.     else
  853.         grfMode = STGM_SHARE_EXCLUSIVE | STGM_READ;
  854.     hrStg = StgOpenStorage(szOle, NULL, grfMode | STGM_TRANSACTED, NULL,
  855.             0, &lpstg);
  856.     if (hrStg != hrSuccess)
  857.         goto stg_err;
  858. #ifdef _WIN32
  859.     cbOle = 1 + lstrlen(szRFSStreamName);
  860.     Assert(cbOle < MAX_PATH);
  861.     MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, szRFSStreamName, cbOle, szOle, cbOle);
  862. #else
  863.     szOle = szRFSStreamName;
  864. #endif
  865.     hrStg = lpstg->lpVtbl->OpenStream(lpstg, szOle, NULL, grfMode, 0, &lpstream);
  866.     if (hrStg != hrSuccess)
  867.         goto stg_err;
  868.     /* WARNING:  If any code is added between here and the error handler */
  869.     /* that can fail, a check in the error handler must be added to free */
  870.     /* the open stream in the event of an error.                         */
  871.     *lppstream = lpstream;
  872.     *lppstg = lpstg;
  873. stg_err:
  874.     if (hrStg != hrSuccess)
  875.         hr = ResultFromScode(MapStorageSCode(GetScode(hrStg)));
  876.     if (hr != hrSuccess)
  877.         UlRelease(lpstg);
  878.     DebugTraceResult(OpenRFSStream, hr);
  879.     return hr;
  880. }
  881. /*
  882.  *  CloseRFSStream
  883.  *
  884.  *  Purpose:
  885.  *      Close the stream within a docfile that holds receive folder
  886.  *      settings.
  887.  *
  888.  *  Arguments:
  889.  *      lpstream    Pointer to the stream.
  890.  *      lpstg       Pointer to the storage instance in which this
  891.  *                  stream resides.
  892.  *
  893.  *  Returns:
  894.  *      void
  895.  *
  896.  *  Side effects:
  897.  *      None.
  898.  *
  899.  *  Errors:
  900.  *      None.
  901.  */
  902. static void CloseRFSStream(IStream *lpstream, LPSTORAGE lpstg)
  903. {
  904.     AssertSz(lpstream, "Bad lpstream");
  905.     AssertSz(lpstg, "Bad lpstg");
  906.     NFSideAssertSz(UlRelease(lpstream) == 0L, "lpstream not released");
  907.     NFSideAssertSz(UlRelease(lpstg) == 0L, "lpstg not released");
  908.     return;
  909. }