0

I need to run my Delphi application in console mode so that I can run it on my VPS as a Wine emulated application on my Linux server so that it communicates via telnet to my Teamspeak server as serverquery. It needs to stay constantly stay connected and move players out of one channel into another channel, so passively using PHP is not an option. I know TS3 bots already exist, but none are programmed in Delphi for Teamspeak 3. The program works flawlessly in the Windows application, but just hangs in the console version.

I have indy setup IdTelnet1.ThreadedEvent := true in the datamodule which only seemed to somewhat help. I'm guessing somehow I need to talk with that thread, but not sure how.

I have tried to do it this way, but the program just hangs:

program TS3bot;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  System.SysUtils,
  Unit1 in 'Unit1.pas' {DataModule1: TDataModule};

begin
  try
    DataModule1 := TDataModule1.Create(nil);
    try
      { TODO -oUser -cConsole Main : Insert code here }
      DataModule1.IdTelnet1.Connect;
      DataModule1.IdTelnet1.TelnetThread.Start;
      repeat
        //
      until (DataModule1.IdTelnet1.Connected = false);
      DataModule1.IdTelnet1.TelnetThread.Stop;
    except
      on E: Exception do
        Writeln(E.ClassName, ': ', E.Message);
    end;
  finally
    writeln('Program ended.');
    DataModule1.Free;
  end;
end.

UNIT1

unit Unit1;

interface

uses
  System.SysUtils, System.Classes, IdBaseComponent, IdComponent,
  IdTCPConnection, IdTCPClient, IdTelnet, IdGlobal;

type
  TDataModule1 = class(TDataModule)
    IdTelnet1: TIdTelnet;
    procedure IdTelnet1Connected(Sender: TObject);
    procedure IdTelnet1DataAvailable(Sender: TIdTelnet; const Buffer: TIdBytes);
    procedure IdTelnet1Disconnected(Sender: TObject);
    procedure DataModuleDestroy(Sender: TObject);
  private
    { Private declarations }
    procedure processCommand(Command : string);
    procedure processCommands;
    procedure InterpetBuffer(Buffer: string);
  public
    { Public declarations }
  end;

Const
  Elements = (3); //(Elements - 1)
  ListOfOnConnectCommands : array [0..Elements] of string =
  ('login serverquery password',
  'use 1',
  'clientupdate client_nickname=NickNameServer',
  'servernotifyregister event=server');

var
  DataModule1: TDataModule1;
  BufferNumber: integer = 0;
  CommandSent : boolean = false;
  CommandOK : boolean = false;
  CommandNumber : integer = 0;

implementation

{%CLASSGROUP 'System.Classes.TPersistent'}

{$R *.dfm}

procedure pSplitIT(BreakString, BaseString: string; StringList: TStrings);
var
  EndOfCurrentString: byte;
begin
  StringList.Clear;

  repeat
    EndOfCurrentString := Pos(BreakString, BaseString);

    if EndOfCurrentString = 0 then
      StringList.add(BaseString)
    else
      StringList.add(Copy(BaseString, 1, EndOfCurrentString - 1));
    BaseString := Copy(BaseString, EndOfCurrentString + length(BreakString), length(BaseString) - EndOfCurrentString);

  until EndOfCurrentString = 0;
end;

