"""User command functions for the mudpy engine."""
-# Copyright (c) 2004-2019 mudpy authors. Permission to use, copy,
+# Copyright (c) 2004-2022 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 random
import re
+import traceback
import unicodedata
import mudpy
actor.send("Exiting chat mode.")
else:
actor.send("Sorry, but you're already busy with something else!")
+ return True
def create(actor, parameters):
elif len(arguments) > 2:
message = "You can only specify an element and a filename."
actor.send(message)
+ return True
def delete(actor, parameters):
+ '". Try "show element ' +
element + '" for verification.')
actor.send(message)
+ return True
def destroy(actor, parameters):
6
)
actor.send(message)
+ return True
def error(actor, input_data):
"""Generic error for an unrecognized command word."""
# 90% of the time use a generic error
- if random.randrange(10):
+ # Allow the random.randrange() call in bandit since it's not used for
+ # security/cryptographic purposes
+ if random.randrange(10): # nosec
message = '''I'm not sure what "''' + input_data + '''" means...'''
# 10% of the time use the classic diku error
else:
message = "Arglebargle, glop-glyf!?!"
- # send the error message
+ # try to send the error message, and log if we can't
+ try:
+ actor.send(message)
+ except Exception:
+ mudpy.misc.log(
+ 'Sending a command error to user %s raised exception...\n%s' % (
+ actor.owner.account.get("name"), traceback.format_exc()))
+ return True
+
+
+def evaluate(actor, parameters):
+ """Evaluate a Python expression."""
+
+ if not parameters:
+ message = "You need to supply a Python expression."
+ elif "__" in parameters:
+ message = "Double-underscores (__) are not allowed in expressions."
+ elif "lambda" in parameters:
+ message = "Lambda functions are not allowed in expressions."
+ else:
+ # Strictly limit the allowed builtins and modules
+ eval_globals = {"__builtins__": dict()}
+ for allowed in ("dir", "globals", "len", "locals"):
+ eval_globals["__builtins__"][allowed] = __builtins__[allowed]
+ eval_globals["mudpy"] = mudpy
+ eval_globals["universe"] = actor.universe
+ try:
+ # there is no other option than to use eval() for this, since
+ # its purpose is to evaluate arbitrary expressions, so do what
+ # we can to secure it and allow it for bandit analysis
+ message = repr(eval(parameters, eval_globals)) # nosec
+ except Exception as e:
+ message = ("$(red)Your expression raised an exception...$(eol)"
+ "$(eol)$(bld)%s$(nrm)" % e)
+ actor.send(message)
+ return True
+
+
+def c_get(actor, parameters):
+ """Move a prop into inventory."""
+ if not parameters:
+ message = "What do you wish to get?"
+ else:
+ message = ('Not yet implemented.')
+ actor.send(message)
+ return True
+
+
+def drop(actor, parameters):
+ """Move a prop out of inventory."""
+ if not parameters:
+ message = "What do you wish to drop?"
+ else:
+ message = ('Not yet implemented.')
actor.send(message)
+ return True
def halt(actor, parameters):
# set a flag to terminate the world
actor.universe.terminate_flag = True
+ return True
def help(actor, parameters):
description = command.get("description")
if not description:
description = "(no short description provided)"
- if command.get("administrative"):
+ if command.is_restricted():
output = "$(red)"
else:
output = "$(grn)"
if actor.can_run(command):
if really_see_also:
really_see_also += ", "
- if command.get("administrative"):
+ if command.is_restricted():
really_see_also += "$(red)"
else:
really_see_also += "$(grn)"
# no specific command word was indicated
else:
- # give a sorted list of commands with descriptions if provided
- output = "These are the commands available to you:$(eol)$(eol)"
- sorted_commands = list(actor.universe.groups["command"].keys())
- sorted_commands.sort()
- for item in sorted_commands:
- command = actor.universe.groups["command"][item]
+ # preamble text
+ output = ("These are the commands available to you [brackets indicate "
+ "optional portion]:$(eol)$(eol)")
+
+ # list command names in alphabetical order
+ for command_name, command in sorted(
+ actor.universe.groups["command"].items()):
+
+ # skip over disallowed commands
if actor.can_run(command):
- description = command.get("description")
- if not description:
- description = "(no short description provided)"
- if command.get("administrative"):
- output += " $(red)"
+
+ # start incrementing substrings
+ for position in range(1, len(command_name) + 1):
+
+ # we've found our shortest possible abbreviation
+ candidate = mudpy.misc.find_command(
+ command_name[:position])
+ try:
+ if candidate.subkey == command_name:
+ break
+ except AttributeError:
+ pass
+
+ # use square brackets to indicate optional part of command name
+ if position < len(command_name):
+ abbrev = "%s[%s]" % (
+ command_name[:position], command_name[position:])
else:
- output += " $(grn)"
- output += item + "$(nrm) - " + description + "$(eol)"
- output += ('$(eol)Enter "help COMMAND" for help on a command '
- 'named "COMMAND".')
+ abbrev = command_name
+
+ # supply a useful default if the short description is missing
+ description = command.get(
+ "description", "(no short description provided)")
+
+ # administrative command names are in red, others in green
+ if command.is_restricted():
+ color = "red"
+ else:
+ color = "grn"
+
+ # format the entry for this command
+ output = "%s $(%s)%s$(nrm) - %s$(eol)" % (
+ output, color, abbrev, description)
+
+ # add a footer with instructions on getting additional information
+ output = ('%s $(eol)Enter "help COMMAND" for help on a command named '
+ '"COMMAND".' % output)
# send the accumulated output to the user
actor.send(output)
+ return True
+
+
+def inventory(actor, parameters):
+ """List the inventory."""
+ message = ('Not yet implemented.')
+ actor.send(message)
+ return True
def look(actor, parameters):
actor.send("You can't look at or in anything yet.")
else:
actor.look_at(actor.get("location"))
+ return True
def move(actor, parameters):
"""Move the avatar in a given direction."""
- if parameters in actor.universe.contents[actor.get("location")].portals():
- actor.move_direction(parameters)
- else:
- actor.send("You cannot go that way.")
+ for portal in sorted(
+ actor.universe.contents[actor.get("location")].portals()):
+ if portal.startswith(parameters):
+ actor.move_direction(portal)
+ return portal
+ actor.send("You cannot go that way.")
+ return True
def preferences(actor, parameters):
message = ""
arguments = parameters.split()
allowed_prefs = set()
+ base_prefs = []
user_config = actor.universe.contents.get("mudpy.user")
if user_config:
- allowed_prefs.update(user_config.get("pref_allow", []))
+ base_prefs = user_config.get("pref_allow", [])
+ allowed_prefs.update(base_prefs)
if actor.owner.account.get("administrator"):
allowed_prefs.update(user_config.get("pref_admin", []))
if not arguments:
message += "These are your current preferences:"
- for pref in allowed_prefs:
- message += ("$(eol) $(red)%s $(grn)%s$(nrm)"
- % (pref, actor.owner.account.get(pref)))
+
+ # color-code base and admin prefs
+ for pref in sorted(allowed_prefs):
+ if pref in base_prefs:
+ color = "grn"
+ else:
+ color = "red"
+ message += ("$(eol) $(%s)%s$(nrm) - %s" % (
+ color, pref, actor.owner.account.get(pref, "<not set>")))
+
elif arguments[0] not in allowed_prefs:
message += (
'Preference "%s" does not exist. Try the `preferences` command by '
"itself for a list of valid preferences." % arguments[0])
elif len(arguments) == 1:
- message += "%s" % actor.owner.account.get(arguments[0])
+ message += "%s" % actor.owner.account.get(arguments[0], "<not set>")
else:
pref = arguments[0]
value = " ".join(arguments[1:])
'Preference "%s" cannot be set to type "%s".' % (
pref, type(value)))
actor.send(message)
+ return True
def quit(actor, parameters):
if actor.owner:
actor.owner.state = "main_utility"
actor.owner.deactivate_avatar()
+ return True
def reload(actor, parameters):
# set a flag to reload
actor.universe.reload_flag = True
+ return True
def say(actor, parameters):
# there was no message
else:
actor.send("What do you want to say?")
+ return True
def c_set(actor, parameters):
+ '". Try "show element ' +
element + '" for verification.')
actor.send(message)
+ return True
def show(actor, parameters):
elif arguments[0] == "version":
message = repr(actor.universe.versions)
elif arguments[0] == "time":
- message = actor.universe.groups["internal"]["counters"].get(
- "elapsed"
- ) + " increments elapsed since the world was created."
+ message = "%s increments elapsed since the world was created." % (
+ str(actor.universe.groups["internal"]["counters"].get("elapsed")))
elif arguments[0] == "groups":
message = "These are the element groups:$(eol)"
groups = list(actor.universe.groups.keys())
(facet, str(facets[facet])))
else:
message = 'Element "' + arguments[1] + '" does not exist.'
- elif arguments[0] == "result":
- if len(arguments) < 2:
- message = "You need to specify an expression."
- else:
- try:
- message = repr(eval(" ".join(arguments[1:])))
- except Exception as e:
- message = ("$(red)Your expression raised an exception...$(eol)"
- "$(eol)$(bld)%s$(nrm)" % e)
elif arguments[0] == "log":
if len(arguments) == 4:
if re.match(r"^\d+$", arguments[3]) and int(arguments[3]) >= 0:
else:
message = '''I don't know what "''' + parameters + '" is.'
actor.send(message)
+ return True