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 / smhps.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-04-11  |  78.0 KB  |  2,735 lines

  1. /*
  2.  *  S M H P S . C
  3.  *
  4.  *  Sample mail handling hook configuration property sheets
  5.  *  Copyright 1992-95 Microsoft Corporation.  All Rights Reserved.
  6.  */
  7.  
  8. #include "_pch.h"
  9. #ifndef WIN16
  10. #include <commctrl.h>
  11. #endif
  12.  
  13. extern LPTSTR lpszConfigEvt;
  14. extern SPropTagArray sptRule;
  15. extern SPropTagArray sptConfigProps;
  16.  
  17. typedef struct _FILTER
  18. {
  19.     LPSCD               lpscd;              /* back-pointer to config struct */
  20.     
  21.     TCHAR               rgch[cchNameMax];   /* filter name */
  22.     MAPIUID             muid;               /* muid of filter profile section */
  23.     LPPROFSECT          lpsec;              /* profile section object */
  24.     LPSPropValue        lpval;              /* filter property values */
  25.  
  26.     SCODE               sc;
  27.  
  28. } FILTER, FAR * LPFILTER;
  29.  
  30.  
  31.  
  32. /*  sptDelete
  33.  *
  34.  *  This is the set of properties that need to be deleted from a rule
  35.  *  profile section any time the rule is edited.  Otherwise, changes in
  36.  *  target folders may not be retained across edits.
  37.  */
  38. const static SizedSPropTagArray (2, sptDelete) =
  39. {
  40.     2,
  41.     {
  42.         PR_RULE_TARGET_ENTRYID,
  43.         PR_RULE_STORE_ENTRYID
  44.     }
  45. };
  46.  
  47. enum {ipMsgSto, ipDefSto, cpStoTblMax};
  48. const static SizedSPropTagArray (cpStoTblMax, sptStoTbl) =
  49. {
  50.     cpStoTblMax,
  51.     {
  52.         PR_DISPLAY_NAME,
  53.         PR_DEFAULT_STORE
  54.     }
  55. };
  56.             
  57. /*
  58.  *  Common Dialog Functions ---------------------------------------------------
  59.  */
  60.  
  61. /*
  62.  *  SizeODButtons()
  63.  *
  64.  *  Purpose:
  65.  *
  66.  *      Set the control size for the two owner-draw buttons in the filter
  67.  *      page of the configuration property sheets.
  68.  *
  69.  *  Arguments:
  70.  *
  71.  *      hinst       the DLL instance
  72.  *      hdlg        the dialog in which the buttons will be drawn
  73.  *      id          the dialog ID identifying which buttons to size
  74.  */
  75. VOID
  76. SizeODButtons (HINSTANCE hInst, HWND hdlg, UINT id)
  77. {
  78.     BITMAP  bitmap;
  79.     HBITMAP hbmp;
  80.  
  81.     if (!(hbmp = LoadBitmap (hInst, MAKEINTRESOURCE(ID_UpArrow))))
  82.         return;
  83.     GetObject (hbmp, sizeof(BITMAP), &bitmap);
  84.  
  85.     if (id == SMH_FilterPage)
  86.     {
  87.         SetWindowPos (GetDlgItem (hdlg, ID_FilterUp), NULL, 0, 0, bitmap.bmWidth,
  88.             bitmap.bmHeight, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER);
  89.         SetWindowPos (GetDlgItem (hdlg, ID_FilterDown), NULL, 0, 0, bitmap.bmWidth,
  90.             bitmap.bmHeight, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER);
  91.     }
  92.     DeleteBitmap (hbmp);
  93. }
  94.  
  95.  
  96. /*
  97.  *  DrawODButton()
  98.  *
  99.  *  Purpose:
  100.  *
  101.  *      Draws the button control for either of the two owner-draw buttons
  102.  *      in the filter page of the configuration property sheets.
  103.  *
  104.  *  Arguments:
  105.  *
  106.  *      hinst       the DLL instance
  107.  *      pdi         the DRAWITEMSTRUCT info for drawing the button
  108.  */
  109. VOID
  110. DrawODButton (HINSTANCE hInst, DRAWITEMSTRUCT FAR * lpdi, BOOL fDrawFocus)
  111. {
  112.     HDC hDC;
  113.     HBITMAP hbmpOld;
  114.     HBITMAP hbmpArw;
  115.     WORD wBtnRes;
  116.     BITMAP bitmap;
  117.  
  118.     Assert (lpdi->CtlType == ODT_BUTTON);
  119.     if (!(hDC = CreateCompatibleDC (lpdi->hDC)))
  120.         return;
  121.  
  122.     /*  Get the bitmap */
  123.  
  124.     if (lpdi->itemState & ODS_SELECTED)
  125.         wBtnRes = (lpdi->CtlID == ID_FilterUp) ? ID_UpArrowInv : ID_DownArrowInv;
  126.     else if (lpdi->itemState & ODS_DISABLED)
  127.         wBtnRes = (lpdi->CtlID == ID_FilterUp) ? ID_UpArrowDis : ID_DownArrowDis;
  128.     else
  129.         wBtnRes = (lpdi->CtlID == ID_FilterUp) ? ID_UpArrow : ID_DownArrow;
  130.  
  131.     /*  blit the bitmap */
  132.  
  133.     if (!(hbmpArw = CreateMappedBitmap (hInst, wBtnRes, FALSE, NULL, 0)))
  134.         goto ret;
  135.     hbmpOld = SelectObject (hDC, hbmpArw);
  136.     BitBlt (lpdi->hDC, 0, 0, lpdi->rcItem.right - lpdi->rcItem.left,
  137.         lpdi->rcItem.bottom - lpdi->rcItem.top, hDC, 0, 0, SRCCOPY);
  138.  
  139.     /*  Draw a focus rectangle if the button has the focus */
  140.  
  141.     if(fDrawFocus && (lpdi->itemState & ODS_FOCUS))
  142.     {
  143.         GetObject (hbmpArw, sizeof(BITMAP), &bitmap);
  144.         lpdi->rcItem.right = bitmap.bmWidth;
  145.         lpdi->rcItem.bottom = bitmap.bmHeight;
  146.         InflateRect (&lpdi->rcItem, -3, -3);
  147.         if (lpdi->itemState & ODS_SELECTED)
  148.             OffsetRect (&lpdi->rcItem, 1, 1);
  149.         DrawFocusRect (lpdi->hDC, &lpdi->rcItem);
  150.     }
  151.  
  152.     SelectObject (hDC, hbmpOld);
  153.     DeleteBitmap (hbmpArw);
  154. ret:
  155.     DeleteDC (hDC);
  156. }
  157.  
  158.  
  159. /*
  160.  *  RTF Stream Callbacks ------------------------------------------------------
  161.  */
  162.  
  163. DWORD CALLBACK
  164. WriteRTFToBuffer (DWORD dwCookie, LPBYTE lpb, LONG cb, LONG FAR * lpcb)
  165. {
  166.     LPBYTE lpbT = NULL;
  167.     LPRTFS lprtfs = (LPRTFS)dwCookie;
  168.  
  169.     if ((lprtfs->cb + cb) > lprtfs->cbMax)
  170.     {
  171.         if (!FAILED ((*lprtfs->lpfnAlloc) (lprtfs->cb + (cb * 2), &lpbT)))
  172.         {
  173.             memcpy (lpbT, lprtfs->lpb, (UINT)lprtfs->cb);
  174.             (*lprtfs->lpfnFree) (lprtfs->lpb);
  175.             lprtfs->lpb = lpbT;
  176.             lprtfs->cbMax = lprtfs->cb + (cb * 2);
  177.         }
  178.         else
  179.             return (DWORD)E_FAIL;
  180.     }
  181.  
  182.     memcpy (lprtfs->lpb + lprtfs->cb, lpb, (UINT)cb);
  183.     lprtfs->cb += cb;
  184.     *lpcb = cb;
  185.  
  186.     return (DWORD)NOERROR;
  187. }
  188.  
  189.  
  190. DWORD CALLBACK
  191. ReadRTFFromBuffer (DWORD dwCookie, LPBYTE lpb, LONG cb, LONG FAR * lpcb)
  192. {
  193.     LPRTFS lprtfs = (LPRTFS)dwCookie;
  194.  
  195.     cb = min (lprtfs->cb + cb, lprtfs->cbMax) - lprtfs->cb;
  196.     memcpy (lpb, lprtfs->lpb + lprtfs->cb, (UINT)cb);
  197.     lprtfs->cb += cb;
  198.     *lpcb = cb;
  199.  
  200.     return NOERROR;
  201. }
  202.  
  203. /*
  204.  *  Store listbox support -----------------------------------------------------
  205.  */
  206. VOID
  207. FillStoresListbox (LPSCD lpscd, HWND hdlg)
  208. {
  209.     HRESULT hr = hrSuccess;
  210.     CHAR rgch[MAX_PATH] = {0};
  211.     HWND hctrl = GetDlgItem (hdlg, ID_Store);
  212.     LPMAPISESSION lpsess;
  213.     LPMAPITABLE lptbl = NULL;
  214.     LPSRowSet lprws = NULL;
  215.     UINT iDef;
  216.     UINT irw;
  217.     
  218.     /*  Logon to the profile for access to the stores table */
  219.     
  220.     if (!(lpsess = lpscd->lpsess))
  221.     {
  222.         hr = MAPILogonEx ((ULONG)GetParent (hdlg),
  223.                     lpscd->lpval[ipProfile].Value.lpszA,
  224.                     NULL,
  225.                     MAPI_NEW_SESSION            |
  226.                          MAPI_EXPLICIT_PROFILE  |
  227.                          MAPI_EXTENDED          |
  228.                          MAPI_NO_MAIL           |
  229.                          MAPI_PASSWORD_UI       |
  230.                          MAPI_TIMEOUT_SHORT,
  231.                     &lpsess);
  232.     }
  233.     if (HR_FAILED (hr))
  234.         goto ret;
  235.  
  236.     hr = lpsess->lpVtbl->GetMsgStoresTable (lpsess, 0, &lptbl);
  237.     if (HR_FAILED (hr))
  238.         goto ret;
  239.  
  240.     hr = lptbl->lpVtbl->SetColumns (lptbl, (LPSPropTagArray)&sptStoTbl, 0);
  241.     if (HR_FAILED (hr))
  242.         goto ret;
  243.  
  244.     while (TRUE)
  245.     {
  246.         hr = lptbl->lpVtbl->QueryRows (lptbl, 64, 0, &lprws);
  247.         if (HR_FAILED (hr))
  248.             goto ret;
  249.  
  250.         if (lprws->cRows == 0)
  251.             break;
  252.  
  253.         for (irw = 0; irw < lprws->cRows; irw++)
  254.         {
  255.             ComboBox_AddString (hctrl,
  256.                 lprws->aRow[irw].lpProps[ipMsgSto].Value.lpszA);
  257.  
  258.             if (lprws->aRow[irw].lpProps[ipDefSto].Value.b)
  259.                 lstrcpy (rgch, lprws->aRow[irw].lpProps[ipMsgSto].Value.lpszA);
  260.                     
  261.             /*  Free the row data */
  262.             
  263.             (*lpscd->lpfnFree) (lprws->aRow[irw].lpProps);
  264.         }
  265.         
  266.         (*lpscd->lpfnFree) (lprws);
  267.         lprws = NULL;
  268.     }
  269.     (*lpscd->lpfnFree) (lprws);
  270.     lprws = NULL;
  271.  
  272.     iDef = ComboBox_FindString (hctrl, -1, rgch);
  273.     ComboBox_SetCurSel (hctrl, iDef == CB_ERR ? 0 : iDef);
  274.     
  275. ret:
  276.     
  277.     lpscd->lpsess = lpsess;
  278.     UlRelease (lptbl);
  279.     return;
  280. }
  281.  
  282.  
  283. SCODE
  284. ScPickResponseRecip (HWND hdlg, LPFILTER lpfltr)
  285. {
  286.     HRESULT hr;
  287.     SCODE sc = S_OK;
  288.     ADRPARM adrparm = {0};
  289.     CHAR rgch[cchNameMax];
  290.     LPADRBOOK lpab = NULL;
  291.     LPADRLIST lpadr = NULL;
  292.     LPSCD lpscd = lpfltr->lpscd;
  293.     LPSPropValue lpval = lpfltr->lpval;
  294.     LPSPropValue lpvalT;
  295.     LPTSTR rglpszDestTitles[] = { "To" };
  296.     ULONG rgulDestComps[] = { MAPI_TO };
  297.     UINT ip;
  298.  
  299.     hr = lpscd->lpsess->lpVtbl->OpenAddressBook (lpscd->lpsess,
  300.                                         0,
  301.                                         NULL,
  302.                                         AB_NO_DIALOG,
  303.                                         &lpab);
  304.     if (!HR_FAILED (hr))
  305.     {
  306.         /*  Iniitalize the adrparm structure */
  307.  
  308.         wsprintf (rgch, "Auto-Forward Recipient for '%s'", lpfltr->rgch);
  309.  
  310.         adrparm.ulFlags = ADDRESS_ONE | DIALOG_MODAL | AB_RESOLVE;
  311.         adrparm.lpszCaption = rgch;
  312.         adrparm.lpszNewEntryTitle = rgch;
  313.         adrparm.lpszDestWellsTitle = "Auto-Forward Recipient";
  314.         adrparm.lppszDestTitles = rglpszDestTitles;
  315.         adrparm.lpulDestComps = rgulDestComps;
  316.         adrparm.lpContRestriction = NULL;
  317.         hr = lpab->lpVtbl->Address (lpab, (ULONG FAR*)&hdlg, &adrparm, &lpadr);
  318.         if (!HR_FAILED (hr))
  319.         {
  320.             /*  Zip though and copy out the display name and the
  321.              *  entryid
  322.              */
  323.             lpvalT = lpadr->aEntries[0].rgPropVals;
  324.             for (ip = 0; ip < lpadr->aEntries[0].cValues; lpvalT++, ip++)
  325.             {
  326.                 if (lpvalT->ulPropTag == PR_DISPLAY_NAME)
  327.                 {
  328.                     sc = (*lpscd->lpfnAllocMore) (lstrlen (lpvalT->Value.LPSZ) + 1,
  329.                         lpval, &(lpval[ipRLFwdRecip].Value.lpszA));
  330.                     if (FAILED (sc))
  331.                         goto ret;
  332.  
  333.                     lpval[ipRLFwdRecip].ulPropTag = PR_RULE_FORWARD_RECIP;
  334.                     lstrcpy (lpval[ipRLFwdRecip].Value.lpszA,
  335.                         lpvalT->Value.lpszA);
  336.                 }
  337.                 else if (lpvalT->ulPropTag == PR_ENTRYID)
  338.                 {
  339.                     sc = (*lpscd->lpfnAllocMore) (lpvalT->Value.bin.cb, lpval,
  340.                         &(lpval[ipRLFwdEid].Value.bin.lpb));
  341.                     if (FAILED (sc))
  342.                         goto ret;
  343.  
  344.                     lpval[ipRLFwdEid].ulPropTag = PR_RULE_FORWARD_RECIP_ENTRYID;
  345.                     lpval[ipRLFwdEid].Value.bin.cb = lpvalT->Value.bin.cb;
  346.                     memcpy (lpval[ipRLFwdEid].Value.bin.lpb,
  347.                         lpvalT->Value.bin.lpb,
  348.                         lpvalT->Value.bin.cb);
  349.                 }
  350.             }
  351. ret:
  352.             (*lpscd->lpfnFree) (lpadr->aEntries[0].rgPropVals);
  353.             (*lpscd->lpfnFree) (lpadr);
  354.             hr = ResultFromScode (sc);
  355.         }
  356.         UlRelease (lpab);
  357.     }
  358.  
  359.     DebugTraceResult (ScPickResponseRecip(), hr);
  360.     return GetScode (hr);
  361. }
  362.  
  363.  
  364. SCODE
  365. ScResolveResponseRecip (HWND hdlg, LPFILTER lpfltr, LPTSTR lpszRecip)
  366. {
  367.     SCODE sc = S_OK;
  368.     HRESULT hr;
  369.     CHAR rgch[cchNameMax];
  370.     CHAR rgch2[256];
  371.     BOOL fCtl3d = FALSE;
  372.     LPADRBOOK lpab = NULL;
  373.     LPADRLIST lpadr = NULL;
  374.     LPSCD lpscd = lpfltr->lpscd;
  375.     LPSPropValue lpval = lpfltr->lpval;
  376.     LPSPropValue lpvalT;
  377.     UINT ip;
  378.  
  379.     hr = lpscd->lpsess->lpVtbl->OpenAddressBook (lpscd->lpsess,
  380.                                         0,
  381.                                         NULL,
  382.                                         AB_NO_DIALOG,
  383.                                         &lpab);
  384.     if (HR_FAILED (hr))
  385.         goto ret;
  386.  
  387.     if (FAILED (sc = (*lpscd->lpfnAlloc) (sizeof(SPropValue), &lpvalT)) ||
  388.         FAILED (sc = (*lpscd->lpfnAlloc) (CbNewADRLIST(1), &lpadr)))
  389.     {
  390.         hr = ResultFromScode (sc);
  391.         goto ret;
  392.     }
  393.  
  394.     lpadr->cEntries = 1;
  395.     lpadr->aEntries[0].cValues = 1;
  396.     lpadr->aEntries[0].rgPropVals = lpvalT;
  397.     lpvalT[0].ulPropTag = PR_DISPLAY_NAME;
  398.     lpvalT[0].Value.LPSZ = lpszRecip;
  399.     wsprintf (rgch, "Auto-Forward Recipient for '%s'", lpszRecip);
  400.     hr = lpab->lpVtbl->ResolveName (lpab, 0, 0, rgch, lpadr);
  401.     if (HR_FAILED (hr))
  402.     {
  403.         wsprintf (rgch2,
  404.             "Recipient '%s' for auto-forward filter '%s' is ambiguous.\n"
  405.             "Please select a recipient from the Check Names dialog.",
  406.             lpszRecip, lpfltr->rgch);
  407.             
  408.         if (CTL3D_GetVer(lpCtl3D) >= 0x220 && !CTL3D_IsAutoSubclass(lpCtl3D))
  409.             CTL3D_AutoSubclass (lpCtl3D, lpscd->hinst, &fCtl3d);
  410.         MessageBox (hdlg, rgch2, rgch, MB_TASKMODAL | MB_OK | MB_ICONINFORMATION);
  411.         CTL3D_CeaseAutoSubclass(lpCtl3D, fCtl3d);
  412.         
  413.         hr = lpab->lpVtbl->ResolveName (lpab, (ULONG)hdlg, MAPI_DIALOG, rgch, lpadr);
  414.     }
  415.  
  416.     if (!HR_FAILED (hr))
  417.     {
  418.         /*  Zip though and copy out the display name and the
  419.          *  entryid
  420.          */
  421.         lpvalT = lpadr->aEntries[0].rgPropVals;
  422.         for (ip = 0; ip < lpadr->aEntries[0].cValues; lpvalT++, ip++)
  423.         {
  424.             if (lpvalT->ulPropTag == PR_DISPLAY_NAME)
  425.             {
  426.                 sc = (*lpscd->lpfnAllocMore) (lstrlen (lpvalT->Value.LPSZ) + 1,
  427.                     lpval, &(lpval[ipRLFwdRecip].Value.lpszA));
  428.                 if (FAILED (sc))
  429.                 {
  430.                     hr = ResultFromScode (sc);
  431.                     goto ret;
  432.                 }
  433.  
  434.                 lpval[ipRLFwdRecip].ulPropTag = PR_RULE_FORWARD_RECIP;
  435.                 lstrcpy (lpval[ipRLFwdRecip].Value.lpszA,
  436.                          lpvalT->Value.lpszA);
  437.             }
  438.             else if (lpvalT->ulPropTag == PR_ENTRYID)
  439.             {
  440.                 sc = (*lpscd->lpfnAllocMore) (lpvalT->Value.bin.cb, lpval,
  441.                     &(lpval[ipRLFwdEid].Value.bin.lpb));
  442.                 if (FAILED (sc))
  443.                 {
  444.                     hr = ResultFromScode (sc);
  445.                     goto ret;
  446.                 }
  447.  
  448.                 lpval[ipRLFwdEid].ulPropTag = PR_RULE_FORWARD_RECIP_ENTRYID;
  449.                 lpval[ipRLFwdEid].Value.bin.cb = lpvalT->Value.bin.cb;
  450.                 memcpy (lpval[ipRLFwdEid].Value.bin.lpb,
  451.                         lpvalT->Value.bin.lpb,
  452.                         lpvalT->Value.bin.cb);
  453.             }
  454.         }
  455.     }
  456.  
  457. ret:
  458.     
  459.     if (lpadr)
  460.     {
  461.         (*lpscd->lpfnFree) (lpadr->aEntries[0].rgPropVals);
  462.         (*lpscd->lpfnFree) (lpadr);
  463.     }
  464.  
  465.     UlRelease (lpab);
  466.     DebugTraceResult (ScResolveResponseRecip(), hr);
  467.     return GetScode (hr);
  468. }
  469.  
  470.  
  471. /*
  472.  *  Filter Description Property Sheet Page ------------------------------------
  473.  *  
  474.  *  The Filter description page of the configuration property sheets
  475.  *  provides access to the many flags that are available to the SMH
  476.  *  service.
  477.  */
  478.  
  479. /*
  480.  *  FilterDescriptionPage_INITDAILOG()
  481.  *
  482.  *  Purpose:
  483.  *
  484.  *      Handles the WM_INITDIALOG message for the filter description dialog
  485.  */
  486. BOOL
  487. FilterDescriptionPage_INITDIALOG (HWND hdlg, HWND hwndFocus, LPARAM lParam)
  488. {
  489.     LPFILTER lpfltr = (LPFILTER)(((PROPSHEETPAGE *)lParam)->lParam);
  490.     LPSPropValue lpval;
  491.     HWND hctrl;
  492.     UINT iSto;
  493.  
  494.     /*  Setup the dialog */
  495.  
  496.     CTL3D_Subclass (lpCtl3D, hdlg, CTL3D_ALL);
  497.     SetWindowLong (hdlg, DWL_USER, ((PROPSHEETPAGE *)lParam)->lParam);
  498.  
  499.     Edit_LimitText (GetDlgItem (hdlg, ID_Name), cchNameMax);
  500.  
  501.     if (lpval = lpfltr->lpval)
  502.     {
  503.         /*  Fill in the display name */
  504.         
  505.         Assert (!IsBadReadPtr (lpval, sizeof(SPropValue) * cpRLMax));
  506.         if (lpval[ipRLDisp].ulPropTag == PR_DISPLAY_NAME)
  507.             Edit_SetText (GetDlgItem (hdlg, ID_Name),
  508.                     lpval[ipRLDisp].Value.LPSZ);
  509.  
  510.         /*  Check the corresponding rule type.  Note that the rule type
  511.          *  enumeration follows the same order as the corresponding control
  512.          *  ID's such that calculating the rule type is a simple addition to
  513.          *  the base control ID.
  514.          */
  515.         if (lpval[ipRLType].ulPropTag == PR_RULE_TYPE)
  516.             CheckRadioButton (hdlg,
  517.                     ID_AnyRecip,
  518.                     ID_ToRecip,
  519.                     (UINT)(ID_AnyRecip + lpval[ipRLType].Value.l - 1));
  520.             
  521.         /*  Setup the rule data */
  522.         
  523.         if (lpval[ipRLData].ulPropTag == PR_RULE_DATA)
  524.             Edit_SetText (GetDlgItem (hdlg, ID_Value),
  525.                     lpval[ipRLData].Value.bin.lpb);
  526.  
  527.         /*  Setup the message store display name.  Note that an empty or
  528.          *  missing value here implies uses the default store.
  529.          */
  530.         FillStoresListbox (lpfltr->lpscd, hdlg);
  531.         if (lpval[ipRLStore].ulPropTag == PR_RULE_STORE_DISPLAY_NAME)
  532.         {
  533.             hctrl = GetDlgItem (hdlg, ID_Store);
  534.             iSto = ComboBox_FindString (hctrl, -1, lpval[ipRLStore].Value.lpszA);
  535.             ComboBox_SetCurSel (hctrl, iSto == CB_ERR ? 0 : iSto);
  536.         }
  537.  
  538.         /*  Setup the target folder path */
  539.         
  540.         if (lpval[ipRLPath].ulPropTag == PR_RULE_TARGET_PATH)
  541.             Edit_SetText (GetDlgItem (hdlg, ID_Folder),
  542.                     lpval[ipRLPath].Value.LPSZ);
  543.  
  544.         /*  Check the boxes indicated by the rule flags */
  545.         
  546.         if (lpval[ipRLFlags].ulPropTag == PR_RULE_FLAGS)
  547.         {
  548.             CheckDlgButton (hdlg, ID_NotMatch,
  549.                     !!(lpval[ipRLFlags].Value.l & RULE_NOT));
  550.             CheckDlgButton (hdlg, ID_ArchTarg,
  551.                     !!(lpval[ipRLFlags].Value.l & RULE_ARCHIVED));
  552.             CheckDlgButton (hdlg, ID_ArchTargYr,
  553.                     !!(lpval[ipRLFlags].Value.l & RULE_ARCHIVED_BY_YEAR));
  554.             EnableWindow (GetDlgItem (hdlg, ID_ArchTargYr),
  555.                     !!(lpval[ipRLFlags].Value.l & RULE_ARCHIVED));
  556.  
  557.             if (lpval[ipRLFlags].Value.l & RULE_DELETE)
  558.             {
  559.                 CheckRadioButton (hdlg, ID_DeleteMsg, ID_FilterMsg, ID_DeleteMsg);
  560.                 EnableWindow (GetDlgItem (hdlg, ID_ArchTarg), FALSE);
  561.                 EnableWindow (GetDlgItem (hdlg, ID_ArchTargYr), FALSE);
  562.                 EnableWindow (GetDlgItem (hdlg, ID_Folder), FALSE);
  563.                 EnableWindow (GetDlgItem (hdlg, ID_ReplyFwd), FALSE);
  564.                 EnableWindow (GetDlgItem (hdlg, ID_Store), FALSE);
  565.                 EnableWindow (GetDlgItem (hdlg, ID_Txt3), FALSE);
  566.                 EnableWindow (GetDlgItem (hdlg, ID_Txt4), FALSE);
  567.             }
  568.             else if (lpval[ipRLFlags].Value.l & RULE_NO_MOVE)
  569.                 CheckRadioButton (hdlg, ID_DeleteMsg, ID_FilterMsg, ID_LeaveMsg);
  570.             else
  571.                 CheckRadioButton (hdlg, ID_DeleteMsg, ID_FilterMsg, ID_FilterMsg);
  572.         }
  573.         else
  574.         {
  575.             Button_Enable (GetDlgItem (hdlg, ID_ArchTargYr), FALSE);
  576.             CheckRadioButton (hdlg, ID_FilterMsg, ID_DeleteMsg, ID_FilterMsg);
  577.             lpval[ipRLFlags].ulPropTag = PR_RULE_FLAGS;
  578.             lpval[ipRLFlags].Value.l = 0;
  579.         }
  580.     }
  581.     
  582.     return TRUE;
  583. }
  584.  
  585. /*
  586.  *  FilterDescriptionPage_NOTIFY()
  587.  *
  588.  *  Purpose:
  589.  *
  590.  *      Handles the WM_NOTIFY message for the filter description dialog.
  591.  *      On PSN_APPLY, SMHFlags is recomputed from the checkbox states.
  592.  */
  593. BOOL
  594. FilterDescriptionPage_NOTIFY (HWND hdlg, UINT id, NMHDR FAR * lpnmhdr)
  595. {
  596.     SCODE sc;
  597.     HRESULT hr;
  598.     HWND hctrl;
  599.     LPFILTER lpfltr = (LPFILTER)GetWindowLong (hdlg, DWL_USER);
  600.     LPSCD lpscd = lpfltr->lpscd;
  601.     LPSPropValue lpval = lpfltr->lpval;
  602.     UINT cb;
  603.     UINT i;
  604.  
  605.     switch (lpnmhdr->code)
  606.     {
  607.       case PSN_KILLACTIVE:
  608.         if (IsDlgButtonChecked (hdlg, ID_FilterMsg) &&
  609.             Edit_GetTextLength (GetDlgItem(hdlg, ID_Folder)) == 0)
  610.         {
  611.             MessageBox(hdlg, "You have to enter folder name", 
  612.                         "Sample Spooler Hook", 
  613.                         MB_TASKMODAL | MB_OK | MB_ICONSTOP);
  614.             SetWindowLong(hdlg, DWL_MSGRESULT, TRUE);
  615.             return TRUE;
  616.         }  
  617.         break;
  618.  
  619.       case PSN_RESET:
  620.       case PSN_SETACTIVE:
  621.       default:
  622.  
  623.         break;
  624.  
  625.       case PSN_APPLY:
  626.                 
  627.         /*  Turn off any flags we may be setting down the road */
  628.  
  629.         lpval[ipRLFlags].Value.l &= ~(RULE_ARCHIVED |
  630.                                       RULE_ARCHIVED_BY_YEAR |
  631.                                       RULE_NOT |
  632.                                       RULE_DELETE |
  633.                                       RULE_NO_MOVE);
  634.  
  635.         /*  Get the rule name */
  636.  
  637.         hctrl = GetDlgItem (hdlg, ID_Name);
  638.         cb = Edit_GetTextLength (hctrl) + 1;
  639.         if(cb != 1)
  640.         {
  641.             Edit_GetText (hctrl, lpfltr->rgch, cb);
  642.  
  643.             lpval[ipRLDisp].ulPropTag = PR_DISPLAY_NAME;
  644.             lpval[ipRLDisp].Value.LPSZ = lpfltr->rgch;
  645.         }
  646.  
  647.         /*  Rule type */
  648.  
  649.         lpval[ipRLType].ulPropTag = PR_RULE_TYPE;
  650.         for (i = RL_ANY_RECIP; i < RL_TYPE_MAX; i++)
  651.         {
  652.             if (IsDlgButtonChecked (hdlg, ID_AnyRecip + i - 1))
  653.             {   
  654.                 lpval[ipRLType].Value.l = i;
  655.                 break;
  656.             }
  657.         }
  658.  
  659.         /*  Rule data */
  660.  
  661.         hctrl = GetDlgItem (hdlg, ID_Value);
  662.         cb = Edit_GetTextLength (hctrl) + 1;
  663.         sc = (*lpscd->lpfnAllocMore) (cb, lpval, &lpval[ipRLData].Value.bin.lpb);
  664.         if (FAILED (sc))
  665.             goto ret;
  666.  
  667.         lpval[ipRLData].ulPropTag = PR_RULE_DATA;
  668.         lpval[ipRLData].Value.bin.cb = (ULONG)cb;
  669.         Edit_GetText (hctrl, lpval[ipRLData].Value.bin.lpb, cb);
  670.  
  671.         /*  Target store EID */
  672.  
  673.         lpval[ipRLSEid].ulPropTag = PR_NULL;
  674.  
  675.         /*  Target store */
  676.  
  677.         hctrl = GetDlgItem (hdlg, ID_Store);
  678.         cb = ComboBox_GetTextLength (hctrl) + 1;
  679.         sc = (*lpscd->lpfnAllocMore) (cb, lpval, &(lpval[ipRLStore].Value.lpszA));
  680.         if (FAILED (sc))
  681.             goto ret;
  682.  
  683.         lpval[ipRLStore].ulPropTag = PR_RULE_STORE_DISPLAY_NAME;
  684.         ComboBox_GetText (hctrl, lpval[ipRLStore].Value.LPSZ, cb);
  685.  
  686.         /*  Target folder EID */
  687.  
  688.         lpval[ipRLEid].ulPropTag = PR_NULL;
  689.  
  690.         /*  Target folder */
  691.  
  692.         hctrl = GetDlgItem (hdlg, ID_Folder);
  693.         cb = Edit_GetTextLength (hctrl) + 1;
  694.         sc = (*lpscd->lpfnAllocMore) (cb, lpval, &(lpval[ipRLPath].Value.lpszA));
  695.         if (FAILED (sc))
  696.             goto ret;
  697.  
  698.         lpval[ipRLPath].ulPropTag = PR_RULE_TARGET_PATH;
  699.         Edit_GetText (hctrl, lpval[ipRLPath].Value.LPSZ, cb);
  700.  
  701.         /*  Flags */
  702.  
  703.         if (IsDlgButtonChecked (hdlg, ID_ArchTarg))
  704.         {
  705.             lpval[ipRLFlags].Value.l |= RULE_ARCHIVED;
  706.             if (IsDlgButtonChecked (hdlg, ID_ArchTargYr))
  707.                 lpval[ipRLFlags].Value.l |= RULE_ARCHIVED_BY_YEAR;
  708.         }
  709.         if (IsDlgButtonChecked (hdlg, ID_NotMatch))
  710.             lpval[ipRLFlags].Value.l |= RULE_NOT;
  711.         if (IsDlgButtonChecked (hdlg, ID_DeleteMsg))
  712.             lpval[ipRLFlags].Value.l |= RULE_DELETE;
  713.         if (IsDlgButtonChecked (hdlg, ID_LeaveMsg))
  714.             lpval[ipRLFlags].Value.l |= RULE_NO_MOVE;
  715.  
  716.         /*  Delete the folder and store entryid's properties */
  717.  
  718.         lpfltr->lpsec->lpVtbl->DeleteProps (lpfltr->lpsec,
  719.                                     (LPSPropTagArray)&sptDelete,
  720.                                     NULL);
  721.             
  722.         /*  Set the values and save changes on the profile section */
  723.  
  724.         hr = lpfltr->lpsec->lpVtbl->SetProps (lpfltr->lpsec,
  725.                                             cpRLMax,
  726.                                             lpval,
  727.                                             NULL);
  728.         if (FAILED (sc = GetScode (hr)))
  729.             goto ret;
  730.  
  731.         hr = lpfltr->lpsec->lpVtbl->SaveChanges (lpfltr->lpsec, KEEP_OPEN_READWRITE);
  732.         if (FAILED (sc = GetScode (hr)))
  733.             goto ret;
  734.  
  735. ret:        
  736.         /*  Set error code into filter */
  737.     
  738.         lpfltr->sc = sc;
  739.         return !FAILED (sc);
  740.  
  741.       case PSN_HELP:
  742.  
  743.         return TRUE;
  744.     }
  745.  
  746.     return FALSE;
  747. }
  748.  
  749.  
  750. /*
  751.  *  FilterDescriptionPage_COMMAND()
  752.  *
  753.  *  Purpose:
  754.  *
  755.  *      Handles the WM_COMMAND message for the filter description dialog
  756.  *
  757.  *      IMPORTANT: This function relies on the dialog control IDs as
  758.  *      defined in _SMH.RH.  The yearly archive checkboxes must have an
  759.  *      ID that is one greater than the companion checkbox.
  760.  */
  761. BOOL
  762. FilterDescriptionPage_COMMAND (HWND hdlg, UINT id, HWND hwndCtl, UINT codeNotify)
  763. {
  764.     BOOL fCheck;
  765.     
  766.     switch (id)
  767.     {
  768.       case ID_LeaveMsg:
  769.       case ID_FilterMsg:
  770.       case ID_DeleteMsg:
  771.  
  772.         /*  Enable windows based on the check state of the ID_FilterMsg */
  773.         
  774.         fCheck = IsDlgButtonChecked (hdlg, ID_FilterMsg);
  775.         EnableWindow (GetDlgItem (hdlg, ID_ArchTarg), fCheck);
  776.         EnableWindow (GetDlgItem (hdlg, ID_ArchTargYr),
  777.             fCheck && IsDlgButtonChecked (hdlg, ID_ArchTarg));
  778.         EnableWindow (GetDlgItem (hdlg, ID_Folder), fCheck);
  779.         EnableWindow (GetDlgItem (hdlg, ID_Store), fCheck);
  780.         EnableWindow (GetDlgItem (hdlg, ID_Txt3), fCheck);
  781.         EnableWindow (GetDlgItem (hdlg, ID_Txt4), fCheck);
  782.         break;
  783.  
  784.       case ID_ArchTarg:
  785.  
  786.         /*  Enable yearly sub-archive button when the archiving is enabled */
  787.         
  788.         EnableWindow (GetDlgItem (hdlg, ID_ArchTargYr),
  789.             IsDlgButtonChecked (hdlg, ID_ArchTarg));
  790.         
  791.         break;
  792.  
  793.       default:
  794.  
  795.         return TRUE;
  796.     }
  797.     
  798.     PropSheet_Changed (GetParent (hdlg), hdlg);
  799.     return TRUE;
  800. }
  801.  
  802.  
  803. /*
  804.  *  FilterDescriptionPageProc()
  805.  *
  806.  *  Purpose:
  807.  *
  808.  *      Dispatches window messages to the proper function for processing
  809.  */
  810. BOOL CALLBACK
  811. FilterDescriptionPageProc (HWND hdlg, UINT msg, WPARAM wParam, LPARAM lParam)
  812. {
  813.     switch (msg)
  814.     {
  815.       case WM_INITDIALOG:
  816.  
  817.         FHandleWm (FilterDescriptionPage, hdlg, INITDIALOG, wParam, lParam);
  818.         return TRUE;
  819.  
  820.       case WM_COMMAND:
  821.  
  822.         FHandleWm (FilterDescriptionPage, hdlg, COMMAND, wParam, lParam);
  823.         break;
  824.  
  825.       case WM_NOTIFY:
  826.  
  827.         return FHandleWm (FilterDescriptionPage, hdlg, NOTIFY, wParam, lParam);
  828.     }
  829.  
  830.     return FALSE;
  831. }
  832.  
  833.  
  834. BOOL
  835. ResponsePage_INITDIALOG (HWND hdlg, HWND hwndFocus, LPARAM lParam)
  836. {
  837.     EDITSTREAM es = {0};
  838.     LPFILTER lpfltr = (LPFILTER)(((PROPSHEETPAGE *)lParam)->lParam);
  839.     LPFORMATBAR lpfb;
  840.     LPSCD lpscd = lpfltr->lpscd;
  841.     LPSPropValue lpval;
  842.     RTFS rtfs = {0};
  843.     
  844.     /*  Set the user data component to point to the SCD structure */
  845.     
  846.     CTL3D_Subclass (lpCtl3D, hdlg, CTL3D_ALL);
  847.     SetWindowLong (hdlg, DWL_USER, ((PROPSHEETPAGE *)lParam)->lParam);
  848.  
  849.     /*  Setup the toolbar for the annotation */
  850.  
  851.     if (!FAILED (ScCreateToolbar (lpscd, hdlg, ID_Annotation, FALSE, &lpfb)) &&
  852.         !FAILED (ScNewRicheditCallback (lpfb,
  853.                                 lpscd->lpfnAlloc,
  854.                                 lpscd->lpfnAllocMore,
  855.                                 lpscd->lpfnFree,
  856.                                 &lpfb->lpreoc)))
  857.     {
  858.         SendMessage (GetDlgItem (hdlg, ID_Annotation),
  859.             EM_SETOLECALLBACK,
  860.             0,
  861.             (LPARAM)lpfb->lpreoc);
  862.     }
  863.  
  864.     /*  Init the dialog fields */
  865.  
  866.     if (lpval = lpfltr->lpval)
  867.     {
  868.         /*  Fill in the display name */
  869.         
  870.         Assert (!IsBadReadPtr (lpval, sizeof(SPropValue) * cpRLMax));
  871.  
  872.         CheckDlgButton (hdlg, ID_ReplyFwd,
  873.             !!(lpval[ipRLFlags].Value.l & RULE_AUTO_RESPONSE));
  874.         
  875.         /*  Check the boxes indicated by the rule flags */
  876.         
  877.         if (!(lpval[ipRLFlags].Value.l & RULE_AUTO_FORWARD))
  878.         {
  879.             CheckRadioButton (hdlg, ID_Reply, ID_Forward, ID_Reply);
  880.             EnableWindow (GetDlgItem (hdlg, ID_Recip), FALSE);
  881.             EnableWindow (GetDlgItem (hdlg, ID_PickRecip), FALSE);
  882.         }
  883.         else
  884.             CheckRadioButton (hdlg, ID_Reply, ID_Forward, ID_Forward);
  885.  
  886.         /*  Setup the fowarding recipient */
  887.         
  888.         if (lpval[ipRLFwdRecip].ulPropTag == PR_RULE_FORWARD_RECIP)
  889.             Edit_SetText (GetDlgItem (hdlg, ID_Recip),
  890.                     lpval[ipRLFwdRecip].Value.LPSZ);
  891.  
  892.         /*  How 'bout the RTF */
  893.         
  894.         if (lpval[ipRLRepFwdRTF].ulPropTag == PR_RULE_REP_FWD_RTF)
  895.         {
  896.             rtfs.cbMax = lpval[ipRLRepFwdRTF].Value.bin.cb;
  897.             rtfs.lpb = lpval[ipRLRepFwdRTF].Value.bin.lpb;
  898.             es.pfnCallback = ReadRTFFromBuffer;
  899.             es.dwCookie = (DWORD)&rtfs;
  900.             SendMessage (GetDlgItem (hdlg, ID_Annotation),
  901.                 EM_STREAMIN,
  902.                 SF_RTF | SFF_SELECTION | SFF_PLAINRTF,
  903.                 (LPARAM)&es);
  904.         }
  905.         else if (lpval[ipRLRepFwd].ulPropTag == PR_RULE_REP_FWD_TEXT)
  906.             Edit_SetText (GetDlgItem (hdlg, ID_Annotation),
  907.                 lpval[ipRLRepFwd].Value.LPSZ);
  908.     }
  909.     
  910.     return TRUE;
  911. }
  912.  
  913.  
  914. BOOL
  915. ResponsePage_NOTIFY (HWND hdlg, UINT id, NMHDR FAR * lpnmhdr)
  916. {
  917.     SCODE sc = S_OK;
  918.     HRESULT hr;
  919.     CHAR rgch[cchNameMax];
  920.     EDITSTREAM es = {0};
  921.     HWND hctrl;
  922.     LPFILTER lpfltr = (LPFILTER)GetWindowLong (hdlg, DWL_USER);
  923.     LPSCD lpscd = lpfltr->lpscd;
  924.     LPSPropValue lpval = lpfltr->lpval;
  925.     RTFS rtfs = {0};
  926.     SizedSPropTagArray (1, spt) = {1, { PR_RULE_FORWARD_RECIP_ENTRYID }};
  927.     UINT cb;
  928.     
  929.     switch (lpnmhdr->code)
  930.     {
  931.       case PSN_KILLACTIVE:
  932.       case PSN_RESET:
  933.       case PSN_SETACTIVE:
  934.       default:
  935.  
  936.         break;
  937.  
  938.       case PSN_APPLY:
  939.  
  940.         if (lpval = lpfltr->lpval)
  941.         {
  942.             /*  Turn off any flags we may be setting down the road */
  943.  
  944.             lpval[ipRLFlags].Value.l &= ~(RULE_AUTO_RESPONSE |
  945.                                           RULE_AUTO_APPEND_ORIG |
  946.                                           RULE_AUTO_REPLY |
  947.                                           RULE_AUTO_FORWARD);
  948.             
  949.             /*  See if we are enabled */
  950.             
  951.             if (IsDlgButtonChecked (hdlg, ID_ReplyFwd))
  952.                 lpval[ipRLFlags].Value.l |= RULE_AUTO_RESPONSE;
  953.  
  954.             /*  Grab the annotation in both plain text and RTF */
  955.  
  956.             hctrl = GetDlgItem (hdlg, ID_Annotation);
  957.             cb = Edit_GetTextLength (hctrl) + 1;
  958.             sc = (*lpscd->lpfnAllocMore) (cb, lpval, &lpval[ipRLRepFwd].Value.LPSZ);
  959.             if (FAILED (sc))
  960.                 goto ret;
  961.         
  962.             lpval[ipRLRepFwd].ulPropTag = PR_RULE_REP_FWD_TEXT;
  963.             Edit_GetText (hctrl, lpval[ipRLRepFwd].Value.LPSZ, cb);
  964.  
  965.             rtfs.cb = 0;
  966.             rtfs.cbMax = 0;
  967.             rtfs.lpfnAlloc = lpscd->lpfnAlloc;
  968.             rtfs.lpfnFree = lpscd->lpfnFree;
  969.             es.pfnCallback = WriteRTFToBuffer;
  970.             es.dwCookie = (DWORD)&rtfs;
  971.             SendMessage (hctrl, EM_STREAMOUT, SF_RTF | SFF_PLAINRTF, (LPARAM)&es);
  972.             if (!es.dwError)
  973.             {
  974.                 /* make a copy of the RTF data for long term storage */
  975.  
  976.                 sc = (*lpscd->lpfnAllocMore) (rtfs.cb,
  977.                                 lpval,
  978.                                 &lpval[ipRLRepFwdRTF].Value.bin.lpb);
  979.                 if (!FAILED (sc))
  980.                 {
  981.                     lpval[ipRLRepFwdRTF].ulPropTag = PR_RULE_REP_FWD_RTF;
  982.                     lpval[ipRLRepFwdRTF].Value.bin.cb = rtfs.cb;
  983.                     memcpy (lpval[ipRLRepFwdRTF].Value.bin.lpb, rtfs.lpb, (UINT)rtfs.cb);
  984.                 }
  985.                 else
  986.                     lpval[ipRLRepFwdRTF].ulPropTag = PR_NULL;
  987.             }
  988.  
  989.             (*lpscd->lpfnFree) (rtfs.lpb);
  990.  
  991.             /*  Delete props that need to be recalc'd */
  992.             
  993.             lpval[ipRLFwdEid].ulPropTag = PR_NULL;
  994.             lpfltr->lpsec->lpVtbl->DeleteProps (lpfltr->lpsec,
  995.                 (LPSPropTagArray)&spt, NULL);
  996.             
  997.             /*  Grab the recipient information */
  998.  
  999.             hctrl = GetDlgItem (hdlg, ID_Recip);
  1000.             hctrl = GetDlgItem (hdlg, ID_Recip);
  1001.             cb = Edit_GetTextLength (hctrl) + 1;
  1002.             Edit_GetText (hctrl, rgch, cb);
  1003.  
  1004.             /*  See if what we have cached will work */
  1005.  
  1006.             if (IsDlgButtonChecked (hdlg, ID_ReplyFwd) &&
  1007.                 IsDlgButtonChecked (hdlg, ID_Forward))
  1008.             {
  1009.                 if ((lpval[ipRLFwdEid].ulPropTag != PR_RULE_FORWARD_RECIP_ENTRYID) ||
  1010.                     (lpval[ipRLFwdRecip].ulPropTag != PR_RULE_FORWARD_RECIP) ||
  1011.                     lstrcmp (lpval[ipRLFwdRecip].Value.lpszA, rgch))
  1012.                 {
  1013.                     /*  We do not have a resolved recipient */
  1014.  
  1015.                     (void) ScResolveResponseRecip (GetParent (hdlg), lpfltr, rgch);
  1016.                 }
  1017.             }
  1018.  
  1019.             /*  Set the response type */
  1020.  
  1021.             lpval[ipRLFlags].Value.l |= RULE_AUTO_APPEND_ORIG |
  1022.                 (IsDlgButtonChecked (hdlg, ID_Reply)
  1023.                      ? RULE_AUTO_REPLY
  1024.                      : RULE_AUTO_FORWARD);
  1025.  
  1026.             /*  Set the values and save changes on the profile section */
  1027.  
  1028.             hr = lpfltr->lpsec->lpVtbl->SetProps (lpfltr->lpsec,
  1029.                                             cpRLMax,
  1030.                                             lpval,
  1031.                                             NULL);
  1032.             if (FAILED (sc = GetScode (hr)))
  1033.                 goto ret;
  1034.  
  1035.             hr = lpfltr->lpsec->lpVtbl->SaveChanges (lpfltr->lpsec, KEEP_OPEN_READWRITE);
  1036.             if (FAILED (sc = GetScode (hr)))
  1037.                 goto ret;
  1038.         }
  1039. ret:
  1040.         lpfltr->sc = sc;
  1041.         return !FAILED(sc);
  1042.  
  1043.       case PSN_HELP:
  1044.  
  1045.         return TRUE;
  1046.     }
  1047.  
  1048.     return FALSE;
  1049. }
  1050.  
  1051.  
  1052. BOOL
  1053. ResponsePage_COMMAND (HWND hdlg, UINT id, HWND hwndCtl, UINT codeNotify)
  1054. {
  1055.     BOOL fCheck = FALSE;
  1056.     LPFILTER lpfltr = (LPFILTER)GetWindowLong (hdlg, DWL_USER);
  1057.  
  1058.     if (FDoRTFCommand (GetDlgItem (hdlg, ID_Frame), id, codeNotify))
  1059.         return TRUE;
  1060.     
  1061.     switch (id)
  1062.     {
  1063.       case ID_Forward:
  1064.         
  1065.         fCheck = TRUE;
  1066.  
  1067.         /*  Fall through */
  1068.         
  1069.       case ID_Reply:
  1070.  
  1071.         EnableWindow (GetDlgItem (hdlg, ID_Recip), fCheck);
  1072.         EnableWindow (GetDlgItem (hdlg, ID_PickRecip), fCheck);
  1073.         break;
  1074.  
  1075.       case ID_PickRecip:
  1076.  
  1077.         if (!FAILED (ScPickResponseRecip (GetParent (hdlg), lpfltr)))
  1078.         {
  1079.             Edit_SetText (GetDlgItem (hdlg, ID_Recip),
  1080.                     lpfltr->lpval[ipRLFwdRecip].Value.LPSZ);
  1081.         }
  1082.     }
  1083.  
  1084.     PropSheet_Changed (GetParent (hdlg), hdlg);
  1085.     return TRUE;
  1086. }
  1087.  
  1088.  
  1089. BOOL CALLBACK
  1090. ResponsePageProc (HWND hdlg, UINT msg, WPARAM wParam, LPARAM lParam)
  1091. {
  1092.     switch (msg)
  1093.     {
  1094.       case WM_INITDIALOG:
  1095.  
  1096.         FHandleWm (ResponsePage, hdlg, INITDIALOG, wParam, lParam);
  1097.         return TRUE;
  1098.  
  1099.       case WM_COMMAND:
  1100.  
  1101.         FHandleWm (ResponsePage, hdlg, COMMAND, wParam, lParam);
  1102.         break;
  1103.  
  1104.       case WM_NOTIFY:
  1105.  
  1106.         return FHandleWm (ResponsePage, hdlg, NOTIFY, wParam, lParam);
  1107.     }
  1108.  
  1109.     return FALSE;
  1110. }
  1111.  
  1112.  
  1113. BOOL
  1114. SoundsPage_INITDIALOG (HWND hdlg, HWND hwndFocus, LPARAM lParam)
  1115. {
  1116.     LPFILTER lpfltr = (LPFILTER)(((PROPSHEETPAGE *)lParam)->lParam);
  1117.     LPSPropValue lpval;
  1118.     UINT i;
  1119.     
  1120.     /*  Set the user data component to point to the SCD structure */
  1121.     
  1122.     CTL3D_Subclass (lpCtl3D, hdlg, CTL3D_ALL);
  1123.     SetWindowLong (hdlg, DWL_USER, ((PROPSHEETPAGE *)lParam)->lParam);
  1124.  
  1125.     /*  Init the dialog fields */
  1126.  
  1127.     if (lpval = lpfltr->lpval)
  1128.     {
  1129.         /*  See if we are enabled */
  1130.         
  1131.         CheckDlgButton (hdlg, ID_Sound,
  1132.             !!(lpval[ipRLFlags].Value.l & RULE_PLAY_SOUNDS));
  1133.         
  1134.         /*  Fill in the display name */
  1135.         
  1136.         Assert (!IsBadReadPtr (lpval, sizeof(SPropValue) * cpRLMax));
  1137.         Edit_SetText (GetDlgItem (hdlg, ID_Name), ((LPSCD)lParam)->rgch);
  1138.  
  1139.         /*  Setup the sound entries */
  1140.  
  1141.         for (i = 0; i < csndMax; i++)
  1142.         {
  1143.             if (lpval[ipRLLoPri + i].ulPropTag == sptRule.aulPropTag[ipRLLoPri + i])
  1144.             {
  1145.                 Edit_SetText (GetDlgItem (hdlg, ID_LoPri + i),
  1146.                     lpval[ipRLLoPri + i].Value.LPSZ);
  1147.             }
  1148.         }
  1149.     }
  1150.  
  1151.     return TRUE;
  1152. }
  1153.  
  1154.  
  1155. BOOL
  1156. SoundsPage_NOTIFY (HWND hdlg, UINT id, NMHDR FAR * lpnmhdr)
  1157. {
  1158.     SCODE sc = S_OK;
  1159.     HRESULT hr;
  1160.     HWND hctrl;
  1161.     LPFILTER lpfltr = (LPFILTER)GetWindowLong (hdlg, DWL_USER);
  1162.     LPSCD lpscd = lpfltr->lpscd;
  1163.     LPSPropValue lpval;
  1164.     UINT cb;
  1165.     UINT i;
  1166.     
  1167.     switch (lpnmhdr->code)
  1168.     {
  1169.       case PSN_KILLACTIVE:
  1170.       case PSN_RESET:
  1171.       case PSN_SETACTIVE:
  1172.       default:
  1173.  
  1174.         break;
  1175.  
  1176.       case PSN_APPLY:
  1177.  
  1178.         if (lpval = lpfltr->lpval)
  1179.         {
  1180.             /*  Turn off any flags we may be setting down the road */
  1181.  
  1182.             lpval[ipRLFlags].Value.l &= ~RULE_PLAY_SOUNDS;
  1183.  
  1184.             /*  See if we are enabled */
  1185.             
  1186.             if (IsDlgButtonChecked (hdlg, ID_Sound))
  1187.                 lpval[ipRLFlags].Value.l |= RULE_PLAY_SOUNDS;
  1188.             
  1189.             /*  Grab the sounds */
  1190.  
  1191.             for (i = 0; i < csndMax; i++)
  1192.             {
  1193.                 hctrl = GetDlgItem (hdlg, ID_LoPri + i);
  1194.                 cb = Edit_GetTextLength (hctrl) + 1;
  1195.                 sc = (*lpscd->lpfnAllocMore) (cb, lpval, &(lpval[ipRLLoPri + i].Value.lpszA));
  1196.                 if (FAILED (sc))
  1197.                     break;
  1198.  
  1199.                 lpval[ipRLLoPri + i].ulPropTag = sptRule.aulPropTag[ipRLLoPri + i];
  1200.                 Edit_GetText (hctrl, lpval[ipRLLoPri + i].Value.LPSZ, cb);
  1201.             }
  1202.             
  1203.             /*  Set the values and save changes on the profile section */
  1204.  
  1205.             hr = lpfltr->lpsec->lpVtbl->SetProps (lpfltr->lpsec,
  1206.                                             cpRLMax,
  1207.                                             lpval,
  1208.                                             NULL);
  1209.             if (!FAILED (sc = GetScode (hr)))
  1210.             {
  1211.                 hr = lpfltr->lpsec->lpVtbl->SaveChanges (lpfltr->lpsec, KEEP_OPEN_READWRITE);
  1212.                 sc = GetScode (hr);
  1213.             }
  1214.         }
  1215.  
  1216.         lpfltr->sc = sc;
  1217.         return !FAILED(sc);
  1218.  
  1219.       case PSN_HELP:
  1220.  
  1221.         return TRUE;
  1222.     }
  1223.  
  1224.     return FALSE;
  1225. }
  1226.  
  1227.  
  1228. BOOL
  1229. SoundsPage_COMMAND (HWND hdlg, UINT id, HWND hwndCtl, UINT codeNotify)
  1230. {
  1231.     PropSheet_Changed (GetParent (hdlg), hdlg);
  1232.     return TRUE;
  1233. }
  1234.  
  1235.  
  1236. BOOL CALLBACK
  1237. SoundsPageProc (HWND hdlg, UINT msg, WPARAM wParam, LPARAM lParam)
  1238. {
  1239.     switch (msg)
  1240.     {
  1241.       case WM_INITDIALOG:
  1242.  
  1243.         FHandleWm (SoundsPage, hdlg, INITDIALOG, wParam, lParam);
  1244.         return TRUE;
  1245.  
  1246.       case WM_COMMAND:
  1247.  
  1248.         FHandleWm (SoundsPage, hdlg, COMMAND, wParam, lParam);
  1249.         break;
  1250.  
  1251.       case WM_NOTIFY:
  1252.  
  1253.         return FHandleWm (SoundsPage, hdlg, NOTIFY, wParam, lParam);
  1254.     }
  1255.  
  1256.     return FALSE;
  1257. }
  1258.  
  1259.  
  1260. /*
  1261.  *  HrEditFilterProperties()
  1262.  *
  1263.  *  Purpose:
  1264.  *
  1265.  *      Brings up the filter description dialog for the rule properties
  1266.  *      found in the profile section muid passed in.
  1267.  *
  1268.  *  Arguments:
  1269.  *
  1270.  *      lpscd       SMH dialog structure
  1271.  *      hdlg        parent dialog for the filter description
  1272.  *      fEdit       indicates lpscd->muid contains a section to edit
  1273.  *
  1274.  *  Returns:
  1275.  *
  1276.  *      (HRESULT)
  1277.  */
  1278. HRESULT
  1279. HrEditFilterProperties (LPFILTER lpfltr, HWND hdlg, BOOL fEdit)
  1280. {
  1281.     HRESULT hr = hrSuccess;
  1282.     ULONG cval;
  1283.     UINT ipg;
  1284.     PROPSHEETPAGE psp[] =
  1285.     {
  1286.         {
  1287.             sizeof(PROPSHEETPAGE),
  1288.             PSP_USETITLE,
  1289.             lpfltr->lpscd->hinst,
  1290.             MAKEINTRESOURCE(SMH_PropertiesPage),
  1291.             NULL,
  1292.             MAKEINTRESOURCE(SMH_GeneralTab),
  1293.             FilterDescriptionPageProc,
  1294.             0,
  1295.             NULL,
  1296.             NULL
  1297.         },
  1298.         {
  1299.             sizeof(PROPSHEETPAGE),
  1300.             PSP_USETITLE,
  1301.             lpfltr->lpscd->hinst,
  1302.             MAKEINTRESOURCE(SMH_ResponsePage),
  1303.             NULL,
  1304.             MAKEINTRESOURCE(SMH_ResponseTab),
  1305.             ResponsePageProc,
  1306.             0,
  1307.             NULL,
  1308.             NULL
  1309.         },
  1310.         {
  1311.             sizeof(PROPSHEETPAGE),
  1312.             PSP_USETITLE,
  1313.             lpfltr->lpscd->hinst,
  1314.             MAKEINTRESOURCE(SMH_SoundsPage),
  1315.             NULL,
  1316.             MAKEINTRESOURCE(SMH_SoundsTab),
  1317.             SoundsPageProc,
  1318.             0,
  1319.             NULL,
  1320.             NULL
  1321.         },
  1322.     };
  1323.     PROPSHEETHEADER psh =
  1324.     {
  1325.         sizeof(PROPSHEETHEADER),
  1326.         PSH_PROPSHEETPAGE | PSH_PROPTITLE,
  1327.         GetParent (hdlg),
  1328.         lpfltr->lpscd->hinst,
  1329.         NULL,
  1330.         NULL,
  1331.         sizeof(psp) / sizeof(PROPSHEETPAGE),
  1332.         0,
  1333.         (LPCPROPSHEETPAGE)&psp
  1334.     };
  1335.  
  1336.     /*  If we are creating a new entry, then we first need to create
  1337.      *  new profile section UID.
  1338.      */
  1339.     if (!fEdit)
  1340.     {
  1341.         lstrcpy (lpfltr->rgch, "Untitled");
  1342.         hr = lpfltr->lpscd->lpsup->lpVtbl->NewUID (lpfltr->lpscd->lpsup, &lpfltr->muid);
  1343.         if (HR_FAILED (hr))
  1344.             goto ret;
  1345.     }
  1346.  
  1347.     /*  Open the rules profile section */
  1348.     
  1349.     hr = lpfltr->lpscd->lpadmin->lpVtbl->OpenProfileSection (lpfltr->lpscd->lpadmin,
  1350.                                         &lpfltr->muid,
  1351.                                         NULL,
  1352.                                         MAPI_MODIFY,
  1353.                                         &lpfltr->lpsec);
  1354.     if (HR_FAILED (hr))
  1355.         goto ret;
  1356.  
  1357.     /*  Get the set of properties describing the rule */
  1358.  
  1359.     hr = lpfltr->lpsec->lpVtbl->GetProps (lpfltr->lpsec,
  1360.                                         (LPSPropTagArray)&sptRule,
  1361.                                         0,
  1362.                                         &cval,
  1363.                                         &lpfltr->lpval);
  1364.     if (HR_FAILED (hr))
  1365.         goto ret;
  1366.  
  1367.     /*  set property sheet data */
  1368.  
  1369.     psh.pszCaption = lpfltr->rgch;
  1370.     for (ipg = 0; ipg < psh.nPages; ipg++)
  1371.         psp[ipg].lParam = (LPARAM)lpfltr;
  1372.  
  1373.     switch (PropertySheet (&psh))
  1374.     {
  1375.       case -1:
  1376.  
  1377.         hr = ResultFromScode (MAPI_E_CALL_FAILED);
  1378.         break;
  1379.  
  1380.       case 0:
  1381.  
  1382.         hr = ResultFromScode (MAPI_E_USER_CANCEL);
  1383.         break;
  1384.     }
  1385.  
  1386. ret:
  1387.  
  1388.     /*  On success, the profile sub-section has been updated and
  1389.      *  committed.  We can now release the resources held for access
  1390.      *  to the section.
  1391.      */
  1392.     (*lpfltr->lpscd->lpfnFree) (lpfltr->lpval);
  1393.     UlRelease (lpfltr->lpsec);
  1394.     lpfltr->lpval = NULL;
  1395.     lpfltr->lpsec = NULL;
  1396.  
  1397.     DebugTraceResult (HrEditFilterProperties(), hr);
  1398.     return hr;
  1399. }
  1400.  
  1401.  
  1402. /*
  1403.  *  Filters Property Sheet Page -----------------------------------------------
  1404.  *  
  1405.  *  The filters page of the configuration property sheets provides a list
  1406.  *  of the exisitng filter AND the order in which they are processed.  The 
  1407.  *  page allows the user to delete, edit or create rules as well as customize
  1408.  *  the order in which the rules are processed.
  1409.  *  
  1410.  *  The list is based on the profile section property PR_SMH_RULES.  This
  1411.  *  property is a multi-valued binary property that contains rule section
  1412.  *  muids.  These muids are paired with the values from PR_SMH_RULE_NAMES.
  1413.  *  
  1414.  *  Furthermore, there exists an additional property, PR_SMH_ORPHANED_RULES,   
  1415.  *  that is used to maintain references to rules that have been deleted.
  1416.  *  
  1417.  *  When page processing is complete -- when either OK, APPLY or CANCEL
  1418.  *  is chosen, the properties related to this page are set in the profile
  1419.  *  and the changes are saved.  Note that switching out of the filters
  1420.  *  page to another page includes an implicit APPLY before switching
  1421.  *  pages.
  1422.  */
  1423.  
  1424. /*
  1425.  *  EnableFilterPageCtrls()
  1426.  *
  1427.  *  Purpose:
  1428.  *
  1429.  *      Enables the set of buttons on the filter page based on the
  1430.  *      current selection in the filter list dialog
  1431.  */
  1432. VOID
  1433. EnableFilterPageCtrls (HWND hdlg)
  1434. {
  1435.     BOOL fDelete;
  1436.     BOOL fEdit;
  1437.     BOOL fDown = FALSE;
  1438.     BOOL fUp = FALSE;
  1439.     HWND hctrl = GetDlgItem (hdlg, ID_FilterOrderLB);
  1440.     UINT isel = ListBox_GetCurSel (hctrl);
  1441.  
  1442.     if (fDelete = fEdit = (isel != LB_ERR))
  1443.     {
  1444.         /*  If we are at the top, "move up" is not very realistic */
  1445.  
  1446.         fUp = (isel != 0);
  1447.  
  1448.         /*  If we are at the bottom, "move down" is not very realistic */
  1449.  
  1450.         fDown = (isel != (UINT)(ListBox_GetCount (hctrl) - 1));
  1451.     }
  1452.  
  1453.     /*  Enable the controls */
  1454.  
  1455.     Button_Enable (GetDlgItem (hdlg, ID_FilterUp), fUp);
  1456.     Button_Enable (GetDlgItem (hdlg, ID_FilterDown), fDown);
  1457.     Button_Enable (GetDlgItem (hdlg, ID_EditFilter), fEdit);
  1458.     Button_Enable (GetDlgItem (hdlg, ID_RmvFilter), fDelete);
  1459.     return;
  1460. }
  1461.  
  1462.  
  1463. /*
  1464.  *  FilterPage_INITDIALOG()
  1465.  *
  1466.  *  Purpose:
  1467.  *
  1468.  *      Handles the WM_INITDIALOG message for the filter description
  1469.  *      dialog.
  1470.  *
  1471.  *      The current list of filters are processed and the name is
  1472.  *      retrieved for use in the dialog.
  1473.  */
  1474. BOOL
  1475. FilterPage_INITDIALOG (HWND hdlg, HWND hwndFocus, LPARAM lParam)
  1476. {
  1477.     SCODE sc = S_OK;
  1478.     BOOL fInit;
  1479.     HWND hctrl;
  1480.     LPBYTE lpmuid;
  1481.     LPSCD lpscd = (LPSCD)(((PROPSHEETPAGE *)lParam)->lParam);
  1482.     LPSPropValue lpval;
  1483.     LPTSTR lpsz;
  1484.     UINT cb;
  1485.     UINT crl;
  1486.     UINT irl = 0;
  1487.  
  1488.     /*  Setup the dialog */
  1489.  
  1490.     CTL3D_Subclass(lpCtl3D, hdlg, CTL3D_ALL);
  1491.     SizeODButtons (lpscd->hinst, hdlg, SMH_FilterPage);
  1492.     SetWindowLong (hdlg, DWL_USER, ((PROPSHEETPAGE *)lParam)->lParam);
  1493.  
  1494.     /*  Load the filter LBX and create the mapping */
  1495.  
  1496.     if ((lpval = lpscd->lpval) && (lpval[ipRules].ulPropTag == PR_SMH_RULES))
  1497.     {
  1498.         hctrl = GetDlgItem (hdlg, ID_FilterOrderLB);
  1499.  
  1500.         crl = (UINT)lpval[ipRules].Value.MVbin.cValues;
  1501.         Assert (crl == lpval[ipNames].Value.MVbin.cValues);
  1502.         
  1503.         if (fInit = !lpscd->lpbin)
  1504.         {
  1505.             /*  As we fill the listbox we are going to make a copy of the
  1506.              *  of the multi-valued arrays for use while editing
  1507.              */
  1508.             
  1509.             cb = (crl + GROW_SIZE) * sizeof(LPTSTR);
  1510.             if (FAILED (sc = (*lpscd->lpfnAlloc) (cb, (LPVOID FAR *)&lpscd->lppsz)))
  1511.                 goto ret;
  1512.  
  1513.             cb = (crl + GROW_SIZE) * sizeof(SBinary);
  1514.             if (FAILED (sc = (*lpscd->lpfnAlloc) (cb, &lpscd->lpbin)))
  1515.                 goto ret;
  1516.  
  1517.             lpscd->crlMax = crl + GROW_SIZE;
  1518.         }
  1519.         
  1520.         for (irl = 0; irl < crl; irl++)
  1521.         {
  1522.             if (fInit)
  1523.             {
  1524.                 /*  Allocate space (linked) for the copy */
  1525.                 
  1526.                 lpsz = lpval[ipNames].Value.MVSZ.lppszA[irl];
  1527.                 lpmuid = lpval[ipRules].Value.MVbin.lpbin[irl].lpb;
  1528.                 cb = lstrlen (lpval[ipNames].Value.MVSZ.lppszA[irl]) + 1;
  1529.                 if (FAILED (sc = (*lpscd->lpfnAlloc) (cb, &lpscd->lppsz[irl])) ||
  1530.                     FAILED (sc = (*lpscd->lpfnAlloc) (sizeof(MAPIUID), &lpscd->lpbin[irl].lpb)))
  1531.                     break;
  1532.             }
  1533.             else
  1534.                 lpsz = lpscd->lppsz[irl];
  1535.  
  1536.             /*  Add the item to the list and copy it local (maybe) */
  1537.             
  1538.             if ((ListBox_AddString (hctrl, lpsz) != LB_ERRSPACE) &&
  1539.                 (ListBox_SetItemData (hctrl, irl, irl) != LB_ERR) &&
  1540.                 fInit)
  1541.             {
  1542.                 lstrcpy (lpscd->lppsz[irl], lpsz);
  1543.                 lpscd->lpbin[irl].cb = sizeof(MAPIUID);
  1544.                 memcpy (lpscd->lpbin[irl].lpb, lpmuid, sizeof(MAPIUID));
  1545.             }
  1546.         }
  1547.  
  1548.         /*  Set the selection to the first filter in the list */
  1549.  
  1550.         ListBox_SetCurSel (hctrl, 0);
  1551.     }
  1552.     else
  1553.         sc = MAPI_E_UNCONFIGURED;
  1554.  
  1555. ret:
  1556.     
  1557.     EnableFilterPageCtrls (hdlg);
  1558.     lpscd->crl = irl;
  1559.     lpscd->sc = sc;
  1560.     return TRUE;
  1561. }
  1562.  
  1563.  
  1564. /*
  1565.  *  FilterPage_NOTIFY()
  1566.  *
  1567.  *  Purpose:
  1568.  *
  1569.  *      Handles the WM_NOTIFY message for the filter description dialog.
  1570.  *      On PSN_APPLY, the filter order is computed and set in PR_SMH_RULES.
  1571.  */
  1572. BOOL
  1573. FilterPage_NOTIFY (HWND hdlg, UINT id, NMHDR FAR * lpnmhdr)
  1574. {
  1575.     HRESULT hr;
  1576.     LPSCD lpscd;
  1577.     SPropValue rgval[2];
  1578.  
  1579.     switch (lpnmhdr->code)
  1580.     {
  1581.       case PSN_KILLACTIVE:
  1582.       case PSN_RESET:
  1583.       case PSN_SETACTIVE:
  1584.       default:
  1585.  
  1586.         break;
  1587.  
  1588.       case PSN_APPLY:
  1589.  
  1590.         DebugTrace ("SMH: saving contents of filter page\n");
  1591.  
  1592.         /*  Setup and save out the new properties */
  1593.  
  1594.         lpscd = (LPSCD)GetWindowLong (hdlg, DWL_USER);
  1595.         
  1596.         if(lpscd->crl)
  1597.         {
  1598.             rgval[0].ulPropTag = PR_SMH_RULES;
  1599.             rgval[0].Value.MVbin.cValues = lpscd->crl;
  1600.             rgval[0].Value.MVbin.lpbin = lpscd->lpbin;
  1601.             rgval[1].ulPropTag = PR_SMH_RULE_NAMES;
  1602.             rgval[1].Value.MVSZ.cValues = lpscd->crl;
  1603.             rgval[1].Value.MVSZ.lppszA = lpscd->lppsz;
  1604.             
  1605.             hr = lpscd->lpsec->lpVtbl->SetProps (lpscd->lpsec, 2, rgval, NULL);
  1606.         }
  1607.         else
  1608.         {
  1609.             SizedSPropTagArray(2, taga) = {2, {PR_SMH_RULES, PR_SMH_RULE_NAMES}};
  1610.             LPSPropProblemArray pProbl = NULL;
  1611.  
  1612.             hr = lpscd->lpsec->lpVtbl->DeleteProps(lpscd->lpsec, 
  1613.                                             (LPSPropTagArray)&taga, &pProbl);
  1614.             if (!hr)
  1615.             {
  1616.                 if(pProbl)
  1617.                 {
  1618.                     DebugTraceProblems("SMH: DeleteProps :", pProbl);
  1619.                     MAPIFreeBuffer(pProbl);
  1620.                 }
  1621.             }
  1622.         }
  1623.  
  1624.         if (!HR_FAILED (hr))
  1625.             hr = lpscd->lpsec->lpVtbl->SaveChanges (lpscd->lpsec, KEEP_OPEN_READWRITE);
  1626.  
  1627.         lpscd->sc = GetScode (hr);
  1628.         return TRUE;
  1629.  
  1630.       case PSN_HELP:
  1631.  
  1632.         return TRUE;
  1633.     }
  1634.  
  1635.     return FALSE;
  1636. }
  1637.  
  1638.  
  1639. /*
  1640.  *  FilterPage_COMMAND()
  1641.  *
  1642.  *  Purpose:
  1643.  *
  1644.  *      Handles the WM_COMMAND message for the filter description dialog.
  1645.  */
  1646. BOOL
  1647. FilterPage_COMMAND (HWND hdlg, UINT id, HWND hwndCtl, UINT codeNotify)
  1648. {
  1649.     SCODE sc;
  1650.     FILTER fltr = {0};
  1651.     HWND hctrl = GetDlgItem (hdlg, ID_FilterOrderLB);
  1652.     LPBYTE lpb;
  1653.     LPSBinary lpbin;
  1654.     LPSCD lpscd = (LPSCD)GetWindowLong (hdlg, DWL_USER);
  1655.     LPTSTR FAR * lppsz;
  1656.     LPTSTR lpsz;
  1657.     UINT cb;
  1658.     UINT irl = 0;
  1659.     INT nAdj;
  1660.  
  1661.     irl = ListBox_GetCurSel (hctrl);
  1662.     switch (id)
  1663.     {
  1664.       case ID_NewFilter:
  1665.  
  1666.         if (lpscd->crl == lpscd->crlMax)
  1667.         {
  1668.             /*  We need to make room for new entries */
  1669.  
  1670.             cb = (lpscd->crl + GROW_SIZE) * sizeof(LPVOID);
  1671.             if (FAILED (sc = (*lpscd->lpfnAlloc) (cb, (LPVOID FAR *)&lppsz)))
  1672.                 break;
  1673.             memcpy (lppsz, lpscd->lppsz, lpscd->crl * sizeof(LPTSTR));
  1674.                 
  1675.             cb = (lpscd->crl + GROW_SIZE) * sizeof(SBinary);
  1676.             if (FAILED (sc = (*lpscd->lpfnAlloc) (cb, &lpbin)))
  1677.                 break;
  1678.             memcpy (lpbin, lpscd->lpbin, lpscd->crl * sizeof(SBinary));
  1679.  
  1680.             /*  Swap out the old for the new */
  1681.  
  1682.             (*lpscd->lpfnFree) (lpscd->lppsz);
  1683.             (*lpscd->lpfnFree) (lpscd->lpbin);
  1684.             lpscd->crlMax += GROW_SIZE;
  1685.             lpscd->lppsz = lppsz;
  1686.             lpscd->lpbin = lpbin;
  1687.  
  1688.         }
  1689.         irl = lpscd->crl;
  1690.  
  1691.         /*  Get the new filter */
  1692.  
  1693.         fltr.lpscd = lpscd;
  1694.         if (!FAILED (sc = GetScode (HrEditFilterProperties (&fltr, hdlg, FALSE))))
  1695.         {
  1696.             /*  Allocate space for the new rule identifiers */
  1697.             
  1698.             if (!FAILED (sc = (*lpscd->lpfnAlloc) (lstrlen (fltr.rgch) + 1, &lpscd->lppsz[irl])) &&
  1699.                 !FAILED (sc = (*lpscd->lpfnAlloc) (sizeof(MAPIUID), &lpscd->lpbin[irl].lpb)))
  1700.             {
  1701.                 if ((ListBox_AddString (hctrl, fltr.rgch) != LB_ERR) &&
  1702.                     (ListBox_SetItemData (hctrl, irl, irl) != LB_ERR))
  1703.                 {
  1704.                     /*  Copy the identifiers across */
  1705.                     
  1706.                     lstrcpy (lpscd->lppsz[irl], fltr.rgch);
  1707.                     memcpy (lpscd->lpbin[irl].lpb, &fltr.muid, sizeof(MAPIUID));
  1708.                     lpscd->lpbin[irl].cb = sizeof(MAPIUID);
  1709.  
  1710.                     ListBox_SetCurSel (hctrl, irl);
  1711.                     PropSheet_Changed (GetParent (hdlg), hdlg);
  1712.                     lpscd->crl++;
  1713.                 }
  1714.                 else
  1715.                     sc = MAPI_E_CALL_FAILED;
  1716.             }
  1717.         }
  1718.         lpscd->sc = sc;
  1719.         break;
  1720.  
  1721.       case ID_FilterOrderLB:
  1722.  
  1723.         if (codeNotify != LBN_DBLCLK)
  1724.             break;
  1725.  
  1726.         /*  Fall through to edit */
  1727.              
  1728.       case ID_EditFilter:
  1729.  
  1730.         /*  Copy the muid out for use in the dialog */
  1731.  
  1732.         fltr.lpscd = lpscd;
  1733.         lstrcpy (fltr.rgch, lpscd->lppsz[irl]);
  1734.         memcpy (&fltr.muid, lpscd->lpbin[irl].lpb, sizeof(MAPIUID));
  1735.         if (!FAILED (sc = GetScode (HrEditFilterProperties (&fltr, hdlg, TRUE))))
  1736.         {
  1737.             /*  The name may have changed.  If so, update it */
  1738.  
  1739.             if (lstrcmp (fltr.rgch, lpscd->lppsz[irl]))
  1740.             {
  1741.                 /*  See if we need a bigger buffer and alloc one */
  1742.  
  1743.                 if ((cb = lstrlen (fltr.rgch)) > (UINT)lstrlen (lpscd->lppsz[irl]))
  1744.                 {
  1745.                     if (!FAILED (sc = (*lpscd->lpfnAlloc) (cb + 1, &lpsz)))
  1746.                     {
  1747.                         (*lpscd->lpfnFree) (lpscd->lppsz[irl]);
  1748.                         lstrcpy (lpsz, fltr.rgch);
  1749.                         lpscd->lppsz[irl] = lpsz;
  1750.                     }
  1751.                     else
  1752.                         break;
  1753.                 }
  1754.                 else
  1755.                     lstrcpy (lpscd->lppsz[irl], fltr.rgch);
  1756.                 
  1757.                 if ((ListBox_DeleteString (hctrl, irl) == LB_ERR) ||
  1758.                     (ListBox_InsertString (hctrl, irl, fltr.rgch) == LB_ERRSPACE) ||
  1759.                     (ListBox_SetItemData (hctrl, irl, irl) == LB_ERR))
  1760.                     sc = MAPI_E_NOT_ENOUGH_MEMORY;
  1761.  
  1762.                 ListBox_SetCurSel (hctrl, irl);
  1763.             }
  1764.             PropSheet_Changed (GetParent (hdlg), hdlg);
  1765.         }
  1766.         lpscd->sc = sc;
  1767.         break;
  1768.  
  1769.       case ID_RmvFilter:
  1770.  
  1771.         /*  Remove the string and collapse the local copies */
  1772.  
  1773.         if ((irl != LB_ERR) && (ListBox_DeleteString (hctrl, irl) != LB_ERR))
  1774.         {
  1775.             (*lpscd->lpfnFree) (lpscd->lpbin[irl].lpb);
  1776.             (*lpscd->lpfnFree) (lpscd->lppsz[irl]);
  1777.             lpscd->crl -= 1;
  1778.             if (irl != lpscd->crl)
  1779.             {
  1780.                 memcpy (&lpscd->lppsz[irl], &lpscd->lppsz[irl + 1],
  1781.                     (lpscd->crl - irl) * sizeof(LPTSTR));
  1782.                 memcpy (&lpscd->lpbin[irl], &lpscd->lpbin[irl + 1],
  1783.                     (lpscd->crl - irl) * sizeof(SBinary));
  1784.             }
  1785.         }
  1786.         else
  1787.             MessageBeep (0);
  1788.  
  1789.         ListBox_SetCurSel (hctrl, irl);
  1790.         PropSheet_Changed (GetParent (hdlg), hdlg);
  1791.         break;
  1792.  
  1793.       case ID_FilterUp:
  1794.       case ID_FilterDown:
  1795.  
  1796.         /*  Ensure we really have something to move */
  1797.         
  1798.         if (id == ID_FilterUp)
  1799.         {
  1800.             nAdj = -1;
  1801.             if ((irl == LB_ERR) || (irl == 0))
  1802.                 break;
  1803.         }
  1804.         else
  1805.         {
  1806.             nAdj = 1;
  1807.             if ((irl == LB_ERR) || (irl == (UINT)(ListBox_GetCount (hctrl) - 1)))
  1808.                 break;
  1809.         }
  1810.  
  1811.         /*  Move it */
  1812.  
  1813.         if ((ListBox_DeleteString (hctrl, irl + nAdj) == LB_ERR) ||
  1814.             (ListBox_InsertString (hctrl, irl, lpscd->lppsz[irl + nAdj]) == LB_ERRSPACE))
  1815.         {
  1816.             ListBox_ResetContent (hctrl);
  1817.             lpscd->sc = MAPI_E_CALL_FAILED;
  1818.             break;
  1819.         }
  1820.         else
  1821.             ListBox_SetItemData (hctrl, irl, irl);
  1822.  
  1823.         /*  Move it in the local copies */
  1824.  
  1825.         lpsz = lpscd->lppsz[irl + nAdj];
  1826.         lpscd->lppsz[irl + nAdj] = lpscd->lppsz[irl];
  1827.         lpscd->lppsz[irl] = lpsz;
  1828.         
  1829.         lpb = lpscd->lpbin[irl + nAdj].lpb;
  1830.         lpscd->lpbin[irl + nAdj].lpb = lpscd->lpbin[irl].lpb;
  1831.         lpscd->lpbin[irl].lpb = lpb;
  1832.  
  1833.         /*  Set the selection to the new position */
  1834.         
  1835.         ListBox_SetCurSel (hctrl, irl + nAdj);
  1836.         PropSheet_Changed (GetParent (hdlg), hdlg);
  1837.         break;
  1838.  
  1839.       case ID_Export:
  1840.  
  1841.         ScExportFilters (lpscd, GetParent (hdlg));
  1842.         break;
  1843.  
  1844.       case ID_Import:
  1845.  
  1846.         ScImportFilters (lpscd, GetParent (hdlg), hctrl);
  1847.         PropSheet_Changed (GetParent (hdlg), hdlg);
  1848.         break;
  1849.  
  1850.       default:
  1851.         break;
  1852.     }
  1853.  
  1854.     EnableFilterPageCtrls (hdlg);
  1855.     return TRUE;
  1856. }
  1857.  
  1858.  
  1859. /*
  1860.  *  FilterPageProc()
  1861.  *
  1862.  *  Purpose:
  1863.  *
  1864.  *      Dispatches window messages to the proper function for processing
  1865.  */
  1866. BOOL CALLBACK
  1867. FilterPageProc (HWND hdlg, UINT msg, WPARAM wParam, LPARAM lParam)
  1868. {
  1869.     switch (msg)
  1870.     {
  1871.       case WM_INITDIALOG:
  1872.  
  1873.         FHandleWm (FilterPage, hdlg, INITDIALOG, wParam, lParam);
  1874.         return TRUE;
  1875.  
  1876.       case WM_COMMAND:
  1877.  
  1878.         FHandleWm (FilterPage, hdlg, COMMAND, wParam, lParam);
  1879.         return TRUE;
  1880.  
  1881.       case WM_DRAWITEM:
  1882.  
  1883.         DrawODButton (((LPSCD)GetWindowLong (hdlg, DWL_USER))->hinst,
  1884.             (DRAWITEMSTRUCT FAR *)lParam, TRUE);
  1885.         break;
  1886.  
  1887.       case WM_NOTIFY:
  1888.  
  1889.         return FHandleWm (FilterPage, hdlg, NOTIFY, wParam, lParam);
  1890.     }
  1891.  
  1892.     return FALSE;
  1893. }
  1894.  
  1895.  
  1896. /*
  1897.  *  General Property Sheet Page -----------------------------------------------
  1898.  *  
  1899.  *  The general page of the configuration property sheets provides access
  1900.  *  to the many flags that are available to the SMH service.  The dialog
  1901.  *  is used to set the value for PR_SMH_FLAGS.
  1902.  */
  1903.  
  1904. /*
  1905.  *  GeneralPage_INITDAILOG()
  1906.  *
  1907.  *  Purpose:
  1908.  *
  1909.  *      Handles the WM_INITDIALOG message for the filter description dialog
  1910.  */
  1911. BOOL
  1912. GeneralPage_INITDIALOG (HWND hdlg, HWND hwndFocus, LPARAM lParam)
  1913. {
  1914.     LPSCD lpscd = (LPSCD)(((PROPSHEETPAGE *)lParam)->lParam);
  1915.     LPSPropValue lpval = lpscd->lpval;
  1916.     ULONG ulFlags;
  1917.  
  1918.     CTL3D_Subclass(lpCtl3D, hdlg, CTL3D_ALL);
  1919.     SetWindowLong (hdlg, DWL_USER, ((PROPSHEETPAGE *)lParam)->lParam);
  1920.  
  1921.     ulFlags = (lpval[ipFlags].ulPropTag == PR_SMH_FLAGS)
  1922.                 ? lpval[ipFlags].Value.l
  1923.                 : 0;
  1924.  
  1925.     /*  Enable/check the checkboxes based on SMH flags */
  1926.  
  1927.     CheckDlgButton (hdlg, ID_AddToPab, !!(ulFlags & SMH_ADD_TO_PAB));
  1928.     CheckDlgButton (hdlg, ID_Deleted, !!(ulFlags & SMH_FILTER_DELETED));
  1929.     CheckDlgButton (hdlg, ID_DeletedYr, !!(ulFlags & SMH_FILTER_DELETED_YR));
  1930.     CheckDlgButton (hdlg, ID_Inbound, !!(ulFlags & SMH_FILTER_INBOUND));
  1931.     CheckDlgButton (hdlg, ID_SentMail, !!(ulFlags & SMH_FILTER_SENTMAIL));
  1932.     CheckDlgButton (hdlg, ID_SentMailYr, !!(ulFlags & SMH_FILTER_SENTMAIL_YR));
  1933.     CheckDlgButton (hdlg, ID_Unread, !!(ulFlags & SMH_UNREAD_VIEWER));
  1934.     EnableWindow (GetDlgItem (hdlg, ID_DeletedYr), !!(ulFlags & SMH_FILTER_DELETED));
  1935.     EnableWindow (GetDlgItem (hdlg, ID_SentMailYr), !!(ulFlags & SMH_FILTER_SENTMAIL));
  1936.     lpval[ipFlags].ulPropTag = PR_SMH_FLAGS;
  1937.     lpval[ipFlags].Value.l = ulFlags;
  1938.     return TRUE;
  1939. }
  1940.  
  1941. /*
  1942.  *  GeneralPage_NOTIFY()
  1943.  *
  1944.  *  Purpose:
  1945.  *
  1946.  *      Handles the WM_NOTIFY message for the filter description dialog.
  1947.  *      On PSN_APPLY, SMHFlags is recomputed from the checkbox states.
  1948.  */
  1949. BOOL
  1950. GeneralPage_NOTIFY (HWND hdlg, UINT id, NMHDR FAR * lpnmhdr)
  1951. {
  1952.     HRESULT hr;
  1953.     LPSCD lpscd = (LPSCD)GetWindowLong (hdlg, DWL_USER);
  1954.     SPropValue val = {0};
  1955.  
  1956.     switch (lpnmhdr->code)
  1957.     {
  1958.       case PSN_KILLACTIVE:
  1959.       case PSN_RESET:
  1960.       case PSN_SETACTIVE:
  1961.       default:
  1962.  
  1963.         break;
  1964.  
  1965.       case PSN_APPLY:
  1966.  
  1967.         DebugTrace ("SMH: saving contents of general page\n");
  1968.         
  1969.         /*  Calc the value for PR_SMH_FLAGS */
  1970.  
  1971.         if (IsDlgButtonChecked (hdlg, ID_SentMail))
  1972.         {
  1973.             val.Value.l |= SMH_FILTER_SENTMAIL;
  1974.             if (IsDlgButtonChecked (hdlg, ID_SentMailYr))
  1975.                 val.Value.l |= SMH_FILTER_SENTMAIL_YR;
  1976.             else
  1977.                 val.Value.l &= ~SMH_FILTER_SENTMAIL_YR;
  1978.         }
  1979.         else
  1980.             val.Value.l &= ~(SMH_FILTER_SENTMAIL | SMH_FILTER_SENTMAIL_YR);
  1981.  
  1982.         if (IsDlgButtonChecked (hdlg, ID_Deleted))
  1983.         {
  1984.             val.Value.l |= SMH_FILTER_DELETED;
  1985.             if (IsDlgButtonChecked (hdlg, ID_DeletedYr))
  1986.                 val.Value.l |= SMH_FILTER_DELETED_YR;
  1987.             else
  1988.                 val.Value.l &= ~SMH_FILTER_DELETED_YR;
  1989.         }
  1990.         else
  1991.             val.Value.l &= ~(SMH_FILTER_DELETED | SMH_FILTER_DELETED_YR);
  1992.  
  1993.         if (IsDlgButtonChecked (hdlg, ID_Inbound))
  1994.             val.Value.l |= SMH_FILTER_INBOUND;
  1995.         else
  1996.             val.Value.l &= ~SMH_FILTER_INBOUND;
  1997.  
  1998.         if (IsDlgButtonChecked (hdlg, ID_Unread))
  1999.             val.Value.l |= SMH_UNREAD_VIEWER;
  2000.         else
  2001.             val.Value.l &= ~SMH_UNREAD_VIEWER;
  2002.  
  2003.         if (IsDlgButtonChecked (hdlg, ID_AddToPab))
  2004.             val.Value.l |= SMH_ADD_TO_PAB;
  2005.         else
  2006.             val.Value.l &= ~SMH_ADD_TO_PAB;
  2007.  
  2008.         val.ulPropTag = PR_SMH_FLAGS;
  2009.         hr = lpscd->lpsec->lpVtbl->SetProps (lpscd->lpsec,
  2010.                                         1,
  2011.                                         &val,
  2012.                                         NULL);
  2013.         if (!HR_FAILED (hr))
  2014.             hr = lpscd->lpsec->lpVtbl->SaveChanges (lpscd->lpsec, KEEP_OPEN_READWRITE);
  2015.         
  2016.         lpscd->sc = GetScode (hr);
  2017.         return TRUE;
  2018.  
  2019.       case PSN_HELP:
  2020.  
  2021.         return TRUE;
  2022.     }
  2023.  
  2024.     return FALSE;
  2025. }
  2026.  
  2027.  
  2028. /*
  2029.  *  GeneralPage_COMMAND()
  2030.  *
  2031.  *  Purpose:
  2032.  *
  2033.  *      Handles the WM_COMMAND message for the filter description dialog
  2034.  *
  2035.  *      IMPORTANT: This function relies on the dialog control IDs as
  2036.  *      defined in _SMH.RH.  The yearly archive checkboxes must have an
  2037.  *      ID that is one greater than the companion checkbox.
  2038.  */
  2039. BOOL
  2040. GeneralPage_COMMAND (HWND hdlg, UINT id, HWND hwndCtl, UINT codeNotify)
  2041. {
  2042.     switch (id)
  2043.     {
  2044.       case ID_SentMail:
  2045.       case ID_Deleted:
  2046.  
  2047.         EnableWindow (GetDlgItem (hdlg, id + 1),
  2048.                     !!IsDlgButtonChecked (hdlg, id));
  2049.         break;
  2050.  
  2051.       case ID_SentMailYr:
  2052.       case ID_DeletedYr:
  2053.       case ID_Inbound:
  2054.       case ID_Unread:
  2055.       case ID_AddToPab:
  2056.  
  2057.         break;
  2058.  
  2059.       default:
  2060.  
  2061.         return TRUE;
  2062.     }
  2063.     PropSheet_Changed (GetParent (hdlg), hdlg);
  2064.     return TRUE;
  2065. }
  2066.  
  2067.  
  2068. /*
  2069.  *  GeneralPageProc()
  2070.  *
  2071.  *  Purpose:
  2072.  *
  2073.  *      Dispatches window messages to the proper function for processing
  2074.  */
  2075. BOOL CALLBACK
  2076. GeneralPageProc (HWND hdlg, UINT msg, WPARAM wParam, LPARAM lParam)
  2077. {
  2078.     switch (msg)
  2079.     {
  2080.       case WM_INITDIALOG:
  2081.  
  2082.         FHandleWm (GeneralPage, hdlg, INITDIALOG, wParam, lParam);
  2083.         return TRUE;
  2084.  
  2085.       case WM_COMMAND:
  2086.  
  2087.         FHandleWm (GeneralPage, hdlg, COMMAND, wParam, lParam);
  2088.         break;
  2089.  
  2090.       case WM_NOTIFY:
  2091.  
  2092.         return FHandleWm (GeneralPage, hdlg, NOTIFY, wParam, lParam);
  2093.     }
  2094.  
  2095.     return FALSE;
  2096. }
  2097.  
  2098.  
  2099. /*
  2100.  *  Exclussion Edit Dialog ----------------------------------------------------
  2101.  *  
  2102.  *  The exclusion edit dialog alows the user to input a single entry into
  2103.  *  the list of excluded message classes.
  2104.  *  
  2105.  *  All information is passed via the SCD structure.
  2106.  *  
  2107.  *      lpscd->rgch     [IN\OUT]    contains the message class to exclude
  2108.  *  
  2109.  *  The caller is responsible for merging the new value into the
  2110.  *  exclusion list.
  2111.  */
  2112.  
  2113. /*
  2114.  *  ExclusionEdit_INITDIALOG()
  2115.  *
  2116.  *  Purpose:
  2117.  *
  2118.  *      Handles the WM_INITDIALOG message for the filter description dialog
  2119.  */
  2120. BOOL
  2121. ExclusionEdit_INITDIALOG (HWND hdlg, HWND hwndFocus, LPARAM lParam)
  2122. {
  2123.     CTL3D_Subclass(lpCtl3D, hdlg, CTL3D_ALL);
  2124.     SetWindowLong (hdlg, DWL_USER, lParam);
  2125.  
  2126.     /*  Enable/limit the exclusion edit */
  2127.  
  2128.     Edit_LimitText (GetDlgItem (hdlg, ID_ExclusionClass), cchNameMax - 1);
  2129.     Button_Enable (GetDlgItem (hdlg, IDOK), FALSE);
  2130.     return TRUE;
  2131. }
  2132.  
  2133.  
  2134. /*
  2135.  *  ExclusionEdit_COMMAND()
  2136.  *
  2137.  *  Purpose:
  2138.  *
  2139.  *      Handles the WM_COMMAND message for the filter description dialog
  2140.  */
  2141. BOOL ExclusionEdit_COMMAND (HWND hdlg, UINT id, HWND hwndCtl, UINT codeNotify)
  2142. {
  2143.     LPSCD lpscd = (LPSCD)GetWindowLong (hdlg, DWL_USER);
  2144.     HWND hctrl = GetDlgItem (hdlg, ID_ExclusionClass);
  2145.  
  2146.     switch (id)
  2147.     {
  2148.       case IDOK:
  2149.  
  2150.         Edit_GetText (hctrl, lpscd->rgch, cchNameMax);
  2151.         break;
  2152.  
  2153.       case IDCANCEL:
  2154.  
  2155.         break;
  2156.  
  2157.       default:
  2158.  
  2159.         return FALSE;
  2160.     }
  2161.  
  2162.     EndDialog (hdlg, id);
  2163.     return TRUE;
  2164. }
  2165.  
  2166.  
  2167. /*
  2168.  *  ExclusionEditProc()
  2169.  *
  2170.  *  Purpose:
  2171.  *
  2172.  *      Dispatches window messages to the proper function for processing
  2173.  */
  2174. BOOL CALLBACK
  2175. ExclusionEditProc (HWND hdlg, UINT msg, WPARAM wParam, LPARAM lParam)
  2176. {
  2177.     HWND hctrl = GetDlgItem (hdlg, ID_ExclusionClass);
  2178.  
  2179.     switch (msg)
  2180.     {
  2181.       case WM_INITDIALOG:
  2182.  
  2183.         FHandleWm (ExclusionEdit, hdlg, INITDIALOG, wParam, lParam);
  2184.         return TRUE;
  2185.  
  2186.       case WM_COMMAND:
  2187.  
  2188.         FHandleWm (ExclusionEdit, hdlg, COMMAND, wParam, lParam);
  2189.         break;
  2190.     }
  2191.     Button_Enable (GetDlgItem (hdlg, IDOK), !!Edit_GetTextLength (hctrl));
  2192.     return FALSE;
  2193. }
  2194.  
  2195.  
  2196. /*
  2197.  *  Exclussion Page Property Sheet --------------------------------------------
  2198.  *  
  2199.  *  The exclusions page exposes the list of message classes that are
  2200.  *  excluded from inbound filtering.  The property that correlates to 
  2201.  *  the list is PR_SMH_EXCLUSIONS.  Any actions required against this
  2202.  *  property are processed within the context of this property sheet.
  2203.  */
  2204.  
  2205. /*
  2206.  *  ExclusionPage_INITDIALOG()
  2207.  *
  2208.  *  Purpose:
  2209.  *
  2210.  *      Handles the WM_INITDIALOG message for the filter description dialog
  2211.  */
  2212. BOOL
  2213. ExclusionPage_INITDIALOG (HWND hdlg, HWND hwndFocus, LPARAM lParam)
  2214. {
  2215.     LPSCD lpscd = (LPSCD)(((PROPSHEETPAGE *)lParam)->lParam);
  2216.     HWND hctrl = GetDlgItem (hdlg, ID_ExclusionLB);
  2217.     UINT isz;
  2218.  
  2219.     CTL3D_Subclass(lpCtl3D, hdlg, CTL3D_ALL);
  2220.     SetWindowLong (hdlg, DWL_USER, ((PROPSHEETPAGE *)lParam)->lParam);
  2221.  
  2222.     /*  Populate the exclusion listbox */
  2223.  
  2224.     if (lpscd->lpval[ipExc].ulPropTag == PR_SMH_EXCLUSIONS)
  2225.         for (isz = 0; isz < lpscd->lpval[ipExc].Value.MVSZ.cValues; isz++)
  2226.             ListBox_AddString (hctrl, lpscd->lpval[ipExc].Value.MVSZ.LPPSZ[isz]);
  2227.  
  2228.     return TRUE;
  2229. }
  2230.  
  2231.  
  2232. /*
  2233.  *  ExclusionPage_NOTIFY()
  2234.  *
  2235.  *  Purpose:
  2236.  *
  2237.  *      Handles the WM_NOTIFY message for the filter description dialog
  2238.  */
  2239. BOOL
  2240. ExclusionPage_NOTIFY (HWND hdlg, UINT id, NMHDR FAR * lpnmhdr)
  2241. {
  2242.     SCODE sc;
  2243.     LPSCD lpscd = (LPSCD)GetWindowLong (hdlg, DWL_USER);
  2244.     HWND hctrl = GetDlgItem (hdlg, ID_ExclusionLB);
  2245.     LPSPropValue lpval;
  2246.     LPTSTR FAR * lppsz = NULL;
  2247.     SizedSPropTagArray (1, spt) = {1, { PR_SMH_EXCLUSIONS }};
  2248.     UINT cex;
  2249.     UINT iex;
  2250.  
  2251.     switch (lpnmhdr->code)
  2252.     {
  2253.       case PSN_KILLACTIVE:
  2254.       case PSN_RESET:
  2255.       case PSN_SETACTIVE:
  2256.       default:
  2257.  
  2258.         break;
  2259.  
  2260.       case PSN_APPLY:
  2261.  
  2262.         DebugTrace ("SMH: saving contents of exclusions page\n");
  2263.  
  2264.         /*  Assemble a new PR_SMH_EXCLUSIONS property value */
  2265.  
  2266.         lpval = &lpscd->lpval[ipExc];
  2267.         cex = ListBox_GetCount (hctrl);
  2268.         if (cex)
  2269.         {
  2270.             sc = (*lpscd->lpfnAllocMore) (cex * sizeof(LPTSTR),
  2271.                                     lpscd->lpval,
  2272.                                     (LPVOID FAR *)&lppsz);
  2273.             if (!FAILED (sc))
  2274.             {
  2275.                 lpval->ulPropTag = PR_SMH_EXCLUSIONS;
  2276.                 lpval->Value.MVSZ.LPPSZ = lppsz;
  2277.                 for (iex = 0; iex < cex; iex++, lppsz++)
  2278.                 {
  2279.                     sc = (*lpscd->lpfnAllocMore) (ListBox_GetTextLen (hctrl, iex) + 1,
  2280.                                         lpscd->lpval,
  2281.                                         lppsz);
  2282.                     if (FAILED (sc))
  2283.                         break;
  2284.  
  2285.                     ListBox_GetText (hctrl, iex, *lppsz);
  2286.                 }
  2287.                 lpval->Value.MVSZ.cValues = iex;
  2288.  
  2289.                 /*  Set the new value */
  2290.  
  2291.                 sc = GetScode (lpscd->lpsec->lpVtbl->SetProps (lpscd->lpsec,
  2292.                                                         1,
  2293.                                                         lpval,
  2294.                                                         NULL));
  2295.                 if (!FAILED (sc))
  2296.                     sc = GetScode (lpscd->lpsec->lpVtbl->SaveChanges (lpscd->lpsec,
  2297.                                                         KEEP_OPEN_READWRITE));
  2298.             }
  2299.             lpscd->sc = sc;
  2300.         }
  2301.         else
  2302.         {
  2303.             lpval->ulPropTag = PR_NULL;
  2304.             lpscd->lpsec->lpVtbl->DeleteProps (lpscd->lpsec, (LPSPropTagArray)&spt, NULL);
  2305.         }
  2306.         return TRUE;
  2307.  
  2308.       case PSN_HELP:
  2309.  
  2310.         return TRUE;
  2311.     }
  2312.  
  2313.     return FALSE;
  2314. }
  2315.  
  2316.  
  2317. /*
  2318.  *  ExclusionPage_COMMAND()
  2319.  *
  2320.  *  Purpose:
  2321.  *
  2322.  *      Handles the WM_COMMAND message for the filter description dialog
  2323.  */
  2324. BOOL
  2325. ExclusionPage_COMMAND (HWND hdlg, UINT id, HWND hwndCtl, UINT codeNotify)
  2326. {
  2327.     LPSCD lpscd = (LPSCD)GetWindowLong (hdlg, DWL_USER);
  2328.     HWND hctrl = GetDlgItem (hdlg, ID_ExclusionLB);
  2329.     UINT iex;
  2330.  
  2331.     switch (id)
  2332.     {
  2333.       case ID_NewExclusion:
  2334.  
  2335.         id = DialogBoxParam (lpscd->hinst,
  2336.                     MAKEINTRESOURCE (SMH_ExclusionEdit),
  2337.                     GetParent(hdlg),
  2338.                     ExclusionEditProc,
  2339.                     (LPARAM)lpscd);
  2340.         if (id == IDOK)
  2341.             ListBox_SetCurSel (hctrl, ListBox_AddString (hctrl, lpscd->rgch));
  2342.  
  2343.         PropSheet_Changed (GetParent (hdlg), hdlg);
  2344.         break;
  2345.  
  2346.       case ID_RmvExclusion:
  2347.  
  2348.         iex = ListBox_GetCurSel (hctrl);
  2349.         ListBox_DeleteString (hctrl, iex);
  2350.         ListBox_SetCurSel (hctrl, iex);
  2351.         PropSheet_Changed (GetParent (hdlg), hdlg);
  2352.         break;
  2353.  
  2354.       default:
  2355.  
  2356.         break;
  2357.     }
  2358.     return TRUE;
  2359. }
  2360.  
  2361.  
  2362. /*
  2363.  *  ExclusionPageProc()
  2364.  *
  2365.  *  Purpose:
  2366.  *
  2367.  *      Dispatches window messages to the proper function for processing
  2368.  */
  2369. BOOL CALLBACK
  2370. ExclusionPageProc (HWND hdlg, UINT msg, WPARAM wParam, LPARAM lParam)
  2371. {
  2372.     switch (msg)
  2373.     {
  2374.       case WM_INITDIALOG:
  2375.  
  2376.         FHandleWm (ExclusionPage, hdlg, INITDIALOG, wParam, lParam);
  2377.         return TRUE;
  2378.  
  2379.       case WM_COMMAND:
  2380.  
  2381.         FHandleWm (ExclusionPage, hdlg, COMMAND, wParam, lParam);
  2382.         return TRUE;
  2383.  
  2384.       case WM_NOTIFY:
  2385.  
  2386.         return FHandleWm (ExclusionPage, hdlg, NOTIFY, wParam, lParam);
  2387.     }
  2388.  
  2389.     return FALSE;
  2390. }
  2391.  
  2392.  
  2393. /*
  2394.  *  Out-Of-Office Page Property Sheet -----------------------------------------
  2395.  *  
  2396.  *  The Out-of-office page exposes access to the OOF utility of SMH.  
  2397.  *  The enabling and message text are both modified via this page.
  2398.  *  The corresponding properties are stored in PR_SMH_OOF_ENABLED,
  2399.  *  PR_SMH_OOF_TEXT and PR_SMH_OOF_RTF.
  2400.  *  
  2401.  *  The RTF component of the OOF message uses the RICHEDIT implementation
  2402.  *  that is available as a part of the WIN95 system.
  2403.  */
  2404.  
  2405. /*
  2406.  *  OofPage_INITDIALOG()
  2407.  *
  2408.  *  Purpose:
  2409.  *
  2410.  *      Handles the WM_INITDIALOG message for the filter description dialog
  2411.  */
  2412. BOOL
  2413. OofPage_INITDIALOG (HWND hdlg, HWND hwndFocus, LPARAM lParam)
  2414. {
  2415.     EDITSTREAM es = {0};
  2416.     LPSCD lpscd = (LPSCD)(((PROPSHEETPAGE *)lParam)->lParam);
  2417.     LPFORMATBAR lpfb;
  2418.     RTFS rtfs = {0};
  2419.  
  2420.     CTL3D_Subclass(lpCtl3D, hdlg, CTL3D_ALL);
  2421.     SetWindowLong (hdlg, DWL_USER, ((PROPSHEETPAGE *)lParam)->lParam);
  2422.  
  2423.     if (!FAILED (ScCreateToolbar (lpscd, hdlg, ID_OofText, TRUE, &lpfb)) &&
  2424.         !FAILED (ScNewRicheditCallback (lpfb,
  2425.                                 lpscd->lpfnAlloc,
  2426.                                 lpscd->lpfnAllocMore,
  2427.                                 lpscd->lpfnFree,
  2428.                                 &lpfb->lpreoc)))
  2429.     {
  2430.         SendMessage (GetDlgItem (hdlg, ID_OofText),
  2431.             EM_SETOLECALLBACK,
  2432.             0,
  2433.             (LPARAM)lpfb->lpreoc);
  2434.     }
  2435.  
  2436.     if (lpscd->lpval[ipOofRtf].ulPropTag == PR_SMH_OOF_RTF)
  2437.     {
  2438.         rtfs.cbMax = lpscd->lpval[ipOofRtf].Value.bin.cb;
  2439.         rtfs.lpb = lpscd->lpval[ipOofRtf].Value.bin.lpb;
  2440.         es.pfnCallback = ReadRTFFromBuffer;
  2441.         es.dwCookie = (DWORD)&rtfs;
  2442.         SendMessage (GetDlgItem (hdlg, ID_OofText),
  2443.             EM_STREAMIN,
  2444.             SF_RTF | SFF_SELECTION | SFF_PLAINRTF,
  2445.             (LPARAM)&es);
  2446.     }
  2447.     else if (lpscd->lpval[ipOof].ulPropTag == PR_SMH_OOF_TEXT)
  2448.         Edit_SetText (GetDlgItem (hdlg, ID_OofText), lpscd->lpval[ipOof].Value.LPSZ);
  2449.  
  2450.     if (lpscd->lpval[ipOofEnabled].ulPropTag == PR_SMH_OOF_ENABLED)
  2451.         CheckDlgButton (hdlg, ID_OofEnabled, lpscd->lpval[ipOofEnabled].Value.b);
  2452.     
  2453.     return TRUE;
  2454. }
  2455.  
  2456.  
  2457. /*
  2458.  *  OofPage_NOTIFY()
  2459.  *
  2460.  *  Purpose:
  2461.  *
  2462.  *      Handles the WM_NOTIFY message for the filter description dialog
  2463.  */
  2464. BOOL
  2465. OofPage_NOTIFY (HWND hdlg, UINT id, NMHDR FAR * lpnmhdr)
  2466. {
  2467.     SCODE sc;
  2468.     HWND hctrl;
  2469.     EDITSTREAM es = {0};
  2470.     LPSCD lpscd = (LPSCD)GetWindowLong (hdlg, DWL_USER);
  2471.     RTFS rtfs = {0};
  2472.     SPropValue rgval[3];
  2473.     UINT cb;
  2474.  
  2475.     switch (lpnmhdr->code)
  2476.     {
  2477.       case PSN_KILLACTIVE:
  2478.       case PSN_RESET:
  2479.       case PSN_SETACTIVE:
  2480.       default:
  2481.  
  2482.         break;
  2483.  
  2484.       case PSN_APPLY:
  2485.  
  2486.         DebugTrace ("SMH: saving contents of out-of-office page\n");
  2487.  
  2488.         hctrl = GetDlgItem (hdlg, ID_OofText);
  2489.         cb = Edit_GetTextLength (hctrl) + 1;
  2490.         sc = (*lpscd->lpfnAllocMore) (cb,
  2491.                             lpscd->lpval,
  2492.                             &lpscd->lpval[ipOof].Value.LPSZ);
  2493.         if (!FAILED (sc))
  2494.         {
  2495.             lpscd->lpval[ipOof].ulPropTag = PR_SMH_OOF_TEXT;
  2496.             Edit_GetText (hctrl, lpscd->lpval[ipOof].Value.LPSZ, cb);
  2497.             DebugTrace ("SMH: OOF: text size: %d\n", lstrlen (lpscd->lpval[ipOof].Value.LPSZ));
  2498.  
  2499.             lpscd->lpval[ipOofEnabled].ulPropTag = PR_SMH_OOF_ENABLED;
  2500.             lpscd->lpval[ipOofEnabled].Value.b =
  2501.                 IsDlgButtonChecked (hdlg, ID_OofEnabled);
  2502.  
  2503.             /*  Grab the RTF */
  2504.  
  2505.             rtfs.cbMax = (FAILED ((*lpscd->lpfnAlloc) (cb * 2, &rtfs.lpb))) ? 0 : cb * 2;
  2506.             rtfs.lpfnAlloc = lpscd->lpfnAlloc;
  2507.             rtfs.lpfnFree = lpscd->lpfnFree;
  2508.             es.pfnCallback = WriteRTFToBuffer;
  2509.             es.dwCookie = (DWORD)&rtfs;
  2510.             SendMessage (hctrl, EM_STREAMOUT, SF_RTF | SFF_PLAINRTF, (LPARAM)&es);
  2511.             if (!es.dwError)
  2512.             {
  2513.                 lpscd->lpval[ipOofRtf].ulPropTag = PR_SMH_OOF_RTF;
  2514.                 lpscd->lpval[ipOofRtf].Value.bin.cb = rtfs.cb;
  2515.                 lpscd->lpval[ipOofRtf].Value.bin.lpb = rtfs.lpb;
  2516.                 DebugTrace ("SMH: OOF: RTF size: %ld\n", lpscd->lpval[ipOofRtf].Value.bin.cb);
  2517.             }
  2518.  
  2519.             rgval[0] = lpscd->lpval[ipOof];
  2520.             rgval[1] = lpscd->lpval[ipOofEnabled];
  2521.             rgval[2] = lpscd->lpval[ipOofRtf];
  2522.             sc = GetScode (lpscd->lpsec->lpVtbl->SetProps (lpscd->lpsec,
  2523.                                                         3,
  2524.                                                         rgval,
  2525.                                                         NULL));
  2526.             if (!FAILED (sc))
  2527.                     sc = GetScode (lpscd->lpsec->lpVtbl->SaveChanges (lpscd->lpsec,
  2528.                                                         KEEP_OPEN_READWRITE));
  2529.             (*lpscd->lpfnFree) (rtfs.lpb);
  2530.         }
  2531.         return TRUE;
  2532.  
  2533.       case EN_SELCHANGE:
  2534.  
  2535.         /*  Update the format bar */
  2536.  
  2537.         UpdateFormatBar (GetDlgItem (hdlg, ID_Frame));
  2538.  
  2539.         return FALSE;
  2540.  
  2541.       case PSN_HELP:
  2542.  
  2543.         return TRUE;
  2544.     }
  2545.  
  2546.     return FALSE;
  2547. }
  2548.  
  2549.  
  2550. /*
  2551.  *  OofPage_COMMAND()
  2552.  *
  2553.  *  Purpose:
  2554.  *
  2555.  *      Handles the WM_COMMAND message for the filter description dialog
  2556.  */
  2557. BOOL
  2558. OofPage_COMMAND (HWND hdlg, UINT id, HWND hwndCtl, UINT codeNotify)
  2559. {
  2560.     LPSCD lpscd = (LPSCD)GetWindowLong (hdlg, DWL_USER);
  2561.  
  2562.     if (!FDoRTFCommand (GetDlgItem (hdlg, ID_Frame), id, codeNotify))
  2563.     {
  2564.         switch (id)
  2565.         {
  2566.           case ID_OofText:
  2567.           case ID_OofEnabled:
  2568.  
  2569.             PropSheet_Changed (GetParent (hdlg), hdlg);
  2570.             break;
  2571.         }
  2572.     }
  2573.     return TRUE;
  2574. }
  2575.  
  2576.  
  2577. /*
  2578.  *  OofPageProc()
  2579.  *
  2580.  *  Purpose:
  2581.  *
  2582.  *      Dispatches window messages to the proper function for processing
  2583.  */
  2584. BOOL CALLBACK
  2585. OofPageProc (HWND hdlg, UINT msg, WPARAM wParam, LPARAM lParam)
  2586. {
  2587.     switch (msg)
  2588.     {
  2589.       case WM_INITDIALOG:
  2590.  
  2591.         FHandleWm (OofPage, hdlg, INITDIALOG, wParam, lParam);
  2592.         return TRUE;
  2593.  
  2594.       case WM_COMMAND:
  2595.  
  2596.         FHandleWm (OofPage, hdlg, COMMAND, wParam, lParam);
  2597.         return TRUE;
  2598.  
  2599.       case WM_NOTIFY:
  2600.  
  2601.         return FHandleWm (OofPage, hdlg, NOTIFY, wParam, lParam);
  2602.     }
  2603.  
  2604.     return FALSE;
  2605. }
  2606.  
  2607.  
  2608. /*
  2609.  *  HrDisplayPropSheets()
  2610.  *
  2611.  *  Purpose:
  2612.  *
  2613.  *      Brings up the SMH property sheets.
  2614.  *
  2615.  *  Returns:
  2616.  *
  2617.  *      (HRESULT)
  2618.  */
  2619. HRESULT
  2620. HrDisplayPropSheets (HINSTANCE hinst,
  2621.     HWND hwnd,
  2622.     LPSCD lpscd)
  2623. {
  2624.     HRESULT hr = hrSuccess;
  2625.     CHAR rgch[60] = {0};
  2626.     HINSTANCE hlib;
  2627.     UINT ipg;
  2628.     PROPSHEETPAGE psp[] =
  2629.     {
  2630.         {
  2631.             sizeof(PROPSHEETPAGE),
  2632.             PSP_USETITLE,
  2633.             hinst,
  2634.             MAKEINTRESOURCE(SMH_GeneralPage),
  2635.             NULL,
  2636.             MAKEINTRESOURCE(SMH_GeneralTab),
  2637.             GeneralPageProc,
  2638.             0,
  2639.             NULL,
  2640.             NULL
  2641.         },
  2642.         {
  2643.             sizeof(PROPSHEETPAGE),
  2644.             PSP_USETITLE,
  2645.             hinst,
  2646.             MAKEINTRESOURCE(SMH_FilterPage),
  2647.             NULL,
  2648.             MAKEINTRESOURCE(SMH_FilterTab),
  2649.             FilterPageProc,
  2650.             0,
  2651.             NULL,
  2652.             NULL
  2653.         },
  2654.         {
  2655.             sizeof(PROPSHEETPAGE),
  2656.             PSP_USETITLE,
  2657.             hinst,
  2658.             MAKEINTRESOURCE(SMH_OofPage),
  2659.             NULL,
  2660.             MAKEINTRESOURCE(SMH_OofTab),
  2661.             OofPageProc,
  2662.             0,
  2663.             NULL,
  2664.             NULL
  2665.         },
  2666.         {
  2667.             sizeof(PROPSHEETPAGE),
  2668.             PSP_USETITLE,
  2669.             hinst,
  2670.             MAKEINTRESOURCE(SMH_ExclusionPage),
  2671.             NULL,
  2672.             MAKEINTRESOURCE(SMH_ExclusionTab),
  2673.             ExclusionPageProc,
  2674.             0,
  2675.             NULL,
  2676.             NULL
  2677.         }
  2678.     };
  2679.     PROPSHEETHEADER psh =
  2680.     {
  2681.         sizeof(PROPSHEETHEADER),
  2682.         PSH_PROPSHEETPAGE | PSH_PROPTITLE,
  2683.         hwnd,
  2684.         hinst,
  2685.         NULL,
  2686.         NULL,
  2687.         sizeof(psp) / sizeof(PROPSHEETPAGE),
  2688.         0,
  2689.         (LPCPROPSHEETPAGE)&psp
  2690.     };
  2691.  
  2692.     /*  set property sheet data */
  2693.  
  2694.     for (ipg = 0; ipg < psh.nPages; ipg++)
  2695.         psp[ipg].lParam = (LPARAM)lpscd;
  2696.  
  2697.     hlib = LoadLibrary (RICHEDIT_LIB);
  2698.  
  2699.     if (LoadString (hinst, SMH_ProviderName, rgch, sizeof(rgch)))
  2700.     {
  2701.         if (!lpCtl3D)
  2702.             lpCtl3D = CTL3D_Initialize (hinst);
  2703.         
  2704.         psh.pszCaption = rgch;
  2705.  
  2706.         switch (PropertySheet (&psh))
  2707.         {
  2708.           case -1:
  2709.  
  2710.             hr = ResultFromScode (MAPI_E_CALL_FAILED);
  2711.             break;
  2712.  
  2713.           case 0:
  2714.  
  2715.             hr = ResultFromScode (MAPI_E_USER_CANCEL);
  2716.             break;
  2717.         }
  2718.         
  2719.         if (lpCtl3D)
  2720.         {
  2721.             CTL3D_Uninitialize (lpCtl3D);
  2722.             lpCtl3D = NULL;
  2723.         }
  2724.         
  2725.         UlRelease (lpscd->lpsess);
  2726.         lpscd->lpsess = NULL;
  2727.     }
  2728.     else
  2729.         hr = ResultFromScode (MAPI_E_CALL_FAILED);
  2730.  
  2731.     FreeLibrary (hlib);
  2732.     DebugTraceResult (HrDisplayPropSheets(), hr);
  2733.     return hr;
  2734. }
  2735.