mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-04-16 23:21:57 +02:00
683 lines
20 KiB
ObjectPascal
683 lines
20 KiB
ObjectPascal
{ lTelnet CopyRight (C) 2004-2008 Ales Katona
|
|
|
|
This library is Free software; you can rediStribute it and/or modify it
|
|
under the terms of the GNU Library General Public License as published by
|
|
the Free Software Foundation; either version 2 of the License, or (at your
|
|
option) any later version.
|
|
|
|
This program is diStributed in the hope that it will be useful, but WITHOUT
|
|
ANY WARRANTY; withOut even the implied warranty of MERCHANTABILITY or
|
|
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License
|
|
for more details.
|
|
|
|
You should have received a Copy of the GNU Library General Public License
|
|
along with This library; if not, Write to the Free Software Foundation,
|
|
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
|
|
This license has been modified. See File LICENSE for more inFormation.
|
|
Should you find these sources withOut a LICENSE File, please contact
|
|
me at ales@chello.sk
|
|
}
|
|
|
|
unit lTelnet;
|
|
|
|
{$mode objfpc}{$H+}
|
|
//{$define debug}
|
|
|
|
interface
|
|
|
|
uses
|
|
Classes, SysUtils, lNet, lControlStack;
|
|
|
|
const
|
|
// Telnet printer signals
|
|
TS_NUL = #0;
|
|
TS_ECHO = #1;
|
|
TS_SGA = #3; // Surpass go-ahead
|
|
TS_BEL = #7;
|
|
TS_BS = #8;
|
|
TS_HT = #9;
|
|
TS_LF = #10;
|
|
TS_VT = #11;
|
|
TS_FF = #12;
|
|
TS_CR = #13;
|
|
// Telnet control signals
|
|
TS_NAWS = #31;
|
|
TS_DATA_MARK = #128;
|
|
TS_BREAK = #129;
|
|
TS_HYI = #133; // Hide Your Input
|
|
// Data types codes
|
|
TS_STDTELNET = #160;
|
|
TS_TRANSPARENT = #161;
|
|
TS_EBCDIC = #162;
|
|
// Control bytes
|
|
TS_SE = #240;
|
|
TS_NOP = #241;
|
|
TS_GA = #249; // go ahead currently ignored(full duplex)
|
|
TS_SB = #250;
|
|
TS_WILL = #251;
|
|
TS_WONT = #252;
|
|
TS_DO = #253;
|
|
TS_DONT = #254;
|
|
// Mother of all power
|
|
TS_IAC = #255;
|
|
|
|
type
|
|
TLTelnetClient = class;
|
|
|
|
TLTelnetControlChars = set of Char;
|
|
|
|
TLHowEnum = (TE_WILL = 251, TE_WONT, TE_DO, TE_DONW);
|
|
|
|
TLSubcommandCallback= function(command: char; const parameters, defaultResponse: string): string;
|
|
TLSubcommandEntry= record
|
|
callback: TLSubcommandCallback;
|
|
defaultResponse: string;
|
|
requiredParams: integer
|
|
end;
|
|
TLSubcommandArray= array[#$00..#$ff] of TLSubcommandEntry;
|
|
EInsufficientSubcommandParameters= class(Exception);
|
|
|
|
{ TLTelnet }
|
|
|
|
TLTelnet = class(TLComponent, ILDirect)
|
|
protected
|
|
FStack: TLControlStack;
|
|
FConnection: TLTcp;
|
|
FPossible: TLTelnetControlChars;
|
|
FActiveOpts: TLTelnetControlChars;
|
|
FOutput: TMemoryStream;
|
|
FOperation: Char;
|
|
FCommandCharIndex: Byte;
|
|
FOnReceive: TLSocketEvent;
|
|
FOnConnect: TLSocketEvent;
|
|
FOnDisconnect: TLSocketEvent;
|
|
FOnError: TLSocketErrorEvent;
|
|
FCommandArgs: string[3];
|
|
FOrders: TLTelnetControlChars;
|
|
FBuffer: array of Char;
|
|
FBufferIndex: Integer;
|
|
FBufferEnd: Integer;
|
|
FSubcommandCallbacks: TLSubcommandArray;
|
|
procedure InflateBuffer;
|
|
function AddToBuffer(const aStr: string): Boolean; inline;
|
|
|
|
function Question(const Command: Char; const Value: Boolean): Char;
|
|
|
|
function GetConnected: Boolean;
|
|
|
|
function GetTimeout: Integer;
|
|
procedure SetTimeout(const Value: Integer);
|
|
|
|
function GetSocketClass: TLSocketClass;
|
|
procedure SetSocketClass(Value: TLSocketClass);
|
|
|
|
function GetSession: TLSession;
|
|
procedure SetSesssion(const AValue: TLSession);
|
|
procedure SetCreator(AValue: TLComponent); override;
|
|
|
|
procedure StackFull;
|
|
procedure DoubleIAC(var s: string);
|
|
function TelnetParse(const msg: string): Integer;
|
|
function React(const Operation, Command: Char): boolean; virtual; abstract;
|
|
procedure SendCommand(const Command: Char; const Value: Boolean); virtual; abstract;
|
|
|
|
procedure OnCs(aSocket: TLSocket);
|
|
public
|
|
constructor Create(aOwner: TComponent); override;
|
|
destructor Destroy; override;
|
|
|
|
function Get(out aData; const aSize: Integer; aSocket: TLSocket = nil): Integer; virtual; abstract;
|
|
function GetMessage(out msg: string; aSocket: TLSocket = nil): Integer; virtual; abstract;
|
|
|
|
function Send(const aData; const aSize: Integer; aSocket: TLSocket = nil): Integer; virtual; abstract;
|
|
function SendMessage(const msg: string; aSocket: TLSocket = nil): Integer; virtual; abstract;
|
|
|
|
function OptionIsSet(const Option: Char): Boolean;
|
|
function RegisterOption(const aOption: Char; const aCommand: Boolean): Boolean;
|
|
procedure SetOption(const Option: Char);
|
|
procedure UnSetOption(const Option: Char);
|
|
|
|
function RegisterSubcommand(aOption: char; callback: TLSubcommandCallback;
|
|
const defaultResponse: string= ''; requiredParams: integer= 0): boolean;
|
|
|
|
procedure Disconnect(const Forced: Boolean = True); override;
|
|
|
|
procedure SendCommand(const aCommand: Char; const How: TLHowEnum); virtual;
|
|
public
|
|
property Output: TMemoryStream read FOutput;
|
|
property Connected: Boolean read GetConnected;
|
|
property Timeout: Integer read GetTimeout write SetTimeout;
|
|
property OnReceive: TLSocketEvent read FOnReceive write FOnReceive;
|
|
property OnDisconnect: TLSocketEvent read FOnDisconnect write FOnDisconnect;
|
|
property OnConnect: TLSocketEvent read FOnConnect write FOnConnect;
|
|
property OnError: TLSocketErrorEvent read FOnError write FOnError;
|
|
property Connection: TLTCP read FConnection;
|
|
property SocketClass: TLSocketClass read GetSocketClass write SetSocketClass;
|
|
property Session: TLSession read GetSession write SetSesssion;
|
|
end;
|
|
|
|
{ TLTelnetClient }
|
|
|
|
TLTelnetClient = class(TLTelnet, ILClient)
|
|
protected
|
|
FLocalEcho: Boolean;
|
|
procedure OnEr(const msg: string; aSocket: TLSocket);
|
|
procedure OnDs(aSocket: TLSocket);
|
|
procedure OnRe(aSocket: TLSocket);
|
|
procedure OnCo(aSocket: TLSocket);
|
|
|
|
function React(const Operation, Command: Char): boolean; override;
|
|
|
|
procedure SendCommand(const Command: Char; const Value: Boolean); override;
|
|
public
|
|
constructor Create(aOwner: TComponent); override;
|
|
|
|
function Connect(const anAddress: string; const aPort: Word): Boolean;
|
|
function Connect: Boolean;
|
|
|
|
function Get(out aData; const aSize: Integer; aSocket: TLSocket = nil): Integer; override;
|
|
function GetMessage(out msg: string; aSocket: TLSocket = nil): Integer; override;
|
|
|
|
function Send(const aData; const aSize: Integer; aSocket: TLSocket = nil): Integer; override;
|
|
function SendMessage(const msg: string; aSocket: TLSocket = nil): Integer; override;
|
|
|
|
procedure CallAction; override;
|
|
public
|
|
property LocalEcho: Boolean read FLocalEcho write FLocalEcho;
|
|
end;
|
|
|
|
|
|
function LTelnetSubcommandCallback(command: char; const parameters, defaultResponse: string): string;
|
|
|
|
implementation
|
|
|
|
uses
|
|
Math;
|
|
|
|
const subcommandEndLength= 2;
|
|
|
|
var
|
|
zz: Char;
|
|
TNames: array[Char] of string;
|
|
|
|
//*******************************TLTelnetClient********************************
|
|
|
|
constructor TLTelnet.Create(aOwner: TComponent);
|
|
begin
|
|
inherited Create(aOwner);
|
|
|
|
FConnection := TLTCP.Create(nil);
|
|
FConnection.Creator := Self;
|
|
FConnection.OnCanSend := @OnCs;
|
|
|
|
FOutput := TMemoryStream.Create;
|
|
FCommandCharIndex := 0;
|
|
FStack := TLControlStack.Create;
|
|
FStack.OnFull := @StackFull;
|
|
end;
|
|
|
|
destructor TLTelnet.Destroy;
|
|
begin
|
|
Disconnect(True);
|
|
FOutput.Free;
|
|
FConnection.Free;
|
|
FStack.Free;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
function TLTelnet.GetConnected: Boolean;
|
|
begin
|
|
Result := FConnection.Connected;
|
|
end;
|
|
|
|
function TLTelnet.GetSession: TLSession;
|
|
begin
|
|
Result := FConnection.Session;
|
|
end;
|
|
|
|
procedure TLTelnet.SetSesssion(const AValue: TLSession);
|
|
begin
|
|
FConnection.Session := aValue;
|
|
end;
|
|
|
|
procedure TLTelnet.SetCreator(AValue: TLComponent);
|
|
begin
|
|
inherited SetCreator(AValue);
|
|
FConnection.Creator := aValue;
|
|
end;
|
|
|
|
procedure TLTelnet.InflateBuffer;
|
|
var
|
|
n: Integer;
|
|
begin
|
|
n := Max(Length(FBuffer), 25);
|
|
SetLength(FBuffer, n * 10);
|
|
end;
|
|
|
|
function TLTelnet.AddToBuffer(const aStr: string): Boolean; inline;
|
|
begin
|
|
Result := False;
|
|
|
|
while Length(aStr) + FBufferEnd > Length(FBuffer) do
|
|
InflateBuffer;
|
|
|
|
Move(aStr[1], FBuffer[FBufferEnd], Length(aStr));
|
|
Inc(FBufferEnd, Length(aStr));
|
|
end;
|
|
|
|
function TLTelnet.Question(const Command: Char; const Value: Boolean): Char;
|
|
begin
|
|
Result := TS_NOP;
|
|
if Value then begin
|
|
if Command in FOrders then
|
|
Result := TS_DO
|
|
else
|
|
Result := TS_WILL;
|
|
end else begin
|
|
if Command in FOrders then
|
|
Result := TS_DONT
|
|
else
|
|
Result := TS_WONT;
|
|
end;
|
|
end;
|
|
|
|
function TLTelnet.GetSocketClass: TLSocketClass;
|
|
begin
|
|
Result := FConnection.SocketClass;
|
|
end;
|
|
|
|
function TLTelnet.GetTimeout: Integer;
|
|
begin
|
|
Result := FConnection.Timeout;
|
|
end;
|
|
|
|
procedure TLTelnet.SetSocketClass(Value: TLSocketClass);
|
|
begin
|
|
FConnection.SocketClass := Value;
|
|
end;
|
|
|
|
procedure TLTelnet.SetTimeout(const Value: Integer);
|
|
begin
|
|
FConnection.Timeout := Value;
|
|
end;
|
|
|
|
procedure TLTelnet.StackFull;
|
|
begin
|
|
{$ifdef debug}
|
|
Writeln('**STACKFULL**');
|
|
{$endif}
|
|
if FStack[1] = TS_IAC then
|
|
begin
|
|
FOutput.WriteByte(Byte(FStack[1]));
|
|
FOutput.WriteByte(Byte(FStack[2]));
|
|
FStack.Clear
|
|
end else
|
|
if React(FStack[1], FStack[2]) then
|
|
FStack.Clear
|
|
end;
|
|
|
|
procedure TLTelnet.DoubleIAC(var s: string);
|
|
var
|
|
i: Longint;
|
|
begin
|
|
i := 0;
|
|
if Length(s) > 0 then
|
|
while i < Length(s) do begin
|
|
Inc(i);
|
|
if s[i] = TS_IAC then begin
|
|
Insert(TS_IAC, s, i);
|
|
Inc(i, 2);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TLTelnet.TelnetParse(const msg: string): Integer;
|
|
var
|
|
i: Longint;
|
|
begin
|
|
Result := 0;
|
|
for i := 1 to Length(msg) do
|
|
if (FStack.ItemIndex > 0) or (msg[i] = TS_IAC) then begin
|
|
if msg[i] = TS_GA then
|
|
FStack.Clear
|
|
else
|
|
FStack.Push(msg[i])
|
|
end else begin
|
|
FOutput.WriteByte(Byte(msg[i]));
|
|
Inc(Result);
|
|
end;
|
|
end;
|
|
|
|
procedure TLTelnet.OnCs(aSocket: TLSocket);
|
|
var
|
|
n: Integer;
|
|
begin
|
|
n := 1;
|
|
|
|
while (n > 0) and (FBufferIndex < FBufferEnd) do begin
|
|
n := FConnection.Send(FBuffer[FBufferIndex], FBufferEnd - FBufferIndex);
|
|
|
|
if n > 0 then
|
|
Inc(FBufferIndex, n);
|
|
end;
|
|
|
|
if FBufferEnd - FBufferIndex < FBufferIndex then begin // if we can move the "right" side of the buffer back to the left
|
|
Move(FBuffer[FBufferIndex], FBuffer[0], FBufferEnd - FBufferIndex);
|
|
FBufferEnd := FBufferEnd - FBufferIndex;
|
|
FBufferIndex := 0;
|
|
end;
|
|
end;
|
|
|
|
function TLTelnet.OptionIsSet(const Option: Char): Boolean;
|
|
begin
|
|
Result := False;
|
|
Result := Option in FActiveOpts;
|
|
end;
|
|
|
|
function TLTelnet.RegisterOption(const aOption: Char;
|
|
const aCommand: Boolean): Boolean;
|
|
begin
|
|
Result := False;
|
|
if not (aOption in FPossible) then begin
|
|
FPossible := FPossible + [aOption];
|
|
if aCommand then
|
|
FOrders := FOrders + [aOption];
|
|
Result := True;
|
|
end;
|
|
end;
|
|
|
|
procedure TLTelnet.SetOption(const Option: Char);
|
|
begin
|
|
if Option in FPossible then
|
|
SendCommand(Option, True);
|
|
end;
|
|
|
|
procedure TLTelnet.UnSetOption(const Option: Char);
|
|
begin
|
|
if Option in FPossible then
|
|
SendCommand(Option, False);
|
|
end;
|
|
|
|
(* If already set, the callback can be reverted to nil but it can't be changed *)
|
|
(* in a single step. The default response, if specified, is used by the *)
|
|
(* LTelnetSubcommandCallback() function and is available to others; the *)
|
|
(* callback will not be invoked until there is at least the indicated number of *)
|
|
(* parameter bytes available. *)
|
|
//
|
|
function TLTelnet.RegisterSubcommand(aOption: char; callback: TLSubcommandCallback;
|
|
const defaultResponse: string= ''; requiredParams: integer= 0): boolean;
|
|
|
|
begin
|
|
result := (not Assigned(FSubcommandCallbacks[aOption].callback)) or (@callback = nil);
|
|
if result then begin
|
|
FSubcommandCallbacks[aOption].callback := callback;
|
|
FSubcommandCallbacks[aOption].defaultResponse := defaultResponse;
|
|
Inc(requiredParams, subcommandEndLength);
|
|
if requiredParams < 0 then (* Assume -subcommandEndLength is a *)
|
|
requiredParams := 0; (* valid parameter. *)
|
|
FSubcommandCallbacks[aOption].requiredParams := requiredParams;
|
|
end
|
|
end { TLTelnet.RegisterSubcommand } ;
|
|
|
|
procedure TLTelnet.Disconnect(const Forced: Boolean = True);
|
|
begin
|
|
FConnection.Disconnect(Forced);
|
|
end;
|
|
|
|
procedure TLTelnet.SendCommand(const aCommand: Char; const How: TLHowEnum);
|
|
begin
|
|
{$ifdef debug}
|
|
Writeln('**SENT** ', TNames[Char(How)], ' ', TNames[aCommand]);
|
|
{$endif}
|
|
AddToBuffer(TS_IAC + Char(How) + aCommand);
|
|
OnCs(nil);
|
|
end;
|
|
|
|
//****************************TLTelnetClient*****************************
|
|
|
|
constructor TLTelnetClient.Create(aOwner: TComponent);
|
|
begin
|
|
inherited Create(aOwner);
|
|
FConnection.OnError := @OnEr;
|
|
FConnection.OnDisconnect := @OnDs;
|
|
FConnection.OnReceive := @OnRe;
|
|
FConnection.OnConnect := @OnCo;
|
|
|
|
FPossible := [TS_ECHO, TS_HYI, TS_SGA];
|
|
FActiveOpts := [];
|
|
FOrders := [];
|
|
end;
|
|
|
|
procedure TLTelnetClient.OnEr(const msg: string; aSocket: TLSocket);
|
|
begin
|
|
if Assigned(FOnError) then
|
|
FOnError(msg, aSocket)
|
|
else
|
|
FOutput.Write(Pointer(msg)^, Length(msg));
|
|
end;
|
|
|
|
procedure TLTelnetClient.OnDs(aSocket: TLSocket);
|
|
begin
|
|
if Assigned(FOnDisconnect) then
|
|
FOnDisconnect(aSocket);
|
|
end;
|
|
|
|
procedure TLTelnetClient.OnRe(aSocket: TLSocket);
|
|
var
|
|
s: string;
|
|
begin
|
|
if aSocket.GetMessage(s) > 0 then
|
|
if (TelnetParse(s) > 0) and Assigned(FOnReceive) then
|
|
FOnReceive(aSocket);
|
|
end;
|
|
|
|
procedure TLTelnetClient.OnCo(aSocket: TLSocket);
|
|
begin
|
|
if Assigned(FOnConnect) then
|
|
FOnConnect(aSocket);
|
|
end;
|
|
|
|
function TLTelnetClient.React(const Operation, Command: Char): boolean;
|
|
|
|
procedure Accept(const Operation, Command: Char);
|
|
begin
|
|
FActiveOpts := FActiveOpts + [Command];
|
|
{$ifdef debug}
|
|
Writeln('**SENT** ', TNames[Operation], ' ', TNames[Command]);
|
|
{$endif}
|
|
AddToBuffer(TS_IAC + Operation + Command);
|
|
OnCs(nil);
|
|
end;
|
|
|
|
procedure Refuse(const Operation, Command: Char);
|
|
begin
|
|
FActiveOpts := FActiveOpts - [Command];
|
|
{$ifdef debug}
|
|
Writeln('**SENT** ', TNames[Operation], ' ', TNames[Command]);
|
|
{$endif}
|
|
AddToBuffer(TS_IAC + Operation + Command);
|
|
OnCs(nil);
|
|
end;
|
|
|
|
(* Retrieve the parameters from the current instance, and pass them explicitly *)
|
|
(* to the callback. Return false if there are insufficient parameters on the *)
|
|
(* stack. *)
|
|
//
|
|
function subcommand(command: char): boolean;
|
|
|
|
var parameters, response: string;
|
|
i: integer;
|
|
|
|
begin
|
|
FStack.AllowInflation := true; (* We might need more than the standard *)
|
|
if FStack.ItemIndex > 65536 then (* command, but protect against parse *)
|
|
{%H- 6018 } exit(true); (* failure which could be a DoS attack. *)
|
|
i := FStack.ItemIndex - TL_CSLENGTH; (* Number of parameter bytes available.*)
|
|
if i < FSubcommandCallbacks[command].requiredParams then
|
|
exit(false); (* Early insufficient-parameters decision *)
|
|
result := true;
|
|
if FStack.ItemIndex > TL_CSLENGTH then begin
|
|
SetLength(parameters, FStack.ItemIndex - TL_CSLENGTH );
|
|
Move(FStack[3], parameters[1], FStack.ItemIndex - TL_CSLENGTH );
|
|
if (Length(parameters) >= 2) and (parameters[Length(parameters)] = TS_IAC) and
|
|
(parameters[Length(parameters) - 1] <> TS_IAC) then
|
|
exit(false); (* Special case: need at least one more *)
|
|
i := 1;
|
|
while i <= Length(parameters) - 1 do (* Undouble IACs *)
|
|
if (parameters[i] = TS_IAC) and (parameters[i + 1] = TS_IAC) then
|
|
Delete(parameters, i, 1)
|
|
else
|
|
Inc(i)
|
|
end else
|
|
parameters := '';
|
|
if Length(parameters) < FSubcommandCallbacks[command].requiredParams then
|
|
exit(false); (* Insufficient params after IAC undouble *)
|
|
if (FSubcommandCallbacks[command].requiredParams >= subcommandEndLength) and
|
|
(Length(parameters) >= subcommandEndLength) then
|
|
SetLength(parameters, Length(parameters) - subcommandEndLength);
|
|
try
|
|
response := FSubcommandCallbacks[command].callback(command, parameters,
|
|
FSubcommandCallbacks[command].defaultResponse)
|
|
except
|
|
on e: EInsufficientSubcommandParameters do
|
|
Exit(false) (* Late insufficient-parameters decision *)
|
|
else
|
|
Raise (* Application-specific error *)
|
|
end;
|
|
DoubleIAC(response);
|
|
AddToBuffer(TS_IAC + TS_SB + command + response + TS_IAC + TS_SE);
|
|
OnCs(nil)
|
|
end { subcommand } ;
|
|
|
|
begin
|
|
result := true; (* Stack will normally be cleared *)
|
|
{$ifdef debug}
|
|
Writeln('**GOT** ', TNames[Operation], ' ', TNames[Command]);
|
|
{$endif}
|
|
case Operation of
|
|
TS_DO : if Command in FPossible then Accept(TS_WILL, Command)
|
|
else Refuse(TS_WONT, Command);
|
|
|
|
TS_DONT : if Command in FPossible then Refuse(TS_WONT, Command);
|
|
|
|
TS_WILL : if Command in FPossible then FActiveOpts := FActiveOpts + [Command]
|
|
else Refuse(TS_DONT, Command);
|
|
|
|
TS_WONT : if Command in FPossible then FActiveOpts := FActiveOpts - [Command];
|
|
TS_SB : if not Assigned(FSubcommandCallbacks[command].callback) then
|
|
refuse(TS_WONT, command)
|
|
else
|
|
result := subcommand(command)
|
|
|
|
(* In the final case above, the stack will not be cleared if sufficient *)
|
|
(* parameters to keep the subcommand happy have not yet been parsed out of the *)
|
|
(* message. *)
|
|
|
|
end;
|
|
end;
|
|
|
|
procedure TLTelnetClient.SendCommand(const Command: Char; const Value: Boolean);
|
|
begin
|
|
if Connected then begin
|
|
{$ifdef debug}
|
|
Writeln('**SENT** ', TNames[Question(Command, Value)], ' ', TNames[Command]);
|
|
{$endif}
|
|
case Question(Command, Value) of
|
|
TS_WILL : FActiveOpts := FActiveOpts + [Command];
|
|
end;
|
|
AddToBuffer(TS_IAC + Question(Command, Value) + Command);
|
|
OnCs(nil);
|
|
end;
|
|
end;
|
|
|
|
function TLTelnetClient.Connect(const anAddress: string; const aPort: Word): Boolean;
|
|
begin
|
|
Result := FConnection.Connect(anAddress, aPort);
|
|
end;
|
|
|
|
function TLTelnetClient.Connect: Boolean;
|
|
begin
|
|
Result := FConnection.Connect(FHost, FPort);
|
|
end;
|
|
|
|
function TLTelnetClient.Get(out aData; const aSize: Integer; aSocket: TLSocket): Integer;
|
|
begin
|
|
Result := FOutput.Read(aData {%H- 5058 } , aSize);
|
|
if FOutput.Position = FOutput.Size then
|
|
FOutput.Clear;
|
|
end;
|
|
|
|
function TLTelnetClient.GetMessage(out msg: string; aSocket: TLSocket): Integer;
|
|
begin
|
|
Result := 0;
|
|
msg := '';
|
|
if FOutput.Size > 0 then begin
|
|
FOutput.Position := 0;
|
|
SetLength(msg, FOutput.Size);
|
|
Result := FOutput.Read(PChar(msg)^, Length(msg));
|
|
FOutput.Clear;
|
|
end;
|
|
end;
|
|
|
|
function TLTelnetClient.Send(const aData; const aSize: Integer;
|
|
aSocket: TLSocket): Integer;
|
|
var
|
|
Tmp: string;
|
|
begin
|
|
{$ifdef debug}
|
|
Writeln('**SEND START** ');
|
|
{$endif}
|
|
Result := 0;
|
|
if aSize > 0 then begin
|
|
SetLength(Tmp, aSize);
|
|
Move(aData, PChar(Tmp)^, aSize);
|
|
DoubleIAC(Tmp);
|
|
if LocalEcho and (not OptionIsSet(TS_ECHO)) and (not OptionIsSet(TS_HYI)) then
|
|
FOutput.Write(PChar(Tmp)^, Length(Tmp));
|
|
|
|
AddToBuffer(Tmp);
|
|
OnCs(nil);
|
|
|
|
Result := aSize;
|
|
end;
|
|
{$ifdef debug}
|
|
Writeln('**SEND END** ');
|
|
{$endif}
|
|
end;
|
|
|
|
function TLTelnetClient.SendMessage(const msg: string; aSocket: TLSocket
|
|
): Integer;
|
|
begin
|
|
Result := Send(PChar(msg)^, Length(msg));
|
|
end;
|
|
|
|
procedure TLTelnetClient.CallAction;
|
|
begin
|
|
FConnection.CallAction;
|
|
end;
|
|
|
|
(* This is a default callback for use with the RegisterSubcommand() method. It *)
|
|
(* may be used where the result is unchanging, for example in order to return *)
|
|
(* the terminal type. *)
|
|
//
|
|
function LTelnetSubcommandCallback(command: char; const parameters, defaultResponse: string): string;
|
|
|
|
begin
|
|
result := defaultResponse
|
|
end { LTelnetSubcommandCallback } ;
|
|
|
|
|
|
initialization
|
|
for zz := #0 to #255 do
|
|
TNames[zz] := IntToStr(Ord(zz));
|
|
TNames[#1] := 'TS_ECHO';
|
|
TNames[#133] := 'TS_HYI';
|
|
TNames[#251] := 'TS_WILL';
|
|
TNames[#252] := 'TS_WONT';
|
|
TNames[#253] := 'TS_DO';
|
|
TNames[#254] := 'TS_DONT';
|
|
|
|
end.
|
|
|