PageRenderTime 36ms CodeModel.GetById 11ms app.highlight 20ms RepoModel.GetById 1ms app.codeStats 1ms

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