/*++

   Copyright    (c)    1994    Microsoft Corporation

   Module  Name :

        smtpcli.hxx

   Abstract:

        This module defines the SMTP_CONNECTION class.
        This object maintains information about a new client connection

   Author:

           Rohan Phillips    ( Rohanp )    11-Dec-1995

   Project:

           SMTP Server DLL

   Revision History:

--*/

#ifndef _SMTP_CLIENT_HXX_
#define _SMTP_CLIENT_HXX_

/************************************************************
 *     Include Headers
 ************************************************************/
#include "conn.hxx"
#include "simssl2.h"
#include "addr821.hxx"



/************************************************************
 *     Symbolic Constants
 ************************************************************/
static const char * SmtpCommands [] = {
     #undef SmtpDef
     #define SmtpDef(a) #a,
     #include "smtpdef.h"
     NULL
     };

enum SMTPSTATE
     {
     #undef SmtpDef
     #define SmtpDef(a) a,
     #include "smtpdef.h"
     LAST_SMTP_STATE
     };

enum LASTIOSTATE
     {
       READIO, WRITEIO, TRANSFILEIO, MAIL_QUEUEIO, REMOTE_MAIL_QUEUEIO, WRITEFILEIO
     };


const DWORD  MIN_SMTP_COMMAND_SIZE      = 4; //4 chars

const DWORD SMTP_RESP_STATUS =       211;
const DWORD SMTP_RESP_HELP   =       214;
const DWORD SMTP_RESP_READY  =       220;
const DWORD SMTP_RESP_CLOSE  =       221;
const DWORD SMTP_RESP_AUTHENTICATED = 235;
const DWORD SMTP_RESP_OK     =       250;
const DWORD SMTP_RESP_WILL_FWRD =    251;
const DWORD SMTP_RESP_ETRN_ZERO_MSGS = 251;
const DWORD SMTP_RESP_VRFY_CODE =    252;
const DWORD SMTP_RESP_ETRN_N_MSGS =  253;
const DWORD SMTP_RESP_AUTH1_PASSED =  334;
const DWORD SMTP_RESP_START     =    354;
const DWORD SMTP_RESP_SRV_UNAVAIL  = 421;
const DWORD SMTP_RESP_MBX_UNAVAIL  = 450;
const DWORD SMTP_RESP_REJECT_MAILFROM = 450;
const DWORD SMTP_RESP_ERROR        = 451;
const DWORD SMTP_RESP_NORESOURCES  = 452;
const DWORD SMTP_RESP_NODE_INVALID = 459;
const DWORD SMTP_RESP_BAD_CMD      = 500;
const DWORD SMTP_RESP_BAD_ARGS     = 501;
const DWORD SMTP_RESP_NOT_IMPL     = 502;
const DWORD SMTP_RESP_BAD_SEQ      = 503;
const DWORD SMTP_RESP_PARM_NOT_IMP = 504;
const DWORD SMTP_RESP_MUST_SECURE  = 530;
const DWORD SMTP_RESP_AUTH_REJECT  = 535;
const DWORD SMTP_RESP_NOT_FOUND    = 550;
const DWORD SMTP_RESP_PLS_FWRD     = 551;
const DWORD SMTP_RESP_NOSTORAGE    = 552;
const DWORD SMTP_RESP_MBX_SYNTAX   = 553;
const DWORD SMTP_RESP_TRANS_FAILED = 554;

//State of FSA in IsLineCompleteRFC822
const DWORD SEEN_NOTHING    = 1;
const DWORD SEEN_CR         = 2;
const DWORD SEEN_CRLF       = 3;

