--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/applayerprotocols/telnetengine/SRC/TELFSM.CPP Tue Feb 02 01:09:52 2010 +0200
@@ -0,0 +1,1681 @@
+// Copyright (c) 2003-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+// Telnet Protocol API
+// Supported RFC class implementations
+//
+//
+
+/**
+ @file
+*/
+
+#include "TELFSM.H"
+#include "TELDEBUG.H"
+
+// The option negotiation class
+// Independent of the option
+// All option classes contain one of these state machine classes
+
+TOptionFSM::TOptionFSM()
+/**
+Constructor
+Set up the defaults
+*/
+ {
+ Allowed = ENoOption;
+ Us = ENo;
+ UsQ = EEmpty;
+ Him = ENo;
+ HimQ = EEmpty;
+ }
+
+void TOptionFSM::Reset()
+/**
+Reset restores the state machine to default but leaves the permissions
+*/
+ {
+ Us = ENo;
+ UsQ = EEmpty;
+ Him = ENo;
+ HimQ = EEmpty;
+ }
+
+TInt32 TOptionFSM::Request(const TInt32 aRequest,TInt32& aAction,TInt32& aEvent)
+/**
+Implementation of RFC 1143 Q Method bidirectional Telnet option state machine
+Can be called from the client side (aRequest = EClientXX) or the line side (aRequest = EServerXX).
+
+errors are returned for illegal requests
+aEvent is set when an option transits to enabled or disabled
+aAction's are the Telnet defined DO, WILL, WONT, DONT
+*/
+ {
+ TInt32 Ret = EErrNone;
+ aAction = ENoAction;
+ aEvent = ENoEvent;
+
+ switch(aRequest)
+ {
+//
+ case EServerWill :
+ if(Him == ENo)
+ {
+ if(Allowed & EServerWill)
+ {
+ Him = EYes;
+ Ret = EErrNone;
+ aEvent = EServerEnabled;
+ aAction = ESendDo;
+ }
+ else
+ {
+ Ret = EErrNone;
+ aEvent = ENoEvent;
+ aAction = ESendDont;
+ }
+ }
+ else if(Him == EYes)
+ {
+ Ret = EErrNone;
+ aEvent = ENoEvent;
+ aAction = ENoAction;
+ }
+ else if(Him == EWantNo && HimQ == EEmpty)
+ {
+ Him = ENo;
+ Ret = EProtocolError;
+ aEvent = EServerDisabled;
+ aAction = ENoAction;
+ }
+ else if(Him == EWantNo && HimQ == EOpposite)
+ {
+ Him = EYes;
+ HimQ = EEmpty;
+ Ret = EProtocolError;
+ aEvent = EServerEnabled;
+ aAction = ENoAction;
+ }
+ else if(Him == EWantYes && HimQ == EEmpty)
+ {
+ Him = EYes;
+ Ret = EErrNone;
+ aEvent = EServerEnabled;
+ aAction = ENoAction;
+ }
+ else if(Him == EWantYes && HimQ == EOpposite)
+ {
+ Him = EWantNo;
+ HimQ = EEmpty;
+ Ret = EErrNone;
+ aEvent = ENoEvent;
+ aAction = ESendDont;
+ }
+ break;
+//
+ case EServerDo :
+ if(Us == ENo)
+ {
+ if(Allowed & EServerDo)
+ {
+ Us = EYes;
+ Ret = EErrNone;
+ aEvent = EClientEnabled;
+ aAction = ESendWill;
+ }
+ else
+ {
+ Ret = EErrNone;
+ aEvent = ENoEvent;
+ aAction = ESendWont;
+ }
+ }
+ else if(Us == EYes)
+ {
+ Ret = EErrNone;
+ aEvent = ENoEvent;
+ aAction = ENoAction;
+ }
+ else if(Us == EWantNo && UsQ == EEmpty)
+ {
+ Us = ENo;
+ Ret = EProtocolError;
+ aEvent = EClientDisabled;
+ aAction = ENoAction;
+ }
+ else if(Us == EWantNo && UsQ == EOpposite)
+ {
+ Us = EYes;
+ UsQ = EEmpty;
+ Ret = EProtocolError;
+ aEvent = EClientEnabled;
+ aAction = ENoAction;
+ }
+ else if(Us == EWantYes && UsQ == EEmpty)
+ {
+ Us = EYes;
+ Ret = EErrNone;
+ aEvent = EClientEnabled;
+ aAction = ENoAction;
+ }
+ else if(Us == EWantYes && UsQ == EOpposite)
+ {
+ Us = EWantNo;
+ UsQ = EEmpty;
+ Ret = EErrNone;
+ aEvent = ENoEvent;
+ aAction = ESendWont;
+ }
+ break;
+//
+
+ case EServerWont :
+ if(Him == ENo)
+ {
+ Ret = EErrNone;
+ aEvent = ENoEvent;
+ aAction = ENoAction;
+ }
+ else if(Him == EYes)
+ {
+ Him = ENo;
+ Ret = EErrNone;
+ aEvent = EServerDisabled;
+ aAction = ESendDont;
+ }
+ else if(Him == EWantNo && HimQ == EEmpty)
+ {
+ Him = ENo;
+ Ret = EErrNone;
+ aEvent = EServerDisabled;
+ aAction = ENoAction;
+ }
+ else if(Him == EWantNo && HimQ == EOpposite)
+ {
+ Him = EWantYes;
+ HimQ = ENone;
+ Ret = EErrNone;
+ aEvent = ENoEvent;
+ aAction = ESendDo;
+ }
+ else if(Him == EWantYes && HimQ == EEmpty)
+ {
+ Him = ENo;
+ Ret = EErrNone;
+ aEvent = EServerDisabled;
+ aAction = ENoAction;
+ }
+ else if(Him == EWantYes && HimQ == EOpposite)
+ {
+ Him = ENo;
+ HimQ = ENone;
+ Ret = EErrNone;
+ aEvent = EServerDisabled;
+ aAction = ENoAction;
+ }
+ break;
+//
+ case EServerDont :
+ if(Us == ENo)
+ {
+ Ret = EErrNone;
+ aEvent = ENoEvent;
+ aAction = ENoAction;
+ }
+ else if(Us == EYes)
+ {
+ Us = ENo;
+ Ret = EErrNone;
+ aEvent = EClientDisabled;
+ aAction = ESendWont;
+ }
+ else if(Us == EWantNo && UsQ == EEmpty)
+ {
+ Us = ENo;
+ Ret = EErrNone;
+ aEvent = EClientDisabled;
+ aAction = ENoAction;
+ }
+ else if(Us == EWantNo && UsQ == EOpposite)
+ {
+ Us = EWantYes;
+ UsQ = ENone;
+ Ret = EErrNone;
+ aEvent = ENoEvent;
+ aAction = ESendWill;
+ }
+ else if(Us == EWantYes && UsQ == EEmpty)
+ {
+ Us = ENo;
+ Ret = EErrNone;
+ aEvent = EClientDisabled;
+ aAction = ENoAction;
+ }
+ else if(Us == EWantYes && UsQ == EOpposite)
+ {
+ Us = ENo;
+ UsQ = ENone;
+ Ret = EErrNone;
+ aEvent = EClientDisabled;
+ aAction = ENoAction;
+ }
+ break;
+//
+ case EClientDo :
+ if(!(Allowed & EClientDo))
+ {
+ Ret = EPermissionsError;
+ aEvent = ENoEvent;
+ aAction = ENoAction;
+ }
+ else if(Him == ENo)
+ {
+ Him = EWantYes;
+ Ret = EErrNone;
+ aEvent = ENoEvent;
+ aAction = ESendDo;
+ }
+ else if(Him == EYes)
+ {
+ Ret = EProtocolError;
+ aEvent = ENoEvent;
+ aAction = ENoAction;
+ }
+ else if(Him == EWantNo && HimQ == EEmpty)
+ {
+ if(UsQ == EOpposite)
+ {
+ Ret = EErrNone;
+ HimQ = EOpposite;
+ }
+ else
+ Ret = EProtocolError;
+ aEvent = ENoEvent;
+ aAction = ENoAction;
+ }
+ else if(Him == EWantNo && HimQ == EOpposite)
+ {
+ Ret = EProtocolError;
+ aEvent = ENoEvent;
+ aAction = ENoAction;
+ }
+ else if(Him == EWantYes && HimQ == EEmpty)
+ {
+ Ret = EProtocolError;
+ aEvent = ENoEvent;
+ aAction = ENoAction;
+ }
+ else if(Him == EWantYes && HimQ == EOpposite)
+ {
+ HimQ = EEmpty;
+ Ret = EErrNone;
+ aEvent = ENoEvent;
+ aAction = ENoAction;
+ }
+ break;
+//
+ case EClientWill :
+ if(!(Allowed & EClientWill))
+ {
+ Ret = EPermissionsError;
+ aEvent = ENoEvent;
+ aAction = ENoAction;
+ }
+ else if(Us == ENo)
+ {
+ Us = EWantYes;
+ Ret = EErrNone;
+ aEvent = ENoEvent;
+ aAction = ESendWill;
+ }
+ else if(Us == EYes)
+ {
+ Ret = EProtocolError;
+ aEvent = ENoEvent;
+ aAction = ENoAction;
+ }
+ else if(Us == EWantNo && UsQ == EEmpty)
+ {
+ if(HimQ == EOpposite)
+ {
+ Ret = EErrNone;
+ UsQ = EOpposite;
+ }
+ else
+ Ret = EProtocolError;
+ aEvent = ENoEvent;
+ aAction = ENoAction;
+ }
+ else if(Us == EWantNo && UsQ == EOpposite)
+ {
+ Ret = EProtocolError;
+ aEvent = ENoEvent;
+ aAction = ENoAction;
+ }
+ else if(Us == EWantYes && UsQ == EEmpty)
+ {
+ Ret = EProtocolError;
+ aEvent = ENoEvent;
+ aAction = ENoAction;
+ }
+ else if(Us == EWantYes && UsQ == EOpposite)
+ {
+ UsQ = EEmpty;
+ Ret = EErrNone;
+ aEvent = ENoEvent;
+ aAction = ENoAction;
+ }
+ break;
+//
+ case EClientDont :
+ if(Him == ENo)
+ {
+ Ret = EProtocolError;
+ aEvent = ENoEvent;
+ aAction = ENoAction;
+ }
+ else if(Him == EYes)
+ {
+ Him = EWantNo;
+ Ret = EErrNone;
+ aEvent = ENoEvent;
+ aAction = ESendDont;
+ }
+ else if(Him == EWantNo && HimQ == EEmpty)
+ {
+ Ret = EProtocolError;
+ aEvent = ENoEvent;
+ aAction = ENoAction;
+ }
+ else if(Him == EWantNo && HimQ == EOpposite)
+ {
+ HimQ = EEmpty;
+ Ret = EErrNone;
+ aEvent = ENoEvent;
+ aAction = ENoAction;
+ }
+ else if(Him == EWantYes && HimQ == EEmpty)
+ {
+ if(UsQ == EOpposite)
+ {
+ HimQ = EOpposite;
+ Ret = EErrNone;
+ }
+ else
+ Ret = EProtocolError;
+ aEvent = ENoEvent;
+ aAction = ENoAction;
+ }
+ else if(Him == EWantYes && HimQ == EOpposite)
+ {
+ Ret = EProtocolError;
+ aEvent = ENoEvent;
+ aAction = ENoAction;
+ }
+ break;
+//
+ case EClientWont :
+ if(Us == ENo)
+ {
+ Ret = EProtocolError;
+ aEvent = ENoEvent;
+ aAction = ENoAction;
+ }
+ else if(Us == EYes)
+ {
+ Us = EWantNo;
+ Ret = EErrNone;
+ aEvent = ENoEvent;
+ aAction = ESendWont;
+ }
+ else if(Us == EWantNo && UsQ == EEmpty)
+ {
+ Ret = EProtocolError;
+ aEvent = ENoEvent;
+ aAction = ENoAction;
+ }
+ else if(Us == EWantNo && UsQ == EOpposite)
+ {
+ UsQ = EEmpty;
+ Ret = EErrNone;
+ aEvent = ENoEvent;
+ aAction = ENoAction;
+ }
+ else if(Us == EWantYes && UsQ == EEmpty)
+ {
+ if(HimQ == EOpposite)
+ {
+ UsQ = EOpposite;
+ Ret = EErrNone;
+ }
+ else
+ Ret = EProtocolError;
+
+ aEvent = ENoEvent;
+ aAction = ENoAction;
+ }
+ else if(Us == EWantYes && UsQ == EOpposite)
+ {
+ Ret = EProtocolError;
+ aEvent = ENoEvent;
+ aAction = ENoAction;
+ }
+ break;
+
+ default :
+ break;
+
+
+ }
+ return(Ret);
+ }
+
+// The base class for all RFC option classes
+
+CRFCOptionBase::~CRFCOptionBase()
+/**
+Destructor
+*/
+ {
+ __FLOG_STATIC(KTelnetLoggingCompnt(),KTelnetLoggingTag(),_L("CRFCOptionBase::D'Tor"));
+ }
+
+void CRFCOptionBase::CreateOptionResponse(TInt8 aOption,TInt32 aAction,TDes8& aBuffer)
+/**
+Create a Telnet protocol request or response
+*/
+ {
+ aBuffer.Append(KTelnetIAC);
+
+ // MAP our local codes to the genuine telnet ones
+ if(aAction == TOptionFSM::ESendWill)
+ aBuffer.Append(KTelnetWILL);
+ else if(aAction == TOptionFSM::ESendDo)
+ aBuffer.Append(KTelnetDO);
+ else if(aAction == TOptionFSM::ESendDont)
+ aBuffer.Append(KTelnetDONT);
+ else if(aAction == TOptionFSM::ESendWont)
+ aBuffer.Append(KTelnetWONT);
+
+ aBuffer.Append(aOption);
+ };
+
+
+void CUnknownOption::RequestUnknown(TInt8 aOption,const TInt32 aRequest, TDes8& aAction,TInt32& aEvent)
+/**
+For tidy code we keep a class that handles unknown option requests from the server.
+The result of a call into this object will always be WONT or DONT
+*/
+ {
+ TInt32 action;
+ iFSM.Request(aRequest,action,aEvent);
+ if(action != TOptionFSM::ENoAction)
+ CRFCOptionBase::CreateOptionResponse(aOption,action,aAction);
+ }
+
+CUnknownOption* CUnknownOption::NewL()
+ {
+ CUnknownOption* self = new(ELeave) CUnknownOption;
+ CleanupStack::PushL(self);
+ self->ConstructL();
+ CleanupStack::Pop();
+ return self;
+ }
+
+void CUnknownOption::ConstructL()
+ {
+ }
+
+CUnknownOption::~CUnknownOption()
+/**
+Destructor
+*/
+ {
+ __FLOG_STATIC(KTelnetLoggingCompnt(),KTelnetLoggingTag(),_L("CUnknownOption::D'Tor"));
+ }
+
+CSuppressGAOption* CSuppressGAOption::NewL()
+ {
+ CSuppressGAOption* self = new(ELeave) CSuppressGAOption;
+ CleanupStack::PushL(self);
+ self->ConstructL();
+ CleanupStack::Pop();
+ return self;
+ }
+
+TInt32 CSuppressGAOption::RequestOption(const TInt32 aRequest, TDes8& aAction,TInt32& aEvent)
+/**
+Virtual overide
+Should always be a request for DO or WILL as we always suppress the Go Ahead signal
+*/
+ {
+ TInt32 action;
+
+ iFSM.Request(aRequest,action,aEvent);
+ if(action != TOptionFSM::ENoAction)
+ CreateOptionResponse(KTelnetProtOptionSuppressGA,action,aAction);
+ return(KErrNone);
+ }
+
+void CSuppressGAOption::ConstructL()
+ {
+ }
+
+void CSuppressGAOption::GetTelnetOptionStatus(TDes8& aCurrentStatus)
+/**
+Virtual overide
+Returns a Telnet Protocol option status , see RFC 859
+*/
+ {
+ if(iFSM.ClientEnabled())
+ {
+ aCurrentStatus.Append(KTelnetDO);
+ aCurrentStatus.Append(KTelnetProtOptionSuppressGA);
+ }
+ }
+
+
+CStatusOption* CStatusOption::NewL()
+ {
+ CStatusOption* self = new(ELeave) CStatusOption;
+ CleanupStack::PushL(self);
+ self->ConstructL();
+ CleanupStack::Pop();
+ return self;
+ }
+
+TInt32 CStatusOption::RequestOption(const TInt32 aRequest, TDes8& aAction,TInt32& aEvent)
+/**
+Virtual overide
+*/
+ {
+ TInt32 action;
+
+ iFSM.Request(aRequest,action,aEvent);
+ if(action != TOptionFSM::ENoAction)
+ CreateOptionResponse(KTelnetProtOptionStatus,action,aAction);
+
+ return(KErrNone);
+ }
+
+void CStatusOption::ConstructL()
+ {
+ }
+
+void CStatusOption::GetTelnetOptionStatus(TDes8& aCurrentStatus)
+/**
+Virtual overide
+Returns a Telnet Protocol option status , see RFC 859
+*/
+ {
+ if(iFSM.ClientEnabled())
+ {
+ aCurrentStatus.Append(KTelnetWILL);
+ aCurrentStatus.Append(KTelnetProtOptionStatus);
+ }
+ if(iFSM.ServerEnabled())
+ {
+ aCurrentStatus.Append(KTelnetDO);
+ aCurrentStatus.Append(KTelnetProtOptionStatus);
+ }
+ }
+
+CSpeedOption* CSpeedOption::NewL()
+ {
+ CSpeedOption* self = new(ELeave) CSpeedOption;
+ CleanupStack::PushL(self);
+ self->ConstructL();
+ CleanupStack::Pop();
+ return self;
+ }
+
+TInt32 CSpeedOption::RequestOption(const TInt32 aRequest, TDes8& aAction,TInt32& aEvent)
+/**
+Virtual overide
+*/
+ {
+ TInt32 action;
+ TInt32 err;
+ err = iFSM.Request(aRequest,action,aEvent);
+ if(action != TOptionFSM::ENoAction)
+ CreateOptionResponse(KTelnetProtOptionTerminalSpeed,action,aAction);
+ return(err);
+ }
+
+void CSpeedOption::GetTelnetSubOption(TDes8& aOutBuffer)
+/**
+Creates the sub option for telling the server our speed
+*/
+ {
+ aOutBuffer.Append(KTelnetIAC); // Interpret As Command
+ aOutBuffer.Append(KTelnetSB); // Suboption start
+ aOutBuffer.Append(KTelnetProtOptionTerminalSpeed); //Terminal Speed
+ aOutBuffer.Append(KTelnetCommandIS); // IS
+
+ aOutBuffer.Append(iTermSpeed); // Receive Speed
+ aOutBuffer.Append(',');
+ aOutBuffer.Append(iTermSpeed); // Send Speed
+
+ aOutBuffer.Append(KTelnetIAC); // Interpret As Command
+ aOutBuffer.Append(KTelnetSE); // Suboption End
+ }
+
+void CSpeedOption::ConstructL()
+ {
+ iTermSpeed = _L8("38400");
+ }
+
+void CSpeedOption::GetTelnetOptionStatus(TDes8& aCurrentStatus)
+/**
+Virtual overide
+Returns a Telnet Protocol option status , see RFC 859
+*/
+ {
+ if(iFSM.ClientEnabled())
+ {
+ aCurrentStatus.Append(KTelnetWILL);
+ aCurrentStatus.Append(KTelnetProtOptionTerminalSpeed);
+ }
+ }
+
+TBool CSpeedOption::Set(const TDesC8& aSpeed)
+/**
+Sets the speed option, return TRUE if it's altered
+*/
+ {
+ TBool ret;
+ (iTermSpeed == aSpeed) ? (ret = FALSE) : (ret = TRUE);
+ iTermSpeed = aSpeed;
+ return ret;
+ }
+
+CLogoutOption* CLogoutOption::NewL()
+ {
+ CLogoutOption* self = new(ELeave) CLogoutOption;
+ CleanupStack::PushL(self);
+ self->ConstructL();
+ CleanupStack::Pop();
+ return self;
+ }
+
+TInt32 CLogoutOption::RequestOption(const TInt32 aRequest, TDes8& aAction,TInt32& aEvent)
+/**
+Virtual overide
+*/
+ {
+ TInt32 action;
+ TInt32 err;
+ err = iFSM.Request(aRequest,action,aEvent);
+ if(action != TOptionFSM::ENoAction)
+ CreateOptionResponse(KTelnetProtOptionLogoff,action,aAction);
+ return(err);
+ }
+
+void CLogoutOption::ConstructL()
+ {
+ }
+
+void CLogoutOption::GetTelnetOptionStatus(TDes8& aCurrentStatus)
+/**
+I don't think this method is relevant for status reporting but for consistency and is
+never called to report it's status.
+*/
+ {
+ if(iFSM.ServerEnabled())
+ {
+ aCurrentStatus.Append(KTelnetDO);
+ aCurrentStatus.Append(KTelnetProtOptionLogoff);
+ }
+ }
+
+CTerminalTypeOption* CTerminalTypeOption::NewL()
+ {
+ CTerminalTypeOption* self = new(ELeave) CTerminalTypeOption;
+ CleanupStack::PushL(self);
+ self->ConstructL();
+ CleanupStack::Pop();
+ return self;
+ }
+
+TInt32 CTerminalTypeOption::RequestOption(const TInt32 aRequest, TDes8& aAction,TInt32& aEvent)
+/**
+Virtual overide
+*/
+ {
+ TInt32 action;
+ TInt32 err;
+ err = iFSM.Request(aRequest,action,aEvent);
+ if(action != TOptionFSM::ENoAction)
+ CreateOptionResponse(KTelnetProtOptionTerminalType,action,aAction);
+ return(err);
+ }
+
+void CTerminalTypeOption::ConstructL()
+ {
+ iTermType = _L8("dumb");
+ }
+
+void CTerminalTypeOption::GetTelnetSubOption(TDes8& aOutBuffer)
+ {
+ aOutBuffer.Append(KTelnetIAC); // Interpret As Command
+ aOutBuffer.Append(KTelnetSB); // Suboption Start
+ aOutBuffer.Append(KTelnetProtOptionTerminalType); // Terminal Type
+ aOutBuffer.Append(KTelnetCommandIS); // IS
+ aOutBuffer.Append(iTermType); // Terminal Type eg "dumb"
+ aOutBuffer.Append(KTelnetIAC);// Interpret As Command
+ aOutBuffer.Append(KTelnetSE); // Suboption End
+ }
+
+void CTerminalTypeOption::GetTelnetOptionStatus(TDes8& aCurrentStatus)
+/**
+Virtual overide
+Returns a Telnet Protocol option status , see RFC 859
+*/
+ {
+ if(iFSM.ClientEnabled())
+ {
+ aCurrentStatus.Append(KTelnetWILL);
+ aCurrentStatus.Append(KTelnetProtOptionTerminalType);
+ }
+ }
+
+TBool CTerminalTypeOption::Set(const TDesC8& aType)
+/**
+Sets the terminal type, returns TRUE if the type has altered
+*/
+ {
+ TBool ret;
+ (aType == iTermType) ? (ret = FALSE) : (ret = TRUE);
+ iTermType = aType;
+ return ret;
+ }
+
+CWindowSizeOption* CWindowSizeOption::NewL()
+ {
+ CWindowSizeOption* self = new(ELeave) CWindowSizeOption;
+ CleanupStack::PushL(self);
+ self->ConstructL();
+ CleanupStack::Pop();
+ return self;
+ }
+
+TInt32 CWindowSizeOption::RequestOption(const TInt32 aRequest, TDes8& aAction,TInt32& aEvent)
+ {
+ TInt32 action;
+ TInt32 err;
+ err = iFSM.Request(aRequest,action,aEvent);
+ if(action != TOptionFSM::ENoAction)
+ CreateOptionResponse(KTelnetProtOptionWindowSize,action,aAction);
+ return(err);
+ }
+
+void CWindowSizeOption::ConstructL()
+ {
+ iWindowSize.x = 80;
+ iWindowSize.y = 24;
+ }
+
+TBool CWindowSizeOption::Set(const TTelnetConfig::TWindowSize& aSize)
+/**
+Sets the window size, returns TRUE if it's altered
+*/
+ {
+ TBool ret;
+ (iWindowSize.x == aSize.x && iWindowSize.y == aSize.y) ? (ret = FALSE) : (ret = TRUE);
+ iWindowSize.x = aSize.x;
+ iWindowSize.y = aSize.y;
+ return ret;
+ }
+
+void CWindowSizeOption::GetTelnetSubOption(TDes8& aOutBuffer)
+/**
+Creates the window size suboption in short's
+Make sure we escape any Interpret As Command 255's (unlikely to occur)
+*/
+ {
+ aOutBuffer.Append(KTelnetIAC); // Interpret As Command
+ aOutBuffer.Append(KTelnetSB); // Suboption Start
+ aOutBuffer.Append(KTelnetProtOptionWindowSize); // Window Size (NAWS)
+
+ TUint8 nibble;
+
+ nibble = (TUint8)(iWindowSize.x >> 8); // High Byte of x
+ aOutBuffer.Append(nibble);
+ if(nibble == KTelnetIAC) // Escape check
+ aOutBuffer.Append(KTelnetIAC);
+ nibble = (TUint8)iWindowSize.x; // Low byte of x
+ aOutBuffer.Append(nibble);
+ if(nibble == KTelnetIAC) // Escape check
+ aOutBuffer.Append(KTelnetIAC);
+
+ nibble = (TUint8)(iWindowSize.y >> 8); // High byte of y
+ aOutBuffer.Append(nibble);
+ if(nibble == KTelnetIAC) // Escape check
+ aOutBuffer.Append(KTelnetIAC);
+ nibble = (TUint8)iWindowSize.y; // Low byte of y
+ aOutBuffer.Append(nibble);
+ if(nibble == KTelnetIAC) // Escape check
+ aOutBuffer.Append(KTelnetIAC);
+
+ aOutBuffer.Append(KTelnetIAC); // Interpret As Command
+ aOutBuffer.Append(KTelnetSE); // Suboption End
+ }
+
+void CWindowSizeOption::GetTelnetOptionStatus(TDes8& aCurrentStatus)
+/**
+Virtual overide
+Returns a Telnet Protocol option status , see RFC 859
+*/
+ {
+ if(iFSM.ClientEnabled())
+ {
+ aCurrentStatus.Append(KTelnetWILL);
+ aCurrentStatus.Append(KTelnetProtOptionWindowSize);
+ }
+ }
+
+
+CEchoOption* CEchoOption::NewL()
+ {
+ CEchoOption* self = new(ELeave) CEchoOption;
+ CleanupStack::PushL(self);
+ self->ConstructL();
+ CleanupStack::Pop();
+ return self;
+ }
+
+TInt32 CEchoOption::RequestOption(const TInt32 aRequest,TDes8& aAction,TInt32& aEvent)
+ {
+ TInt32 action;
+ TInt32 err;
+ err = iFSM.Request(aRequest,action,aEvent);
+ if(action != TOptionFSM::ENoAction)
+ CreateOptionResponse(KTelnetProtOptionEcho,action,aAction);
+ return(err);
+ }
+
+void CEchoOption::ConstructL()
+ {
+ }
+
+void CEchoOption::GetTelnetOptionStatus(TDes8& aCurrentStatus)
+/**
+Virtual overide
+Returns a Telnet Protocol option status , see RFC 859
+*/
+ {
+ if(iFSM.ClientEnabled())
+ {
+ aCurrentStatus.Append(KTelnetWILL);
+ aCurrentStatus.Append(KTelnetProtOptionEcho);
+ }
+ }
+
+
+CBinaryOption* CBinaryOption::NewL()
+ {
+ CBinaryOption* self = new(ELeave) CBinaryOption;
+ CleanupStack::PushL(self);
+ self->ConstructL();
+ CleanupStack::Pop();
+ return self;
+ }
+
+TInt32 CBinaryOption::RequestOption(const TInt32 aRequest,TDes8& aAction,TInt32& aEvent)
+ {
+ TInt32 action;
+ TInt32 err;
+
+ err = iFSM.Request(aRequest,action,aEvent);
+ if(action != TOptionFSM::ENoAction)
+ CreateOptionResponse(KTelnetProtOptionBinary,action,aAction);
+ return(err);
+ }
+
+void CBinaryOption::ConstructL()
+ {
+ }
+
+void CBinaryOption::GetTelnetOptionStatus(TDes8& aCurrentStatus)
+/**
+Virtual overide
+Returns a Telnet Protocol option status , see RFC 859
+*/
+ {
+ if(iFSM.ClientEnabled())
+ {
+ aCurrentStatus.Append(KTelnetWILL);
+ aCurrentStatus.Append(KTelnetProtOptionBinary);
+ }
+ }
+
+CProto* CProto::NewL(const TTelnetConfig& aConfig,MProtoEvent* aNotifier)
+ {
+ CProto* self = new(ELeave) CProto;
+ CleanupStack::PushL(self);
+ self->ConstructL(aConfig,aNotifier);
+ CleanupStack::Pop();
+ return self;
+ }
+
+void CProto::ConstructL(const TTelnetConfig& aConfig,MProtoEvent* aNotifier)
+/**
+Initialises the protocol object and creates the RFC objects
+*/
+ {
+ iNotifier = aNotifier;
+
+ iReceiveState = ENormal;
+ iUrgentFlag = FALSE;
+
+ iBinary = CBinaryOption::NewL();
+ iEcho = CEchoOption::NewL();
+ iWindowSize = CWindowSizeOption::NewL();
+ iTerminalType = CTerminalTypeOption::NewL();
+ iLogout = CLogoutOption::NewL();
+ iSpeed = CSpeedOption::NewL();
+ iGA = CSuppressGAOption::NewL();
+ iStatus = CStatusOption::NewL();
+ iUnknown = CUnknownOption::NewL();
+
+ // Set the permitted requests for all the RFC objects
+ // Logout permissions are set from the aConfig
+ // Echo permissions are set from aConfig
+ iWindowSize->SetRequestPermission
+ (
+ TOptionFSM::EServerDo | TOptionFSM::EClientWill
+ );
+
+ iStatus->SetRequestPermission
+ (
+ TOptionFSM::EServerWill | TOptionFSM::EClientDo |
+ TOptionFSM::EClientWill | TOptionFSM::EServerDo
+ );
+
+ iSpeed->SetRequestPermission
+ (
+ TOptionFSM::EServerDo | TOptionFSM::EClientWill
+ );
+
+ iTerminalType->SetRequestPermission
+ (
+ TOptionFSM::EServerDo | TOptionFSM::EClientWill
+ );
+
+ iBinary->SetRequestPermission
+ (
+ TOptionFSM::EClientDo | TOptionFSM::EServerWill |
+ TOptionFSM::EServerDo | TOptionFSM::EClientWill
+ );
+
+ iGA->SetRequestPermission
+ (
+ TOptionFSM::EClientDo | TOptionFSM::EServerWill |
+ TOptionFSM::EServerDo | TOptionFSM::EClientWill
+ );
+ // NULL means we don't want a protocol string returned to send to the server
+ ModifyConfig(aConfig,NULL);
+ }
+
+void CProto::ReceiveUrgent(TInt aUrgentData)
+/**
+We've received an urgent notification
+aUrgent will be the urgent data byte, currently we're not interested in what it is
+*/
+ {
+ iUrgentFlag = TRUE;
+ iUrgentData = aUrgentData;
+ }
+
+void CProto::GetOptionStatus(TDes8& aOutBuffer)\
+/**
+Called when the server wants to know our perceived state of the Telnet option RFC's
+RFC member methods add WILL/DO KTelnetProtOptionXXXX, if its currently enabled for the client
+*/
+ {
+ aOutBuffer.Append(KTelnetIAC); // Interpret As Command
+ aOutBuffer.Append(KTelnetSB); // Suboption Start
+ aOutBuffer.Append(KTelnetProtOptionStatus); // KTelnetProtOptionStatus
+ aOutBuffer.Append(KTelnetCommandIS); // IS
+
+ iBinary->GetTelnetOptionStatus(aOutBuffer); // ? WILL Binary
+ iWindowSize->GetTelnetOptionStatus(aOutBuffer); // ? WILL NAWS
+ iTerminalType->GetTelnetOptionStatus(aOutBuffer); // ? WILL Terminal Type
+ iSpeed->GetTelnetOptionStatus(aOutBuffer); // ? WILL Terminal Speed
+ iGA->GetTelnetOptionStatus(aOutBuffer); // ? DO Suppress Go Ahead
+ iStatus->GetTelnetOptionStatus(aOutBuffer); // ? WILL and/or DO Status
+
+ aOutBuffer.Append(KTelnetIAC); // Interpret As Command
+ aOutBuffer.Append(KTelnetSE); // Suboption End
+ }
+
+void CProto::OptionStatus(TOptionStatus& aStatus)
+/**
+Client has requested the state of the RFC options
+*/
+ {
+ (iBinary->ReceiveBinary() == TRUE) ? (aStatus.iServerBinary = TRUE) : (aStatus.iServerBinary = FALSE);
+ (iBinary->SendBinary() == TRUE) ? (aStatus.iClientBinary = TRUE) : (aStatus.iClientBinary = FALSE);
+ (iEcho->ReceiveEcho() == TRUE) ? (aStatus.iEcho = TRUE) : (aStatus.iEcho = FALSE);
+ (iWindowSize->SendWindowSize()) ? (aStatus.iNAWS = TRUE) : (aStatus.iNAWS = FALSE);
+ (iSpeed->SendSpeed() == TRUE) ? (aStatus.iTerminalSpeed = TRUE) : (aStatus.iTerminalSpeed = FALSE);
+ (iTerminalType->SendTerminalType() == TRUE) ? (aStatus.iTerminalType = TRUE) : (aStatus.iTerminalType = FALSE);
+ (iStatus->ReceiveStatus() == TRUE) ? (aStatus.iServerStatus = TRUE) : (aStatus.iServerStatus = FALSE);
+ (iStatus->SendStatus() == TRUE) ? (aStatus.iClientStatus = TRUE) : (aStatus.iClientStatus = FALSE);
+ }
+
+void CProto::ServerOptionStatus(TDes8& aActionBuffer)
+ {
+ if(iStatus->ReceiveStatus())
+ {
+ aActionBuffer.Append(KTelnetIAC); // Interpret As Command
+ aActionBuffer.Append(KTelnetSB); // Suboption Start
+ aActionBuffer.Append(KTelnetProtOptionStatus);// Status
+ aActionBuffer.Append(KTelnetCommandSEND); // Send
+ aActionBuffer.Append(KTelnetIAC); // Interpret As Command
+ aActionBuffer.Append(KTelnetSE); // Suboption End
+ }
+ }
+
+void CProto::GetInitOptions(TDes8& aActionBuffer)
+/**
+Should be called following connection
+Place here any calls to enable options at connection time
+*/
+ {
+ TInt32 event;
+ // Switch on binary if the terminal is not "dumb"
+ if(iTerminalType->TerminalType() != _L8("dumb"))
+ ClientRequestOption(KTelnetProtOptionBinary,aActionBuffer,event);
+ // Always suppress the Go Ahead signal
+ ClientRequestOption(KTelnetProtOptionSuppressGA,aActionBuffer,event);
+ }
+
+
+void CProto::ModifyConfig(const TTelnetConfig& aConfig,TDes8 * aActionBuffer)
+/**
+Modify the configurable options
+aActionBuffer is set to NULL if the caller does not want to notify the server of option changes
+*/
+ {
+ // If the speed has changed
+ if(iSpeed->Set(aConfig.iTermSpeed))
+ {
+ // If speed option is not enabled and caller wants to notify server
+ if(!iSpeed->SendSpeed() && aActionBuffer)
+ {
+ TInt32 event;
+ // If caller wants to notify server
+ // Switch the option on
+ ClientRequestOption(KTelnetProtOptionTerminalSpeed,*aActionBuffer,event);
+ }
+ }
+ // Terminal Type
+ // We don't currently support lists of terminal types.
+ // All telnet servers request the terminal type first thing so, just modify the terminal type
+ // If the connection is up, then the client will have to close the connection
+ iTerminalType->Set(aConfig.iTermType);
+ // NAWS
+ // If window size has changed
+ if(iWindowSize->Set(aConfig.iWindowSize))
+ {
+ // If NAWS is not enabled and the user wants to notify the server
+ if(!iWindowSize->SendWindowSize() && aActionBuffer)
+ {
+ TInt32 event;
+ // Switch on NAWS
+ ClientRequestOption(KTelnetProtOptionWindowSize,*aActionBuffer,event);
+ }
+ else
+ // Window size is already enabled
+ // If the caller wants to notify the server
+ if(aActionBuffer)
+ // return IAC SB NAWS IS X Y IAC SE
+ iWindowSize->GetTelnetSubOption(*aActionBuffer);
+ }
+
+ // Enable/disable server logout is a passive set action
+ // If the Client wants to force a Telnet defined logout then it should call DoForceLogout()
+ if(aConfig.iAllowLogout)
+ iLogout->SetRequestPermission
+ (
+ TOptionFSM::EServerWill | TOptionFSM::EClientDo
+ );
+ else
+ iLogout->SetRequestPermission
+ (
+ TOptionFSM::ENoOption
+ );
+ // Echo
+ // First set the permissions for the Server depending on the member boolean
+ if(aConfig.iServerEcho)
+ iEcho->SetRequestPermission(TOptionFSM::EServerWill | TOptionFSM::EClientDo);
+ else
+ iEcho->SetRequestPermission(TOptionFSM::ENoOption);
+
+ // Echo is a "toggler"
+ // If we are required to supply an action and the client wants to change the echo state
+ if(aActionBuffer && iEcho->ReceiveEcho() != aConfig.iServerEcho)
+ {
+ TInt32 event;
+ // Call the routine to create the request as the client is attempting to toggle
+ // Server echo
+ ClientRequestOption(KTelnetProtOptionEcho,*aActionBuffer,event);
+ }
+ }
+
+
+TInt CProto::ClientRequestOption(TInt32 aOptionRequest,TDes8& aAction,TInt32& aEvent)
+/**
+Creates client side option requests
+Currently we only switch on options
+Ignore the errors as we can pre-check the state of the option before we call this.
+*/
+ {
+ TInt32 err = KErrNone;
+ TInt32 event;
+ TBuf8<10> action;
+
+ aEvent = TOptionFSM::ENoEvent;
+
+ // If binary
+ if(aOptionRequest == KTelnetProtOptionBinary)
+ {
+ // Request the server to transmit in Binary
+ err = iBinary->RequestOption(TOptionFSM::EClientDo,action,event);
+ aEvent |= event;
+ aAction.Append(action);
+
+ // Tell the server we are prepared to transmit in binary
+ action.SetLength(0);
+ err = iBinary->RequestOption(TOptionFSM::EClientWill,action,event);
+ aEvent |= event;
+ aAction.Append(action);
+ }
+ else if(aOptionRequest == KTelnetProtOptionSuppressGA)
+ {
+ // Request the server to suppress the go ahead signal
+ err = iGA->RequestOption(TOptionFSM::EClientDo,action,event);
+ aEvent |= event;
+ aAction.Append(action);
+
+ // Tell the server we are prepared to suppress the go ahead signal
+ action.SetLength(0);
+ err = iGA->RequestOption(TOptionFSM::EClientWill,action,event);
+ aEvent |= event;
+ aAction.Append(action);
+ }
+ else if(aOptionRequest == KTelnetProtOptionStatus)
+ {
+ // Tell the server we are prepared to send status information
+ err = iStatus->RequestOption(TOptionFSM::EClientWill,action,event);
+ aEvent = event;
+ aAction.Append(action);
+ }
+ else if(aOptionRequest == KTelnetProtOptionLogoff)
+ {
+ // Client is forcing a logout
+ iLogout->SetRequestPermission
+ (
+ TOptionFSM::EServerWill | TOptionFSM::EClientDo
+ );
+ err = iLogout->RequestOption(TOptionFSM::EClientDo,action,event);
+ aEvent = event;
+ aAction.Append(action);
+ }
+ else if(aOptionRequest == KTelnetProtOptionWindowSize)
+ {
+ // Tell the Server we are prepared to send window size information
+ err = iWindowSize->RequestOption(TOptionFSM::EClientWill,action,event);
+ aEvent = event;
+ aAction.Append(action);
+ }
+ else if(aOptionRequest == KTelnetProtOptionTerminalType)
+ {
+ // Tell the server we are prepared to send terminal type information
+ err = iTerminalType->RequestOption(TOptionFSM::EClientWill,action,event);
+ aEvent = event;
+ aAction.Append(action);
+ }
+ else if(aOptionRequest == KTelnetProtOptionTerminalSpeed)
+ {
+ // Tell the server we are prepared to send terminal speed information
+ err = iSpeed->RequestOption(TOptionFSM::EClientWill,action,event);
+ aEvent = event;
+ aAction.Append(action);
+ }
+ else if(aOptionRequest == KTelnetProtOptionEcho)
+ {
+ // Echo is a special case where we toggle
+ if(iEcho->ReceiveEcho())
+ // Server Echo is currently enabled on so tell server DONT
+ err = iEcho->RequestOption(TOptionFSM::EClientDont,action,event);
+ else
+ // Server Echo is currently disabled so tell server DO
+ err = iEcho->RequestOption(TOptionFSM::EClientDo,action,event);
+ aEvent = event;
+ aAction.Append(action);
+ }
+
+
+ return(err);
+ }
+
+TInt CProto::ProtoWrite(const TDesC8& aInBuffer,TDes8& aOutBuffer)
+/**
+Modifies the output stream :-
+Escape EIAC in Binary mode.
+PAD CR to CR NULL when not in binary mode
+*/
+ {
+ if(iBinary->SendBinary())
+ {
+ for(TInt i=0;i<aInBuffer.Length();i++)
+ {
+ if(aInBuffer[i] == KTelnetIAC)
+ aOutBuffer.Append(KTelnetIAC);
+ aOutBuffer.Append(aInBuffer[i]);
+ }
+ }
+ else
+ {
+ for(TInt i=0;i<aInBuffer.Length();i++)
+ {
+ aOutBuffer.Append(aInBuffer[i]);
+ if(aInBuffer[i] == KTelnetCR && (i == (aInBuffer.Length() - 1) || aInBuffer[i+1] != KTelnetLF))
+ {
+ aOutBuffer.Append(KTelnetNULL);
+ }
+ }
+ }
+ return(KErrNone);
+ }
+
+TInt CProto::ProtoWrite(const TTelnetUserControl& aControlCode,TDes8& aBuffer,TDes8& aUrgentBuffer)
+/**
+Writes a Telnet 854 defined control code to the server
+In the case of an Interrupt Process we need to send urgent data
+*/
+ {
+ TInt err;
+ if(aControlCode == KTelnetIP)
+ // Interrupt Process, supported in Binary and NVT mode
+ {
+ aUrgentBuffer.Append(KTelnetIAC); // Interpret As Command *** URGENT ***
+ aUrgentBuffer.Append(KTelnetIP); // Interrupt Process *** URGENT ***
+ aUrgentBuffer.Append(KTelnetIAC); // Interpret As Command *** URGENT ***
+ aBuffer.Append(KTelnetDM); // Data Mark
+ err = KErrNone;
+ }
+ else
+ {
+ // All codes valid when not in binary
+ if(!iBinary->SendBinary())
+ {
+ __FLOG_STATIC1(KTelnetLoggingCompnt(),KTelnetLoggingTag(),_L("CProto::ProtoWrite() Normal Send Control = %d"),aControlCode);
+ aBuffer.Append(KTelnetIAC); // Interpret As Command
+ aBuffer.Append((TInt8)aControlCode); // Code
+ err = KErrNone;
+ }
+ else if(aControlCode == KTelnetAYT || aControlCode == KTelnetAO)
+ // In binary Are You There and Abort Output only
+ {
+ __FLOG_STATIC1(KTelnetLoggingCompnt(),KTelnetLoggingTag(),_L("CProto::ProtoWrite() Binary Send Control = %d"),aControlCode);
+ aBuffer.Append(KTelnetIAC); // Interpret As Command
+ aBuffer.Append((TInt8)aControlCode); // Code
+ err = KErrNone;
+ }
+ else
+ {
+ err = KErrGeneral;
+ __FLOG_STATIC(KTelnetLoggingCompnt(),KTelnetLoggingTag(),_L("CProto::ProtoWrite() ERROR Illegal Code in Binary"));
+ }
+ }
+ return(err);
+ }
+
+
+TInt CProto::ProtoRead(const TDesC8& aInBuffer,TDes8& aClientOutBuffer,TDes8& aProtoOutBuffer)
+/**
+Process data received from the Telnet Server
+Contains receive state machine plus sub-state machine for suboptions
+*/
+ {
+// TBuf8<64> action;
+ TBuf8<128> subOptions;
+ TInt32 numEvents = 0;
+ // Loop through the input buffer byte by byte
+ for(TInt i=0;i<aInBuffer.Length();i++)
+ {
+ switch(iReceiveState)
+ {
+ case ENormal :
+ // Check for Interpret as command
+ if(aInBuffer[i] == KTelnetIAC)
+ {
+ // Reset the object protocol receive buffer
+ iProtReadBuffer.SetLength(0);
+ // Set the state
+ iReceiveState = EIAC;
+ __FLOG_STATIC(KTelnetLoggingCompnt(),KTelnetLoggingTag(),_L("CProto::ProtoRead() IAC"));
+ }
+ // Check for first character of a RFC 854 Sync
+ else if(aInBuffer[i] == KTelnetIP)
+ {
+ __FLOG_STATIC(KTelnetLoggingCompnt(),KTelnetLoggingTag(),_L("CProto::ProtoRead() IP"));
+ }
+ // Check for Data Mark that follows Sync and ends urgent processing
+ else if(aInBuffer[i] == KTelnetDM && iUrgentFlag)
+ {
+ iUrgentFlag = FALSE;
+ __FLOG_STATIC(KTelnetLoggingCompnt(),KTelnetLoggingTag(),_L("CProto::ProtoRead() DM"));
+ }
+ // Check we are not discarding during urgent receive waiting for DM
+ else if(!iUrgentFlag)
+ {
+ // Pass to client
+ // Normal data received, just write it to the output buffer
+ aClientOutBuffer.Append(aInBuffer[i]);
+ }
+ else
+ {
+ // Discard
+ __FLOG_STATIC(KTelnetLoggingCompnt(),KTelnetLoggingTag(),_L("CProto::ProtoRead() Discard During Urgent"));
+ }
+ break;
+
+ case EIAC :
+ // Last character received was an Interpret As Command
+ // Check for DO WILL WONT DONT
+ if(aInBuffer[i] == KTelnetDO || aInBuffer[i] == KTelnetWILL || aInBuffer[i] == KTelnetDONT || aInBuffer[i] == KTelnetWONT)
+ {
+ // Add it to the protocol buffer
+ iProtReadBuffer.Append(aInBuffer[i]);
+ iReceiveState = ECommand;
+ }
+ else if(aInBuffer[i] == KTelnetSB)
+ {
+ // Suboption Start
+ iReceiveState = ESubOpt;
+ iSubOptState = ESB;
+ }
+ else
+ {
+ // Interpret As Command followed by Interpret As Command
+ if(aInBuffer[i] == KTelnetIAC)
+ {
+ // Previous Interpret As Command is Escaping a genuine 255 , legal in Binary Mode
+ if(iBinary->ReceiveBinary() && !iUrgentFlag)
+ {
+ // Pass to client
+ aClientOutBuffer.Append(aInBuffer[i]);
+ }
+ else
+ {
+ // Discard whilst in urgent or illegal in NVT mode
+ __FLOG_STATIC1(KTelnetLoggingCompnt(),KTelnetLoggingTag(),_L("CProto::ProtoRead() Illegal IAC Urgent = %d"),iUrgentFlag);
+ }
+ }
+ else
+ {
+ // Unsupported command
+ __FLOG_STATIC1(KTelnetLoggingCompnt(),KTelnetLoggingTag(),_L("CProto::ProtoRead() Unsupported Command = %d"),aInBuffer[i]);
+ }
+ // Back to normal state
+ iReceiveState = ENormal;
+ }
+ break;
+
+ case ESubOpt :
+ // Receiving a Suboption sequence
+ if(iSubOptState == ESB)
+ {
+ // TERMINAL-TYPE,TERMINAL-SPEED,STATUS
+ iProtReadBuffer.Append(aInBuffer[i]);
+ iSubOptState = EOption;
+ }
+ else if(iSubOptState == EOption)
+ {
+ // SEND or IS
+ iProtReadBuffer.Append(aInBuffer[i]);
+ iSubOptState = ERequest;
+ }
+ else if(iSubOptState == ERequest)
+ {
+ // IAC or STATUS info from the server
+ if(aInBuffer[i] == KTelnetIAC)
+ {
+ iSubOptState = EEndIAC;
+ }
+ iProtReadBuffer.Append(aInBuffer[i]);
+ }
+ else if(iSubOptState == EEndIAC && aInBuffer[i] == KTelnetSE)
+ {
+ // SE Suboption End
+ // Scan through the sequence we have just received
+ // Currently we support sending Window Size ,Terminal Speed and Status Information
+ if(iProtReadBuffer[0] == KTelnetProtOptionTerminalType)
+ {
+ // Get our window size
+ iTerminalType->GetTelnetSubOption(aProtoOutBuffer);
+ __FLOG_STATIC(KTelnetLoggingCompnt(),KTelnetLoggingTag(),_L("CProto::ProtoRead() SE Term Type"));
+ }
+ else if(iProtReadBuffer[0] == KTelnetProtOptionTerminalSpeed)
+ {
+ // Get our speed
+ iSpeed->GetTelnetSubOption(aProtoOutBuffer);
+ __FLOG_STATIC(KTelnetLoggingCompnt(),KTelnetLoggingTag(),_L("CProto::ProtoRead() SE Term Speed"));
+ }
+ else if(iProtReadBuffer[0] == KTelnetProtOptionStatus)
+ {
+ // Check whether it's a request for us to send or it's status info from the server
+ if(iProtReadBuffer[1] == KTelnetCommandSEND)
+ {
+ // Server wants our status
+ GetOptionStatus(aProtoOutBuffer);
+ __FLOG_STATIC(KTelnetLoggingCompnt(),KTelnetLoggingTag(),_L("CProto::ProtoRead() SE STATUS SEND"));
+ }
+ else if(iProtReadBuffer[1] == KTelnetCommandIS)
+ {
+ // Status info from the server
+ // We are currently doing nothing with it but in case
+ // the client wants to know the server's perceived state of the connection
+ // store it in the object
+ iServerStatus = iProtReadBuffer;
+ __FLOG_STATIC(KTelnetLoggingCompnt(),KTelnetLoggingTag(),_L("CProto::ProtoRead() SE STATUS IS"));
+ }
+ else
+ {
+ // Corruption
+ __FLOG_STATIC(KTelnetLoggingCompnt(),KTelnetLoggingTag(),_L("CProto::ProtoRead() STATUS SubOption ERROR"));
+ }
+ }
+ iReceiveState = ENormal;
+ }
+ else
+ {
+ iReceiveState = ENormal;
+ __FLOG_STATIC(KTelnetLoggingCompnt(),KTelnetLoggingTag(),_L("CProto::ProtoRead() SubOption Unexpected Receive ERROR"));
+ }
+
+ break;
+
+ case ECommand :
+ // Last byte received was a DO, WILL, WONT or DONT
+ {
+ TInt32 event = TOptionFSM::ENoEvent;
+ TOptionFSM::TRequests request = TOptionFSM::ENoOption;
+ TBuf8<64> action;
+
+ // Map to our internal command code
+ if(iProtReadBuffer[0] == KTelnetDO)
+ request = TOptionFSM::EServerDo;
+ else if(iProtReadBuffer[0] == KTelnetWILL)
+ request = TOptionFSM::EServerWill;
+ else if(iProtReadBuffer[0] == KTelnetWONT)
+ request = TOptionFSM::EServerWont;
+ else if(iProtReadBuffer[0] == KTelnetDONT)
+ request = TOptionFSM::EServerDont;
+
+ // switch on the RFC option
+ // Most cases get a possible action and a possible event
+ switch(aInBuffer[i])
+ {
+ case KTelnetProtOptionEcho :
+ iEcho->RequestOption(request,action,event);
+ if(action.Length())
+ aProtoOutBuffer.Append(action);
+ __FLOG_STATIC2(KTelnetLoggingCompnt(),KTelnetLoggingTag(),_L("CProto::ProtoRead() Echo Event = %d Request = %d"),event,request);
+ if(event != TOptionFSM::ENoEvent)
+ numEvents++;
+ break;
+
+ case KTelnetProtOptionSuppressGA :
+ iGA->RequestOption(request,action,event);
+ if(action.Length())
+ aProtoOutBuffer.Append(action);
+ __FLOG_STATIC1(KTelnetLoggingCompnt(),KTelnetLoggingTag(),_L("CProto::ProtoRead() GA Event = %d"),event);
+ break;
+
+ case KTelnetProtOptionBinary :
+ iBinary->RequestOption(request,action,event);
+ if(action.Length())
+ aProtoOutBuffer.Append(action);
+ __FLOG_STATIC2(KTelnetLoggingCompnt(),KTelnetLoggingTag(),_L("CProto::ProtoRead() Binary Event = %d request = %d"),event,request);
+ if(event != TOptionFSM::ENoEvent)
+ numEvents++;
+ break;
+
+ case KTelnetProtOptionTerminalSpeed :
+ iSpeed->RequestOption(request,action,event);
+ if(action.Length())
+ aProtoOutBuffer.Append(action);
+ __FLOG_STATIC1(KTelnetLoggingCompnt(),KTelnetLoggingTag(),_L("CProto::ProtoRead() Terminal Speed Event = %d"),event);
+ if(event != TOptionFSM::ENoEvent)
+ numEvents++;
+ break;
+
+ case KTelnetProtOptionTerminalType :
+ iTerminalType->RequestOption(request,action,event);
+ if(action.Length())
+ aProtoOutBuffer.Append(action);
+ __FLOG_STATIC1(KTelnetLoggingCompnt(),KTelnetLoggingTag(),_L("CProto::ProtoRead() Terminal Type Event = %d"),event);
+ if(event != TOptionFSM::ENoEvent)
+ numEvents++;
+ break;
+
+ case KTelnetProtOptionWindowSize :
+ // Winbdow size, send our window size if it's enabled
+ iWindowSize->RequestOption(request,action,event);
+ if(action.Length())
+ aProtoOutBuffer.Append(action);
+ if(event == TOptionFSM::EClientEnabled)
+ {
+ iWindowSize->GetTelnetSubOption(subOptions);
+ }
+ __FLOG_STATIC1(KTelnetLoggingCompnt(),KTelnetLoggingTag(),_L("CProto::ProtoRead() Window Size Event = %d"),event);
+ if(event != TOptionFSM::ENoEvent)
+ numEvents++;
+ break;
+
+ case KTelnetProtOptionLogoff :
+ // Server may want to log us out
+ iLogout->RequestOption(request,action,event);
+ if(action.Length())
+ aProtoOutBuffer.Append(action);
+ __FLOG_STATIC1(KTelnetLoggingCompnt(),KTelnetLoggingTag(),_L("CProto::ProtoRead() Logout Event = %d"),event);
+ break;
+
+ case KTelnetProtOptionStatus :
+ iStatus->RequestOption(request,action,event);
+ if(action.Length())
+ aProtoOutBuffer.Append(action);
+ __FLOG_STATIC2(KTelnetLoggingCompnt(),KTelnetLoggingTag(),_L("CProto::ProtoRead() Status Event = %d request = %d"),event,request);
+ if(event != TOptionFSM::ENoEvent)
+ numEvents++;
+ break;
+
+ default :
+ iUnknown->RequestUnknown(aInBuffer[i],request,action,event);
+ if(action.Length())
+ aProtoOutBuffer.Append(action);
+ __FLOG_STATIC1(KTelnetLoggingCompnt(),KTelnetLoggingTag(),_L("CProto::ProtoRead() Unsupported Option = %d"),aInBuffer[i]);
+ break;
+
+ }
+ }
+ iReceiveState = ENormal;
+ break;
+
+ default :
+ break;
+ }
+ }
+ // If any option events have occured then tell the client side so it can retrieve the status
+ // if it's interested
+ if(numEvents)
+ iNotifier->ProtoEvent();
+
+ if(subOptions.Length())
+ {
+ aProtoOutBuffer.Append(subOptions);
+ __FLOG_STATIC1(KTelnetLoggingCompnt(),KTelnetLoggingTag(),_L("CProto::ProtoRead() Add SubOpt Length = %d"),subOptions.Length());
+ }
+ return(KErrNone);
+ }
+
+void CProto::Reset()
+/**
+Clear states
+Don't bother to zero buffers as state machine does them
+*/
+ {
+ iReceiveState = ENormal;
+ iUrgentFlag = FALSE;
+
+ iBinary->Reset();
+ iLogout->Reset();
+ iWindowSize->Reset();
+ iSpeed->Reset();
+ iStatus->Reset();
+ iTerminalType->Reset();
+ iEcho->Reset();
+ iGA->Reset();
+ }
+
+
+CProto::CProto()
+/**
+Constructor
+*/
+ {
+ }
+
+
+CProto::~CProto()
+/**
+Destructor
+*/
+ {
+ __FLOG_STATIC(KTelnetLoggingCompnt(),KTelnetLoggingTag(),_L("CProto::D'Tor"));
+
+ delete iUnknown;
+ delete iStatus;
+ delete iGA;
+ delete iSpeed;
+ delete iLogout;
+ delete iTerminalType;
+ delete iWindowSize;
+ delete iEcho;
+ delete iBinary;
+ }