mirror of
				https://gitlab.com/freepascal.org/fpc/source.git
				synced 2025-11-04 02:19:22 +01:00 
			
		
		
		
	* Patch from Mark Morgan Lloyd to add subcommands to ltelnet. Mantis #22032
git-svn-id: trunk@21340 -
This commit is contained in:
		
							parent
							
								
									1294ea4357
								
							
						
					
					
						commit
						a7ee1899bc
					
				@ -68,7 +68,14 @@ type
 | 
			
		||||
  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
 | 
			
		||||
                     end;
 | 
			
		||||
  TLSubcommandArray= array[#$00..#$ff] of TLSubcommandEntry;
 | 
			
		||||
 | 
			
		||||
  { TLTelnet }
 | 
			
		||||
 | 
			
		||||
  TLTelnet = class(TLComponent, ILDirect)
 | 
			
		||||
@ -89,6 +96,7 @@ type
 | 
			
		||||
    FBuffer: array of Char;
 | 
			
		||||
    FBufferIndex: Integer;
 | 
			
		||||
    FBufferEnd: Integer;
 | 
			
		||||
    FSubcommandCallbacks: TLSubcommandArray;
 | 
			
		||||
    procedure InflateBuffer;
 | 
			
		||||
    function AddToBuffer(const aStr: string): Boolean; inline;
 | 
			
		||||
    
 | 
			
		||||
@ -127,7 +135,9 @@ type
 | 
			
		||||
    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= ''): boolean;
 | 
			
		||||
 | 
			
		||||
    procedure Disconnect(const Forced: Boolean = True); override;
 | 
			
		||||
    
 | 
			
		||||
    procedure SendCommand(const aCommand: Char; const How: TLHowEnum); virtual;
 | 
			
		||||
@ -173,7 +183,10 @@ type
 | 
			
		||||
   public
 | 
			
		||||
    property LocalEcho: Boolean read FLocalEcho write FLocalEcho;
 | 
			
		||||
  end;
 | 
			
		||||
  
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
function LTelnetSubcommandCallback(command: char; const parameters, defaultResponse: string): string;
 | 
			
		||||
 | 
			
		||||
implementation
 | 
			
		||||
 | 
			
		||||
uses
 | 
			
		||||
@ -379,6 +392,20 @@ begin
 | 
			
		||||
    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.             *)
 | 
			
		||||
//
 | 
			
		||||
function TLTelnet.RegisterSubcommand(aOption: char; callback: TLSubcommandCallback; const defaultResponse: string= ''): boolean;
 | 
			
		||||
 | 
			
		||||
begin
 | 
			
		||||
  result := (not Assigned(FSubcommandCallbacks[aOption].callback)) or (@callback = nil);
 | 
			
		||||
  if result then begin
 | 
			
		||||
    FSubcommandCallbacks[aOption].callback := callback;
 | 
			
		||||
    FSubcommandCallbacks[aOption].defaultResponse := defaultResponse
 | 
			
		||||
  end
 | 
			
		||||
end { TLTelnet.RegisterSubcommand } ;
 | 
			
		||||
 | 
			
		||||
procedure TLTelnet.Disconnect(const Forced: Boolean = True);
 | 
			
		||||
begin
 | 
			
		||||
  FConnection.Disconnect(Forced);
 | 
			
		||||
@ -458,7 +485,33 @@ procedure TLTelnetClient.React(const Operation, Command: Char);
 | 
			
		||||
    AddToBuffer(TS_IAC + Operation + Command);
 | 
			
		||||
    OnCs(nil);
 | 
			
		||||
  end;
 | 
			
		||||
  
 | 
			
		||||
 | 
			
		||||
(* Retrieve the parameters from the current instance, and pass them explicitly  *)
 | 
			
		||||
(* to the callback.                                                             *)
 | 
			
		||||
//
 | 
			
		||||
  procedure subcommand(command: char);
 | 
			
		||||
 | 
			
		||||
  var   parameters, response: string;
 | 
			
		||||
        i: integer;
 | 
			
		||||
 | 
			
		||||
  begin
 | 
			
		||||
    if FStack.ItemIndex > 5 then begin
 | 
			
		||||
      SetLength(parameters, FStack.ItemIndex - 5);
 | 
			
		||||
      Move(FStack[3], parameters[1], FStack.ItemIndex - 5);
 | 
			
		||||
      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 := '';
 | 
			
		||||
    response := FSubcommandCallbacks[command].callback(command, parameters, FSubcommandCallbacks[command].defaultResponse);
 | 
			
		||||
    DoubleIAC(response);
 | 
			
		||||
    AddToBuffer(TS_IAC + TS_SB + command + response + TS_IAC + TS_SE);
 | 
			
		||||
    OnCs(nil)
 | 
			
		||||
  end { subcommand } ;
 | 
			
		||||
 | 
			
		||||
begin
 | 
			
		||||
  {$ifdef debug}
 | 
			
		||||
  Writeln('**GOT** ', TNames[Operation], ' ', TNames[Command]);
 | 
			
		||||
@ -473,6 +526,10 @@ begin
 | 
			
		||||
              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
 | 
			
		||||
                subcommand(command)
 | 
			
		||||
  end;
 | 
			
		||||
end;
 | 
			
		||||
 | 
			
		||||
@ -556,6 +613,17 @@ 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));
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user