private void Send(string cmd) { cmd = cmd + "\r\n"; byte[] sndBuffer = Encoding.Default.GetBytes(cmd); string outText = AsciiDecoder.AsciiToUnicode(sndBuffer, sndBuffer.Length); _textProcessor.AllText += outText; List <MUDTextRun> runs = this._ansiColorParser.Translate((char)27 + "[1;33m" + cmd.Replace("\r\n", "") + (char)27 + "[0;66m"); //fire the "received a server message" event with the runs to be displayed App.Current.Dispatcher.BeginInvoke(new Action(() => { if (serverMessage != null) { this.serverMessage(runs); } })); try { //send to server _stream.Write(sndBuffer, 0, sndBuffer.Length); } catch (Exception e) { Disconnect(); Connect("mud.pkuxkx.net", 8080); } }
public List <byte> HandleAndRemoveTelnetBytes(byte[] buffer, int receivedCount, out List <string> telnetMessages) { //list to hold a report of any telnet control sequences received or sent telnetMessages = new List <string>(); //list to hold any bytes which aren't telnet bytes (which will be most of the bytes) List <byte> contentBytes = new List <byte>(); //we'll scan for telnet control sequences. anything NOT a telnet control sequence will be added to the contentBytes list for later processing. int currentIndex = 0; while (currentIndex < receivedCount) { //search for an IAC, which may signal the beginning of a telnet message while (currentIndex < receivedCount && buffer[currentIndex] != (byte)Telnet.InterpretAsCommand) { contentBytes.Add(buffer[currentIndex]); currentIndex++; } //if at the end of the data, stop. otherwise we've encountered an IAC and there should be at least one more byte here if (++currentIndex == receivedCount) { break; } //read the next byte byte secondByte = buffer[currentIndex]; //if another IAC, then this was just sequence IAC IAC, which is the escape sequence to represent byte value 255 (=IAC) in the content stream if (secondByte == (byte)Telnet.InterpretAsCommand) { //write byte value 255 to the content stream and move on contentBytes.Add(secondByte); } //otherwise we have a "real" telnet sequence, where the second byte is a command or negotiation else { //start building a string representation of this message, to be reported to the caller //caller might want to show this info to the user always, or optionally for debugging purposes StringBuilder stringVersionOfMessage = new StringBuilder(); //also build a string version of the response (if any) StringBuilder stringVersionOfResponse = new StringBuilder(); //DO if (secondByte == (byte)Telnet.DO) { stringVersionOfMessage.Append("DO "); //what are we being told to do? currentIndex++; if (currentIndex == receivedCount) { break; } byte thirdByte = buffer[currentIndex]; stringVersionOfMessage.Append(interpretByteAsTelnet(thirdByte)); //if NAWS (negotiate about window size) if (thirdByte == (byte)Telnet.NAWS) { //on connection, we offered to negotiate about window size. so this is a "go ahead and negotiate" response. //so then, send information about client window size per the NAWS protocol //we're lieing to server by telling it a ridiculously large size, so that it won't do line breaking or paging for us (annoying!) stringVersionOfResponse.Append(this.sendTelnetBytes( (byte)Telnet.SubnegotiationBegin, (byte)31, 254, 254, 254, 254, (byte)Telnet.InterpretAsCommand, (byte)Telnet.SubnegotiationEnd)); } //everything else the server might ask us to do is unsupported by us else { stringVersionOfMessage.Append(interpretByteAsTelnet(thirdByte)); //sorry, i won't do whatever "that thing you said to do" was stringVersionOfResponse.Append(this.sendTelnetBytes((byte)Telnet.InterpretAsCommand, (byte)Telnet.WONT, thirdByte)); } } //DONT else if (secondByte == (byte)Telnet.DONT) { stringVersionOfMessage.Append("DONT "); currentIndex++; if (currentIndex == receivedCount) { break; } byte thirdByte = buffer[currentIndex]; stringVersionOfMessage.Append(interpretByteAsTelnet(thirdByte)); //whatever you want me to stop doing, that's no problem because i wasn't going to do it anyway stringVersionOfResponse.Append(this.sendTelnetBytes((byte)Telnet.WONT, thirdByte)); } //WILL else if (secondByte == (byte)Telnet.WILL) { stringVersionOfMessage.Append("WILL "); //find out what the server is willing to do currentIndex++; if (currentIndex == receivedCount) { break; } byte thirdByte = buffer[currentIndex]; stringVersionOfMessage.Append(interpretByteAsTelnet(thirdByte)); //anything the server offers to do for us, we'll tell it not to because we don't know what it is stringVersionOfResponse.Append((this.sendTelnetBytes((byte)Telnet.DONT, thirdByte))); } //WONT else if (secondByte == (byte)Telnet.WONT) { stringVersionOfMessage.Append("WONT "); //find out what the server is NOT willing to do currentIndex++; if (currentIndex == receivedCount) { break; } byte thirdByte = buffer[currentIndex]; stringVersionOfMessage.Append(interpretByteAsTelnet(thirdByte)); //because we haven't asked the server to DO anything, should not expect to receive any WONT //however if we do receive a WONT, respond with a DONT to confirm that the server can go ahead and NOT do that thing it doesn't want to do stringVersionOfResponse.Append(this.sendTelnetBytes((byte)Telnet.DONT, thirdByte)); } //subnegotiations else if (secondByte == (byte)Telnet.SubnegotiationBegin) { stringVersionOfMessage.Append("SB "); List <byte> subnegotiationBytes = new List <byte>(); //read until an IAC followed by an SE while (currentIndex < receivedCount - 1 && !(buffer[currentIndex] == (byte)Telnet.InterpretAsCommand && buffer[currentIndex] == (byte)Telnet.SubnegotiationEnd)) { subnegotiationBytes.Add(buffer[currentIndex]); currentIndex++; } byte[] subnegotiationBytesArray = subnegotiationBytes.ToArray(); //append the content of the subnegotiation to the incoming message report string stringVersionOfMessage.Append(AsciiDecoder.AsciiToUnicode(subnegotiationBytesArray, subnegotiationBytes.Count)); //append the subnegotiation end stringVersionOfMessage.Append(" SE"); } //any other telnet message else { //try to convert it to a known message via the enum defined above stringVersionOfMessage.Append(interpretByteAsTelnet(secondByte)); } //report the control sequence we found, if any string messageToReport = stringVersionOfMessage.ToString(); if (!string.IsNullOrEmpty(messageToReport)) { telnetMessages.Add("RECV: " + messageToReport.ToString()); } //report the response message sent, if any string responseToReport = stringVersionOfResponse.ToString(); if (!string.IsNullOrEmpty(responseToReport)) { telnetMessages.Add("SEND: " + stringVersionOfResponse.ToString()); } } //move up to the next byte in the data currentIndex++; } return(contentBytes); }
//called when receiving any message void handleServerMessage(IAsyncResult result) { try { NetworkStream ns; //get length of data in buffer int receivedCount; try { ns = (NetworkStream)result.AsyncState; receivedCount = ns.EndRead(result); } catch { //if there was any issue reading the server text, ignore the message (what else can we do?) return; } //0 bytes received means the server disconnected if (receivedCount == 0) { this.Disconnect(); return; } //list of bytes which aren't telnet sequences //ultimately, this will be the original buffer minus any telnet messages from the server List <string> telnetMessages; List <byte> contentBytes = this._telnetParser.HandleAndRemoveTelnetBytes(this._rcvBuffer, receivedCount, out telnetMessages); //report any telnet sequences seen to the caller App.Current.Dispatcher.BeginInvoke(new Action(delegate { foreach (string telnetMessage in telnetMessages) { //fire the "received a server message" event this.telnetMessage(telnetMessage); } })); //now we've filtered-out and responded accordingly to any telnet data. //next, convert the actual MUD content of the message from ASCII to Unicode string message = AsciiDecoder.AsciiToUnicode(contentBytes.ToArray(), contentBytes.Count); _textProcessor.AllText += message; _textProcessor.CurrentText = message; _textProcessor.ProcessText(); //run the following on the main thread so that calling code doesn't have to think about threading if (this.serverMessage != null) { App.Current.Dispatcher.BeginInvoke(new Action(delegate { //pass the message to the mudTranslator to parse any ANSI control sequences (colors!) List <MUDTextRun> runs = this._ansiColorParser.Translate(message); //fire the "received a server message" event with the runs to be displayed this.serverMessage(runs); })); } //now that we're done with this message, listen for the next message ns.BeginRead(_rcvBuffer, 0, _rcvBuffer.Length, new AsyncCallback(handleServerMessage), _stream); } catch (Exception e) { System.Windows.MessageBox.Show(e.Message + "\r\n" + e.StackTrace); } }