/* strings to be appended to numeric reply codes */
static const char * SMTP_READY_STR       =   "SMTP server ready";
static const char * SMTP_BAD_CMD_STR     =   "Unrecognized command";
static const char * SMTP_BAD_BODY_TYPE_STR =   "Unsupported BODY type";
static const char * SMTP_MAIL_OK_STR     =   "Sender OK";
static const char * SMTP_QUIT_OK_STR     =   "Service closing transmission channel";
static const char * SMTP_BAD_SEQ_STR     =   "Bad sequence of commands";
static const char * SMTP_NOT_IMPL_STR    =   "Command not implemented";
static const char * SMTP_HELO_OK_STR     =   "Hi there, pleased to meet you";
static const char * SMTP_RECIP_OK_STR    =   "Recipient OK";
static const char * SMTP_BAD_RECIP_STR   =   "Addressee unknown";
static const char * SMTP_START_MAIL_STR  =   "Start mail input; end with <CRLF>.<CRLF>";
static const char * SMTP_RSET_OK_STR     =   "Resetting";
static const char * SMTP_LOCAL_DEL_STR   =   "Error in local delivery";
static const char * SMTP_SRV_UNAVAIL_STR =   "Service not available or retries exceeded, closing channel";
static const char * SMTP_NO_STORAGE      =   "Insufficient system storage";
static const char * SMTP_NO_VALID_RECIPS =   "No valid recipients";
static const char * SMTP_QUEUE_MAIL      =   "Queued mail for delivery";
static const char * SMTP_NO_MEMORY       =   "Out of memory";
static const char * SMTP_EMPTY_MAIL      =   "Empty mail message";
static const char * SMTP_TIMEOUT_MSG     =   "Timeout waiting for client input";
static const char * SMTP_TOO_MANY_ERR_MSG =  "Too many errors on this connection---closing";
static const char * SMTP_NO_DOMAIN_NAME_MSG  =  "Domain Name required";
static const char * SMTP_NEED_MAIL_FROM_MSG  =  "Need Mail From: first";
static const char * SMTP_MAX_MSG_SIZE_EXCEEDED_MSG = "Message size exceeds fixed maximum message size";
static const char * SMTP_MAX_SESSION_SIZE_EXCEEDED_MSG = "Session size exceeds fixed maximum session size";
static const char * SMTP_INVALID_ADDR_MSG   = "Invalid Address";
static const char * SMTP_SRV_UNAVAIL_MSG    = "Service not available, closing transmission channel";
static const char * SMTP_NO_ETRN_IN_MSG    = "ETRN may not be issued while mail transaction is occurring";
static const char * SMTP_ONLY_ONE_TLS_MSG = "Only one STARTTLS command can be issued per session";
static const char * SMTP_TLS_NOT_SUPPORTED = "Not supported at this server";
static const char * SMTP_NO_CERT_MSG = "Unable to initialize security subsystem";
static const char * SMTP_MSG_MUST_SECURE = "Must issue a STARTTLS command first";
static const char * SMTP_MSG_NOT_SECURE_ENOUGH = "Command refused due to lack of security";
static const char * SMTP_BDAT_EXPECTED = "BDAT command expected";
static const char * SMTP_BDAT_CHUNK_OK_STR = "CHUNK received OK";
static const char * SMTP_RDNS_REJECTION = "Rejected : Domain does not match IP address";
static const char * SMTP_RDNS_FAILURE = "Unable to verify the connecting host domain";

static const char * SMTP_REMOTE_HOST_REJECTED_FOR_SIZE = "Msg Size greater than allowed by Remote Host";
static const char * SMTP_REMOTE_HOST_REJECTED_FOR_TYPE = "Body type not supported by Remote Host";
static const char * SMTP_REMOTE_HOST_DROPPED_CONNECTION = "Connection dropped by Remote Host";
static const char * SMTP_REMOTE_HOST_REJECTED_AUTH = "Failed to authenticate with Remote Host";
static const char * SMTP_REMOTE_HOST_REJECTED_SSL = "Failed to negotiate secure channel with Remote Host";

//Enhanced status codes
static const char * EPROT_SUCCESS        = "2.0.0";
static const char * E_GOODBYE             = "2.0.0";
static const char * ESENDER_ADDRESS_VALID  = "2.1.0";
static const char * EVALID_DEST_ADDRESS     = "2.1.5";
static const char * EMESSAGE_GOOD         = "2.6.0";
static const char * ESEC_SUCCESS         = "2.7.0";

static const char * EINTERNAL_ERROR         = "4.0.0";
static const char * ENO_RESOURCES         = "4.3.1";
static const char * ENO_SECURITY_TMP     = "4.7.3";
static const char * EMAILBOX_FULL        = "4.2.2";

