| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741 |
- {
- $Project$
- $Workfile$
- $Revision$
- $DateUTC$
- $Id$
- This file is part of the Indy (Internet Direct) project, and is offered
- under the dual-licensing agreement described on the Indy website.
- (http://www.indyproject.org/)
- Copyright:
- (c) 1993-2005, Chad Z. Hower and the Indy Pit Crew. All rights reserved.
- }
- {
- $Log$
- }
- {
- Rev 1.15 2/13/05 7:21:30 PM RLebeau
- Updated TIdTelnetReadThread.Run() to use a timeout when calling the
- IOHandler's CheckForDataOnSource() method.
- Rev 1.14 10/07/2004 10:00:28 ANeillans
- Fixed compile bug
- Rev 1.13 7/8/04 4:12:06 PM RLebeau
- Updated calls to Write() to use the IOHandler
- Rev 1.12 7/4/04 1:38:36 PM RLebeau
- Updated Negotiate() to trigger the OnDataAvailable event only when data is
- actually available.
- Rev 1.11 5/16/04 3:14:06 PM RLebeau
- Added destructor to terminate the reading thread
- Rev 1.10 3/29/04 11:47:00 AM RLebeau
- Updated to support new ThreadedEvent property
- Rev 1.9 2004.03.06 1:31:56 PM czhower
- To match Disconnect changes to core.
- Rev 1.8 2004.02.03 5:44:32 PM czhower
- Name changes
- Rev 1.7 1/21/2004 4:20:48 PM JPMugaas
- InitComponent
- Rev 1.6 2003.11.29 10:20:16 AM czhower
- Updated for core change to InputBuffer.
- Rev 1.5 3/6/2003 5:08:50 PM SGrobety
- Updated the read buffer methodes to fit the new core (InputBuffer ->
- InputBufferAsString + call to CheckForDataOnSource)
- Rev 1.4 2/24/2003 10:32:46 PM JPMugaas
- Rev 1.3 12/8/2002 07:26:10 PM JPMugaas
- Added published host and port properties.
- Rev 1.2 12/7/2002 06:43:30 PM JPMugaas
- These should now compile except for Socks server. IPVersion has to be a
- property someplace for that.
- Rev 1.1 12/6/2002 05:30:40 PM JPMugaas
- Now decend from TIdTCPClientCustom instead of TIdTCPClient.
- Rev 1.0 11/13/2002 08:02:50 AM JPMugaas
- 03-01-2002 Andrew P.Rybin Renamings and standardization
- 26-05-2000 SG: Converted to Indy, no other change
- 07-Mar-2000 Mark Added a bunch of stuff... it's very much a work in progress
- 05-Mar-2000 Mark Added constants for telnet implememtation.
- 13-JAN-2000 MTL: Moved to new Palette Scheme (Winshoes Servers)
- }
- unit IdTelnet;
- {
- Author: Mark Holmes
- This is the telnet client component. I'm still testing
- There is no real terminal emulation other than dumb terminal
- }
- interface
- {$i IdCompilerDefines.inc}
- uses
- Classes,
- IdAssignedNumbers,
- IdGlobal,
- IdException,
- IdStack,
- IdTCPClient, IdThread;
- const
- { These are the telnet command constansts from RFC 854 }
- TNC_EOR = $EF; // End of Record RFC 885
- TNC_SE = $F0; // End of subnegotiation parameters.
- TNC_NOP = $F1; // No operation.
- TNC_DATA_MARK = $F2; // The data stream portion of a Synch.
- // This should always be accompanied
- // by a TCP Urgent notification.
- TNC_BREAK = $F3; // NVT character BRK.
- TNC_IP = $F4; // The function IP.
- TNC_AO = $F5; // The function ABORT OUTPUT.
- TNC_AYT = $F6; // The function ARE YOU THERE.
- TNC_EC = $F7; // The function ERASE CHARACTER.
- TNC_EL = $F8; // The function ERASE LINE.
- TNC_GA = $F9; // The GO AHEAD signal.
- TNC_SB = $FA; // Indicates that what follows is
- // subnegotiation of the indicated
- // option.
- TNC_WILL = $FB; // Indicates the desire to begin
- // performing, or confirmation that
- // you are now performing, the
- // indicated option.
- TNC_WONT = $FC; // Indicates the refusal to perform,
- // or continue performing, the
- // indicated option.
- TNC_DO = $FD; // Indicates the request that the
- // other party perform, or
- // confirmation that you are expecting
- // the other party to perform, the
- // indicated option.
- TNC_DONT = $FE; // Indicates the demand that the
- // other party stop performing,
- // or confirmation that you are no
- // longer expecting the other party
- // to perform, the indicated option.
- TNC_IAC = $FF; // Data Byte 255.
- { Telnet options registered with IANA }
- TNO_BINARY = $00; // Binary Transmission
- TNO_ECHO = $01; // Echo
- TNO_RECONNECT = $02; // Reconnection
- TNO_SGA = $03; // Suppress Go Ahead
- TNO_AMSN = $04; // Approx Message Size Negotiation
- TNO_STATUS = $05; // Status
- TNO_TIMING_MARK = $06; // Timing Mark
- TNO_RCTE = $07; // Remote Controlled Trans and Echo -BELL
- TNO_OLW = $08; // Output Line Width
- TNO_OPS = $09; // Output Page Size
- TNO_OCRD = $0A; // Output Carriage-Return Disposition
- TNO_OHTS = $0B; // Output Horizontal Tab Stops
- TNO_OHTD = $0C; // Output Horizontal Tab Disposition
- TNO_OFD = $0D; // Output Formfeed Disposition
- TNO_OVT = $0E; // Output Vertical Tabstops
- TNO_OVTD = $0F; // Output Vertical Tab Disposition
- TNO_OLD = $10; // Output Linefeed Disposition
- TNO_EA = $11; // Extended ASCII
- TNO_LOGOUT = $12; // Logout
- TNO_BYTE_MACRO = $13; // Byte Macro
- TNO_DET = $14; // Data Entry Terminal
- TNO_SUPDUP = $15; // SUPDUP
- TNO_SUPDUP_OUTPUT = $16; // SUPDUP Output
- TNO_SL = $17; // Send Location
- TNO_TERMTYPE = $18; // Terminal Type
- TNO_EOR = $19; // End of Record
- TNO_TACACS_ID = $1A; // TACACS User Identification
- TNO_OM = $1B; // Output Marking
- TNO_TLN = $1C; // Terminal Location Number
- TNO_3270REGIME = $1D; // 3270 regime
- TNO_X3PAD = $1E; // X.3 PAD
- TNO_NAWS = $1F; // Window size
- TNO_TERM_SPEED = $20; // Terminal speed
- TNO_RFLOW = $21; // Remote flow control
- TNO_LINEMODE = $22; // Linemode option
- TNO_XDISPLOC = $23; // X Display Location
- TNO_ENV = $24; // Environment
- TNO_AUTH = $25; // Authenticate
- TNO_ENCRYPT = $26; // Encryption option
- TNO_NEWENV = $27;
- TNO_TN3270E = $28;
- TNO_XAUTH = $29;
- TNO_CHARSET = $2A;
- TNO_RSP = $2B;
- TNO_COMPORT = $2C;
- TNO_SUPLOCALECHO = $2D;
- TNO_STARTTLS = $2E;
- TNO_KERMIT = $2F;
- TNO_SEND_URL = $30;
- TNO_FORWARD_X = $31;
- // 50-137 = Unassigned
- TNO_PRAGMA_LOGON = $8A;
- TNO_SSPI_LOGON = $8B;
- TNO_PRAGMA_HEARTBEAT = $8C;
- TNO_EOL = $FF; // Extended-Options-List
- // Sub options
- TNOS_TERM_IS = $00;
- TNOS_TERMTYPE_SEND = $01; // Sub option
- TNOS_REPLY = $02;
- TNOS_NAME = $03;
- //Auth commands
- TNOAUTH_IS = $00;
- TNOAUTH_SEND = $01;
- TNOAUTH_REPLY = $02;
- TNOAUTH_NAME = $03;
- // Auth options $25
- TNOAUTH_NULL = $00;
- TNOAUTH_KERBEROS_V4 = $01;
- TNOAUTH_KERBEROS_V5 = $02;
- TNOAUTH_SPX = $03;
- TNOAUTH_MINK = $04;
- TNOAUTH_SRP = $05;
- TNOAUTH_RSA = $06;
- TNOAUTH_SSL = $07;
- TNOAUTH_LOKI = $0A;
- TNOAUTH_SSA = $0B;
- TNOAUTH_KEA_SJ = $0C;
- TNOAUTH_KEA_SJ_INTEG = $0D;
- TNOAUTH_DSS = $0E;
- TNOAUTH_NTLM = $0F;
- //Kerberos4 Telnet Authentication suboption commands
- TNOAUTH_KRB4_AUTH = $00;
- TNOAUTH_KRB4_REJECT = $01;
- TNOAUTH_KRB4_ACCEPT = $02;
- TNOAUTH_KRB4_CHALLENGE = $03;
- TNOAUTH_KRB4_RESPONSE = $04;
- TNOAUTH_KRB4_FORWARD = $05;
- TNOAUTH_KRB4_FORWARD_ACCEPT = $06;
- TNOAUTH_KRB4_FORWARD_REJECT = $07;
- TNOAUTH_KRB4_EXP = $08;
- TNOAUTH_KRB4_PARAMS = $09;
- //Kerberos5 Telnet Authentication suboption commands
- TNOAUTH_KRB5_AUTH = $00;
- TNOAUTH_KRB5_REJECT = $01;
- TNOAUTH_KRB5_ACCEPT = $02;
- TNOAUTH_KRB5_RESPONSE = $03;
- TNOAUTH_KRB5_FORWARD = $04;
- TNOAUTH_KRB5_FORWARD_ACCEPT = $05;
- TNOAUTH_KRB5_FORWARD_REJECT = $06;
- //DSS Telnet Authentication suboption commands
- TNOAUTH_DSS_INITIALIZE = $01;
- TNOAUTH_DSS_TOKENBA = $02;
- TNOAUTH_DSS_CERTA_TOKENAB = $03;
- TNOAUTH_DSS_CERTB_TOKENBA2 = $04;
- //SRP Telnet Authentication suboption commands
- TNOAUTH_SRP_AUTH = $00;
- TNOAUTH_SRP_REJECT = $01;
- TNOAUTH_SRP_ACCEPT = $02;
- TNOAUTH_SRP_CHALLENGE = $03;
- TNOAUTH_SRP_RESPONSE = $04;
- TNOAUTH_SRP_EXP = $08;
- TNOAUTH_SRP_PARAMS = $09;
- // KEA_SJ and KEA_SJ_INTEG Telnet Authenticatio suboption commands
- TNOAUTH_KEA_CERTA_RA = $01;
- TNOAUTH_KEA_CERTB_RB_IVB_NONCEB = $02;
- TNOAUTH_KEA_IVA_RESPONSEB_NONCEA = $03;
- TNOAUTH_KEA_RESPONSEA = $04;
- //Telnet Encryption Types (Option 38)
- // commands
- TNOENC_IS = $00;
- TNOENC_SUPPORT = $01;
- TNOENC_REPLY = $02;
- TNOENC_START = $03;
- TNOENC_END = $04;
- TNOENC_REQUEST_START = $05;
- TNOENC_REQUEST_END = $06;
- TNOENC_ENC_KEYID = $07;
- TNOENC_DEC_KEYID = $08;
- // types
- TNOENC_NULL = $00;
- TNOENC_DES_CFB64 = $01;
- TNOENC_DES_OFB64 = $02;
- TNOENC_DES3_CFB64 = $03;
- TNOENC_DES3_OFB64 = $04;
- TNOENC_CAST5_40_CFB64 = $08;
- TNOENC_CAST5_40_OFB64 = $09;
- TNOENC_CAST128_CFB64 = $0A;
- TNOENC_CAST128_OFB64 = $0B;
- TNOENC_AES_CCM = $0C;
- //DES3_CFB64 Telnet Encryption type suboption commands
- TNOENC_CFB64_IV = $01;
- TNOENC_CFB64_IV_OK = $02;
- TNOENC_CFB64_IV_BAD = $03;
- //CAST5_40_OFB64 and CAST128_OFB64 Telnet Encryption types suboption commands
- TNOENC_OFB64_IV = $01;
- TNOENC_OFB64_IV_OK = $02;
- TNOENC_OFB64_IV_BAD = $03;
- //CAST5_40_CFB64 and CAST128_CFB64 Telnet Encryption types suboption commands
- //same as DES3_CFB64 Telnet Encryption type suboption commands
- //DES_CFB64 Telnet Encryption type
- //same as DES3_CFB64 Telnet Encryption type suboption commands
- //DES_OFB64 Telnet Encryption type
- //same as CAST5_40_OFB64 and CAST128_OFB64 Telnet Encryption types suboption commands
- type
- TIdTelnet = class;
- {Commands to telnet client from server}
- TIdTelnetCommand = (tncNoLocalEcho, tncLocalEcho, tncEcho);
- TIdTelnetDataAvailEvent = procedure (Sender: TIdTelnet; const Buffer: TIdBytes) of object;
- TIdTelnetCommandEvent = procedure(Sender: TIdTelnet; Status: TIdTelnetCommand) of object;
- {This object is for the thread that listens for the telnet server responses
- to key input and initial protocol negotiations }
- TIdTelnetReadThread = class(TIdThread)
- protected
- FClient: TIdTelnet;
- //
- procedure Run; override;
- public
- constructor Create(AClient: TIdTelnet); reintroduce;
- property Client: TIdTelnet read FClient;
- end; //TIdTelnetReadThread
- TIdTelnet = class(TIdTCPClientCustom)
- protected
- fTerminal : String;
- fThreadedEvent: Boolean;
- FOnDataAvailable: TIdTelnetDataAvailEvent;
- fIamTelnet: Boolean;
- FOnTelnetCommand: TIdTelnetCommandEvent;
- FTelnetThread: TIdTelnetReadThread;
- //
- procedure DoOnDataAvailable(const Buf: TIdBytes);
- // Are we connected to a telnet server or some other server?
- property IamTelnet: Boolean read fIamTelnet write fIamTelnet;
- // Protocol negotiation begins here
- procedure Negotiate;
- // Handle the termtype request
- procedure Handle_SB(const SbType: Byte; const SbData: TIdBytes);
- // Send the protocol resp to the server based on what's in Reply {Do not Localize}
- procedure SendNegotiationResp(const Response: Byte; const ResponseData: Byte);
- procedure SendSubNegotiationResp(const SbType: Byte; const ResponseData: TIdBytes);
- // Update the telnet status
- procedure DoTelnetCommand(Status: TIdTelnetCommand);
- procedure InitComponent; override;
- public
- //
- {$IFDEF WORKAROUND_INLINE_CONSTRUCTORS}
- constructor Create(AOwner: TComponent); reintroduce; overload;
- {$ENDIF}
- destructor Destroy; override;
- procedure Connect; override;
- procedure Disconnect(ANotifyPeer: Boolean); override;
- procedure SendCh(Ch: Char);
- procedure SendString(const S: String);
- property TelnetThread: TIdTelnetReadThread read FTelnetThread;
- published
- property Host;
- property Port default IdPORT_TELNET;
- property OnTelnetCommand: TIdTelnetCommandEvent read FOnTelnetCommand write FOnTelnetCommand;
- property OnDataAvailable: TIdTelnetDataAvailEvent read FOnDataAvailable write FOnDataAvailable;
- property Terminal: string read fTerminal write fTerminal;
- property ThreadedEvent: Boolean read fThreadedEvent write fThreadedEvent default False;
- end;
- EIdTelnetError = class(EIdException);
- EIdTelnetClientConnectError = class(EIdTelnetError);
- EIdTelnetServerOnDataAvailableIsNil = class(EIdTelnetError);
- implementation
- uses
- IdResourceStringsCore,
- IdResourceStringsProtocols,
- SysUtils;
- constructor TIdTelnetReadThread.Create(AClient: TIdTelnet);
- begin
- FClient := AClient;
- inherited Create(False);
- end;
- procedure TIdTelnetReadThread.Run;
- begin
- // if we have data run it through the negotiation routine. If we aren't
- // connected to a telnet server then the data just passes through the
- // negotiate routine unchanged.
- // RLebeau 3/29/04 - made Negotiate() get called by Synchronize() to
- // ensure that the OnTelnetCommand event handler is synchronized when
- // ThreadedEvent is false
- if FClient.IOHandler.InputBufferIsEmpty then begin
- FClient.IOHandler.CheckForDataOnSource(IdTimeoutInfinite);
- end;
- if not FClient.IOHandler.InputBufferIsEmpty then begin
- if FClient.ThreadedEvent then begin
- FClient.Negotiate;
- end else begin
- Synchronize(FClient.Negotiate);
- end;
- end;
- FClient.IOHandler.CheckForDisconnect;
- end;
- { TIdTelnet }
- procedure TIdTelnet.SendCh(Ch : Char);
- begin
- // this code is necessary to allow the client to receive data properly
- // from a non-telnet server
- if Connected then begin
- if (Ch <> CR) or IamTelnet then begin
- IOHandler.Write(Ch);
- end else begin
- IOHandler.Write(EOL);
- end;
- end;
- end;
- procedure TIdTelnet.SendString(const S : String);
- var
- I: Integer;
- Ch: Char;
- begin
- // this code is necessary to allow the client to receive data properly
- // from a non-telnet server
- for I := 1 to Length(S) do begin
- try
- Ch := S[I];
- if (Ch <> CR) or IamTelnet then begin
- IOHandler.Write(Ch);
- end else begin
- IOHandler.Write(EOL);
- end;
- except
- end;
- end;
- end;
- {$IFDEF WORKAROUND_INLINE_CONSTRUCTORS}
- constructor TIdTelnet.Create(AOwner: TComponent);
- begin
- inherited Create(AOwner);
- end;
- {$ENDIF}
- procedure TIdTelnet.InitComponent;
- begin
- inherited InitComponent;
- Terminal := 'dumb'; {Do not Localize}
- ThreadedEvent := False;
- IamTelnet := False;
- Port := IdPORT_TELNET;
- end;
- destructor TIdTelnet.Destroy;
- begin
- Disconnect;
- inherited Destroy;
- end;
- procedure TIdTelnet.Disconnect(ANotifyPeer: Boolean);
- begin
- if Assigned(FTelnetThread) then begin
- FTelnetThread.Terminate;
- end;
- try
- inherited Disconnect(ANotifyPeer);
- finally
- if Assigned(FTelnetThread) and (not IsCurrentThread(FTelnetThread)) then begin
- FTelnetThread.WaitFor;
- FreeAndNil(FTelnetThread);
- end;
- end;
- end;
- procedure TIdTelnet.DoOnDataAvailable(const Buf: TIdBytes);
- begin
- if Assigned(FOnDataAvailable) then begin
- OnDataAvailable(Self, Buf);
- end else begin
- raise EIdTelnetServerOnDataAvailableIsNil.Create(RSTELNETSRVOnDataAvailableIsNil);
- end;
- end;
- procedure TIdTelnet.Connect;
- begin
- inherited Connect;
- try
- // create the reading thread and assign the current Telnet object to it
- IAmTelnet := False;
- FTelnetThread := TIdTelnetReadThread.Create(Self);
- except
- Disconnect(True);
- IndyRaiseOuterException(EIdTelnetClientConnectError.Create(RSNoCreateListeningThread)); // translate
- end;
- end;
- procedure TIdTelnet.SendNegotiationResp(const Response: Byte; const ResponseData: Byte);
- var
- Resp: TIdBytes;
- begin
- SetLength(Resp, 3);
- Resp[0] := TNC_IAC;
- Resp[1] := Response;
- Resp[2] := ResponseData;
- IOHandler.Write(Resp);
- end;
- procedure TIdTelnet.SendSubNegotiationResp(const SbType: Byte; const ResponseData: TIdBytes);
- var
- Resp: TIdBytes;
- begin
- SetLength(Resp, 3 + Length(ResponseData) + 2);
- Resp[0] := TNC_IAC;
- Resp[1] := TNC_SB;
- Resp[2] := SbType;
- CopyTIdBytes(ResponseData, 0, Resp, 3, Length(ResponseData));
- Resp[Length(Resp)-2] := TNC_IAC;
- Resp[Length(Resp)-1] := TNC_SE;
- IOHandler.Write(Resp);
- end;
- procedure TIdTelnet.Handle_SB(const SbType: Byte; const SbData: TIdBytes);
- var
- Resp: TIdBytes;
- LTerminal: String;
- begin
- Resp := nil;
- case SbType of
- TNO_TERMTYPE:
- if (Length(SbData) > 0) and (SbData[0] = TNOS_TERMTYPE_SEND) then
- begin
- // if someone inadvertantly sets Terminal to null
- // You can set terminal to anything you want I suppose but be
- // prepared to handle the data emulation yourself
- LTerminal := Terminal;
- if LTerminal = '' then begin
- Terminal := 'UNKNOWN'; {Do not Localize}
- end;
- SetLength(Resp, 1);
- Resp[0] := TNOS_TERM_IS;
- AppendString(Resp, LTerminal);
- SendSubNegotiationResp(TNO_TERMTYPE, Resp);
- end;
- end;
- // add authentication code here
- end;
- procedure TIdTelnet.Negotiate;
- var
- b : Byte;
- nBuf : TIdBytes;
- sbBuf : TIdBytes;
- CurrentSb : Byte;
- Reply : Byte;
- begin
- nBuf := nil;
- sbBuf := nil;
- repeat
- b := IOHandler.ReadByte;
- if b <> TNC_IAC then
- begin
- AppendByte(nBuf, b);
- Continue;
- end;
- { start of command sequence }
- IamTelnet := True;
- b := IOHandler.ReadByte;
- if b = TNC_IAC then
- begin
- AppendByte(nBuf, TNC_IAC);
- Continue;
- end;
- case b of
- TNC_WILL:
- begin
- b := IOHandler.ReadByte;
- case b of
- TNO_ECHO:
- begin
- Reply := TNC_DO;
- DoTelnetCommand(tncNoLocalEcho);
- //doStatus('NOLOCALECHO'); {Do not Localize}
- end;
- TNO_EOR:
- Reply := TNC_DO;
- else
- Reply := TNC_DONT;
- end;
- SendNegotiationResp(Reply, b);
- end;
- TNC_WONT:
- begin
- b := IOHandler.ReadByte;
- case b of
- TNO_ECHO:
- begin
- Reply := TNC_DONT;
- DoTelnetCommand(tncLocalEcho);
- //Dostatus('LOCALECHO'); {Do not Localize}
- end;
- else
- Reply := TNC_DONT;
- end;
- SendNegotiationResp(Reply, b);
- end;
- TNC_DONT:
- begin
- b := IOHandler.ReadByte;
- case b of
- TNO_ECHO:
- begin
- DoTelnetCommand(tncEcho);
- //DoStatus('ECHO'); {Do not Localize}
- Reply := TNC_WONT;
- end;
- else
- Reply := TNC_WONT;
- end;
- SendNegotiationResp(Reply, b);
- end;
- TNC_DO:
- begin
- b := IOHandler.ReadByte;
- case b of
- TNO_ECHO:
- begin
- Reply := TNC_WILL;
- DoTelnetCommand(tncLocalEcho);
- end;
- TNO_TERMTYPE:
- Reply := TNC_WILL;
- //TNO_NAWS:
- TNO_AUTH:
- begin
- {
- if (Authentication) then begin
- Reply := TNC_WILL;
- end else
- }
- begin
- Reply := TNC_WONT;
- end;
- end;
- else
- Reply := TNC_WONT;
- end;
- SendNegotiationResp(Reply, b);
- end;
- TNC_EOR:
- begin
- // send any current data to the app
- if Length(nBuf) > 0 then
- begin
- DoOnDataAvailable(nBuf);
- SetLength(nBuf, 0);
- end;
- end;
- TNC_SB:
- begin
- SetLength(sbBuf, 0);
- // send any current data to the app, as the sub-negotiation
- // may affect how subsequent data needs to be processed...
- if Length(nBuf) > 0 then
- begin
- DoOnDataAvailable(nBuf);
- SetLength(nBuf, 0);
- end;
- CurrentSB := IOHandler.ReadByte;
- repeat
- b := IOHandler.ReadByte;
- if b = TNC_IAC then
- begin
- b := IOHandler.ReadByte;
- case b of
- TNC_IAC:
- begin
- AppendByte(sbBuf, TNC_IAC);
- end;
- TNC_SE:
- begin
- Handle_Sb(CurrentSB, sbBuf);
- SetLength(sbBuf, 0);
- Break;
- end;
- TNC_SB:
- begin
- Handle_Sb(CurrentSB, sbBuf);
- SetLength(sbBuf, 0);
- CurrentSB := IOHandler.ReadByte;
- end;
- end;
- end else begin
- AppendByte(sbBuf, b);
- end;
- until False;
- end;
- end;
- until IOHandler.InputBufferIsEmpty;
- // if any data remains then send this data to the app
- if Length(nBuf) > 0 then begin
- DoOnDataAvailable(nBuf);
- end;
- end;
- procedure TIdTelnet.DoTelnetCommand(Status: TIdTelnetCommand);
- begin
- if Assigned(FOnTelnetCommand) then
- FOnTelnetCommand(Self, Status);
- end;
- END.
|