home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / sdk / dbmsg / mapi / manager.sh / smh.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-04-11  |  44.0 KB  |  1,439 lines

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