procedure TDataModule1.processCommand(Command : string);
begin
  writeln('processCommand: ' + Command);
  IdTelnet1.SendString(Command);
  IdTelnet1.SendCh(#10);
  IdTelnet1.SendCh(#13);
end;

procedure TDataModule1.processCommands;
var
  MyString: string;
begin
  if CommandNumber <= Elements then
  begin
    MyString := ListOfOnConnectCommands[CommandNumber];
    writeln('processCommands: ' + MyString);
    IdTelnet1.SendString(MyString);
    IdTelnet1.SendCh(#10);
    IdTelnet1.SendCh(#13);
    inc(CommandNumber);
    //exit;
  end;
end;

procedure TDataModule1.InterpetBuffer(Buffer: string);
var
  MyTstringlist: Tstringlist;
  MyBuffer: string;
  I: integer;
  clid: integer;
  member, legionnaire, enteredGuestChannel: boolean;
begin
  enteredGuestChannel := false;
  member := false;
  legionnaire := false;

  inc(BufferNumber);
  writeln('---------------------------------------------------------');
  writeln('IdTelnet1DataAvailable BufferNumber: ' + BufferNumber.ToString);
  writeln('---------------------------------------------------------');

  if Pos('notifycliententerview',Buffer)>0 then
    begin
      writeln('----------------------');
      writeln('EXIT notifycliententerview:');
      writeln(Buffer);

      MyTstringlist := Tstringlist.Create;
      MyBuffer := Buffer;

      pSplitIT(' ',MyBuffer,MyTstringlist);
      writeln('COUNT: ' + MyTstringlist.Count.ToString);
      for I := 0 to MyTstringlist.Count - 1 do
      begin
        writeln(MyTstringlist.Strings[I]);
        if MyTstringlist.Strings[I] = 'ctid=45' then
        begin
          // client entered GUESTS CHANNEL, see if we can move them.
          enteredGuestChannel := true;
        end;
        if Pos('client_servergroups=',MyTstringlist.Strings[I]) > 0 then
        begin
          if Pos('18',MyTstringlist.Strings[I]) > 0 then
          begin
            member := true;
          end;
          if Pos('19',MyTstringlist.Strings[I]) > 0 then
          begin
            legionnaire := true;
          end;
          if Pos('28',MyTstringlist.Strings[I]) > 0 then
          begin
            legionnaire := true;
          end;
        end;
        //clid
        if Pos('clid=',MyTstringlist.Strings[I]) > 0 then
        begin
          clid := StrToInt(copy(MyTstringlist.Strings[I],6,high(MyTstringlist.Strings[I])));
        end;

      end;

      writeln('----------------------');

      MyTstringlist.Free;

      if ( (enteredGuestChannel = true)
        and (member = true) ) then
        begin
          processCommand('clientmove clid=' + clid.ToString + ' cid=47');
        end
      else if ( (enteredGuestChannel = true)
        and (legionnaire = true) ) then
        begin
          processCommand('clientmove clid=' + clid.ToString + ' cid=47');
        end;

      exit;
    end;

  // Create Returns in terminal
  if Pos(#10#13,Buffer)>0 then
    begin
      MyTstringlist := Tstringlist.Create;
      pSplitIT(#10#13,Buffer,MyTstringlist);
      writeln('COUNT: ' + MyTstringlist.Count.ToString);
      for I := 0 to MyTstringlist.Count - 1 do
      begin
        writeln(MyTstringlist.Strings[I]);
      end;
      MyTstringlist.Free;
    end
    else
    begin
      writeln(Buffer);
    end;

  if Pos('error id=0 msg=ok',Buffer)>0 then
    begin
      processCommands;
    end;

  writeln('');
end;

procedure TDataModule1.DataModuleDestroy(Sender: TObject);
begin
  processCommand('logout');
  processCommand('quit');
  IdTelnet1.Disconnect(true);
end;

procedure TDataModule1.IdTelnet1Connected(Sender: TObject);
begin
  writeln('IdTelnet1Connected');
//  sleep(5000);
  //writeln('processCommands:');
//  processCommands;
end;

procedure TDataModule1.IdTelnet1DataAvailable(Sender: TIdTelnet;
  const Buffer: TIdBytes);
begin
  InterpetBuffer(bytestostring(Buffer));
end;

procedure TDataModule1.IdTelnet1Disconnected(Sender: TObject);
begin
  writeln('IdTelnet1Disconnected');
end;

end.

Here is my original code from TForm:

unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, IdBaseComponent,
  IdComponent, IdTCPConnection, IdTCPClient, IdTelnet, IdGlobal, Vcl.ExtCtrls;

type
  TForm1 = class(TForm)
    Memo1: TMemo;
    Edit1: TEdit;
    IdTelnet1: TIdTelnet;
    Button1: TButton;
    Button2: TButton;
    Button3: TButton;
    Memo2: TMemo;
    Timer1: TTimer;
    Button4: TButton;
    IdSchedulerOfThreadDefault1: TIdSchedulerOfThreadDefault;
    procedure Button1Click(Sender: TObject);
    procedure IdTelnet1Disconnected(Sender: TObject);
    procedure IdTelnet1DataAvailable(Sender: TIdTelnet; const Buffer: TIdBytes);
    procedure Button3Click(Sender: TObject);
    procedure IdTelnet1Status(ASender: TObject; const AStatus: TIdStatus;
      const AStatusText: string);
    procedure IdTelnet1Connected(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure Timer1Timer(Sender: TObject);
    procedure Button4Click(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
    procedure InterpetBuffer(buffer: string);
    procedure processCommands;
    procedure processCommand(Command : string);
  public
    { Public declarations }
  end;

Const
  Elements = (3); //(Elements - 1)
  ListOfOnConnectCommands : array [0..Elements] of string =
  ('login severquery password',
  'use 1',
  'clientupdate client_nickname=NickNameServer',
  'servernotifyregister event=server');

var
  Form1: TForm1;
  BufferNumber: integer = 0;
  CommandSent : boolean = false;
  CommandOK : boolean = false;
  CommandNumber : integer = 0;

implementation

{$R *.dfm}


procedure pSplitIT(BreakString, BaseString: string; StringList: TStrings);
var
  EndOfCurrentString: byte;
begin
  StringList.Clear;

  repeat
    EndOfCurrentString := Pos(BreakString, BaseString);

    if EndOfCurrentString = 0 then
      StringList.add(BaseString)
    else
      StringList.add(Copy(BaseString, 1, EndOfCurrentString - 1));
    BaseString := Copy(BaseString, EndOfCurrentString + length(BreakString), length(BaseString) - EndOfCurrentString);

  until EndOfCurrentString = 0;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  BufferNumber := 0;
  IdTelnet1.Connect;
end;

procedure TForm1.Button2Click(Sender: TObject);
var
  MyString: string;
  I: integer;
begin
  MyString := edit1.Text;
  for I := Low(MyString) to High(MyString) do
  begin
    IdTelnet1.SendCh(MyString[I]);
  end;
  IdTelnet1.SendCh(#10);
  IdTelnet1.SendCh(#13);
  edit1.Text := '';
end;

procedure TForm1.Button3Click(Sender: TObject);
begin
  processCommand('logout');
  processCommand('quit');
  IdTelnet1.Disconnect(true);
end;

procedure TForm1.Button4Click(Sender: TObject);
begin
  processCommands;
end;

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  processCommand('logout');
  processCommand('quit');

  IdTelnet1.Disconnect(true);
end;

procedure TForm1.IdTelnet1Connected(Sender: TObject);
begin
  memo1.Lines.Add('IdTelnet1Connected');
  // Wait 1 second after connected to send commands.
  Timer1.Enabled := true;
end;

procedure TForm1.InterpetBuffer(Buffer: string);
var
  MyTstringlist: Tstringlist;
  MyBuffer: string;
  I: integer;
  //ctid: integer;
  clid: integer;
  member, legionnaire, enteredGuestChannel: boolean;
begin
  inc(BufferNumber);
  memo1.Lines.Add('---------------------------------------------------------');
  memo1.Lines.Add('IdTelnet1DataAvailable BufferNumber: ' + BufferNumber.ToString);
  memo1.Lines.Add('---------------------------------------------------------');

  OutputDebugString(PChar('IdTelnet1DataAvailable BufferNumber: ' + BufferNumber.ToString));

  if Pos('notifycliententerview',Buffer)>0 then
    begin
      memo1.Lines.Add('----------------------');
      memo1.Lines.Add('EXIT notifycliententerview:');
      memo1.Lines.Add(Buffer);

      MyTstringlist := Tstringlist.Create;
      MyBuffer := Buffer;

      pSplitIT(' ',MyBuffer,MyTstringlist);
      memo1.Lines.Add('COUNT: ' + MyTstringlist.Count.ToString);
      for I := 0 to MyTstringlist.Count - 1 do
      begin
        memo1.Lines.Add(MyTstringlist.Strings[I]);
        if MyTstringlist.Strings[I] = 'ctid=45' then
        begin
          // client entered GUESTS CHANNEL, see if we can move them.
          enteredGuestChannel := true;
        end;
        if Pos('client_servergroups=',MyTstringlist.Strings[I]) > 0 then
        begin
          if Pos('18',MyTstringlist.Strings[I]) > 0 then
          begin
            member := true;
          end;
          if Pos('19',MyTstringlist.Strings[I]) > 0 then
          begin
            legionnaire := true;
          end;
          if Pos('28',MyTstringlist.Strings[I]) > 0 then
          begin
            legionnaire := true;
          end;
        end;
        //clid
        if Pos('clid=',MyTstringlist.Strings[I]) > 0 then
        begin
          clid := StrToInt(copy(MyTstringlist.Strings[I],6,high(MyTstringlist.Strings[I])));
        end;

      end;

      memo1.Lines.Add('----------------------');

      MyTstringlist.Free;

      if ( (enteredGuestChannel = true)
        and (member = true) ) then
        begin
          processCommand('clientmove clid=' + clid.ToString + ' cid=47');
        end
      else if ( (enteredGuestChannel = true)
        and (legionnaire = true) ) then
        begin
          processCommand('clientmove clid=' + clid.ToString + ' cid=47');
        end;

      exit;
    end;

  // Create Returns in terminal
  if Pos(#10#13,Buffer)>0 then
    begin
      MyTstringlist := Tstringlist.Create;
      pSplitIT(#10#13,Buffer,MyTstringlist);
      memo1.Lines.Add('COUNT: ' + MyTstringlist.Count.ToString);
      for I := 0 to MyTstringlist.Count - 1 do
      begin
        memo1.Lines.Add(MyTstringlist.Strings[I]);
      end;
      MyTstringlist.Free;
    end
    else
    begin
      memo1.Lines.Add(Buffer);
    end;

  if Pos('error id=0 msg=ok',Buffer)>0 then
    begin
      processCommands;
    end;

  memo1.Lines.Add('');
end;

procedure TForm1.processCommand(Command : string);
begin
  memo2.Lines.Add('processCommand: ' + Command);
  IdTelnet1.SendString(Command);
  IdTelnet1.SendCh(#10);
  IdTelnet1.SendCh(#13);
end;

procedure TForm1.processCommands;
var
  MyString: string;
begin
  if CommandNumber <= Elements then
  begin
    MyString := ListOfOnConnectCommands[CommandNumber];
    memo2.Lines.Add('processCommands: ' + MyString);
    IdTelnet1.SendString(MyString);
    IdTelnet1.SendCh(#10);
    IdTelnet1.SendCh(#13);
    inc(CommandNumber);
  end;
end;

procedure TForm1.Timer1Timer(Sender: TObject);
begin
  if IdTelnet1.Connected = false then
  begin
    memo2.Lines.Add('NOT CONNECTED YET...WAITING TO SEND COMMANDS.');
    exit;
  end;

  processCommands;
  Timer1.Enabled := false;
end;

procedure TForm1.IdTelnet1DataAvailable(Sender: TIdTelnet;
  const Buffer: TIdBytes);
begin
  InterpetBuffer(bytestostring(Buffer));
end;

procedure TForm1.IdTelnet1Disconnected(Sender: TObject);
begin
  memo1.Lines.Add('IdTelnet1Disconnected');
end;

procedure TForm1.IdTelnet1Status(ASender: TObject; const AStatus: TIdStatus;
  const AStatusText: string);
begin
  memo1.Lines.Add('AStatusText: ' + AStatusText);
end;

end.

I expect the program to run in console just like the GUI windows version of itself, but I'm not exactly sure how to go about this with indy idTelnet. I have mainly converted it over to the best of my knowledge and what I could find on the internet (which isn't much). Somehow I need to figure out what is causing it to hang instead of processing telnet messages?

halfer
  • 19,824
  • 17
  • 99
  • 186
El Diablo
  • 168
  • 1
  • 12
  • When you step through the code in the debugger, where specifically does it "hang"? – Ken White Jan 11 '19 at 21:21
  • 1
    TeamSpeak does not communicate using the Telnet protocol, so using `TIdTelnet` is not the right choice. Use `TIdTCPClient` instead, and run your own thread to use it synchronously without blocking your main thread. But you are not exactly coding for TeamSpeak's protocol very well. Why not use the official TeamSpeak SDK instead? It is a C library, so it should work in Delphi. – Remy Lebeau Jan 11 '19 at 22:01
  • I'm not advanced enough to use C librarys with Delphi. :/ Any books / information I can read up on that? – El Diablo Jan 11 '19 at 23:37
  • 2
    @ElDiablo there are numerous questions on StackOverflow about using the TeamSpeak SDK in Delphi. And there is a 3rd party of the SDK to Delphi. [Google is your friend](https://www.google.com/search?ie=UTF-8&q=delphi+TeamSpeak+sdk). – Remy Lebeau Jan 12 '19 at 17:00

1 Answers1

0

Okay, I did much research and found some code to help me with the console application.

I know Remy Lebeau said that Teamspeak doesn't use telnet protocol, but I used it and it works just fine.

The credit has to go to Tony Caduto on this webpage: http://www.44342.com/delphi-f1279-t5081-p1.htm follow the link and go to the bottom of the page. Search for the last reply by Tony Caduto.

This code works now!

Now I can run this on my VPS running linux via WINE! I just don't have the money to buy the more expensive version of Delphi that would run it on linux. I am going to wait until they release a version for small developers like myself that will allow us to run delphi applications on linux. Until then, WINE is the way.

edit: make sure you put IdTelnet1.TelnetThread.Loop := true; after IdTelnet1.Connect; or you get an error.

Here is the code:

program TS3bot;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  System.SysUtils,
  Unit1 in 'Unit1.pas' {DataModule1: TDataModule};

begin
  try
    DataModule1 := TDataModule1.Create(nil);
    with DataModule1 do
    try
      { TODO -oUser -cConsole Main : Insert code here }
      IdTelnet1.ThreadedEvent := true;
      IdTelnet1.Connect;
      IdTelnet1.TelnetThread.Loop := true;
      while (IdTelnet1.Connected = true) do
      begin
        Sleep(60);
      end;
    except
      on E: Exception do
        Writeln(E.ClassName, ': ', E.Message);
    end;
  finally
    writeln('Program ended.');
    freeandnil(DataModule1);
  end;
end.

Here is the other part just in case it changed:

unit Unit1;

interface

uses
  System.SysUtils, System.Classes, IdBaseComponent, IdComponent,
  IdTCPConnection, IdTCPClient, IdTelnet, IdGlobal;

type
  TDataModule1 = class(TDataModule)
    IdTelnet1: TIdTelnet;
    procedure IdTelnet1Connected(Sender: TObject);
    procedure IdTelnet1DataAvailable(Sender: TIdTelnet; const Buffer: TIdBytes);
    procedure IdTelnet1Disconnected(Sender: TObject);
    procedure DataModuleDestroy(Sender: TObject);
  private
    { Private declarations }
    procedure processCommand(Command : string);
    procedure processCommands;
    procedure InterpetBuffer(Buffer: string);
  public
    { Public declarations }
  end;

Const
  Elements = (3); //(Elements - 1)
  ListOfOnConnectCommands : array [0..Elements] of string =
  ('login serverquery mypassword',
  'use 1',
  'clientupdate client_nickname=ServerNickName',
  'servernotifyregister event=server');

var
  DataModule1: TDataModule1;
  BufferNumber: integer = 0;
  CommandSent : boolean = false;
  CommandOK : boolean = false;
  CommandNumber : integer = 0;

implementation

{%CLASSGROUP 'System.Classes.TPersistent'}

{$R *.dfm}

procedure pSplitIT(BreakString, BaseString: string; StringList: TStrings);
var
  EndOfCurrentString: byte;
begin
  StringList.Clear;

  repeat
    EndOfCurrentString := Pos(BreakString, BaseString);

    if EndOfCurrentString = 0 then
      StringList.add(BaseString)
    else
      StringList.add(Copy(BaseString, 1, EndOfCurrentString - 1));
    BaseString := Copy(BaseString, EndOfCurrentString + length(BreakString), length(BaseString) - EndOfCurrentString);

  until EndOfCurrentString = 0;
end;

procedure TDataModule1.processCommand(Command : string);
begin
  writeln('processCommand: ' + Command);
  IdTelnet1.SendString(Command);
  IdTelnet1.SendCh(#10);
  IdTelnet1.SendCh(#13);
end;

procedure TDataModule1.processCommands;
var
  MyString: string;
begin
  if CommandNumber <= Elements then
  begin
    MyString := ListOfOnConnectCommands[CommandNumber];
    writeln('processCommands: ' + MyString);
    IdTelnet1.SendString(MyString);
    IdTelnet1.SendCh(#10);
    IdTelnet1.SendCh(#13);
    inc(CommandNumber);
    //exit;
  end;
end;

procedure TDataModule1.InterpetBuffer(Buffer: string);
var
  MyTstringlist: Tstringlist;
  MyBuffer: string;
  I: integer;
  clid: integer;
  member, legionnaire, enteredGuestChannel: boolean;
begin
  enteredGuestChannel := false;
  member := false;
  legionnaire := false;

  inc(BufferNumber);
  writeln('---------------------------------------------------------');
  writeln('IdTelnet1DataAvailable BufferNumber: ' + BufferNumber.ToString);
  writeln('---------------------------------------------------------');

  if Pos('notifycliententerview',Buffer)>0 then
    begin
      writeln('----------------------');
      writeln('EXIT notifycliententerview:');
      writeln(Buffer);

      MyTstringlist := Tstringlist.Create;
      MyBuffer := Buffer;

      pSplitIT(' ',MyBuffer,MyTstringlist);
      writeln('COUNT: ' + MyTstringlist.Count.ToString);
      for I := 0 to MyTstringlist.Count - 1 do
      begin
        writeln(MyTstringlist.Strings[I]);
        if MyTstringlist.Strings[I] = 'ctid=45' then
        begin
          // client entered GUESTS CHANNEL, see if we can move them.
          enteredGuestChannel := true;
        end;
        if Pos('client_servergroups=',MyTstringlist.Strings[I]) > 0 then
        begin
          if Pos('18',MyTstringlist.Strings[I]) > 0 then
          begin
            member := true;
          end;
          if Pos('19',MyTstringlist.Strings[I]) > 0 then
          begin
            legionnaire := true;
          end;
          if Pos('28',MyTstringlist.Strings[I]) > 0 then
          begin
            legionnaire := true;
          end;
        end;
        //clid
        if Pos('clid=',MyTstringlist.Strings[I]) > 0 then
        begin
          clid := StrToInt(copy(MyTstringlist.Strings[I],6,high(MyTstringlist.Strings[I])));
        end;

      end;

      writeln('----------------------');

      MyTstringlist.Free;

      if ( (enteredGuestChannel = true)
        and (member = true) ) then
        begin
          processCommand('clientmove clid=' + clid.ToString + ' cid=47');
        end
      else if ( (enteredGuestChannel = true)
        and (legionnaire = true) ) then
        begin
          processCommand('clientmove clid=' + clid.ToString + ' cid=47');
        end;

      exit;
    end;

  // Create Returns in terminal
  if Pos(#10#13,Buffer)>0 then
    begin
      MyTstringlist := Tstringlist.Create;
      pSplitIT(#10#13,Buffer,MyTstringlist);
      writeln('COUNT: ' + MyTstringlist.Count.ToString);
      for I := 0 to MyTstringlist.Count - 1 do
      begin
        writeln(MyTstringlist.Strings[I]);
      end;
      MyTstringlist.Free;
    end
    else
    begin
      writeln(Buffer);
    end;

  if Pos('error id=0 msg=ok',Buffer)>0 then
    begin
      processCommands;
    end;

  writeln('');
end;

procedure TDataModule1.DataModuleDestroy(Sender: TObject);
begin
  processCommand('logout');
  processCommand('quit');
  IdTelnet1.Disconnect(true);
end;

procedure TDataModule1.IdTelnet1Connected(Sender: TObject);
begin
  writeln('IdTelnet1Connected');
  sleep(5000);
  writeln('processCommands:');
  processCommands;
end;

procedure TDataModule1.IdTelnet1DataAvailable(Sender: TIdTelnet;
  const Buffer: TIdBytes);
begin
  InterpetBuffer(bytestostring(Buffer));
end;

procedure TDataModule1.IdTelnet1Disconnected(Sender: TObject);
begin
  writeln('IdTelnet1Disconnected');
end;

end.
El Diablo
  • 168
  • 1
  • 12