/////////////////////////////////////////////////////////////
// VT100 TERMINFO
/////////////////////////////////////////////////////////////
var VT100 = (function() {
var impl = {};
Object.defineConstant(impl, "key_backspace","\x08");
Object.defineConstant(impl, "key_down", "\x1BOB");
Object.defineConstant(impl, "key_enter", "\x1BOM");
Object.defineConstant(impl, "key_f0", "\x1BOy");
Object.defineConstant(impl, "key_f1", "\x1BOP");
Object.defineConstant(impl, "key_f10", "\x1BOx");
Object.defineConstant(impl, "key_f2", "\x1BOQ");
Object.defineConstant(impl, "key_f3", "\x1BOR");
Object.defineConstant(impl, "key_f4", "\x1BOS");
Object.defineConstant(impl, "key_f5", "\x1BOt");
Object.defineConstant(impl, "key_f6", "\x1BOu");
Object.defineConstant(impl, "key_f7", "\x1BOv");
Object.defineConstant(impl, "key_f8", "\x1BOl");
Object.defineConstant(impl, "key_f9", "\x1BOw");
Object.defineConstant(impl, "key_left", "\x1BOD");
Object.defineConstant(impl, "key_right", "\x1BOC");
Object.defineConstant(impl, "key_up", "\x1BOA");
Object.defineConstant(impl, "keypad_local", "\x1B
/////////////////////////////////////////////////////////////
// VT100 TERMINFO
/////////////////////////////////////////////////////////////
var VT100 = (function() {
var impl = {};
Object.defineConstant(impl, "key_backspace","\x08");
Object.defineConstant(impl, "key_down", "\x1BOB");
Object.defineConstant(impl, "key_enter", "\x1BOM");
Object.defineConstant(impl, "key_f0", "\x1BOy");
Object.defineConstant(impl, "key_f1", "\x1BOP");
Object.defineConstant(impl, "key_f10", "\x1BOx");
Object.defineConstant(impl, "key_f2", "\x1BOQ");
Object.defineConstant(impl, "key_f3", "\x1BOR");
Object.defineConstant(impl, "key_f4", "\x1BOS");
Object.defineConstant(impl, "key_f5", "\x1BOt");
Object.defineConstant(impl, "key_f6", "\x1BOu");
Object.defineConstant(impl, "key_f7", "\x1BOv");
Object.defineConstant(impl, "key_f8", "\x1BOl");
Object.defineConstant(impl, "key_f9", "\x1BOw");
Object.defineConstant(impl, "key_left", "\x1BOD");
Object.defineConstant(impl, "key_right", "\x1BOC");
Object.defineConstant(impl, "key_up", "\x1BOA");
Object.defineConstant(impl, "keypad_local", "\x1B[?1l\x1B>");
Object.defineConstant(impl, "keypad_xmit", "\x1B[?1h\x1B=");
return impl;
})();
Namespace.register("VT100", null, VT100, "withVT100");
[/code]
Now we're cookin' with asparagus!!! Sending VT100.keypad_xmit causes the client to behave as expected, giving the key values listed in the terminfo as expected.
I think the only client that uses TTYPE to select the terminal types is Windows Telnet. One of its modes is somewhat screwy, and I'm not exactly sure how many requests you need to send to select this mode.
So for all intense and purposes I think it's safe to ignore cycling as nobody uses Windows Telnet, except for the occasional troll.
What I did for my server is to send 3 TTYPE requests at once. I store the first response as the client name, and the routine keeps an eye out for an MTTS response.
It's not an option to send MTTS first as many server will only request TTYPE once and expect the client name.
Well first off, I don't care about having fancy-dancy VT100 support for Windows Telnet users. I hear the client is broken with respect to SGA and echo. Bah, shucks. So Immos can't login over raw telnet sessions from Windows boxes and have access to OLC. That's actually a good thing. Immos should be logging in over ssh.
However, I have every intention of respecting the telnet standard. And no, Windows is not the only client that does terminal type negotiation. One of my Linux boxes send XTERM-COLOR and alternately, NXTERM. I've no idea what mode NXTERM corresponds to, so I do the proper thing and reset the terminal type back to XTERM-COLOR. And lo and behold, the client actually supports this properly.
If that lagged 99% of my users, then they are totally going to be pissed by the follow up, where they get asked two questions, one to determine if ANSI color works (even if "supported" by the client, this could be forwarded to a monochrome display), and the second to see if Unicode text works (as the channel may not be 8-bit clean, fonts may not be installed, etc..).
Also, if you note carefully, by where the input is chunked, I've piggy-backed the negotiations such that BINARY and TTYPE options are sent together, and the NAWS and NEW ENVIRON negotiation are also sent together. So doing a full, protocol proper exchange is:
Server -> Client IAC DO BINARY, IAC DO TTYPE
Client -> Server IAC WILL/WONT BINARY, IAC WILL TTYPE
Server -> Client IAC SB TTYPE SEND IAC SE
Client -> Server IAC SB TTYPE IS XTERM-COLOR IAC SE
Server -> Client IAC SB TTYPE SEND IAC SE
Client -> Server IAC SB TTYPE IS NXTERM-ZOMG-WTF-IS-THIS IAC SE
Server -> Client IAC SB TTYPE SEND IAC SE
Client -> Server IAC SB TTYPE IS NXTERM-ZOMG-WTF-IS-THIS IAC SE
And I don't like that ttype so I keep negotiating
Server -> Client IAC SB TTYPE SEND IAC SE
Client -> Server IAC SB TTYPE IS XTERM-COLOR IAC SE
This is the only safe way to conclude the terminal is back in a known mode.
After that, I can finish:
Server -> Client IAC DO NAWS, IAC DO NEW ENVIRON
Client -> Server IAC WILL NAWS, IAC SB NAWS (window size) IAC SE, IAC WILL NEW ENVIRON
Server -> Client IAC SB NEW ENVIRON SEND VAR USER VAR IPADDRESS IAC SE
Course the client cheats the server out of getting environ information, and sends back null strings, but can't do much about that. Some clients even report the user name correctly, making this a second identity check.
All in all, proper use of the telnet protocol is pretty useful.