home *** CD-ROM | disk | FTP | other *** search
/ Power GUI Programming with VisualAge C++ / powergui.iso / trialva / ibmcppw / sdk / mapi / win16 / dev / sample.xp / xpbase.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-07-11  |  95.5 KB  |  3,138 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 && lpxpl)
  983.     {
  984.         /* Error. Get rid of anything already on the session object. */
  985.  
  986.         CleanupSession(lpxpl);
  987.         lpxpl->lpVtbl->Release(lpxpl);
  988.     }
  989.  
  990.     DebugTraceResult(XPP_TransportLogon, hResult);
  991.     return hResult;
  992. }
  993.  
  994.  
  995. /*
  996.  -  lpxpl->lpVtbl->AddressTypes
  997.  -
  998.  *  Purpose:
  999.  *      Called by the Spooler to find out what recipients it should expect
  1000.  *      this transport to handle.
  1001.  *
  1002.  *  Parameters:
  1003.  *      ulFlags             Ignored for now.
  1004.  *      lpcAdrType          Pointer: where to store number of address types
  1005.  *      lpppAdrTypeArray    Pointer: where to store list of address types
  1006.  *      lpcMAPIUID          Pointer: where to store number of UID's
  1007.  *      lpppMAPIUIDArray    Pointer: where to store list of MAPI UID's
  1008.  *
  1009.  *  Returns:
  1010.  *      (HRESULT)           Errors encountered if any.
  1011.  *
  1012.  *  Operation:
  1013.  *      Returns the Address Type entered at Logon time in the address type
  1014.  *      array. Makes no use of the UID array.
  1015.  */
  1016.  
  1017. STDMETHODIMP
  1018. XPL_AddressTypes(LPXPL lpxpl,
  1019.     ULONG * lpulFlags,
  1020.     ULONG * lpcAdrType, LPTSTR * *lpppAdrTypeArray,
  1021.     ULONG * lpcMAPIUID, LPMAPIUID * *lpppMAPIUIDArray)
  1022. {
  1023.     ULONG cb;
  1024.     SCODE sc;
  1025.     LPTSTR lpsz;
  1026.  
  1027.     /* We are returning an array with exactly one value.  We first need
  1028.        to AllocateMore a buffer (that is linked to the lpxpl object) and
  1029.        copy our Email Address Type into there.  We then return the address
  1030.        of this copy of our AddressType.  */
  1031.  
  1032.     if ( *lpulFlags & ~(MAPI_UNICODE) )
  1033.         return ResultFromScode( MAPI_E_UNKNOWN_FLAGS );
  1034.  
  1035.     if ( *lpulFlags & MAPI_UNICODE )
  1036.         return ResultFromScode( MAPI_E_BAD_CHARWIDTH ) ;
  1037.  
  1038.     *lpcAdrType = 1;
  1039.  
  1040.     lpsz = ArrayIndex(PR_SAMPLE_EMAIL_ADDR_TYPE, lpxpl->lpPropArray).Value.LPSZ;
  1041.  
  1042.     cb = (lstrlen(lpsz) + 1) * sizeof(TCHAR);
  1043.  
  1044.     sc = lpxpl->AllocateMore(cb, (LPVOID) lpxpl, (LPVOID *) &lpxpl->lpszAdrType);
  1045.  
  1046.     if (FAILED(sc))
  1047.     {
  1048.         DebugTrace("AllocateMore in XPL_AddressType failed!\n");
  1049.         return ResultFromScode(sc);
  1050.     }
  1051.  
  1052.     lstrcpy(lpxpl->lpszAdrType, lpsz);
  1053.  
  1054.     *lpppAdrTypeArray = &(lpxpl->lpszAdrType);
  1055.  
  1056.     /* Routing by UID has no particular meaning for this transport. */
  1057.  
  1058.     *lpcMAPIUID = 0;
  1059.     *lpppMAPIUIDArray = NULL;
  1060.  
  1061.     return hrSuccess;
  1062. }
  1063.  
  1064.  
  1065. /*
  1066.  -  lpxpl->lpVtbl->RegisterOptions
  1067.  -
  1068.  *  Purpose:
  1069.  *      Called by the Spooler to find out what per-message or per-recipient
  1070.  *      options this transport might wish supported.
  1071.  *
  1072.  *  Parameters:
  1073.  *      lpulFlags           Indicates whether strings are UNICODE or not.
  1074.  *      lpcOptions          Pointer: where to store number of address
  1075.  *                          types for which options are being requested
  1076.  *      lppOptions          Pointer: where to store a list of display
  1077.  *                          names associated with each address type
  1078.  *
  1079.  *  Returns:
  1080.  *      (HRESULT)           Errors encountered if any.
  1081.  */
  1082.  
  1083. STDMETHODIMP
  1084. XPL_RegisterOptions(LPXPL lpxpl,
  1085.     ULONG * lpulFlags,
  1086.     ULONG * lpcOptions,
  1087.     LPOPTIONDATA * lppOptions)
  1088. {
  1089.     /* Just give them what we have in our XPLogon object.       */
  1090.     /* These options were initialized at TransportLogon() time. */
  1091.  
  1092.     if ( *lpulFlags & ~(MAPI_UNICODE) )
  1093.         return ResultFromScode( MAPI_E_UNKNOWN_FLAGS );
  1094.  
  1095.     if ( *lpulFlags & MAPI_UNICODE )
  1096.         return ResultFromScode( MAPI_E_BAD_CHARWIDTH ) ;
  1097.  
  1098.     *lpcOptions = lpxpl->cOptData;
  1099.     *lppOptions = lpxpl->lpOptData;
  1100.  
  1101.     return 0;
  1102. }
  1103.  
  1104.  
  1105. /*
  1106.  -  lpxpl->lpVtbl->TransportLogoff
  1107.  -
  1108.  *  Purpose:
  1109.  *      Called by the Spooler to log off a particular Transport session.
  1110.  *
  1111.  *  Parameters:
  1112.  *      ulFlags             May contain LOGOFF_HURRY, which tells
  1113.  *                          the transport to close this session
  1114.  *                          as quickly as possible.
  1115.  *
  1116.  *  Returns:
  1117.  *      (HRESULT)           Errors encountered if any.
  1118.  *
  1119.  *  Operation:
  1120.  *      Find the session. Tell MAPI the session's going away, unlink it from
  1121.  *      the list, close open handles and deallocate session memory.
  1122.  */
  1123.  
  1124. STDMETHODIMP
  1125. XPL_TransportLogoff(LPXPL lpxpl, ULONG ulFlags)
  1126. {
  1127.     SCODE sc = S_OK;
  1128.     LPXPL lpxplCurr;
  1129.     LPXPL lpxplPrev = NULL;
  1130.     LPXPP lpxpp = lpxpl->lpxppParent;
  1131.  
  1132.     /* Get the critical section */
  1133.  
  1134.     EnterCriticalSection(&lpxpp->csTransport);
  1135.  
  1136.     /* Find the session in the list. */
  1137.  
  1138.     lpxplCurr = lpxpp->XPSessionList;
  1139.  
  1140.     while (lpxplCurr)
  1141.     {
  1142.         if (lpxpl == lpxplCurr)
  1143.         {
  1144.             /* Unlink the session from the list. */
  1145.  
  1146.             if (lpxplPrev == NULL)
  1147.                 lpxpp->XPSessionList = lpxpl->lpNextSession;
  1148.             else
  1149.                 lpxplPrev->lpNextSession = lpxpl->lpNextSession;
  1150.  
  1151.             break;
  1152.         }
  1153.  
  1154.         lpxplPrev = lpxplCurr;
  1155.         lpxplCurr = lpxplCurr->lpNextSession;
  1156.     }
  1157.  
  1158.     /* Release the critical section */
  1159.  
  1160.     LeaveCriticalSection(&lpxpp->csTransport);
  1161.  
  1162.     /* lpxplCurr must be non-NULL if we found the session. */
  1163.  
  1164.     if (!lpxplCurr)
  1165.     {
  1166.         sc = MAPI_E_INVALID_PARAMETER;
  1167.         goto ret;
  1168.     }
  1169.  
  1170.     /* Clean up the stuff inside the session structure. This may
  1171.        cause the XPP object to be released. */
  1172.  
  1173.     CleanupSession(lpxpl);
  1174.  
  1175. ret:
  1176.     DebugTraceSc(TransportLogoff, sc);
  1177.     return ResultFromScode(sc);
  1178. }
  1179.  
  1180.  
  1181. /*
  1182.  -  lpxpl->lpVtbl->TransportNotify
  1183.  -
  1184.  *  Purpose:
  1185.  *      Called by the Spooler to call some event to the Transport's attention.
  1186.  *
  1187.  *  Parameters:
  1188.  *      lpulFlags           Flags passed bidirectionally.
  1189.  *                          This transport pays attention to the
  1190.  *                          (BEGIN/END/FLUSH)(INBOUND/OUTBOUND)
  1191.  *                          flags and ignores the others.
  1192.  *      lppvData            Data passed bidirectionally. Not
  1193.  *                          used by this transport.
  1194.  *
  1195.  *  Returns:
  1196.  *      (HRESULT)           Errors encountered if any.
  1197.  *
  1198.  *  Operation:
  1199.  *      If the flag has any bearing on inbound/outbound startup/shutdown,
  1200.  *      then the appropriate change is made to the transport status in the
  1201.  *      XPLogon object and the HrUpdateTransportStatus routine is called to
  1202.  *      ModifyStatusRow() the change.
  1203.  */
  1204.  
  1205. STDMETHODIMP
  1206. XPL_TransportNotify(LPXPL lpxpl,
  1207.     ULONG * lpulFlags,
  1208.     LPVOID * lppvData)
  1209. {
  1210.     HRESULT hResult = hrSuccess;
  1211.     LPXPP lpxpp = lpxpl->lpxppParent;
  1212.  
  1213. #define TRANSPORT_NOTIFY_FLAGS  (NOTIFY_BEGIN_INBOUND       | \
  1214.                                 NOTIFY_END_INBOUND          | \
  1215.                                 NOTIFY_BEGIN_INBOUND_FLUSH  | \
  1216.                                 NOTIFY_END_INBOUND_FLUSH    | \
  1217.                                 NOTIFY_BEGIN_OUTBOUND       | \
  1218.                                 NOTIFY_END_OUTBOUND         | \
  1219.                                 NOTIFY_BEGIN_OUTBOUND_FLUSH | \
  1220.                                 NOTIFY_END_OUTBOUND_FLUSH   | \
  1221.                                 NOTIFY_CANCEL_MESSAGE       | \
  1222.                                 NOTIFY_ABORT_DEFERRED)
  1223.  
  1224.     /* Validate we were passed a legal flag. */
  1225.  
  1226.     Assert(*lpulFlags & TRANSPORT_NOTIFY_FLAGS);
  1227.  
  1228.     /* Make sure we have a good session. */
  1229.  
  1230.     if (!FIsValidSession(lpxpl))
  1231.     {
  1232.         hResult = ResultFromScode(E_INVALIDARG);
  1233.         DebugTrace("FIsValidSession  failed in TransportNotify.\n");
  1234.         goto ret;
  1235.     }
  1236.  
  1237.     /* Get the Critical Section */
  1238.  
  1239.     EnterCriticalSection(&lpxpp->csTransport);
  1240.  
  1241.     /* Set appropriate status flags and re-register status row */
  1242.  
  1243.     if (*lpulFlags & NOTIFY_BEGIN_INBOUND)
  1244.     {
  1245.         DebugTrace("NOTIFY_BEGIN_INBOUND received and handled\n");
  1246.         lpxpl->ulTransportStatus |= STATUS_INBOUND_ENABLED;
  1247.     }
  1248.  
  1249.     if (*lpulFlags & NOTIFY_END_INBOUND)
  1250.     {
  1251.         DebugTrace("NOTIFY_END_INBOUND received and handled\n");
  1252.         lpxpl->ulTransportStatus &= ~STATUS_INBOUND_ENABLED;
  1253.     }
  1254.  
  1255.     if (*lpulFlags & NOTIFY_END_INBOUND_FLUSH)
  1256.     {
  1257.         DebugTrace("NOTIFY_END_INBOUND_FLUSH received and handled\n");
  1258.         lpxpl->ulTransportStatus &= ~STATUS_INBOUND_FLUSH;
  1259.     }
  1260.  
  1261.     if (*lpulFlags & NOTIFY_BEGIN_OUTBOUND)
  1262.     {
  1263.         DebugTrace("NOTIFY_BEGIN_OUTBOUND received and handled\n");
  1264.         lpxpl->ulTransportStatus |= STATUS_OUTBOUND_ENABLED;
  1265.     }
  1266.  
  1267.     if (*lpulFlags & NOTIFY_END_OUTBOUND)
  1268.     {
  1269.         DebugTrace("NOTIFY_END_OUTBOUND received and handled\n");
  1270.         lpxpl->ulTransportStatus &= ~STATUS_OUTBOUND_ENABLED;
  1271.     }
  1272.  
  1273.     if (*lpulFlags & NOTIFY_END_OUTBOUND_FLUSH)
  1274.     {
  1275.         DebugTrace("NOTIFY_END_OUTBOUND_FLUSH received and handled\n");
  1276.         lpxpl->ulTransportStatus &= ~STATUS_OUTBOUND_FLUSH;
  1277.     }
  1278.  
  1279.     if (*lpulFlags & NOTIFY_ABORT_DEFERRED)
  1280.     {
  1281.         DebugTrace("NOTIFY_ABORT_DEFERRED received and handled\n");
  1282.  
  1283.         hResult = HrDeleteDeferred(lpxpl, (LPSBinary)*lppvData);
  1284.     }
  1285.  
  1286.     /* We're just going to ignore NOTIFY_CANCEL_MESSAGE for now. */
  1287.  
  1288.     if (*lpulFlags & NOTIFY_CANCEL_MESSAGE)
  1289.     {
  1290.         DebugTrace("NOTIFY_CANCEL_MESSAGE received and ignored\n");
  1291.     }
  1292.  
  1293.     HrUpdateTransportStatus(lpxpl, 0L);
  1294.  
  1295.     /* Release the critical section. */
  1296.  
  1297.     LeaveCriticalSection(&lpxpp->csTransport);
  1298.  
  1299. ret:
  1300.  
  1301.     DebugTraceResult(XPL_TransportNotify, hResult);
  1302.     return hResult;
  1303. }
  1304.  
  1305.  
  1306. /*
  1307.  -  XPL_ValidateState
  1308.  -
  1309.  *  Purpose:
  1310.  *      Logon object method used by Spooler if ValidateState is called on
  1311.  *      the spooler status object.
  1312.  *
  1313.  *  Parameters:
  1314.  *      lpxpl               This pointer for logon object
  1315.  *      ulUIParam           Window handle
  1316.  *      ulFlags
  1317.  *
  1318.  *  Returns:
  1319.  *      (HRESULT)           E_INVALIDARG if object doesn't
  1320.  *                          look like a XPL; MAPI_E_NO_SUPPORT
  1321.  *                          otherwise.
  1322.  *
  1323.  *  Operation:
  1324.  *      Compare the PR_ADDRTYPE found in the profile to the one I am
  1325.  *      currently using.  If it has changed, then SpoolerNotify() to
  1326.  *      ask to be reloaded so MAPI will call AddressTypes() and
  1327.  *      RegisterOptions() on us again!
  1328.  *
  1329.  *  Note: We could check all the properties in our profile and be a
  1330.  *        better implementation of this call.  But for now, AddrType
  1331.  *        is the most important property to check.
  1332.  */
  1333.  
  1334. STDMETHODIMP
  1335. XPL_ValidateState(LPXPL lpxpl,
  1336.     ULONG ulUIParam,
  1337.     ULONG ulFlags)
  1338. {
  1339.     SCODE sc = S_OK;
  1340.     HRESULT hResult;
  1341.     LPPROFSECT lpProf = NULL;
  1342.     LPSPropValue lpspvAddrType = NULL;
  1343.     LPMAPISUP lpMAPISup = lpxpl->lpMAPISup;
  1344.     LPSPropValue lpPropArray = NULL;
  1345.     LPTSTR lpszAddrType = NULL;
  1346.  
  1347.     /*  If it doesn't seem to be an object or refcount is zero, return zero */
  1348.  
  1349.     if (IsBadReadPtr(lpxpl, sizeof(XPL)) ||
  1350.         lpxpl->lcInit == 0 ||
  1351.         lpxpl->lpMySession != lpxpl)
  1352.     {
  1353.         DebugTraceSc(XPL_ValidateState, E_INVALIDARG);
  1354.         return ResultFromScode(E_INVALIDARG);
  1355.     }
  1356.  
  1357.     if (ulFlags & ~SUPPRESS_UI)
  1358.     {
  1359.         DebugTraceSc(XPL_ValidateState, MAPI_E_UNKNOWN_FLAGS);
  1360.         return ResultFromScode(MAPI_E_UNKNOWN_FLAGS);
  1361.     }
  1362.  
  1363.     sc = ScCopySessionProps(lpxpl, &lpPropArray, NULL);
  1364.  
  1365.     if (FAILED(sc))
  1366.     {
  1367.         hResult = ResultFromScode(sc);
  1368.         DebugTrace("ScCopySessionProps failed in ValidateState.\n");
  1369.         goto ret;
  1370.     }
  1371.  
  1372.     lpszAddrType = ArrayIndex(PR_SAMPLE_EMAIL_ADDR_TYPE, lpPropArray).Value.LPSZ;
  1373.  
  1374.     /* Try to open our profile. */
  1375.  
  1376.     hResult = lpMAPISup->lpVtbl->OpenProfileSection(lpMAPISup,
  1377.         (LPMAPIUID) NULL, MAPI_MODIFY, &lpProf);
  1378.  
  1379.     if (hResult)
  1380.     {
  1381.         DebugTrace("OpenProfileSection  failed in ValidateState.\n");
  1382.         goto ret;
  1383.     }
  1384.  
  1385.     hResult = HrGetOneProp((LPMAPIPROP)lpProf,
  1386.             PR_SAMPLE_EMAIL_ADDR_TYPE, &lpspvAddrType);
  1387.  
  1388.     if (HR_FAILED(hResult))
  1389.     {
  1390.         DebugTrace("HrGetOneProp failed in ValidateState.\n");
  1391.         goto ret;
  1392.     }
  1393.  
  1394.     /* Now, compare what I think my AddrType is to that in the profile.
  1395.        If they are different, tell the spooler I'd like to be reloaded. */
  1396.  
  1397.     if (lpspvAddrType->ulPropTag == PR_SAMPLE_EMAIL_ADDR_TYPE)
  1398.     {
  1399.         if (lstrcmp(lpszAddrType, lpspvAddrType->Value.LPSZ))
  1400.         {
  1401.             hResult = lpMAPISup->lpVtbl->SpoolerNotify(lpMAPISup,
  1402.                 NOTIFY_CONFIG_CHANGE, NULL);
  1403.  
  1404.             if (HR_FAILED(hResult))
  1405.             {
  1406.                 DebugTrace("SpoolerNotify failed  in ValidateState.\n");
  1407.                 goto ret;
  1408.             }
  1409.         }
  1410.     }
  1411.  
  1412.     hResult = hrSuccess;
  1413.  
  1414. ret:
  1415.     UlRelease(lpProf);
  1416.  
  1417.     lpxpl->FreeBuffer(lpPropArray);
  1418.     lpxpl->FreeBuffer(lpspvAddrType);
  1419.  
  1420.     DebugTraceResult(XPL_ValidateState, hResult);
  1421.     return hResult;
  1422. }
  1423.  
  1424.  
  1425. /*
  1426.  -  XPL_FlushQueues
  1427.  -
  1428.  *  Purpose:
  1429.  *      Logon object method used by Spooler if FlushQueues is called on
  1430.  *      the spooler status object.
  1431.  *
  1432.  *  Parameters:
  1433.  *      lpxpl               This pointer for logon object
  1434.  *      ulUIParam           Window handle
  1435.  *      cbTargetTransport   Count of bytes in Entryid. Zero.
  1436.  *      lpTargetTransport   Entryid of transport. NULL.
  1437.  *      ulFlags
  1438.  *
  1439.  *  Returns:
  1440.  *      (HRESULT)           E_INVALIDARG if object doesn't
  1441.  *                          look like a XPL; MAPI_E_NO_SUPPORT
  1442.  *                          otherwise.
  1443.  *
  1444.  *  Operation:
  1445.  *      Validate the object pointer. Return MAPI_E_NO_SUPPORT.
  1446.  */
  1447.  
  1448. STDMETHODIMP
  1449. XPL_FlushQueues(LPXPL lpxpl,
  1450.     ULONG ulUIParam,
  1451.     ULONG cbTargetTransport,
  1452.     LPENTRYID lpTargetTransport,
  1453.     ULONG ulFlags)
  1454. {
  1455.     HRESULT hResult;
  1456.  
  1457.     /*  Validate the object */
  1458.  
  1459.     /*  If it doesn't seem to be an object or refcount is zero, return zero */
  1460.  
  1461.     if (IsBadReadPtr(lpxpl, sizeof(XPL)) ||
  1462.         lpxpl->lcInit == 0 ||
  1463.         lpxpl->lpMySession != lpxpl)
  1464.     {
  1465.         DebugTraceSc(XPL_FlushQueues, E_INVALIDARG);
  1466.         return ResultFromScode(E_INVALIDARG);
  1467.     }
  1468.  
  1469.     /*  There is nothing special the sample transport
  1470.         needs to do before signaling its readiness for
  1471.         flushing */
  1472.  
  1473.     /*  Update our status row to inform the spooler
  1474.         that we are ready for flushing */
  1475.  
  1476.     if (ulFlags & FLUSH_UPLOAD)
  1477.         lpxpl->ulTransportStatus |= STATUS_OUTBOUND_FLUSH;
  1478.     if (ulFlags & FLUSH_DOWNLOAD)
  1479.         lpxpl->ulTransportStatus |= STATUS_INBOUND_FLUSH;
  1480.  
  1481.     hResult = HrUpdateTransportStatus(lpxpl, 0L);
  1482.  
  1483.     DebugTraceResult(XPL_FlushQueues, hResult);
  1484.     return hResult;
  1485. }
  1486.  
  1487.  
  1488. /*
  1489.  -  FIsValidSession
  1490.  -
  1491.  *  Purpose:
  1492.  *      Called from several places in the Transport to verify a session.
  1493.  *
  1494.  *  Parameters:
  1495.  *      lpxpl               handle which is to be confirmed
  1496.  *
  1497.  *  Returns:
  1498.  *      (BOOL)              TRUE if a valid session, FALSE if not.
  1499.  *
  1500.  *  Operation:
  1501.  *      Get the critical section, look for lpxpl in the session list,
  1502.  *      release the critical section, return boolean result.
  1503.  */
  1504.  
  1505. BOOL
  1506. FIsValidSession(LPXPL lpxpl)
  1507. {
  1508.     LPXPL lpxplT;
  1509.     LPXPP lpxpp;
  1510.     BOOL fIsValid = FALSE;
  1511.  
  1512.     /*  First make sure that it can possibly be a session; then
  1513.         Take advantage of the internal consistency check ... does
  1514.         it point to itself? then validate the parent XPP. */
  1515.  
  1516.     if ((IsBadWritePtr(lpxpl, sizeof(XPL))) ||
  1517.         (lpxpl->lpMySession != lpxpl) ||
  1518.         (IsBadWritePtr(lpxpl->lpxppParent, sizeof(XPP))))
  1519.         return FALSE;
  1520.  
  1521.     /*  Maybe it's a session ... see if it's in the list.
  1522.         Lock out session data structure during the check. */
  1523.  
  1524.     lpxpp = lpxpl->lpxppParent;
  1525.     EnterCriticalSection(&lpxpp->csTransport);
  1526.  
  1527.     /*  Look in the session list for the session */
  1528.  
  1529.     lpxplT = lpxpp->XPSessionList;
  1530.  
  1531.     while (lpxplT)
  1532.     {
  1533.         if (lpxplT == lpxpl)
  1534.         {
  1535.             fIsValid = TRUE;
  1536.             break;
  1537.         }
  1538.         lpxplT = lpxplT->lpNextSession;
  1539.     }
  1540.  
  1541.     /*  Release the critical section and return the result. */
  1542.  
  1543.     LeaveCriticalSection(&lpxpp->csTransport);
  1544.  
  1545.     return fIsValid;
  1546. }
  1547.  
  1548.  
  1549. /*
  1550.  -  CleanupSession
  1551.  -
  1552.  *  Purpose:
  1553.  *      Called from TransportLogoff() and error cases of TransportLogon()
  1554.  *      to cleanup session data.
  1555.  *
  1556.  *  Parameters:
  1557.  *      lpxpl           handle which is to be confirmed
  1558.  *
  1559.  *  Returns:
  1560.  *      none.
  1561.  *
  1562.  *  Operation:
  1563.  *      Close any open search handles, deallocate associated structures.
  1564.  *      We assume that if we need the critical section, we already have it.
  1565.  */
  1566.  
  1567. static void
  1568. CleanupSession(LPXPL lpxpl)
  1569. {
  1570.     LPMAPISUP lpMAPISup = lpxpl->lpMAPISup;
  1571.     BOOL fRefSupport = lpxpl->fRefSupport;
  1572.  
  1573.     /* Get rid of any open handle hanging around from Poll() or
  1574.     StartMessage() */
  1575.  
  1576.     if (lpxpl->hInFindHandle != INVALID_HANDLE_VALUE)
  1577.         CloseHandle(lpxpl->hInFindHandle);
  1578.  
  1579.     if (lpxpl->hOutFindHandle != INVALID_HANDLE_VALUE)
  1580.         CloseHandle(lpxpl->hOutFindHandle);
  1581.  
  1582.     /* OK, Deallocate the memory. */
  1583.  
  1584.     /* Session User Display Name and Entry-ID */
  1585.  
  1586.     if (lpxpl->lpMyIDArray)
  1587.     {
  1588.         lpxpl->FreeBuffer(lpxpl->lpMyIDArray[0].Value.bin.lpb);
  1589.         lpxpl->FreeBuffer(lpxpl->lpMyIDArray);
  1590.     }
  1591.  
  1592.     /* Free the session property array */
  1593.  
  1594.     lpxpl->FreeBuffer(lpxpl->lpPropArray);
  1595.  
  1596.     /* Free the Message OptionData struct */
  1597.  
  1598.     lpxpl->FreeBuffer(lpxpl->lpOptData);
  1599.  
  1600.     /* Release() the support object if need be. Do this last,
  1601.        since it could cause spooler to call XPP_Release. */
  1602.  
  1603.     if (fRefSupport)
  1604.         lpMAPISup->lpVtbl->Release(lpMAPISup);
  1605. }
  1606.  
  1607.  
  1608. /*
  1609.  -  lpxpp->lpVtbl->QueryInterface
  1610.  -
  1611.  *  Purpose:
  1612.  *
  1613.  *  Parameters:
  1614.  *      lpxpp               Pointer to object
  1615.  *      lpiid               New interface to Query to
  1616.  *      lppUnk              Where to store pointer to new object
  1617.  *
  1618.  *  Returns:
  1619.  *      (SCODE)             E_INVALIDARG if the input
  1620.  *                          object doesn't look like a XPP;
  1621.  *                          E_INVALIDARG if the IID
  1622.  *                          isn't readable or lppNewObj isn't
  1623.  *                          writable; E_NOINTERFACE
  1624.  *                          if we don't know the IID.
  1625.  *
  1626.  *  Operation:
  1627.  *      Validate parameters. See if the caller wants IUnknown or IXPProvider.
  1628.  *      If so, increment the usage count and return a new object.
  1629.  */
  1630.  
  1631. STDMETHODIMP
  1632. XPP_QueryInterface(LPXPP lpxpp,
  1633.     REFIID lpiid,
  1634.     LPVOID FAR * lppUnk)
  1635. {
  1636.     /*  Validate the parameters: 1) Does it seem to be an object?
  1637.         2) is the refcount nonzero? 3) Is there enough there for
  1638.         an interface ID? 4) Is there enough there for a new object? */
  1639.  
  1640.     if ((IsBadWritePtr(lpxpp, sizeof(XPP))) ||
  1641.         (lpxpp->lcInit == 0) ||
  1642.         (lpxpp->lpxppMyAddress != lpxpp) ||
  1643.         (IsBadReadPtr(lpiid, sizeof(IID))) ||
  1644.         (IsBadWritePtr(lppUnk, sizeof(LPXPP))))
  1645.     {
  1646.         DebugTraceSc(XPP_QueryInterface, E_INVALIDARG);
  1647.         return ResultFromScode(E_INVALIDARG);
  1648.     }
  1649.  
  1650.     /*  See if the requested interface is one of ours */
  1651.  
  1652.     if (memcmp(lpiid, &IID_IUnknown, sizeof(IID)) &&
  1653.         memcmp(lpiid, &IID_IXPProvider, sizeof(IID)))
  1654.     {
  1655.         *lppUnk = NULL;         /* OLE requires zeroing [out] parameters */
  1656.         DebugTraceSc(XPP_QueryInterface, E_NOINTERFACE);
  1657.         return ResultFromScode(E_NOINTERFACE);
  1658.     }
  1659.  
  1660.     /*  We'll do this one. Bump the usage count and return a new pointer. */
  1661.  
  1662.     ++lpxpp->lcInit;
  1663.     *lppUnk = lpxpp;
  1664.  
  1665.     return hrSuccess;
  1666. }
  1667.  
  1668.  
  1669. /*
  1670.  -  lpxpp->lpVtbl->AddRef
  1671.  -
  1672.  *  Purpose:
  1673.  *      Increment reference count if nonzero.
  1674.  *
  1675.  *  Parameters:
  1676.  *      lpxpp               Pointer to object (should be XPP)
  1677.  *
  1678.  *
  1679.  *  Returns:
  1680.  *      (ULONG)             Current reference count or zero if
  1681.  *                          it doesn't seem to be XPP.
  1682.  *
  1683.  *  Operation:
  1684.  *      Make sure it looks like a XPP, and if so, bump the reference count
  1685.  *      and return the result to the caller.
  1686.  */
  1687.  
  1688. STDMETHODIMP_(ULONG)
  1689. XPP_AddRef(LPXPP lpxpp)
  1690. {
  1691.     /*  If it doesn't seem to be an object or refcount is zero, return zero */
  1692.  
  1693.     if (IsBadWritePtr(lpxpp, sizeof(XPP)) ||
  1694.         lpxpp->lcInit == 0 ||
  1695.         lpxpp->lpxppMyAddress != lpxpp)
  1696.         return 0;
  1697.  
  1698.     return ++lpxpp->lcInit;
  1699. }
  1700.  
  1701.  
  1702. /*
  1703.  -  lpxpp->lpVtbl->Release
  1704.  -
  1705.  *  Purpose:
  1706.  *      Decrement lcInit. If it's zero, release the object.
  1707.  *
  1708.  *  Parameters:
  1709.  *      lpxpp               Pointer to object (should be XPP)
  1710.  *
  1711.  *  Returns:
  1712.  *      (ULONG)             Current reference count or zero if
  1713.  *                                  it doesn't seem to be XPP.
  1714.  *
  1715.  *  Operation:
  1716.  *      Make sure it looks like a XPP, and if so, decrement the reference
  1717.  *      count. If the count is now zero, deallocate the object.
  1718.  *
  1719.  *      Return the reference count to the caller.
  1720.  */
  1721.  
  1722. STDMETHODIMP_(ULONG)
  1723. XPP_Release(LPXPP lpxpp)
  1724. {
  1725.     /*  If it doesn't seem to be an object or refcount is zero, return zero */
  1726.  
  1727.     if (IsBadWritePtr(lpxpp, sizeof(XPP)) ||
  1728.         lpxpp->lcInit == 0 ||
  1729.         lpxpp->lpxppMyAddress != lpxpp)
  1730.         return 0;
  1731.  
  1732.     --lpxpp->lcInit;
  1733.  
  1734.     if (lpxpp->lcInit == 0)
  1735.     {
  1736.         ULONG ulT;
  1737.  
  1738.         DebugTrace("XPP_Release() freeing XPP.\n");
  1739.  
  1740.         /* If we've inited and not deinited, do it now */
  1741.  
  1742.         if (lpxpp->fInited)
  1743.         {
  1744.             ulT = DEINIT_HURRY;
  1745.             lpxpp->lpVtbl->Shutdown(lpxpp, &ulT);
  1746.         }
  1747.  
  1748.         lpxpp->lpVtbl = NULL;
  1749.         (*lpxpp->lpFreeBuffer) (lpxpp);
  1750.         return 0;
  1751.     }
  1752.  
  1753.     return lpxpp->lcInit;
  1754. }
  1755.  
  1756.  
  1757. /*
  1758.  -  lpxpl->lpVtbl->QueryInterface
  1759.  -
  1760.  *  Purpose:
  1761.  *
  1762.  *  Parameters:
  1763.  *      lpxpl               Pointer to object
  1764.  *      lpiid               New interface to Query to
  1765.  *      lppUnk              Where to store pointer to new object
  1766.  *
  1767.  *  Returns:
  1768.  *      (SCODE)             E_INVALIDARG if the input
  1769.  *                          object doesn't look like a XPL;
  1770.  *                          E_INVALIDARG if the IID
  1771.  *                          isn't readable or lppNewObj isn't
  1772.  *                          writable; E_NOINTERFACE
  1773.  *                          if we don't know the IID.
  1774.  *
  1775.  *  Operation:
  1776.  *      Validate parameters. See if the caller wants IUnknown or IXPLogon.
  1777.  *      If so, increment the usage count and return a new object.
  1778.  */
  1779.  
  1780. STDMETHODIMP
  1781. XPL_QueryInterface(LPXPL lpxpl,
  1782.     REFIID lpiid,
  1783.     LPVOID FAR * lppUnk)
  1784. {
  1785.     /*  Validate the parameters: 1) Does it seem to be an object?
  1786.         2) is the refcount nonzero? 3) Is there enough there for
  1787.         an interface ID? 4) Is there enough there for a new object? */
  1788.  
  1789.     if ((IsBadWritePtr(lpxpl, sizeof(XPL))) ||
  1790.         (lpxpl->lcInit == 0) ||
  1791.         (lpxpl->lpMySession != lpxpl) ||
  1792.         (IsBadReadPtr(lpiid, sizeof(IID))) ||
  1793.         (IsBadWritePtr(lppUnk, sizeof(LPXPL))))
  1794.     {
  1795.         DebugTraceSc(XPL_QueryInterface, E_INVALIDARG);
  1796.         return ResultFromScode(E_INVALIDARG);
  1797.     }
  1798.  
  1799.     /*  See if the requested interface is one of ours */
  1800.  
  1801.     if (memcmp(lpiid, &IID_IUnknown, sizeof(IID)) &&
  1802.         memcmp(lpiid, &IID_IXPLogon, sizeof(IID)))
  1803.     {
  1804.         *lppUnk = NULL;         /* OLE requires zeroing [out] parameters */
  1805.         DebugTraceSc(XPL_QueryInterface, E_NOINTERFACE);
  1806.         return ResultFromScode(E_NOINTERFACE);
  1807.     }
  1808.  
  1809.     /*  We'll do this one. Bump the usage count and return a new pointer. */
  1810.  
  1811.     ++lpxpl->lcInit;
  1812.     *lppUnk = lpxpl;
  1813.  
  1814.     return hrSuccess;
  1815. }
  1816.  
  1817.  
  1818. /*
  1819.  -  lpxpl->lpVtbl->AddRef
  1820.  -
  1821.  *  Purpose:
  1822.  *      Increment reference count if nonzero.
  1823.  *
  1824.  *  Parameters:
  1825.  *      lpxpl               Pointer to object (should be XPL)
  1826.  *
  1827.  *  Returns:
  1828.  *      (ULONG)             Current reference count or zero if
  1829.  *                          it doesn't seem to be XPL.
  1830.  *
  1831.  *  Operation:
  1832.  *      Make sure it looks like a XPL, and if so, bump the reference count
  1833.  *      and return the result to the caller.
  1834.  */
  1835.  
  1836. STDMETHODIMP_(ULONG)
  1837. XPL_AddRef(LPXPL lpxpl)
  1838. {
  1839.     /*  If it doesn't seem to be an object or refcount is zero, return zero */
  1840.  
  1841.     if (IsBadWritePtr(lpxpl, sizeof(XPL)) ||
  1842.         lpxpl->lcInit == 0 ||
  1843.         lpxpl->lpMySession != lpxpl)
  1844.         return 0;
  1845.  
  1846.     return ++lpxpl->lcInit;
  1847. }
  1848.  
  1849.  
  1850. /*
  1851.  -  lpxpl->lpVtbl->Release
  1852.  -
  1853.  *  Purpose:
  1854.  *      Decrement lcInit. If it's zero, release the object.
  1855.  *
  1856.  *  Parameters:
  1857.  *      lpxpl               Pointer to object (should be XPL)
  1858.  *
  1859.  *  Returns:
  1860.  *      (ULONG)             Current reference count or zero if
  1861.  *                          it doesn't seem to be XPL.
  1862.  *
  1863.  *  Operation:
  1864.  *      Make sure it looks like a XPL, and if so, decrement the reference
  1865.  *      count. If the count is now zero, deallocate the object.
  1866.  *
  1867.  *      Return the reference count to the caller.
  1868.  */
  1869.  
  1870. STDMETHODIMP_(ULONG)
  1871. XPL_Release(LPXPL lpxpl)
  1872. {
  1873.     /*  If it doesn't seem to be an object or refcount is zero, return zero */
  1874.  
  1875.     if (IsBadWritePtr(lpxpl, sizeof(XPL)) ||
  1876.         lpxpl->lcInit == 0 ||
  1877.         lpxpl->lpMySession != lpxpl)
  1878.         return 0;
  1879.  
  1880.     --lpxpl->lcInit;
  1881.  
  1882.     if (lpxpl->lcInit == 0)
  1883.     {
  1884.         DebugTrace("XPL_Release() freeing XPL.\n");
  1885.  
  1886.         /* Ignore return code; we're going away reguardless! */
  1887.  
  1888.         XPL_TransportLogoff(lpxpl, LOGOFF_HURRY);
  1889.         lpxpl->lpVtbl = NULL;
  1890.         (*lpxpl->FreeBuffer) (lpxpl);
  1891.  
  1892.         return 0;
  1893.     }
  1894.  
  1895.     return lpxpl->lcInit;
  1896. }
  1897.  
  1898.  
  1899. /*
  1900.  -  ScCheckLogonProps
  1901.  -
  1902.  *  Purpose:
  1903.  *      Looks at the properties returned from the XP Logon property
  1904.  *      sheet and does some 'lite' validation of the values.  Users
  1905.  *      of this function must accept the symantics associated with
  1906.  *      the three possible return values.  That is, if the caller
  1907.  *      is displaying UI and MAPI_E_INVALID_PARAMETER is returned
  1908.  *      then the UI must be re-displayed.  If the caller is NOT
  1909.  *      displaying UI and MAPI_E_UNCONFIGURED is returned then
  1910.  *      they should pass this error back up the call stack, as MAPI
  1911.  *      will call the Service Entry point to get this info.
  1912.  *      MAPI_E_USER_CANCEL will only be returned if UI is allowed,
  1913.  *      in which case this should be treated the same a when the
  1914.  *      user presses <Cancel> in the Logon dialog.
  1915.  *
  1916.  *  Parameters:
  1917.  *      lpXPDialog          - Contains everything I need
  1918.  *      fUIAllowed          - Indicates if MessageBox's are allowed
  1919.  *
  1920.  *  Returns:
  1921.  *      S_OK                        - All data appears valid
  1922.  *      MAPI_E_USER_CANCEL          - Bad data and the user wants to abort
  1923.  *      MAPI_E_UNCONFIGURED         - Bad data and the user wants to try again
  1924.  */
  1925.  
  1926. SCODE
  1927. ScCheckLogonProps(LPXPDLG lpXPDialog, BOOL fUIAllowed)
  1928. {
  1929.     SCODE sc = MAPI_E_UNCONFIGURED;
  1930.     LPTSTR lpszT = NULL;
  1931.     HINSTANCE hInst = lpXPDialog->hInst;
  1932.     HWND hWnd = lpXPDialog->hwnd;
  1933.     LPSPropValue lpProps = *(lpXPDialog->lppPropArray);
  1934.     HANDLE hf = INVALID_HANDLE_VALUE;
  1935.     ULONG ulT;
  1936.     BOOL fDeleteFile = FALSE;
  1937.     LPTSTR szFuBar = TEXT("fubar");
  1938.     TCHAR szFooUNC[MAX_PATH];
  1939.     TCHAR szFooPath[MAX_PATH];
  1940.     UINT ids = 0;
  1941.     LONG lFlags;
  1942.  
  1943. #ifdef _WINNT
  1944.     ULONG cb;
  1945.     TCHAR szBuff[16];
  1946. #endif  /* _WINNT */
  1947.  
  1948.     /* Check Display Name */
  1949.  
  1950.     lpszT = ArrayIndex(PR_SAMPLE_DISPLAY_NAME, lpProps).Value.LPSZ;
  1951.  
  1952.     if (PROP_TYPE(ArrayIndex(PR_SAMPLE_DISPLAY_NAME, lpProps).ulPropTag) == PT_ERROR ||
  1953.         !lpszT || (*lpszT == '\0'))
  1954.     {
  1955.         ids = IDS_NO_DISPLAY_NAME;
  1956.         goto ret;
  1957.     }
  1958.  
  1959.     /* Check Address Type */
  1960.  
  1961.     lpszT = ArrayIndex(PR_SAMPLE_EMAIL_ADDR_TYPE, lpProps).Value.LPSZ;
  1962.  
  1963.     if (PROP_TYPE(ArrayIndex(PR_SAMPLE_EMAIL_ADDR_TYPE, lpProps).ulPropTag) == PT_ERROR ||
  1964.         !lpszT || (*lpszT == '\0'))
  1965.     {
  1966.         ids = IDS_NO_ADDR_TYPE;
  1967.         goto ret;
  1968.     }
  1969.  
  1970.     /* Check Email Address */
  1971.  
  1972.     lpszT = ArrayIndex(PR_SAMPLE_EMAIL_ADDRESS, lpProps).Value.LPSZ;
  1973.  
  1974.     if (PROP_TYPE(ArrayIndex(PR_SAMPLE_EMAIL_ADDRESS, lpProps).ulPropTag) == PT_ERROR ||
  1975.         !lpszT || (*lpszT == '\0'))
  1976.     {
  1977.         ids = IDS_NO_EMAIL_ADDRESS;
  1978.         goto ret;
  1979.     }
  1980.  
  1981.     /* Save this, we'll need it later */
  1982.  
  1983.     lstrcpy(szFooUNC, lpszT);
  1984.  
  1985.     if (szFooUNC[lstrlen(szFooUNC)-1] != '\\')
  1986.         lstrcat(szFooUNC, TEXT("\\"));
  1987.  
  1988.     lstrcat(szFooUNC, TEXT("foo.txt"));
  1989.  
  1990.     /* Check Inbound Directory */
  1991.  
  1992.     lpszT = ArrayIndex(PR_SAMPLE_INBOUND_DIR, lpProps).Value.LPSZ;
  1993.  
  1994.     if (PROP_TYPE(ArrayIndex(PR_SAMPLE_INBOUND_DIR, lpProps).ulPropTag) == PT_ERROR ||
  1995.         !lpszT || (*lpszT == '\0'))
  1996.     {
  1997.         ids = IDS_NO_INBOUND_DIR;
  1998.         goto ret;
  1999.     }
  2000.  
  2001.     lstrcpy(szFooPath, lpszT);
  2002.  
  2003.     if (szFooPath[lstrlen(szFooPath)-1] != '\\')
  2004.         lstrcat(szFooPath, TEXT("\\"));
  2005.  
  2006.     lstrcat(szFooPath, TEXT("foo.txt"));
  2007.  
  2008.     /* Check Outbound Directory */
  2009.  
  2010.     lFlags = ArrayIndex(PR_SAMPLE_FLAGS, lpProps).Value.l;
  2011.  
  2012.     if (PROP_TYPE(ArrayIndex(PR_SAMPLE_FLAGS, lpProps).ulPropTag) == PT_ERROR ||
  2013.         !(lFlags & PR_SAMPLE_FLAG_PEER_TO_PEER))
  2014.     {
  2015.         lpszT = ArrayIndex(PR_SAMPLE_OUTBOUND_DIR, lpProps).Value.LPSZ;
  2016.  
  2017.         if (!lpszT || (*lpszT == '\0'))
  2018.         {
  2019.             ids = IDS_NO_OUTBOUND_DIR;
  2020.             goto ret;
  2021.         }
  2022.     }
  2023.  
  2024.  
  2025. #ifdef _WINNT
  2026.  
  2027.     /* Do a little loop-back test to validate PR_SAMPLE_EMAIL_ADDRESS
  2028.        and PR_SAMPLE_INBOUND_DIR point to the same place and are valid.
  2029.        The WFW and Windows 95 Redirector can't talk to itself, so we only
  2030.        do this on NT.  Shouldn't be done on platforms whose redirector
  2031.        cannot do the loop-back thang. */
  2032.  
  2033.     if ((hf = CreateFile(szFooUNC, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
  2034.                 FILE_FLAG_WRITE_THROUGH, NULL)) == INVALID_HANDLE_VALUE)
  2035.     {
  2036.         ids = IDS_BAD_EMAIL_ADDRESS;
  2037.         goto ret;
  2038.     }
  2039.  
  2040.     if (!WriteFile(hf, szFuBar, lstrlen(szFuBar), &cb, NULL))
  2041.     {
  2042.         ids = IDS_BAD_EMAIL_ADDRESS;
  2043.         goto ret;
  2044.     }
  2045.  
  2046.     CloseHandle(hf);
  2047.  
  2048.     fDeleteFile = TRUE;
  2049.  
  2050.     /* Now, read the file */
  2051.  
  2052.     if ((hf = CreateFile(szFooPath, GENERIC_READ, 0, NULL, OPEN_EXISTING,
  2053.                 FILE_ATTRIBUTE_READONLY, NULL)) == INVALID_HANDLE_VALUE)
  2054.     {
  2055.         ids = IDS_BAD_INBOUND_DIR;
  2056.         goto ret;
  2057.     }
  2058.  
  2059.     if (!ReadFile(hf, szBuff, lstrlen(szFuBar), &cb, NULL))
  2060.     {
  2061.         ids = IDS_BAD_INBOUND_DIR;
  2062.         goto ret;
  2063.     }
  2064.  
  2065.     szBuff[lstrlen(szFuBar)] = '\0';
  2066.  
  2067.     CloseHandle(hf);
  2068.     hf = INVALID_HANDLE_VALUE;
  2069.  
  2070.     if (lstrcmp(szFuBar, szBuff))
  2071.     {
  2072.         ids = IDS_UNC_DIR_MISMATCH;
  2073.         goto ret;
  2074.     }
  2075.  
  2076. #endif  /* _WINNT */
  2077.  
  2078.     /*  If there's a high water mark, make sure there's a low water
  2079.         mark at least 1K less than high water and no more than 32K. */
  2080.  
  2081.     ulT = ArrayIndex(PR_SAMPLE_LOGHIGHWATER, lpProps).Value.ul;
  2082.     if (PROP_TYPE(ArrayIndex(PR_SAMPLE_LOGHIGHWATER, lpProps).ulPropTag) == PT_ERROR ||
  2083.         ulT)
  2084.     {
  2085.         /* It looks like we'll be doing size adjustment. See what
  2086.         the current "low water" mark is. */
  2087.  
  2088.         ULONG ulLow;
  2089.  
  2090.         ulLow = ArrayIndex(PR_SAMPLE_LOGLOWWATER, lpProps).Value.ul;
  2091.  
  2092.         /* Make sure it's not more than 32K. If so, trim it down. */
  2093.  
  2094.         if (ulLow > 32)
  2095.             ulLow = 32;
  2096.  
  2097.         /* Make sure there's at least 1K between high and low water. If
  2098.         not, increase high water mark to satisfy this. */
  2099.  
  2100.         if (ulLow > (ulT - 1))
  2101.             ulT = ulLow + 1;
  2102.  
  2103.         /* Save this stuff into the logon property array. */
  2104.  
  2105.         ArrayIndex(PR_SAMPLE_LOGLOWWATER, lpProps).Value.ul = ulLow;
  2106.         ArrayIndex(PR_SAMPLE_LOGHIGHWATER, lpProps).Value.ul = ulT;
  2107.     }
  2108.  
  2109.     sc = S_OK;
  2110.  
  2111. ret:
  2112.     if (fDeleteFile)
  2113.         DeleteFile(szFooUNC);
  2114.  
  2115.     if (hf != INVALID_HANDLE_VALUE)
  2116.         CloseHandle(hf);
  2117.  
  2118.     /*  OK, the following block goes something like this:
  2119.         We initialized sc to MAPI_E_UNCONFIGURED at the top
  2120.         and only set it to S_OK if we make it all the way through
  2121.         the validation stuff.  If, along the way, we find bad data
  2122.         we set ids to the appropriate error string (this is Assert'd
  2123.         below).  Then, if UI is allowed, we get a bunch of string
  2124.         resources via LoadString and format an error message that
  2125.         will be displayed in a MessageBox.  If we are running the
  2126.         debug version of the transport, then the MessageBox will
  2127.         have an Abort/Retry/Ignore button selection, else, it will
  2128.         only have a Yes/No button selection.  These buttons carry
  2129.         with them the following meaning:
  2130.  
  2131.         DEBUG
  2132.             Abort   Return MAPI_E_USER_CANCEL; causes Logon to fail;
  2133.                     indicates that data is not to be saved in the profile.
  2134.  
  2135.             Retry   Return MAPI_E_UNCONFIGURED; re-display
  2136.                     Logon UI so user can fix problem.
  2137.  
  2138.             Ignore  Return S_OK; we accept the data as is and will
  2139.                     write it into the profile (if asked to save).
  2140.  
  2141.         !DEBUG
  2142.             Yes     Same as Retry above.
  2143.  
  2144.             No      Same as Abort above.
  2145.  
  2146.         Since we are using MessageBox for our error dialog, we are
  2147.         limited to this confusing choice of buttons.
  2148.     */
  2149.  
  2150.     if (FAILED(sc) && fUIAllowed)
  2151.     {
  2152.         TCHAR szErrTitle[64];
  2153.         TCHAR szErrFormat[128];
  2154.         TCHAR szErrStr[128];
  2155.         TCHAR szErrMsg[256];
  2156.         UINT fuButtons = MB_ICONEXCLAMATION | MB_SETFOREGROUND;
  2157.         int rc;
  2158.  
  2159.         Assert(ids);
  2160.  
  2161.         if (!LoadString(hInst, ids, szErrStr, sizeof(szErrStr) - 1) ||
  2162.             !LoadString(hInst, IDS_BAD_LOGON_PROPS_TITLE,
  2163.                         szErrTitle, sizeof(szErrTitle) - 1) ||
  2164.             !LoadString(hInst, IDS_BAD_LOGON_PROPS_FORMAT,
  2165.                         szErrFormat, sizeof(szErrFormat) - 1))
  2166.         {
  2167.             DebugTrace("Unable to do a LoadString in ScCheckLogonProps.\n");
  2168.             return sc;
  2169.         }
  2170.  
  2171.         wsprintf(szErrMsg, szErrFormat, szErrStr);
  2172.  
  2173. #ifdef DEBUG
  2174.         fuButtons |= MB_ABORTRETRYIGNORE;
  2175. #else
  2176.         fuButtons |= MB_YESNO;
  2177. #endif
  2178.  
  2179.         rc = MessageBox(hWnd, szErrMsg, szErrTitle, fuButtons);
  2180.  
  2181.         if (rc == IDRETRY || rc == IDYES)
  2182.             sc = MAPI_E_UNCONFIGURED;
  2183.         else if (rc == IDABORT || rc == IDNO)
  2184.             sc = MAPI_E_USER_CANCEL;
  2185.         else
  2186.             sc = S_OK;
  2187.     }
  2188.  
  2189.     return sc;
  2190. }
  2191.  
  2192.  
  2193. /*
  2194.  -  HrCheckSpoolerYield
  2195.  -
  2196.  *  Purpose:
  2197.  *      Used to enforce the .2 second rule.  Called periodically while
  2198.  *      processing a message to determine if we have used more than .2
  2199.  *      seconds.  If so, then call SpoolerYield(), else just continue.
  2200.  *      This is called with fReset set to TRUE when we first enter one
  2201.  *      of the Transport Logon methods (usually one that is known to
  2202.  *      take a long time like StartMessage() or SubmitMessage(). )
  2203.  *
  2204.  *  Parameters:
  2205.  *      lpMAPISup           - The Transports support object
  2206.  *      fReset              - Sets dwStart to current TickCount and returns
  2207.  *
  2208.  */
  2209.  
  2210. HRESULT
  2211. HrCheckSpoolerYield(LPMAPISUP lpMAPISup, BOOL fReset)
  2212. {
  2213.     HRESULT hr = hrSuccess;
  2214.     DWORD dwStop;
  2215.     static DWORD dwStart;
  2216.  
  2217.     if (fReset)
  2218.     {
  2219.         dwStart = GetTickCount();
  2220.         return hr;
  2221.     }
  2222.  
  2223.     dwStop = GetTickCount();
  2224.  
  2225.     if ((dwStop - dwStart) > 200)
  2226.     {
  2227.         hr = lpMAPISup->lpVtbl->SpoolerYield(lpMAPISup, 0);
  2228.         dwStart = GetTickCount();
  2229.     }
  2230.  
  2231.     return hr;
  2232. }
  2233.  
  2234. /*
  2235.  -  ScCopySessionProps
  2236.  -
  2237.  *  Purpose:
  2238.  *      Used to make a working copy of the session properties associated
  2239.  *      with a particular logon object.  This is done to protect us from
  2240.  *      having our data change out from under us due to a call to some
  2241.  *      transport UI.  This is done instead of mutexing to avoid the chance
  2242.  *      of deadlock conditions and to avoid having to create an elaborate
  2243.  *      mutex object that suits our special needs.
  2244.  *
  2245.  *  Parameters:
  2246.  *      lpxpl               - The Transports logon object
  2247.  *      lppPropArray        - Receives the new PropArray set
  2248.  *      lppMyIdArray        - Receives the new IdArray
  2249.  */
  2250.  
  2251. SCODE
  2252. ScCopySessionProps(
  2253.     LPXPL lpxpl,
  2254.     LPSPropValue FAR * lppPropArray,
  2255.     LPSPropValue FAR * lppMyIDArray)
  2256. {
  2257.     SCODE sc = S_OK;
  2258.     ULONG cProps;
  2259.     LPSPropValue lpPropArray = lpxpl->lpPropArray;
  2260.     LPSPropValue lpMyIDArray = lpxpl->lpMyIDArray;
  2261.     LPALLOCATEBUFFER lpAllocBuff = lpxpl->AllocateBuffer;
  2262.  
  2263.     if (lppPropArray)
  2264.     {
  2265.         cProps = MAX_LOGON_PROPERTIES - TEMP_LOGON_PROPERTIES;
  2266.  
  2267.         sc = ScDupPropset((int)cProps, lpPropArray, lpAllocBuff, lppPropArray);
  2268.  
  2269.         if (FAILED(sc))
  2270.             goto ret;
  2271.     }
  2272.  
  2273.     if (lppMyIDArray)
  2274.     {
  2275.         cProps = NUM_SENDER_PROPS;
  2276.  
  2277.         sc = ScDupPropset((int)cProps, lpMyIDArray, lpAllocBuff, lppMyIDArray);
  2278.  
  2279.         if (FAILED(sc) && lppPropArray)
  2280.         {
  2281.             lpxpl->FreeBuffer(*lppPropArray);
  2282.             *lppPropArray = NULL;
  2283.         }
  2284.     }
  2285.  
  2286. ret:
  2287.     return sc;
  2288. }
  2289.  
  2290. /*
  2291.  -  ServiceEntry
  2292.  -
  2293.  *  Purpose:
  2294.  *      This is the service entry point for the MAPI Configuration
  2295.  *      application.  This function uses the XP Logon dialog to allow
  2296.  *      the user to configure the provider.  If asked to, through the
  2297.  *      UI, the new settings will be saved in the profile.
  2298.  *
  2299.  *  Parameters:
  2300.  *      hInstance           [IN] Instance handle of the calling process
  2301.  *      lpMalloc            [IN] OLE style allocator to be used by PropSheet.
  2302.  *      lpMAPISup           [IN] MAPI Support object - used to get memory
  2303.  *                          allocators, BuildDisplayTable, etc.
  2304.  *      ulUIParam           [IN] hWnd of the caller who is parent of my UI.
  2305.  *      ulFlags             [IN] UI_SERVICE indicates that the caller wants
  2306.  *                          UI to help in configuring this provider.
  2307.  *                          MSG_SERVICE_UI_READ_ONLY indicates the caller
  2308.  *                          does not want write access to the configuration
  2309.  *                          property sheet.  No other flags are supported.
  2310.  *      ulContext           [IN] MSG_SERVICE_DELETE, MSG_SERVICE_INSTALL, and
  2311.  *                          MSG_SERVICE_UNINSTALL are noops and simply return
  2312.  *                          hrSuccess.  MSG_SERVICE_CONFIGURE and
  2313.  *                          MSG_SERVICE_CREATE allow the caller to create
  2314.  *                          or update the Logon properties in this providers
  2315.  *                          profile section.
  2316.  *      cValues             [IN] The caller may supply an array of property
  2317.  *                          values to configure this provider with.  This is
  2318.  *                          the number of values found in the array.
  2319.  *      lpProps             [IN] Caller supplied configuration properties.
  2320.  *      lpAdminProviders    [IN] An IProviderAdmin object used to retrieve a
  2321.  *                          ProfileSection object for this provider.
  2322.  *      lppMapiError        [OUT] Extended error information optionally
  2323.  *                          returned when the call fails.
  2324.  */
  2325.  
  2326. HRESULT STDAPICALLTYPE
  2327. ServiceEntry(
  2328.     HINSTANCE hInstance,
  2329.     LPMALLOC lpMalloc,
  2330.     LPMAPISUP lpMAPISup,
  2331.     ULONG ulUIParam,
  2332.     ULONG ulFlags,
  2333.     ULONG ulContext,
  2334.     ULONG cValues,
  2335.     LPSPropValue lpProps,
  2336.     LPPROVIDERADMIN lpAdminProviders,
  2337.     LPMAPIERROR FAR *lppMapiError)
  2338. {
  2339.     SCODE sc = S_OK;
  2340.     HRESULT hResult = hrSuccess;
  2341.     ULONG ulT;
  2342.     ULONG ulCount = 0;
  2343.     LPSPropValue lpPropArray = NULL;
  2344.     LPSPropValue lpLogonProps = NULL;
  2345.     LPALLOCATEBUFFER lpAllocBuff;
  2346.     LPALLOCATEMORE lpAllocMore;
  2347.     LPFREEBUFFER lpFreeBuff;
  2348.     LPPROFSECT lpProfileObj = NULL;
  2349.     XPDLG XPDialog;
  2350.     BOOL fNeedUI = FALSE;
  2351.     BOOL fAllowUI = FALSE;
  2352.     BOOL fInitialParamsOk = TRUE;
  2353.  
  2354.     /* Validate parameters */
  2355.     //$BUG: No parameter checking....
  2356.  
  2357.     /* Check the Support Object */
  2358.  
  2359.     if (FBadUnknown(lpMAPISup))
  2360.     {
  2361.         DebugTraceSc(Bad lpMAPISup in XP ServiceEntry, E_INVALIDARG);
  2362.         return ResultFromScode(E_INVALIDARG);
  2363.     }
  2364.  
  2365.     /* Check for context */
  2366.  
  2367.     if ((ulContext == MSG_SERVICE_DELETE) ||
  2368.         (ulContext == MSG_SERVICE_INSTALL) ||
  2369.         (ulContext == MSG_SERVICE_UNINSTALL))
  2370.         return hrSuccess;
  2371.  
  2372.     if (ulContext != MSG_SERVICE_CONFIGURE && ulContext != MSG_SERVICE_CREATE)
  2373.     {
  2374.         DebugTraceSc(ServiceEntry unsupported context, MAPI_E_NO_SUPPORT);
  2375.         return ResultFromScode(MAPI_E_NO_SUPPORT);
  2376.     }
  2377.  
  2378.     if ( ulFlags & MAPI_UNICODE )
  2379.     {
  2380.         DebugTraceSc(ServiceEntry Bad character width, MAPI_E_BAD_CHARWIDTH);
  2381.         return ResultFromScode(MAPI_E_BAD_CHARWIDTH);
  2382.     }
  2383.  
  2384.     /* Check for UI */
  2385.  
  2386.     if (ulFlags & SERVICE_UI_ALWAYS)
  2387.         fAllowUI = fNeedUI = TRUE;
  2388.     else
  2389.         if (ulFlags & SERVICE_UI_ALLOWED)
  2390.             fAllowUI = TRUE;
  2391.  
  2392.     if (ulFlags & MSG_SERVICE_UI_READ_ONLY)
  2393.         ulFlags = UI_READONLY;
  2394.  
  2395.     /* Get the memory allocation routines we'll be needing. */
  2396.  
  2397.     hResult = lpMAPISup->lpVtbl->GetMemAllocRoutines(lpMAPISup,
  2398.         &lpAllocBuff, &lpAllocMore, &lpFreeBuff);
  2399.  
  2400.     if (hResult)
  2401.     {
  2402.         DebugTrace("GetMemAllocRoutines failed in ServiceEntry.\n");
  2403.         goto ret;
  2404.     }
  2405.  
  2406.     /* Open the Profile Section for this Transport Provider. */
  2407.  
  2408.     hResult = HrOpenSingleProvider(lpAdminProviders, &lpProfileObj);
  2409.  
  2410.     if (hResult)
  2411.     {
  2412.         DebugTrace("Unable to open the profile.\n");
  2413.         goto ret;
  2414.     }
  2415.  
  2416.     /* Profile is open, get the properties out of it. */
  2417.  
  2418.     hResult = lpProfileObj->lpVtbl->GetProps(lpProfileObj,
  2419.         (LPSPropTagArray) &sptLogonArray, ulFlags & MAPI_UNICODE, &ulCount, &lpPropArray);
  2420.  
  2421.     if (HR_FAILED(hResult))
  2422.     {
  2423.         DebugTrace("GetProps failed in XP ServiceEntry.\n");
  2424.         goto ret;
  2425.     }
  2426.  
  2427.     hResult = hrSuccess;
  2428.  
  2429.     /*  If the user passed in a property array to configure our profile
  2430.         with, then we'll merge this array with that from the profile
  2431.         section.  This merged array will, conditionally, be used in our
  2432.         Logon UI and, conditionally,  written out to the profile section.
  2433.         Also, lpLogonProps becomes our alias for the array no matter where
  2434.         the properties come from. */
  2435.  
  2436.     if (lpProps)
  2437.     {
  2438.         sc = ScMergeLogonProps(cValues, lpProps, ulCount,
  2439.             lpPropArray, lpAllocBuff, lpAllocMore, &lpLogonProps);
  2440.  
  2441.         if (FAILED(sc))
  2442.         {
  2443.             hResult = ResultFromScode(sc);
  2444.             DebugTrace("ScMergeLogonProps failed in XP ServiceEntry.\n");
  2445.             goto ret;
  2446.         }
  2447.     }
  2448.     else
  2449.     {
  2450.         lpLogonProps = lpPropArray;
  2451.         lpPropArray = NULL;
  2452.     }
  2453.  
  2454.     Assert(ulCount == MAX_LOGON_PROPERTIES);
  2455.     ulCount -= TEMP_LOGON_PROPERTIES;
  2456.  
  2457.     /* Find out if the stored SAMPLE_FLAGS say we should have UI.
  2458.        But, only if we aren't already forcing UI to be presented. */
  2459.  
  2460.     if (fAllowUI && !fNeedUI && lpLogonProps)
  2461.     {
  2462.         if ((ArrayIndex(PR_SAMPLE_FLAGS, lpLogonProps).ulPropTag == PR_SAMPLE_FLAGS) &&
  2463.             (ArrayIndex(PR_SAMPLE_FLAGS, lpLogonProps).Value.l & PR_SAMPLE_FLAG_UI_ALWAYS))
  2464.                 fNeedUI = TRUE;
  2465.     }
  2466.  
  2467.     /* Fill in the logon UI structure */
  2468.  
  2469.     XPDialog.hInst = hInstance;
  2470.     XPDialog.hwnd = (HWND) ulUIParam;
  2471.     XPDialog.lppPropArray = &lpLogonProps;
  2472.     XPDialog.lpPTArray = (LPSPropTagArray) &sptLogonArray;
  2473.     XPDialog.AllocateBuffer = lpAllocBuff;
  2474.     XPDialog.AllocateMore = lpAllocMore;
  2475.     XPDialog.FreeBuffer = lpFreeBuff;
  2476.     XPDialog.lpMalloc = lpMalloc;
  2477.     XPDialog.lpMAPISup = lpMAPISup;
  2478.     XPDialog.fLogon = TRUE;
  2479.     XPDialog.ulFlags = ulFlags;
  2480.  
  2481.     /* Check the logon props BEFORE the dialog call, as the props will
  2482.        be freed if Cancel is selected, and we will want to know if the
  2483.        provider configuration information was valid */
  2484.  
  2485.     sc = ScCheckLogonProps(&XPDialog, FALSE);
  2486.     if ((sc == MAPI_E_USER_CANCEL) || (sc == MAPI_E_UNCONFIGURED))
  2487.     {
  2488.         if (fAllowUI)
  2489.         {
  2490.             fNeedUI = TRUE;
  2491.             fInitialParamsOk = FALSE;
  2492.         }
  2493.         else
  2494.             goto ret;
  2495.     }
  2496.  
  2497.     while (fAllowUI && fNeedUI)
  2498.     {
  2499.         sc = ScDoLogonDlg(&XPDialog);
  2500.  
  2501.         if (FAILED(sc))
  2502.         {
  2503.             hResult = ResultFromScode(sc);
  2504.  
  2505.             if (sc != MAPI_E_USER_CANCEL)
  2506.             {
  2507.                 DebugTrace("ScDoLogonDlg failed in XP ServiceEntry.\n");
  2508.             }
  2509.             else
  2510.                 if (!fInitialParamsOk)
  2511.                     hResult = ResultFromScode(MAPI_E_UNCONFIGURED);
  2512.  
  2513.             goto ret;
  2514.         }
  2515.  
  2516.         if (!lpLogonProps)
  2517.         {
  2518.             hResult = ResultFromScode(MAPI_E_CALL_FAILED);
  2519.             DebugTrace("No Logon Props returned in XP ServiceEntry.\n");
  2520.             goto ret;
  2521.         }
  2522.  
  2523.         /* Got a prop array, make sure everything in it is good */
  2524.  
  2525.         for (ulT = 0; ulT < ulCount; ulT++)
  2526.         {
  2527.             if (PROP_TYPE((lpLogonProps)[ulT].ulPropTag) == PT_ERROR)
  2528.             {
  2529.                 hResult = ResultFromScode(MAPI_E_UNCONFIGURED);
  2530.                 DebugTrace("Property %x not available, returning MAPI_E_UNCONFIGURED\n", PROP_ID((lpLogonProps)[ulT].ulPropTag));
  2531.                 goto ret;
  2532.             }
  2533.         }
  2534.  
  2535.         /* Do some simple validation of the Logon Props */
  2536.  
  2537.         sc = ScCheckLogonProps(&XPDialog, TRUE);
  2538.  
  2539.         if (sc == MAPI_E_USER_CANCEL)
  2540.             goto ret;
  2541.         else if (sc == MAPI_E_UNCONFIGURED)
  2542.             continue;
  2543.         else
  2544.             fNeedUI = FALSE;
  2545.     }
  2546.  
  2547.     /*  If the user passed in properties and didn't request UI, then
  2548.         we need to check the array of Logon Props now.  If they are
  2549.         bad, then we'll simply return an error. */
  2550.  
  2551.     if (lpProps && !(ulFlags & SERVICE_UI_ALWAYS))
  2552.     {
  2553.         if (sc = ScCheckLogonProps(&XPDialog, FALSE))
  2554.         {
  2555.             hResult = ResultFromScode(sc);
  2556.             DebugTrace("User supplied properties did not pass validation.\n");
  2557.             goto ret;
  2558.         }
  2559.     }
  2560.  
  2561.     /*  If we get here, everything is fine and we can proceed. But first
  2562.         we should write the properties out if the user is willing. */
  2563.  
  2564.     ulT = ArrayIndex(PR_SAMPLE_FLAGS, lpLogonProps).ulPropTag;
  2565.     Assert(PROP_TYPE(ulT) != PT_ERROR);
  2566.  
  2567.     ulT = ArrayIndex(PR_SAMPLE_FLAGS, lpLogonProps).Value.ul;
  2568.  
  2569.     if (ulT & PR_SAMPLE_FLAG_SAVE_DATA)
  2570.     {
  2571.         hResult = lpProfileObj->lpVtbl->SetProps(lpProfileObj,
  2572.             ulCount, lpLogonProps, NULL);
  2573.  
  2574.         if (hResult)
  2575.         {
  2576.             DebugTrace("SetProps failed in XP ServiceEntry.\n");
  2577.             goto ret;
  2578.         }
  2579.  
  2580.         lpProfileObj->lpVtbl->SaveChanges(lpProfileObj, 0);
  2581.     }
  2582.  
  2583. ret:
  2584.     UlRelease(lpProfileObj);
  2585.     lpFreeBuff(lpPropArray);
  2586.     lpFreeBuff(lpLogonProps);
  2587.  
  2588.     DebugTraceResult(ServiceEntry, hResult);
  2589.     return hResult;
  2590. };
  2591.  
  2592.  
  2593. /*
  2594.  -  HrOpenSingleProvider
  2595.  -
  2596.  *  Purpose:
  2597.  *      Gets the IProfileSect object for a single provider from the
  2598.  *      ProviderTable in the IProviderAdmin object.  My entry in the
  2599.  *      table is supposed to be in the first row - this better be true.
  2600.  *
  2601.  */
  2602.  
  2603. HRESULT
  2604. HrOpenSingleProvider(LPPROVIDERADMIN lpAdminProviders,
  2605.     LPPROFSECT FAR * lppProfSect)
  2606. {
  2607.     HRESULT hResult;
  2608.     LPMAPITABLE lpTable = NULL;
  2609.     LPSRowSet lpRows = NULL;
  2610.     LPSPropValue lpProp;
  2611.     SPropTagArray sptaProvider = {1, {PR_PROVIDER_UID}};
  2612.  
  2613.     hResult = lpAdminProviders->lpVtbl->GetProviderTable(
  2614.         lpAdminProviders, 0, &lpTable);
  2615.  
  2616.     if (hResult)
  2617.         goto ret;
  2618.  
  2619.     hResult = lpTable->lpVtbl->SetColumns(lpTable, &sptaProvider, 0L);
  2620.  
  2621.     if (hResult)
  2622.         goto ret;
  2623.  
  2624.     hResult = lpTable->lpVtbl->QueryRows(lpTable, 1, 0, &lpRows);
  2625.  
  2626.     if (hResult || lpRows == NULL)
  2627.     {
  2628.         hResult = ResultFromScode(MAPI_E_NOT_FOUND);
  2629.         goto ret;
  2630.     }
  2631.  
  2632.     Assert(lpRows->aRow[0].cValues == 1);
  2633.     lpProp = lpRows->aRow[0].lpProps;
  2634.     Assert(lpProp);
  2635.     Assert(lpProp->ulPropTag == PR_PROVIDER_UID);
  2636.  
  2637.     /* Found the right property; use it to open our section */
  2638.  
  2639.     hResult = lpAdminProviders->lpVtbl->OpenProfileSection(
  2640.         lpAdminProviders, (LPMAPIUID) lpProp->Value.bin.lpb,
  2641.         NULL, MAPI_MODIFY, lppProfSect);
  2642.  
  2643. ret:
  2644.     FreeProws(lpRows);
  2645.     UlRelease(lpTable);
  2646.  
  2647.     DebugTraceResult(HrOpenSingleProvider, hResult);
  2648.     return hResult;
  2649. }
  2650.  
  2651. /*
  2652.  -  ScMergeLogonProps
  2653.  -
  2654.  *  Purpose:
  2655.  *      This function merges a property array that the user passed into
  2656.  *      ServiceEntry with the property array of Transport Logon props
  2657.  *      found in the Profile.  This merged array is what either gets
  2658.  *      passed into the XP Logon dialog (in the case when UI is requested)
  2659.  *      or simply gets written out to the profile section for the
  2660.  *      Transport Provider.
  2661.  *
  2662.  *  Parameters:
  2663.  *      cProps1             - count of properties in the users array
  2664.  *      lpProps1            - the users property array
  2665.  *      cProps2             - count of properties from the XP profile
  2666.  *      lpProps2            - property array from the XP profile
  2667.  *      lpAllocBuff         - MAPI allocator used by ScDupPropset
  2668.  *      lppPropsDest        - receives the newly built prop array
  2669.  */
  2670.  
  2671. SCODE
  2672. ScMergeLogonProps(
  2673.     ULONG cProps1,
  2674.     LPSPropValue lpProps1,
  2675.     ULONG cProps2,
  2676.     LPSPropValue lpProps2,
  2677.     LPALLOCATEBUFFER lpAllocBuff,
  2678.     LPALLOCATEMORE lpAllocMore,
  2679.     LPSPropValue FAR * lppPropsDest)
  2680. {
  2681.     SCODE sc;
  2682.     ULONG ulTag;
  2683.     TCHAR szEmpty[1] = "";
  2684.     ULONG cT = cProps2;
  2685.     UINT cch;
  2686.     UINT id;
  2687.     LPTSTR lpszT;
  2688.  
  2689.     /*  If any of the properties that we tried to read from the
  2690.         profile didn't exist, then the profile provider would return
  2691.         them to us as type PT_ERROR.  We will convert these to either
  2692.         empty strings or zeros before we try to merge in the user
  2693.         supplied values.  This will allow us to do parameter validation
  2694.         on the properties even if the user didn't ask for UI. */
  2695.  
  2696.     while (cT--)
  2697.     {
  2698.         ulTag = lpProps2[cT].ulPropTag;
  2699.  
  2700.         if (PROP_TYPE(ulTag) == PT_ERROR)
  2701.         {
  2702.             id = (UINT)PROP_ID(ulTag);
  2703.  
  2704.             switch (id)
  2705.             {
  2706.             case (UINT)PROP_ID(PR_SAMPLE_DISPLAY_NAME):
  2707.             case (UINT)PROP_ID(PR_SAMPLE_EMAIL_ADDR_TYPE):
  2708.             case (UINT)PROP_ID(PR_SAMPLE_EMAIL_ADDRESS):
  2709.             case (UINT)PROP_ID(PR_SAMPLE_INBOUND_DIR):
  2710.             case (UINT)PROP_ID(PR_SAMPLE_OUTBOUND_DIR):
  2711.             case (UINT)PROP_ID(PR_SAMPLE_FILENAME):
  2712.             case (UINT)PROP_ID(PR_SAMPLE_DIRECTORY):
  2713.             case (UINT)PROP_ID(PR_SAMPLE_LOGFILE):
  2714.             case (UINT)PROP_ID(PR_TEMP_LOGHIGHWATER):
  2715.             case (UINT)PROP_ID(PR_TEMP_LOGLOWWATER):
  2716.                 lpProps2[cT].ulPropTag = PROP_TAG(PT_TSTRING, id);
  2717.                 lpProps2[cT].Value.LPSZ = szEmpty;
  2718.                 break;
  2719.  
  2720.             case (UINT)PROP_ID(PR_SAMPLE_LOGHIGHWATER):
  2721.             case (UINT)PROP_ID(PR_SAMPLE_LOGLOWWATER):
  2722.             case (UINT)PROP_ID(PR_SAMPLE_FLAGS):
  2723.                 lpProps2[cT].ulPropTag = PROP_TAG(PT_LONG, id);
  2724.                 lpProps2[cT].Value.l = 0;
  2725.                 break;
  2726.  
  2727.             case (UINT)PROP_ID(PR_TEMP_PEER_TO_PEER):
  2728.             case (UINT)PROP_ID(PR_TEMP_UI_ALWAYS):
  2729.             case (UINT)PROP_ID(PR_TEMP_LOG_EVENTS):
  2730.             case (UINT)PROP_ID(PR_TEMP_SAVE_DATA):
  2731.                 lpProps2[cT].ulPropTag = PROP_TAG(PT_BOOLEAN, id);
  2732.                 lpProps2[cT].Value.b = FALSE;
  2733.                 break;
  2734.  
  2735.             default:
  2736.                 DebugTrace("Got a bad PropTag in ScMergeLogonProps.\n");
  2737.             }
  2738.         }
  2739.     }
  2740.  
  2741.     /*  Now, replace the profile properties with those passed in by the
  2742.         user.  Check the ones of the type "File Path" to see that they
  2743.         have a slash as their last character.  If not, then add one. */
  2744.  
  2745.     while (cProps1--)
  2746.     {
  2747.         ulTag = lpProps1[cProps1].ulPropTag;
  2748.  
  2749.         switch (ulTag)
  2750.         {
  2751.             /* Do the String properties first */
  2752.  
  2753.         case PR_SAMPLE_INBOUND_DIR:
  2754.         case PR_SAMPLE_OUTBOUND_DIR:
  2755.         case PR_SAMPLE_DIRECTORY:
  2756.             if (lpProps1[cProps1].Value.LPSZ)
  2757.             {
  2758.                 cch = lstrlen(lpProps1[cProps1].Value.LPSZ);
  2759.  
  2760.                 if (cch && lpProps1[cProps1].Value.LPSZ[cch - 1] != '\\')
  2761.                 {
  2762.                     sc = lpAllocMore((cch + 2) * sizeof(TCHAR),
  2763.                         lpProps2, (LPVOID FAR *) &lpszT);
  2764.  
  2765.                     if (!FAILED(sc))
  2766.                     {
  2767.                         lstrcpy(lpszT, lpProps1[cProps1].Value.LPSZ);
  2768.                         lpszT[cch] = '\\';
  2769.                         lpszT[cch + 1] = '\0';
  2770.                         ArrayIndex(ulTag, lpProps2).Value.LPSZ = lpszT;
  2771.                     }
  2772.                 }
  2773.                 else
  2774.                     ArrayIndex(ulTag, lpProps2).Value.LPSZ = lpProps1[cProps1].Value.LPSZ;
  2775.             }
  2776.             else
  2777.                 ArrayIndex(ulTag, lpProps2).Value.LPSZ = szEmpty;
  2778.  
  2779.             break;
  2780.  
  2781.         case PR_SAMPLE_DISPLAY_NAME:
  2782.         case PR_SAMPLE_EMAIL_ADDR_TYPE:
  2783.         case PR_SAMPLE_EMAIL_ADDRESS:
  2784.         case PR_SAMPLE_FILENAME:
  2785.         case PR_SAMPLE_LOGFILE:
  2786.             if (lpProps1[cProps1].Value.LPSZ)
  2787.                 ArrayIndex(ulTag, lpProps2).Value.LPSZ = lpProps1[cProps1].Value.LPSZ;
  2788.             else
  2789.                 ArrayIndex(ulTag, lpProps2).Value.LPSZ = szEmpty;
  2790.  
  2791.             break;
  2792.  
  2793.             /* Then the long values */
  2794.  
  2795.         case PR_SAMPLE_LOGHIGHWATER:
  2796.         case PR_SAMPLE_LOGLOWWATER:
  2797.         case PR_SAMPLE_FLAGS:
  2798.             ArrayIndex(ulTag, lpProps2).Value.l = lpProps1[cProps1].Value.l;
  2799.             break;
  2800.  
  2801.             /* We have a bad value, lets return an error! */
  2802.  
  2803.         default:
  2804.             DebugTrace("Got a bad PropTag in ScMergeLogonProps()");
  2805.             return E_INVALIDARG;
  2806.         }
  2807.     }
  2808.  
  2809.     return ScDupPropset((int)cProps2, lpProps2, lpAllocBuff, lppPropsDest);
  2810. }
  2811.  
  2812.  
  2813. /*
  2814.  -  HrDeleteDeferred
  2815.  -
  2816.  *  Purpose:
  2817.  *      Removes a deferred message node from the list when the Spooler
  2818.  *      does a NOTIFY_ABORT_DEFERRED.
  2819.  *
  2820.  *  Parameters:
  2821.  *      lpxpl           The session owning the deferred message
  2822.  *      lpsbinEID       EntryID of the deferred message to delete
  2823.  *
  2824.  *  Returns:
  2825.  *      hResult         Indicating Success/Faailure
  2826.  */
  2827.  
  2828. HRESULT
  2829. HrDeleteDeferred(LPXPL lpxpl, LPSBinary lpsbinEID)
  2830. {
  2831.     LPDEFMSG lpDefMsg;
  2832.     LPDEFMSG *lppDefMsg = &(lpxpl->lpDeferredList);
  2833.  
  2834.     while (lpDefMsg = *lppDefMsg)
  2835.     {
  2836.         if ((lpDefMsg->sbinEIDDef.cb == lpsbinEID->cb) &&
  2837.             !memcmp(lpDefMsg->sbinEIDDef.lpb,
  2838.                     lpsbinEID->lpb,
  2839.                     (UINT)lpsbinEID->cb))
  2840.         {
  2841.             *lppDefMsg = lpDefMsg->lpNext;
  2842.             break;
  2843.         }
  2844.         else
  2845.             lppDefMsg = &(lpDefMsg->lpNext);
  2846.     }
  2847.  
  2848.     lpxpl->FreeBuffer(lpDefMsg);
  2849.  
  2850.     return hrSuccess;
  2851. }
  2852.  
  2853.  
  2854. /*
  2855.  *  WizardEntry()
  2856.  *
  2857.  *  Purpose:
  2858.  *
  2859.  *      This is the initial entrypoint for the MAPI 1.0 configuration
  2860.  *      wizard.  This function tells the wizard DLL how many pages the
  2861.  *      configuration for this service requires as well as the dialog
  2862.  *      procedure to call for each individual event.
  2863.  *
  2864.  *  Arguments:
  2865.  *
  2866.  *      hInstance       the instance of my dll, this can be used to
  2867.  *                      retrieve resources out of my DLL, etc.
  2868.  *
  2869.  *      lppszRsrcName   [OUT]   on return, this buffer is filled with
  2870.  *                              the full name of the dialog resource ID.
  2871.  *                              Note that this requires the name to be a
  2872.  *                              text value and not something generated
  2873.  *                              with the MAKEINTRESOURCE() macro
  2874.  *
  2875.  *      lpfnDlgProc     [OUT]   on return, holds a function pointer to
  2876.  *                              the dialog proc to call for each event
  2877.  *
  2878.  *      lpMapiProp      the pointer to a IMAPIProp object that is my
  2879.  *                      interface to the profile.
  2880.  *
  2881.  *      lpsup           A profile suport object that can be used to
  2882.  *                      get MAPI allocators
  2883.  *
  2884.  *  Returns:
  2885.  *
  2886.  *      (SCODE)         S_OK
  2887.  */
  2888.  
  2889. ULONG STDAPICALLTYPE
  2890. WizardEntry (HINSTANCE hInstance,
  2891.     LPTSTR FAR * lppszRsrcName,
  2892.     DLGPROC FAR * lpfnDlgProc,
  2893.     LPMAPIPROP lpMapiProp,
  2894.     LPVOID lpsup)
  2895. {
  2896.     const static TCHAR szWizTemplate[] = "SampleTransportWizard";
  2897.  
  2898.     Unreferenced (lpsup);
  2899.     
  2900.     /*  Should probably mutex access here */
  2901.  
  2902.     *lppszRsrcName = (LPTSTR)szWizTemplate;
  2903.     *lpfnDlgProc = (DLGPROC) WizardWndProc;
  2904.     lpmpWizard = lpMapiProp;
  2905.     UlAddRef (lpMapiProp);
  2906.  
  2907.     return S_OK;
  2908. }
  2909.  
  2910. /*
  2911.  *  TogglePage()
  2912.  *
  2913.  *  Purpose:
  2914.  *
  2915.  *      Loops through the controls on a wizard page and eiter
  2916.  *      enables/shows the control or hides/disables it.
  2917.  */
  2918.  
  2919. VOID
  2920. TogglePage (HWND hdlg, UINT ipage, BOOL fEnable)
  2921. {
  2922.     UINT ictl = 0;
  2923.     HANDLE hctl;
  2924.  
  2925.     while (hctl = GetDlgItem (hdlg, (WIZ_BASE + (ipage * 10) + ictl++)))
  2926.     {
  2927.         EnableWindow(hctl, fEnable);
  2928.         ShowWindow (hctl, (fEnable ? SW_SHOW : SW_HIDE));
  2929.     }
  2930. }
  2931.  
  2932. BOOL STDAPICALLTYPE
  2933. WizardWndProc (HWND hDlg,
  2934.     UINT wMsgID,
  2935.     WPARAM wParam,
  2936.     LPARAM lParam)
  2937. {
  2938.     UINT cb;
  2939.     UINT cpageJump = 1;
  2940.     UINT idFocus = 0;
  2941.  
  2942.     static fInited = FALSE;
  2943.     static UINT ipWiz = 0;
  2944.     static SPropValue rgvalWiz[cWizProps] = {0};
  2945.     static CHAR rgchName[cchNameMax + 1] = {0};
  2946.     static CHAR rgchType[cchTypeMax + 1] = {0};
  2947.     static CHAR rgchUNC[MAX_PATH] = {0};
  2948.     static CHAR rgchPath[MAX_PATH] = {0};
  2949.  
  2950.     switch (wMsgID)
  2951.     {
  2952.       case WM_INITDIALOG:
  2953.  
  2954.         if (!fInited)
  2955.         {
  2956.             fInited = TRUE;
  2957.             SetWindowText (GetDlgItem (hDlg, IDC_TypeEdit), "MSPEER");
  2958.             SendMessage (GetDlgItem (hDlg, IDC_TypeEdit), EM_LIMITTEXT, (WPARAM)cchTypeMax, 0);
  2959.             SendMessage (GetDlgItem (hDlg, IDC_NameEdit), EM_LIMITTEXT, (WPARAM)cchNameMax, 0);
  2960.             SendMessage (GetDlgItem (hDlg, IDC_UNCEdit), EM_LIMITTEXT, (WPARAM)MAX_PATH - 1, 0);
  2961.             SendMessage (GetDlgItem (hDlg, IDC_PathEdit), EM_LIMITTEXT, (WPARAM)MAX_PATH - 1, 0);
  2962.             rgvalWiz[ipDispName].ulPropTag = PR_NULL;
  2963.             rgvalWiz[ipEmailType].ulPropTag = PR_NULL;
  2964.             rgvalWiz[ipEmailAddress].ulPropTag = PR_NULL;
  2965.             rgvalWiz[ipInbox].ulPropTag = PR_NULL;
  2966.             rgvalWiz[ipOutbox].ulPropTag = PR_SAMPLE_OUTBOUND_DIR;
  2967.             rgvalWiz[ipOutbox].Value.lpszA = "\\TEMP";
  2968.             rgvalWiz[ipFilename].ulPropTag = PR_NULL;
  2969.             rgvalWiz[ipDirectory].ulPropTag = PR_NULL;
  2970.             rgvalWiz[ipFlags].ulPropTag = PR_SAMPLE_FLAGS;
  2971.             rgvalWiz[ipFlags].Value.l = PR_SAMPLE_FLAG_PEER_TO_PEER | PR_SAMPLE_FLAG_SAVE_DATA;
  2972.             rgvalWiz[ipLogFile].ulPropTag = PR_SAMPLE_LOGFILE;
  2973.             rgvalWiz[ipLogFile].Value.lpszA = "SMPXP.LOG";
  2974.             rgvalWiz[ipLogHigh].ulPropTag = PR_SAMPLE_LOGHIGHWATER;
  2975.             rgvalWiz[ipLogHigh].Value.l = 0;
  2976.             rgvalWiz[ipLogLow].ulPropTag = PR_SAMPLE_LOGLOWWATER;
  2977.             rgvalWiz[ipLogLow].Value.l = 0;
  2978.             DebugTrace ("MSPEER: Wizard page initialized\n");
  2979.         }
  2980.         break;
  2981.  
  2982.       case WIZ_QUERYNUMPAGES:
  2983.  
  2984.         DebugTrace ("MSPEER: Wizard page count %d\n", cpageMax);
  2985.         return (BOOL)cpageMax;
  2986.  
  2987.       case WM_CLOSE:
  2988.  
  2989.         UlRelease (lpmpWizard);
  2990.         lpmpWizard = NULL;
  2991.         break;
  2992.  
  2993.       case WM_COMMAND:
  2994.  
  2995.         switch (LOWORD(wParam))
  2996.         {
  2997.           case WIZ_NEXT:
  2998.  
  2999.             switch (ipWiz)
  3000.             {
  3001.               case 0:
  3002.                 idFocus = IDC_NameEdit;
  3003.                 break;
  3004.  
  3005.               case 1:
  3006.  
  3007.                 /*  Going from name page to address type */
  3008.  
  3009.                 if (!(cb = (UINT)GetWindowText (GetDlgItem (hDlg, IDC_NameEdit),
  3010.                                         rgchName, cchNameMax + 1)))
  3011.                 {
  3012.                     /*  We require a display name */
  3013.  
  3014.                     MessageBeep (0);
  3015.                     return 0;
  3016.                 }
  3017.                 rgvalWiz[ipDispName].ulPropTag = PR_SAMPLE_DISPLAY_NAME;
  3018.                 rgvalWiz[ipDispName].Value.lpszA = rgchName;
  3019.                 idFocus = IDC_TypeEdit;
  3020.                 break;
  3021.  
  3022.               case 2:
  3023.  
  3024.                 /* Going from type page to inbox */
  3025.  
  3026.                 if (!(cb = (UINT)GetWindowText (GetDlgItem (hDlg, IDC_TypeEdit),
  3027.                                         rgchType, cchTypeMax + 1)))
  3028.                 {
  3029.                     /*  We require an address type */
  3030.  
  3031.                     MessageBeep (0);
  3032.                     return 0;
  3033.                 }
  3034.                 rgvalWiz[ipEmailType].ulPropTag = PR_SAMPLE_EMAIL_ADDR_TYPE;
  3035.                 rgvalWiz[ipEmailType].Value.lpszA = rgchType;
  3036.                 idFocus = IDC_UNCEdit;
  3037.                 break;
  3038.  
  3039.               case 3:
  3040.  
  3041.                 /* Going from inbox page to path page */
  3042.  
  3043.                 if (!(cb = (UINT)GetWindowText (GetDlgItem (hDlg, IDC_UNCEdit),
  3044.                                         rgchUNC, MAX_PATH)))
  3045.                 {
  3046.                     /*  We require an address type */
  3047.  
  3048.                     MessageBeep (0);
  3049.                     return 0;
  3050.                 }
  3051.                 rgvalWiz[ipEmailAddress].ulPropTag = PR_SAMPLE_EMAIL_ADDRESS;
  3052.                 rgvalWiz[ipEmailAddress].Value.lpszA = rgchUNC;
  3053.                 idFocus = IDC_PathEdit;
  3054.                 break;
  3055.  
  3056.               case 4:
  3057.  
  3058.                 /* Going from the path page to completion*/
  3059.  
  3060.                 rgvalWiz[ipInbox].ulPropTag = PR_SAMPLE_INBOUND_DIR;
  3061.                 if ((cb = (UINT)GetWindowText (GetDlgItem (hDlg, IDC_PathEdit), rgchPath, MAX_PATH)))
  3062.                     rgvalWiz[ipInbox].Value.lpszA = rgchPath;
  3063.                 else
  3064.                     rgvalWiz[ipInbox].Value.lpszA = rgvalWiz[ipEmailAddress].Value.lpszA;
  3065.  
  3066.                 Assert (lpmpWizard);
  3067.                 lpmpWizard->lpVtbl->SetProps (lpmpWizard, cWizProps, rgvalWiz, NULL);
  3068.                 break;
  3069.  
  3070.               default:
  3071.                 Assert (FALSE);
  3072.                 break;
  3073.             }
  3074.  
  3075.             /*  Disable Current Page */
  3076.             TogglePage (hDlg, ipWiz, FALSE);
  3077.  
  3078.             /*  Enable Next Page */
  3079.             TogglePage (hDlg, ++ipWiz, TRUE);
  3080.             SetFocus (GetDlgItem (hDlg, idFocus));
  3081. #ifdef  WIN32
  3082.             SendDlgItemMessage (hDlg, idFocus, EM_SETSEL, 0, -1);
  3083. #else
  3084.             SendDlgItemMessage (hDlg, idFocus, EM_SETSEL, 0, MAKELONG(0,-1));
  3085. #endif
  3086.             return (BOOL)cpageJump;
  3087.  
  3088.           case WIZ_PREV:
  3089.  
  3090.             /*  Disable Current Page */
  3091.             TogglePage (hDlg, ipWiz, FALSE);
  3092.             
  3093.             /*  Enable Previous Page */
  3094.             TogglePage (hDlg, --ipWiz, TRUE);
  3095.  
  3096.             switch (ipWiz)
  3097.             {
  3098.               case 1:
  3099.                 idFocus = IDC_NameEdit;
  3100.                 break;
  3101.  
  3102.               case 2:
  3103.                 idFocus = IDC_TypeEdit;
  3104.                 break;
  3105.  
  3106.               case 3:
  3107.                 idFocus = IDC_UNCEdit;
  3108.                 break;
  3109.  
  3110.               case 4:
  3111.                 idFocus = IDC_PathEdit;
  3112.                 break;
  3113.  
  3114.               default:
  3115.                 break;
  3116.             }
  3117.             SetFocus (GetDlgItem (hDlg, idFocus));
  3118. #ifdef  WIN32
  3119.             SendDlgItemMessage (hDlg, idFocus, EM_SETSEL, 0, -1);
  3120. #else
  3121.             SendDlgItemMessage (hDlg, idFocus, EM_SETSEL, 0, MAKELONG(0,-1));
  3122. #endif
  3123.             return (BOOL)cpageJump;
  3124.  
  3125.           default:
  3126.  
  3127.             return FALSE;
  3128.         }
  3129.         break;
  3130.  
  3131.       default:
  3132.  
  3133.         return FALSE;
  3134.     }
  3135.  
  3136.     return TRUE;
  3137. }
  3138.