//called when receiving any message
        void handleServerMessage(IAsyncResult result)
        {
            //get length of data in buffer
            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 <string> telnetMessages;
            List <byte>   contentBytes = this.telnetParser.HandleAndRemoveTelnetBytes(this.buffer, receivedCount, out telnetMessages);

            //report any telnet sequences seen to the caller
            Application.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);

            //run the following on the main thread so that calling code doesn't have to think about threading
            if (this.serverMessage != null)
            {
                Application.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
            connection.Client.BeginReceive(this.buffer, 0, this.buffer.Length, SocketFlags.None, new AsyncCallback(this.handleServerMessage), null);
        }
Beispiel #2
0
        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);
        }