protected override void NegotiateInbound(byte[] data, int numberOfBytes) { for (int i = 0; i < numberOfBytes; i++) { if (_TelnetNegotiationState == TelnetNegotiationState.Data) { if (data[i] == (byte)TelnetCommand.IAC) { _TelnetNegotiationState = TelnetNegotiationState.IAC; } else { AddToInputQueue(data[i]); } } else if (_TelnetNegotiationState == TelnetNegotiationState.IAC) { if (data[i] == (byte)TelnetCommand.IAC) { _TelnetNegotiationState = TelnetNegotiationState.Data; AddToInputQueue(data[i]); } else { switch ((TelnetCommand)data[i]) { case TelnetCommand.NoOperation: case TelnetCommand.DataMark: case TelnetCommand.Break: case TelnetCommand.InterruptProcess: case TelnetCommand.AbortOutput: case TelnetCommand.AreYouThere: case TelnetCommand.EraseCharacter: case TelnetCommand.EraseLine: case TelnetCommand.GoAhead: // TODO We recognize, but ignore these for now _TelnetNegotiationState = TelnetNegotiationState.Data; break; case TelnetCommand.Do: _TelnetNegotiationState = TelnetNegotiationState.Do; break; case TelnetCommand.Dont: _TelnetNegotiationState = TelnetNegotiationState.Dont; break; case TelnetCommand.Will: _TelnetNegotiationState = TelnetNegotiationState.Will; break; case TelnetCommand.Wont: _TelnetNegotiationState = TelnetNegotiationState.Wont; break; case TelnetCommand.Subnegotiation: _TelnetNegotiationState = TelnetNegotiationState.Subnegotiation; _SubnegotiationData.Length = 0; break; default: _TelnetNegotiationState = TelnetNegotiationState.Data; break; } } } else if (_TelnetNegotiationState == TelnetNegotiationState.Do) { switch ((TelnetOption)data[i]) { case TelnetOption.TransmitBinary: SendWill(data[i]); break; case TelnetOption.Echo: SendWill(data[i]); break; case TelnetOption.SuppressGoAhead: SendWill(data[i]); break; case TelnetOption.WindowSize: SendWont(data[i]); break; case TelnetOption.TerminalType: SendWont(data[i]); break; case TelnetOption.LineMode: SendWont(data[i]); break; default: SendWont(data[i]); break; } _TelnetNegotiationState = TelnetNegotiationState.Data; } else if (_TelnetNegotiationState == TelnetNegotiationState.Dont) { switch ((TelnetOption)data[i]) { case TelnetOption.TransmitBinary: SendWill(data[i]); break; case TelnetOption.Echo: SendWill(data[i]); break; case TelnetOption.SuppressGoAhead: SendWill(data[i]); break; case TelnetOption.WindowSize: SendWont(data[i]); break; case TelnetOption.TerminalType: SendWont(data[i]); break; case TelnetOption.LineMode: SendWont(data[i]); break; default: SendWont(data[i]); break; } _TelnetNegotiationState = TelnetNegotiationState.Data; } else if (_TelnetNegotiationState == TelnetNegotiationState.Will) { switch ((TelnetOption)data[i]) { case TelnetOption.TransmitBinary: SendDo(data[i]); break; case TelnetOption.Echo: SendDont(data[i]); break; case TelnetOption.SuppressGoAhead: SendDo(data[i]); break; case TelnetOption.WindowSize: SendDont(data[i]); break; case TelnetOption.TerminalType: SendSubnegotiate(data[i]); break; case TelnetOption.LineMode: SendDont(data[i]); break; default: SendDont(data[i]); break; } _TelnetNegotiationState = TelnetNegotiationState.Data; } else if (_TelnetNegotiationState == TelnetNegotiationState.Wont) { switch ((TelnetOption)data[i]) { case TelnetOption.TransmitBinary: SendDont(data[i]); break; case TelnetOption.Echo: SendDont(data[i]); break; case TelnetOption.SuppressGoAhead: SendDo(data[i]); break; case TelnetOption.WindowSize: SendDont(data[i]); break; case TelnetOption.TerminalType: SendDont(data[i]); break; case TelnetOption.LineMode: SendDont(data[i]); break; default: SendDont(data[i]); break; } _TelnetNegotiationState = TelnetNegotiationState.Data; } // TODO Port to fTelnet, HtmlTerm else if (_TelnetNegotiationState == TelnetNegotiationState.Subnegotiation) { // First byte of subnegotiation should be the option to negotiate switch ((TelnetOption)data[i]) { case TelnetOption.TerminalType: case TelnetOption.WindowSize: // Known option _SubnegotiationOption = (TelnetOption)data[i]; break; default: // Unknown option _SubnegotiationOption = TelnetOption.None; break; } _TelnetNegotiationState = TelnetNegotiationState.SubnegotiationData; } else if (_TelnetNegotiationState == TelnetNegotiationState.SubnegotiationData) { // Add next byte to negotiation string, unless it's an IAC switch ((TelnetCommand)data[i]) { case TelnetCommand.IAC: _TelnetNegotiationState = TelnetNegotiationState.SubnegotiationIAC; break; default: _SubnegotiationData.Append((char)data[i]); break; } } else if (_TelnetNegotiationState == TelnetNegotiationState.SubnegotiationIAC) { // Check to see if negotiation has ended, or if it's just a doubled IAC switch ((TelnetCommand)data[i]) { case TelnetCommand.IAC: // Doubled IAC means go back to data _SubnegotiationData.Append((char)data[i]); _TelnetNegotiationState = TelnetNegotiationState.SubnegotiationData; break; case TelnetCommand.EndSubnegotiation: // Subnegotiation has ended // TODO Do something with FSubnegotiationData based on FSubnegotiationOption switch (_SubnegotiationOption) { case TelnetOption.TerminalType: // TODO break; case TelnetOption.WindowSize: // TODO break; } _TelnetNegotiationState = TelnetNegotiationState.Data; break; default: // Something unknown has happened _TelnetNegotiationState = TelnetNegotiationState.Data; break; } } else { _TelnetNegotiationState = TelnetNegotiationState.Data; } } }
// NB: The base class constructor calls InitSocket(), which means this method will run before this classes constructor, so // everything accessed here needs to be initialized already (ie can't rely on the constructor to initialize it) protected override void InitSocket() { base.InitSocket(); Array.Clear(_TelnetOptions, 0, _TelnetOptions.Length); _TelnetNegotiationState = TelnetNegotiationState.Data; }