ltelnet.pp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682
  1. { lTelnet CopyRight (C) 2004-2008 Ales Katona
  2. This library is Free software; you can rediStribute it and/or modify it
  3. under the terms of the GNU Library General Public License as published by
  4. the Free Software Foundation; either version 2 of the License, or (at your
  5. option) any later version.
  6. This program is diStributed in the hope that it will be useful, but WITHOUT
  7. ANY WARRANTY; withOut even the implied warranty of MERCHANTABILITY or
  8. FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License
  9. for more details.
  10. You should have received a Copy of the GNU Library General Public License
  11. along with This library; if not, Write to the Free Software Foundation,
  12. Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  13. This license has been modified. See File LICENSE for more inFormation.
  14. Should you find these sources withOut a LICENSE File, please contact
  15. me at [email protected]
  16. }
  17. unit lTelnet;
  18. {$mode objfpc}{$H+}
  19. //{$define debug}
  20. interface
  21. uses
  22. Classes, SysUtils, lNet, lControlStack;
  23. const
  24. // Telnet printer signals
  25. TS_NUL = #0;
  26. TS_ECHO = #1;
  27. TS_SGA = #3; // Surpass go-ahead
  28. TS_BEL = #7;
  29. TS_BS = #8;
  30. TS_HT = #9;
  31. TS_LF = #10;
  32. TS_VT = #11;
  33. TS_FF = #12;
  34. TS_CR = #13;
  35. // Telnet control signals
  36. TS_NAWS = #31;
  37. TS_DATA_MARK = #128;
  38. TS_BREAK = #129;
  39. TS_HYI = #133; // Hide Your Input
  40. // Data types codes
  41. TS_STDTELNET = #160;
  42. TS_TRANSPARENT = #161;
  43. TS_EBCDIC = #162;
  44. // Control bytes
  45. TS_SE = #240;
  46. TS_NOP = #241;
  47. TS_GA = #249; // go ahead currently ignored(full duplex)
  48. TS_SB = #250;
  49. TS_WILL = #251;
  50. TS_WONT = #252;
  51. TS_DO = #253;
  52. TS_DONT = #254;
  53. // Mother of all power
  54. TS_IAC = #255;
  55. type
  56. TLTelnetClient = class;
  57. TLTelnetControlChars = set of Char;
  58. TLHowEnum = (TE_WILL = 251, TE_WONT, TE_DO, TE_DONW);
  59. TLSubcommandCallback= function(command: char; const parameters, defaultResponse: string): string;
  60. TLSubcommandEntry= record
  61. callback: TLSubcommandCallback;
  62. defaultResponse: string;
  63. requiredParams: integer
  64. end;
  65. TLSubcommandArray= array[#$00..#$ff] of TLSubcommandEntry;
  66. EInsufficientSubcommandParameters= class(Exception);
  67. { TLTelnet }
  68. TLTelnet = class(TLComponent, ILDirect)
  69. protected
  70. FStack: TLControlStack;
  71. FConnection: TLTcp;
  72. FPossible: TLTelnetControlChars;
  73. FActiveOpts: TLTelnetControlChars;
  74. FOutput: TMemoryStream;
  75. FOperation: Char;
  76. FCommandCharIndex: Byte;
  77. FOnReceive: TLSocketEvent;
  78. FOnConnect: TLSocketEvent;
  79. FOnDisconnect: TLSocketEvent;
  80. FOnError: TLSocketErrorEvent;
  81. FCommandArgs: string[3];
  82. FOrders: TLTelnetControlChars;
  83. FBuffer: array of Char;
  84. FBufferIndex: Integer;
  85. FBufferEnd: Integer;
  86. FSubcommandCallbacks: TLSubcommandArray;
  87. procedure InflateBuffer;
  88. function AddToBuffer(const aStr: string): Boolean; inline;
  89. function Question(const Command: Char; const Value: Boolean): Char;
  90. function GetConnected: Boolean;
  91. function GetTimeout: Integer;
  92. procedure SetTimeout(const Value: Integer);
  93. function GetSocketClass: TLSocketClass;
  94. procedure SetSocketClass(Value: TLSocketClass);
  95. function GetSession: TLSession;
  96. procedure SetSesssion(const AValue: TLSession);
  97. procedure SetCreator(AValue: TLComponent); override;
  98. procedure StackFull;
  99. procedure DoubleIAC(var s: string);
  100. function TelnetParse(const msg: string): Integer;
  101. function React(const Operation, Command: Char): boolean; virtual; abstract;
  102. procedure SendCommand(const Command: Char; const Value: Boolean); virtual; abstract;
  103. procedure OnCs(aSocket: TLSocket);
  104. public
  105. constructor Create(aOwner: TComponent); override;
  106. destructor Destroy; override;
  107. function Get(out aData; const aSize: Integer; aSocket: TLSocket = nil): Integer; virtual; abstract;
  108. function GetMessage(out msg: string; aSocket: TLSocket = nil): Integer; virtual; abstract;
  109. function Send(const aData; const aSize: Integer; aSocket: TLSocket = nil): Integer; virtual; abstract;
  110. function SendMessage(const msg: string; aSocket: TLSocket = nil): Integer; virtual; abstract;
  111. function OptionIsSet(const Option: Char): Boolean;
  112. function RegisterOption(const aOption: Char; const aCommand: Boolean): Boolean;
  113. procedure SetOption(const Option: Char);
  114. procedure UnSetOption(const Option: Char);
  115. function RegisterSubcommand(aOption: char; callback: TLSubcommandCallback;
  116. const defaultResponse: string= ''; requiredParams: integer= 0): boolean;
  117. procedure Disconnect(const Forced: Boolean = True); override;
  118. procedure SendCommand(const aCommand: Char; const How: TLHowEnum); virtual;
  119. public
  120. property Output: TMemoryStream read FOutput;
  121. property Connected: Boolean read GetConnected;
  122. property Timeout: Integer read GetTimeout write SetTimeout;
  123. property OnReceive: TLSocketEvent read FOnReceive write FOnReceive;
  124. property OnDisconnect: TLSocketEvent read FOnDisconnect write FOnDisconnect;
  125. property OnConnect: TLSocketEvent read FOnConnect write FOnConnect;
  126. property OnError: TLSocketErrorEvent read FOnError write FOnError;
  127. property Connection: TLTCP read FConnection;
  128. property SocketClass: TLSocketClass read GetSocketClass write SetSocketClass;
  129. property Session: TLSession read GetSession write SetSesssion;
  130. end;
  131. { TLTelnetClient }
  132. TLTelnetClient = class(TLTelnet, ILClient)
  133. protected
  134. FLocalEcho: Boolean;
  135. procedure OnEr(const msg: string; aSocket: TLSocket);
  136. procedure OnDs(aSocket: TLSocket);
  137. procedure OnRe(aSocket: TLSocket);
  138. procedure OnCo(aSocket: TLSocket);
  139. function React(const Operation, Command: Char): boolean; override;
  140. procedure SendCommand(const Command: Char; const Value: Boolean); override;
  141. public
  142. constructor Create(aOwner: TComponent); override;
  143. function Connect(const anAddress: string; const aPort: Word): Boolean;
  144. function Connect: Boolean;
  145. function Get(out aData; const aSize: Integer; aSocket: TLSocket = nil): Integer; override;
  146. function GetMessage(out msg: string; aSocket: TLSocket = nil): Integer; override;
  147. function Send(const aData; const aSize: Integer; aSocket: TLSocket = nil): Integer; override;
  148. function SendMessage(const msg: string; aSocket: TLSocket = nil): Integer; override;
  149. procedure CallAction; override;
  150. public
  151. property LocalEcho: Boolean read FLocalEcho write FLocalEcho;
  152. end;
  153. function LTelnetSubcommandCallback(command: char; const parameters, defaultResponse: string): string;
  154. implementation
  155. uses
  156. Math;
  157. const subcommandEndLength= 2;
  158. var
  159. zz: Char;
  160. TNames: array[Char] of string;
  161. //*******************************TLTelnetClient********************************
  162. constructor TLTelnet.Create(aOwner: TComponent);
  163. begin
  164. inherited Create(aOwner);
  165. FConnection := TLTCP.Create(nil);
  166. FConnection.Creator := Self;
  167. FConnection.OnCanSend := @OnCs;
  168. FOutput := TMemoryStream.Create;
  169. FCommandCharIndex := 0;
  170. FStack := TLControlStack.Create;
  171. FStack.OnFull := @StackFull;
  172. end;
  173. destructor TLTelnet.Destroy;
  174. begin
  175. Disconnect(True);
  176. FOutput.Free;
  177. FConnection.Free;
  178. FStack.Free;
  179. inherited Destroy;
  180. end;
  181. function TLTelnet.GetConnected: Boolean;
  182. begin
  183. Result := FConnection.Connected;
  184. end;
  185. function TLTelnet.GetSession: TLSession;
  186. begin
  187. Result := FConnection.Session;
  188. end;
  189. procedure TLTelnet.SetSesssion(const AValue: TLSession);
  190. begin
  191. FConnection.Session := aValue;
  192. end;
  193. procedure TLTelnet.SetCreator(AValue: TLComponent);
  194. begin
  195. inherited SetCreator(AValue);
  196. FConnection.Creator := aValue;
  197. end;
  198. procedure TLTelnet.InflateBuffer;
  199. var
  200. n: Integer;
  201. begin
  202. n := Max(Length(FBuffer), 25);
  203. SetLength(FBuffer, n * 10);
  204. end;
  205. function TLTelnet.AddToBuffer(const aStr: string): Boolean; inline;
  206. begin
  207. Result := False;
  208. while Length(aStr) + FBufferEnd > Length(FBuffer) do
  209. InflateBuffer;
  210. Move(aStr[1], FBuffer[FBufferEnd], Length(aStr));
  211. Inc(FBufferEnd, Length(aStr));
  212. end;
  213. function TLTelnet.Question(const Command: Char; const Value: Boolean): Char;
  214. begin
  215. Result := TS_NOP;
  216. if Value then begin
  217. if Command in FOrders then
  218. Result := TS_DO
  219. else
  220. Result := TS_WILL;
  221. end else begin
  222. if Command in FOrders then
  223. Result := TS_DONT
  224. else
  225. Result := TS_WONT;
  226. end;
  227. end;
  228. function TLTelnet.GetSocketClass: TLSocketClass;
  229. begin
  230. Result := FConnection.SocketClass;
  231. end;
  232. function TLTelnet.GetTimeout: Integer;
  233. begin
  234. Result := FConnection.Timeout;
  235. end;
  236. procedure TLTelnet.SetSocketClass(Value: TLSocketClass);
  237. begin
  238. FConnection.SocketClass := Value;
  239. end;
  240. procedure TLTelnet.SetTimeout(const Value: Integer);
  241. begin
  242. FConnection.Timeout := Value;
  243. end;
  244. procedure TLTelnet.StackFull;
  245. begin
  246. {$ifdef debug}
  247. Writeln('**STACKFULL**');
  248. {$endif}
  249. if FStack[1] = TS_IAC then
  250. begin
  251. FOutput.WriteByte(Byte(FStack[1]));
  252. FOutput.WriteByte(Byte(FStack[2]));
  253. FStack.Clear
  254. end else
  255. if React(FStack[1], FStack[2]) then
  256. FStack.Clear
  257. end;
  258. procedure TLTelnet.DoubleIAC(var s: string);
  259. var
  260. i: Longint;
  261. begin
  262. i := 0;
  263. if Length(s) > 0 then
  264. while i < Length(s) do begin
  265. Inc(i);
  266. if s[i] = TS_IAC then begin
  267. Insert(TS_IAC, s, i);
  268. Inc(i, 2);
  269. end;
  270. end;
  271. end;
  272. function TLTelnet.TelnetParse(const msg: string): Integer;
  273. var
  274. i: Longint;
  275. begin
  276. Result := 0;
  277. for i := 1 to Length(msg) do
  278. if (FStack.ItemIndex > 0) or (msg[i] = TS_IAC) then begin
  279. if msg[i] = TS_GA then
  280. FStack.Clear
  281. else
  282. FStack.Push(msg[i])
  283. end else begin
  284. FOutput.WriteByte(Byte(msg[i]));
  285. Inc(Result);
  286. end;
  287. end;
  288. procedure TLTelnet.OnCs(aSocket: TLSocket);
  289. var
  290. n: Integer;
  291. begin
  292. n := 1;
  293. while (n > 0) and (FBufferIndex < FBufferEnd) do begin
  294. n := FConnection.Send(FBuffer[FBufferIndex], FBufferEnd - FBufferIndex);
  295. if n > 0 then
  296. Inc(FBufferIndex, n);
  297. end;
  298. if FBufferEnd - FBufferIndex < FBufferIndex then begin // if we can move the "right" side of the buffer back to the left
  299. Move(FBuffer[FBufferIndex], FBuffer[0], FBufferEnd - FBufferIndex);
  300. FBufferEnd := FBufferEnd - FBufferIndex;
  301. FBufferIndex := 0;
  302. end;
  303. end;
  304. function TLTelnet.OptionIsSet(const Option: Char): Boolean;
  305. begin
  306. Result := False;
  307. Result := Option in FActiveOpts;
  308. end;
  309. function TLTelnet.RegisterOption(const aOption: Char;
  310. const aCommand: Boolean): Boolean;
  311. begin
  312. Result := False;
  313. if not (aOption in FPossible) then begin
  314. FPossible := FPossible + [aOption];
  315. if aCommand then
  316. FOrders := FOrders + [aOption];
  317. Result := True;
  318. end;
  319. end;
  320. procedure TLTelnet.SetOption(const Option: Char);
  321. begin
  322. if Option in FPossible then
  323. SendCommand(Option, True);
  324. end;
  325. procedure TLTelnet.UnSetOption(const Option: Char);
  326. begin
  327. if Option in FPossible then
  328. SendCommand(Option, False);
  329. end;
  330. (* If already set, the callback can be reverted to nil but it can't be changed *)
  331. (* in a single step. The default response, if specified, is used by the *)
  332. (* LTelnetSubcommandCallback() function and is available to others; the *)
  333. (* callback will not be invoked until there is at least the indicated number of *)
  334. (* parameter bytes available. *)
  335. //
  336. function TLTelnet.RegisterSubcommand(aOption: char; callback: TLSubcommandCallback;
  337. const defaultResponse: string= ''; requiredParams: integer= 0): boolean;
  338. begin
  339. result := (not Assigned(FSubcommandCallbacks[aOption].callback)) or (@callback = nil);
  340. if result then begin
  341. FSubcommandCallbacks[aOption].callback := callback;
  342. FSubcommandCallbacks[aOption].defaultResponse := defaultResponse;
  343. Inc(requiredParams, subcommandEndLength);
  344. if requiredParams < 0 then (* Assume -subcommandEndLength is a *)
  345. requiredParams := 0; (* valid parameter. *)
  346. FSubcommandCallbacks[aOption].requiredParams := requiredParams;
  347. end
  348. end { TLTelnet.RegisterSubcommand } ;
  349. procedure TLTelnet.Disconnect(const Forced: Boolean = True);
  350. begin
  351. FConnection.Disconnect(Forced);
  352. end;
  353. procedure TLTelnet.SendCommand(const aCommand: Char; const How: TLHowEnum);
  354. begin
  355. {$ifdef debug}
  356. Writeln('**SENT** ', TNames[Char(How)], ' ', TNames[aCommand]);
  357. {$endif}
  358. AddToBuffer(TS_IAC + Char(How) + aCommand);
  359. OnCs(nil);
  360. end;
  361. //****************************TLTelnetClient*****************************
  362. constructor TLTelnetClient.Create(aOwner: TComponent);
  363. begin
  364. inherited Create(aOwner);
  365. FConnection.OnError := @OnEr;
  366. FConnection.OnDisconnect := @OnDs;
  367. FConnection.OnReceive := @OnRe;
  368. FConnection.OnConnect := @OnCo;
  369. FPossible := [TS_ECHO, TS_HYI, TS_SGA];
  370. FActiveOpts := [];
  371. FOrders := [];
  372. end;
  373. procedure TLTelnetClient.OnEr(const msg: string; aSocket: TLSocket);
  374. begin
  375. if Assigned(FOnError) then
  376. FOnError(msg, aSocket)
  377. else
  378. FOutput.Write(Pointer(msg)^, Length(msg));
  379. end;
  380. procedure TLTelnetClient.OnDs(aSocket: TLSocket);
  381. begin
  382. if Assigned(FOnDisconnect) then
  383. FOnDisconnect(aSocket);
  384. end;
  385. procedure TLTelnetClient.OnRe(aSocket: TLSocket);
  386. var
  387. s: string;
  388. begin
  389. if aSocket.GetMessage(s) > 0 then
  390. if (TelnetParse(s) > 0) and Assigned(FOnReceive) then
  391. FOnReceive(aSocket);
  392. end;
  393. procedure TLTelnetClient.OnCo(aSocket: TLSocket);
  394. begin
  395. if Assigned(FOnConnect) then
  396. FOnConnect(aSocket);
  397. end;
  398. function TLTelnetClient.React(const Operation, Command: Char): boolean;
  399. procedure Accept(const Operation, Command: Char);
  400. begin
  401. FActiveOpts := FActiveOpts + [Command];
  402. {$ifdef debug}
  403. Writeln('**SENT** ', TNames[Operation], ' ', TNames[Command]);
  404. {$endif}
  405. AddToBuffer(TS_IAC + Operation + Command);
  406. OnCs(nil);
  407. end;
  408. procedure Refuse(const Operation, Command: Char);
  409. begin
  410. FActiveOpts := FActiveOpts - [Command];
  411. {$ifdef debug}
  412. Writeln('**SENT** ', TNames[Operation], ' ', TNames[Command]);
  413. {$endif}
  414. AddToBuffer(TS_IAC + Operation + Command);
  415. OnCs(nil);
  416. end;
  417. (* Retrieve the parameters from the current instance, and pass them explicitly *)
  418. (* to the callback. Return false if there are insufficient parameters on the *)
  419. (* stack. *)
  420. //
  421. function subcommand(command: char): boolean;
  422. var parameters, response: string;
  423. i: integer;
  424. begin
  425. FStack.AllowInflation := true; (* We might need more than the standard *)
  426. if FStack.ItemIndex > 65536 then (* command, but protect against parse *)
  427. {%H- 6018 } exit(true); (* failure which could be a DoS attack. *)
  428. i := FStack.ItemIndex - TL_CSLENGTH; (* Number of parameter bytes available.*)
  429. if i < FSubcommandCallbacks[command].requiredParams then
  430. exit(false); (* Early insufficient-parameters decision *)
  431. result := true;
  432. if FStack.ItemIndex > TL_CSLENGTH then begin
  433. SetLength(parameters, FStack.ItemIndex - TL_CSLENGTH );
  434. Move(FStack[3], parameters[1], FStack.ItemIndex - TL_CSLENGTH );
  435. if (Length(parameters) >= 2) and (parameters[Length(parameters)] = TS_IAC) and
  436. (parameters[Length(parameters) - 1] <> TS_IAC) then
  437. exit(false); (* Special case: need at least one more *)
  438. i := 1;
  439. while i <= Length(parameters) - 1 do (* Undouble IACs *)
  440. if (parameters[i] = TS_IAC) and (parameters[i + 1] = TS_IAC) then
  441. Delete(parameters, i, 1)
  442. else
  443. Inc(i)
  444. end else
  445. parameters := '';
  446. if Length(parameters) < FSubcommandCallbacks[command].requiredParams then
  447. exit(false); (* Insufficient params after IAC undouble *)
  448. if (FSubcommandCallbacks[command].requiredParams >= subcommandEndLength) and
  449. (Length(parameters) >= subcommandEndLength) then
  450. SetLength(parameters, Length(parameters) - subcommandEndLength);
  451. try
  452. response := FSubcommandCallbacks[command].callback(command, parameters,
  453. FSubcommandCallbacks[command].defaultResponse)
  454. except
  455. on e: EInsufficientSubcommandParameters do
  456. Exit(false) (* Late insufficient-parameters decision *)
  457. else
  458. Raise (* Application-specific error *)
  459. end;
  460. DoubleIAC(response);
  461. AddToBuffer(TS_IAC + TS_SB + command + response + TS_IAC + TS_SE);
  462. OnCs(nil)
  463. end { subcommand } ;
  464. begin
  465. result := true; (* Stack will normally be cleared *)
  466. {$ifdef debug}
  467. Writeln('**GOT** ', TNames[Operation], ' ', TNames[Command]);
  468. {$endif}
  469. case Operation of
  470. TS_DO : if Command in FPossible then Accept(TS_WILL, Command)
  471. else Refuse(TS_WONT, Command);
  472. TS_DONT : if Command in FPossible then Refuse(TS_WONT, Command);
  473. TS_WILL : if Command in FPossible then FActiveOpts := FActiveOpts + [Command]
  474. else Refuse(TS_DONT, Command);
  475. TS_WONT : if Command in FPossible then FActiveOpts := FActiveOpts - [Command];
  476. TS_SB : if not Assigned(FSubcommandCallbacks[command].callback) then
  477. refuse(TS_WONT, command)
  478. else
  479. result := subcommand(command)
  480. (* In the final case above, the stack will not be cleared if sufficient *)
  481. (* parameters to keep the subcommand happy have not yet been parsed out of the *)
  482. (* message. *)
  483. end;
  484. end;
  485. procedure TLTelnetClient.SendCommand(const Command: Char; const Value: Boolean);
  486. begin
  487. if Connected then begin
  488. {$ifdef debug}
  489. Writeln('**SENT** ', TNames[Question(Command, Value)], ' ', TNames[Command]);
  490. {$endif}
  491. case Question(Command, Value) of
  492. TS_WILL : FActiveOpts := FActiveOpts + [Command];
  493. end;
  494. AddToBuffer(TS_IAC + Question(Command, Value) + Command);
  495. OnCs(nil);
  496. end;
  497. end;
  498. function TLTelnetClient.Connect(const anAddress: string; const aPort: Word): Boolean;
  499. begin
  500. Result := FConnection.Connect(anAddress, aPort);
  501. end;
  502. function TLTelnetClient.Connect: Boolean;
  503. begin
  504. Result := FConnection.Connect(FHost, FPort);
  505. end;
  506. function TLTelnetClient.Get(out aData; const aSize: Integer; aSocket: TLSocket): Integer;
  507. begin
  508. Result := FOutput.Read(aData {%H- 5058 } , aSize);
  509. if FOutput.Position = FOutput.Size then
  510. FOutput.Clear;
  511. end;
  512. function TLTelnetClient.GetMessage(out msg: string; aSocket: TLSocket): Integer;
  513. begin
  514. Result := 0;
  515. msg := '';
  516. if FOutput.Size > 0 then begin
  517. FOutput.Position := 0;
  518. SetLength(msg, FOutput.Size);
  519. Result := FOutput.Read(PChar(msg)^, Length(msg));
  520. FOutput.Clear;
  521. end;
  522. end;
  523. function TLTelnetClient.Send(const aData; const aSize: Integer;
  524. aSocket: TLSocket): Integer;
  525. var
  526. Tmp: string;
  527. begin
  528. {$ifdef debug}
  529. Writeln('**SEND START** ');
  530. {$endif}
  531. Result := 0;
  532. if aSize > 0 then begin
  533. SetLength(Tmp, aSize);
  534. Move(aData, PChar(Tmp)^, aSize);
  535. DoubleIAC(Tmp);
  536. if LocalEcho and (not OptionIsSet(TS_ECHO)) and (not OptionIsSet(TS_HYI)) then
  537. FOutput.Write(PChar(Tmp)^, Length(Tmp));
  538. AddToBuffer(Tmp);
  539. OnCs(nil);
  540. Result := aSize;
  541. end;
  542. {$ifdef debug}
  543. Writeln('**SEND END** ');
  544. {$endif}
  545. end;
  546. function TLTelnetClient.SendMessage(const msg: string; aSocket: TLSocket
  547. ): Integer;
  548. begin
  549. Result := Send(PChar(msg)^, Length(msg));
  550. end;
  551. procedure TLTelnetClient.CallAction;
  552. begin
  553. FConnection.CallAction;
  554. end;
  555. (* This is a default callback for use with the RegisterSubcommand() method. It *)
  556. (* may be used where the result is unchanging, for example in order to return *)
  557. (* the terminal type. *)
  558. //
  559. function LTelnetSubcommandCallback(command: char; const parameters, defaultResponse: string): string;
  560. begin
  561. result := defaultResponse
  562. end { LTelnetSubcommandCallback } ;
  563. initialization
  564. for zz := #0 to #255 do
  565. TNames[zz] := IntToStr(Ord(zz));
  566. TNames[#1] := 'TS_ECHO';
  567. TNames[#133] := 'TS_HYI';
  568. TNames[#251] := 'TS_WILL';
  569. TNames[#252] := 'TS_WONT';
  570. TNames[#253] := 'TS_DO';
  571. TNames[#254] := 'TS_DONT';
  572. end.