X-Git-Url: https://mudpy.org/gitweb?p=mudpy.git;a=blobdiff_plain;f=mudpy%2Fmisc.py;h=24443dd9a82bf035ea43197112ad8da27cd66010;hp=b4009c90c9cf9e9dafb6962e330084da75853735;hb=40fb678ab8ea5e35f06826bda8f484053dd831b1;hpb=f0c07e0cbc98ffc01b59d15a0e9854b04ebc8a78 diff --git a/mudpy/misc.py b/mudpy/misc.py index b4009c9..24443dd 100644 --- a/mudpy/misc.py +++ b/mudpy/misc.py @@ -406,7 +406,7 @@ class Universe: """Create a new, empty Universe (the Big Bang).""" new_universe = Universe() for attribute in vars(self).keys(): - exec("new_universe." + attribute + " = self." + attribute) + setattr(new_universe, attribute, getattr(self, attribute)) new_universe.reload_flag = False del self return new_universe @@ -457,10 +457,8 @@ class Universe: self.listening_socket.listen(1) # note that we're now ready for user connections - log( - "Listening for Telnet connections on: " + - host + ":" + str(port) - ) + log("Listening for Telnet connections on %s port %s" % ( + host, str(port))) def get_time(self): """Convenience method to get the elapsed time counter.""" @@ -639,14 +637,13 @@ class User: """Flag the user as authenticated and disconnect duplicates.""" if self.state != "authenticated": self.authenticated = True + log("User %s authenticated for account %s." % ( + self, self.account.subkey), 2) if ("mudpy.limit" in universe.contents and self.account.subkey in universe.contents["mudpy.limit"].get("admins")): self.account.set("administrator", True) - log("Administrator %s authenticated." % - self.account.get("name"), 2) - else: - log("User %s authenticated for account %s." % ( - self, self.account.subkey), 2) + log("Account %s is an administrator." % ( + self.account.subkey), 2) def show_menu(self): """Send the user their current menu.""" @@ -663,7 +660,27 @@ class User: def prompt(self): """"Generate and return an input prompt.""" - return self.account.get("prompt", ">") + " " + + # Start with the user's preference, if one was provided + prompt = self.account.get("prompt") + + # If the user has not set a prompt, then immediately return the default + # provided for the current state + if not prompt: + return get_menu_prompt(self.state) + + # Allow including the World clock state + if "$_(time)" in prompt: + prompt = prompt.replace( + "$_(time)", + str(universe.groups["internal"]["counters"].get("elapsed"))) + + # Append a single space for clear separation from user input + if prompt[-1] != " ": + prompt = "%s " % prompt + + # Return the cooked prompt + return prompt def adjust_echoing(self): """Adjust echoing to match state menu requirements.""" @@ -1454,6 +1471,27 @@ def check_for_connection(listening_socket): return user +def find_command(command_name): + """Try to find a command by name or abbreviation.""" + + # lowercase the command + command_name = command_name.lower() + + command = None + if command_name in universe.groups["command"]: + # the command matches a command word for which we have data + command = universe.groups["command"][command_name] + else: + for candidate in sorted(universe.groups["command"]): + if candidate.startswith(command_name) and not universe.groups[ + "command"][candidate].get("administrative"): + # the command matches the start of a command word and is not + # restricted to administrators + command = universe.groups["command"][candidate] + break + return command + + def get_menu(state, error=None, choices=None): """Show the correct menu text to a user.""" @@ -1647,9 +1685,9 @@ def handle_user_input(user): user.send("", add_prompt=False, prepend_padding=False) # check to make sure the state is expected, then call that handler - if "handler_" + user.state in globals(): - exec("handler_" + user.state + "(user)") - else: + try: + globals()["handler_" + user.state](user) + except KeyError: generic_menu_handler(user) # since we got input, flag that the menu/prompt needs to be redisplayed @@ -1844,21 +1882,36 @@ def handler_active(user): else: command_name, parameters = first_word(input_data) - # lowercase the command - command_name = command_name.lower() - - # the command matches a command word for which we have data - if command_name in universe.groups["command"]: - command = universe.groups["command"][command_name] - else: - command = None + # expand to an actual command + command = find_command(command_name) # if it's allowed, do it + ran = False if actor.can_run(command): - exec(command.get("action")) - - # otherwise, give an error - elif command_name: + # dereference the relative object path for the requested function + action = mudpy + action_fname = command.get("action", command.key) + for component in action_fname.split("."): + try: + action = getattr(action, component) + ran = True + except AttributeError: + log('Could not find action function "%s" for command "%s"' + % (action_fname, command_name)) + action = None + break + if action: + try: + action(actor, parameters) + except Exception: + log('Command string "%s" from user %s raised an ' + 'exception...\n%s' % ( + input_data, actor.owner.account.get("name"), + traceback.format_exc())) + mudpy.command.error(actor, input_data) + + # if the command was not run, give an error + if not ran: mudpy.command.error(actor, input_data) # if no input, just idle back with a prompt @@ -2024,8 +2077,9 @@ def setup(): log("Import path: %s" % ", ".join(sys.path), 1) log("Installed dependencies: %s" % universe.versions.dependencies_text, 1) log("Other python packages: %s" % universe.versions.environment_text, 1) - log("Started %s with command line: %s" % ( - universe.versions.version, " ".join(sys.argv)), 1) + log("Running version: %s" % universe.versions.version, 1) + log("Initial directory: %s" % universe.startdir, 1) + log("Command line: %s" % " ".join(sys.argv), 1) # pass the initialized universe back return universe