void handleServerMessage(IAsyncResult result) { int receivedCount; try { receivedCount = connection.Client.EndReceive(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 <byte> contentBytes = this.telnetParser.HandleAndRemoveTelnetBytes(this.buffer, receivedCount); //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); //run the following on the main thread so that calling code doesn't have to think about threading if (this.serverMessage != null) { List <MUDToken> runs = this.ansiParser.Translate(message, this, telnetParser, TextGrouping); this.serverMessage(runs); } //now that we're done with this message, listen for the next message connection.Client.BeginReceive(this.buffer, 0, this.buffer.Length, SocketFlags.None, new AsyncCallback(this.handleServerMessage), null); }
public List <byte> HandleAndRemoveTelnetBytes(byte[] buffer, int receivedCount) { //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 { //DO if (secondByte == (byte)Telnet.DO || secondByte == (byte)Telnet.DONT || secondByte == (byte)Telnet.WILL || secondByte == (byte)Telnet.WONT) { //what are we being told to do? currentIndex++; if (currentIndex == receivedCount) { break; } byte thirdByte = buffer[currentIndex]; if (secondByte == (byte)Telnet.WILL && thirdByte == (byte)Telnet.SuppressGoAhead) { this.sendTelnetBytes((byte)Telnet.DO, thirdByte); } } //subnegotiations else if (secondByte == (byte)Telnet.SubnegotiationBegin) { 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 AsciiDecoder.AsciiToUnicode(subnegotiationBytesArray, subnegotiationBytes.Count); } } //move up to the next byte in the data currentIndex++; } return(contentBytes); }