X-Git-Url: https://mudpy.org/gitweb?p=mudpy.git;a=blobdiff_plain;f=lib%2Fmudpy%2Fmisc.py;h=8f6630f8b05e83a28329dd316336d2093b851462;hp=73f02537151c7e151710fdf3e05ae76929cb14ac;hb=761af6ff61bb547f76c761acbe41d0ef11d51681;hpb=b6574aab1f989ed8d9713afac7424c296983b3e4 diff --git a/lib/mudpy/misc.py b/lib/mudpy/misc.py index 73f0253..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-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. @@ -12,7 +12,7 @@ class Element: def __init__(self, key, universe, filename=None): """Set up a new element.""" - import data + import mudpy.data import os.path # keep track of our key name @@ -56,7 +56,7 @@ class Element: # add the file if it doesn't exist yet if filename not in self.universe.files: - data.DataFile(filename, self.universe) + mudpy.data.DataFile(filename, self.universe) # record or reset a pointer to the origin file self.origin = self.universe.files[filename] @@ -142,7 +142,7 @@ class Element: return default def getint(self, facet, default=None): - """Return values as int/long type.""" + """Return values as int type.""" if default is None: default = 0 if self.origin.data.has_option(self.key, facet): @@ -169,41 +169,40 @@ class Element: def getlist(self, facet, default=None): """Return values as list type.""" - import data + import mudpy.data if default is None: default = [] value = self.get(facet) if value: - return data.makelist(value) + return mudpy.data.makelist(value) else: return default def getdict(self, facet, default=None): """Return values as dict type.""" - import data + import mudpy.data if default is None: default = {} value = self.get(facet) if value: - return data.makedict(value) + return mudpy.data.makedict(value) else: return default def set(self, facet, value): """Set values.""" if not self.has_facet(facet) or not self.get(facet) == value: - if type(value) is long or repr(type(value)) == "": + # TODO: remove this check after the switch to py3k + if repr(type(value)) == "": value = str(value) - elif not type(value) is str: + if not type(value) is str: value = repr(value) self.origin.data.set(self.key, facet, value) self.origin.modified = True def append(self, facet, value): - """Append value tp a list.""" - if type(value) is long: - value = str(value) - elif not type(value) is str: + """Append value to a list.""" + if not type(value) is str: value = repr(value) newlist = self.getlist(facet) newlist.append(value) @@ -350,7 +349,7 @@ class Element: description = element.get("description") if description: message += description + "$(eol)" - portal_list = element.portals().keys() + portal_list = list(element.portals().keys()) if portal_list: portal_list.sort() message += "$(cyn)[ Exits: " + ", ".join( @@ -457,7 +456,7 @@ class Universe: def load(self): """Load universe data from persistent storage.""" - import data + import mudpy.data # the files dict must exist and filename needs to be read-only if not hasattr( @@ -475,7 +474,7 @@ class Universe: del self.files[data_filename] # start loading from the initial file - data.DataFile(self.filename, self) + mudpy.data.DataFile(self.filename, self) # make a list of inactive avatars inactive_avatars = [] @@ -575,7 +574,7 @@ class User: def __init__(self): """Default values for the in-memory user variables.""" - import telnet + import mudpy.telnet self.account = None self.address = "" self.authenticated = False @@ -590,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 = {} @@ -755,12 +754,15 @@ class User: def adjust_echoing(self): """Adjust echoing to match state menu requirements.""" - import telnet - if telnet.is_enabled(self, telnet.TELOPT_ECHO, telnet.US): + import mudpy.telnet + if mudpy.telnet.is_enabled(self, mudpy.telnet.TELOPT_ECHO, + mudpy.telnet.US): if menu_echo_on(self.state): - telnet.disable(self, telnet.TELOPT_ECHO, telnet.US) + mudpy.telnet.disable(self, mudpy.telnet.TELOPT_ECHO, + mudpy.telnet.US) elif not menu_echo_on(self.state): - telnet.enable(self, telnet.TELOPT_ECHO, telnet.US) + mudpy.telnet.enable(self, mudpy.telnet.TELOPT_ECHO, + mudpy.telnet.US) def remove(self): """Remove a user from the list of connected users.""" @@ -778,7 +780,7 @@ class User: prepend_padding=True ): """Send arbitrary text to a connected user.""" - import telnet + import mudpy.telnet # unless raw mode is on, clean it up all nice and pretty if not raw: @@ -830,7 +832,8 @@ class User: output = wrap_ansi_text(output, wrap) # if supported by the client, encode it utf-8 - if telnet.is_enabled(self, telnet.TELOPT_BINARY, telnet.US): + if mudpy.telnet.is_enabled(self, mudpy.telnet.TELOPT_BINARY, + mudpy.telnet.US): encoded_output = output.encode("utf-8") # otherwise just send ascii @@ -839,12 +842,14 @@ class User: # end with a terminator if requested if add_prompt or add_terminator: - if telnet.is_enabled(self, telnet.TELOPT_EOR, telnet.US): - encoded_output += telnet.telnet_proto(telnet.IAC, - telnet.EOR) - elif not telnet.is_enabled(self, telnet.TELOPT_SGA, telnet.US): - encoded_output += telnet.telnet_proto(telnet.IAC, - telnet.GA) + if mudpy.telnet.is_enabled( + self, mudpy.telnet.TELOPT_EOR, mudpy.telnet.US): + encoded_output += mudpy.telnet.telnet_proto( + mudpy.telnet.IAC, mudpy.telnet.EOR) + elif not mudpy.telnet.is_enabled( + self, mudpy.telnet.TELOPT_SGA, mudpy.telnet.US): + encoded_output += mudpy.telnet.telnet_proto( + mudpy.telnet.IAC, mudpy.telnet.GA) # and tack it onto the queue self.output_queue.append(encoded_output) @@ -912,14 +917,14 @@ class User: def enqueue_input(self): """Process and enqueue any new input.""" - import telnet + import mudpy.telnet import unicodedata # check for some input try: raw_input = self.connection.recv(1024) except: - raw_input = "" + raw_input = b"" # we got something if raw_input: @@ -928,21 +933,21 @@ class User: self.partial_input += raw_input # reply to and remove any IAC negotiation codes - telnet.negotiate_telnet_options(self) + 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: @@ -951,8 +956,10 @@ class User: line = line.strip() # log non-printable characters remaining - if telnet.is_enabled(self, telnet.TELOPT_BINARY, telnet.HIM): - asciiline = filter(lambda x: " " <= x <= "~", line) + if mudpy.telnet.is_enabled(self, mudpy.telnet.TELOPT_BINARY, + mudpy.telnet.HIM): + 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"): @@ -963,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.""" @@ -1322,7 +1341,7 @@ def random_name(): def replace_macros(user, text, is_input=False): """Replaces macros in text output.""" import codecs - import data + import mudpy.data import os.path # third person pronouns @@ -1372,7 +1391,7 @@ def replace_macros(user, text, is_input=False): # this is how we handle local file inclusion (dangerous!) elif macro.startswith("inc:"): - incfile = data.find_file(macro[4:], universe=universe) + incfile = mudpy.data.find_file(macro[4:], universe=universe) if os.path.exists(incfile): incfd = codecs.open(incfile, "r", "utf-8") replacement = "" @@ -1495,7 +1514,7 @@ def reload_data(): def check_for_connection(listening_socket): """Check for a waiting connection and return a new user object.""" - import telnet + import mudpy.telnet # try to accept a new connection try: @@ -1519,7 +1538,7 @@ def check_for_connection(listening_socket): user.address = address[0] # let the client know we WILL EOR (RFC 885) - telnet.enable(user, telnet.TELOPT_EOR, telnet.US) + mudpy.telnet.enable(user, mudpy.telnet.TELOPT_EOR, mudpy.telnet.US) user.negotiation_pause = 2 # return the new user object @@ -1645,7 +1664,7 @@ def get_menu_choices(user): def get_formatted_menu_choices(state, choices): """Returns a formatted string of menu choices.""" choice_output = "" - choice_keys = choices.keys() + choice_keys = list(choices.keys()) choice_keys.sort() for choice in choice_keys: choice_output += " [$(red)" + choice + "$(nrm)] " + choices[ @@ -1712,10 +1731,11 @@ def get_choice_action(user, choice): def handle_user_input(user): """The main handler, branches to a state-specific handler.""" - import telnet + import mudpy.telnet # if the user's client echo is off, send a blank line for aesthetics - if telnet.is_enabled(user, telnet.TELOPT_ECHO, telnet.US): + if mudpy.telnet.is_enabled(user, mudpy.telnet.TELOPT_ECHO, + mudpy.telnet.US): user.send("", add_prompt=False, prepend_padding=False) # check to make sure the state is expected, then call that handler @@ -1765,9 +1785,9 @@ def handler_entering_account_name(user): name = input_data.lower() # fail if there are non-alphanumeric characters - if name != filter( - lambda x: x >= "0" and x <= "9" or x >= "a" and x <= "z", name - ): + if name != "".join(filter( + lambda x: x >= "0" and x <= "9" or x >= "a" and x <= "z", + name)): user.error = "bad_name" # if that account exists, time to request a password @@ -1789,13 +1809,13 @@ def handler_entering_account_name(user): def handler_checking_password(user): """Handle the login account password.""" - import password + import mudpy.password # get the next waiting line of input input_data = user.input_queue.pop(0) # does the hashed input equal the stored hash? - if password.verify(input_data, user.account.get("passhash")): + if mudpy.password.verify(input_data, user.account.get("passhash")): # if so, set the username and load from cold storage if not user.replace_old_connections(): @@ -1823,7 +1843,7 @@ def handler_checking_password(user): def handler_entering_new_password(user): """Handle a new password entry.""" - import password + import mudpy.password # get the next waiting line of input input_data = user.input_queue.pop(0) @@ -1831,15 +1851,15 @@ def handler_entering_new_password(user): # make sure the password is strong--at least one upper, one lower and # one digit, seven or more characters in length if len(input_data) > 6 and len( - filter(lambda x: x >= "0" and x <= "9", input_data) + list(filter(lambda x: x >= "0" and x <= "9", input_data)) ) and len( - filter(lambda x: x >= "A" and x <= "Z", input_data) + list(filter(lambda x: x >= "A" and x <= "Z", input_data)) ) and len( - filter(lambda x: x >= "a" and x <= "z", input_data) + list(filter(lambda x: x >= "a" and x <= "z", input_data)) ): # hash and store it, then move on to verification - user.account.set("passhash", password.create(input_data)) + user.account.set("passhash", mudpy.password.create(input_data)) user.state = "verifying_new_password" # the password was weak, try again if you haven't tried too many times @@ -1864,13 +1884,13 @@ def handler_entering_new_password(user): def handler_verifying_new_password(user): """Handle the re-entered new password for verification.""" - import password + import mudpy.password # get the next waiting line of input input_data = user.input_queue.pop(0) # hash the input and match it to storage - if password.verify(input_data, user.account.get("passhash")): + if mudpy.password.verify(input_data, user.account.get("passhash")): user.authenticate() # the hashes matched, so go active @@ -2042,7 +2062,7 @@ def command_help(actor, parameters): # give a sorted list of commands with descriptions if provided output = "These are the commands available to you:$(eol)$(eol)" - sorted_commands = universe.categories["command"].keys() + sorted_commands = list(universe.categories["command"].keys()) sorted_commands.sort() for item in sorted_commands: command = universe.categories["command"][item] @@ -2182,13 +2202,13 @@ def command_show(actor, parameters): ) + " increments elapsed since the world was created." elif arguments[0] == "categories": message = "These are the element categories:$(eol)" - categories = universe.categories.keys() + categories = list(universe.categories.keys()) categories.sort() for category in categories: message += "$(eol) $(grn)" + category + "$(nrm)" elif arguments[0] == "files": message = "These are the current files containing the universe:$(eol)" - filenames = universe.files.keys() + filenames = list(universe.files.keys()) filenames.sort() for filename in filenames: if universe.files[filename].is_writeable():