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

Windows编程

开发平台:

Visual C++

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