static const char * EBAD_SENDER             = "5.1.7";
static const char * ENOT_IMPLEMENTED     = "5.3.3";
static const char * EMESSAGE_TOO_BIG     = "5.3.4";
static const char * EINVALID_COMMAND     = "5.5.1";
static const char * ESYNTAX_ERROR         = "5.5.2";
static const char * ETOO_MANY_RCPTS         = "5.5.3";
static const char * EINVALID_ARGS         = "5.5.4";
static const char * ENO_FORWARDING         = "5.7.1";
static const char * ENO_SECURITY         = "5.7.3";
static const char * E_TLSNEEDED          = "5.7.0";
static const char * ENO_SEC_PACKAGE         = "5.7.4";
;


const DWORD MIN_BUFFLENGTH              =  10;
const DWORD SMTP_MAX_ERRORS             =  10;
const DWORD SMTP_MAX_USER_NAME_LEN      =  64;
const DWORD SMTP_MAX_DOMAIN_NAME_LEN    = 256;
const DWORD SMTP_MAX_PATH_LEN           = 64;
const DWORD SMTP_MAX_COMMANDLINE_LEN    = 512;
const DWORD SMTP_MAX_REPLY_LEN          = 1024;
const DWORD SMTP_MAX_MSG_SIZE           = 42 * 1024;
const char SMTP_COMMAND_NOERROR         = (char) 0;
const char SMTP_COMMAND_TOO_SHORT       = (char) 1;
const char SMTP_COMMAND_TOO_LONG        = (char) 2;
const char SMTP_COMMAND_NOT_FOUND       = (char) 3;

enum MailBodyDiagnosticCode {
    ERR_NONE = 0,
    ERR_OUT_OF_MEMORY,
    ERR_MAX_MSG_SIZE, 
    ERR_AUTH_NEEDED,
    ERR_TLS_NEEDED,
    ERR_HELO_NEEDED,
    ERR_MAIL_NEEDED,
    ERR_RCPT_NEEDED,
    ERR_NO_VALID_RCPTS,
    ERR_RETRY
};

//
// Protocl Events
//
#include "cpropbag.h"
#include "pe_out.hxx"
#include <smtpevent.h>
#include "pe_supp.hxx"
#include "pe_disp.h"

//
// Forwards for inbound extension related objects
//
interface    IEventRouter;
interface    ISmtpOutboundCommandDispatcher;
class        CInboundContext;


#define MAX_SSL_FRAGMENT_SIZE   (32 * 1024)

//We would like this to be LTE 32K but large enough to accomodate the
//complete average mail file
#define SMTP_WRITE_BLOCK_SIZE   (4000)

//See NT:415893
//Previously this value was 512 bytes, which would allow a buffer overrun to
//happen against us after the DATA command.  This value should be calculated
//from the max accepted values used.
#define REWRITTEN_GEN_MSGID_BUFFER  20
#define MAX_REWRITTEN_MSGID \
    (REWRITTEN_GEN_MSGID_BUFFER+1) + \
    sizeof("Message-ID:   <123456789@>\r\n") + \
    (MAX_INTERNET_NAME+1)

//Worst case this will rewrite the following
//  - "FROM: " + mail from
//  - "RETURN-PATH: " + return path
//  - "BCC: "
//  - "MESSAGE-ID: " generated id  + FQDN
//  - "X-OriginalArrivalTime: " + 64 byte buffer
//  - "Date: " + cMaxArpaData buffer
//  - CRLF CRLF
#define MAX_REWRITTEN_HEADERS \
    ((MAX_INTERNET_NAME+1) * 3 ) + \
    sizeof("From:  \r\n") + \
    sizeof("Return-Path: \r\n") + \
    sizeof("Bcc: \r\n") + \
    sizeof("Message-ID: \r\n") + MAX_REWRITTEN_MSGID + \
    sizeof("X-OriginalArrivalTime: \r\n") + 64 + \
    sizeof("Date:  \r\n") + cMaxArpaDate +\
    sizeof("\r\n\r\n")

#define MAX_NATIVE_RESPONSE_SIZE    1024

