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

  1. /*
  2.  *  S M H C F G . C
  3.  *
  4.  *  Sample mail handling hook configuration
  5.  *  Copyright 1992-95 Microsoft Corporation.  All Rights Reserved.
  6.  */
  7.  
  8. #include "_pch.h"
  9.  
  10. /*
  11.  *  Configuration Properties
  12.  *  
  13.  *  sptConfigProps
  14.  *  
  15.  *      This is the set of properties that we expect to find in the
  16.  *      provider's profile section.
  17.  *  
  18.  *  sptRule
  19.  *  
  20.  *      This is the set of properties that are expected to be found in
  21.  *      each rule's profile section.
  22.  */
  23. const SizedSPropTagArray (cpMax, sptConfigProps) =
  24. {
  25.     cpMax,
  26.     {
  27.         PR_PROFILE_NAME,
  28.         PR_SMH_FLAGS,
  29.         PR_SMH_RULES,
  30.         PR_SMH_RULE_NAMES,
  31.         PR_SMH_OOF_TEXT,
  32.         PR_SMH_OOF_ENABLED,
  33.         PR_SMH_OOF_RTF,
  34.         PR_SMH_SOUND_SCHEMES,
  35.         PR_SMH_REPFWD_SCHEMES,
  36.         PR_SMH_EXCLUSIONS
  37.     }
  38. };
  39. const SizedSPropTagArray (cpRLMax, sptRule) =
  40. {
  41.     cpRLMax,
  42.     {
  43.         PR_DISPLAY_NAME,
  44.         PR_RULE_TYPE,
  45.         PR_RULE_DATA,
  46.         PR_RULE_FLAGS,
  47.         PR_RULE_TARGET_ENTRYID,
  48.         PR_RULE_TARGET_PATH,
  49.         PR_RULE_STORE_ENTRYID,
  50.         PR_RULE_STORE_DISPLAY_NAME,
  51.         PR_RULE_SOUND_LOPRI,
  52.         PR_RULE_SOUND_NORMAL,
  53.         PR_RULE_SOUND_HIPRI,
  54.         PR_RULE_FORWARD_RECIP,
  55.         PR_RULE_FORWARD_RECIP_ENTRYID,
  56.         PR_RULE_REP_FWD_RTF,
  57.         PR_RULE_REP_FWD_TEXT
  58.     }
  59. };
  60.  
  61.  
  62. /*
  63.  *  Configuration event name
  64.  */
  65. const TCHAR lpszConfigEvt[] = "SMH_CONFIGURATION_EVENT";
  66.  
  67.  
  68. /*
  69.  *  HrOpenSingleProvider()
  70.  *  
  71.  *  Purpose:
  72.  *  
  73.  *      Opens the profile section of this service provider.  This is done
  74.  *      by opening the message service table and querying all rows.
  75.  *      Since the SMH service contains only one provider, there is only
  76.  *      one row in the table.  This contains our profile section.  Use
  77.  *      the PR_PROFILE_UID to open the section.
  78.  *  
  79.  *  Arguments:
  80.  *  
  81.  *      lpadmin         the IProfileAdmin object
  82.  *      lppprof [OUT]   on return contains the profile section obj
  83.  *  
  84.  *  Returns:
  85.  *  
  86.  *      (HRESULT)
  87.  *      lppprof [OUT]   contains the profile section object iff the call
  88.  *                      is successful.
  89.  */
  90. HRESULT
  91. HrOpenSingleProvider (LPPROVIDERADMIN lpadmin, LPPROFSECT FAR * lppprof)
  92. {
  93.     HRESULT hr;
  94.     LPMAPITABLE lptbl = NULL;
  95.     LPSRowSet lprws = NULL;
  96.     SPropTagArray sptProvider = {1, {PR_PROVIDER_UID}};
  97.     SRestriction res = {0};
  98.  
  99.     res.rt = RES_EXIST;
  100.     res.res.resExist.ulPropTag = PR_PROVIDER_DLL_NAME;
  101.  
  102.     hr = lpadmin->lpVtbl->GetProviderTable (lpadmin, 0, &lptbl);
  103.     if (!HR_FAILED (hr))
  104.     {
  105.         hr = lptbl->lpVtbl->SetColumns (lptbl, &sptProvider, 0L);
  106.         if (!HR_FAILED (hr))
  107.         {
  108.             hr = lptbl->lpVtbl->Restrict (lptbl, &res, 0);
  109.             if (!HR_FAILED (hr))
  110.             {
  111.                 hr = lptbl->lpVtbl->QueryRows (lptbl, 10, 0, &lprws);
  112.                 if (!HR_FAILED (hr) && lprws->cRows)
  113.                 {
  114.                     Assert (lprws->cRows == 1);
  115.                     Assert (lprws->aRow[0].cValues == 1);
  116.                     Assert (lprws->aRow[0].lpProps);
  117.                     Assert (lprws->aRow[0].lpProps[0].ulPropTag == PR_PROVIDER_UID);
  118.                     hr = lpadmin->lpVtbl->OpenProfileSection (lpadmin,
  119.                         (LPMAPIUID)lprws->aRow[0].lpProps[0].Value.bin.lpb,
  120.                         NULL,
  121.                         MAPI_MODIFY,
  122.                         lppprof);
  123.                     MAPIFreeBuffer (lprws->aRow[0].lpProps);
  124.                 }
  125.                 MAPIFreeBuffer (lprws);
  126.             }
  127.         }
  128.         UlRelease (lptbl);
  129.     }
  130.     DebugTraceResult (HrOpenSingleProvider, hr);
  131.     return hr;
  132. }
  133.  
  134.  
  135. /*
  136.  *  HrMergeValues()
  137.  *  
  138.  *  Purpose:
  139.  *  
  140.  *      Merges two property value arrays into one.  By making a copy of
  141.  *      the first and then adding/replacing props from the second.
  142.  *  
  143.  *      IMPORTANT: if there are any property values that are separately
  144.  *      allocated with either MAPIAllocateBuffer() or MAPIAllocateMore(),
  145.  *      then these property values must remain valid as long as the
  146.  *      merged property array is expected to be valid.
  147.  *  
  148.  *  Returns:
  149.  *  
  150.  *      (HRESULT)
  151.  */
  152. HRESULT
  153. HrMergeValues (ULONG cval1,
  154.     LPSPropValue lpval1,
  155.     ULONG cval2,
  156.     LPSPropValue lpval2,
  157.     LPALLOCATEBUFFER lpfnAlloc,
  158.     ULONG FAR * lpcvalMerged,
  159.     LPSPropValue FAR * lppvalMerged)
  160. {
  161.     SCODE sc;
  162.     LPSPropValue lpval = NULL;
  163.     UINT cb;
  164.     UINT ip;
  165.  
  166.     cb = (UINT)(cval1 + cval2) * sizeof(SPropValue);
  167.     sc = (*lpfnAlloc)(cb, &lpval);
  168.     if (!FAILED (sc))
  169.     {
  170.         /*  Slurp the original data across */
  171.  
  172.         memcpy (lpval, lpval1, (UINT)cval1 * sizeof(SPropValue));
  173.  
  174.         /*  Move the new stuff over */
  175.  
  176.         while (cval2--)
  177.         {
  178.             for (ip = 0; ip < (UINT)cval1; ip++)
  179.             {
  180.                 /*  See if we match properties */
  181.  
  182.                 if (PROP_ID (lpval[ip].ulPropTag) == PROP_ID (lpval2[cval2].ulPropTag))
  183.                 {
  184.                     /*  We matched, but are we a real property */
  185.  
  186.                     if (PROP_TYPE (lpval2[cval2].ulPropTag) != PT_ERROR)
  187.                         lpval[ip] = lpval2[cval2];
  188.                     break;
  189.                 }
  190.             }
  191.             if (ip == cval1)
  192.                 lpval[cval1++] = lpval2[cval2];
  193.         }
  194.         *lpcvalMerged = cval1;
  195.         *lppvalMerged = lpval;
  196.     }
  197.     DebugTraceSc (HrMergeValues(), sc);
  198.     return ResultFromScode (sc);
  199. }
  200.  
  201.  
  202. /*
  203.  *  HrUpdateProfileFormat()
  204.  *  
  205.  *  Purpose:
  206.  *  
  207.  *      Converts the WMS level of SMH profile properties to post WMS
  208.  *      levels.  Namely rules are now stored via a pair of properties
  209.  *      in the profile.  PR_SMH_RULES has been changed to a multi-valued
  210.  *      binary property and PR_SMH_RULE_NAMES contains the display names
  211.  *      for the rules.  The prevents the configuration functions from
  212.  *      opening all profile sections to build the list of rules.
  213.  *  
  214.  *  Arguments:
  215.  *  
  216.  *      lpvOPSCtxt          Context passed to OpenProfileSection()
  217.  *                          (a session or an profadmin object)
  218.  *      lpfnOpenProfSect    Pointer to OpenProfileSection()
  219.  *      lpfnMore            MAPIAllocateMore() function
  220.  *      lpfnFree            MAPIFreeBuffer() function
  221.  *      lpvalNew            propvalue array for the converted values
  222.  *      lpvalOld            propvalue of the old PR_SMH_RULES
  223.  *  
  224.  *  Returns:
  225.  *  
  226.  *      (HRESULT)
  227.  */
  228.  
  229. HRESULT
  230. HrUpdateProfileFormat (LPVOID lpvOPSCtxt,
  231.     LPOPENPROFSECT lpfnOpenProfSect,
  232.     LPALLOCATEMORE lpfnMore,
  233.     LPFREEBUFFER lpfnFree,
  234.     LPSPropValue lpvalNew,
  235.     LPSPropValue lpvalOld)
  236. {
  237.     SCODE sc = S_OK;
  238.     LPMAPIUID lpmuid;
  239.     LPPROFSECT lpsec = NULL;
  240.     LPSBinary lpbin;
  241.     LPSPropValue lpval = NULL;
  242.     LPTSTR FAR * lppsz;
  243.     SizedSPropTagArray (2, spt) = {2, {PR_DISPLAY_NAME, PR_RULE_TYPE}};
  244.     UINT cb;
  245.     UINT crl;
  246.     UINT i;
  247.     ULONG cval;
  248.     
  249.     DebugTrace ("SMH: updating profile to new format\n");
  250.  
  251.     /*  Make sure that the size is an even number of UIDs */
  252.  
  253.     Assert ((lpvalOld->Value.bin.cb % sizeof(MAPIUID)) == 0);
  254.     crl = (UINT)lpvalOld->Value.bin.cb / sizeof(MAPIUID);
  255.  
  256.     /*  Allocate space for the two new properties */
  257.  
  258.     cb = crl * sizeof(SBinary);
  259.     sc = (*lpfnMore) (cb, lpvalNew, &lpbin);
  260.     if (FAILED (sc))
  261.         goto ret;
  262.     memset (lpbin, 0, cb);
  263.     
  264.     cb = crl * sizeof(LPTSTR);
  265.     sc = (*lpfnMore) (cb, lpvalNew, (LPVOID FAR *)&lppsz);
  266.     if (FAILED (sc))
  267.         goto ret;
  268.     memset (lppsz, 0, cb);
  269.     
  270.     /*  Iterate through the old list building the two new lists as we go */
  271.     
  272.     lpmuid = (LPMAPIUID)lpvalOld->Value.bin.lpb;
  273.     for (i = 0; crl--; lpmuid++)
  274.     {
  275.         /*  Open the old profile section and get PR_DISPLAY_NAME
  276.          *  and PR_RULE_TYPE for conversion purposes.  The type
  277.          *  will be converted and reset into the profile section.
  278.          *  Thus, completing the conversion for that section.
  279.          *
  280.          *  The display name will be extracted and copied out to
  281.          *  the external names property and will be saved out when
  282.          *  all section conversions are completed
  283.          */
  284.         if (!HR_FAILED ((*lpfnOpenProfSect) (lpvOPSCtxt, lpmuid, NULL, MAPI_MODIFY, &lpsec)) &&
  285.             !HR_FAILED (lpsec->lpVtbl->GetProps (lpsec, (LPSPropTagArray)&spt, 0, &cval, &lpval)) &&
  286.             !FAILED ((*lpfnMore) (sizeof(MAPIUID), lpvalNew, &lpbin[i].lpb)) &&
  287.             !FAILED ((*lpfnMore) (lstrlen (lpval[0].Value.LPSZ) + 1, lpvalNew, &lppsz[i])))
  288.         {
  289.             switch (lpval[1].Value.l)
  290.             {
  291.               case 1:
  292.                 lpval[1].Value.l = RL_SUBJECT;
  293.                 break;
  294.               case 2:
  295.                 lpval[1].Value.l = RL_SENDER;
  296.                 break;
  297.               case 4:
  298.                 lpval[1].Value.l = RL_HAS_ATTACH;
  299.                 break;
  300.               case 8:
  301.                 lpval[1].Value.l = RL_BODY;
  302.                 break;
  303.               case 16:
  304.                 lpval[1].Value.l = RL_TO_RECIP;
  305.                 break;
  306.               case 32:
  307.                 lpval[1].Value.l = RL_CC_RECIP;
  308.                 break;
  309.               case 64:
  310.                 lpval[1].Value.l = RL_BCC_RECIP;
  311.                 break;
  312.               case 128:
  313.                 lpval[1].Value.l = RL_ANY_RECIP;
  314.                 break;
  315.               case 256:
  316.                 lpval[1].Value.l = RL_MSG_CLASS;
  317.                 break;
  318.             }
  319.             if (!HR_FAILED (HrSetOneProp ((LPMAPIPROP)lpsec, &lpval[1])))
  320.             {
  321.                 DebugTrace ("SMH: converting '%s' rule\n", lpval[0].Value.LPSZ);
  322.                 lpbin[i].cb = sizeof(MAPIUID);
  323.                 memcpy (lpbin[i].lpb, lpmuid, sizeof(MAPIUID));
  324.                 lstrcpy (lppsz[i], lpval[0].Value.LPSZ);
  325.                 i++;
  326.             }
  327.         }
  328.         (*lpfnFree) (lpval);
  329.         UlRelease (lpsec);
  330.         lpval = NULL;
  331.         lpsec = NULL;
  332.     }
  333.     lpvalNew[ipRules].ulPropTag = PR_SMH_RULES;
  334.     lpvalNew[ipRules].Value.MVbin.cValues = i;
  335.     lpvalNew[ipRules].Value.MVbin.lpbin = lpbin;
  336.     lpvalNew[ipNames].ulPropTag = PR_SMH_RULE_NAMES;
  337.     lpvalNew[ipNames].Value.MVSZ.cValues = i;
  338.     lpvalNew[ipNames].Value.MVSZ.LPPSZ = lppsz;
  339.  
  340. ret:
  341.  
  342.     DebugTraceSc (HrUpdateProfileFormat(), sc);
  343.     return ResultFromScode (sc ? sc : ((i == crl) ? 0 : MAPI_W_ERRORS_RETURNED));
  344. }
  345.         
  346.  
  347. /*
  348.  *  HrGetConfigEvent()
  349.  *  
  350.  *  Purpose:
  351.  *  
  352.  *      Gets the configuration event handle.  The handle is used to
  353.  *      signal logged in handlers that their configuration has been
  354.  *      modified and, at the next reasonable chance, should be reloaded.
  355.  *  
  356.  *      Called at SMH init time only.
  357.  *  
  358.  *  Arguments:
  359.  *  
  360.  *      lphevt  [OUT]   contains the handle iff the call succeeds
  361.  *  
  362.  *  Returns:
  363.  *  
  364.  *      (HRESULT)
  365.  */
  366. #ifdef  _WIN32
  367. HRESULT
  368. HrGetConfigEvent (HANDLE FAR * lphevt)
  369. {
  370.     HANDLE hevt = NULL;
  371.         
  372.     if (!(hevt = CreateEvent (NULL, TRUE, FALSE, lpszConfigEvt)) &&
  373.         !(hevt = OpenEvent (EVENT_MODIFY_STATE, FALSE, lpszConfigEvt)))
  374.         ResultFromScode (MAPI_E_NOT_ENOUGH_RESOURCES);
  375.  
  376.     *lphevt = hevt;
  377.     return hrSuccess;
  378. }
  379. #endif  /* _WIN32 */
  380.  
  381.  
  382. /*
  383.  *  SignalConfigChanged()
  384.  *  
  385.  *  Purpose:
  386.  *  
  387.  *      Sets the configuration event such that logged in hooks can update
  388.  *      their configuration on the fly.
  389.  *  
  390.  *      Called from within the service entry when configuration changes
  391.  *      are commited.
  392.  */
  393. #ifdef  _WIN32
  394. VOID
  395. SignalConfigChanged (VOID)
  396. {
  397.     HANDLE hevt = NULL;
  398.     
  399.     if (hevt = OpenEvent (EVENT_MODIFY_STATE, FALSE, lpszConfigEvt))
  400.     {
  401.         SetEvent (hevt);
  402.         CloseHandle (hevt);
  403.     }
  404.     return;
  405. }
  406. #endif  /* _WIN32 */
  407.  
  408.  
  409. /*
  410.  *  FConfigChanged()
  411.  *  
  412.  *  Purpose:
  413.  *  
  414.  *      Tests the configuration event such that logged in hooks can update
  415.  *      their configuration on the fly if the configuration has changed.
  416.  *  
  417.  *      Called from within the SMH object at regualr intervals
  418.  *  
  419.  *  Returns:
  420.  *  
  421.  *      TRUE iff the config changed
  422.  *  
  423.  */
  424. #ifdef  _WIN32
  425. BOOL
  426. FConfigChanged (HANDLE hevt)
  427. {
  428.     ULONG dw;
  429.  
  430.     dw = WaitForSingleObject (hevt, 0);
  431.     Assert (dw != WAIT_ABANDONED);
  432.     return (dw == WAIT_OBJECT_0);
  433. }
  434. #endif  /* _WIN32 */
  435.  
  436.  
  437. /*
  438.  *  SMH_ServiceEntry()
  439.  *  
  440.  *  Purpose:
  441.  *  
  442.  *      The ServiceEntry() function is the MAPI entry point to configure
  443.  *      a service for use in a profile.  The call can then bring up UI to
  444.  *      ensure configuration of the SMH provider.
  445.  *  
  446.  *  Parameters:
  447.  *  
  448.  *      hinst           DLL instance
  449.  *      lpmalloc        OLE style allocator (used by PropSheet())
  450.  *      lpsup           MAPI profile support object
  451.  *      ulUIParam       hwnd that is to be used as UI parent
  452.  *      ulFlags         configuration flags
  453.  *      ulContext       configuration action
  454.  *      cval            count of caller supplied properties
  455.  *      lpval           caller supplied properties to be configured
  456.  *      lpadmin         IProviderAdmin object
  457.  *      lppmerr [OUT]   extended error information
  458.  *  
  459.  *  Operation:
  460.  *  
  461.  *      The ServiceEntry() uses the IProviderAdmin object to open its
  462.  *      profile section and retrieve the current set of properties.  The
  463.  *      caller supplied properties are then merged into the set of
  464.  *      current properties.
  465.  *  
  466.  *      If either this set of properties is not sufficient for
  467.  *      configuration or the caller specifically asked for configuration
  468.  *      UI, then ServiceEntry() will make calls to bring up its config
  469.  *      UI.
  470.  *  
  471.  *      ServiceEntry() recognizes several configuration flags.  If
  472.  *      SERVICE_UI_ALWAYS and/or SERVICE_UI_ALLOWED are set, UI is
  473.  *      allowed and we be brought up if appropriate.  Is
  474.  *      MSG_SERVICE_UI_READ_ONLY is set, then the UI should not 
  475.  *      allow the configuration to be modified.
  476.  *  
  477.  *      The configuration contexts MSG_SERVICE_DELETE, MSG_SERVICE_INSTALL, 
  478.  *      and MSG_SERVICE_UNINSTALL are ignored and no action is taken.
  479.  *      MSG_SERVICE_CONFIGURE and MSG_SERVICE_CREATE allow the caller to
  480.  *      create or update the configuration properties in this providers
  481.  *      profile section. 
  482.  *  
  483.  *      SMH will not return extended information in the MAPIERROR in case
  484.  *      of error
  485.  */
  486. HRESULT STDAPICALLTYPE
  487. SMH_ServiceEntry(
  488.     HINSTANCE hinst,
  489.     LPMALLOC lpmalloc,
  490.     LPMAPISUP lpsup,
  491.     ULONG ulUIParam,
  492.     ULONG ulFlags,
  493.     ULONG ulContext,
  494.     ULONG cval,
  495.     LPSPropValue lpval,
  496.     LPPROVIDERADMIN lpadmin,
  497.     LPMAPIERROR FAR * lppmerr)
  498. {
  499.     HRESULT hr = hrSuccess;
  500.     BOOL fUI = FALSE;
  501.     LPALLOCATEBUFFER lpfnAlloc = NULL;
  502.     LPALLOCATEMORE lpfnAllocMore = NULL;
  503.     LPFREEBUFFER lpfnFree = NULL;
  504.     LPMAPIUID lpmuid = NULL;
  505.     LPPROFSECT lpprof = NULL;
  506.     LPPROFSECT lpprofSvc = NULL;
  507.     LPSCD lpscd = NULL;
  508.     LPSPropValue lpvalCur = NULL;
  509.     LPSPropValue lpvalNew = NULL;
  510.     LPSPropValue lpvalOld;
  511.     SPropValue val;
  512.     UINT csec = 0;
  513.     UINT i;
  514.     ULONG cvalCur;
  515.     ULONG cvalNew;
  516.     ULONG ulMyFlags;
  517.  
  518.     if ((ulContext == MSG_SERVICE_INSTALL) ||
  519.         (ulContext == MSG_SERVICE_UNINSTALL))
  520.         goto ret;
  521.  
  522.     if ((ulContext != MSG_SERVICE_CONFIGURE) &&
  523.         (ulContext != MSG_SERVICE_CREATE) &&
  524.         (ulContext != MSG_SERVICE_DELETE))
  525.     {
  526.         hr = ResultFromScode (MAPI_E_NO_SUPPORT);
  527.         goto ret;
  528.     }
  529.  
  530.     if (ulFlags & MAPI_UNICODE)
  531.     {
  532.         /*  Unicode is not supported by SMH */
  533.  
  534.         hr = ResultFromScode (MAPI_E_BAD_CHARWIDTH);
  535.         goto ret;
  536.     }
  537.  
  538.     /*  Find out our UI options */
  539.  
  540.     fUI = !!(ulFlags & SERVICE_UI_ALWAYS);
  541.     ulMyFlags = (ulFlags & MSG_SERVICE_UI_READ_ONLY)
  542.         ? UI_READONLY
  543.         : 0;
  544.  
  545.     /*  Get memory routines */
  546.  
  547.     hr = lpsup->lpVtbl->GetMemAllocRoutines (lpsup,
  548.                             &lpfnAlloc,
  549.                             &lpfnAllocMore,
  550.                             &lpfnFree);
  551.     if (HR_FAILED (hr))
  552.         goto ret;
  553.  
  554.     /*  Open the profile section */
  555.  
  556.     hr = HrOpenSingleProvider (lpadmin, &lpprof);
  557.     if (HR_FAILED (hr))
  558.         goto ret;
  559.  
  560.     /*  Get the values already in the profile */
  561.  
  562.     hr = lpprof->lpVtbl->GetProps (lpprof,
  563.                             (LPSPropTagArray)&sptConfigProps,
  564.                             0,
  565.                             &cvalCur,
  566.                             &lpvalCur);
  567.     if (HR_FAILED (hr))
  568.         goto ret;
  569.  
  570.     /*  Check that the rules are stored in the correct format */
  571.     
  572.     if (lpvalCur[ipRules].ulPropTag != PR_SMH_RULES)
  573.     {
  574.         hr = HrGetOneProp ((LPMAPIPROP)lpprof,
  575.                     CHANGE_PROP_TYPE(PR_SMH_RULES, PT_BINARY),
  576.                     &lpvalOld);
  577.         if (!HR_FAILED (hr))
  578.         {
  579.             /*  The rules are stored in the wrong format */
  580.  
  581.             hr = HrUpdateProfileFormat (lpadmin,
  582.                             lpadmin->lpVtbl->OpenProfileSection,
  583.                             lpfnAllocMore,
  584.                             lpfnFree,
  585.                             lpvalCur,
  586.                             lpvalOld);
  587.             (*lpfnFree) (lpvalOld);
  588.             if (HR_FAILED (hr))
  589.                 goto ret;
  590.  
  591.             /*  Save out anything we got back */
  592.  
  593.             lpprof->lpVtbl->SetProps (lpprof, cpMax, lpvalCur, NULL);
  594.         }
  595.     }
  596.  
  597.     if (ulContext != MSG_SERVICE_DELETE)
  598.     {
  599.         /*  Merge what was in the profile with what was passed in */
  600.  
  601.         hr = HrMergeValues (cvalCur,
  602.                             lpvalCur,
  603.                             cval,
  604.                             lpval,
  605.                             lpfnAlloc,
  606.                             &cvalNew,
  607.                             &lpvalNew);
  608.         if (HR_FAILED (hr))
  609.             goto ret;
  610.  
  611.         /*  If we dont have all the props we need, then
  612.          *  we will have to ask for them
  613.          */
  614.         fUI = fUI || (lpvalNew[ipFlags].ulPropTag != PR_SMH_FLAGS);
  615.         if ((lpvalNew[ipFlags].ulPropTag != PR_SMH_FLAGS) &&
  616.             (!(ulFlags & (SERVICE_UI_ALLOWED | SERVICE_UI_ALWAYS)) ||
  617.             (ulFlags & MSG_SERVICE_UI_READ_ONLY)))
  618.         {
  619.             /*  We need UI but can't have it. */
  620.  
  621.             hr = ResultFromScode (MAPI_E_UNCONFIGURED);
  622.             goto ret;
  623.         }
  624.  
  625.         if (fUI)
  626.         {
  627.             /*  Do the config dialog */
  628.  
  629.             if (!FAILED ((*lpfnAlloc) (sizeof(SCD), &lpscd)))
  630.             {
  631.                 memset (lpscd, 0, sizeof(SCD));
  632.                 lpscd->hinst = hinst;
  633.                 lpscd->hwnd = (HWND)ulUIParam;
  634.                 lpscd->lpfnAlloc = lpfnAlloc;
  635.                 lpscd->lpfnAllocMore = lpfnAllocMore;
  636.                 lpscd->lpfnFree = lpfnFree;
  637.                 lpscd->lpmalloc = lpmalloc;
  638.                 lpscd->lpval = lpvalNew;
  639.                 lpscd->lpsec = lpprof;
  640.                 lpscd->lpsup = lpsup;
  641.                 lpscd->lpadmin = lpadmin;
  642.                 lpscd->ulFlags = ulMyFlags;
  643.                 hr = HrDisplayPropSheets (hinst, (HWND)ulUIParam, lpscd);
  644.             }
  645.             else
  646.             {
  647.                 hr = ResultFromScode (MAPI_E_NOT_ENOUGH_MEMORY);
  648.                 goto ret;
  649.             }
  650.         }
  651.  
  652.         /*  Open the service profile section and set PR_SERVICE_EXTRA_UIDS */
  653.  
  654.         if (!HR_FAILED (lpadmin->lpVtbl->OpenProfileSection (lpadmin,
  655.                                             NULL,
  656.                                             NULL,
  657.                                             MAPI_MODIFY,
  658.                                             &lpprofSvc)))
  659.         {
  660.             /*  PR_SERVICE_EXTRA_UIDS is composed of all additional
  661.              *  sections used by SMH.  By setting this value, we gain
  662.              *  the ability to have the service copied and\or moved
  663.              *  while having the additional sections move across with
  664.              *  it.
  665.              */
  666.             if (lpvalNew[ipRules].ulPropTag == PR_SMH_RULES)
  667.                 csec += (UINT)lpvalNew[ipRules].Value.MVbin.cValues;
  668.             
  669.             if (csec && !FAILED ((*lpfnAlloc) (csec * sizeof(MAPIUID), &lpmuid)))
  670.             {
  671.                 for (i = 0; i < csec; i++)
  672.                     memcpy (&lpmuid[i],
  673.                         lpvalNew[ipRules].Value.MVbin.lpbin[i].lpb,
  674.                         sizeof(MAPIUID));
  675.  
  676.                 val.ulPropTag = PR_SERVICE_EXTRA_UIDS;
  677.                 val.Value.bin.cb = csec * sizeof(MAPIUID);
  678.                 val.Value.bin.lpb = (LPBYTE)lpmuid;
  679.                 lpprofSvc->lpVtbl->SetProps (lpprofSvc, 1, &val, NULL);
  680.                 lpprofSvc->lpVtbl->SaveChanges (lpprofSvc, 0);
  681.                 (*lpfnFree) (lpmuid);
  682.             }
  683.             UlRelease (lpprofSvc);
  684.         }
  685.     }
  686.     
  687. ret:
  688.  
  689. #ifdef  _WIN32
  690.     if (!HR_FAILED (hr))
  691.         SignalConfigChanged ();
  692. #endif
  693.  
  694.     /*  Cleanup what was left behind */
  695.  
  696.     if (lpscd)
  697.     {   
  698.         for (i = 0; i < lpscd->crl; i++)
  699.         {
  700.             (*lpfnFree) (lpscd->lppsz[i]);
  701.             (*lpfnFree) (lpscd->lpbin[i].lpb);
  702.         }
  703.         (*lpfnFree) (lpscd->lppsz);
  704.         (*lpfnFree) (lpscd->lpbin);
  705.         (*lpfnFree) (lpscd);
  706.     }
  707.                 
  708.     if (lpfnFree)
  709.     {
  710.         (*lpfnFree) (lpvalCur);
  711.         (*lpfnFree) (lpvalNew);
  712.     }
  713.  
  714.     UlRelease (lpprof);
  715.     DebugTraceResult (SMH_ServiceEntry, hr);
  716.     return hr;
  717. };
  718.