2017-10-27 12:15:33 +00:00
|
|
|
import re
|
2016-03-30 18:31:23 +00:00
|
|
|
import Utils
|
|
|
|
|
2016-12-05 23:32:31 +00:00
|
|
|
STR_MORE = "%s (more...)" % Utils.FONT_RESET
|
2016-03-29 11:56:58 +00:00
|
|
|
STR_CONTINUED = "(...continued) "
|
|
|
|
|
|
|
|
OUT_CUTOFF = 400
|
|
|
|
|
2017-10-27 12:15:33 +00:00
|
|
|
REGEX_CUTOFF = re.compile("^.{1,%d}(?:\s|$)" % OUT_CUTOFF)
|
|
|
|
|
2016-03-29 15:22:22 +00:00
|
|
|
class Out(object):
|
|
|
|
def __init__(self, module_name, target):
|
2016-03-29 11:56:58 +00:00
|
|
|
self.module_name = module_name
|
2016-03-29 15:22:22 +00:00
|
|
|
self.target = target
|
2016-03-29 11:56:58 +00:00
|
|
|
self._text = ""
|
|
|
|
self.written = False
|
|
|
|
def write(self, text):
|
|
|
|
self._text += text
|
|
|
|
self.written = True
|
|
|
|
return self
|
|
|
|
def send(self):
|
|
|
|
if self.has_text():
|
2018-07-14 08:50:12 +00:00
|
|
|
text = self._text
|
2016-03-29 11:56:58 +00:00
|
|
|
text_encoded = text.encode("utf8")
|
|
|
|
if len(text_encoded) > OUT_CUTOFF:
|
|
|
|
text = "%s%s" % (text_encoded[:OUT_CUTOFF].decode("utf8"
|
|
|
|
).rstrip(), STR_MORE)
|
|
|
|
self._text = "%s%s" % (STR_CONTINUED, text_encoded[OUT_CUTOFF:
|
|
|
|
].decode("utf8").lstrip())
|
2018-07-14 08:50:12 +00:00
|
|
|
self.target.send_message(text, prefix="[%s] " % self.prefix())
|
2016-03-29 11:56:58 +00:00
|
|
|
def set_prefix(self, prefix):
|
|
|
|
self.module_name = prefix
|
|
|
|
def has_text(self):
|
|
|
|
return bool(self._text)
|
|
|
|
|
2016-03-29 15:22:22 +00:00
|
|
|
class StdOut(Out):
|
2016-03-29 11:56:58 +00:00
|
|
|
def prefix(self):
|
2016-03-30 18:31:23 +00:00
|
|
|
return "%s%s%s" % (Utils.color(Utils.COLOR_GREEN),
|
|
|
|
self.module_name, Utils.FONT_RESET)
|
2016-03-29 15:22:22 +00:00
|
|
|
class StdErr(Out):
|
2016-03-29 11:56:58 +00:00
|
|
|
def prefix(self):
|
2016-03-30 18:31:23 +00:00
|
|
|
return "%s!%s%s" % (Utils.color(Utils.COLOR_RED),
|
|
|
|
self.module_name, Utils.FONT_RESET)
|
2016-03-29 11:56:58 +00:00
|
|
|
|
|
|
|
class Module(object):
|
|
|
|
def __init__(self, bot):
|
|
|
|
self.bot = bot
|
|
|
|
bot.events.on("received").on("message").on("channel").hook(
|
|
|
|
self.channel_message)
|
|
|
|
bot.events.on("received").on("message").on("private").hook(
|
|
|
|
self.private_message)
|
2016-03-29 15:22:22 +00:00
|
|
|
bot.events.on("received").on("command").on("help").hook(self.help,
|
2016-04-06 11:02:44 +00:00
|
|
|
help="Show help for commands", usage="<command>")
|
2016-04-05 17:41:03 +00:00
|
|
|
bot.events.on("received").on("command").on("usage").hook(self.usage,
|
2016-04-06 11:02:44 +00:00
|
|
|
help="Show usage help for commands", min_args=1,
|
|
|
|
usage="<command>")
|
2016-03-29 15:22:22 +00:00
|
|
|
bot.events.on("received").on("command").on("more").hook(self.more,
|
2018-07-14 08:50:12 +00:00
|
|
|
help="Get more output from the last command", skip_out=True)
|
2016-03-29 11:56:58 +00:00
|
|
|
|
2017-12-26 10:32:36 +00:00
|
|
|
bot.events.on("postboot").on("configure").on(
|
2016-04-14 15:48:44 +00:00
|
|
|
"channelset").call(setting="command-prefix",
|
|
|
|
help="Set the command prefix used in this channel")
|
|
|
|
|
2017-12-26 10:32:36 +00:00
|
|
|
bot.events.on("new").on("user", "channel").hook(self.new)
|
|
|
|
bot.events.on("send").on("stdout").hook(self.send_stdout)
|
|
|
|
bot.events.on("send").on("stderr").hook(self.send_stderr)
|
|
|
|
|
2016-03-29 11:56:58 +00:00
|
|
|
def new(self, event):
|
|
|
|
if "user" in event:
|
|
|
|
target = event["user"]
|
|
|
|
else:
|
|
|
|
target = event["channel"]
|
|
|
|
target.last_stdout = None
|
|
|
|
target.last_stderr = None
|
|
|
|
|
|
|
|
def has_command(self, command):
|
|
|
|
return command.lower() in self.bot.events.on("received").on(
|
|
|
|
"command").get_children()
|
|
|
|
def get_hook(self, command):
|
|
|
|
return self.bot.events.on("received").on("command").on(command
|
|
|
|
).get_hooks()[0]
|
|
|
|
|
2016-03-30 11:49:46 +00:00
|
|
|
def is_highlight(self, server, s):
|
|
|
|
return s.lower() == server.nickname_lower or (s.lower().startswith(
|
|
|
|
server.nickname_lower) and len(s) == len(server.nickname_lower
|
|
|
|
)+1 and s[-1] in [":", ","])
|
|
|
|
|
|
|
|
def message(self, event, command, args_index=1):
|
2016-03-29 15:22:22 +00:00
|
|
|
if self.has_command(command):
|
|
|
|
hook = self.get_hook(command)
|
|
|
|
is_channel = False
|
|
|
|
|
|
|
|
if "channel" in event:
|
|
|
|
target = event["channel"]
|
|
|
|
is_channel = True
|
|
|
|
else:
|
|
|
|
target = event["user"]
|
|
|
|
if not is_channel and hook.kwargs.get("channel_only"):
|
|
|
|
return
|
2016-04-04 22:20:55 +00:00
|
|
|
if is_channel and hook.kwargs.get("private_only"):
|
2016-04-04 17:41:07 +00:00
|
|
|
return
|
2016-03-29 15:22:22 +00:00
|
|
|
|
|
|
|
log = target.log
|
|
|
|
|
|
|
|
module_name = hook.function.__self__._name
|
|
|
|
stdout, stderr = StdOut(module_name, target), StdErr(module_name,
|
|
|
|
target)
|
|
|
|
|
|
|
|
returns = self.bot.events.on("preprocess").on("command"
|
2016-04-18 15:48:36 +00:00
|
|
|
).call(hook=hook, user=event["user"], server=event["server"],
|
|
|
|
target=target, is_channel=is_channel)
|
2016-03-29 15:22:22 +00:00
|
|
|
for returned in returns:
|
|
|
|
if returned:
|
|
|
|
stderr.write(returned).send()
|
2016-04-03 12:20:05 +00:00
|
|
|
log.skip_next()
|
2016-03-29 15:22:22 +00:00
|
|
|
return
|
2016-03-30 11:49:46 +00:00
|
|
|
args_split = list(filter(None, event["message_split"][args_index:]))
|
2016-03-29 15:22:22 +00:00
|
|
|
min_args = hook.kwargs.get("min_args")
|
|
|
|
if min_args and len(args_split) < min_args:
|
2016-04-10 16:31:55 +00:00
|
|
|
if "usage" in hook.kwargs:
|
|
|
|
stderr.write("Not enough arguments, usage: %s %s" % (
|
|
|
|
command, hook.kwargs["usage"])).send()
|
|
|
|
else:
|
|
|
|
stderr.write("Not enough arguments (minimum: %d)" % min_args
|
|
|
|
).send()
|
2016-03-29 15:22:22 +00:00
|
|
|
else:
|
|
|
|
args = " ".join(args_split)
|
|
|
|
server = event["server"]
|
|
|
|
user = event["user"]
|
|
|
|
self.bot.events.on("received").on("command").on(command).call(
|
|
|
|
1, user=user, server=server, target=target, log=log,
|
|
|
|
args=args, args_split=args_split, stdout=stdout, stderr=stderr,
|
2016-05-06 12:36:01 +00:00
|
|
|
command=command.lower(), is_channel=is_channel)
|
2018-07-14 08:50:12 +00:00
|
|
|
if not hook.kwargs.get("skip_out", False):
|
|
|
|
stdout.send()
|
|
|
|
stderr.send()
|
|
|
|
target.last_stdout = stdout
|
|
|
|
target.last_stderr = stderr
|
2016-04-03 12:20:05 +00:00
|
|
|
log.skip_next()
|
|
|
|
|
2016-03-29 15:22:22 +00:00
|
|
|
|
2016-03-29 11:56:58 +00:00
|
|
|
def channel_message(self, event):
|
2016-04-14 15:48:44 +00:00
|
|
|
command_prefix = event["channel"].get_setting("command-prefix",
|
|
|
|
event["server"].get_setting("command-prefix", "!"))
|
2016-03-29 11:56:58 +00:00
|
|
|
if event["message_split"][0].startswith(command_prefix):
|
|
|
|
command = event["message_split"][0].replace(
|
|
|
|
command_prefix, "", 1).lower()
|
2016-03-29 15:22:22 +00:00
|
|
|
self.message(event, command)
|
2016-03-30 11:49:46 +00:00
|
|
|
elif len(event["message_split"]) > 1 and self.is_highlight(
|
|
|
|
event["server"], event["message_split"][0]):
|
|
|
|
command = event["message_split"][1].lower()
|
|
|
|
self.message(event, command, 2)
|
2016-03-29 15:22:22 +00:00
|
|
|
|
2016-03-29 11:56:58 +00:00
|
|
|
def private_message(self, event):
|
2016-03-29 15:22:22 +00:00
|
|
|
if event["message_split"]:
|
|
|
|
command = event["message_split"][0].lower()
|
|
|
|
self.message(event, command)
|
2016-03-29 11:56:58 +00:00
|
|
|
|
|
|
|
def help(self, event):
|
|
|
|
if event["args"]:
|
|
|
|
command = event["args_split"][0].lower()
|
|
|
|
if command in self.bot.events.on("received").on(
|
|
|
|
"command").get_children():
|
|
|
|
hooks = self.bot.events.on("received").on("command").on(command).get_hooks()
|
|
|
|
if hooks and "help" in hooks[0].kwargs:
|
|
|
|
event["stdout"].write("%s: %s" % (command, hooks[0].kwargs["help"]))
|
2016-04-05 17:41:03 +00:00
|
|
|
else:
|
|
|
|
event["stderr"].write("No help available for %s" % command)
|
|
|
|
else:
|
|
|
|
event["stderr"].write("Unknown command '%s'" % command)
|
2016-03-29 11:56:58 +00:00
|
|
|
else:
|
|
|
|
help_available = []
|
|
|
|
for child in self.bot.events.on("received").on("command").get_children():
|
|
|
|
hooks = self.bot.events.on("received").on("command").on(child).get_hooks()
|
|
|
|
if hooks and "help" in hooks[0].kwargs:
|
|
|
|
help_available.append(child)
|
|
|
|
help_available = sorted(help_available)
|
|
|
|
event["stdout"].write("Commands: %s" % ", ".join(help_available))
|
|
|
|
|
2016-04-05 17:41:03 +00:00
|
|
|
def usage(self, event):
|
|
|
|
command = event["args_split"][0].lower()
|
|
|
|
if command in self.bot.events.on("received").on(
|
|
|
|
"command").get_children():
|
|
|
|
hooks = self.bot.events.on("received").on("command").on(command).get_hooks()
|
|
|
|
if hooks and "usage" in hooks[0].kwargs:
|
|
|
|
event["stdout"].write("Usage: %s %s" % (command, hooks[0].kwargs["usage"]))
|
|
|
|
else:
|
|
|
|
event["stderr"].write("No usage help available for %s" % command)
|
|
|
|
else:
|
|
|
|
event["stderr"].write("Unknown command '%s'" % command)
|
|
|
|
|
2016-03-29 11:56:58 +00:00
|
|
|
def more(self, event):
|
2016-03-29 15:22:22 +00:00
|
|
|
if event["target"].last_stdout and event["target"].last_stdout.has_text():
|
2016-03-29 11:56:58 +00:00
|
|
|
event["target"].last_stdout.send()
|
|
|
|
|
|
|
|
def send_stdout(self, event):
|
2016-03-31 12:37:08 +00:00
|
|
|
stdout = StdOut(event["module_name"], event["target"])
|
2016-03-29 11:56:58 +00:00
|
|
|
stdout.write(event["message"]).send()
|
|
|
|
if stdout.has_text():
|
|
|
|
event["target"].last_stdout = stdout
|
|
|
|
def send_stderr(self, event):
|
2016-03-31 12:37:08 +00:00
|
|
|
stderr = StdErr(event["module_name"], event["target"])
|
2016-03-29 11:56:58 +00:00
|
|
|
stderr.write(event["message"]).send()
|
|
|
|
if stderr.has_text():
|
|
|
|
event["target"].last_stderr = stderr
|