//This is the largest allowed size for an AUTH NTLM uuencoded
//response string. Largest response size = 0x770 ~ 1600. uuencode
//inflates size by 1.5 so about 2500 is the largest allowable size.

#define MAX_REPLY_SIZE  4000
//
//  Redefine the type to indicate that this is a call-back function
//
typedef  ATQ_COMPLETION   PFN_ATQ_COMPLETION;

enum ReverseDnsLookupCodes{
    SUCCESS,
    LOOKUP_FAILED,
    NO_MATCH
};



/************************************************************
 *    Type Definitions
 ************************************************************/

typedef struct _SMTPCLI_FILE_OVERLAPPED
{
    SERVEREVENT_OVERLAPPED SeoOverlapped;
    LASTIOSTATE        m_LastIoState;
    DWORD            m_cbIoSize;
    LPBYTE            m_pIoBuffer;
}   SMTPCLI_FILE_OVERLAPPED;

typedef struct _TURN_DOMAIN_LIST
{
    MULTISZ*    pmsz;
    const char   *    szCurrentDomain;
}TURN_DOMAIN_LIST, *PTURN_DOMAIN_LIST;

/*++
    class SMTP_CONNECTION

      This class is used for keeping track of individual client
       connections established with the server.

      It maintains the state of the connection being processed.

--*/
class SMTP_CONNECTION : public CLIENT_CONNECTION
{

  public:

    ~SMTP_CONNECTION (void);

     static  CPool       Pool;

    // override the mem functions to use CPool functions
    void *operator new (size_t cSize)
                               { return Pool.Alloc(); }
    void operator delete (void *pInstance)
                               { Pool.Free(pInstance); }
    int SmtpGetCommand(const char * Request, DWORD RequestLen, LPDWORD CmdSize);
    BOOL SendSmtpResponse(BOOL SyncSend = TRUE);
    virtual BOOL ProcessClient( IN DWORD cbWritten,
                                IN DWORD dwCompletionStatus,
                                IN  OUT  OVERLAPPED * lpo);

    virtual BOOL StartSession( VOID);
    BOOL DoEHLOCommand(const char * InputLine, DWORD parameterSize);
    BOOL DoHELOCommand(const char * InputLine, DWORD parameterSize);
    BOOL DoRSETCommand(const char * InputLine, DWORD parameterSize);
    BOOL DoNOOPCommand(const char * InputLine, DWORD parameterSize);
    BOOL DoQUITCommand(const char * InputLine, DWORD parameterSize);
    BOOL DoHELPCommand(const char * InputLine, DWORD parameterSize);
    BOOL DoMAILCommand(const char * InputLine, DWORD parameterSize);
    BOOL DoRCPTCommand(const char * InputLine, DWORD parameterSize);
    BOOL DoDATACommand(const char * InputLine, DWORD parameterSize);
    BOOL DoVRFYCommand(const char * InputLine, DWORD parameterSize);
    BOOL DoAUTHCommand(const char * InputLine, DWORD parameterSize);
    BOOL DoLASTCommand(const char * InputLine, DWORD parameterSize);
    BOOL DoETRNCommand(const char * InputLine, DWORD parameterSize);
    BOOL DoTURNCommand(const char * InputLine, DWORD parameterSize);
    BOOL DoSTARTTLSCommand(const char * InputLine, DWORD parameterSize);
    BOOL DoTLSCommand(const char * InputLine, DWORD parameterSize);
    BOOL DoBDATCommand(const char * InputLine, DWORD parameterSize);
    BOOL ProcessReadIO( IN      DWORD InputBufferLen,
                        IN      DWORD dwCompletionStatus,
                        IN OUT  OVERLAPPED * lpo);
    BOOL ProcessFileWrite(IN    DWORD BytesWritten,
                        IN      DWORD       dwCompletionStatus,
                        IN OUT  OVERLAPPED  *lpo);
    BOOL ProcessDATAMailBody(const char *InputLine, DWORD UndecryptedTailSize, BOOL *pfAsyncOp);
    BOOL ProcessBDATMailBody(const char *InputLine, DWORD UndecryptedTailSize, BOOL *pfAsyncOp);
    BOOL DoDATACommandEx(const char * InputLine, DWORD parameterSize, DWORD UndecryptedTailSize,BOOL *lpfWritePended, BOOL *pfAsyncOp);
    BOOL DoBDATCommandEx(const char * InputLine, DWORD parameterSize, DWORD UndecryptedTailSize, BOOL *lpfWritePended, BOOL *pfAsyncOp);
    BOOL Do_EODCommand(const char * InputLine, DWORD parameterSize);
    BOOL FormatSmtpMessage(DWORD dwCode, const char * szEnhancedCodes, IN const char * Format, ...);
    BOOL FormatSmtpMessage(unsigned char *Buffer, DWORD dwBytes);
    void FormatEhloResponse(void);

