📄 idtelnet.pas
字号:
{ $HDR$}
{**********************************************************************}
{ Unit archived using Team Coherence }
{ Team Coherence is Copyright 2002 by Quality Software Components }
{ }
{ For further information / comments, visit our WEB site at }
{ http://www.TeamCoherence.com }
{**********************************************************************}
{}
{ $Log: 10371: IdTelnet.pas
{
{ Rev 1.0 2002.11.12 10:55:40 PM czhower
}
unit IdTelnet;
// CHANGES
//
// 26-05-2000 SG: Converted to Indy, no other change
// 13-JAN-2000 MTL: Moved to new Palette Scheme (Winshoes Servers)
//
///////////////////////////////////////////////////////////////////////////////
// Author: Mark Holmes
// ..
// This is the telnet client component. I'm still testing {Do not Localize}
// There is no real terminal emulation other than dumb terminal
//
////////////////////////////////////////////////////////////////////////////////
{
******************************************************************************
Date Author Change.
--------------------------------------------------------------------------------
05-Mar-2000 Mark Added constants for telnet implememtation.
07-Mar-2000 Mark Added a bunch of stuff... it's very much a work in progress
03-01-2002 Andrew P.Rybin Renamings and standardization
}
interface
uses
Classes,
IdException,
IdGlobal,
IdStack,
IdTCPClient, IdThread,
SysUtils;
const
{ These are the telnet command constansts from RFC 854 }
TNC_EOR = #239; // End of Record RFC 885
TNC_SE = #240; // End of subnegotiation parameters.
TNC_NOP = #241; // No operation.
TNC_DATA_MARK = #242; // The data stream portion of a Synch.
// This should always be accompanied
// by a TCP Urgent notification.
TNC_BREAK = #243; // NVT character BRK.
TNC_IP = #244; // The function IP.
TNC_AO = #245; // The function ABORT OUTPUT.
TNC_AYT = #246; // The function ARE YOU THERE.
TNC_EC = #247; // The function ERASE CHARACTER.
TNC_EL = #248; // The function ERASE LINE.
TNC_GA = #249; // The GO AHEAD signal.
TNC_SB = #250; // Indicates that what follows is
// subnegotiation of the indicated
// option.
TNC_WILL = #251; // Indicates the desire to begin
// performing, or confirmation that
// you are now performing, the
// indicated option.
TNC_WONT = #252; // Indicates the refusal to perform,
// or continue performing, the
// indicated option.
TNC_DO = #253; // Indicates the request that the
// other party perform, or
// confirmation that you are expecting
// the other party to perform, the
// indicated option.
TNC_DONT = #254; // 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 = #255; // Data Byte 255.
{ Telnet options from RFC 1010 }
TNO_BINARY = #0; // Binary Transmission
TNO_ECHO = #1; // Echo
TNO_RECONNECT = #2; // Reconnection
TNO_SGA = #3; // Suppress Go Ahead
TNO_AMSN = #4; // Approx Message Size Negotiation
TNO_STATUS = #5; // Status
TNO_TIMING_MARK = #6; // Timing Mark
TNO_RCTE = #7; // Remote Controlled Trans and Echo -BELL
TNO_OLW = #8; // Output Line Width
TNO_OPS = #9; // Output Page Size
TNO_OCRD = #10; // Output Carriage-Return Disposition
TNO_OHTS = #11; // Output Horizontal Tab Stops
TNO_OHTD = #12; // Output Horizontal Tab Disposition
TNO_OFD = #13; // Output Formfeed Disposition
TNO_OVT = #14; // Output Vertical Tabstops
TNO_OVTD = #15; // Output Vertical Tab Disposition
TNO_OLD = #16; // Output Linefeed Disposition
TNO_EA = #17; // Extended ASCII
TNO_LOGOUT = #18; // Logout
TNO_BYTE_MACRO = #19; // Byte Macro
TNO_DET = #20; // Data Entry Terminal
TNO_SUPDUP = #21; // SUPDUP
TNO_SUPDUP_OUTPUT = #22; // SUPDUP Output
TNO_SL = #23; // Send Location
TNO_TERMTYPE = #24; // Terminal Type
TNO_EOR = #25; // End of Record
TNO_TACACS_ID = #26; // TACACS User Identification
TNO_OM = #27; // Output Marking
TNO_TLN = #28; // Terminal Location Number
TNO_3270REGIME = #29; // 3270 regime
TNO_X3PAD = #30; // X.3 PAD
TNO_NAWS = #31; // Window size
TNO_TERM_SPEED = #32; // Terminal speed
TNO_RFLOW = #33; // Remote flow control
TNO_LINEMODE = #34; // Linemode option
TNO_XDISPLOC = #35; // X Display Location
TNO_AUTH = #37; // Authenticate
TNO_ENCRYPT = #38; // Encryption option
TNO_EOL = #255; // Extended-Options-List [84,JBP]
// Sub options
TNOS_TERM_IS = #0;
TNOS_TERMTYPE_SEND = #1; // Sub option
TNOS_REPLY = #2;
TNOS_NAME = #3;
type
TIdTelnet = class;
{Various states for telnet }
TIdTelnetState =(tnsDATA, tnsIAC, tnsIAC_SB, tnsIAC_WILL, tnsIAC_DO, tnsIAC_WONT,
tnsIAC_DONT, tnsIAC_SBIAC, tnsIAC_SBDATA, tnsSBDATA_IAC);
{Commands to telnet client from server}
TIdTelnetCommand = (tncNoLocalEcho, tncLocalEcho, tncEcho);
TIdTelnetDataAvailEvent = procedure (Sender: TIdTelnet; const Buffer: String) 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;
FRecvData: String;
//
procedure Run; override;
public
constructor Create(AClient: TIdTelnet); reintroduce;
property Client: TIdTelnet read FClient;
property RecvData: String read FRecvData write FRecvData;
End; //TIdTelnetReadThread
TIdTelnet = class(TIdTCPClient)
protected
fState: TIdTelnetState;
fReply: Char;
fSentDoDont: String;
fSentWillWont: String;
fReceivedDoDont: String;
fReceivedWillWont: String;
fTerminal : String;
FOnDataAvailable: TIdTelnetDataAvailEvent;
fIamTelnet: Boolean;
FOnDisconnect: TNotifyEvent;
FOnConnect: TNotifyEvent;
FOnTelnetCommand: TIdTelnetCommandEvent;
FTelnetThread: TIdTelnetReadThread;
//
procedure DoOnDataAvailable;
procedure SetOnTelnetCommand(const Value: TIdTelnetCommandEvent);
// what is our current state ?
property State : TIdTelnetState read fState write fState;
// what we send to the telnet server in response to protocol negotiations
property Reply : Char read fReply write fReply;
// did we send a DO DONT command?
property SentDoDont : String read fSentDoDont write fSentDoDont;
// did we send a WILL WONT command?
property SentWillWont: String read fSentWillWont write fSentWillWont;
// did we receive a DO DONT request from the server?
property ReceivedDoDont: String read fReceivedDoDont write fReceivedDoDont;
// did we receive a WILL WONT answer from the server?
property ReceivedWillWont: String read fReceivedWillWont write fReceivedWillWont;
// Are we connected to a telnet server or some other server?
property IamTelnet: Boolean read fIamTelnet write fIamTelnet;
// Protocol negotiation begins here
function Negotiate(const Buf: String) : String;
// Handle the termtype request
procedure Handle_SB(CurrentSb: Byte; sbData: String; sbCount: Integer);
// Send the protocol resp to the server based on what's in Reply {Do not Localize}
procedure SendNegotiationResp(var Resp: String);
// Update the telnet status
procedure DoTelnetCommand(Status: TIdTelnetCommand);
public
//
constructor Create(AOwner: TComponent); override;
procedure Connect(const ATimeout: Integer = IdTimeoutDefault); override;
procedure Disconnect; override;
procedure SendCh(Ch: Char);
property TelnetThread: TIdTelnetReadThread read FTelnetThread;
published
property OnTelnetCommand: TIdTelnetCommandEvent read FOnTelnetCommand write SetOnTelnetCommand;
property OnDataAvailable: TIdTelnetDataAvailEvent read FOnDataAvailable write FOnDataAvailable;
property Terminal: string read fTerminal write fTerminal;
property OnConnect: TNotifyEvent read FOnConnect write FOnConnect;
property OnDisconnect: TNotifyEvent read FOnDisconnect write FOnDisconnect;
end;
EIdTelnetError = class(EIdException);
EIdTelnetClientConnectError = class(EIdTelnetError);
EIdTelnetServerOnDataAvailableIsNil = class(EIdTelnetError);
implementation
uses
IdResourceStrings;
constructor TIdTelnetReadThread.Create(AClient: TIdTelnet);
begin
inherited Create(False);
FClient := AClient;
FreeOnTerminate:= FALSE; //other way TRUE
end;
procedure TIdTelnetReadThread.Run;
begin
// if we have data run it through the negotiation routine. If we aren't {Do not Localize}
// connected to a telnet server then the data just passes through the
// negotiate routine unchanged.
FRecvData := FClient.Negotiate(FClient.CurrentReadBuffer);
// if textual data is returned by the server then send this data to
// the client app
Synchronize(FClient.DoOnDataAvailable);
FClient.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 Ch <> CR then
Write(Ch)
else if (Ch = CR) and (IamTelnet = True) then
Write(Ch)
else
Write(EOL);
end;
constructor TIdTelnet.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
Port := 23;
State := tnsData;
SentDoDont := #0;
SentWillWont := #0;
ReceivedDoDont := #0;
ReceivedWillWont := #0;
Terminal := 'dumb'; {Do not Localize}
IamTelnet := False;
end;
procedure TIdTelnet.Disconnect;
begin
if Assigned(FTelnetThread) then begin
FTelnetThread.Terminate;
end;
IAmTelnet := False;
inherited Disconnect;
if Assigned(FOnDisconnect) then begin
OnDisconnect(SELF);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -