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

Windows编程

开发平台:

Visual C++

  1. /*
  2.  -  X P B A S E . C
  3.  -
  4.  *  Purpose:
  5.  *      The sample transport provider illustrates the use of the MAPI
  6.  *      Transport Service Provider Interface and those parts of the
  7.  *      general SPI involved with the Provider Status, Notification,
  8.  *      and some other stuff.
  9.  *
  10.  *      This module contains the following SPI entry points:
  11.  *
  12.  *          XPProviderInit()
  13.  *          Shutdown()
  14.  *          TransportLogon()
  15.  *          AddressTypes()
  16.  *          RegisterOptions()
  17.  *          TransportLogoff()
  18.  *          TransportNotify()
  19.  *          ValidateState()
  20.  *          FlushQueues()
  21.  *          IUnknown methods for IXPProvider (XPP) & IXPLogon (XPL) objects
  22.  *
  23.  *      Additional support functions found here:
  24.  *
  25.  *          FIsValidSession()
  26.  *          CleanupSession()
  27.  *          ScCheckLogonProps()
  28.  *          HrCheckSpoolerYield()
  29.  *          ScCopySessionProps()
  30.  *          ServiceEntry()
  31.  *          HrOpenSingleProvider()
  32.  *          ScMergeLogonProps()
  33.  *
  34.  *  NOTE:
  35.  *  We have a luxury which most providers don't share: our SPI operations
  36.  *  all occur on a single process context.  This means we don't have to
  37.  *  worry a lot about DLL context, etc. like other providers.
  38.  *
  39.  *  Copyright 1992-1995 Microsoft Corporation.  All Rights Reserved.
  40.  */
  41. #include "xppch.h"
  42. #include "xpresrc.h"
  43. /* On 32-bit, we want MB_SETFOREGROUND on MessageBoxes. */
  44. #ifndef MB_SETFOREGROUND
  45. #define MB_SETFOREGROUND 0
  46. #endif
  47. /*
  48.  *  No bitness in the name of this DLL.  MAPI will handle that.
  49.  */
  50. #define szDLLName   "smpxp.dll"
  51. /* Property Tags of Profile/UI information for a transport session. */
  52. /* NOTE!!! THE ORDERING OF THIS ARRAY MUST BE EXACTLY THE SAME AS THE
  53.    ORDERING OF PROP ID'S IN SMPLXPT.H!!!! */
  54. SizedSPropTagArray(MAX_LOGON_PROPERTIES, sptLogonArray) =
  55. {
  56.     MAX_LOGON_PROPERTIES,
  57.     {
  58.         /* Properties stored in Profile */
  59.         PR_SAMPLE_DISPLAY_NAME,
  60.         PR_SAMPLE_EMAIL_ADDR_TYPE,
  61.         PR_SAMPLE_EMAIL_ADDRESS,
  62.         PR_SAMPLE_INBOUND_DIR,
  63.         PR_SAMPLE_OUTBOUND_DIR,
  64.         PR_SAMPLE_FILENAME,
  65.         PR_SAMPLE_DIRECTORY,
  66.         PR_SAMPLE_FLAGS,
  67.         PR_SAMPLE_LOGFILE,
  68.         PR_SAMPLE_LOGHIGHWATER,
  69.         PR_SAMPLE_LOGLOWWATER,
  70.         /* UI Temporary properties */
  71.         PR_TEMP_PEER_TO_PEER,
  72.         PR_TEMP_UI_ALWAYS,
  73.         PR_TEMP_LOG_EVENTS,
  74.         PR_TEMP_SAVE_DATA,
  75.         PR_TEMP_LOGHIGHWATER,
  76.         PR_TEMP_LOGLOWWATER
  77.     }
  78. };
  79. /* MessageOption & RecipientOption Default Property Value */
  80. static SPropValue spvMsgOpt = {PR_SAMPLE_PER_MSG_DEFER, 0L, FALSE};
  81. static SPropValue spvRecipOpt = {PR_SAMPLE_PER_RECIP_DEFER, 0L, FALSE};
  82. /* Wizard configuration items */
  83. static LPMAPIPROP lpmpWizard = NULL;
  84. enum
  85. {
  86.     ipDispName,
  87.     ipEmailType,
  88.     ipEmailAddress,
  89.     ipInbox,
  90.     ipOutbox,
  91.     ipFilename,
  92.     ipDirectory,
  93.     ipFlags,
  94.     ipLogFile,
  95.     ipLogHigh,
  96.     ipLogLow,
  97.     cWizProps
  98. };
  99. #define cchNameMax  40
  100. #define cchTypeMax  8
  101. /* Virtual Table for the IXPProvider object */
  102. XPP_Vtbl vtblXPP =
  103. {
  104.     XPP_QueryInterface,
  105.     XPP_AddRef,
  106.     XPP_Release,
  107.     XPP_Shutdown,
  108.     XPP_TransportLogon,
  109. };
  110. /* Virtual Table for the IXPLogon object */
  111. XPL_Vtbl vtblXPL =
  112. {
  113.     XPL_QueryInterface,
  114.     XPL_AddRef,
  115.     XPL_Release,
  116.     XPL_AddressTypes,
  117.     XPL_RegisterOptions,
  118.     XPL_TransportNotify,
  119.     XPL_Idle,
  120.     XPL_TransportLogoff,
  121.     XPL_SubmitMessage,
  122.     XPL_EndMessage,
  123.     XPL_Poll,
  124.     XPL_StartMessage,
  125.     XPL_OpenStatusEntry,
  126.     XPL_ValidateState,
  127.     XPL_FlushQueues
  128. };
  129. /* Miscellaneous function prototypes. */
  130. HRESULT HrDeleteDeferred(LPXPL lpxpl, LPSBinary lpsbinEID);
  131. static void CleanupSession(LPXPL lpxpl);
  132. MSGSERVICEENTRY ServiceEntry;
  133. WIZARDENTRY WizardEntry;
  134. SERVICEWIZARDDLGPROC WizardWndProc;
  135. HRESULT HrOpenSingleProvider(LPPROVIDERADMIN, LPPROFSECT FAR *);
  136. SCODE ScMergeLogonProps(ULONG, LPSPropValue, ULONG, LPSPropValue,
  137.     LPALLOCATEBUFFER, LPALLOCATEMORE, LPSPropValue FAR *);
  138. /*
  139.  -  XPProviderInit
  140.  -
  141.  *  Purpose:
  142.  *      Called by the Spooler prior to initiating actual Transport operations.
  143.  *      Only needs to be called once, regardless of the number of sessions
  144.  *      which the Spooler might establish with this Transport provider.
  145.  *
  146.  *  Parameters:
  147.  *      hInstance           Instance of this library
  148.  *      lpMalloc            OLE2 PMALLOC memory allocator
  149.  *      lpAllocateBuffer    MAPIAllocateBuffer
  150.  *      lpAllocateMore      MAPIAllocateMore
  151.  *      lpFreeBuffer        MAPIFreeBuffer
  152.  *      ulFlags             Reserved for now. Should be zero.
  153.  *      ulSpoolerVer        MAPI version the Spooler is implemented to
  154.  *      lpulTransportVer    Transport puts its MAPI version here
  155.  *      lppXPProvider       Transport returns Transport Init Object here
  156.  *
  157.  *  Returns:
  158.  *      SUCCESS_SUCCESS     Transport thinks all is well. Transport's
  159.  *                          version of MAPI has been stored in
  160.  *                          *lpulTransportVer. Transport's Init Object
  161.  *                          address has been stored in *lppEntryPoints.
  162.  *
  163.  *      MAPI_E_VERSION      Transport doesn't like version of Spooler.
  164.  *                          Contents of lpulTransportVer and
  165.  *                          lppXPProvider are untouched by the Transport.
  166.  *
  167.  *      MAPI_E_CALL_FAILED  Transport already inited or session table
  168.  *                          non-empty. Contents of lpulTransportVer and
  169.  *                          lppXPProvider are untouched by the Transport.
  170.  *
  171.  *  Operation:
  172.  *      In the call, the Spooler will tell the Transport what version of MAPI
  173.  *      it normally expects to support. If the Transport knows that it cannot
  174.  *      handle this version, it should return an error on this call. If it
  175.  *      doesn't know, it should trust the Spooler to handle the problem.
  176.  *
  177.  *      The Transport puts the version of MAPI it expects to support back into
  178.  *      lpulTransportVer and the Spooler should Shutdown if it cannot or
  179.  *      doesn't want to handle this version.
  180.  *
  181.  *      Besides the information which the Spooler will use for its half of the
  182.  *      MAPI version handshake, the Transport will return a valid Init Object
  183.  *      address into the location pointed to by lppXPProvider.
  184.  */
  185. STDINITMETHODIMP
  186. XPProviderInit(HINSTANCE hInstance,
  187.     LPMALLOC lpMalloc,
  188.     LPALLOCATEBUFFER lpAllocateBuffer,
  189.     LPALLOCATEMORE lpAllocateMore,
  190.     LPFREEBUFFER lpFreeBuffer,
  191.     ULONG ulFlags,
  192.     ULONG ulSpoolerVer,
  193.     ULONG * lpulTransportVer,
  194.     LPXPPROVIDER * lppXPProvider)
  195. {
  196.     SCODE sc = S_OK;
  197.     LPXPP lpxpp;
  198.     /*  Test Spooler Version. As we are a MAPI 1.0 transport, we'll
  199.         accept any MAPI version over 1.0 (and trust the Spooler to
  200.         refuse to handle 1.0 if he's too far advanced!)
  201.     */
  202.     if (ulSpoolerVer < CURRENT_SPI_VERSION)
  203.     {
  204.         sc = MAPI_E_VERSION;
  205.         DebugTrace("Spooler version check failed.n");
  206.         goto ret;
  207.     }
  208.     /*  Allocate space for the XPP structure */
  209.     sc = (*lpAllocateBuffer) (sizeof(XPP), (LPVOID *) &lpxpp);
  210.     if (sc)
  211.     {
  212.         DebugTrace("XPProvider allocation failed.n");
  213.         goto ret;
  214.     }
  215.     /*  Fill in the data members and the jump table. */
  216.     lpxpp->lpVtbl = &vtblXPP;
  217.     lpxpp->lcInit = 1;
  218.     lpxpp->lpxppMyAddress = lpxpp;
  219.     lpxpp->hInst = hInstance;
  220.     lpxpp->XPSessionList = (LPXPL) NULL;
  221.     lpxpp->fInited = TRUE;
  222.     lpxpp->lpMalloc = lpMalloc;
  223.     lpxpp->lpFreeBuffer = lpFreeBuffer;
  224.     /* We're keeping it, we need to AddRef it! */
  225.     UlAddRef(lpMalloc);
  226.     /*  Initialize a critical section to be used while:
  227.             1. Accessing the Status Object
  228.             2. Doing session list management
  229.             3. Initializing the logging sub-system
  230.             4. Processing a TransportNotify call
  231.         These are areas where the potential for re-entrancy
  232.         is high and we need to protect ourselves.
  233.     */
  234.     InitializeCriticalSection(&lpxpp->csTransport);
  235.     /*  Return version number and IXPProvider object to the Spooler. */
  236.     *lpulTransportVer = CURRENT_SPI_VERSION;
  237.     *lppXPProvider = (LPXPPROVIDER) lpxpp;
  238. ret:
  239.     DebugTraceSc(XPProviderInit, sc);
  240.     return ResultFromScode(sc);
  241. }
  242. /*
  243.  -  lpxpp->lpVtbl->Shutdown
  244.  -
  245.  *  Purpose:
  246.  *      Called by the Spooler when all operations on a Transport are complete.
  247.  *      Only needs to be called once, regardless of the number of sessions
  248.  *      which the Spooler might have established with this Transport provider.
  249.  *
  250.  *  Parameters:
  251.  *      lpulFlags           Contains flags passed from Spooler:
  252.  *
  253.  *                          DEINIT_NORMAL indicates a normal
  254.  *                          operation. All cleanup should proceed
  255.  *                          at whatever pace is required for
  256.  *                          completeness.
  257.  *
  258.  *                          DEINIT_HURRY indicates rapid shutdown.
  259.  *                          Anything that can be done very quickly
  260.  *                          should be done; time-consuming operations
  261.  *                          are to be avoided.
  262.  *
  263.  *                          In the absence of these flag bits, the
  264.  *                          Transport should assume DEINIT_NORMAL.
  265.  *
  266.  *  Returns:
  267.  *      SUCCESS_SUCCESS     Transport has done all cleanup. Go ahead
  268.  *                          and release it.
  269.  *
  270.  *      MAPI_E_CALL_FAILED  Transport hasn't been inited or has
  271.  *                          already been deinited.
  272.  *
  273.  *  Operation:
  274.  *      This call normally will happen if the Spooler doesn't like the
  275.  *      Transport version passed in from XPProviderInit; if the Spooler
  276.  *      attempts to log into the Transport and fails; and after a
  277.  *      TransportLogoff.
  278.  *
  279.  *      If there are any sessions active in this process, the Transport
  280.  *      should clean them up (propagating the DEINIT_HURRY down to
  281.  *      LOGOFF_HURRY in the TransportLogoff flags) before returning.
  282.  *
  283.  *      The Spooler guarantees non-reentrancy on this call.
  284.  */
  285. STDMETHODIMP
  286. XPP_Shutdown(LPXPP lpxpp, ULONG FAR * lpulFlags)
  287. {
  288.     LPXPL lpxpl = NULL;
  289.     ULONG ulFlags;
  290.     HRESULT hResult = hrSuccess;
  291.     /*  Walk down the session list. Log off any active sessions.
  292.         NOTE: IT IS *REALLY* IMPORTANT THAT ANY WORK DONE TO CHANGE
  293.         THE WAY THIS LIST IS WALKED OR RELINKED BY LOGOFF BE DONE IN
  294.         SUCH A WAY THAT BOTH THIS CODE AND THE TRANSPORTLOGOFF CODE
  295.         CONTINUE TO WORK CORRECTLY!!
  296.     */
  297.     /* Get the Critical Section */
  298.     EnterCriticalSection(&lpxpp->csTransport);
  299.     lpxpl = lpxpp->XPSessionList;
  300.     ulFlags = (*lpulFlags & DEINIT_HURRY) ? LOGOFF_HURRY : LOGOFF_NORMAL;
  301.     while (lpxpl)
  302.     {
  303.         LPXPL lpNext = lpxpl->lpNextSession;
  304.         hResult = XPL_TransportLogoff(lpxpl, ulFlags);
  305.         if (hResult)
  306.         {
  307.             DebugTrace("Logging off session failed.n");
  308.             /*
  309.              * A logoff failed. If we are in HURRY mode, we'll let it
  310.              * go. Otherwise, we pass the error along and get out!
  311.              */
  312.             if (!(*lpulFlags & DEINIT_HURRY))
  313.             {
  314.                 DebugTrace("Returning Logoff result to caller.n");
  315.                 /*
  316.                  * Relink the listhead so that everything has some
  317.                  * degree of internal consistency.
  318.                  */
  319.                 lpxpp->XPSessionList = lpxpl;
  320.                 goto ret;
  321.             }
  322.             DebugTrace("DEINIT_HURRY set, deallocating session and proceeding.n");
  323.             CleanupSession(lpxpl);
  324.         }
  325.         lpxpl->lpVtbl->Release(lpxpl);
  326.         lpxpl = lpNext;
  327.     }
  328.     /* Release the Critical Section */
  329.     LeaveCriticalSection(&lpxpp->csTransport);
  330.     /* Delete critical section which XPProviderInit() initialized. */
  331.     DeleteCriticalSection(&lpxpp->csTransport);
  332.     lpxpp->XPSessionList = NULL;
  333.     lpxpp->fInited = FALSE;
  334.     *lpulFlags = 0;
  335. ret:
  336.     /* Turn off logging if active */
  337.     DeInitTransportLog((*lpulFlags & DEINIT_HURRY) ? LOG_DEINIT_HURRY : 0L);
  338.     DebugTraceResult(XPP_Shutdown, hResult);
  339.     return hResult;
  340. }
  341. /*
  342.  -  lpxpp->lpVtbl->TransportLogon
  343.  -
  344.  *  Purpose:
  345.  *      Called by the Spooler to establish a session with a Transport.
  346.  *      This call might be made many times, once for each session the Spooler
  347.  *      wants to establish with an external messaging system through this
  348.  *      Transport. These multiple sessions will usually be established on a
  349.  *      one-for-one basis with the number of identities which the current
  350.  *      profile has established for the given messaging system.
  351.  *
  352.  *  Parameters:
  353.  *      lpxpp               The parent XPProvider object who will
  354.  *                          own this new session.
  355.  *
  356.  *      lpMAPISup           A pointer to a MAPI Support Object which
  357.  *                          is uniquely associated with this session
  358.  *                          by the Spooler. Any MAPI Support calls
  359.  *                          associated with this session should be
  360.  *                          done using this Support Object.
  361.  *
  362.  *      ulUIParam           The hWnd who will become the parent of any
  363.  *                          UI we decide to put up (like a logon dialog).
  364.  *
  365.  *      lpszProfileName     Contains a display name associated with the
  366.  *                          current user's profile.  Expected to be
  367.  *                          used by the Transport primarily to make
  368.  *                          any UI easier for the user to decipher.
  369.  *
  370.  *      lpulFlags           (In)
  371.  *
  372.  *                          Flags passed from Spooler to Transport:
  373.  *
  374.  *                          LOGON_NO_DIALOG instructs the Transport
  375.  *                          not to put any UI up during this operation.
  376.  *                          If the operation cannot be completed
  377.  *                          without UI, an error should be returned.
  378.  *
  379.  *                          LOGON_NO_CONNECT is set by the Spooler
  380.  *                          when the transport connection is being
  381.  *                          made in order to do things like get
  382.  *                          per-message/per-recipient options; using
  383.  *                          preprocessor stuff, etc -- but to do so
  384.  *                          "offline". The Transport is not to connect
  385.  *                          to the outside world, and if there are
  386.  *                          insufficient credentials to allow the
  387.  *                          Transport to operate as if the user should
  388.  *                          be permitted access, the Transport may
  389.  *                          wish to fail without presenting UI.
  390.  *
  391.  *                          LOGON_NO_INBOUND is set by the Spooler
  392.  *                          to signal the Transport not to accept
  393.  *                          incoming mail on this session. The Spooler
  394.  *                          will ignore the NOTIFY_NEWMAIL flag on
  395.  *                          SpoolerNotify() and it will not Poll()
  396.  *                          the Transport on this session. It's OK
  397.  *                          to make external connections for reasons
  398.  *                          other than mail reception. The Spooler
  399.  *                          may TransportNotify() to enable inbound.
  400.  *
  401.  *                          LOGON_NO_OUTBOUND is set by the Spooler
  402.  *                          to signal the Transport that outgoing
  403.  *                          mail won't be sent right now on this
  404.  *                          session. The Spooler will ignore the
  405.  *                          NOTIFY_READYTOSEND flag on SpoolerNotify()
  406.  *                          and will not be calling SubmitMessage().
  407.  *                          It's OK to make external connections for
  408.  *                          reasons other than mail transmission. The
  409.  *                          Spooler may TransportNotify() to signal
  410.  *                          the start of outbound operations.
  411.  *  Returns:
  412.  *      lpulFlags           (Out)
  413.  *
  414.  *                          Flags passed from Transport to Spooler:
  415.  *
  416.  *                          LOGON_SP_IDLE tells the Spooler to call
  417.  *                          the Idle() entry point with this logon
  418.  *                          handle as part of its idle processing.
  419.  *                          The transport may use this to check its
  420.  *                          underlying messaging system for incoming
  421.  *                          mail, to do special processing outside
  422.  *                          of the SPI, or maybe some kind of network
  423.  *                          link maintenance, for example.
  424.  *
  425.  *                          LOGON_SP_POLL instructs the Spooler to
  426.  *                          call the Transport at its Poll() entry
  427.  *                          point on a regular basis to see if any
  428.  *                          new mail is ready for import into the
  429.  *                          MAPI subsystem.
  430.  *
  431.  *                          LOGON_SP_RESOLVE instructs the Spooler
  432.  *                          and MAPI to ensure that all addresses in
  433.  *                          an outgoing message's recipient table are
  434.  *                          fully resolved before this transport is
  435.  *                          given the message. This could be used by
  436.  *                          a transport to make a best-guess routing
  437.  *                          from a recipient's system to allow a given
  438.  *                          recipient to include all other recipients
  439.  *                          of a message in a reply ("Reply-All").
  440.  *
  441.  *      lppXPLogon          Contains a pointer to the Transport
  442.  *                          Logon object (an instance of IXPLogon)
  443.  *                          that is used to access the session we
  444.  *                          just created.
  445.  *
  446.  *      MAPI_E_UNCONFIGURED Something's wrong with credentials or
  447.  *                          other things needed for logon. We're
  448.  *                          not really saying what.
  449.  *
  450.  *  Operation:
  451.  *      The Spooler makes this call when it wants to establish a session with
  452.  *      the Transport provider. When called here, the Transport will need to
  453.  *      perform several actions:
  454.  *
  455.  *  1) Get credentials out of the profile.
  456.  *
  457.  *  2)  Determine if credentials are sufficient. Some providers may choose
  458.  *      to just send along what they have to the host and let validation
  459.  *      happen there; others will want to determine that credentials have
  460.  *      some validity before setting off breakin alarms on a mail host system.
  461.  *
  462.  *  3) If credentials are insufficient, return MAPI_E_UNCONFIGURED.
  463.  *
  464.  *  4) Validate credentials. This may involve establishing a connection to the
  465.  *     underlying messaging system and allowing it to determine that the
  466.  *     credentials are OK.
  467.  *
  468.  *  5) If credentials not OK, the Transport provider should return
  469.  *     MAPI_E_UNCONFIGURED.  This will reuqest that MAPI calls the ServiceEntry
  470.  *     point to obtain the missing configuration information.
  471.  *
  472.  *  6) Save credentials. The profile section made available to the Transport
  473.  *     Provider can be used to store this information if so indicated.
  474.  *
  475.  *      Transports that are less concerned about security may leave out any or
  476.  *      all of the above.
  477.  *
  478.  *  7) Build the logon object.
  479.  *
  480.  *  8) Construct a Status Table row and call ModifyStatusRow().
  481.  *
  482.  *  9) Link the logon object into the list for the transport.
  483.  *
  484.  * 10) Start up logger if need be
  485.  *
  486.  * 11) Log completion of logon operation.
  487.  *
  488.  *
  489.  *  Note:
  490.  *      There are some parameters stored at the session level (in the
  491.  *      profile) that are more global in nature, such as the logging stuff
  492.  *      and peer-to-peer. The way we will resolve this is to interpret new
  493.  *      information in the light of old stuff, favoring the "on" state. So
  494.  *      a session that says "no logging" will in fact not be logged only if
  495.  *      not preceded by a session with logging on, and the session will be
  496.  *      logged as soon as a session that specifies logging comes online. The
  497.  *      inbound and outbound paths will be respected; the first logfile name
  498.  *      will rule.  A session that didn't want to be peer-to-peer could have
  499.  *      its way among lots of peer-to-peer transports by specifying a
  500.  *      different outbound path.
  501.  *
  502.  */
  503. STDMETHODIMP
  504. XPP_TransportLogon(LPXPP lpxpp,
  505.     LPMAPISUP lpMAPISup,
  506.     ULONG ulUIParam,
  507.     LPTSTR lpszProfileName,
  508.     ULONG * lpulFlags,
  509.     LPMAPIERROR * lppMapiError,
  510.     LPXPLOGON FAR * lppXPLogon)
  511. {
  512.     LPSPropValue lpPropArray = NULL;
  513.     LPSPropValue lpMyIDArray = NULL;
  514.     LPVOID lpvT, lpvT2;
  515.     ULONG ulCount = 0;
  516.     ULONG ulT;
  517.     SCODE sc = 0;
  518.     HRESULT hResult = 0;
  519.     LPXPL lpxpl = NULL;
  520.     LPPROFSECT lpProfileObj = NULL;
  521.     LPOPTIONDATA lpOptData = NULL;
  522.     LPALLOCATEBUFFER lpAllocBuffer;
  523.     LPALLOCATEMORE lpAllocMore;
  524.     LPFREEBUFFER lpFreeBuffer;
  525.     BOOL fNeedUI = FALSE;
  526.     BOOL fInitialParamsOk = TRUE;
  527.     *lppMapiError = NULL;
  528.     if ( *lpulFlags & MAPI_UNICODE )
  529.         return ResultFromScode( MAPI_E_BAD_CHARWIDTH ) ;
  530.     /*  Get the memory allocation routines we'll be needing. */
  531.     hResult = lpMAPISup->lpVtbl->GetMemAllocRoutines(lpMAPISup,
  532.         &lpAllocBuffer, &lpAllocMore, &lpFreeBuffer);
  533.     if (hResult)
  534.     {
  535.         DebugTrace("GetMemAllocRoutines failed in XP Logon.n");
  536.         goto ret;
  537.     }
  538.     /* Try to open our profile. */
  539.     hResult = lpMAPISup->lpVtbl->OpenProfileSection(lpMAPISup,
  540.         (LPMAPIUID) NULL, MAPI_MODIFY, &lpProfileObj);
  541.     if (hResult)
  542.     {
  543.         DebugTrace("OpenProfileSection failed in XP Logon.n");
  544.         goto ret;
  545.     }
  546.     /* Profile is open, get the properties out of it. */
  547.     hResult = lpProfileObj->lpVtbl->GetProps(lpProfileObj,
  548.         (LPSPropTagArray) &sptLogonArray, 0, /* ansi */
  549.         &ulCount, &lpPropArray);
  550.     if (hResult)
  551.     {
  552. #ifdef DEBUG
  553.         LPMAPIERROR lpMapiError = NULL;
  554.         DebugTrace("GetProps failed in XP Logon.n");
  555.         lpProfileObj->lpVtbl->GetLastError(lpProfileObj, hResult,
  556.             0L, &lpMapiError);
  557.         if ( lpMapiError && lpMapiError->lpszError )
  558.         {
  559.             DebugTrace(lpMapiError->lpszError);
  560.             DebugTrace("n");
  561.             lpFreeBuffer((LPVOID) lpMapiError);
  562.         }
  563. #endif
  564.         /* Couldn't read all of the properties. We'll recover
  565.            from the error by just bringing up UI if allowed. */
  566.         hResult = hrSuccess;
  567.     }
  568.     /* Profile is open. Get all of our expected properties. */
  569.     Assert(ulCount == MAX_LOGON_PROPERTIES);
  570.     ulCount -= TEMP_LOGON_PROPERTIES;
  571.     Assert(ulCount < MAX_LOGON_PROPERTIES);
  572.     /* Make sure that we have the properties we want. If not, signal the
  573.        need for UI.
  574.        We could also check that network paths etc. exist at this point. */
  575.     if (lpPropArray)
  576.     {
  577.         XPDLG       XPDialog;
  578.         fNeedUI = FALSE;        /* Default to saying we have what we need */
  579.         for (ulT = 0; ulT < ulCount; ulT++)
  580.         {
  581.             /* If any of the properties is PT_ERROR, we need to
  582.                bring up UI. */
  583.             if (PROP_TYPE(lpPropArray[ulT].ulPropTag) == PT_ERROR)
  584.             {
  585.                 fNeedUI = TRUE;
  586.                 break;
  587.             }
  588.         }
  589.         /* The configuration checking assumes that the information came from
  590.            a dialog box, so we have to look like a dialog box to use it. */
  591.         XPDialog.hInst = NULL;
  592.         XPDialog.hwnd = (HWND) ulUIParam;
  593.         XPDialog.lppPropArray = &lpPropArray;
  594.         XPDialog.lpPTArray = (LPSPropTagArray) &sptLogonArray;
  595.         XPDialog.AllocateBuffer = lpAllocBuffer;
  596.         XPDialog.AllocateMore = lpAllocMore;
  597.         XPDialog.FreeBuffer = lpFreeBuffer;
  598.         XPDialog.lpMalloc = NULL;
  599.         XPDialog.lpMAPISup = lpMAPISup;
  600.         XPDialog.fLogon = TRUE;
  601.         XPDialog.ulFlags = 0;
  602.         /* Do some simple validation of the Logon Props */
  603.         sc = ScCheckLogonProps(&XPDialog, FALSE);
  604.         if ((sc == MAPI_E_USER_CANCEL) || (sc == MAPI_E_UNCONFIGURED))
  605.             fNeedUI = TRUE;
  606.     }
  607.     else
  608.         fNeedUI = TRUE;         /* No prop array means we need UI */
  609.     /* Now we have a local flag that will tell us whether UI must be
  610.        presented. We should consider it a "I require data to complete
  611.        logon" state as well. At this point, act on the LOGON_NO_DIALOG
  612.        flag and error out if we are not allowed to present UI but we
  613.        have some reason for wanting it. */
  614.     if (fNeedUI)
  615.     {
  616.         /* Fill in the logon UI structure */
  617.         hResult = ResultFromScode(MAPI_E_UNCONFIGURED);
  618.         DebugTrace("Need UI, returning MAPI_E_UNCONFIGURED to get some.n");
  619.         goto ret;
  620.     }
  621.     /* Create the session structure and copy important data into it */
  622.     sc = lpAllocBuffer(sizeof(XPL), (LPVOID *) &lpxpl);
  623.     if (sc)
  624.     {
  625.         hResult = ResultFromScode(sc);
  626.         DebugTrace("Allocating XPLogon object failed in XP Logon.n");
  627.         goto ret;
  628.     }
  629.     memset(lpxpl, 0, sizeof(XPL));
  630.     lpxpl->lpVtbl = &vtblXPL;
  631.     lpxpl->lcInit = 1;
  632.     lpxpl->lpMySession = lpxpl; /* Used to validate structure */
  633.     lpxpl->lpxppParent = lpxpp;
  634.     lpxpl->lpMAPISup = lpMAPISup;   /* Copy of our support object */
  635.     lpxpl->AllocateBuffer = lpAllocBuffer;
  636.     lpxpl->AllocateMore = lpAllocMore;
  637.     lpxpl->FreeBuffer = lpFreeBuffer;
  638.     lpxpl->ulSessionFlags = *lpulFlags; /* Important session flags*/
  639.     lpxpl->cLogonPropValues = ulCount;  /* Count of logon properties */
  640.     lpxpl->lpPropArray = lpPropArray;   /* Array of properties */
  641.     lpxpl->lpMyIDArray = NULL;  /* Transport ID */
  642.     lpxpl->fRefSupport = FALSE;
  643.     /* Figure out what the initial status of the transport will be */
  644.     if ((*lpulFlags & LOGON_NO_CONNECT))
  645.     {
  646.         lpxpl->ulTransportStatus = STATUS_OFFLINE;
  647.     }
  648.     else
  649.     {
  650.         lpxpl->ulTransportStatus = STATUS_AVAILABLE;
  651.         if (!(*lpulFlags & LOGON_NO_INBOUND))
  652.             lpxpl->ulTransportStatus |= STATUS_INBOUND_ENABLED;
  653.         if (!(*lpulFlags & LOGON_NO_OUTBOUND))
  654.             lpxpl->ulTransportStatus |= STATUS_OUTBOUND_ENABLED;
  655.     }
  656.     /* Initialize Status object ResourceMethods.  FlushQueues
  657.        and SettingsDialog are currently implemented */
  658.     lpxpl->ulResourceMethods = STATUS_SETTINGS_DIALOG | STATUS_FLUSH_QUEUES;
  659.     /* Initialize message send/receive state */
  660.     lpxpl->fFoundInMessage = FALSE;
  661.     lpxpl->hInFindHandle = INVALID_HANDLE_VALUE;
  662.     lpxpl->hOutFindHandle = INVALID_HANDLE_VALUE;
  663.     /* Allocate and initialize the Message & Recipient OptionData struct */
  664.     sc = lpAllocBuffer(2 * sizeof(OPTIONDATA), (LPVOID *) &lpOptData);
  665.     if (sc)
  666.     {
  667.         hResult = ResultFromScode(sc);
  668.         DebugTrace("Allocating OPTIONDATA failed in XP Logon.n");
  669.         goto ret;
  670.     }
  671.     /* Option Data is registered by Address Type.  In the SettingsDialog()
  672.        call on the Status object we force the email address type field to
  673.        be read-only.  This ensures that this OptionData remains valid for
  674.        the duration of this session.
  675.        NOTE:    The ulOrdinal must match the value assigned in the .DEF file.
  676.                 If this value changes, it must be changed here and in the
  677.                 .DEF file to the same value! */
  678.     lpOptData[0].ulFlags = OPTION_TYPE_MESSAGE;
  679.     lpOptData[0].lpRecipGUID = NULL;
  680.     lpOptData[0].lpszAdrType = ArrayIndex(PR_SAMPLE_EMAIL_ADDR_TYPE, lpPropArray).Value.LPSZ;
  681.     lpOptData[0].lpszDLLName = szDLLName;
  682.     lpOptData[0].ulOrdinal = 3;
  683.     lpOptData[0].cbOptionsData = 0;
  684.     lpOptData[0].lpbOptionsData = NULL;
  685.     lpOptData[0].cOptionsProps = 1;
  686.     lpOptData[0].lpOptionsProps = &spvMsgOpt;
  687.     lpOptData[1].ulFlags = OPTION_TYPE_RECIPIENT;
  688.     lpOptData[1].lpRecipGUID = NULL;
  689.     lpOptData[1].lpszAdrType = ArrayIndex(PR_SAMPLE_EMAIL_ADDR_TYPE, lpPropArray).Value.LPSZ;
  690.     lpOptData[1].lpszDLLName = szDLLName;
  691.     lpOptData[1].ulOrdinal = 3;
  692.     lpOptData[1].cbOptionsData = 0;
  693.     lpOptData[1].lpbOptionsData = NULL;
  694.     lpOptData[1].cOptionsProps = 1;
  695.     lpOptData[1].lpOptionsProps = &spvRecipOpt;
  696.     lpxpl->cOptData = 2;
  697.     lpxpl->lpOptData = lpOptData;
  698.     lpOptData = NULL;
  699.     /* Allocate initial property array for transport ID. */
  700.     sc = lpAllocBuffer(sizeof(SPropValue) * NUM_SENDER_PROPS,
  701.             (LPVOID *) &lpMyIDArray);
  702.     if (sc)
  703.     {
  704.         hResult = ResultFromScode(sc);
  705.         DebugTrace("Allocating Sender ID array failed in XP Logon.n");
  706.         goto ret;
  707.     }
  708.     /* Zero the memory and hook it into the logon object now.  That
  709.        way, if we get a failure between here and ret: then this
  710.        memory will be freed in CleanupSession(). */
  711.     memset(lpMyIDArray, 0, sizeof(SPropValue) * NUM_SENDER_PROPS);
  712.     lpxpl->lpMyIDArray = lpMyIDArray;
  713.     /* Create the One-Off directly into the property value structure. */
  714.     lpMyIDArray[0].ulPropTag = PR_SENDER_ENTRYID;
  715.     hResult = lpMAPISup->lpVtbl->CreateOneOff(lpMAPISup,
  716.         ArrayIndex(PR_SAMPLE_DISPLAY_NAME, lpPropArray).Value.LPSZ,
  717.         ArrayIndex(PR_SAMPLE_EMAIL_ADDR_TYPE, lpPropArray).Value.LPSZ,
  718.         ArrayIndex(PR_SAMPLE_EMAIL_ADDRESS, lpPropArray).Value.LPSZ,
  719.         fMapiUnicode,
  720.         &lpMyIDArray[0].Value.bin.cb,
  721.         (LPENTRYID *) &lpMyIDArray[0].Value.bin.lpb);
  722.     if (hResult)
  723.     {
  724.         DebugTrace("CreateOneOff failed in XP Logon.n");
  725.         lpMyIDArray[0].Value.bin.lpb = NULL;
  726.         goto ret;
  727.     }
  728.     /* Create the PR_SENDER_NAME property value. */
  729.     lpMyIDArray[1].ulPropTag = PR_SENDER_NAME;
  730.     lpvT2 = ArrayIndex(PR_SAMPLE_DISPLAY_NAME, lpPropArray).Value.LPSZ;
  731.     ulT = (lstrlen((LPCTSTR) lpvT2) + 1) * sizeof(TCHAR);
  732.     sc = lpAllocMore(ulT, (LPVOID) lpMyIDArray, &lpvT);
  733.     if (sc)
  734.     {
  735.         hResult = ResultFromScode(sc);
  736.         DebugTrace("Allocating user DisplayName failed in XP Logon.n");
  737.         goto ret;
  738.     }
  739.     lstrcpy((LPTSTR) lpvT, (LPCTSTR) lpvT2);
  740.     lpMyIDArray[1].Value.LPSZ = (LPTSTR) lpvT;
  741.     /* Create the PR_SENDER_SEARCH_KEY value. */
  742.     lpMyIDArray[2].ulPropTag = PR_SENDER_SEARCH_KEY;
  743.     /* Size of property = type plus colon plus address plus null. */
  744.     ulT = 2 + lstrlen(ArrayIndex(PR_SAMPLE_EMAIL_ADDR_TYPE, lpPropArray).Value.LPSZ) +
  745.           lstrlen(ArrayIndex(PR_SAMPLE_EMAIL_ADDRESS, lpPropArray).Value.LPSZ);
  746.     ulT *= sizeof(TCHAR);
  747.     sc = lpAllocMore(ulT, (LPVOID) lpMyIDArray, &lpvT);
  748.     if (sc)
  749.     {
  750.         hResult = ResultFromScode(sc);
  751.         DebugTrace("Allocating SearchKey failed in XP Logon.n");
  752.         goto ret;
  753.     }
  754.     /* PR_SENDER_SEARCH_KEY is "TYPE:ADDRESS" folded to uppercase. */
  755.     wsprintf((LPTSTR) lpvT, TEXT("%s:%s"),
  756.             ArrayIndex(PR_SAMPLE_EMAIL_ADDR_TYPE, lpPropArray).Value.LPSZ,
  757.             ArrayIndex(PR_SAMPLE_EMAIL_ADDRESS, lpPropArray).Value.LPSZ);
  758.     CharUpperBuff((LPTSTR) lpvT, (UINT) ulT-sizeof(TCHAR));
  759.     lpMyIDArray[2].Value.bin.cb = ulT;
  760.     lpMyIDArray[2].Value.bin.lpb = lpvT;
  761.     /* Register the preprocessor */
  762.     hResult = lpMAPISup->lpVtbl->RegisterPreprocessor (lpMAPISup, NULL,
  763.         ArrayIndex(PR_SAMPLE_EMAIL_ADDR_TYPE, lpPropArray).Value.LPSZ,
  764. #ifdef  WIN16
  765.         "SMPXP.DLL",
  766. #else
  767.         "SMPXP32.DLL",
  768. #endif
  769.         "PreprocessMessage", "RemovePreprocessInfo", 0L);
  770.     if (hResult)
  771.     {
  772.         DebugTrace("RegisterPreprocessor failed in XP Logon.n");
  773.         goto ret;
  774.     }
  775.     /* Get the Critical Section */
  776.     EnterCriticalSection(&lpxpp->csTransport);
  777.     /* Build the status row and register it */
  778.     hResult = HrBuildTransportStatus(lpxpl, 0L);
  779.     if (hResult)
  780.     {
  781.         DebugTrace("HrBuildTransportStatus failed in XP Logon.n");
  782.         LeaveCriticalSection(&lpxpp->csTransport);
  783.         goto ret;
  784.     }
  785.     /* Link the session structure into the list. */
  786.     lpxpl->lpNextSession = lpxpp->XPSessionList;
  787.     lpxpp->XPSessionList = lpxpl;
  788.     /* AddRef() the support object. */
  789.     lpMAPISup->lpVtbl->AddRef(lpMAPISup);
  790.     lpxpl->fRefSupport = TRUE;
  791.     /* Release the Critical Section. */
  792.     LeaveCriticalSection(&lpxpp->csTransport);
  793.     /* Start up logfile stuff if this session indicates it. */
  794.     InitTransportLog(lpxpl, 0L);
  795.     /* OK, we were successful. Set the return values. */
  796.     *lppXPLogon = (LPXPLOGON) lpxpl;
  797.     /* No flags necessary if no connect ... */
  798.     if (lpxpl->ulSessionFlags & LOGON_NO_CONNECT)
  799.     {
  800.         *lpulFlags = 0;
  801.     }
  802.     else
  803.     {
  804.         /* Idle and resolve for transmit; Poll for receive */
  805.         *lpulFlags = LOGON_SP_IDLE | LOGON_SP_RESOLVE | LOGON_SP_POLL;
  806.     }
  807. ret:
  808.     UlRelease(lpProfileObj);
  809.     /*  Make sure we have an hResult.
  810.         Assumptions:
  811.             if hResult is set, it reflects the last error.
  812.             if sc is set and hResult is not, we want hResult to be set.
  813.     */
  814.     if (hResult)
  815.     {
  816.         /* Error. Get rid of anything already on the session object. */
  817.         /* If no session object, free data that could have been      */
  818.         /* allocated before session object creation.                 */
  819.         if (lpxpl)
  820.         {
  821.             CleanupSession(lpxpl);
  822.             lpxpl->lpVtbl->Release(lpxpl);
  823.         }
  824.         else lpFreeBuffer (lpPropArray);
  825.     }
  826.     DebugTraceResult(XPP_TransportLogon, hResult);
  827.     return hResult;
  828. }
  829. /*
  830.  -  lpxpl->lpVtbl->AddressTypes
  831.  -
  832.  *  Purpose:
  833.  *      Called by the Spooler to find out what recipients it should expect
  834.  *      this transport to handle.
  835.  *
  836.  *  Parameters:
  837.  *      ulFlags             Ignored for now.
  838.  *      lpcAdrType          Pointer: where to store number of address types
  839.  *      lpppAdrTypeArray    Pointer: where to store list of address types
  840.  *      lpcMAPIUID          Pointer: where to store number of UID's
  841.  *      lpppMAPIUIDArray    Pointer: where to store list of MAPI UID's
  842.  *
  843.  *  Returns:
  844.  *      (HRESULT)           Errors encountered if any.
  845.  *
  846.  *  Operation:
  847.  *      Returns the Address Type entered at Logon time in the address type
  848.  *      array. Makes no use of the UID array.
  849.  */
  850. STDMETHODIMP
  851. XPL_AddressTypes(LPXPL lpxpl,
  852.     ULONG * lpulFlags,
  853.     ULONG * lpcAdrType, LPTSTR * *lpppAdrTypeArray,
  854.     ULONG * lpcMAPIUID, LPMAPIUID * *lpppMAPIUIDArray)
  855. {
  856.     ULONG cb;
  857.     SCODE sc;
  858.     LPTSTR lpsz;
  859.     /* We are returning an array with exactly one value.  We first need
  860.        to AllocateMore a buffer (that is linked to the lpxpl object) and
  861.        copy our Email Address Type into there.  We then return the address
  862.        of this copy of our AddressType.  */
  863.     if ( *lpulFlags & ~(MAPI_UNICODE) )
  864.         return ResultFromScode( MAPI_E_UNKNOWN_FLAGS );
  865.     if ( *lpulFlags & MAPI_UNICODE )
  866.         return ResultFromScode( MAPI_E_BAD_CHARWIDTH ) ;
  867.     *lpcAdrType = 1;
  868.     lpsz = ArrayIndex(PR_SAMPLE_EMAIL_ADDR_TYPE, lpxpl->lpPropArray).Value.LPSZ;
  869.     cb = (lstrlen(lpsz) + 1) * sizeof(TCHAR);
  870.     sc = lpxpl->AllocateMore(cb, (LPVOID) lpxpl, (LPVOID *) &lpxpl->lpszAdrType);
  871.     if (FAILED(sc))
  872.     {
  873.         DebugTrace("AllocateMore in XPL_AddressType failed!n");
  874.         return ResultFromScode(sc);
  875.     }
  876.     lstrcpy(lpxpl->lpszAdrType, lpsz);
  877.     *lpppAdrTypeArray = &(lpxpl->lpszAdrType);
  878.     /* Routing by UID has no particular meaning for this transport. */
  879.     *lpcMAPIUID = 0;
  880.     *lpppMAPIUIDArray = NULL;
  881.     return hrSuccess;
  882. }
  883. /*
  884.  -  lpxpl->lpVtbl->RegisterOptions
  885.  -
  886.  *  Purpose:
  887.  *      Called by the Spooler to find out what per-message or per-recipient
  888.  *      options this transport might wish supported.
  889.  *
  890.  *  Parameters:
  891.  *      lpulFlags           Indicates whether strings are UNICODE or not.
  892.  *      lpcOptions          Pointer: where to store number of address
  893.  *                          types for which options are being requested
  894.  *      lppOptions          Pointer: where to store a list of display
  895.  *                          names associated with each address type
  896.  *
  897.  *  Returns:
  898.  *      (HRESULT)           Errors encountered if any.
  899.  */
  900. STDMETHODIMP
  901. XPL_RegisterOptions(LPXPL lpxpl,
  902.     ULONG * lpulFlags,
  903.     ULONG * lpcOptions,
  904.     LPOPTIONDATA * lppOptions)
  905. {
  906.     /* Just give them what we have in our XPLogon object.       */
  907.     /* These options were initialized at TransportLogon() time. */
  908.     if ( *lpulFlags & ~(MAPI_UNICODE) )
  909.         return ResultFromScode( MAPI_E_UNKNOWN_FLAGS );
  910.     if ( *lpulFlags & MAPI_UNICODE )
  911.         return ResultFromScode( MAPI_E_BAD_CHARWIDTH ) ;
  912.     *lpcOptions = lpxpl->cOptData;
  913.     *lppOptions = lpxpl->lpOptData;
  914.     return 0;
  915. }
  916. /*
  917.  -  lpxpl->lpVtbl->TransportLogoff
  918.  -
  919.  *  Purpose:
  920.  *      Called by the Spooler to log off a particular Transport session.
  921.  *
  922.  *  Parameters:
  923.  *      ulFlags             May contain LOGOFF_HURRY, which tells
  924.  *                          the transport to close this session
  925.  *                          as quickly as possible.
  926.  *
  927.  *  Returns:
  928.  *      (HRESULT)           Errors encountered if any.
  929.  *
  930.  *  Operation:
  931.  *      Find the session. Tell MAPI the session's going away, unlink it from
  932.  *      the list, close open handles and deallocate session memory.
  933.  */
  934. STDMETHODIMP
  935. XPL_TransportLogoff(LPXPL lpxpl, ULONG ulFlags)
  936. {
  937.     SCODE sc = S_OK;
  938.     LPXPL lpxplCurr;
  939.     LPXPL lpxplPrev = NULL;
  940.     LPXPP lpxpp = lpxpl->lpxppParent;
  941.     /* Get the critical section */
  942.     EnterCriticalSection(&lpxpp->csTransport);
  943.     /* Find the session in the list. */
  944.     lpxplCurr = lpxpp->XPSessionList;
  945.     while (lpxplCurr)
  946.     {
  947.         if (lpxpl == lpxplCurr)
  948.         {
  949.             /* Unlink the session from the list. */
  950.             if (lpxplPrev == NULL)
  951.                 lpxpp->XPSessionList = lpxpl->lpNextSession;
  952.             else
  953.                 lpxplPrev->lpNextSession = lpxpl->lpNextSession;
  954.             break;
  955.         }
  956.         lpxplPrev = lpxplCurr;
  957.         lpxplCurr = lpxplCurr->lpNextSession;
  958.     }
  959.     /* Release the critical section */
  960.     LeaveCriticalSection(&lpxpp->csTransport);
  961.     /* lpxplCurr must be non-NULL if we found the session. */
  962.     if (!lpxplCurr)
  963.     {
  964.         sc = MAPI_E_INVALID_PARAMETER;
  965.         goto ret;
  966.     }
  967.     /* Clean up the stuff inside the session structure. This may
  968.        cause the XPP object to be released. */
  969.     CleanupSession(lpxpl);
  970. ret:
  971.     DebugTraceSc(TransportLogoff, sc);
  972.     return ResultFromScode(sc);
  973. }
  974. /*
  975.  -  lpxpl->lpVtbl->TransportNotify
  976.  -
  977.  *  Purpose:
  978.  *      Called by the Spooler to call some event to the Transport's attention.
  979.  *
  980.  *  Parameters:
  981.  *      lpulFlags           Flags passed bidirectionally.
  982.  *                          This transport pays attention to the
  983.  *                          (BEGIN/END/FLUSH)(INBOUND/OUTBOUND)
  984.  *                          flags and ignores the others.
  985.  *      lppvData            Data passed bidirectionally. Not
  986.  *                          used by this transport.
  987.  *
  988.  *  Returns:
  989.  *      (HRESULT)           Errors encountered if any.
  990.  *
  991.  *  Operation:
  992.  *      If the flag has any bearing on inbound/outbound startup/shutdown,
  993.  *      then the appropriate change is made to the transport status in the
  994.  *      XPLogon object and the HrUpdateTransportStatus routine is called to
  995.  *      ModifyStatusRow() the change.
  996.  */
  997. STDMETHODIMP
  998. XPL_TransportNotify(LPXPL lpxpl,
  999.     ULONG * lpulFlags,
  1000.     LPVOID * lppvData)
  1001. {
  1002.     HRESULT hResult = hrSuccess;
  1003.     LPXPP lpxpp = lpxpl->lpxppParent;
  1004. #define TRANSPORT_NOTIFY_FLAGS  (NOTIFY_BEGIN_INBOUND       | 
  1005.                                 NOTIFY_END_INBOUND          | 
  1006.                                 NOTIFY_BEGIN_INBOUND_FLUSH  | 
  1007.                                 NOTIFY_END_INBOUND_FLUSH    | 
  1008.                                 NOTIFY_BEGIN_OUTBOUND       | 
  1009.                                 NOTIFY_END_OUTBOUND         | 
  1010.                                 NOTIFY_BEGIN_OUTBOUND_FLUSH | 
  1011.                                 NOTIFY_END_OUTBOUND_FLUSH   | 
  1012.                                 NOTIFY_CANCEL_MESSAGE       | 
  1013.                                 NOTIFY_ABORT_DEFERRED)
  1014.     /* Validate we were passed a legal flag. */
  1015.     Assert(*lpulFlags & TRANSPORT_NOTIFY_FLAGS);
  1016.     /* Make sure we have a good session. */
  1017.     if (!FIsValidSession(lpxpl))
  1018.     {
  1019.         hResult = ResultFromScode(E_INVALIDARG);
  1020.         DebugTrace("FIsValidSession  failed in TransportNotify.n");
  1021.         goto ret;
  1022.     }
  1023.     /* Get the Critical Section */
  1024.     EnterCriticalSection(&lpxpp->csTransport);
  1025.     /* Set appropriate status flags and re-register status row */
  1026.     if (*lpulFlags & NOTIFY_BEGIN_INBOUND)
  1027.     {
  1028.         DebugTrace("NOTIFY_BEGIN_INBOUND received and handledn");
  1029.         lpxpl->ulTransportStatus |= STATUS_INBOUND_ENABLED;
  1030.     }
  1031.     if (*lpulFlags & NOTIFY_END_INBOUND)
  1032.     {
  1033.         DebugTrace("NOTIFY_END_INBOUND received and handledn");
  1034.         lpxpl->ulTransportStatus &= ~STATUS_INBOUND_ENABLED;
  1035.     }
  1036.     if (*lpulFlags & NOTIFY_END_INBOUND_FLUSH)
  1037.     {
  1038.         DebugTrace("NOTIFY_END_INBOUND_FLUSH received and handledn");
  1039.         lpxpl->ulTransportStatus &= ~STATUS_INBOUND_FLUSH;
  1040.     }
  1041.     if (*lpulFlags & NOTIFY_BEGIN_OUTBOUND)
  1042.     {
  1043.         DebugTrace("NOTIFY_BEGIN_OUTBOUND received and handledn");
  1044.         lpxpl->ulTransportStatus |= STATUS_OUTBOUND_ENABLED;
  1045.     }
  1046.     if (*lpulFlags & NOTIFY_END_OUTBOUND)
  1047.     {
  1048.         DebugTrace("NOTIFY_END_OUTBOUND received and handledn");
  1049.         lpxpl->ulTransportStatus &= ~STATUS_OUTBOUND_ENABLED;
  1050.     }
  1051.     if (*lpulFlags & NOTIFY_END_OUTBOUND_FLUSH)
  1052.     {
  1053.         DebugTrace("NOTIFY_END_OUTBOUND_FLUSH received and handledn");
  1054.         lpxpl->ulTransportStatus &= ~STATUS_OUTBOUND_FLUSH;
  1055.     }
  1056.     if (*lpulFlags & NOTIFY_ABORT_DEFERRED)
  1057.     {
  1058.         DebugTrace("NOTIFY_ABORT_DEFERRED received and handledn");
  1059.         hResult = HrDeleteDeferred(lpxpl, (LPSBinary)*lppvData);
  1060.     }
  1061.     /* We're just going to ignore NOTIFY_CANCEL_MESSAGE for now. */
  1062.     if (*lpulFlags & NOTIFY_CANCEL_MESSAGE)
  1063.     {
  1064.         DebugTrace("NOTIFY_CANCEL_MESSAGE received and ignoredn");
  1065.     }
  1066.     HrUpdateTransportStatus(lpxpl, 0L);
  1067.     /* Release the critical section. */
  1068.     LeaveCriticalSection(&lpxpp->csTransport);
  1069. ret:
  1070.     DebugTraceResult(XPL_TransportNotify, hResult);
  1071.     return hResult;
  1072. }
  1073. /*
  1074.  -  XPL_ValidateState
  1075.  -
  1076.  *  Purpose:
  1077.  *      Logon object method used by Spooler if ValidateState is called on
  1078.  *      the spooler status object.
  1079.  *
  1080.  *  Parameters:
  1081.  *      lpxpl               This pointer for logon object
  1082.  *      ulUIParam           Window handle
  1083.  *      ulFlags
  1084.  *
  1085.  *  Returns:
  1086.  *      (HRESULT)           E_INVALIDARG if object doesn't
  1087.  *                          look like a XPL; MAPI_E_NO_SUPPORT
  1088.  *                          otherwise.
  1089.  *
  1090.  *  Operation:
  1091.  *      Compare the PR_ADDRTYPE found in the profile to the one I am
  1092.  *      currently using.  If it has changed, then SpoolerNotify() to
  1093.  *      ask to be reloaded so MAPI will call AddressTypes() and
  1094.  *      RegisterOptions() on us again!
  1095.  *
  1096.  *  Note: We could check all the properties in our profile and be a
  1097.  *        better implementation of this call.  But for now, AddrType
  1098.  *        is the most important property to check.
  1099.  */
  1100. STDMETHODIMP
  1101. XPL_ValidateState(LPXPL lpxpl,
  1102.     ULONG ulUIParam,
  1103.     ULONG ulFlags)
  1104. {
  1105.     SCODE sc = S_OK;
  1106.     HRESULT hResult;
  1107.     LPPROFSECT lpProf = NULL;
  1108.     LPSPropValue lpspvAddrType = NULL;
  1109.     LPMAPISUP lpMAPISup = lpxpl->lpMAPISup;
  1110.     LPSPropValue lpPropArray = NULL;
  1111.     LPTSTR lpszAddrType = NULL;
  1112.     /*  If it doesn't seem to be an object or refcount is zero, return zero */
  1113.     if (IsBadReadPtr(lpxpl, sizeof(XPL)) ||
  1114.         lpxpl->lcInit == 0 ||
  1115.         lpxpl->lpMySession != lpxpl)
  1116.     {
  1117.         DebugTraceSc(XPL_ValidateState, E_INVALIDARG);
  1118.         return ResultFromScode(E_INVALIDARG);
  1119.     }
  1120.     if (ulFlags & ~SUPPRESS_UI)
  1121.     {
  1122.         DebugTraceSc(XPL_ValidateState, MAPI_E_UNKNOWN_FLAGS);
  1123.         return ResultFromScode(MAPI_E_UNKNOWN_FLAGS);
  1124.     }
  1125.     sc = ScCopySessionProps(lpxpl, &lpPropArray, NULL);
  1126.     if (FAILED(sc))
  1127.     {
  1128.         hResult = ResultFromScode(sc);
  1129.         DebugTrace("ScCopySessionProps failed in ValidateState.n");
  1130.         goto ret;
  1131.     }
  1132.     lpszAddrType = ArrayIndex(PR_SAMPLE_EMAIL_ADDR_TYPE, lpPropArray).Value.LPSZ;
  1133.     /* Try to open our profile. */
  1134.     hResult = lpMAPISup->lpVtbl->OpenProfileSection(lpMAPISup,
  1135.         (LPMAPIUID) NULL, MAPI_MODIFY, &lpProf);
  1136.     if (hResult)
  1137.     {
  1138.         DebugTrace("OpenProfileSection  failed in ValidateState.n");
  1139.         goto ret;
  1140.     }
  1141.     hResult = HrGetOneProp((LPMAPIPROP)lpProf,
  1142.             PR_SAMPLE_EMAIL_ADDR_TYPE, &lpspvAddrType);
  1143.     if (HR_FAILED(hResult))
  1144.     {
  1145.         DebugTrace("HrGetOneProp failed in ValidateState.n");
  1146.         goto ret;
  1147.     }
  1148.     /* Now, compare what I think my AddrType is to that in the profile.
  1149.        If they are different, tell the spooler I'd like to be reloaded. */
  1150.     if (lpspvAddrType->ulPropTag == PR_SAMPLE_EMAIL_ADDR_TYPE)
  1151.     {
  1152.         if (lstrcmp(lpszAddrType, lpspvAddrType->Value.LPSZ))
  1153.         {
  1154.             hResult = lpMAPISup->lpVtbl->SpoolerNotify(lpMAPISup,
  1155.                 NOTIFY_CONFIG_CHANGE, NULL);
  1156.             if (HR_FAILED(hResult))
  1157.             {
  1158.                 DebugTrace("SpoolerNotify failed  in ValidateState.n");
  1159.                 goto ret;
  1160.             }
  1161.         }
  1162.     }
  1163.     hResult = hrSuccess;
  1164. ret:
  1165.     UlRelease(lpProf);
  1166.     lpxpl->FreeBuffer(lpPropArray);
  1167.     lpxpl->FreeBuffer(lpspvAddrType);
  1168.     DebugTraceResult(XPL_ValidateState, hResult);
  1169.     return hResult;
  1170. }
  1171. /*
  1172.  -  XPL_FlushQueues
  1173.  -
  1174.  *  Purpose:
  1175.  *      Logon object method used by Spooler if FlushQueues is called on
  1176.  *      the spooler status object.
  1177.  *
  1178.  *  Parameters:
  1179.  *      lpxpl               This pointer for logon object
  1180.  *      ulUIParam           Window handle
  1181.  *      cbTargetTransport   Count of bytes in Entryid. Zero.
  1182.  *      lpTargetTransport   Entryid of transport. NULL.
  1183.  *      ulFlags
  1184.  *
  1185.  *  Returns:
  1186.  *      (HRESULT)           E_INVALIDARG if object doesn't
  1187.  *                          look like a XPL; MAPI_E_NO_SUPPORT
  1188.  *                          otherwise.
  1189.  *
  1190.  *  Operation:
  1191.  *      Validate the object pointer. Return MAPI_E_NO_SUPPORT.
  1192.  */
  1193. STDMETHODIMP
  1194. XPL_FlushQueues(LPXPL lpxpl,
  1195.     ULONG ulUIParam,
  1196.     ULONG cbTargetTransport,
  1197.     LPENTRYID lpTargetTransport,
  1198.     ULONG ulFlags)
  1199. {
  1200.     HRESULT hResult;
  1201.     /*  Validate the object */
  1202.     /*  If it doesn't seem to be an object or refcount is zero, return zero */
  1203.     if (IsBadReadPtr(lpxpl, sizeof(XPL)) ||
  1204.         lpxpl->lcInit == 0 ||
  1205.         lpxpl->lpMySession != lpxpl)
  1206.     {
  1207.         DebugTraceSc(XPL_FlushQueues, E_INVALIDARG);
  1208.         return ResultFromScode(E_INVALIDARG);
  1209.     }
  1210.     /*  There is nothing special the sample transport
  1211.         needs to do before signaling its readiness for
  1212.         flushing */
  1213.     /*  Update our status row to inform the spooler
  1214.         that we are ready for flushing */
  1215.     if (ulFlags & FLUSH_UPLOAD)
  1216.         lpxpl->ulTransportStatus |= STATUS_OUTBOUND_FLUSH;
  1217.     if (ulFlags & FLUSH_DOWNLOAD)
  1218.         lpxpl->ulTransportStatus |= STATUS_INBOUND_FLUSH;
  1219.     hResult = HrUpdateTransportStatus(lpxpl, 0L);
  1220.     DebugTraceResult(XPL_FlushQueues, hResult);
  1221.     return hResult;
  1222. }
  1223. /*
  1224.  -  FIsValidSession
  1225.  -
  1226.  *  Purpose:
  1227.  *      Called from several places in the Transport to verify a session.
  1228.  *
  1229.  *  Parameters:
  1230.  *      lpxpl               handle which is to be confirmed
  1231.  *
  1232.  *  Returns:
  1233.  *      (BOOL)              TRUE if a valid session, FALSE if not.
  1234.  *
  1235.  *  Operation:
  1236.  *      Get the critical section, look for lpxpl in the session list,
  1237.  *      release the critical section, return boolean result.
  1238.  */
  1239. BOOL
  1240. FIsValidSession(LPXPL lpxpl)
  1241. {
  1242.     LPXPL lpxplT;
  1243.     LPXPP lpxpp;
  1244.     BOOL fIsValid = FALSE;
  1245.     /*  First make sure that it can possibly be a session; then
  1246.         Take advantage of the internal consistency check ... does
  1247.         it point to itself? then validate the parent XPP. */
  1248.     if ((IsBadWritePtr(lpxpl, sizeof(XPL))) ||
  1249.         (lpxpl->lpMySession != lpxpl) ||
  1250.         (IsBadWritePtr(lpxpl->lpxppParent, sizeof(XPP))))
  1251.         return FALSE;
  1252.     /*  Maybe it's a session ... see if it's in the list.
  1253.         Lock out session data structure during the check. */
  1254.     lpxpp = lpxpl->lpxppParent;
  1255.     EnterCriticalSection(&lpxpp->csTransport);
  1256.     /*  Look in the session list for the session */
  1257.     lpxplT = lpxpp->XPSessionList;
  1258.     while (lpxplT)
  1259.     {
  1260.         if (lpxplT == lpxpl)
  1261.         {
  1262.             fIsValid = TRUE;
  1263.             break;
  1264.         }
  1265.         lpxplT = lpxplT->lpNextSession;
  1266.     }
  1267.     /*  Release the critical section and return the result. */
  1268.     LeaveCriticalSection(&lpxpp->csTransport);
  1269.     return fIsValid;
  1270. }
  1271. /*
  1272.  -  CleanupSession
  1273.  -
  1274.  *  Purpose:
  1275.  *      Called from TransportLogoff() and error cases of TransportLogon()
  1276.  *      to cleanup session data.
  1277.  *
  1278.  *  Parameters:
  1279.  *      lpxpl           handle which is to be confirmed
  1280.  *
  1281.  *  Returns:
  1282.  *      none.
  1283.  *
  1284.  *  Operation:
  1285.  *      Close any open search handles, deallocate associated structures.
  1286.  *      We assume that if we need the critical section, we already have it.
  1287.  */
  1288. static void
  1289. CleanupSession(LPXPL lpxpl)
  1290. {
  1291.     LPMAPISUP lpMAPISup = lpxpl->lpMAPISup;
  1292.     BOOL fRefSupport = lpxpl->fRefSupport;
  1293.     /* Get rid of any open handle hanging around from Poll() or
  1294.     StartMessage() */
  1295.     if (lpxpl->hInFindHandle != INVALID_HANDLE_VALUE)
  1296.         CloseHandle(lpxpl->hInFindHandle);
  1297.     if (lpxpl->hOutFindHandle != INVALID_HANDLE_VALUE)
  1298.         CloseHandle(lpxpl->hOutFindHandle);
  1299.     /* OK, Deallocate the memory. */
  1300.     /* Session User Display Name and Entry-ID */
  1301.     if (lpxpl->lpMyIDArray)
  1302.     {
  1303.         lpxpl->FreeBuffer(lpxpl->lpMyIDArray[0].Value.bin.lpb);
  1304.         lpxpl->FreeBuffer(lpxpl->lpMyIDArray);
  1305.     }
  1306.     /* Free the session property array */
  1307.     lpxpl->FreeBuffer(lpxpl->lpPropArray);
  1308.     /* Free the Message OptionData struct */
  1309.     lpxpl->FreeBuffer(lpxpl->lpOptData);
  1310.     /* Release() the support object if need be. Do this last,
  1311.        since it could cause spooler to call XPP_Release. */
  1312.     if (fRefSupport)
  1313.         lpMAPISup->lpVtbl->Release(lpMAPISup);
  1314. }
  1315. /*
  1316.  -  lpxpp->lpVtbl->QueryInterface
  1317.  -
  1318.  *  Purpose:
  1319.  *
  1320.  *  Parameters:
  1321.  *      lpxpp               Pointer to object
  1322.  *      lpiid               New interface to Query to
  1323.  *      lppUnk              Where to store pointer to new object
  1324.  *
  1325.  *  Returns:
  1326.  *      (SCODE)             E_INVALIDARG if the input
  1327.  *                          object doesn't look like a XPP;
  1328.  *                          E_INVALIDARG if the IID
  1329.  *                          isn't readable or lppNewObj isn't
  1330.  *                          writable; E_NOINTERFACE
  1331.  *                          if we don't know the IID.
  1332.  *
  1333.  *  Operation:
  1334.  *      Validate parameters. See if the caller wants IUnknown or IXPProvider.
  1335.  *      If so, increment the usage count and return a new object.
  1336.  */
  1337. STDMETHODIMP
  1338. XPP_QueryInterface(LPXPP lpxpp,
  1339.     REFIID lpiid,
  1340.     LPVOID FAR * lppUnk)
  1341. {
  1342.     /*  Validate the parameters: 1) Does it seem to be an object?
  1343.         2) is the refcount nonzero? 3) Is there enough there for
  1344.         an interface ID? 4) Is there enough there for a new object? */
  1345.     if ((IsBadWritePtr(lpxpp, sizeof(XPP))) ||
  1346.         (lpxpp->lcInit == 0) ||
  1347.         (lpxpp->lpxppMyAddress != lpxpp) ||
  1348.         (IsBadReadPtr(lpiid, sizeof(IID))) ||
  1349.         (IsBadWritePtr(lppUnk, sizeof(LPXPP))))
  1350.     {
  1351.         DebugTraceSc(XPP_QueryInterface, E_INVALIDARG);
  1352.         return ResultFromScode(E_INVALIDARG);
  1353.     }
  1354.     /*  See if the requested interface is one of ours */
  1355.     if (memcmp(lpiid, &IID_IUnknown, sizeof(IID)) &&
  1356.         memcmp(lpiid, &IID_IXPProvider, sizeof(IID)))
  1357.     {
  1358.         *lppUnk = NULL;         /* OLE requires zeroing [out] parameters */
  1359.         DebugTraceSc(XPP_QueryInterface, E_NOINTERFACE);
  1360.         return ResultFromScode(E_NOINTERFACE);
  1361.     }
  1362.     /*  We'll do this one. Bump the usage count and return a new pointer. */
  1363.     ++lpxpp->lcInit;
  1364.     *lppUnk = lpxpp;
  1365.     return hrSuccess;
  1366. }
  1367. /*
  1368.  -  lpxpp->lpVtbl->AddRef
  1369.  -
  1370.  *  Purpose:
  1371.  *      Increment reference count if nonzero.
  1372.  *
  1373.  *  Parameters:
  1374.  *      lpxpp               Pointer to object (should be XPP)
  1375.  *
  1376.  *
  1377.  *  Returns:
  1378.  *      (ULONG)             Current reference count or zero if
  1379.  *                          it doesn't seem to be XPP.
  1380.  *
  1381.  *  Operation:
  1382.  *      Make sure it looks like a XPP, and if so, bump the reference count
  1383.  *      and return the result to the caller.
  1384.  */
  1385. STDMETHODIMP_(ULONG)
  1386. XPP_AddRef(LPXPP lpxpp)
  1387. {
  1388.     /*  If it doesn't seem to be an object or refcount is zero, return zero */
  1389.     if (IsBadWritePtr(lpxpp, sizeof(XPP)) ||
  1390.         lpxpp->lcInit == 0 ||
  1391.         lpxpp->lpxppMyAddress != lpxpp)
  1392.         return 0;
  1393.     return ++lpxpp->lcInit;
  1394. }
  1395. /*
  1396.  -  lpxpp->lpVtbl->Release
  1397.  -
  1398.  *  Purpose:
  1399.  *      Decrement lcInit. If it's zero, release the object.
  1400.  *
  1401.  *  Parameters:
  1402.  *      lpxpp               Pointer to object (should be XPP)
  1403.  *
  1404.  *  Returns:
  1405.  *      (ULONG)             Current reference count or zero if
  1406.  *                                  it doesn't seem to be XPP.
  1407.  *
  1408.  *  Operation:
  1409.  *      Make sure it looks like a XPP, and if so, decrement the reference
  1410.  *      count. If the count is now zero, deallocate the object.
  1411.  *
  1412.  *      Return the reference count to the caller.
  1413.  */
  1414. STDMETHODIMP_(ULONG)
  1415. XPP_Release(LPXPP lpxpp)
  1416. {
  1417.     /*  If it doesn't seem to be an object or refcount is zero, return zero */
  1418.     if (IsBadWritePtr(lpxpp, sizeof(XPP)) ||
  1419.         lpxpp->lcInit == 0 ||
  1420.         lpxpp->lpxppMyAddress != lpxpp)
  1421.         return 0;
  1422.     --lpxpp->lcInit;
  1423.     if (lpxpp->lcInit == 0)
  1424.     {
  1425.         ULONG ulT;
  1426.         DebugTrace("XPP_Release() freeing XPP.n");
  1427.         /* If we've inited and not deinited, do it now */
  1428.         if (lpxpp->fInited)
  1429.         {
  1430.             ulT = DEINIT_HURRY;
  1431.             lpxpp->lpVtbl->Shutdown(lpxpp, &ulT);
  1432.         }
  1433.         lpxpp->lpVtbl = NULL;
  1434.         (*lpxpp->lpFreeBuffer) (lpxpp);
  1435.         return 0;
  1436.     }
  1437.     return lpxpp->lcInit;
  1438. }
  1439. /*
  1440.  -  lpxpl->lpVtbl->QueryInterface
  1441.  -
  1442.  *  Purpose:
  1443.  *
  1444.  *  Parameters:
  1445.  *      lpxpl               Pointer to object
  1446.  *      lpiid               New interface to Query to
  1447.  *      lppUnk              Where to store pointer to new object
  1448.  *
  1449.  *  Returns:
  1450.  *      (SCODE)             E_INVALIDARG if the input
  1451.  *                          object doesn't look like a XPL;
  1452.  *                          E_INVALIDARG if the IID
  1453.  *                          isn't readable or lppNewObj isn't
  1454.  *                          writable; E_NOINTERFACE
  1455.  *                          if we don't know the IID.
  1456.  *
  1457.  *  Operation:
  1458.  *      Validate parameters. See if the caller wants IUnknown or IXPLogon.
  1459.  *      If so, increment the usage count and return a new object.
  1460.  */
  1461. STDMETHODIMP
  1462. XPL_QueryInterface(LPXPL lpxpl,
  1463.     REFIID lpiid,
  1464.     LPVOID FAR * lppUnk)
  1465. {
  1466.     /*  Validate the parameters: 1) Does it seem to be an object?
  1467.         2) is the refcount nonzero? 3) Is there enough there for
  1468.         an interface ID? 4) Is there enough there for a new object? */
  1469.     if ((IsBadWritePtr(lpxpl, sizeof(XPL))) ||
  1470.         (lpxpl->lcInit == 0) ||
  1471.         (lpxpl->lpMySession != lpxpl) ||
  1472.         (IsBadReadPtr(lpiid, sizeof(IID))) ||
  1473.         (IsBadWritePtr(lppUnk, sizeof(LPXPL))))
  1474.     {
  1475.         DebugTraceSc(XPL_QueryInterface, E_INVALIDARG);
  1476.         return ResultFromScode(E_INVALIDARG);
  1477.     }
  1478.     /*  See if the requested interface is one of ours */
  1479.     if (memcmp(lpiid, &IID_IUnknown, sizeof(IID)) &&
  1480.         memcmp(lpiid, &IID_IXPLogon, sizeof(IID)))
  1481.     {
  1482.         *lppUnk = NULL;         /* OLE requires zeroing [out] parameters */
  1483.         DebugTraceSc(XPL_QueryInterface, E_NOINTERFACE);
  1484.         return ResultFromScode(E_NOINTERFACE);
  1485.     }
  1486.     /*  We'll do this one. Bump the usage count and return a new pointer. */
  1487.     ++lpxpl->lcInit;
  1488.     *lppUnk = lpxpl;
  1489.     return hrSuccess;
  1490. }
  1491. /*
  1492.  -  lpxpl->lpVtbl->AddRef
  1493.  -
  1494.  *  Purpose:
  1495.  *      Increment reference count if nonzero.
  1496.  *
  1497.  *  Parameters:
  1498.  *      lpxpl               Pointer to object (should be XPL)
  1499.  *
  1500.  *  Returns:
  1501.  *      (ULONG)             Current reference count or zero if
  1502.  *                          it doesn't seem to be XPL.
  1503.  *
  1504.  *  Operation:
  1505.  *      Make sure it looks like a XPL, and if so, bump the reference count
  1506.  *      and return the result to the caller.
  1507.  */
  1508. STDMETHODIMP_(ULONG)
  1509. XPL_AddRef(LPXPL lpxpl)
  1510. {
  1511.     /*  If it doesn't seem to be an object or refcount is zero, return zero */
  1512.     if (IsBadWritePtr(lpxpl, sizeof(XPL)) ||
  1513.         lpxpl->lcInit == 0 ||
  1514.         lpxpl->lpMySession != lpxpl)
  1515.         return 0;
  1516.     return ++lpxpl->lcInit;
  1517. }
  1518. /*
  1519.  -  lpxpl->lpVtbl->Release
  1520.  -
  1521.  *  Purpose:
  1522.  *      Decrement lcInit. If it's zero, release the object.
  1523.  *
  1524.  *  Parameters:
  1525.  *      lpxpl               Pointer to object (should be XPL)
  1526.  *
  1527.  *  Returns:
  1528.  *      (ULONG)             Current reference count or zero if
  1529.  *                          it doesn't seem to be XPL.
  1530.  *
  1531.  *  Operation:
  1532.  *      Make sure it looks like a XPL, and if so, decrement the reference
  1533.  *      count. If the count is now zero, deallocate the object.
  1534.  *
  1535.  *      Return the reference count to the caller.
  1536.  */
  1537. STDMETHODIMP_(ULONG)
  1538. XPL_Release(LPXPL lpxpl)
  1539. {
  1540.     /*  If it doesn't seem to be an object or refcount is zero, return zero */
  1541.     if (IsBadWritePtr(lpxpl, sizeof(XPL)) ||
  1542.         lpxpl->lcInit == 0 ||
  1543.         lpxpl->lpMySession != lpxpl)
  1544.         return 0;
  1545.     --lpxpl->lcInit;
  1546.     if (lpxpl->lcInit == 0)
  1547.     {
  1548.         DebugTrace("XPL_Release() freeing XPL.n");
  1549.         /* Ignore return code; we're going away reguardless! */
  1550.         XPL_TransportLogoff(lpxpl, LOGOFF_HURRY);
  1551.         lpxpl->lpVtbl = NULL;
  1552.         (*lpxpl->FreeBuffer) (lpxpl);
  1553.         return 0;
  1554.     }
  1555.     return lpxpl->lcInit;
  1556. }
  1557. /*
  1558.  -  ScCheckLogonProps
  1559.  -
  1560.  *  Purpose:
  1561.  *      Looks at the properties returned from the XP Logon property
  1562.  *      sheet and does some 'lite' validation of the values.  Users
  1563.  *      of this function must accept the symantics associated with
  1564.  *      the three possible return values.  That is, if the caller
  1565.  *      is displaying UI and MAPI_E_INVALID_PARAMETER is returned
  1566.  *      then the UI must be re-displayed.  If the caller is NOT
  1567.  *      displaying UI and MAPI_E_UNCONFIGURED is returned then
  1568.  *      they should pass this error back up the call stack, as MAPI
  1569.  *      will call the Service Entry point to get this info.
  1570.  *      MAPI_E_USER_CANCEL will only be returned if UI is allowed,
  1571.  *      in which case this should be treated the same a when the
  1572.  *      user presses <Cancel> in the Logon dialog.
  1573.  *
  1574.  *  Parameters:
  1575.  *      lpXPDialog          - Contains everything I need
  1576.  *      fUIAllowed          - Indicates if MessageBox's are allowed
  1577.  *
  1578.  *  Returns:
  1579.  *      S_OK                        - All data appears valid
  1580.  *      MAPI_E_USER_CANCEL          - Bad data and the user wants to abort
  1581.  *      MAPI_E_UNCONFIGURED         - Bad data and the user wants to try again
  1582.  */
  1583. SCODE
  1584. ScCheckLogonProps(LPXPDLG lpXPDialog, BOOL fUIAllowed)
  1585. {
  1586.     SCODE sc = MAPI_E_UNCONFIGURED;
  1587.     LPTSTR lpszT = NULL;
  1588.     HINSTANCE hInst = lpXPDialog->hInst;
  1589.     HWND hWnd = lpXPDialog->hwnd;
  1590.     LPSPropValue lpProps = *(lpXPDialog->lppPropArray);
  1591.     HANDLE hf = INVALID_HANDLE_VALUE;
  1592.     ULONG ulT;
  1593.     BOOL fDeleteFile = FALSE;
  1594.     LPTSTR szFuBar = TEXT("fubar");
  1595.     TCHAR szFooUNC[MAX_PATH];
  1596.     TCHAR szFooPath[MAX_PATH];
  1597.     UINT ids = 0;
  1598.     LONG lFlags;
  1599. #ifdef _WINNT
  1600.     ULONG cb;
  1601.     TCHAR szBuff[16];
  1602. #endif  /* _WINNT */
  1603.     /* Check Display Name */
  1604.     lpszT = ArrayIndex(PR_SAMPLE_DISPLAY_NAME, lpProps).Value.LPSZ;
  1605.     if (PROP_TYPE(ArrayIndex(PR_SAMPLE_DISPLAY_NAME, lpProps).ulPropTag) == PT_ERROR ||
  1606.         !lpszT || (*lpszT == ''))
  1607.     {
  1608.         ids = IDS_NO_DISPLAY_NAME;
  1609.         goto ret;
  1610.     }
  1611.     /* Check Address Type */
  1612.     lpszT = ArrayIndex(PR_SAMPLE_EMAIL_ADDR_TYPE, lpProps).Value.LPSZ;
  1613.     if (PROP_TYPE(ArrayIndex(PR_SAMPLE_EMAIL_ADDR_TYPE, lpProps).ulPropTag) == PT_ERROR ||
  1614.         !lpszT || (*lpszT == ''))
  1615.     {
  1616.         ids = IDS_NO_ADDR_TYPE;
  1617.         goto ret;
  1618.     }
  1619.     /* Check Email Address */
  1620.     lpszT = ArrayIndex(PR_SAMPLE_EMAIL_ADDRESS, lpProps).Value.LPSZ;
  1621.     if (PROP_TYPE(ArrayIndex(PR_SAMPLE_EMAIL_ADDRESS, lpProps).ulPropTag) == PT_ERROR ||
  1622.         !lpszT || (*lpszT == ''))
  1623.     {
  1624.         ids = IDS_NO_EMAIL_ADDRESS;
  1625.         goto ret;
  1626.     }
  1627.     /* Save this, we'll need it later */
  1628.     lstrcpy(szFooUNC, lpszT);
  1629.     if (szFooUNC[lstrlen(szFooUNC)-1] != '\')
  1630.         lstrcat(szFooUNC, TEXT("\"));
  1631.     lstrcat(szFooUNC, TEXT("foo.txt"));
  1632.     /* Check Inbound Directory */
  1633.     lpszT = ArrayIndex(PR_SAMPLE_INBOUND_DIR, lpProps).Value.LPSZ;
  1634.     if (PROP_TYPE(ArrayIndex(PR_SAMPLE_INBOUND_DIR, lpProps).ulPropTag) == PT_ERROR ||
  1635.         !lpszT || (*lpszT == ''))
  1636.     {
  1637.         ids = IDS_NO_INBOUND_DIR;
  1638.         goto ret;
  1639.     }
  1640.     lstrcpy(szFooPath, lpszT);
  1641.     if (szFooPath[lstrlen(szFooPath)-1] != '\')
  1642.         lstrcat(szFooPath, TEXT("\"));
  1643.     lstrcat(szFooPath, TEXT("foo.txt"));
  1644.     /* Check Outbound Directory */
  1645.     lFlags = ArrayIndex(PR_SAMPLE_FLAGS, lpProps).Value.l;
  1646.     if (PROP_TYPE(ArrayIndex(PR_SAMPLE_FLAGS, lpProps).ulPropTag) == PT_ERROR ||
  1647.         !(lFlags & PR_SAMPLE_FLAG_PEER_TO_PEER))
  1648.     {
  1649.         lpszT = ArrayIndex(PR_SAMPLE_OUTBOUND_DIR, lpProps).Value.LPSZ;
  1650.         if (!lpszT || (*lpszT == ''))
  1651.         {
  1652.             ids = IDS_NO_OUTBOUND_DIR;
  1653.             goto ret;
  1654.         }
  1655.     }
  1656. #ifdef _WINNT
  1657.     /* Do a little loop-back test to validate PR_SAMPLE_EMAIL_ADDRESS
  1658.        and PR_SAMPLE_INBOUND_DIR point to the same place and are valid.
  1659.        The WFW and Windows 95 Redirector can't talk to itself, so we only
  1660.        do this on NT.  Shouldn't be done on platforms whose redirector
  1661.        cannot do the loop-back thang. */
  1662.     if ((hf = CreateFile(szFooUNC, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
  1663.                 FILE_FLAG_WRITE_THROUGH, NULL)) == INVALID_HANDLE_VALUE)
  1664.     {
  1665.         ids = IDS_BAD_EMAIL_ADDRESS;
  1666.         goto ret;
  1667.     }
  1668.     if (!WriteFile(hf, szFuBar, lstrlen(szFuBar), &cb, NULL))
  1669.     {
  1670.         ids = IDS_BAD_EMAIL_ADDRESS;
  1671.         goto ret;
  1672.     }
  1673.     CloseHandle(hf);
  1674.     fDeleteFile = TRUE;
  1675.     /* Now, read the file */
  1676.     if ((hf = CreateFile(szFooPath, GENERIC_READ, 0, NULL, OPEN_EXISTING,
  1677.                 FILE_ATTRIBUTE_READONLY, NULL)) == INVALID_HANDLE_VALUE)
  1678.     {
  1679.         ids = IDS_BAD_INBOUND_DIR;
  1680.         goto ret;
  1681.     }
  1682.     if (!ReadFile(hf, szBuff, lstrlen(szFuBar), &cb, NULL))
  1683.     {
  1684.         ids = IDS_BAD_INBOUND_DIR;
  1685.         goto ret;
  1686.     }
  1687.     szBuff[lstrlen(szFuBar)] = '';
  1688.     CloseHandle(hf);
  1689.     hf = INVALID_HANDLE_VALUE;
  1690.     if (lstrcmp(szFuBar, szBuff))
  1691.     {
  1692.         ids = IDS_UNC_DIR_MISMATCH;
  1693.         goto ret;
  1694.     }
  1695. #endif  /* _WINNT */
  1696.     /*  If there's a high water mark, make sure there's a low water
  1697.         mark at least 1K less than high water and no more than 32K. */
  1698.     ulT = ArrayIndex(PR_SAMPLE_LOGHIGHWATER, lpProps).Value.ul;
  1699.     if (PROP_TYPE(ArrayIndex(PR_SAMPLE_LOGHIGHWATER, lpProps).ulPropTag) == PT_ERROR ||
  1700.         ulT)
  1701.     {
  1702.         /* It looks like we'll be doing size adjustment. See what
  1703.         the current "low water" mark is. */
  1704.         ULONG ulLow;
  1705.         ulLow = ArrayIndex(PR_SAMPLE_LOGLOWWATER, lpProps).Value.ul;
  1706.         /* Make sure it's not more than 32K. If so, trim it down. */
  1707.         if (ulLow > 32)
  1708.             ulLow = 32;
  1709.         /* Make sure there's at least 1K between high and low water. If
  1710.         not, increase high water mark to satisfy this. */
  1711.         if (ulLow > (ulT - 1))
  1712.             ulT = ulLow + 1;
  1713.         /* Save this stuff into the logon property array. */
  1714.         ArrayIndex(PR_SAMPLE_LOGLOWWATER, lpProps).Value.ul = ulLow;
  1715.         ArrayIndex(PR_SAMPLE_LOGHIGHWATER, lpProps).Value.ul = ulT;
  1716.     }
  1717.     sc = S_OK;
  1718. ret:
  1719.     if (fDeleteFile)
  1720.         DeleteFile(szFooUNC);
  1721.     if (hf != INVALID_HANDLE_VALUE)
  1722.         CloseHandle(hf);
  1723.     /*  OK, the following block goes something like this:
  1724.         We initialized sc to MAPI_E_UNCONFIGURED at the top
  1725.         and only set it to S_OK if we make it all the way through
  1726.         the validation stuff.  If, along the way, we find bad data
  1727.         we set ids to the appropriate error string (this is Assert'd
  1728.         below).  Then, if UI is allowed, we get a bunch of string
  1729.         resources via LoadString and format an error message that
  1730.         will be displayed in a MessageBox.  If we are running the
  1731.         debug version of the transport, then the MessageBox will
  1732.         have an Abort/Retry/Ignore button selection, else, it will
  1733.         only have a Yes/No button selection.  These buttons carry
  1734.         with them the following meaning:
  1735.         DEBUG
  1736.             Abort   Return MAPI_E_USER_CANCEL; causes Logon to fail;
  1737.                     indicates that data is not to be saved in the profile.
  1738.             Retry   Return MAPI_E_UNCONFIGURED; re-display
  1739.                     Logon UI so user can fix problem.
  1740.             Ignore  Return S_OK; we accept the data as is and will
  1741.                     write it into the profile (if asked to save).
  1742.         !DEBUG
  1743.             Yes     Same as Retry above.
  1744.             No      Same as Abort above.
  1745.         Since we are using MessageBox for our error dialog, we are
  1746.         limited to this confusing choice of buttons.
  1747.     */
  1748.     if (FAILED(sc) && fUIAllowed)
  1749.     {
  1750.         TCHAR szErrTitle[64];
  1751.         TCHAR szErrFormat[128];
  1752.         TCHAR szErrStr[128];
  1753.         TCHAR szErrMsg[256];
  1754.         UINT fuButtons = MB_ICONEXCLAMATION | MB_SETFOREGROUND;
  1755.         int rc;
  1756.         Assert(ids);
  1757.         if (!LoadString(hInst, ids, szErrStr, sizeof(szErrStr) - 1) ||
  1758.             !LoadString(hInst, IDS_BAD_LOGON_PROPS_TITLE,
  1759.                         szErrTitle, sizeof(szErrTitle) - 1) ||
  1760.             !LoadString(hInst, IDS_BAD_LOGON_PROPS_FORMAT,
  1761.                         szErrFormat, sizeof(szErrFormat) - 1))
  1762.         {
  1763.             DebugTrace("Unable to do a LoadString in ScCheckLogonProps.n");
  1764.             return sc;
  1765.         }
  1766.         wsprintf(szErrMsg, szErrFormat, szErrStr);
  1767. #ifdef DEBUG
  1768.         fuButtons |= MB_ABORTRETRYIGNORE;
  1769. #else
  1770.         fuButtons |= MB_YESNO;
  1771. #endif
  1772.         rc = MessageBox(hWnd, szErrMsg, szErrTitle, fuButtons);
  1773.         if (rc == IDRETRY || rc == IDYES)
  1774.             sc = MAPI_E_UNCONFIGURED;
  1775.         else if (rc == IDABORT || rc == IDNO)
  1776.             sc = MAPI_E_USER_CANCEL;
  1777.         else
  1778.             sc = S_OK;
  1779.     }
  1780.     return sc;
  1781. }
  1782. /*
  1783.  -  HrCheckSpoolerYield
  1784.  -
  1785.  *  Purpose:
  1786.  *      Used to enforce the .2 second rule.  Called periodically while
  1787.  *      processing a message to determine if we have used more than .2
  1788.  *      seconds.  If so, then call SpoolerYield(), else just continue.
  1789.  *      This is called with fReset set to TRUE when we first enter one
  1790.  *      of the Transport Logon methods (usually one that is known to
  1791.  *      take a long time like StartMessage() or SubmitMessage(). )
  1792.  *
  1793.  *  Parameters:
  1794.  *      lpMAPISup           - The Transports support object
  1795.  *      fReset              - Sets dwStart to current TickCount and returns
  1796.  *
  1797.  */
  1798. HRESULT
  1799. HrCheckSpoolerYield(LPMAPISUP lpMAPISup, BOOL fReset)
  1800. {
  1801.     HRESULT hr = hrSuccess;
  1802.     DWORD dwStop;
  1803.     static DWORD dwStart;
  1804.     if (fReset)
  1805.     {
  1806.         dwStart = GetTickCount();
  1807.         return hr;
  1808.     }
  1809.     dwStop = GetTickCount();
  1810.     if ((dwStop - dwStart) > 200)
  1811.     {
  1812.         hr = lpMAPISup->lpVtbl->SpoolerYield(lpMAPISup, 0);
  1813.         dwStart = GetTickCount();
  1814.     }
  1815.     return hr;
  1816. }
  1817. /*
  1818.  -  ScCopySessionProps
  1819.  -
  1820.  *  Purpose:
  1821.  *      Used to make a working copy of the session properties associated
  1822.  *      with a particular logon object.  This is done to protect us from
  1823.  *      having our data change out from under us due to a call to some
  1824.  *      transport UI.  This is done instead of mutexing to avoid the chance
  1825.  *      of deadlock conditions and to avoid having to create an elaborate
  1826.  *      mutex object that suits our special needs.
  1827.  *
  1828.  *  Parameters:
  1829.  *      lpxpl               - The Transports logon object
  1830.  *      lppPropArray        - Receives the new PropArray set
  1831.  *      lppMyIdArray        - Receives the new IdArray
  1832.  */
  1833. SCODE
  1834. ScCopySessionProps(
  1835.     LPXPL lpxpl,
  1836.     LPSPropValue FAR * lppPropArray,
  1837.     LPSPropValue FAR * lppMyIDArray)
  1838. {
  1839.     SCODE sc = S_OK;
  1840.     ULONG cProps;
  1841.     LPSPropValue lpPropArray = lpxpl->lpPropArray;
  1842.     LPSPropValue lpMyIDArray = lpxpl->lpMyIDArray;
  1843.     LPALLOCATEBUFFER lpAllocBuff = lpxpl->AllocateBuffer;
  1844.     if (lppPropArray)
  1845.     {
  1846.         cProps = MAX_LOGON_PROPERTIES - TEMP_LOGON_PROPERTIES;
  1847.         sc = ScDupPropset((int)cProps, lpPropArray, lpAllocBuff, lppPropArray);
  1848.         if (FAILED(sc))
  1849.             goto ret;
  1850.     }
  1851.     if (lppMyIDArray)
  1852.     {
  1853.         cProps = NUM_SENDER_PROPS;
  1854.         sc = ScDupPropset((int)cProps, lpMyIDArray, lpAllocBuff, lppMyIDArray);
  1855.         if (FAILED(sc) && lppPropArray)
  1856.         {
  1857.             lpxpl->FreeBuffer(*lppPropArray);
  1858.             *lppPropArray = NULL;
  1859.         }
  1860.     }
  1861. ret:
  1862.     return sc;
  1863. }
  1864. /*
  1865.  -  ServiceEntry
  1866.  -
  1867.  *  Purpose:
  1868.  *      This is the service entry point for the MAPI Configuration
  1869.  *      application.  This function uses the XP Logon dialog to allow
  1870.  *      the user to configure the provider.  If asked to, through the
  1871.  *      UI, the new settings will be saved in the profile.
  1872.  *
  1873.  *  Parameters:
  1874.  *      hInstance           [IN] Instance handle of the calling process
  1875.  *      lpMalloc            [IN] OLE style allocator to be used by PropSheet.
  1876.  *      lpMAPISup           [IN] MAPI Support object - used to get memory
  1877.  *                          allocators, BuildDisplayTable, etc.
  1878.  *      ulUIParam           [IN] hWnd of the caller who is parent of my UI.
  1879.  *      ulFlags             [IN] UI_SERVICE indicates that the caller wants
  1880.  *                          UI to help in configuring this provider.
  1881.  *                          MSG_SERVICE_UI_READ_ONLY indicates the caller
  1882.  *                          does not want write access to the configuration
  1883.  *                          property sheet.  No other flags are supported.
  1884.  *      ulContext           [IN] MSG_SERVICE_DELETE, MSG_SERVICE_INSTALL, and
  1885.  *                          MSG_SERVICE_UNINSTALL are noops and simply return
  1886.  *                          hrSuccess.  MSG_SERVICE_CONFIGURE and
  1887.  *                          MSG_SERVICE_CREATE allow the caller to create
  1888.  *                          or update the Logon properties in this providers
  1889.  *                          profile section.
  1890.  *      cValues             [IN] The caller may supply an array of property
  1891.  *                          values to configure this provider with.  This is
  1892.  *                          the number of values found in the array.
  1893.  *      lpProps             [IN] Caller supplied configuration properties.
  1894.  *      lpAdminProviders    [IN] An IProviderAdmin object used to retrieve a
  1895.  *                          ProfileSection object for this provider.
  1896.  *      lppMapiError        [OUT] Extended error information optionally
  1897.  *                          returned when the call fails.
  1898.  */
  1899. HRESULT STDAPICALLTYPE
  1900. ServiceEntry(
  1901.     HINSTANCE hInstance,
  1902.     LPMALLOC lpMalloc,
  1903.     LPMAPISUP lpMAPISup,
  1904.     ULONG ulUIParam,
  1905.     ULONG ulFlags,
  1906.     ULONG ulContext,
  1907.     ULONG cValues,
  1908.     LPSPropValue lpProps,
  1909.     LPPROVIDERADMIN lpAdminProviders,
  1910.     LPMAPIERROR FAR *lppMapiError)
  1911. {
  1912.     SCODE sc = S_OK;
  1913.     HRESULT hResult = hrSuccess;
  1914.     ULONG ulT;
  1915.     ULONG ulCount = 0;
  1916.     LPSPropValue lpPropArray = NULL;
  1917.     LPSPropValue lpLogonProps = NULL;
  1918.     LPALLOCATEBUFFER lpAllocBuff;
  1919.     LPALLOCATEMORE lpAllocMore;
  1920.     LPFREEBUFFER lpFreeBuff;
  1921.     LPPROFSECT lpProfileObj = NULL;
  1922.     XPDLG XPDialog;
  1923.     BOOL fNeedUI = FALSE;
  1924.     BOOL fAllowUI = FALSE;
  1925.     BOOL fInitialParamsOk = TRUE;
  1926.     /* Validate parameters */
  1927.     //$BUG: No parameter checking....
  1928.     /* Check the Support Object */
  1929.     if (FBadUnknown(lpMAPISup))
  1930.     {
  1931.         DebugTraceSc(Bad lpMAPISup in XP ServiceEntry, E_INVALIDARG);
  1932.         return ResultFromScode(E_INVALIDARG);
  1933.     }
  1934.     /* Check for context */
  1935.     if ((ulContext == MSG_SERVICE_DELETE) ||
  1936.         (ulContext == MSG_SERVICE_INSTALL) ||
  1937.         (ulContext == MSG_SERVICE_UNINSTALL))
  1938.         return hrSuccess;
  1939.     if (ulContext != MSG_SERVICE_CONFIGURE && ulContext != MSG_SERVICE_CREATE)
  1940.     {
  1941.         DebugTraceSc(ServiceEntry unsupported context, MAPI_E_NO_SUPPORT);
  1942.         return ResultFromScode(MAPI_E_NO_SUPPORT);
  1943.     }
  1944.     if ( ulFlags & MAPI_UNICODE )
  1945.     {
  1946.         DebugTraceSc(ServiceEntry Bad character width, MAPI_E_BAD_CHARWIDTH);
  1947.         return ResultFromScode(MAPI_E_BAD_CHARWIDTH);
  1948.     }
  1949.     /* Check for UI */
  1950.     if (ulFlags & SERVICE_UI_ALWAYS)
  1951.         fAllowUI = fNeedUI = TRUE;
  1952.     else
  1953.         if (ulFlags & SERVICE_UI_ALLOWED)
  1954.             fAllowUI = TRUE;
  1955.     if (ulFlags & MSG_SERVICE_UI_READ_ONLY)
  1956.         ulFlags = UI_READONLY;
  1957.     /* Get the memory allocation routines we'll be needing. */
  1958.     hResult = lpMAPISup->lpVtbl->GetMemAllocRoutines(lpMAPISup,
  1959.         &lpAllocBuff, &lpAllocMore, &lpFreeBuff);
  1960.     if (hResult)
  1961.     {
  1962.         DebugTrace("GetMemAllocRoutines failed in ServiceEntry.n");
  1963.         goto ret;
  1964.     }
  1965.     /* Open the Profile Section for this Transport Provider. */
  1966.     hResult = HrOpenSingleProvider(lpAdminProviders, &lpProfileObj);
  1967.     if (hResult)
  1968.     {
  1969.         DebugTrace("Unable to open the profile.n");
  1970.         goto ret;
  1971.     }
  1972.     /* Profile is open, get the properties out of it. */
  1973.     hResult = lpProfileObj->lpVtbl->GetProps(lpProfileObj,
  1974.         (LPSPropTagArray) &sptLogonArray, ulFlags & MAPI_UNICODE, &ulCount, &lpPropArray);
  1975.     if (HR_FAILED(hResult))
  1976.     {
  1977.         DebugTrace("GetProps failed in XP ServiceEntry.n");
  1978.         goto ret;
  1979.     }
  1980.     hResult = hrSuccess;
  1981.     /*  If the user passed in a property array to configure our profile
  1982.         with, then we'll merge this array with that from the profile
  1983.         section.  This merged array will, conditionally, be used in our
  1984.         Logon UI and, conditionally,  written out to the profile section.
  1985.         Also, lpLogonProps becomes our alias for the array no matter where
  1986.         the properties come from. */
  1987.     if (lpProps)
  1988.     {
  1989.         sc = ScMergeLogonProps(cValues, lpProps, ulCount,
  1990.             lpPropArray, lpAllocBuff, lpAllocMore, &lpLogonProps);
  1991.         if (FAILED(sc))
  1992.         {
  1993.             hResult = ResultFromScode(sc);
  1994.             DebugTrace("ScMergeLogonProps failed in XP ServiceEntry.n");
  1995.             goto ret;
  1996.         }
  1997.     }
  1998.     else
  1999.     {
  2000.         lpLogonProps = lpPropArray;
  2001.         lpPropArray = NULL;
  2002.     }
  2003.     Assert(ulCount == MAX_LOGON_PROPERTIES);
  2004.     ulCount -= TEMP_LOGON_PROPERTIES;
  2005.     /* Find out if the stored SAMPLE_FLAGS say we should have UI.
  2006.        But, only if we aren't already forcing UI to be presented. */
  2007.     if (fAllowUI && !fNeedUI && lpLogonProps)
  2008.     {
  2009.         if ((ArrayIndex(PR_SAMPLE_FLAGS, lpLogonProps).ulPropTag == PR_SAMPLE_FLAGS) &&
  2010.             (ArrayIndex(PR_SAMPLE_FLAGS, lpLogonProps).Value.l & PR_SAMPLE_FLAG_UI_ALWAYS))
  2011.                 fNeedUI = TRUE;
  2012.     }
  2013.     /* Fill in the logon UI structure */
  2014.     XPDialog.hInst = hInstance;
  2015.     XPDialog.hwnd = (HWND) ulUIParam;
  2016.     XPDialog.lppPropArray = &lpLogonProps;
  2017.     XPDialog.lpPTArray = (LPSPropTagArray) &sptLogonArray;
  2018.     XPDialog.AllocateBuffer = lpAllocBuff;
  2019.     XPDialog.AllocateMore = lpAllocMore;
  2020.     XPDialog.FreeBuffer = lpFreeBuff;
  2021.     XPDialog.lpMalloc = lpMalloc;
  2022.     XPDialog.lpMAPISup = lpMAPISup;
  2023.     XPDialog.fLogon = TRUE;
  2024.     XPDialog.ulFlags = ulFlags;
  2025.     /* Check the logon props BEFORE the dialog call, as the props will
  2026.        be freed if Cancel is selected, and we will want to know if the
  2027.        provider configuration information was valid */
  2028.     sc = ScCheckLogonProps(&XPDialog, FALSE);
  2029.     if ((sc == MAPI_E_USER_CANCEL) || (sc == MAPI_E_UNCONFIGURED))
  2030.     {
  2031.         if (fAllowUI)
  2032.         {
  2033.             fNeedUI = TRUE;
  2034.             fInitialParamsOk = FALSE;
  2035.         }
  2036.         else
  2037.             goto ret;
  2038.     }
  2039.     while (fAllowUI && fNeedUI)
  2040.     {
  2041.         sc = ScDoLogonDlg(&XPDialog);
  2042.         if (FAILED(sc))
  2043.         {
  2044.             hResult = ResultFromScode(sc);
  2045.             if (sc != MAPI_E_USER_CANCEL)
  2046.             {
  2047.                 DebugTrace("ScDoLogonDlg failed in XP ServiceEntry.n");
  2048.             }
  2049.             else
  2050.                 if (!fInitialParamsOk)
  2051.                     hResult = ResultFromScode(MAPI_E_UNCONFIGURED);
  2052.             goto ret;
  2053.         }
  2054.         if (!lpLogonProps)
  2055.         {
  2056.             hResult = ResultFromScode(MAPI_E_CALL_FAILED);
  2057.             DebugTrace("No Logon Props returned in XP ServiceEntry.n");
  2058.             goto ret;
  2059.         }
  2060.         /* Got a prop array, make sure everything in it is good */
  2061.         for (ulT = 0; ulT < ulCount; ulT++)
  2062.         {
  2063.             if (PROP_TYPE((lpLogonProps)[ulT].ulPropTag) == PT_ERROR)
  2064.             {
  2065.                 hResult = ResultFromScode(MAPI_E_UNCONFIGURED);
  2066.                 DebugTrace("Property %x not available, returning MAPI_E_UNCONFIGUREDn", PROP_ID((lpLogonProps)[ulT].ulPropTag));
  2067.                 goto ret;
  2068.             }
  2069.         }
  2070.         /* Do some simple validation of the Logon Props */
  2071.         sc = ScCheckLogonProps(&XPDialog, TRUE);
  2072.         if (sc == MAPI_E_USER_CANCEL)
  2073.             goto ret;
  2074.         else if (sc == MAPI_E_UNCONFIGURED)
  2075.             continue;
  2076.         else
  2077.             fNeedUI = FALSE;
  2078.     }
  2079.     /*  If the user passed in properties and didn't request UI, then
  2080.         we need to check the array of Logon Props now.  If they are
  2081.         bad, then we'll simply return an error. */
  2082.     if (lpProps && !(ulFlags & SERVICE_UI_ALWAYS))
  2083.     {
  2084.         if (sc = ScCheckLogonProps(&XPDialog, FALSE))
  2085.         {
  2086.             hResult = ResultFromScode(sc);
  2087.             DebugTrace("User supplied properties did not pass validation.n");
  2088.             goto ret;
  2089.         }
  2090.     }
  2091.     /*  If we get here, everything is fine and we can proceed. But first
  2092.         we should write the properties out if the user is willing. */
  2093.     ulT = ArrayIndex(PR_SAMPLE_FLAGS, lpLogonProps).ulPropTag;
  2094.     Assert(PROP_TYPE(ulT) != PT_ERROR);
  2095.     ulT = ArrayIndex(PR_SAMPLE_FLAGS, lpLogonProps).Value.ul;
  2096.     if (ulT & PR_SAMPLE_FLAG_SAVE_DATA)
  2097.     {
  2098.         hResult = lpProfileObj->lpVtbl->SetProps(lpProfileObj,
  2099.             ulCount, lpLogonProps, NULL);
  2100.         if (hResult)
  2101.         {
  2102.             DebugTrace("SetProps failed in XP ServiceEntry.n");
  2103.             goto ret;
  2104.         }
  2105.         lpProfileObj->lpVtbl->SaveChanges(lpProfileObj, 0);
  2106.     }
  2107. ret:
  2108.     UlRelease(lpProfileObj);
  2109.     lpFreeBuff(lpPropArray);
  2110.     lpFreeBuff(lpLogonProps);
  2111.     DebugTraceResult(ServiceEntry, hResult);
  2112.     return hResult;
  2113. };
  2114. /*
  2115.  -  HrOpenSingleProvider
  2116.  -
  2117.  *  Purpose:
  2118.  *      Gets the IProfileSect object for a single provider from the
  2119.  *      ProviderTable in the IProviderAdmin object.  My entry in the
  2120.  *      table is supposed to be in the first row - this better be true.
  2121.  *
  2122.  */
  2123. HRESULT
  2124. HrOpenSingleProvider(LPPROVIDERADMIN lpAdminProviders,
  2125.     LPPROFSECT FAR * lppProfSect)
  2126. {
  2127.     HRESULT hResult;
  2128.     LPMAPITABLE lpTable = NULL;
  2129.     LPSRowSet lpRows = NULL;
  2130.     LPSPropValue lpProp;
  2131.     SPropTagArray sptaProvider = {1, {PR_PROVIDER_UID}};
  2132.     hResult = lpAdminProviders->lpVtbl->GetProviderTable(
  2133.         lpAdminProviders, 0, &lpTable);
  2134.     if (hResult)
  2135.         goto ret;
  2136.     hResult = lpTable->lpVtbl->SetColumns(lpTable, &sptaProvider, 0L);
  2137.     if (hResult)
  2138.         goto ret;
  2139.     hResult = lpTable->lpVtbl->QueryRows(lpTable, 1, 0, &lpRows);
  2140.     if (hResult || !lpRows || !lpRows->cRows)
  2141.     {
  2142.         hResult = ResultFromScode(MAPI_E_NOT_FOUND);
  2143.         goto ret;
  2144.     }
  2145.     Assert(lpRows->aRow[0].cValues == 1);
  2146.     lpProp = lpRows->aRow[0].lpProps;
  2147.     Assert(lpProp);
  2148.     Assert(lpProp->ulPropTag == PR_PROVIDER_UID);
  2149.     /* Found the right property; use it to open our section */
  2150.     hResult = lpAdminProviders->lpVtbl->OpenProfileSection(
  2151.         lpAdminProviders, (LPMAPIUID) lpProp->Value.bin.lpb,
  2152.         NULL, MAPI_MODIFY, lppProfSect);
  2153. ret:
  2154.     FreeProws(lpRows);
  2155.     UlRelease(lpTable);
  2156.     DebugTraceResult(HrOpenSingleProvider, hResult);
  2157.     return hResult;
  2158. }
  2159. /*
  2160.  -  ScMergeLogonProps
  2161.  -
  2162.  *  Purpose:
  2163.  *      This function merges a property array that the user passed into
  2164.  *      ServiceEntry with the property array of Transport Logon props
  2165.  *      found in the Profile.  This merged array is what either gets
  2166.  *      passed into the XP Logon dialog (in the case when UI is requested)
  2167.  *      or simply gets written out to the profile section for the
  2168.  *      Transport Provider.
  2169.  *
  2170.  *  Parameters:
  2171.  *      cProps1             - count of properties in the users array
  2172.  *      lpProps1            - the users property array
  2173.  *      cProps2             - count of properties from the XP profile
  2174.  *      lpProps2            - property array from the XP profile
  2175.  *      lpAllocBuff         - MAPI allocator used by ScDupPropset
  2176.  *      lppPropsDest        - receives the newly built prop array
  2177.  */
  2178. SCODE
  2179. ScMergeLogonProps(
  2180.     ULONG cProps1,
  2181.     LPSPropValue lpProps1,
  2182.     ULONG cProps2,
  2183.     LPSPropValue lpProps2,
  2184.     LPALLOCATEBUFFER lpAllocBuff,
  2185.     LPALLOCATEMORE lpAllocMore,
  2186.     LPSPropValue FAR * lppPropsDest)
  2187. {
  2188.     SCODE sc;
  2189.     ULONG ulTag;
  2190.     TCHAR szEmpty[1] = "";
  2191.     ULONG cT = cProps2;
  2192.     UINT cch;
  2193.     UINT id;
  2194.     LPTSTR lpszT;
  2195.     /*  If any of the properties that we tried to read from the
  2196.         profile didn't exist, then the profile provider would return
  2197.         them to us as type PT_ERROR.  We will convert these to either
  2198.         empty strings or zeros before we try to merge in the user
  2199.         supplied values.  This will allow us to do parameter validation
  2200.         on the properties even if the user didn't ask for UI. */
  2201.     while (cT--)
  2202.     {
  2203.         ulTag = lpProps2[cT].ulPropTag;
  2204.         if (PROP_TYPE(ulTag) == PT_ERROR)
  2205.         {
  2206.             id = (UINT)PROP_ID(ulTag);
  2207.             switch (id)
  2208.             {
  2209.             case (UINT)PROP_ID(PR_SAMPLE_DISPLAY_NAME):
  2210.             case (UINT)PROP_ID(PR_SAMPLE_EMAIL_ADDR_TYPE):
  2211.             case (UINT)PROP_ID(PR_SAMPLE_EMAIL_ADDRESS):
  2212.             case (UINT)PROP_ID(PR_SAMPLE_INBOUND_DIR):
  2213.             case (UINT)PROP_ID(PR_SAMPLE_OUTBOUND_DIR):
  2214.             case (UINT)PROP_ID(PR_SAMPLE_FILENAME):
  2215.             case (UINT)PROP_ID(PR_SAMPLE_DIRECTORY):
  2216.             case (UINT)PROP_ID(PR_SAMPLE_LOGFILE):
  2217.             case (UINT)PROP_ID(PR_TEMP_LOGHIGHWATER):
  2218.             case (UINT)PROP_ID(PR_TEMP_LOGLOWWATER):
  2219.                 lpProps2[cT].ulPropTag = PROP_TAG(PT_TSTRING, id);
  2220.                 lpProps2[cT].Value.LPSZ = szEmpty;
  2221.                 break;
  2222.             case (UINT)PROP_ID(PR_SAMPLE_LOGHIGHWATER):
  2223.             case (UINT)PROP_ID(PR_SAMPLE_LOGLOWWATER):
  2224.             case (UINT)PROP_ID(PR_SAMPLE_FLAGS):
  2225.                 lpProps2[cT].ulPropTag = PROP_TAG(PT_LONG, id);
  2226.                 lpProps2[cT].Value.l = 0;
  2227.                 break;
  2228.             case (UINT)PROP_ID(PR_TEMP_PEER_TO_PEER):
  2229.             case (UINT)PROP_ID(PR_TEMP_UI_ALWAYS):
  2230.             case (UINT)PROP_ID(PR_TEMP_LOG_EVENTS):
  2231.             case (UINT)PROP_ID(PR_TEMP_SAVE_DATA):
  2232.                 lpProps2[cT].ulPropTag = PROP_TAG(PT_BOOLEAN, id);
  2233.                 lpProps2[cT].Value.b = FALSE;
  2234.                 break;
  2235.             default:
  2236.                 DebugTrace("Got a bad PropTag in ScMergeLogonProps.n");
  2237.             }
  2238.         }
  2239.     }
  2240.     /*  Now, replace the profile properties with those passed in by the
  2241.         user.  Check the ones of the type "File Path" to see that they
  2242.         have a slash as their last character.  If not, then add one. */
  2243.     while (cProps1--)
  2244.     {
  2245.         ulTag = lpProps1[cProps1].ulPropTag;
  2246.         switch (ulTag)
  2247.         {
  2248.             /* Do the String properties first */
  2249.         case PR_SAMPLE_INBOUND_DIR:
  2250.         case PR_SAMPLE_OUTBOUND_DIR:
  2251.         case PR_SAMPLE_DIRECTORY:
  2252.             if (lpProps1[cProps1].Value.LPSZ)
  2253.             {
  2254.                 cch = lstrlen(lpProps1[cProps1].Value.LPSZ);
  2255.                 if (cch && lpProps1[cProps1].Value.LPSZ[cch - 1] != '\')
  2256.                 {
  2257.                     sc = lpAllocMore((cch + 2) * sizeof(TCHAR),
  2258.                         lpProps2, (LPVOID FAR *) &lpszT);
  2259.                     if (!FAILED(sc))
  2260.                     {
  2261.                         lstrcpy(lpszT, lpProps1[cProps1].Value.LPSZ);
  2262.                         lpszT[cch] = '\';
  2263.                         lpszT[cch + 1] = '';
  2264.                         ArrayIndex(ulTag, lpProps2).Value.LPSZ = lpszT;
  2265.                     }
  2266.                 }
  2267.                 else
  2268.                     ArrayIndex(ulTag, lpProps2).Value.LPSZ = lpProps1[cProps1].Value.LPSZ;
  2269.             }
  2270.             else
  2271.                 ArrayIndex(ulTag, lpProps2).Value.LPSZ = szEmpty;
  2272.             break;
  2273.         case PR_SAMPLE_DISPLAY_NAME:
  2274.         case PR_SAMPLE_EMAIL_ADDR_TYPE:
  2275.         case PR_SAMPLE_EMAIL_ADDRESS:
  2276.         case PR_SAMPLE_FILENAME:
  2277.         case PR_SAMPLE_LOGFILE:
  2278.             if (lpProps1[cProps1].Value.LPSZ)
  2279.                 ArrayIndex(ulTag, lpProps2).Value.LPSZ = lpProps1[cProps1].Value.LPSZ;
  2280.             else
  2281.                 ArrayIndex(ulTag, lpProps2).Value.LPSZ = szEmpty;
  2282.             break;
  2283.             /* Then the long values */
  2284.         case PR_SAMPLE_LOGHIGHWATER:
  2285.         case PR_SAMPLE_LOGLOWWATER:
  2286.         case PR_SAMPLE_FLAGS:
  2287.             ArrayIndex(ulTag, lpProps2).Value.l = lpProps1[cProps1].Value.l;
  2288.             break;
  2289.             /* We have a bad value, lets return an error! */
  2290.         default:
  2291.             DebugTrace("Got a bad PropTag in ScMergeLogonProps()");
  2292.             return E_INVALIDARG;
  2293.         }
  2294.     }
  2295.     return ScDupPropset((int)cProps2, lpProps2, lpAllocBuff, lppPropsDest);
  2296. }
  2297. /*
  2298.  -  HrDeleteDeferred
  2299.  -
  2300.  *  Purpose:
  2301.  *      Removes a deferred message node from the list when the Spooler
  2302.  *      does a NOTIFY_ABORT_DEFERRED.
  2303.  *
  2304.  *  Parameters:
  2305.  *      lpxpl           The session owning the deferred message
  2306.  *      lpsbinEID       EntryID of the deferred message to delete
  2307.  *
  2308.  *  Returns:
  2309.  *      hResult         Indicating Success/Faailure
  2310.  */
  2311. HRESULT
  2312. HrDeleteDeferred(LPXPL lpxpl, LPSBinary lpsbinEID)
  2313. {
  2314.     LPDEFMSG lpDefMsg;
  2315.     LPDEFMSG *lppDefMsg = &(lpxpl->lpDeferredList);
  2316.     while (lpDefMsg = *lppDefMsg)
  2317.     {
  2318.         if ((lpDefMsg->sbinEIDDef.cb == lpsbinEID->cb) &&
  2319.             !memcmp(lpDefMsg->sbinEIDDef.lpb,
  2320.                     lpsbinEID->lpb,
  2321.                     (UINT)lpsbinEID->cb))
  2322.         {
  2323.             *lppDefMsg = lpDefMsg->lpNext;
  2324.             break;
  2325.         }
  2326.         else
  2327.             lppDefMsg = &(lpDefMsg->lpNext);
  2328.     }
  2329.     lpxpl->FreeBuffer(lpDefMsg);
  2330.     return hrSuccess;
  2331. }
  2332. /*
  2333.  *  WizardEntry()
  2334.  *
  2335.  *  Purpose:
  2336.  *
  2337.  *      This is the initial entrypoint for the MAPI 1.0 configuration
  2338.  *      wizard.  This function tells the wizard DLL how many pages the
  2339.  *      configuration for this service requires as well as the dialog
  2340.  *      procedure to call for each individual event.
  2341.  *
  2342.  *  Arguments:
  2343.  *
  2344.  *      hInstance       the instance of my dll, this can be used to
  2345.  *                      retrieve resources out of my DLL, etc.
  2346.  *
  2347.  *      lppszRsrcName   [OUT]   on return, this buffer is filled with
  2348.  *                              the full name of the dialog resource ID.
  2349.  *                              Note that this requires the name to be a
  2350.  *                              text value and not something generated
  2351.  *                              with the MAKEINTRESOURCE() macro
  2352.  *
  2353.  *      lpfnDlgProc     [OUT]   on return, holds a function pointer to
  2354.  *                              the dialog proc to call for each event
  2355.  *
  2356.  *      lpMapiProp      the pointer to a IMAPIProp object that is my
  2357.  *                      interface to the profile.
  2358.  *
  2359.  *      lpsup           A profile suport object that can be used to
  2360.  *                      get MAPI allocators
  2361.  *
  2362.  *  Returns:
  2363.  *
  2364.  *      (SCODE)         S_OK
  2365.  */
  2366. ULONG STDAPICALLTYPE
  2367. WizardEntry (HINSTANCE hInstance,
  2368.     LPTSTR FAR * lppszRsrcName,
  2369.     DLGPROC FAR * lpfnDlgProc,
  2370.     LPMAPIPROP lpMapiProp,
  2371.     LPVOID lpsup)
  2372. {
  2373.     const static TCHAR szWizTemplate[] = "SampleTransportWizard";
  2374.     Unreferenced (lpsup);
  2375.     
  2376.     /*  Should probably mutex access here */
  2377.     *lppszRsrcName = (LPTSTR)szWizTemplate;
  2378.     *lpfnDlgProc = (DLGPROC) WizardWndProc;
  2379.     lpmpWizard = lpMapiProp;
  2380.     UlAddRef (lpMapiProp);
  2381.     return S_OK;
  2382. }
  2383. /*
  2384.  *  TogglePage()
  2385.  *
  2386.  *  Purpose:
  2387.  *
  2388.  *      Loops through the controls on a wizard page and eiter
  2389.  *      enables/shows the control or hides/disables it.
  2390.  */
  2391. VOID
  2392. TogglePage (HWND hdlg, UINT ipage, BOOL fEnable)
  2393. {
  2394.     UINT ictl = 0;
  2395.     HANDLE hctl;
  2396.     while (hctl = GetDlgItem (hdlg, (WIZ_BASE + (ipage * 10) + ictl++)))
  2397.     {
  2398.         EnableWindow(hctl, fEnable);
  2399.         ShowWindow (hctl, (fEnable ? SW_SHOW : SW_HIDE));
  2400.     }
  2401. }
  2402. BOOL STDAPICALLTYPE
  2403. WizardWndProc (HWND hDlg,
  2404.     UINT wMsgID,
  2405.     WPARAM wParam,
  2406.     LPARAM lParam)
  2407. {
  2408.     UINT cb;
  2409.     UINT cpageJump = 1;
  2410.     UINT idFocus = 0;
  2411.     static fInited = FALSE;
  2412.     static UINT ipWiz = 0;
  2413.     static SPropValue rgvalWiz[cWizProps] = {0};
  2414.     static CHAR rgchName[cchNameMax + 1] = {0};
  2415.     static CHAR rgchType[cchTypeMax + 1] = {0};
  2416.     static CHAR rgchUNC[MAX_PATH] = {0};
  2417.     static CHAR rgchPath[MAX_PATH] = {0};
  2418.     switch (wMsgID)
  2419.     {
  2420.       case WM_INITDIALOG:
  2421.         if (!fInited)
  2422.         {
  2423.             fInited = TRUE;
  2424.             SetWindowText (GetDlgItem (hDlg, IDC_TypeEdit), "MSPEER");
  2425.             SendMessage (GetDlgItem (hDlg, IDC_TypeEdit), EM_LIMITTEXT, (WPARAM)cchTypeMax, 0);
  2426.             SendMessage (GetDlgItem (hDlg, IDC_NameEdit), EM_LIMITTEXT, (WPARAM)cchNameMax, 0);
  2427.             SendMessage (GetDlgItem (hDlg, IDC_UNCEdit), EM_LIMITTEXT, (WPARAM)MAX_PATH - 1, 0);
  2428.             SendMessage (GetDlgItem (hDlg, IDC_PathEdit), EM_LIMITTEXT, (WPARAM)MAX_PATH - 1, 0);
  2429.             rgvalWiz[ipDispName].ulPropTag = PR_NULL;
  2430.             rgvalWiz[ipEmailType].ulPropTag = PR_NULL;
  2431.             rgvalWiz[ipEmailAddress].ulPropTag = PR_NULL;
  2432.             rgvalWiz[ipInbox].ulPropTag = PR_NULL;
  2433.             rgvalWiz[ipOutbox].ulPropTag = PR_SAMPLE_OUTBOUND_DIR;
  2434.             rgvalWiz[ipOutbox].Value.lpszA = "\TEMP";
  2435.             rgvalWiz[ipFilename].ulPropTag = PR_NULL;
  2436.             rgvalWiz[ipDirectory].ulPropTag = PR_NULL;
  2437.             rgvalWiz[ipFlags].ulPropTag = PR_SAMPLE_FLAGS;
  2438.             rgvalWiz[ipFlags].Value.l = PR_SAMPLE_FLAG_PEER_TO_PEER | PR_SAMPLE_FLAG_SAVE_DATA;
  2439.             rgvalWiz[ipLogFile].ulPropTag = PR_SAMPLE_LOGFILE;
  2440.             rgvalWiz[ipLogFile].Value.lpszA = "SMPXP.LOG";
  2441.             rgvalWiz[ipLogHigh].ulPropTag = PR_SAMPLE_LOGHIGHWATER;
  2442.             rgvalWiz[ipLogHigh].Value.l = 0;
  2443.             rgvalWiz[ipLogLow].ulPropTag = PR_SAMPLE_LOGLOWWATER;
  2444.             rgvalWiz[ipLogLow].Value.l = 0;
  2445.             DebugTrace ("MSPEER: Wizard page initializedn");
  2446.         }
  2447.         break;
  2448.       case WIZ_QUERYNUMPAGES:
  2449.         DebugTrace ("MSPEER: Wizard page count %dn", cpageMax);
  2450.         return (BOOL)cpageMax;
  2451.       case WM_CLOSE:
  2452.         UlRelease (lpmpWizard);
  2453.         lpmpWizard = NULL;
  2454.         break;
  2455.       case WM_COMMAND:
  2456.         switch (LOWORD(wParam))
  2457.         {
  2458.           case WIZ_NEXT:
  2459.             switch (ipWiz)
  2460.             {
  2461.               case 0:
  2462.                 idFocus = IDC_NameEdit;
  2463.                 break;
  2464.               case 1:
  2465.                 /*  Going from name page to address type */
  2466.                 if (!(cb = (UINT)GetWindowText (GetDlgItem (hDlg, IDC_NameEdit),
  2467.                                         rgchName, cchNameMax + 1)))
  2468.                 {
  2469.                     /*  We require a display name */
  2470.                     MessageBeep (0);
  2471.                     return 0;
  2472.                 }
  2473.                 rgvalWiz[ipDispName].ulPropTag = PR_SAMPLE_DISPLAY_NAME;
  2474.                 rgvalWiz[ipDispName].Value.lpszA = rgchName;
  2475.                 idFocus = IDC_TypeEdit;
  2476.                 break;
  2477.               case 2:
  2478.                 /* Going from type page to inbox */
  2479.                 if (!(cb = (UINT)GetWindowText (GetDlgItem (hDlg, IDC_TypeEdit),
  2480.                                         rgchType, cchTypeMax + 1)))
  2481.                 {
  2482.                     /*  We require an address type */
  2483.                     MessageBeep (0);
  2484.                     return 0;
  2485.                 }
  2486.                 rgvalWiz[ipEmailType].ulPropTag = PR_SAMPLE_EMAIL_ADDR_TYPE;
  2487.                 rgvalWiz[ipEmailType].Value.lpszA = rgchType;
  2488.                 idFocus = IDC_UNCEdit;
  2489.                 break;
  2490.               case 3:
  2491.                 /* Going from inbox page to path page */
  2492.                 if (!(cb = (UINT)GetWindowText (GetDlgItem (hDlg, IDC_UNCEdit),
  2493.                                         rgchUNC, MAX_PATH)))
  2494.                 {
  2495.                     /*  We require an address type */
  2496.                     MessageBeep (0);
  2497.                     return 0;
  2498.                 }
  2499.                 rgvalWiz[ipEmailAddress].ulPropTag = PR_SAMPLE_EMAIL_ADDRESS;
  2500.                 rgvalWiz[ipEmailAddress].Value.lpszA = rgchUNC;
  2501.                 idFocus = IDC_PathEdit;
  2502.                 break;
  2503.               case 4:
  2504.                 /* Going from the path page to completion*/
  2505.                 rgvalWiz[ipInbox].ulPropTag = PR_SAMPLE_INBOUND_DIR;
  2506.                 if ((cb = (UINT)GetWindowText (GetDlgItem (hDlg, IDC_PathEdit), rgchPath, MAX_PATH)))
  2507.                     rgvalWiz[ipInbox].Value.lpszA = rgchPath;
  2508.                 else
  2509.                     rgvalWiz[ipInbox].Value.lpszA = rgvalWiz[ipEmailAddress].Value.lpszA;
  2510.                 Assert (lpmpWizard);
  2511.                 lpmpWizard->lpVtbl->SetProps (lpmpWizard, cWizProps, rgvalWiz, NULL);
  2512.                 break;
  2513.               default:
  2514.                 Assert (FALSE);
  2515.                 break;
  2516.             }
  2517.             /*  Disable Current Page */
  2518.             TogglePage (hDlg, ipWiz, FALSE);
  2519.             /*  Enable Next Page */
  2520.             TogglePage (hDlg, ++ipWiz, TRUE);
  2521.             SetFocus (GetDlgItem (hDlg, idFocus));
  2522. #ifdef  _WIN32
  2523.             SendDlgItemMessage (hDlg, idFocus, EM_SETSEL, 0, -1);
  2524. #else
  2525.             SendDlgItemMessage (hDlg, idFocus, EM_SETSEL, 0, MAKELONG(0,-1));
  2526. #endif
  2527.             return (BOOL)cpageJump;
  2528.           case WIZ_PREV:
  2529.             /*  Disable Current Page */
  2530.             TogglePage (hDlg, ipWiz, FALSE);
  2531.             
  2532.             /*  Enable Previous Page */
  2533.             TogglePage (hDlg, --ipWiz, TRUE);
  2534.             switch (ipWiz)
  2535.             {
  2536.               case 1:
  2537.                 idFocus = IDC_NameEdit;
  2538.                 break;
  2539.               case 2:
  2540.                 idFocus = IDC_TypeEdit;
  2541.                 break;
  2542.               case 3:
  2543.                 idFocus = IDC_UNCEdit;
  2544.                 break;
  2545.               case 4:
  2546.                 idFocus = IDC_PathEdit;
  2547.                 break;
  2548.               default:
  2549.                 break;
  2550.             }
  2551.             SetFocus (GetDlgItem (hDlg, idFocus));
  2552. #ifdef  _WIN32
  2553.             SendDlgItemMessage (hDlg, idFocus, EM_SETSEL, 0, -1);
  2554. #else
  2555.             SendDlgItemMessage (hDlg, idFocus, EM_SETSEL, 0, MAKELONG(0,-1));
  2556. #endif
  2557.             return (BOOL)cpageJump;
  2558.           default:
  2559.             return FALSE;
  2560.         }
  2561.         break;
  2562.       default:
  2563.         return FALSE;
  2564.     }
  2565.     return TRUE;
  2566. }