    //    inbound protocol extension related member functions
    HRESULT OnEvent(
        IUnknown * pIserver,
        IUnknown * pISession,
        IMailMsgProperties *pIMessage,
        LPPE_COMMAND_NODE    pCommandNode,
        LPPE_BINDING_NODE    pBindingNode,
        char * szArgs
        );
    HRESULT OnNotifyAsyncCompletion(
        HRESULT    hrResult
        );
    BOOL ProcessAndSendResponse();
    BOOL GlueDispatch(char * InputLine, DWORD IntermediateSize, DWORD CmdSize, BOOL * pfAsyncOp);
    BOOL ProcessPeBlob(const char * pbInputLine, DWORD cbSize);
    BOOL PE_CdFormatSmtpMessage(DWORD dwCode, const char * szEnhancedCodes,IN const char * Format, ...);
    BOOL PE_FormatSmtpMessage(IN const char * Format, ...);
    BOOL PE_FastFormatSmtpMessage(LPSTR pszBuffer, DWORD dwBytes);
    BOOL PE_DisconnectClient();
    BOOL PE_SendSmtpResponse();
    IUnknown *GetSessionPropertyBag() { return((IUnknown *)(IMailMsgPropertyBag *)(&m_SessionPropertyBag)); }

    char * CheckArgument(IN OUT char * Argument, BOOL WriteError = TRUE);

    static SMTP_CONNECTION * CreateSmtpConnection (IN PCLIENT_CONN_PARAMS  ClientParam,
        PSMTP_SERVER_INSTANCE pInst);

    SOCKET QueryClientSocket(void)
    {
        return QuerySocket();
    }

    LPCSTR QueryClientUserName()
    {
        if(m_szHeloAddr[0] != '\0')
            return m_szHeloAddr;
        else
            return "";
    }

    void StartSessionTimer()
    {
        m_msSession = GetTickCount();
    }

    DWORD QuerySessionTime()
    {
        return GetTickCount() - m_msSession;
    }

    ADDRESS_CHECK* QueryAccessCheck() { return &m_acAccessCheck; }
    BOOL BindInstanceAccessCheck();
    VOID UnbindInstanceAccessCheck();

    PSMTP_SERVER_INSTANCE QuerySmtpInstance( VOID ) const
        { _ASSERT(m_pInstance != NULL); return m_pInstance; }

    BOOL IsSmtpInstance( VOID ) const
        { return m_pInstance != NULL; }

    VOID SetSmtpInstance( IN PSMTP_SERVER_INSTANCE pInstance )
        { _ASSERT(m_pInstance == NULL); m_pInstance = pInstance; }

    SMTP_SERVER_STATISTICS * QuerySmtpStatsObj( VOID ) const
        { return m_pSmtpStats; }

    VOID SetSmtpStatsObj( IN LPSMTP_SERVER_STATISTICS pSmtpStats )
        { m_pSmtpStats = pSmtpStats; }

    //
    // These are overridden from the base CLIENT_CONNECTION class to support
    // switching of receive buffers. We need to be able to switch buffers to
    // support SSL, which needs upto 32K chunks. Note that even though SSL
    // V3.0 restricts fragment sizes to 16K, our schannel is capable of
    // generating 32K fragments (due to a bug). So, we read up to 32K.
    //

    virtual LPCSTR QueryRcvBuffer( VOID) const
      { return ((LPCSTR) m_precvBuffer); }

