Bind to loopback interface by default
[mudpy.git] / mudpy / telnet.py
index e483c13..ec18f70 100644 (file)
@@ -1,6 +1,6 @@
 """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.
 
@@ -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."""
@@ -163,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
@@ -245,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
@@ -259,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