package dmg.protocols.telnet ;
import java.io.IOException;
import java.io.InputStream;
/**
* The Telnet input stream builds the layer between
* a telnet input stream and the application layer.
* If it is used as Filter for higher level Streams,
* is simply extracts the telnet controls out of the stream.
* Otherwise the 'getNext' method returns a byte array which
* represents the control characters and an CharacterObject
* otherwise.
*
*
*
* @author Patrick Fuhrmann
* @version 0.1, 15 Feb 1998
*
*/
public class TelnetInputStream extends InputStream {
//
// the telnet constants
//
private static final byte telnetSE = (-16);
private static final byte telnetNOP = (-15);
private static final byte telnetDM = (-14);
private static final byte telnetBRK = (-13);
private static final byte telnetIP = (-12);
private static final byte telnetAO = (-11);
private static final byte telnetAYT = (-10);
private static final byte telnetEC = (-9);
private static final byte telnetEL = (-8);
private static final byte telnetGA = (-7);
private static final byte telnetSB = (-6);
private static final byte telnetWILL = (-5);
private static final byte telnetWONT = (-4);
private static final byte telnetDO = (-3);
private static final byte telnetDONT = (-2);
private static final byte telnetIAC = (-1);
private static final byte telnetCR = (0xd);
private static final byte telnetLF = (0xa);
private static final byte telnetNUL = (0);
private static final byte telnetOptionEcho = (1);
private static final int telnetStateControl = 0 ;
private static final int telnetStateIntro = 1 ;
private static final int telnetStateAuthUser = 2 ;
private static final int telnetStateAuthPasswd = 3 ;
private static final int telnetStateMOTD = 4 ;
private static final int telnetStateData = 5 ;
private static final int telnetStateNoAccess = 6 ;
private static final int cctData = 1 ;
private static final int cctCR = 2 ;
private static final int cctCR2 = 3 ;
private static final int cctCT1 = 4 ;
private static final int cctCT2 = 5 ;
private static final int cctSUB = 6 ;
private static final int cctESC = 7 ;
//
// class variables
//
int _engineState ;
int _controlDataPos ;
byte [] _controlData ;
InputStream _inputStream ;
public TelnetInputStream( InputStream in ){
// super( in ) ;
_inputStream = in ;
_engineState = 0 ;
_controlData = null ;
_controlDataPos = 0 ;
}
private void _engineControlAdd( byte c ){
//
if( _controlDataPos >= _controlData.length ){
//
// somethin' wrong with telnet engine
//
_controlDataPos = 0 ;
}
_controlData[_controlDataPos++] = c ;
}
private void _engineControlClear(){
if( _controlData == null ) {
_controlData = new byte[32];
}
_controlDataPos = 0 ;
}
private byte [] _engineControlGet(){
if( _controlDataPos == 0 ) {
return null;
}
byte [] rc = new byte[ _controlDataPos ] ;
System.arraycopy( _controlData , 0 , rc , 0 , _controlDataPos ) ;
_engineControlClear() ;
return rc ;
}
public Object readNext() throws IOException {
int rc ;
Object obj ;
while( true ){
if( ( rc = _inputStream.read() ) < 0 ) {
return null;
}
if( ( obj = _next( (byte)rc ) ) != null ) {
return obj;
}
}
}
@Override
public int read() throws IOException {
Object obj ;
while(true){
obj = this.readNext() ;
if( obj == null ){
return -1 ;
}else if( obj instanceof Byte ){
return ((Byte)obj).intValue() ;
}else{
System.out.println("Got telnet control : " + obj) ;
}
}
}
private Object _next( byte c ){
if( _engineState == 0 ){
_engineControlClear() ;
_engineState = cctData ;
}
switch( _engineState ){
case cctData :
if( c == telnetIAC ){
_engineState = cctCT1 ;
}else if( c == telnetCR ){
_engineState = cctCR ;
}else{
return _charOfByte( c ) ;
}
break ;
case cctCT1 :
if( c == telnetIAC ){
_engineState = cctData ;
return _charOfByte( c ) ;
}else if( c == telnetSB ){
_engineState = cctSUB ;
_engineControlAdd( telnetIAC ) ;
_engineControlAdd( c ) ;
}else{
_engineState = cctCT2 ;
_engineControlAdd( telnetIAC ) ;
_engineControlAdd( c ) ;
}
break ;
case cctCT2 :
_engineState = cctData ;
_engineControlAdd( c ) ;
return _engineControlGet() ;
case cctSUB :
if( c == telnetIAC ){
_engineState = cctESC ;
}else{
_engineControlAdd( c ) ;
}
break ;
case cctESC :
if( c == telnetSE ){
_engineState = cctData ;
_engineControlAdd( telnetIAC ) ;
_engineControlAdd( c ) ;
return _engineControlGet() ;
}else{
_engineState = cctSUB ;
_engineControlAdd( telnetIAC ) ;
_engineControlAdd( c ) ;
}
break ;
case cctCR :
_engineState = cctCR2 ;
return '\n';
case cctCR2 :
if( c == telnetIAC ){
_engineState = cctCT1 ;
}else if( c == telnetCR ){
_engineState = cctCR ;
}else{
_engineState = cctData ;
return _charOfByte( c ) ;
}
break ;
}
return null ;
}
// private Byte _charOfByte( byte c ){ return new Byte( c ) ; }
private Character _charOfByte( byte c ){
byte [] rc = new byte[1] ;
rc[0] = c ;
return new String(rc).charAt(0);
}
}