    virtual LPSTR QueryMRcvBuffer(VOID)    // modifiable string
      { return (LPSTR) m_precvBuffer; }

    //
    // This method causes this object to allocate 32K buffers and use them as
    // the receive and output buffer.
    //
    BOOL SwitchToBigSSLBuffers();

    DWORD QueryMaxReadSize() const
      { return m_cbMaxRecvBuffer; }
private :

    //In case of chunking we write to the disk async
    DWORD                              m_AtqLocator;
    SMTPCLI_FILE_OVERLAPPED            m_FileOverLapped;
    SMTPSTATE                          m_State;
    LASTIOSTATE                        m_LastClientIo;
    BOOL                               m_HelloSent;
    BOOL                               m_RecvdMailCmd;
    BOOL                               m_RecvdRcptCmd;
    BOOL                               m_RecvdAuthCmd;
    BOOL                               m_EmptyMail;
    BOOL                               m_Nooped;
    BOOL                               m_InHeader;
    BOOL                               m_LongBodyLine;
    BOOL                               m_fFoundEmbeddedCrlfDotCrlf;
    BOOL                               m_fScannedForCrlfDotCrlf;
    BOOL                               m_fSeenRFC822FromAddress;
    BOOL                               m_fSeenRFC822ToAddress;
    BOOL                               m_fSeenRFC822CcAddress;
    BOOL                               m_fSeenRFC822BccAddress;
    BOOL                               m_fSeenRFC822Subject;
    BOOL                               m_fSeenRFC822MsgId;
    BOOL                               m_fSeenRFC822SenderAddress;
    BOOL                               m_fSeenXPriority;
    BOOL                               m_fSeenXOriginalArrivalTime;
    BOOL                               m_fSeenContentType;
    BOOL                               m_fSetContentType;
    BOOL                               m_NeedToQuit;
    BOOL                               m_TimeToRewriteHeader;
    BOOL                               m_WritingData;
    BOOL                               m_SecurePort;
    BOOL                               m_fNegotiatingSSL;
    DWORD                              m_DNSLookupRetCode;
    BOOL                               m_fUseMbsCta;
    BOOL                               m_fAuthenticated;
    BOOL                               m_fClearText;
    BOOL                               m_fDidUserCmd;
    BOOL                               m_fAuthAnon;
    char                              *m_precvBuffer;
    DWORD                              m_cbMaxRecvBuffer;
    char                               m_OutputBuffer[SMTP_MAX_REPLY_LEN];
    char                              *m_pOutputBuffer;
    DWORD                              m_cbMaxOutputBuffer;
    CBuffer *                          m_pFileWriteBuffer;
    DWORD                              m_cbCurrentWriteBuffer;
    DWORD                              m_cbRecvBufferOffset;
    DWORD                              m_cbTempBDATLen;
    DWORD                              m_OutputBufferSize;
    DWORD                              m_cbParsable;
    DWORD                              m_ProtocolErrors;
    DWORD                              m_dwUnsuccessfulLogons;
    DWORD                              m_TotalMsgSize;
    DWORD                              m_SessionSize;
    DWORD                              m_cbDotStrippedTotalMsgSize;
    DWORD                              m_HeaderSize;
    DWORD                              m_HeaderFlags;
    DWORD                              m_MailBodyError;
    MailBodyDiagnosticCode             m_MailBodyDiagnostic;
    DWORD                              m_dwCurrentCommand;
    DWORD                              m_HopCount;
    DWORD                              m_LocalHopCount;
    LONG                               m_cPendingIoCount;
    LONG                               m_cActiveThreads;
    char                               CommandErrorType;
    char                              *m_pszArgs;
    IMailMsgProperties                *m_pIMsg;
    IMailMsgRecipients                *m_pIMsgRecipsTemp;
    IMailMsgRecipientsAdd             *m_pIMsgRecips;
    IMailMsgBind                      *m_pBindInterface;
    PFIO_CONTEXT                       m_IMsgHandle;
    char                               m_szHeloAddr[MAX_INTERNET_NAME + 1];
    char                               m_szFromAddress[MAX_INTERNET_NAME + 1];
    LIST_ENTRY                         m_HeaderList;
    DWORD                              m_msSession;
    DWORD                              m_CurrentOffset;
    CEncryptCtx                        m_encryptCtx;
    CSecurityCtx                       m_securityCtx;
    AC_RESULT                          m_acCheck;
    ADDRESS_CHECK                      m_acAccessCheck;
    METADATA_REF_HANDLER               m_rfAccessCheck;

