/networking/telnet.d

http://github.com/wilkie/djehuty · D · 221 lines · 120 code · 49 blank · 52 comment · 11 complexity · 4b1320a9cfb04e1c3648100ad74021a7 MD5 · raw file

  1. /*
  2. * telnet.d
  3. *
  4. * This file implements the telnet standard.
  5. *
  6. * Author: Dave Wilkinson
  7. *
  8. */
  9. module networking.telnet;
  10. import core.string;
  11. import core.unicode;
  12. import core.definitions;
  13. import io.socket;
  14. import io.console;
  15. import synch.thread;
  16. private {
  17. const auto CODE_IAC = 255; // Interpret as Command
  18. const auto CODE_SE = 240; // End of subnegotiation parameters.
  19. const auto CODE_NOP = 241; // No operation.
  20. const auto CODE_DM = 242; // The data stream portion of a Synch.
  21. // This should always be accompanied
  22. // by a TCP Urgent notification.
  23. const auto CODE_BR = 243; // NVT character BRK.
  24. const auto CODE_IP = 244; // The function IP (Interrupt Process).
  25. const auto CODE_AO = 245; // The function AO (About Output).
  26. const auto CODE_AYT = 246; // The function AYT (Are You There???).
  27. const auto CODE_EC = 247; // The function EC (Erase Character).
  28. const auto CODE_EL = 248; // The function EL (Erase Line).
  29. const auto CODE_GA = 249; // The GA signal (Go Ahead).
  30. const auto CODE_SB = 250; // Indicates that what follows is
  31. // subnegotiation of the indicated
  32. // option.
  33. // Option Code
  34. const auto CODE_WILL = 251; // Indicates the desire to begin
  35. // performing, or confirmation that
  36. // you are now performing, the
  37. // indicated option.
  38. const auto CODE_WONT = 252; // Indicates the refusal to perform,
  39. // or continue performing, the
  40. // indicated option.
  41. const auto CODE_DO = 253; // Indicates the request that the
  42. // other party perform, or
  43. // confirmation that you are expecting
  44. // the other party to perform, the
  45. // indicated option.
  46. const auto CODE_DONT = 254; // Indicates the demand that the
  47. // other party stop performing,
  48. // or confirmation that you are no
  49. // longer expecting the other party
  50. // to perform, the indicated option.
  51. // Extended with RFC 857
  52. const auto CODE_ECHO = 1; // send as an option code
  53. // Extended with RFC
  54. const auto CODE_SUPPRESS_GO_AHEAD = 3; // send as an option code
  55. }
  56. // Section: Sockpuppets
  57. // Description: This class provides a server interface to the Telnet protocol.
  58. class TelnetServer {
  59. this() {
  60. }
  61. }
  62. // Description: This class provides a client interface to the Telnet protocol.
  63. class TelnetClient {
  64. public:
  65. // Description: This will create an instance of the object. Use 'connect' to make a connection.
  66. this() {
  67. _skt = new Socket();
  68. _thread = new Thread();
  69. _thread.callback = &threadProc;
  70. }
  71. // Description: Connect to the telnet server at the host given. The port is optional; by default it is 23.
  72. // host: The host to connect to.
  73. // port: The port to use to connect. Default is 23.
  74. bool connect(string host, ushort port = 23) {
  75. _connected = _skt.connect(host,port);
  76. if (_connected) {
  77. _thread.start();
  78. }
  79. return _connected;
  80. }
  81. // Description: This function will send the byte to the server
  82. void sendByte(ubyte byteout) {
  83. if (_connected) {
  84. _skt.write(byteout);
  85. }
  86. }
  87. // Description: This function will send the UTF-32 character as a UTF-8 stream.
  88. // chr: The UTF-32 character to send.
  89. void putChar(dchar chr) {
  90. if (_connected) {
  91. dstring chrs = [ chr ];
  92. string chrarray = Unicode.toUtf8(chrs);
  93. _skt.write(cast(ubyte*)chrarray.ptr, chrarray.length);
  94. }
  95. }
  96. // Description: Will set the delegate for callback events from this sockpuppet.
  97. // callback: The delegate fitting the description.
  98. void setDelegate(void delegate(dchar) callback) {
  99. _charDelegate = callback;
  100. }
  101. void close() {
  102. _skt.close();
  103. }
  104. protected:
  105. void sendCommandWord(ubyte optionWord, ubyte commandWord) {
  106. _skt.write(CODE_IAC);
  107. _skt.write(optionWord);
  108. _skt.write(commandWord);
  109. }
  110. void threadProc(bool pleaseStop) {
  111. if (pleaseStop) {
  112. close();
  113. }
  114. ubyte bytein;
  115. for (;;) {
  116. _skt.read(bytein);
  117. if (bytein == CODE_IAC) {
  118. //writefln("Command Incoming");
  119. _skt.read(bytein);
  120. switch (bytein) {
  121. case CODE_DO:
  122. //writefln("Option Word");
  123. _skt.read(bytein);
  124. switch (bytein) {
  125. case CODE_ECHO:
  126. //writefln("Echo");
  127. sendCommandWord(CODE_WILL, CODE_ECHO);
  128. break;
  129. case CODE_SUPPRESS_GO_AHEAD:
  130. //writefln("Supress Go Ahead");
  131. sendCommandWord(CODE_WILL, CODE_SUPPRESS_GO_AHEAD);
  132. break;
  133. case CODE_AYT:
  134. //writefln("Are you there?");
  135. sendCommandWord(CODE_WILL, CODE_AYT);
  136. break;
  137. default:
  138. //writefln(bytein);
  139. break;
  140. }
  141. break;
  142. case CODE_DONT:
  143. _skt.read(bytein);
  144. //writefln("Dont ", bytein);
  145. break;
  146. case CODE_WONT:
  147. _skt.read(bytein);
  148. //writefln("Wont ", bytein);
  149. break;
  150. case CODE_WILL:
  151. _skt.read(bytein);
  152. //writefln("Will ", bytein);
  153. break;
  154. default:
  155. //writefln("Command: ", cast(char)bytein);
  156. break;
  157. }
  158. }
  159. else {
  160. //
  161. if (_charDelegate !is null) {
  162. _charDelegate(Unicode.fromCP866(bytein));
  163. //_charDelegate(bytein);
  164. }
  165. }
  166. }
  167. }
  168. Socket _skt;
  169. bool _connected;
  170. Thread _thread;
  171. void delegate(dchar) _charDelegate;
  172. }