X-Git-Url: https://mudpy.org/gitweb?p=mudpy.git;a=blobdiff_plain;f=mudpy%2Ftelnet.py;h=ec18f70a64e0881671f1880da6ddbe61c2732d7b;hp=0cc29b8402878f4c35909a8720664932a7627c9f;hb=29041014a531835bf9b6a80ca9d7ed414a929432;hpb=6375b4be5c22662376bfb1534a5ec77506f6402e diff --git a/mudpy/telnet.py b/mudpy/telnet.py index 0cc29b8..ec18f70 100644 --- a/mudpy/telnet.py +++ b/mudpy/telnet.py @@ -1,8 +1,8 @@ """Telnet functions and constants for the mudpy engine.""" -# Copyright (c) 2004-2018 Jeremy Stanley . Permission -# to use, copy, modify, and distribute this software is granted under -# terms provided in the LICENSE file distributed with this software. +# 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. import mudpy @@ -24,11 +24,11 @@ option_names = { TELOPT_LINEMODE: "line mode", } -# TODO(fungi): implement support for RFC 1091 terminal type information supported = ( TELOPT_BINARY, TELOPT_ECHO, TELOPT_SGA, + TELOPT_TTYPE, TELOPT_EOR, TELOPT_NAWS, TELOPT_LINEMODE @@ -80,6 +80,14 @@ party_names = { US: "us", } +# 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.""" @@ -97,7 +105,20 @@ def telnet_proto(*arguments): def translate_action(*command): """Convert a Telnet command sequence into text suitable for logging.""" - return "%s %s" % (command_names[command[0]], option_names[command[1]]) + try: + command_name = command_names[command[0]] + except KeyError: + # This should never happen since we filter unknown commands from + # the input queue, but added here for completeness since logging + # should never crash the process + command_name = str(command[0]) + try: + option_name = option_names[command[1]] + except KeyError: + # This can happen for any of the myriad of Telnet options missing + # from the option_names dict + option_name = str(command[1]) + return "%s %s" % (command_name, option_name) def send_command(user, *command): @@ -150,13 +171,24 @@ def disable(user, telopt, party): 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.""" # make a local copy to play with text = user.partial_input - # start at the begining of the input + # start at the beginning of the input position = 0 # as long as we haven't checked it all @@ -232,11 +264,16 @@ def negotiate_telnet_options(user): # 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: + if telopt is TELOPT_NAWS: + user.columns = ( + text[position + 3] * 256 + text[position + 4]) + user.rows = ( + text[position + 5] * 256 + text[position + 6]) + 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 @@ -246,7 +283,7 @@ def negotiate_telnet_options(user): log("Ignored unknown command %s from" % command, user) text = text[:position] + text[position + 2:] - # and this means we got the begining of an IAC + # and this means we got the beginning of an IAC else: position += 1