    // used authentication mechanism
    CHAR                               m_szUsedAuthMechanism[MAX_PATH + 1];
    CHAR                               m_szUsedAuthKeyword[MAX_PATH + 1];
    char                               m_szUserName[MAX_INTERNET_NAME + 1];
    CHAR                               m_szAuthenticatedUserNameFromSink[MAX_INTERNET_NAME + 1];

    //Chunking related flags
    BOOL                               m_fIsLastChunk;
    BOOL                               m_fIsBinaryMime;
    BOOL                               m_fIsChunkComplete;
    DWORD                              m_dwTrailerStatus;
    int                                m_nChunkSize;
    int                                m_nBytesRemainingInChunk;
    BOOL                               m_fBufferFullInBDAT;

    // inbound protocol extension related data members
public:
    CInboundContext                    m_CInboundContext;
    BOOL                               m_fAsyncEventCompletion;
    BOOL                               m_fAsyncEOD;

private:
    BOOL                               m_fIsPeUnderway;
    IEventRouter                      *m_pIEventRouter;
    ISmtpInboundCommandDispatcher     *m_pCInboundDispatcher;
    CMailMsgPropertyBag                m_SessionPropertyBag;
    PSMTP_SERVER_INSTANCE              m_pInstance;
    LPSMTP_SERVER_STATISTICS           m_pSmtpStats;
    PATQ_CONTEXT                       m_AtqSeoContext;
    BOOL                               m_fPeBlobReady;
    ISmtpInCallbackSink             *  m_pPeBlobCallback;

    DWORD m_LineCompletionState;    //stores state of IsLineCompleteRFC822 automaton
    BOOL m_Truncate;                //TRUE when in truncation mode; gpulla
    BOOL m_BufrWasFull;             //TRUE when the last call to IsLineCompleteRFC822 yielded a full buffer.

    SMTP_CONNECTION(
        IN PSMTP_SERVER_INSTANCE pInstance,
        IN SOCKET sClient,
        IN const SOCKADDR_IN *  psockAddrRemote,
        IN const SOCKADDR_IN *  psockAddrLocal = NULL,
        IN PATQ_CONTEXT         pAtqContext    = NULL,
        IN PVOID                pvInitialRequest = NULL,
        IN DWORD                cbInitialData  = 0);

    BOOL InitializeObject (BOOL IsSecureConnection);
    DWORD VerifiyClient (IN const char * ClientHostName, IN const char * KnownIpAddress);
    BOOL ExtractAndValidateRcpt(char * ToName, char ** ppArgument, char * szRcptAddress, char ** ppDomain );
    BOOL ShouldAcceptRcpt(char * szDomainName );
    BOOL IsClientSecureEnough();
    BOOL HandleCompletedMessage(DWORD dwCommand, BOOL *pfAsyncOp);
    BOOL CreateMailBody (char * InputLine, DWORD ParameterSize, DWORD UndecryptedTailSize, BOOL *lpfWritePended);
    BOOL CreateMailBodyFromChunk (char * InputLine, DWORD ParameterSize, DWORD UndecryptedTailSize,BOOL *lpfWritePended);
    BOOL WriteRcvHeader(void);
    BOOL BindToStoreDrive(void);
    void HandleAddressError(char * InputLine);
    BOOL RewriteHeader(void);
    void ReInitClassVariables(void);
    LONG IncPendingIoCount(void) { return InterlockedIncrement( &m_cPendingIoCount );}
    LONG DecPendingIoCount(void) { return InterlockedDecrement( &m_cPendingIoCount ); }
    LONG IncThreadCount(void) { return  InterlockedIncrement( &m_cActiveThreads ); }
    LONG DecThreadCount(void) { return  InterlockedDecrement( &m_cActiveThreads ); }

