on data:
for each byte in data:
if byte == IAC:
buffer cmd byte
expect(COMMAND || SUBNEGOTIATION) //2 more bytes: WILL/WONT/DO/DONT option, OR subnegotiation
else if byte == SB:
buffer SB byte
expect(SB_OPTION)
on data:
for each byte in data:
if byte == IAC:
buffer cmd byte
expect(COMMAND || SUBNEGOTIATION) //2 more bytes: WILL/WONT/DO/DONT option, OR subnegotiation
else if byte == SB:
buffer SB byte
expect(SB_OPTION)
function TelnetParser() {
this.state = "text";
}
function TelnetParser.prototype.parse(data) {
// Convert from binary Buffer to UTF-8-encoded string
// It's just easier for the sake of example than using a Buffer directly.
var a = [];
for (var i = 0, len = data.length; i < len; ++i) {
a[i] = String.fromCharCode(data[i]);
}
data = a.join("");
var nextNonText, ch;
for (var i = 0, len = data.length; i < len; ++i) {
ch = data[i];
switch (this.state) {
case "text":
nextNonText = Math.min(data.indexOf("\r", i), data.indexOf("\xFF", i));
if (nextNonText === -1) {
// emit everything up to the end as a text event
i = len; // break out early
} else {
// emit everything up to this point as a text event
i = nextNonText;
this.state == (data[nextNonText] == "\r") ? "cr" : "iac";
}
break;
case "cr":
if (ch == "\n") {
// emit "\r\n"
} else if (ch == "\0") {
// emit "\r"
} else {
// emit "\r", and don't consume this char.
–i;
}
this.state = "text";
break;
case "iac":
// more goes here
break;
}
}
}
IAC DO LINEMODE
IAC SB 0 1 IAC SE
\r \n
The 1 above is for the EDIT mode. All of the above is sent in a single stream. This does indeed disable linemode, but I don't think it's correct because I get a bunch of weird crap back from the client. For enabling, I am sending the reverse:
IAC DO LINEMODE
IAC SB 1 1 IAC SE
\r \n
That does not re-enable linemode.
I thought I was understanding the RFC properly, but obviously I'm not. What is the correct way to switch between character mode and linemode?