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

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