    //skips over WordSkip in Buffer
    char * SkipWord (char * Buffer, char * WordToSkip, DWORD WordLen);
    BOOL AddToField(void);
    BOOL WriteLine(char * Text, DWORD TexSize);
    VOID ProtocolLog(
        DWORD dwCommand = USE_CURRENT,
        LPCSTR pszParameters = "",
        DWORD dwWin32Error = NO_ERROR,
        DWORD dwSmtpError = NO_ERROR,
        DWORD BytesSent = 0,
        DWORD BytesRecv = 0,
        LPSTR pszTarget = "");

    void TransactionLog(
        const char *pszOperation,
        const char *pszParameters,
        const char *pszTarget,
        DWORD dwWin32Error,
        DWORD dwServiceSpecificStatus
        );

    BOOL DecryptInputBuffer();
    BOOL ProcessInputBuffer(void);

    BOOL DoSmtpArgs (char *InputLine);
    BOOL DoRcptArgs (char *InputLine, char * szORCPTval, DWORD * pdwNotifyVal);
    BOOL DoSizeCommand(char * Value, char * InputLine);
    BOOL DoBodyCommand (char * Value, char * InputLine);
    BOOL DoRetCommand (char * Value, char * InputLine);
    BOOL DoEnvidCommand (char * Value, char * InputLine);
    BOOL DoNotifyCommand (char * Value, DWORD * pdwNotifyValue);
    BOOL DoOrcptCommand (char * Value);
    BOOL IsXtext(char * Xtext);
    BOOL ProcessAuthInfo(AUTH_COMMAND, LPSTR Blob, unsigned char * OutptBuffer, DWORD * dwBytes);
    BOOL DoAuthNegotiation(const char *InputLine, DWORD dwLineSize);
    BOOL PendReadIO(DWORD UndecryptedTailSize);
    BOOL DoUSERCommand(const CHAR *InputLine, DWORD dwLineSize, unsigned char *OutputBuff, DWORD * dwBytes,DWORD * dwResponse, char * szECode);
    BOOL DoPASSCommand(const CHAR *InputLine, DWORD dwLineSize, unsigned char *OutputBuff, DWORD * dwBytes,DWORD * dwResponse, char * szECode);
    BOOL UseMbsCta() { return m_fUseMbsCta; }
    BOOL DoesClientHaveIpAccess();

    //Partially async WriteFile
    BOOL WriteMailFile (char * Buffer, DWORD BuffSize, BOOL *lpfWritePended);

    //Fully async WriteFile
    BOOL WriteMailFileAtq(char * Buffer, DWORD dwBytesToWrite,DWORD dwIoMode);
//    void FreeAtqFileContext( void );

    void ReleasImsg(BOOL DeleteIMsg);
    void ReleasRcptList(void);
    void GetAndPersistRFC822Headers( char* InputLine, char* pszValueBuf );
    HRESULT SetAvailableMailMsgProperties();
    char *IsLineCompleteRFC822(
                                IN char *InputLine,
                                IN DWORD nBytes,
                                IN DWORD UndecryptedTailSize,
                                OUT BOOL *p_FullBuffer
                            );  //gpulla

    BOOL HandleInternalError(DWORD err);
    HRESULT HrGetISessionProperties();
    BOOL AcceptAndDiscardBDAT(const char *InputLine, DWORD UndecryptedTailSize, BOOL *pfAsyncOp);
    BOOL AcceptAndDiscardDATA(const char *InputLine, DWORD UndecryptedTailSize, BOOL *pfAsyncOp);
    BOOL MailBodyErrorProcessing();

};

typedef BOOL (SMTP_CONNECTION::*PMFI)(const char * InputLine, DWORD InputLinseSize);
static PMFI SmtpDispatchTable[] = {
     #undef SmtpDef
     #define SmtpDef(Smtp) &SMTP_CONNECTION::Do##Smtp##Command,
     #include "smtpdef.h"
    // modified by andreik
    // &SMTP_CONNECTION::DoLASTCommand,
    NULL
     };

//SMTPSTATE operator++(SMTPSTATE &state)
//{return state = SMTPSTATE (state + 1);}

# endif

/************************ End of File ***********************/