Question

Using Indy10 - DelphiXE. How do I tell the telnet server I am connecting to with TIdTelnet to not echo the commands I send towards the telnet server?

This is my current attempt (which doesn't work), I try to send the sequence IAC DO SUPPRESS_LOCAL_ECHO on each telnet write but I do believe this has to be done in the negotiating phase?

uses
  TIdTelnet,

...
procedure TIOTelnetConnection.SendSupressEcho;

var
  Resp: TIdBytes;

begin
 SetLength(Resp, 3);
 Resp[0] := TNC_IAC;
 Resp[1] := TNC_DO;
 Resp[2] := TNO_SUPLOCALECHO;
 FIOConnection.IOHandler.Write(Resp);
end;

procedure TIOTelnetConnection.Write(Str: AnsiString);
begin
 SendSupressEcho;
 if Str <> '' then
  FIOConnection.IOHandler.Write(Str);
end;

looking at the TIdTelnet source I see the Negotiate procedure, but it is protected, how can I override it's behaviour?

Was it helpful?

Solution

If the server sends an IAC WILL ECHO to you, TIdTelnet is hard-coded to send an IAC DO ECHO response, and then triggers an OnTelnetCommand(tncNoLocalEcho) event to tell you not to locally echo what you send.

If the server sends an IAC WONT ECHO to you, TIdTelnet is hard-coded to send an IAC DONT ECHO response, and then triggers an OnTelnetCommand(tncLocalEcho) event to tell you to locally echo what you send.

If the server sends an IAC DO ECHO to you, TIdTelnet is hard-coded to send an IAC WILL ECHO response, and then triggers an OnTelnetCommand(tncEcho) event to tell you to echo back whatever you receive.

If the server sends an IAC DONT ECHO to you, TIdTelnet is hard-coded to send an IAC WONT ECHO response, and then triggers an OnTelnetCommand(tncLocalEcho) event to tell you to echo back whatever you receive.

So, if you don't want the server to echo back to you, you can send an IAC DONT ECHO command to the server, not an IAC DO SUPLOCALECHO command. The server will then reply with either IAC WONT ECHO or IAC WILL ECHO accordingly (which apparently TIdTelnet will then reply to, but the server will not respond back again since its ECHO current state does not change, avoiding an endless response loop).

OTHER TIPS

@Remy Lebeau: As I understand it, you're saying: If the server sends an IAC DO ECHO to you, TIdTelnet is hard-coded to send an IAC WILL ECHO response, and then triggers an OnTelnetCommand( tncEcho ) event to tell you to echo back whatever you receive.

That makes sense and agrees with what the RFC857 sets out to achieve...

However, in the code we have:

procedure TIdTelnet.Negotiate;
...
      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;

and

  TNC_DO:
    begin
      b := IOHandler.ReadByte;
      case b of
        TNO_ECHO:
          begin
            Reply := TNC_WILL;
            DoTelnetCommand(tncLocalEcho);
          end;

Surely this code is not correct? (in version 10.6.0.497 of Indy)

I believe this would make more sense:

 procedure TIdTelnet.Negotiate;
 ...
      TNC_DONT:
         begin
           b := IOHandler.ReadByte;
           case b of
             TNO_ECHO:
               begin
               // Agree not to echo back everything received from server 
               // (This being the default - you shouldn't echo unless asked to)
                  Reply := TNC_WONT;            
               // Therefore only print locally what is sent to server
               // (Again: this is the default behavior without negotiation) 
                  DoTelnetCommand(tncLocalEcho);
               end;
             else
               Reply := TNC_WONT;
           end;

and

   TNC_DO:
     begin
       b := IOHandler.ReadByte;
       case b of
         TNO_ECHO:
           begin
           // Agree to echo back everything received from server 
              Reply := TNC_WILL;
              DoTelnetCommand(tncEcho); 
           // Therefore you may still have to locally print what you send
           // (i.e. local echo is usually still implicit in this)
           end;   

In other words, I believe the code is presently swapped from what it should be - which is that the server sending DO ECHO should beget the tncEcho token - which is what you said in the above quote!

How has this bug survived this long? (probably because most Telnet servers don't bother with RFC857 echo negotiation any more)

Unfortunately the only way I see to "compensate" for this bug at the moment is to create a copy of the IDTelnet.pas file; link that to your project in the Project Manager; and then make the corrections to that copy as outlined above.

To tackle the original question: "How to supress echo with TIdTelnet?", I would suggest the following steps:

  1. Add a TIdConnectionIntercept to your form and hook it into your TIdTelnet component via the Intercept property using the Object Inspector.

  2. Produce the event handler for the TIdConnectionIntercept OnSend event.

  3. Use this to detect when its var ABuffer: TIdBytes parameter gets the response to the server's negotiation command regarding echoing. Note that buffer WILL have EXACTLY and ONLY all three bytes of the response in it due to the way the response is stuffed and sent by TIdTelnet.Negotiate

  4. Alter the middle byte as desired (i.e. to enforce a change from WILL to WONT or DO to DONT to suit what you are trying to enforce).

Job's a "good-un"

Remember of course that this technique injects the change AFTER TidTelnet OnTelnetCommand is called, so you will have to alter anything you set up in that handler to suite your modified response.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top