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

Windows编程

开发平台:

Visual C++

  1. /*
  2.  *  S M H . C
  3.  *  
  4.  *  Sample mail handling hook
  5.  *  
  6.  *  Purpose:
  7.  *  
  8.  *      The sample mail handling (SMH) hook illustrates the use of the
  9.  *      MAPI Spooler Hook Provider Interface (ISpoolerHook) and those
  10.  *      parts of the general MAPI API that are available to a spooler
  11.  *      hook implementation.
  12.  *  
  13.  *      Specifically, SMH illusttrates the operation of both an inbound
  14.  *      message hook as well as outbound.  SMH also has examples of the
  15.  *      configuration of a spooler hook provider via calls to SMH's
  16.  *      ServiceEntry() and/or through calls from the Profile Wizard.
  17.  *  
  18.  *  Features:
  19.  *  
  20.  *    Sent Mail:
  21.  *  
  22.  *      SMH allows the archiving of outbound messages (sent mail), into a
  23.  *      well defined set of subfolders in the default stores sent mail
  24.  *      folder.  The archive folders are comprised of monthly archive
  25.  *      folders.  The monthly folders can be, optionally, created under a
  26.  *      year based folder in the sent mail folder.  Thus in a typical
  27.  *      message store, a fully archived sent mail folder might have a
  28.  *      hierarchy that looks similar to the following:
  29.  *  
  30.  *          Sent Mail
  31.  *              |
  32.  *              |-- 1994
  33.  *              |    |
  34.  *              |    |-- 10 October
  35.  *              |    |-- 11 November
  36.  *              |    |-- 12 December
  37.  *              |
  38.  *              |-- 1995
  39.  *                   |
  40.  *                   |-- 01 January
  41.  *  
  42.  *      This allows for a mail user to organize their outgoing mail in
  43.  *      a managible fashion.
  44.  *  
  45.  *    Deleted Mail:
  46.  *  
  47.  *      SMH allows the archiving of deleted mail in the same fashion as
  48.  *      sent mail can be archived.  This feature helps people who choose
  49.  *      keep their 'deleted' mail accessible.  It should be noted here
  50.  *      that this feature does not make use of the ISpoolerHook
  51.  *      interface, but is an example of what all can be done with spooler
  52.  *      hook providers.
  53.  *  
  54.  *    Incoming Mail:
  55.  *  
  56.  *      SMH can also 'filter' incoming messages and route the message
  57.  *      directly to folders, other than the default stores inbox, based
  58.  *      on message content.  The user can define any number of filters
  59.  *      that can help organize and manage the email.  Additionally, the
  60.  *      user can specify a sound scheme to be used on message delivery.
  61.  *      This allows the user to specify specific sounds based on message
  62.  *      content and priority.
  63.  *  
  64.  *    Unread Search Folders:
  65.  *  
  66.  *      Because SMH can filter unread messages deep into a message store
  67.  *      folder hierarchy, SMH can also create a search folder in the root
  68.  *      of the IPM_SUBTREE that searches the entire subtree for unread
  69.  *      messages.
  70.  *  
  71.  *    Out-of-office Processing:
  72.  *  
  73.  *      SMH can generate OOF notifications for incomming mail.  It will
  74.  *      do it's best to not send multiple OOF's to any single recipient
  75.  *      over the period in which the OOF processing is enabled.  The OOF
  76.  *      engine supports full rich-text.
  77.  *  
  78.  *  Copyright 1992-95 Microsoft Corporation.  All Rights Reserved.
  79.  */
  80. #include "_pch.h"
  81. extern SPropTagArray sptRule;
  82. extern SPropTagArray sptConfigProps;
  83. /*
  84.  *  sptMessageProps
  85.  *
  86.  *  These are the properties that are required to check filters against
  87.  *  messages.
  88.  */
  89. const static SizedSPropTagArray (cpMsgPrps, sptMsgPrps) =
  90. {
  91.     cpMsgPrps,
  92.     {
  93.         PR_MESSAGE_FLAGS,
  94.         PR_SUBJECT,
  95.         PR_SENT_REPRESENTING_NAME,
  96.         PR_SENT_REPRESENTING_EMAIL_ADDRESS,
  97.         PR_IMPORTANCE
  98.     }
  99. };
  100. /*
  101.  *  vtblSMH
  102.  *
  103.  *  This is the SMH object's vtable.  The table and its functions are
  104.  *  defined by MAPI's ISpoolerHook interface.
  105.  */
  106. static const SMH_Vtbl vtblSMH =
  107. {
  108.     SMH_QueryInterface,
  109.     SMH_AddRef,
  110.     SMH_Release,
  111.     SMH_InboundMsgHook,
  112.     SMH_OutboundMsgHook
  113. };
  114. /*
  115.  *  lpCtl3D
  116.  *  
  117.  *  Holds context for the 3D control DLL.
  118.  */
  119. LPVOID lpCtl3D = NULL;
  120. /*
  121.  *  HrInitUnreadSearch()
  122.  *
  123.  *  Purpose:
  124.  *
  125.  *      Inits/creates an 'Unread Messages' search folder in the root of
  126.  *      the given store's IPM_SUBTREE hierarchy.
  127.  *
  128.  *  Arguments:
  129.  *
  130.  *      lpsmh           the sample mail handler object
  131.  *      lpmdb           the store getting the search folder
  132.  *
  133.  *  Returns:
  134.  *
  135.  *      (HRESULT)
  136.  */
  137. HRESULT
  138. HrInitUnreadSearch (LPSMH lpsmh)
  139. {
  140.     HRESULT hr;
  141.     ENTRYLIST el = {0};
  142.     LPMAPIFOLDER lpfldr = NULL;
  143.     LPMAPIFOLDER lpfldrUM = NULL;
  144.     LPMDB lpmdb = NULL;
  145.     LPSPropValue lpval = NULL;
  146.     SRestriction res = {0};
  147.     ULONG ulType = 0;
  148.     UINT cerr = 0;
  149.     UINT i;
  150.     for (i = 0; i < lpsmh->lpstotbl->cSto; i++)
  151.     {
  152.         hr = HrOpenStoEntry (lpsmh->lpsess, &lpsmh->lpstotbl->aSto[i], &lpmdb);
  153.         if (!HR_FAILED (hr))
  154.         {
  155.             hr = HrGetOneProp ((LPMAPIPROP)lpmdb, PR_IPM_SUBTREE_ENTRYID, &lpval);
  156.             if (!HR_FAILED (hr))
  157.             {
  158.                 hr = lpmdb->lpVtbl->OpenEntry (lpmdb,
  159.                                         lpval->Value.bin.cb,
  160.                                         (LPENTRYID)lpval->Value.bin.lpb,
  161.                                         NULL,
  162.                                         MAPI_MODIFY,
  163.                                         &ulType,
  164.                                         (LPUNKNOWN FAR *)&lpfldr);
  165.                 if (!HR_FAILED (hr))
  166.                 {
  167.                     hr = lpfldr->lpVtbl->CreateFolder (lpfldr,
  168.                                         FOLDER_SEARCH,
  169.                                         "Unread Messages",
  170.                                         "Simple Mail Handler: unread message search",
  171.                                         NULL,
  172.                                         MAPI_MODIFY | OPEN_IF_EXISTS,
  173.                                         &lpfldrUM);
  174.                     if (!HR_FAILED (hr))
  175.                     {
  176.                         el.cValues = 1;
  177.                         el.lpbin = &lpval->Value.bin;
  178.                         res.rt = RES_BITMASK;
  179.                         res.res.resBitMask.relBMR = BMR_EQZ;
  180.                         res.res.resBitMask.ulPropTag = PR_MESSAGE_FLAGS;
  181.                         res.res.resBitMask.ulMask = MSGFLAG_READ;
  182.                         hr = lpfldrUM->lpVtbl->SetSearchCriteria (lpfldrUM,
  183.                                         &res,
  184.                                         &el,
  185.                                         RECURSIVE_SEARCH | BACKGROUND_SEARCH | RESTART_SEARCH);
  186.                         UlRelease (lpfldrUM);
  187.                         lpfldrUM = NULL;
  188.                     }
  189.                     UlRelease (lpfldr);
  190.                     lpfldr = NULL;
  191.                 }
  192.                 (*lpsmh->lpfnFree) (lpval);
  193.                 lpval = NULL;
  194.             }
  195.         }
  196.         if (HR_FAILED (hr))
  197.         {
  198.             DebugTrace ("SMH: WARNING: failed to init unread search (store:%d)n", i);
  199.             cerr++;
  200.         }
  201.     }
  202.     hr = ResultFromScode (cerr ? MAPI_W_ERRORS_RETURNED : S_OK);
  203.     DebugTraceResult (HrInitUnreadSearch(), hr);
  204.     return hr;
  205. }
  206. /*
  207.  *  LpszFindChar()
  208.  *
  209.  *  Purpose:
  210.  *
  211.  *      Finds the given character in the passed in string.  This is an
  212.  *      exact matching model so strings should be normalized to either
  213.  *      upper or lower case if case insensitvity is required.
  214.  *
  215.  *  Arguments:
  216.  *
  217.  *      lpszSrc         source string
  218.  *      ch              character to find
  219.  *
  220.  *  Returns:
  221.  *
  222.  *      NULL iff the char was not found, otherwise, the return is a
  223.  *      pointer to the character in the source string.
  224.  */
  225. LPTSTR
  226. LpszFindChar (LPTSTR lpszSrc, TCHAR ch)
  227. {
  228.     LPTSTR lpsz = lpszSrc;
  229.     if (lpszSrc)
  230.         while (*lpsz && (*lpsz != ch))
  231.             lpsz++;
  232.     return ((lpsz && *lpsz) ? lpsz : NULL);
  233. }
  234. /*
  235.  *  HrCheckExclusions()
  236.  *
  237.  *  Purpose:
  238.  *
  239.  *      Checks the message class against the list of message classes
  240.  *      excluded from filtering.
  241.  *
  242.  *  Arguments:
  243.  *
  244.  *      lpsmh           the smh parent object
  245.  *      lpmsg           the message to check for exclusion
  246.  *
  247.  *  Returns:
  248.  *
  249.  *      (HRESULT)       If the message is to be excluded, then hrSuccess
  250.  *                      is returned, otherwize MAPI_E_NOT_ME indicates it
  251.  *                      is OK to filter the message
  252.  */
  253. HRESULT
  254. HrCheckExclusions (LPSMH lpsmh, LPMESSAGE lpmsg)
  255. {
  256.     SCODE sc = S_OK;
  257.     UINT isz = 0;
  258.     LPSPropValue lpval = NULL;
  259.     if (lpsmh->valEx.ulPropTag == PR_SMH_EXCLUSIONS)
  260.     {
  261.         if (!HR_FAILED (HrGetOneProp ((LPMAPIPROP)lpmsg, PR_MESSAGE_CLASS, &lpval)))
  262.         {
  263.             /*  See if this is in the list of exclusions */
  264.             for (isz = 0; isz < lpsmh->valEx.Value.MVSZ.cValues; isz++)
  265.                 if (FLpszContainsLpsz (lpval->Value.LPSZ, lpsmh->valEx.Value.MVSZ.LPPSZ[isz]))
  266.                     break;
  267.             (*lpsmh->lpfnFree) (lpval);
  268.         }
  269.         sc = ((isz == lpsmh->valEx.Value.MVSZ.cValues) ? S_OK : MAPI_E_NOT_ME);
  270.     }
  271.     DebugTraceSc (HrCheckExclusions(), sc);
  272.     return ResultFromScode (sc);
  273. }
  274. /*
  275.  *  HrCheckRule()
  276.  *  
  277.  *  Purpose:
  278.  *  
  279.  *      Examines a message to see if the current rule applies to the
  280.  *      message. 
  281.  *  
  282.  *      IMPORTANT: If a rule is of type RL_SUBJECT, RL_FROM, or
  283.  *      RL_ATTACH, then the set of properties required to check for
  284.  *      matches with the message are retained and passed back to the
  285.  *      caller such that subsequent calls to HrCheckRule() will not have
  286.  *      to get those props a second time.  THEREFORE the caller is
  287.  *      responsible for cleaning up any returned property values.
  288.  *  
  289.  *  Arguments:
  290.  *  
  291.  *      lprl            pointer to the rule
  292.  *      lpmsg           pointer to the message to examine
  293.  *      lppval  [OUT]   buffer containing the target entryid value struct
  294.  *  
  295.  *  Returns:
  296.  *  
  297.  *      (HRESULT)       If the rule does apply, hrSuccess is returned and
  298.  *                      the lppval parameter will point to a lpval struct
  299.  *                      containing the entryid of the target folder.
  300.  *  
  301.  *                      If the rule does not apply, the return value is
  302.  *                      an HRESULT with MAPI_E_NOT_ME as the SCODE.
  303.  *  
  304.  *                      Otherwise normal error codes apply.
  305.  */
  306. HRESULT
  307. HrCheckRule (LPSMH lpsmh, LPRULE lprl, LPMESSAGE lpmsg, LPSPropValue FAR * lppval)
  308. {
  309.     HRESULT hr;
  310.     LPMAPITABLE lptbl = NULL;
  311.     LPSPropValue lpval = *lppval;
  312.     LPSPropValue lpvalT = NULL;
  313.     ULONG cval;
  314.     if (!lpval)
  315.     {
  316.         hr = lpmsg->lpVtbl->GetProps (lpmsg,
  317.                                 (LPSPropTagArray)&sptMsgPrps,
  318.                                 0,
  319.                                 &cval,
  320.                                 &lpval);
  321.         if (HR_FAILED (hr))
  322.             goto ret;
  323.     }
  324.     /*  Init for failure */
  325.     hr = ResultFromScode (MAPI_E_NOT_ME);
  326.     if ((lprl->rlTyp == RL_TO_RECIP) ||
  327.         (lprl->rlTyp == RL_CC_RECIP) ||
  328.         (lprl->rlTyp == RL_BCC_RECIP) ||
  329.         (lprl->rlTyp == RL_ANY_RECIP))
  330.     {
  331.         hr = lpmsg->lpVtbl->GetRecipientTable (lpmsg, 0, &lptbl);
  332.         if (HR_FAILED (hr))
  333.             goto ret;
  334.         hr = lptbl->lpVtbl->FindRow (lptbl, lprl->lpres, BOOKMARK_BEGINNING, 0);
  335.         UlRelease (lptbl);
  336.         if (HR_FAILED (hr) && (GetScode (hr) == MAPI_E_NOT_FOUND))
  337.             hr = ResultFromScode (MAPI_E_NOT_ME);
  338.     }
  339.     else if (lprl->rlTyp == RL_SUBJECT)
  340.     {
  341.         if (lpval[ipMsgSubj].ulPropTag == PR_SUBJECT)
  342.             if (FLpszContainsLpsz (lpval[ipMsgSubj].Value.LPSZ, lprl->lpszData))
  343.                 hr = hrSuccess;
  344.     }
  345.     else if (lprl->rlTyp == RL_SENDER)
  346.     {
  347.         if (lpval[ipMsgSentRep].ulPropTag == PR_SENT_REPRESENTING_NAME)
  348.             if (FLpszContainsLpsz (lpval[ipMsgSentRep].Value.LPSZ, lprl->lpszData))
  349.                 hr = hrSuccess;
  350.         if (HR_FAILED (hr))
  351.             if (lpval[ipMsgSentRepEA].ulPropTag == PR_SENT_REPRESENTING_EMAIL_ADDRESS)
  352.                 if (FLpszContainsLpsz (lpval[ipMsgSentRepEA].Value.LPSZ, lprl->lpszData))
  353.                     hr = hrSuccess;
  354.     }
  355.     else if (lprl->rlTyp == RL_HAS_ATTACH)
  356.     {
  357.         if (lpval[ipMsgFlgs].ulPropTag == PR_MESSAGE_FLAGS)
  358.             if (lpval[ipMsgFlgs].Value.l & MSGFLAG_HASATTACH)
  359.                 hr = hrSuccess;
  360.     }
  361.     else if (lprl->rlTyp == RL_BODY)
  362.     {
  363.         if (!HR_FAILED (HrGetOneProp ((LPMAPIPROP)lpmsg, PR_BODY, &lpvalT)))
  364.         {
  365.             if (FLpszContainsLpsz (lpvalT->Value.LPSZ, lprl->lpszData))
  366.                 hr = hrSuccess;
  367.             (*lpsmh->lpfnFree) (lpvalT);
  368.         }
  369.     }
  370.     else if (lprl->rlTyp == RL_MSG_CLASS)
  371.     {
  372.         if (!HR_FAILED (HrGetOneProp ((LPMAPIPROP)lpmsg, PR_MESSAGE_CLASS, &lpvalT)))
  373.         {
  374.             if (FLpszContainsLpsz (lpvalT->Value.LPSZ, lprl->lpszData))
  375.                 hr = hrSuccess;
  376.             (*lpsmh->lpfnFree) (lpvalT);
  377.         }
  378.     }
  379.     if (lprl->ulFlags & RULE_NOT)
  380.     {
  381.         if (GetScode (hr) == MAPI_E_NOT_ME)
  382.             hr = hrSuccess;
  383.         else if (hr == hrSuccess)
  384.             hr = ResultFromScode (MAPI_E_NOT_ME);
  385.     }
  386.     
  387. ret:
  388.     *lppval = lpval;
  389.     DebugTraceResult (HrCheckRule(), hr);
  390.     return hr;
  391. }
  392. /*
  393.  *  HrFolderFromPath()
  394.  *
  395.  *  Purpose:
  396.  *
  397.  *      Takes a IPM root-based path string and returns a folder
  398.  *      corresponding to the path given.  The '' character is the path
  399.  *      separator.  And non-existing folders are created as a psrt of the
  400.  *      process.
  401.  *
  402.  *  Arguments:
  403.  *
  404.  *      lpsmh               pointer to smh parent object
  405.  *      lpmdb               store in which the path is to exist
  406.  *      lpszPath            the root-based path to use
  407.  *      lppfldr     [OUT]   buffer to place target folder
  408.  *      lppvalEid   [OUT]   buffer for target entryid value struct pointer
  409.  *
  410.  *  Returns:
  411.  *
  412.  *      (HRESULT)
  413.  */
  414. HRESULT
  415. HrFolderFromPath (LPSMH lpsmh,
  416.     LPMDB lpmdb,
  417.     LPTSTR lpszPath,
  418.     LPMAPIFOLDER FAR * lppfldr,
  419.     LPSPropValue FAR * lppvalEid)
  420. {
  421.     HRESULT hr;
  422.     LPMAPIFOLDER lpfldr = NULL;
  423.     LPMAPIFOLDER lpfldrT = NULL;
  424.     LPSPropValue lpval = NULL;
  425.     LPTSTR lpch;
  426.     TCHAR rgch[MAX_PATH];
  427.     ULONG ulType;
  428.     if (!LoadString (lpsmh->hinst, SMH_FolderComment, rgch, sizeof(rgch)))
  429.         rgch[0] = 0;
  430.     hr = HrGetOneProp ((LPMAPIPROP)lpmdb, PR_IPM_SUBTREE_ENTRYID, &lpval);
  431.     if (!HR_FAILED (hr))
  432.     {
  433.         hr = lpmdb->lpVtbl->OpenEntry (lpmdb,
  434.                             lpval->Value.bin.cb,
  435.                             (LPENTRYID)lpval->Value.bin.lpb,
  436.                             NULL,
  437.                             MAPI_MODIFY,
  438.                             &ulType,
  439.                             (LPUNKNOWN FAR *)&lpfldr);
  440.         (*lpsmh->lpfnFree) (lpval);
  441.         lpval = NULL;
  442.         if (!HR_FAILED (hr))
  443.         {
  444.             do
  445.             {
  446.                 if (lpch = LpszFindChar (lpszPath, '\'))
  447.                     *lpch = 0;
  448.                 Assert (lstrlen (lpszPath));
  449.                 hr = lpfldr->lpVtbl->CreateFolder (lpfldr,
  450.                             FOLDER_GENERIC,
  451.                             lpszPath,
  452.                             rgch,
  453.                             NULL,
  454.                             MAPI_MODIFY | OPEN_IF_EXISTS,
  455.                             &lpfldrT);
  456.                 if (HR_FAILED (hr))
  457.                 {
  458. #ifdef  DEBUG
  459.                     LPMAPIERROR lperr = NULL;
  460.                     lpfldr->lpVtbl->GetLastError (lpfldr, hr, 0, &lperr);
  461.                     DebugTrace ("SMH: WARNING: unable to open/create folder: '%s' in %sn",
  462.                         lperr->lpszError, lperr->lpszComponent);
  463.                     (*lpsmh->lpfnFree) (lperr);
  464. #endif
  465.                     break;
  466.                 }
  467.                 UlRelease (lpfldr);
  468.                 lpfldr = lpfldrT;
  469.                 lpfldrT = NULL;
  470.                 lpszPath = (lpch ? ++lpch : NULL);
  471.             } while (lpszPath);
  472.         }
  473.         if (!HR_FAILED (hr))
  474.         {
  475.             hr = HrGetOneProp ((LPMAPIPROP)lpfldr, PR_ENTRYID, &lpval);
  476.             if (!HR_FAILED (hr))
  477.             {
  478.                 *lppfldr = lpfldr;
  479.                 *lppvalEid = lpval;
  480.                 lpfldr = NULL;
  481.                 lpval = NULL;
  482.             }
  483.         }
  484.     }
  485.     (*lpsmh->lpfnFree) (lpval);
  486.     UlRelease (lpfldr);
  487.     DebugTraceResult (HrFolderFromPath(), hr);
  488.     return hr;
  489. }
  490. /*
  491.  *  HrBuildRule()
  492.  *
  493.  *  Purpose:
  494.  *
  495.  *      Takes a profile section and builds a rule structure that
  496.  *      corresponds to the properties in the profile section.
  497.  *
  498.  *  Arguments:
  499.  *
  500.  *      lpsmh           pointer to smh parent object
  501.  *      lpmuid          profile section UID
  502.  *      lpprl   [OUT]   buffer for the newly created rule pointer
  503.  *
  504.  *  Returns:
  505.  *
  506.  *      (HRESULT)
  507.  */
  508. HRESULT
  509. HrBuildRule (LPSMH lpsmh, LPMAPIUID lpmuid, LPRULE FAR * lpprl)
  510. {
  511.     SCODE sc;
  512.     HRESULT hr;
  513.     LPMAPISESSION lpsess = lpsmh->lpsess;
  514.     LPPROFSECT lpprof = NULL;
  515.     LPRULE lprl = NULL;
  516.     LPSPropValue lpval = NULL;
  517.     LPSPropValue lpvalEid = NULL;
  518.     LPSPropValue lpvalT;
  519.     LPSRestriction lpres = NULL;
  520.     ULONG cval;
  521.     ULONG ulType;
  522.     UINT cb;
  523.     UINT i;
  524.     sc = (*lpsmh->lpfnAlloc) (sizeof(RULE), &lprl);
  525.     if (FAILED (sc))
  526.     {
  527.         hr = ResultFromScode (sc);
  528.         goto ret;
  529.     }
  530.     memset (lprl, 0, sizeof(RULE));
  531.     memcpy (&lprl->muid, lpmuid, sizeof(MAPIUID));
  532.     hr = lpsess->lpVtbl->OpenProfileSection (lpsess,
  533.                             lpmuid,
  534.                             NULL,
  535.                             MAPI_MODIFY,
  536.                             &lpprof);
  537.     if (HR_FAILED (hr))
  538.         goto ret;
  539.     hr = lpprof->lpVtbl->GetProps (lpprof,
  540.                             (LPSPropTagArray)&sptRule,
  541.                             0,
  542.                             &cval,
  543.                             &lpval);
  544.     if (HR_FAILED (hr))
  545.         goto ret;
  546.     if ((lpval[ipRLType].ulPropTag != PR_RULE_TYPE) ||
  547.         (lpval[ipRLData].ulPropTag != PR_RULE_DATA) ||
  548.         (lpval[ipRLFlags].ulPropTag != PR_RULE_FLAGS) ||
  549.         (!(lpval[ipRLFlags].Value.l & (RULE_DELETE | RULE_NO_MOVE)) &&
  550.           (lpval[ipRLType].ulPropTag != PR_RULE_TYPE) ||
  551.           (lpval[ipRLPath].ulPropTag != PR_RULE_TARGET_PATH) ||
  552.           (lpval[ipRLStore].ulPropTag != PR_RULE_STORE_DISPLAY_NAME)))
  553.     {
  554.         /*  Something very important is missing */
  555.         hr = ResultFromScode (MAPI_E_UNCONFIGURED);
  556.         goto ret;
  557.     }
  558.     lprl->rlTyp = (UINT)lpval[ipRLType].Value.l;
  559.     lprl->ulFlags = lpval[ipRLFlags].Value.l;
  560.     /*  Get the filter value */
  561.     sc = (*lpsmh->lpfnAllocMore) (lpval[ipRLData].Value.bin.cb, lprl, &lprl->lpszData);
  562.     if (FAILED (sc))
  563.     {
  564.         hr = ResultFromScode (sc);
  565.         goto ret;
  566.     }
  567.     memcpy (lprl->lpszData,
  568.         lpval[ipRLData].Value.bin.lpb,
  569.         (UINT)lpval[ipRLData].Value.bin.cb);
  570.     /*  Get the sounds */
  571.     if (lpval[ipRLFlags].Value.l & RULE_PLAY_SOUNDS)
  572.     {
  573.         for (i = 0; i < csndMax; i++)
  574.         {
  575.             if ((lpval[ipRLLoPri + i].ulPropTag == sptRule.aulPropTag[ipRLLoPri + i]) &&
  576.                 (cb = lstrlen (lpval[ipRLLoPri + i].Value.lpszA)))
  577.             {
  578.                 cb += sizeof(TCHAR);
  579.                 sc = (*lpsmh->lpfnAllocMore) (cb, lprl, (LPVOID FAR *)&lprl->rgszSnd[i]);
  580.                 if (FAILED (sc))
  581.                 {
  582.                     hr = ResultFromScode (sc);
  583.                     goto ret;
  584.                 }
  585.                 lstrcpy (lprl->rgszSnd[i], lpval[ipRLLoPri + i].Value.lpszA);
  586.             }
  587.         }
  588.     }
  589.     /*  Fill in the auto response */
  590.     if (lpval[ipRLFlags].Value.l & RULE_AUTO_RESPONSE)
  591.     {
  592.         if (lpval[ipRLRepFwdRTF].ulPropTag == PR_RULE_REP_FWD_RTF)
  593.         {
  594.             sc = (*lpsmh->lpfnAllocMore) (lpval[ipRLRepFwdRTF].Value.bin.cb,
  595.                                           lprl,
  596.                                           (LPVOID FAR *)&lprl->lpbRTF);
  597.             if (FAILED (sc))
  598.             {
  599.                 hr = ResultFromScode (sc);
  600.                 goto ret;
  601.             }
  602.             lprl->cbRTF = lpval[ipRLRepFwdRTF].Value.bin.cb;
  603.             memcpy (lprl->lpbRTF, lpval[ipRLRepFwdRTF].Value.bin.lpb, (UINT)lprl->cbRTF);
  604.         }
  605.         else if (lpval[ipRLRepFwd].ulPropTag == PR_RULE_REP_FWD_TEXT)
  606.         {
  607.             cb = lstrlen (lpval[ipRLRepFwd].Value.lpszA) + sizeof(TCHAR);
  608.             sc = (*lpsmh->lpfnAllocMore) (cb, lprl, (LPVOID FAR *)&lprl->lpszAnno);
  609.             if (FAILED (sc))
  610.             {
  611.                 hr = ResultFromScode (sc);
  612.                 goto ret;
  613.             }
  614.             lstrcpy (lprl->lpszAnno, lpval[ipRLRepFwd].Value.lpszA);
  615.         }
  616.         if (lpval[ipRLFlags].Value.l & RULE_AUTO_FORWARD)
  617.         {
  618.             if (lpval[ipRLFwdEid].ulPropTag != PR_RULE_FORWARD_RECIP_ENTRYID)
  619.             {
  620.                 hr = ResultFromScode (MAPI_E_UNCONFIGURED);
  621.                 goto ret;
  622.             }
  623.             else
  624.             {
  625.                 sc = (*lpsmh->lpfnAlloc) (sizeof(SPropValue), &lprl->lpvalRecip);
  626.                 if (!FAILED (sc))
  627.                 {
  628.                     sc = (*lpsmh->lpfnAllocMore) (lpval[ipRLFwdEid].Value.bin.cb,
  629.                         lprl->lpvalRecip,
  630.                         &lprl->lpvalRecip[0].Value.bin.lpb);
  631.                     if (!FAILED (sc))
  632.                     {
  633.                         lprl->lpvalRecip[0].ulPropTag = PR_ENTRYID;
  634.                         lprl->lpvalRecip[0].Value.bin.cb = lpval[ipRLFwdEid].Value.bin.cb;
  635.                         memcpy (lprl->lpvalRecip[0].Value.bin.lpb,
  636.                                 lpval[ipRLFwdEid].Value.bin.lpb,
  637.                                 lpval[ipRLFwdEid].Value.bin.cb);
  638.                     }
  639.                 }
  640.             }
  641.             if (FAILED (sc))
  642.             {
  643.                 hr = ResultFromScode (sc);
  644.                 goto ret;
  645.             }
  646.         }
  647.     }
  648.     /*  See if we are not going to delete the message */
  649.     
  650.     if (!(lpval[ipRLFlags].Value.l & (RULE_DELETE | RULE_NO_MOVE)))
  651.     {
  652.         /*  Find the target folder */
  653.         hr = HrOpenMdbFromName (lpsmh, lpval[ipRLStore].Value.LPSZ, &lprl->lpmdb);
  654.         if (HR_FAILED (hr))
  655.             goto ret;
  656.         if ((lpval[ipRLEid].ulPropTag != PR_RULE_TARGET_ENTRYID) ||
  657.             (HR_FAILED (lpsess->lpVtbl->OpenEntry (lpsess,
  658.                             lpval[ipRLEid].Value.bin.cb,
  659.                             (LPENTRYID)lpval[ipRLEid].Value.bin.lpb,
  660.                             NULL,
  661.                             MAPI_MODIFY,
  662.                             &ulType,
  663.                             (LPUNKNOWN FAR *)&lprl->lpfldr))))
  664.         {
  665.             hr = HrFolderFromPath (lpsmh,
  666.                             lprl->lpmdb,
  667.                             lpval[ipRLPath].Value.LPSZ,
  668.                             &lprl->lpfldr,
  669.                             &lpvalEid);
  670.             if (HR_FAILED (hr))
  671.                 goto ret;
  672.             lpvalEid->ulPropTag = PR_RULE_TARGET_ENTRYID;
  673.             HrSetOneProp ((LPMAPIPROP)lpprof, lpvalEid);
  674.             lprl->lpvalEid = lpvalEid;
  675.         }
  676.         else
  677.         {
  678.             hr = HrGetOneProp ((LPMAPIPROP)lprl->lpfldr, PR_ENTRYID, &lprl->lpvalEid);
  679.             if (HR_FAILED (hr))
  680.                 goto ret;
  681.         }
  682.     }
  683.     if ((lpval[ipRLType].Value.l == RL_TO_RECIP) ||
  684.         (lpval[ipRLType].Value.l == RL_CC_RECIP) ||
  685.         (lpval[ipRLType].Value.l == RL_BCC_RECIP) ||
  686.         (lpval[ipRLType].Value.l == RL_ANY_RECIP))
  687.     {
  688.         cb = (sizeof(SRestriction) * cresMax) + (sizeof(SPropValue) * cvMax);
  689.         sc = (*lpsmh->lpfnAllocMore) (cb, lprl, &lpres);
  690.         if (FAILED (sc))
  691.         {
  692.             hr = ResultFromScode (sc);
  693.             goto ret;
  694.         }
  695.         lpvalT = (LPSPropValue)&lpres[cresMax];
  696.         lpres[iresAnd].rt = RES_AND;
  697.         lpres[iresAnd].res.resAnd.cRes = 2;
  698.         lpres[iresAnd].res.resAnd.lpRes = &lpres[iresRecip];
  699.         lpvalT[ivRecip].ulPropTag = PR_RECIPIENT_TYPE;
  700.         lpvalT[ivRecip].Value.l = ((lpval[ipRLType].Value.l == RL_TO_RECIP)
  701.                                     ? MAPI_TO
  702.                                     : ((lpval[ipRLType].Value.l == RL_CC_RECIP)
  703.                                         ? MAPI_CC
  704.                                         : ((lpval[ipRLType].Value.l == RL_BCC_RECIP)
  705.                                             ? MAPI_BCC
  706.                                             : 0)));
  707.         lpres[iresRecip].rt = RES_PROPERTY;
  708.         lpres[iresRecip].res.resProperty.relop = RELOP_EQ;
  709.         lpres[iresRecip].res.resContent.ulPropTag = PR_RECIPIENT_TYPE;
  710.         lpres[iresRecip].res.resContent.lpProp = &lpvalT[ivRecip];
  711.         lpres[iresOr].rt = RES_OR;
  712.         lpres[iresOr].res.resOr.cRes = 2;
  713.         lpres[iresOr].res.resOr.lpRes = &lpres[iresEmail];
  714.         lpvalT[ivEmail].ulPropTag = PR_EMAIL_ADDRESS;
  715.         lpvalT[ivEmail].Value.LPSZ = (LPTSTR)lprl->lpszData;
  716.         lpres[iresEmail].rt = RES_CONTENT;
  717.         lpres[iresEmail].res.resContent.ulFuzzyLevel = FL_SUBSTRING | FL_IGNORECASE;
  718.         lpres[iresEmail].res.resContent.ulPropTag = PR_EMAIL_ADDRESS;
  719.         lpres[iresEmail].res.resContent.lpProp = &lpvalT[ivEmail];
  720.         lpvalT[ivDispNm].ulPropTag = PR_DISPLAY_NAME;
  721.         lpvalT[ivDispNm].Value.LPSZ = (LPTSTR)lprl->lpszData;
  722.         lpres[iresDispNm].rt = RES_CONTENT;
  723.         lpres[iresDispNm].res.resContent.ulFuzzyLevel = FL_SUBSTRING | FL_IGNORECASE;
  724.         lpres[iresDispNm].res.resContent.ulPropTag = PR_DISPLAY_NAME;
  725.         lpres[iresDispNm].res.resContent.lpProp = &lpvalT[ivDispNm];
  726.         if ((lpval[ipRLType].Value.l == RL_TO_RECIP) ||
  727.             (lpval[ipRLType].Value.l == RL_CC_RECIP) ||
  728.             (lpval[ipRLType].Value.l == RL_BCC_RECIP))
  729.             lprl->lpres = &lpres[iresAnd];
  730.         else
  731.             lprl->lpres = &lpres[iresOr];
  732.     }
  733. ret:
  734.     (*lpsmh->lpfnFree) (lpval);
  735.     UlRelease (lpprof);
  736.     if (HR_FAILED (hr))
  737.     {
  738.         (*lpsmh->lpfnFree) (lprl->lpvalRecip);
  739.         (*lpsmh->lpfnFree) (lprl->lpvalEid);
  740.         (*lpsmh->lpfnFree) (lprl);
  741.         lprl = NULL;
  742.     }
  743.     *lpprl = lprl;
  744.     DebugTraceResult (HrBuildRule(), hr);
  745.     return hr;
  746. }
  747. /*
  748.  *  ReleaseBkit()
  749.  *
  750.  *  Purpose:
  751.  *
  752.  *      Cleans up all resources held by a bucket structure and wipes the
  753.  *      structure clean.
  754.  *
  755.  *  Arguments:
  756.  *
  757.  *      lpsmh           pointer to the smh object (uses allocation fn's)
  758.  *      lpbkit          pointer to the bucket needing cleaning
  759.  *
  760.  */
  761. VOID
  762. ReleaseBkit (LPSMH lpsmh, LPBKIT lpbkit)
  763. {
  764.     UlRelease (lpbkit->lpfldr);
  765.     UlRelease (lpbkit->lpfldrYr);
  766.     UlRelease (lpbkit->lpfldrParent);
  767.     (*lpsmh->lpfnFree) (lpbkit->lpeid);
  768.     (*lpsmh->lpfnFree) (lpbkit->lpeidYr);
  769.     (*lpsmh->lpfnFree) (lpbkit->lpeidParent);
  770.     memset (lpbkit, 0, sizeof(BKIT));
  771.     return;
  772. }
  773. HRESULT
  774. HrInitSMH (LPSMH lpsmh)
  775. {
  776.     HRESULT hr;
  777.     LPPROFSECT lpprof = NULL;
  778.     LPRULE lprl;
  779.     LPSPropValue lpval = NULL;
  780.     LPSPropValue lpvalOld;
  781.     UINT crl;
  782.     ULONG cval;
  783.     
  784.     /*  Get options from the profile */
  785.     hr = lpsmh->lpsess->lpVtbl->OpenProfileSection (lpsmh->lpsess,
  786.                             &lpsmh->muid,
  787.                             NULL,
  788.                             MAPI_MODIFY,
  789.                             &lpprof);
  790.     if (HR_FAILED (hr))
  791.         goto ret;
  792.     hr = lpprof->lpVtbl->GetProps (lpprof,
  793.                             (LPSPropTagArray)&sptConfigProps,
  794.                             0,
  795.                             &cval,
  796.                             &lpval);
  797.     if (HR_FAILED (hr))
  798.         goto ret;
  799.     /*  Check to see if we are configured */
  800.     if (lpval[ipFlags].ulPropTag != PR_SMH_FLAGS)
  801.     {
  802.         hr = ResultFromScode (MAPI_E_UNCONFIGURED);
  803.         goto ret;
  804.     }
  805.     /*  Check that the rules are stored in the correct format */
  806.     
  807.     if (lpval[ipRules].ulPropTag != PR_SMH_RULES)
  808.     {
  809.         hr = HrGetOneProp ((LPMAPIPROP)lpprof,
  810.                     CHANGE_PROP_TYPE(PR_SMH_RULES, PT_BINARY),
  811.                     &lpvalOld);
  812.         if (!HR_FAILED (hr))
  813.         {
  814.             /*  The rules are stored in the wrong format */
  815.             hr = HrUpdateProfileFormat (lpsmh->lpsess,
  816.                             lpsmh->lpsess->lpVtbl->OpenProfileSection,
  817.                             lpsmh->lpfnAllocMore,
  818.                             lpsmh->lpfnFree,
  819.                             lpval,
  820.                             lpvalOld);
  821.             (*lpsmh->lpfnFree) (lpvalOld);
  822.             if (HR_FAILED (hr))
  823.                 goto ret;
  824.             /*  Save out anything we got back */
  825.             lpprof->lpVtbl->SetProps (lpprof, cpMax, lpval, NULL);
  826.         }
  827.     }
  828.     UlRelease (lpprof);
  829.     lpprof = NULL;
  830.     /*  Grab the exclusions list */
  831.     hr = ResultFromScode (PropCopyMore (&lpsmh->valEx,
  832.                             &lpval[ipExc],
  833.                             lpsmh->lpfnAllocMore,
  834.                             lpsmh));
  835.     if (HR_FAILED (hr))
  836.         goto ret;
  837.     /*  Init the stores table */
  838.     hr = HrInitStoresTable (lpsmh, lpsmh->lpsess);
  839.     if (HR_FAILED (hr))
  840.         goto ret;
  841.     /*  Store the values */
  842.     lpsmh->fAtp = !!(lpval[ipFlags].Value.l & SMH_ADD_TO_PAB);
  843.     lpsmh->fCatSm = !!(lpval[ipFlags].Value.l & SMH_FILTER_SENTMAIL);
  844.     lpsmh->fCatSmByYr = !!(lpval[ipFlags].Value.l & SMH_FILTER_SENTMAIL_YR);
  845.     /*  If we are archiving deleted mail, init the filters */
  846.     
  847.     if (lpval[ipFlags].Value.l & SMH_FILTER_DELETED)
  848.     {
  849.         HrInitDeletedMailFilter (lpsmh);
  850.         lpsmh->fCatWb = !!(lpval[ipFlags].Value.l & SMH_FILTER_DELETED_YR);
  851.     }
  852.     
  853.     /*  If the unread folder is desired, make sure it is there */
  854.     
  855.     if (!!(lpval[ipFlags].Value.l & SMH_UNREAD_VIEWER))
  856.         HrInitUnreadSearch (lpsmh);
  857.     /*  Setup the oof text */
  858.     
  859.     if ((lpval[ipOofEnabled].ulPropTag == PR_SMH_OOF_ENABLED) &&
  860.         lpval[ipOofEnabled].Value.b)
  861.     {
  862.         lpsmh->fOof = !HR_FAILED (HrInitOof (lpsmh,
  863.                                         &lpval[ipOof],
  864.                                         &lpval[ipOofRtf]));
  865.     }
  866.     /*  Build the rules if need be */
  867.     
  868.     if ((lpval[ipFlags].Value.l & SMH_FILTER_INBOUND) &&
  869.         (lpval[ipRules].ulPropTag == PR_SMH_RULES) &&
  870.         (lpval[ipRules].Value.MVbin.cValues != 0))
  871.     {
  872.         crl = (UINT)lpval[ipRules].Value.MVbin.cValues;
  873.         while (crl--)
  874.         {
  875.             hr = HrBuildRule (lpsmh,
  876.                     (LPMAPIUID)lpval[ipRules].Value.MVbin.lpbin[crl].lpb,
  877.                     &lprl);
  878.             if (!HR_FAILED (hr))
  879.             {
  880.                 lprl->rlNext = lpsmh->lstRl;
  881.                 lpsmh->lstRl = lprl;
  882.             }
  883.         }
  884.         hr = hrSuccess;
  885.     }
  886. ret:
  887.     UlRelease (lpprof);
  888.     (*lpsmh->lpfnFree) (lpval);
  889.     DebugTraceResult (HrInitSMH(), hr);
  890.     return hr;
  891. }
  892. VOID
  893. DeinitSMH (LPSMH lpsmh)
  894. {
  895.     LPRULE lprl;
  896.     LPRULE lprlT;
  897.     LPWB lpwb;
  898.     LPWB lpwbT;
  899.     
  900.     ReleaseBkit (lpsmh, &lpsmh->bkitSm);
  901.     memset (&lpsmh->bkitSm, 0, sizeof(BKIT));
  902.     for (lpwb = lpsmh->lstWb; lpwb; lpwb = lpwbT)
  903.     {
  904.         lpwbT = lpwb->wbNext;
  905.         lpwb->lptbl->lpVtbl->Unadvise (lpwb->lptbl, lpwb->ulAdvz);
  906. #ifdef  _WIN32
  907.         if (lpwb->ht)
  908.         {
  909.             lpwb->fBail = TRUE;
  910.             WaitForSingleObject (lpwb->ht, INFINITE);
  911.         }
  912. #endif
  913.         ReleaseBkit (lpsmh, &lpwb->bkit);
  914.         UlRelease (lpwb->lptbl);
  915.         UlRelease (lpwb->lpfldr);
  916.         (*lpsmh->lpfnFree) (lpwb->lpvalEid);
  917.         (*lpsmh->lpfnFree) (lpwb);
  918.     }
  919.     lpsmh->lstWb = NULL;
  920.     for (lprl = lpsmh->lstRl; lprl; lprl = lprlT)
  921.     {
  922.         lprlT = lprl->rlNext;
  923.         ReleaseBkit (lpsmh, &lprl->bkit);
  924.         UlRelease (lprl->lpfldr);
  925.         (*lpsmh->lpfnFree) (lprl->lpvalEid);
  926.         (*lpsmh->lpfnFree) (lprl->lpvalRecip);
  927.         (*lpsmh->lpfnFree) (lprl);
  928.     }
  929.     lpsmh->lstRl = NULL;
  930.     UlRelease (lpsmh->oof.lptad);
  931.     UlRelease (lpsmh->oof.lptbl);
  932.     (*lpsmh->lpfnFree) (lpsmh->oof.lpbRTF);
  933.     (*lpsmh->lpfnFree) (lpsmh->oof.lpszBody);
  934.     memset (&lpsmh->oof, 0, sizeof(OOF));
  935.     ReleaseStoresTable (lpsmh);
  936.     return;
  937. }
  938. /*
  939.  *  SMH Object Methods
  940.  *
  941.  *  SMH_QueryInterface      (See OLE IUnknown object methods)
  942.  *  SMH_AddRef              (See OLE IUnknown object methods)
  943.  *  SMH_Release             (See OLE IUnknown object methods)
  944.  *  SMH_InboundMsgHook      Filters inbound messages
  945.  *  SMH_OutboundMsgHook     Filters sent mail messages
  946.  *
  947.  */
  948. STDMETHODIMP
  949. SMH_QueryInterface (LPSMH lpsmh, REFIID lpiid, LPVOID FAR * lppv)
  950. {
  951.     if (IsBadWritePtr (lpsmh, sizeof(SMH)) ||
  952.         IsBadReadPtr (lpiid, sizeof(IID)) ||
  953.         IsBadWritePtr (lppv, sizeof(LPVOID)))
  954.         return ResultFromScode (MAPI_E_INVALID_PARAMETER);
  955.     if (!memcmp (lpiid, &IID_ISpoolerHook, sizeof(IID)) ||
  956.         !memcmp (lpiid, &IID_IUnknown, sizeof(IID)))
  957.     {
  958.         *lppv = (LPVOID)lpsmh;
  959.         lpsmh->lcInit++;
  960.         return hrSuccess;
  961.     }
  962.     DebugTraceSc (SMH_QueryInterface(), MAPI_E_INTERFACE_NOT_SUPPORTED);
  963.     return ResultFromScode (MAPI_E_INTERFACE_NOT_SUPPORTED);
  964. }
  965. STDMETHODIMP_ (ULONG)
  966. SMH_AddRef (LPSMH lpsmh)
  967. {
  968.     if (IsBadWritePtr (lpsmh, sizeof(SMH)))
  969.         return 0;
  970.     return ++lpsmh->lcInit;
  971. }
  972. STDMETHODIMP_ (ULONG)
  973. SMH_Release (LPSMH lpsmh)
  974. {
  975.     if (IsBadWritePtr (lpsmh, sizeof(SMH)))
  976.         return 0;
  977.     if (--lpsmh->lcInit)
  978.         return lpsmh->lcInit;
  979.     DeinitSMH (lpsmh);
  980.     
  981.     CloseHandle (lpsmh->hevtCfg);
  982.     UlRelease (lpsmh->lpsess);
  983.     (*lpsmh->lpfnFree) (lpsmh);
  984.     if (lpCtl3D)
  985.     {
  986.         CTL3D_Uninitialize (lpCtl3D);
  987.         lpCtl3D = NULL;
  988.     }
  989.     return 0;
  990. }
  991. /*
  992.  *  SMH_InboundMsgHook()
  993.  *
  994.  *  Purpose:
  995.  *
  996.  *      The purpose of this filter is to match inbound messages to
  997.  *      individual rules from the profile and re-route the messages based
  998.  *      on the results of the comparisons.
  999.  *
  1000.  *  Arguments:
  1001.  *
  1002.  *      lpsmh           this filter hook obj
  1003.  *      lpmsg           the message to be filtered
  1004.  *      lpfldrDef       owning folder of message
  1005.  *      lpmdbDef        owning store of message
  1006.  *      lpulFlags       flags returned by filter
  1007.  *      lpcbeid         cb for entryid of default target for message
  1008.  *      lppbeid         pb for entryid of default target for message
  1009.  *
  1010.  *  Operation:
  1011.  *
  1012.  *      Opens the suggested folder (if needed) and checks for the
  1013.  *      existence of the appropriate "bucket" folder.  If it does exist,
  1014.  *      then the  folder is created and cached.  The entryid is grabbed
  1015.  *      and passed back in to the spooler.
  1016.  *
  1017.  *  Returns:
  1018.  *
  1019.  *      (HRESULT)
  1020.  *      lpulFlags   [out]   set HOOK_CANCEL if this is the last hook
  1021.  *      lpcbeid     [out]   the size of the returned EntryID
  1022.  *      lppbeid     [out]   the data of the returned EntryID
  1023.  *
  1024.  */
  1025. STDMETHODIMP
  1026. SMH_InboundMsgHook (LPSMH lpsmh,
  1027.     LPMESSAGE lpmsg,
  1028.     LPMAPIFOLDER lpfldrDef,
  1029.     LPMDB lpmdbDef,
  1030.     ULONG FAR * lpulFlags,
  1031.     ULONG FAR * lpcbeid,
  1032.     LPBYTE FAR * lppeid)
  1033. {
  1034.     HRESULT hr = hrSuccess;
  1035.     LPRULE lprl;
  1036.     LPBYTE lpeid;
  1037.     LPSPropValue lpval = NULL;
  1038.     /*  Quick and dirty parameter check */
  1039.     if (IsBadWritePtr (lpsmh, sizeof(SMH)) ||
  1040.         IsBadWritePtr (lpcbeid, sizeof(ULONG)) ||
  1041.         IsBadWritePtr (lppeid, sizeof(LPBYTE)) ||
  1042.         IsBadWritePtr (*lppeid, (UINT)(*lpcbeid)))
  1043.         return ResultFromScode (MAPI_E_INVALID_PARAMETER);
  1044. #ifdef  _WIN32
  1045.     if (FConfigChanged (lpsmh->hevtCfg))
  1046.     {
  1047.         /*  reconfiguration required */
  1048.         
  1049.         DeinitSMH (lpsmh);
  1050.         hr = HrInitSMH (lpsmh);
  1051.         if (HR_FAILED (hr))
  1052.             return hr;
  1053.         
  1054.         ResetEvent (lpsmh->hevtCfg);
  1055.     }
  1056. #endif  // _WIN32
  1057.     
  1058.     if (lprl = lpsmh->lstRl)    /*  Yup '=' */
  1059.     {
  1060.         hr = HrCheckExclusions (lpsmh, lpmsg);
  1061.         if (!HR_FAILED (hr))
  1062.         {
  1063.             /*  We have not been excluded */
  1064.             for (; lprl; lprl = lprl->rlNext)
  1065.             {
  1066.                 hr = HrCheckRule (lpsmh, lprl, lpmsg, &lpval);
  1067.                 if (!HR_FAILED (hr))
  1068.                 {
  1069.                     /*  We have a match. What do we do, filter or delete? */
  1070.                     
  1071.                     if (!(lprl->ulFlags & (RULE_DELETE | RULE_NO_MOVE)))
  1072.                     {
  1073.                         /*  Filter the critter */
  1074.                         hr = ResultFromScode ((*lpsmh->lpfnAlloc) (lprl->lpvalEid->Value.bin.cb, &lpeid));
  1075.                         if (!HR_FAILED (hr))
  1076.                         {
  1077.                             memcpy (lpeid, lprl->lpvalEid->Value.bin.lpb,
  1078.                                 (UINT)lprl->lpvalEid->Value.bin.cb);
  1079.                             (*lpsmh->lpfnFree) (*lppeid);
  1080.                             *lpcbeid = lprl->lpvalEid->Value.bin.cb;
  1081.                             *lppeid = lpeid;
  1082.                             if (lprl->ulFlags & RULE_ARCHIVED)
  1083.                             {
  1084.                                 hr = HrArchiveMessage (lpsmh,
  1085.                                             lpmsg,
  1086.                                             lpfldrDef,
  1087.                                             lpmdbDef,
  1088.                                             &lprl->bkit,
  1089.                                             !!(lprl->ulFlags & RULE_ARCHIVED_BY_YEAR),
  1090.                                             lpcbeid,
  1091.                                             lppeid);
  1092.                                 
  1093.                                 if (lprl->ulFlags & RULE_TERMINAL)
  1094.                                     *lpulFlags = HOOK_CANCEL;
  1095.                             }
  1096.                         }
  1097.                         /*  Play the sound */
  1098.                         if ((lpval[ipPriority].Value.l < 3) &&
  1099.                             lprl->rgszSnd[lpval[ipPriority].Value.l])
  1100.                             sndPlaySound (lprl->rgszSnd[lpval[ipPriority].Value.l], SND_ASYNC);
  1101.                     }
  1102.                     else
  1103.                     {
  1104.                         if (lprl->ulFlags & RULE_DELETE)
  1105.                             *lpulFlags |= HOOK_DELETE;
  1106.                                           
  1107.                         *lpulFlags |= HOOK_CANCEL;
  1108.                     }
  1109.                     /*  Check for an auto-forwardreply */
  1110.                     if (lprl->ulFlags & RULE_AUTO_RESPONSE)
  1111.                     {
  1112.                         /*  We have a response that needs to
  1113.                          *  be created, and sent on.
  1114.                          */
  1115.                         hr = HrGenerateResponse (lpsmh, lprl, lpfldrDef, lpmsg);
  1116.                     }
  1117.                     break;
  1118.                 }
  1119.                 else if (GetScode (hr) != MAPI_E_NOT_ME)
  1120.                 {
  1121.                     /*  We have a failure that is not really
  1122.                      *  expected, we need to bail.  Also, this
  1123.                      *  should cancel any further hooking
  1124.                      */
  1125.                     *lpulFlags = HOOK_CANCEL;
  1126.                     break;
  1127.                 }
  1128.                 else
  1129.                     hr = hrSuccess;
  1130.             }
  1131.         }
  1132.     }
  1133.     
  1134.     if (lpsmh->fOof)
  1135.     {
  1136.         /*  OOF'ing is done by calling HrGenerateResponse()
  1137.          *  and passing in a NULL for the rule.
  1138.          */
  1139.         hr = HrGenerateResponse (lpsmh, NULL, lpfldrDef, lpmsg);
  1140.     }
  1141.     (*lpsmh->lpfnFree) (lpval);
  1142.     DebugTraceResult (SMH_InboundMsgHook(), hr);
  1143.     return hrSuccess;
  1144. }
  1145. /*
  1146.  *  SMH_OutboundMsgHook()
  1147.  *
  1148.  *  Purpose:
  1149.  *
  1150.  *      The purpose of this filter is to "hash" a users sent mail
  1151.  *      processing based on date.  The most obvious bucket size is
  1152.  *      monthly but there is no reason not to make this an option the
  1153.  *      user could confiigure.
  1154.  *
  1155.  *  Arguments:
  1156.  *
  1157.  *      lpsmh           this filter hook obj
  1158.  *      lpmsg           the message to be filtered
  1159.  *      lpfldrDef       owning folder of message
  1160.  *      lpmdbDef        owning store of message
  1161.  *      lpulFlags       flags returned by filter
  1162.  *      lpcbeid         cb for entryid of default target for message
  1163.  *      lppbeid         pb for entryid of default target for message
  1164.  *
  1165.  *  Operation:
  1166.  *
  1167.  *      Opens the suggested folder (if needed) and checks for the
  1168.  *      existence of the appropriate "bucket" folder.  If it does exist,
  1169.  *      then the  folder is created and cached.  The entryid is grabbed
  1170.  *      and passed back in to the spooler.
  1171.  *
  1172.  *  Returns:
  1173.  *
  1174.  *      (HRESULT)
  1175.  *      lpulFlags   [out]   set HOOK_CANCEL if this is the last hook
  1176.  *      lpcbeid     [out]   the size of the returned EntryID
  1177.  *      lppbeid     [out]   the data of the returned EntryID
  1178.  *
  1179.  */
  1180. STDMETHODIMP
  1181. SMH_OutboundMsgHook (LPSMH lpsmh,
  1182.     LPMESSAGE lpmsg,
  1183.     LPMAPIFOLDER lpfldrDef,
  1184.     LPMDB lpmdbDef,
  1185.     ULONG FAR * lpulFlags,
  1186.     ULONG FAR * lpcbeid,
  1187.     LPBYTE FAR * lppeid)
  1188. {
  1189.     HRESULT hr = hrSuccess;
  1190.     /*  Quick and dirty parameter check */
  1191.     if (IsBadWritePtr (lpsmh, sizeof(SMH)) ||
  1192.         IsBadWritePtr (lpcbeid, sizeof(ULONG)) ||
  1193.         IsBadWritePtr (lppeid, sizeof(LPBYTE)) ||
  1194.         IsBadWritePtr (*lppeid, (UINT)(*lpcbeid)))
  1195.         return ResultFromScode (MAPI_E_INVALID_PARAMETER);
  1196. #ifdef  _WIN32
  1197.     if (FConfigChanged (lpsmh->hevtCfg))
  1198.     {
  1199.         /*  reconfiguration required */
  1200.         
  1201.         DeinitSMH (lpsmh);
  1202.         hr = HrInitSMH (lpsmh);
  1203.         if (HR_FAILED (hr))
  1204.             return hr;
  1205.         
  1206.         ResetEvent (lpsmh->hevtCfg);
  1207.     }
  1208. #endif  // _WIN32
  1209.     if (lpsmh->fAtp)
  1210.         (void) HrAddEntriesToPab (lpsmh, lpmsg);
  1211.     if (lpsmh->fCatSm)
  1212.         hr = HrArchiveMessage (lpsmh,
  1213.                 lpmsg,
  1214.                 lpfldrDef,
  1215.                 lpmdbDef,
  1216.                 &lpsmh->bkitSm,
  1217.                 lpsmh->fCatSmByYr,
  1218.                 lpcbeid,
  1219.                 lppeid);
  1220.     DebugTraceResult (SMH_OutboundMsgHook(), hr);
  1221.     return hrSuccess;
  1222. }
  1223. /*
  1224.  *  SMH_Init()
  1225.  *
  1226.  *  Purpose:
  1227.  *
  1228.  *      Spooler's entry into the sample mail handler.  This function is
  1229.  *      equivilent to a provider logon in that it returns an object to
  1230.  *      the spooler that will be used to make any additional calls into
  1231.  *      the handler.
  1232.  *
  1233.  *  Arguments:
  1234.  *
  1235.  *      lpsess          the session this handler relates to
  1236.  *      hinst           hinst of the SMH dll
  1237.  *      lpfnAlloc       pointer to MAPIAllocateBuffer()
  1238.  *      lpfnAllocMore   pointer to MAPIAllocateMore()
  1239.  *      lpfnFree        pointer to MAPIFreeBuffer()
  1240.  *      lpmuid          pointer to profile section muid
  1241.  *      ulFlags         flags
  1242.  *      lppHook         buffer to hold handler object
  1243.  *
  1244.  *  Returns:
  1245.  *
  1246.  *      (HRESULT)
  1247.  *      lpphook     [OUT]   holds the returned handler object iff successful
  1248.  */
  1249. STDINITMETHODIMP
  1250. SMH_Init (LPMAPISESSION lpsess,
  1251.     HINSTANCE hinst,
  1252.     LPALLOCATEBUFFER lpfnAlloc,
  1253.     LPALLOCATEMORE lpfnAllocMore,
  1254.     LPFREEBUFFER lpfnFree,
  1255.     LPMAPIUID lpmuid,
  1256.     ULONG ulFlags,
  1257.     LPSPOOLERHOOK FAR * lppHook)
  1258. {
  1259.     SCODE sc;
  1260.     LPSMH lpsmh = NULL;
  1261.     HRESULT hr;
  1262.     sc = (*lpfnAlloc) (sizeof(SMH), &lpsmh);
  1263.     if (FAILED (sc))
  1264.         return ResultFromScode (sc);
  1265.     memset (lpsmh, 0, sizeof(SMH));
  1266.     hr = lpsess->lpVtbl->QueryInterface (lpsess,
  1267.                             &IID_IMAPISession,
  1268.                             &lpsmh->lpsess);
  1269.     if (!HR_FAILED (hr))
  1270.     {
  1271.         /*  Fill in all fields of the object */
  1272.         lpsmh->lpVtbl = (SMH_Vtbl FAR *)&vtblSMH;
  1273.         lpsmh->lcInit = 1;
  1274.         lpsmh->hinst = hinst;
  1275.         lpsmh->lpsess = lpsess;
  1276.         lpsmh->lpfnAlloc = lpfnAlloc;
  1277.         lpsmh->lpfnAllocMore = lpfnAllocMore;
  1278.         lpsmh->lpfnFree = lpfnFree;
  1279.         memcpy (&lpsmh->muid, lpmuid, sizeof(MAPIUID));
  1280. #ifdef  _WIN32
  1281.         /*  Setup listening for configuration changes */
  1282.         (void)HrGetConfigEvent (&lpsmh->hevtCfg);
  1283. #endif
  1284.         /*  Fill out the rest of the structure */
  1285.         
  1286.         hr = HrInitSMH (lpsmh);
  1287.     }
  1288.     if (HR_FAILED (hr))
  1289.     {
  1290.         UlRelease (lpsmh);
  1291.         lpsmh = NULL;
  1292.     }
  1293.     *lppHook = (LPSPOOLERHOOK)lpsmh;
  1294.     DebugTraceResult (SMH_Init(), hr);
  1295.     return hr;
  1296. }