From 761af6ff61bb547f76c761acbe41d0ef11d51681 Mon Sep 17 00:00:00 2001 From: Jeremy Stanley Date: Tue, 19 Mar 2013 03:10:40 +0000 Subject: [PATCH] Handle byte type on sockets * bin/test * lib/mudpy/misc.py * lib/mudpy/telnet.py: For Py3K compatibility, socket I/O uses byte type instead of str. --- bin/test | 36 ++++++++++++++++++------------------ lib/mudpy/misc.py | 34 +++++++++++++++++++++++----------- lib/mudpy/telnet.py | 13 ++++--------- 3 files changed, 45 insertions(+), 38 deletions(-) diff --git a/bin/test b/bin/test index 9dec9f4..480c7be 100755 --- a/bin/test +++ b/bin/test @@ -2,32 +2,32 @@ # -*- coding: utf-8 -*- """Regression test script for the mudpy engine.""" -# Copyright (c) 2004-2011 Jeremy Stanley . Permission +# Copyright (c) 2004-2013 Jeremy Stanley . Permission # to use, copy, modify, and distribute this software is granted under # terms provided in the LICENSE file distributed with this software. conversation = ( - ("Identify yourself:", "testuser"), - ("Enter your choice:", "n"), - ("Enter a new password for \"testuser\":", "Test123"), - ("Enter the same new password again:", "Test123"), - ("What would you like to do?", "c"), - ("Pick a gender for your new avatar:", "f"), - ("Choose a name for her:", "1"), - ("What would you like to do?", "a"), - ("Whom would you like to awaken?", ""), - (">", "quit"), - ("What would you like to do?", "d"), - ("Whom would you like to delete?", ""), - ("What would you like to do?", "p"), - ("permanently delete your account?", "y"), - ("Disconnecting...", ""), + (b"Identify yourself:", b"testuser"), + (b"Enter your choice:", b"n"), + (b"Enter a new password for \"testuser\":", b"Test123"), + (b"Enter the same new password again:", b"Test123"), + (b"What would you like to do?", b"c"), + (b"Pick a gender for your new avatar:", b"f"), + (b"Choose a name for her:", b"1"), + (b"What would you like to do?", b"a"), + (b"Whom would you like to awaken?", b""), + (b">", b"quit"), + (b"What would you like to do?", b"d"), + (b"Whom would you like to delete?", b""), + (b"What would you like to do?", b"p"), + (b"permanently delete your account?", b"y"), + (b"Disconnecting...", b""), ) import telnetlib mud = telnetlib.Telnet() mud.open("::1", 6669) for question, answer in conversation: - mud.read_until("%s " % question) - mud.write("%s\r\n" % answer) + mud.read_until(b"%s " % question) + mud.write(b"%s\r\n" % answer) mud.close() diff --git a/lib/mudpy/misc.py b/lib/mudpy/misc.py index 3193e11..8f6630f 100644 --- a/lib/mudpy/misc.py +++ b/lib/mudpy/misc.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- """Miscellaneous functions for the mudpy engine.""" -# Copyright (c) 2004-2012 Jeremy Stanley . Permission +# Copyright (c) 2004-2013 Jeremy Stanley . Permission # to use, copy, modify, and distribute this software is granted under # terms provided in the LICENSE file distributed with this software. @@ -589,7 +589,7 @@ class User: self.menu_seen = False self.negotiation_pause = 0 self.output_queue = [] - self.partial_input = "" + self.partial_input = b"" self.password_tries = 0 self.state = "initial" self.telopts = {} @@ -924,7 +924,7 @@ class User: try: raw_input = self.connection.recv(1024) except: - raw_input = "" + raw_input = b"" # we got something if raw_input: @@ -936,18 +936,18 @@ class User: mudpy.telnet.negotiate_telnet_options(self) # separate multiple input lines - new_input_lines = self.partial_input.split("\n") + new_input_lines = self.partial_input.split(b"\n") # if input doesn't end in a newline, replace the # held partial input with the last line of it - if not self.partial_input.endswith("\n"): + if not self.partial_input.endswith(b"\n"): self.partial_input = new_input_lines.pop() # otherwise, chop off the extra null input and reset # the held partial input else: new_input_lines.pop() - self.partial_input = "" + self.partial_input = b"" # iterate over the remaining lines for line in new_input_lines: @@ -958,8 +958,8 @@ class User: # log non-printable characters remaining if mudpy.telnet.is_enabled(self, mudpy.telnet.TELOPT_BINARY, mudpy.telnet.HIM): - asciiline = "".join( - filter(lambda x: " " <= x <= "~", line)) + asciiline = b"".join( + filter(lambda x: b" " <= x <= b"~", line)) if line != asciiline: logline = "Non-ASCII characters from " if self.account and self.account.get("name"): @@ -970,10 +970,22 @@ class User: log(logline, 4) line = asciiline + try: + line = line.decode("utf-8") + except UnicodeDecodeError: + logline = "Non-UTF-8 characters from " + if self.account and self.account.get("name"): + logline += self.account.get("name") + ": " + else: + logline += "unknown user: " + logline += repr(line) + log(logline, 4) + return + + line = unicodedata.normalize("NFKC", line) + # put on the end of the queue - self.input_queue.append( - unicodedata.normalize("NFKC", line.decode("utf-8")) - ) + self.input_queue.append(line) def new_avatar(self): """Instantiate a new, unconfigured avatar for this user.""" diff --git a/lib/mudpy/telnet.py b/lib/mudpy/telnet.py index 3ce73a3..7765571 100644 --- a/lib/mudpy/telnet.py +++ b/lib/mudpy/telnet.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- """Telnet functions and constants for the mudpy engine.""" -# Copyright (c) 2004-2012 Jeremy Stanley . Permission +# Copyright (c) 2004-2013 Jeremy Stanley . Permission # to use, copy, modify, and distribute this software is granted under # terms provided in the LICENSE file distributed with this software. @@ -49,8 +49,7 @@ US = 1 def telnet_proto(*arguments): """Return a concatenated series of Telnet protocol commands.""" - # (this will need to be byte type during 2to3 migration) - return "".join([chr(x) for x in arguments]) + return bytes((arguments)) def send_command(user, *command): @@ -126,8 +125,7 @@ def negotiate_telnet_options(user): break # the byte following the IAC is our command - # (this will need to be byte type during 2to3 migration) - command = ord(text[position + 1]) + command = text[position+1] # replace a double (literal) IAC if there's an LF later if command is IAC: @@ -139,8 +137,7 @@ def negotiate_telnet_options(user): # implement an RFC 1143 option negotiation queue here elif len_text > position + 2 and WILL <= command <= DONT: - # this will need to be byte type during 2to3 migration - telopt = ord(text[position + 2]) + telopt = text[position+2] if telopt in supported: if command <= WONT: party = HIM @@ -184,10 +181,8 @@ def negotiate_telnet_options(user): # subnegotiation options elif len_text > position + 4 and command is SB: - # this will need to be byte type during 2to3 migration telopt = ord(text[position + 2]) if telopt is TELOPT_NAWS: - # this will need to be byte type during 2to3 migration user.columns = ord(text[position + 3]) * \ 256 + ord(text[position + 4]) end_subnegotiation = text.find(telnet_proto(IAC, SE), position) -- 2.11.0