Implement rudimentary support for determining the terminal type
reported by RFC 1091 TTYPE compatible clients, and store any initial
value returned in the User.ttype attribute. This implementation does
not iterate over SEND TTYPE commands until UNKNOWN is returned, it
only takes the first value returned and assumes this is the default
terminal type for the user's current connection.
self.password_tries = 0
self.state = "telopt_negotiation"
self.telopts = {}
self.password_tries = 0
self.state = "telopt_negotiation"
self.telopts = {}
self.universe = universe
def quit(self):
self.universe = universe
def quit(self):
+ # ask the client for their current terminal type (RFC 1091); it's None
+ # if it's not been initialized, the empty string if it has but the
+ # output was indeterminate, "UNKNOWN" if the client specified it has no
+ # terminal types to supply
+ if self.ttype is None:
+ mudpy.telnet.request_ttype(self)
+
# if output is paused, decrement the counter
if self.state == "telopt_negotiation":
if self.negotiation_pause:
# if output is paused, decrement the counter
if self.state == "telopt_negotiation":
if self.negotiation_pause:
"""Telnet functions and constants for the mudpy engine."""
"""Telnet functions and constants for the mudpy engine."""
-# Copyright (c) 2004-2019 mudpy authors. Permission to use, copy,
+# Copyright (c) 2004-2020 mudpy authors. Permission to use, copy,
# modify, and distribute this software is granted under terms
# provided in the LICENSE file distributed with this software.
# modify, and distribute this software is granted under terms
# provided in the LICENSE file distributed with this software.
TELOPT_LINEMODE: "line mode",
}
TELOPT_LINEMODE: "line mode",
}
-# TODO(fungi): implement support for RFC 1091 terminal type information
supported = (
TELOPT_BINARY,
TELOPT_ECHO,
TELOPT_SGA,
supported = (
TELOPT_BINARY,
TELOPT_ECHO,
TELOPT_SGA,
TELOPT_EOR,
TELOPT_NAWS,
TELOPT_LINEMODE
TELOPT_EOR,
TELOPT_NAWS,
TELOPT_LINEMODE
+# RFC 1091 commands
+IS = 0
+SEND = 1
+ttype_command_names = {
+ IS: "is",
+ SEND: "send",
+}
+
def log(message, user):
"""Log debugging info for Telnet client/server interactions."""
def log(message, user):
"""Log debugging info for Telnet client/server interactions."""
user.telopts[(telopt, party)] = WANTNO
user.telopts[(telopt, party)] = WANTNO
+def request_ttype(user):
+ """Clear and request the terminal type."""
+
+ # only actually request if the corresponding telopt is enabled
+ if is_enabled(user, TELOPT_TTYPE, HIM):
+ # set to the empty string to indicate it's been requested
+ user.ttype = ""
+ user.send(telnet_proto(IAC, SB, TELOPT_TTYPE, SEND, IAC, SE), raw=True)
+ log('Sent terminal type request to', user)
+
+
def negotiate_telnet_options(user):
"""Reply to and remove telnet negotiation options from partial_input."""
def negotiate_telnet_options(user):
"""Reply to and remove telnet negotiation options from partial_input."""
# subnegotiation options
elif len_text > position + 4 and command is SB:
telopt = text[position + 2]
# subnegotiation options
elif len_text > position + 4 and command is SB:
telopt = text[position + 2]
- if telopt is TELOPT_NAWS:
- user.columns = (
- text[position + 3] * 256 + text[position + 4])
end_subnegotiation = text.find(telnet_proto(IAC, SE), position)
if end_subnegotiation > 0:
end_subnegotiation = text.find(telnet_proto(IAC, SE), position)
if end_subnegotiation > 0:
+ if telopt is TELOPT_NAWS:
+ user.columns = (
+ text[position + 3] * 256 + text[position + 4])
+ elif telopt is TELOPT_TTYPE and text[position + 3] is IS:
+ user.ttype = (
+ text[position + 4:end_subnegotiation]).decode("ascii")
text = text[:position] + text[end_subnegotiation + 2:]
else:
position += 1
text = text[:position] + text[end_subnegotiation + 2:]
else:
position += 1