aboutsummaryrefslogtreecommitdiff
path: root/modules
diff options
context:
space:
mode:
Diffstat (limited to 'modules')
-rw-r--r--modules/admin.py208
-rw-r--r--modules/channel_access.py91
-rw-r--r--modules/channel_blacklist.py40
-rw-r--r--modules/channel_keys.py55
-rw-r--r--modules/check_mode.py43
-rw-r--r--modules/commands/__init__.py424
-rw-r--r--modules/commands/outs.py28
-rw-r--r--modules/config.py244
-rw-r--r--modules/ctcp.py29
-rw-r--r--modules/deferred_read.py23
-rw-r--r--modules/fake_echo.py13
-rw-r--r--modules/format_activity.py285
-rw-r--r--modules/help.py124
-rw-r--r--modules/ignore.py163
-rw-r--r--modules/ircv3_chathistory.py36
-rw-r--r--modules/ircv3_echo_message.py21
-rw-r--r--modules/ircv3_labeled_responses.py67
-rw-r--r--modules/ircv3_message_tracking.py17
-rw-r--r--modules/ircv3_metadata.py16
-rw-r--r--modules/ircv3_msgid.py31
-rw-r--r--modules/ircv3_sasl/README.md46
-rw-r--r--modules/ircv3_sasl/__init__.py195
-rw-r--r--modules/ircv3_sasl/scram.py130
-rw-r--r--modules/ircv3_server_time.py12
-rw-r--r--modules/ircv3_sts.py70
-rw-r--r--modules/line_handler/__init__.py260
-rw-r--r--modules/line_handler/channel.py160
-rw-r--r--modules/line_handler/core.py154
-rw-r--r--modules/line_handler/ircv3.py138
-rw-r--r--modules/line_handler/message.py109
-rw-r--r--modules/line_handler/user.py102
-rw-r--r--modules/modules.py122
-rw-r--r--modules/more.py23
-rw-r--r--modules/nick_regain.py48
-rw-r--r--modules/perform.py76
-rw-r--r--modules/permissions/__init__.py357
-rw-r--r--modules/print_activity.py48
-rw-r--r--modules/proxy.py38
-rw-r--r--modules/signals.py65
-rw-r--r--modules/silence.py70
-rw-r--r--modules/strip_color.py22
-rw-r--r--modules/strip_otr.py15
-rw-r--r--modules/throttle.py17
43 files changed, 0 insertions, 4235 deletions
diff --git a/modules/admin.py b/modules/admin.py
deleted file mode 100644
index 364380d4..00000000
--- a/modules/admin.py
+++ /dev/null
@@ -1,208 +0,0 @@
-#--depends-on commands
-#--depends-on permissions
-
-from src import IRCLine, ModuleManager, utils
-
-class Module(ModuleManager.BaseModule):
- @utils.hook("received.command.nick", min_args=1)
- def change_nickname(self, event):
- """
- :help: Change my nickname
- :usage: <nickname>
- :permission: changenickname
- """
- nickname = event["args_split"][0]
- event["server"].send_nick(nickname)
-
- @utils.hook("received.command.raw", min_args=1)
- def raw(self, event):
- """
- :help: Send a line of raw IRC data
- :usage: <raw line>
- :permission: raw
- """
- if IRCLine.is_human(event["args"]):
- line = IRCLine.parse_human(event["args"])
- else:
- line = IRCLine.parse_line(event["args"])
- line = event["server"].send(line)
-
- if not line == None:
- event["stdout"].write("Sent: %s" % line.parsed_line.format())
- else:
- event["stderr"].write("Line was filtered")
-
- @utils.hook("received.command.part")
- def part(self, event):
- """
- :help: Part from the current or given channel
- :usage: [channel]
- :permission: part
- """
- if event["args"]:
- target = event["args_split"][0]
- elif event["is_channel"]:
- target = event["target"].name
- else:
- event["stderr"].write("No channel provided")
- event["server"].send_part(target)
-
- def _id_from_alias(self, alias):
- return self.bot.database.servers.get_by_alias(alias)
- def _server_from_alias(self, alias):
- id, server = self._both_from_alias(alias)
- return server
- def _both_from_alias(self, alias):
- id = self._id_from_alias(alias)
- if id == None:
- raise utils.EventError("Unknown server alias")
- return id, self.bot.get_server_by_id(id)
-
- @utils.hook("received.command.reconnect")
- def reconnect(self, event):
- """
- :help: Reconnect to the current network
- :permission: reconnect
- """
- server = event["server"]
- alias = str(event["server"])
- if event["args"]:
- alias = event["args_split"][0]
- server = self._server_from_alias(alias)
-
- if server:
- line = server.send_quit("Reconnecting")
- line.events.on("send").hook(lambda e: self.bot.reconnect(
- server.id, server.connection_params))
- if not server == event["server"]:
- event["stdout"].write("Reconnecting to %s" % alias)
- else:
- event["stdout"].write("Not connected to %s" % alias)
-
- @utils.hook("received.command.connect", min_args=1)
- def connect(self, event):
- """
- :help: Connect to a network
- :usage: <server id>
- :permission: connect
- """
- alias = event["args_split"][0]
- server = self._server_from_alias(alias)
- if server:
- raise utils.EventError("Already connected to %s" % str(server))
-
- server = self.bot.add_server(self._id_from_alias(alias))
- event["stdout"].write("Connecting to %s" % str(server))
-
- @utils.hook("received.command.disconnect")
- def disconnect(self, event):
- """
- :help: Disconnect from a server
- :usage: [server id]
- :permission: disconnect
- """
- server = event["server"]
- id = -1
- alias = str(event["server"])
- if event["args"]:
- alias = event["args_split"][0]
- id, server = self._both_from_alias(alias)
-
- if not server == None:
- alias = str(server)
- server.disconnect()
- self.bot.disconnect(server)
- elif id in self.bot.reconnections:
- self.bot.reconnections[id].cancel()
- del self.bot.reconnections[id]
- else:
- raise utils.EventError("Server not connected")
-
- event["stdout"].write("Disconnected from %s" % alias)
-
- @utils.hook("received.command.shutdown")
- def shutdown(self, event):
- """
- :help: Shutdown bot
- :usage: [reason]
- :permission: shutdown
- """
- reason = event["args"] or ""
- for server in self.bot.servers.values():
- line = server.send_quit(reason)
- line.events.on("send").hook(self._shutdown_hook(server))
- def _shutdown_hook(self, server):
- def shutdown(e):
- server.disconnect()
- self.bot.disconnect(server)
- return shutdown
-
- @utils.hook("received.command.addserver", min_args=3)
- def add_server(self, event):
- """
- :help: Add a new server
- :usage: <alias> <hostname>:[+]<port> <nickname>!<username>[@<bindhost>]
- :permission: addserver
- """
- alias = event["args_split"][0]
- hostname, sep, port = event["args_split"][1].partition(":")
- tls = port.startswith("+")
- port = port.lstrip("+")
-
- if not hostname or not port or not port.isdigit():
- raise utils.EventError("Please provide <hostname>:[+]<port>")
- port = int(port)
-
- hostmask = IRCLine.parse_hostmask(event["args_split"][2])
- nickname = hostmask.nickname
- username = hostmask.username or nickname
- realname = nickname
- bindhost = hostmask.hostname or None
-
- try:
- server_id = self.bot.database.servers.add(alias, hostname, port, "",
- tls, bindhost, nickname, username, realname)
- except Exception as e:
- event["stderr"].write("Failed to add server")
- self.log.error("failed to add server \"%s\"", [alias],
- exc_info=True)
- return
- event["stdout"].write("Added server '%s'" % alias)
-
- @utils.hook("received.command.editserver")
- @utils.kwarg("min_args", 3)
- @utils.kwarg("help", "Edit server details")
- @utils.kwarg("usage", "<alias> <option> <value>")
- @utils.kwarg("permission", "editserver")
- def edit_server(self, event):
- alias = event["args_split"][0]
- server_id = self._id_from_alias(alias)
- if server_id == None:
- raise utils.EventError("Unknown server '%s'" % alias)
-
- option = event["args_split"][1].lower()
- value = " ".join(event["args_split"][2:])
- value_parsed = None
-
- if option == "hostname":
- value_parsed = value
- elif option == "port":
- if not value.isdigit():
- raise utils.EventError("Invalid port")
- value_parsed = int(value.lstrip("0"))
- elif option == "tls":
- value_lower = value.lower()
- if not value_lower in ["yes", "no"]:
- raise utils.EventError("TLS should be either 'yes' or 'no'")
- value_parsed = value_lower == "yes"
- elif option == "password":
- value_parsed = value
- elif option == "bindhost":
- value_parsed = value
- elif option in ["nickname", "username", "realname"]:
- value_parsed = value
- else:
- raise utils.EventError("Unknown option '%s'" % option)
-
- self.bot.database.servers.edit(server_id, option, value_parsed)
- event["stdout"].write("Set %s for %s" % (option, alias))
diff --git a/modules/channel_access.py b/modules/channel_access.py
deleted file mode 100644
index 5502db9f..00000000
--- a/modules/channel_access.py
+++ /dev/null
@@ -1,91 +0,0 @@
-#--depends-on check_mode
-#--depends-on commands
-#--depends-on permissions
-
-from src import ModuleManager, utils
-
-class Module(ModuleManager.BaseModule):
- _name = "ChanAccess"
-
- def _has_channel_access(self, target, user, require_access):
- access = target.get_user_setting(user.get_id(), "access", [])
- identified = self.exports.get_one("is-identified")(user)
-
- return (require_access in access or "*" in access) and identified
-
- def _command_check(self, event, target, require_access):
- if event["is_channel"]:
- if require_access:
- if self._has_channel_access(target, event["user"],
- require_access):
- return utils.consts.PERMISSION_FORCE_SUCCESS, None
- else:
- return (utils.consts.PERMISSION_ERROR,
- "You do not have permission to do this")
-
- @utils.hook("preprocess.command")
- def preprocess_command(self, event):
- require_access = event["hook"].get_kwarg("require_access")
- if require_access:
- return self._command_check(event, event["target"], require_access)
-
- @utils.hook("check.command.channel-access")
- def check_command(self, event):
- target = event["target"]
- access = event["request_args"][0]
- if len(event["request_args"]) > 1:
- target = event["request_args"][0]
- access = event["request_args"][1]
-
- return self._command_check(event, target, access)
-
- @utils.hook("received.command.access", min_args=1, channel_only=True)
- def access(self, event):
- """
- :help: Show/modify channel access for a user
- :usage: list <nickname>
- :usage: add <nickname> <permission1 permission2 ...>
- :usage: remove <nickname> <permission1 permission2 ...>
- :usage: set <nickname> <permission1 permission2 ...>
- :require_mode: high
- """
- subcommand = event["args_split"][0].lower()
- target = event["server"].get_user(event["args_split"][1])
- access = event["target"].get_user_setting(target.get_id(), "access", [])
-
- if subcommand == "list":
- event["stdout"].write("Access for %s: %s" % (target.nickname,
- " ".join(access)))
- elif subcommand == "set":
- if not len(event["args_split"]) > 2:
- raise utils.EventError("Please provide a list of permissions")
- event["target"].set_user_setting(target.get_id(), "access",
- event["args_split"][2:])
- elif subcommand == "add":
- if not len(event["args_split"]) > 2:
- raise utils.EventError("Please provide a list of permissions")
- for acc in event["args_split"][2:]:
- if acc in access:
- raise utils.EventError("%s already has '%s' permission" % (
- target.nickname, acc))
- access.append(acc)
- event["target"].set_user_setting(target.get_id(), "access", access)
- event["stdout"].write("Added permission to %s: %s" % (
- target.nickname, " ".join(event["args_split"][2:])))
- elif subcommand == "remove":
- if not len(event["args_split"]) > 2:
- raise utils.EventError("Please provide a list of permissions")
- for acc in event["args_split"][2:]:
- if not acc in access:
- raise utils.EventError("%s does not have '%s' permission" %
- (target.nickname, acc))
- access.remove(acc)
- if access:
- event["target"].set_user_setting(target.get_id(), "access",
- access)
- else:
- event["target"].del_user_setting(target.get_id(), "access")
- event["stdout"].write("Removed permission from %s: %s" % (
- target.nickname, " ".join(event["args_split"][2:])))
- else:
- event["stderr"].write("Unknown command '%s'" % subcommand)
diff --git a/modules/channel_blacklist.py b/modules/channel_blacklist.py
deleted file mode 100644
index d151bad8..00000000
--- a/modules/channel_blacklist.py
+++ /dev/null
@@ -1,40 +0,0 @@
-from src import EventManager, ModuleManager, utils
-
-@utils.export("channelset", utils.BoolSetting("blacklist",
- "Refuse to join a given channel"))
-class Module(ModuleManager.BaseModule):
- @utils.hook("preprocess.send.join")
- @utils.kwarg("priority", EventManager.PRIORITY_HIGH)
- def preprocess_send_join(self, event):
- if event["line"].args:
- channels = event["line"].args[0].split(",")
- keys = event["line"].args[1:]
-
- changed = False
- channels_out = []
- for channel_name in filter(None, channels):
- id = event["server"].channels.get_id(channel_name, create=False)
- if not id == None and self.bot.database.channel_settings.get(
- id, "blacklist", False):
- changed = True
- if keys:
- keys.pop(0)
- else:
- key = None
- if keys:
- key = keys.pop(0)
- channels_out.append([channel_name, key])
-
- if changed:
- if not channels_out:
- event["line"].invalidate()
- else:
- channels = [c[0] for c in channels_out]
- keys = [c[1] for c in channels_out if c[1]]
- event["line"].args[0] = ",".join(channels)
- event["line"].args[1:] = keys
-
- @utils.hook("received.join")
- def on_join(self, event):
- if event["channel"].get_setting("blacklist", False):
- event["channel"].send_part()
diff --git a/modules/channel_keys.py b/modules/channel_keys.py
deleted file mode 100644
index 01e3c38f..00000000
--- a/modules/channel_keys.py
+++ /dev/null
@@ -1,55 +0,0 @@
-from src import ModuleManager, utils
-
-@utils.export("channelset", utils.Setting("key", "Channel key (password)",
- example="hunter2"))
-class Module(ModuleManager.BaseModule):
- def _get_key(self, server, channel_name):
- channel_id = server.channels.get_id(channel_name)
- return self.bot.database.channel_settings.get(channel_id, "key", None)
- def _set_key(self, channel, key):
- channel.set_setting("key", key)
- def _unset_key(self, channel):
- channel.del_setting("key")
-
- @utils.hook("preprocess.send.join")
- def preprocess_send_join(self, event):
- if event["line"].args:
- channels = event["line"].args[0].split(",")
-
- init_keys = False
- if len(event["line"].args) > 1:
- init_keys = True
- keys = event["line"].args[1].split(",")
- else:
- keys = []
-
- with_keys = {}
- for channel in channels:
- if keys:
- with_keys[channel] = keys.pop(0)
- else:
- with_keys[channel] = self._get_key(event["server"], channel)
-
- channels_out = []
- keys_out = []
-
- # sort such that channels with keys are at the start
- for channel_name, key in sorted(with_keys.items(),
- key=lambda item: not bool(item[1])):
- channels_out.append(channel_name)
- if key:
- keys_out.append(key)
-
- event["line"].args[0] = ",".join(channels_out)
- if not init_keys:
- event["line"].args.append(None)
- event["line"].args[1] = ",".join(keys_out)
-
- @utils.hook("received.324")
- @utils.hook("received.mode.channel")
- def on_modes(self, event):
- for mode, arg in event["modes"]:
- if mode == "+k":
- self._set_key(event["channel"], arg)
- elif mode == "-k":
- self._unset_key(event["channel"])
diff --git a/modules/check_mode.py b/modules/check_mode.py
deleted file mode 100644
index 9fe3f464..00000000
--- a/modules/check_mode.py
+++ /dev/null
@@ -1,43 +0,0 @@
-#--depends-on commands
-
-from src import ModuleManager, utils
-
-LOWHIGH = {
- "low": "v",
- "high": "o"
-}
-
-@utils.export("channelset", utils.Setting("mode-low",
- "Set which channel mode is considered to be 'low' access", example="v"))
-@utils.export("channelset", utils.Setting("mode-high",
- "Set which channel mode is considered to be 'high' access", example="o"))
-class Module(ModuleManager.BaseModule):
- def _check_command(self, event, channel, require_mode):
- if event["is_channel"] and require_mode:
- if require_mode.lower() in LOWHIGH:
- require_mode = event["target"].get_setting(
- "mode-%s" % require_mode.lower(),
- LOWHIGH[require_mode.lower()])
-
- if not event["target"].mode_or_above(event["user"],
- require_mode):
- return (utils.consts.PERMISSION_ERROR,
- "You do not have permission to do this")
- else:
- return utils.consts.PERMISSION_FORCE_SUCCESS, None
-
- @utils.hook("preprocess.command")
- def preprocess_command(self, event):
- require_mode = event["hook"].get_kwarg("require_mode")
- if not require_mode == None:
- return self._check_command(event, event["target"], require_mode)
-
- @utils.hook("check.command.channel-mode")
- def check_command(self, event):
- target = event["target"]
- mode = event["request_args"][0]
- if len(event["request_args"]) > 1:
- target = event["request_args"][0]
- mode = event["request_args"][1]
-
- return self._check_command(event, target, mode)
diff --git a/modules/commands/__init__.py b/modules/commands/__init__.py
deleted file mode 100644
index 5a750a9b..00000000
--- a/modules/commands/__init__.py
+++ /dev/null
@@ -1,424 +0,0 @@
-#--depends-on config
-#--depends-on permissions
-
-import enum, re, shlex, string, traceback, typing
-from src import EventManager, IRCLine, ModuleManager, utils
-from . import outs
-
-COMMAND_METHOD = "command-method"
-COMMAND_METHODS = ["PRIVMSG", "NOTICE"]
-
-STR_MORE = " (more...)"
-STR_MORE_LEN = len(STR_MORE.encode("utf8"))
-STR_CONTINUED = "(...continued)"
-WORD_BOUNDARIES = [" "]
-
-NON_ALPHANUMERIC = [char for char in string.printable if not char.isalnum()]
-
-class OutType(enum.Enum):
- OUT = 1
- ERR = 2
-
-class BadContextException(Exception):
- def __init__(self, required_context):
- self.required_context = required_context
- Exception.__init__(self)
-
-class CommandEvent(object):
- def __init__(self, command, args):
- self.command = command
- self.args = args
-
-SETTING_COMMANDMETHOD = utils.OptionsSetting(COMMAND_METHODS, COMMAND_METHOD,
- "Set the method used to respond to commands")
-
-@utils.export("channelset", utils.Setting("command-prefix",
- "Set the command prefix used in this channel", example="!"))
-@utils.export("serverset", utils.Setting("command-prefix",
- "Set the command prefix used on this server", example="!"))
-@utils.export("serverset", SETTING_COMMANDMETHOD)
-@utils.export("channelset", SETTING_COMMANDMETHOD)
-@utils.export("botset", SETTING_COMMANDMETHOD)
-@utils.export("channelset", utils.BoolSetting("hide-prefix",
- "Disable/enable hiding prefix in command reponses"))
-@utils.export("channelset", utils.BoolSetting("commands",
- "Disable/enable responding to commands in-channel"))
-@utils.export("channelset", utils.BoolSetting("prefixed-commands",
- "Disable/enable responding to prefixed commands in-channel"))
-class Module(ModuleManager.BaseModule):
- @utils.hook("new.user")
- @utils.hook("new.channel")
- def new(self, event):
- if "user" in event:
- target = event["user"]
- else:
- target = event["channel"]
-
- def has_command(self, command):
- return command.lower() in self.events.on("received").on(
- "command").get_children()
- def get_hooks(self, command):
- return self.events.on("received.command").on(command
- ).get_hooks()
-
- def is_highlight(self, server, s):
- if s and s[-1] in [":", ","]:
- return server.is_own_nickname(s[:-1])
-
- def _command_method(self, server, target):
- return target.get_setting(COMMAND_METHOD,
- server.get_setting(COMMAND_METHOD,
- self.bot.get_setting(COMMAND_METHOD, "PRIVMSG"))).upper()
-
- def _find_command_hook(self, server, target, is_channel, command, args):
- if not self.has_command(command):
- command_event = CommandEvent(command, args)
- self.events.on("get.command").call(command=command_event,
- server=server, target=target, is_channel=is_channel)
-
- command = command_event.command
- args = command_event.args
-
- hook = None
- args_split = []
- channel_skip = False
- private_skip = False
- if self.has_command(command):
- for potential_hook in self.get_hooks(command):
- alias_of = self._get_alias_of(potential_hook)
- if alias_of:
- if self.has_command(alias_of):
- potential_hook = self.get_hooks(alias_of)[0]
- else:
- raise ValueError(
- "'%s' is an alias of unknown command '%s'"
- % (command.lower(), alias_of.lower()))
-
- if not is_channel and potential_hook.get_kwarg("channel_only",
- False):
- channel_skip = True
- continue
- if is_channel and potential_hook.get_kwarg("private_only",
- False):
- private_skip = True
- continue
-
- hook = potential_hook
-
- if args:
- argparse = hook.get_kwarg("argparse", "plain")
- if argparse == "shlex":
- args_split = shlex.split(args)
- elif argparse == "plain":
- args_split = args.split(" ")
-
- break
-
- if not hook and (private_skip or channel_skip):
- raise BadContextException("channel" if channel_skip else "private")
-
- return hook, command, args_split
-
- def _check(self, context, kwargs, requests=[]):
- event_hook = self.events.on(context).on("command")
-
- returns = []
- if requests:
- for request, request_args in requests:
- returns.append(event_hook.on(request).call_for_result_unsafe(
- **kwargs, request_args=request_args))
- else:
- returns = event_hook.call_unsafe(**kwargs)
-
- hard_fail = False
- force_success = False
- error = None
- for returned in returns:
- if returned:
- type, message = returned
- if type == utils.consts.PERMISSION_HARD_FAIL:
- error = message
- hard_fail = True
- break
- elif type == utils.consts.PERMISSION_FORCE_SUCCESS:
- force_success = True
- break
- elif type == utils.consts.PERMISSION_ERROR:
- error = message
-
- if hard_fail:
- return False, error
- elif not force_success and error:
- return False, error
- else:
- return True, None
-
-
- def _check_assert(self, check_kwargs, user,
- check: typing.Union[utils.Check, utils.MultiCheck]):
- checks = check.to_multi() # both Check and MultiCheck has this func
- is_success, message = self._check("check", check_kwargs,
- checks.requests())
- if not is_success:
- raise utils.EventError("%s: %s" % (user.nickname, message))
-
- def command(self, server, target, target_str, is_channel, user, command,
- args_split, line, hook, **kwargs):
- module_name = (self._get_prefix(hook) or
- self.bot.modules.from_context(hook.context).title)
-
- stdout = outs.StdOut(module_name)
- stderr = outs.StdOut(module_name)
-
- ret = False
- has_out = False
-
- if hook.get_kwarg("remove_empty", True):
- args_split = list(filter(None, args_split))
-
- event_kwargs = {"hook": hook, "user": user, "server": server,
- "target": target, "target_str": target_str,
- "is_channel": is_channel, "line": line, "args_split": args_split,
- "command": command, "args": " ".join(args_split), "stdout": stdout,
- "stderr": stderr, "tags": {}}
- event_kwargs.update(kwargs)
-
- check_assert = lambda check: self._check_assert(event_kwargs, user,
- check)
- event_kwargs["check_assert"] = check_assert
-
- eaten = False
-
- check_success, check_message = self._check("preprocess", event_kwargs)
- if check_success:
- new_event = self.events.on(hook.event_name).make_event(**event_kwargs)
- self.log.trace("calling command '%s': %s", [command, new_event.kwargs])
-
- try:
- hook.call(new_event)
- except utils.EventError as e:
- stderr.write(str(e))
- eaten = new_event.eaten
- else:
- if check_message:
- stderr.write("%s: %s" % (user.nickname, check_message))
-
- self._check("postprocess", event_kwargs)
- # postprocess - send stdout/stderr and typing tag
-
- return eaten
-
- @utils.hook("postprocess.command")
- @utils.kwarg("priority", EventManager.PRIORITY_LOW)
- def postprocess(self, event):
- type = None
- obj = None
- if event["stdout"].has_text():
- type = OutType.OUT
- obj = event["stdout"]
- elif event["stderr"].has_text():
- type = OutType.ERR
- obj = event["stderr"]
- else:
- return
- self._out(event["server"], event["target"], event["target_str"], obj,
- type, event["tags"])
-
- def _out(self, server, target, target_str, obj, type, tags):
- if type == OutType.OUT:
- color = utils.consts.GREEN
- else:
- color = utils.consts.RED
-
- line_str = obj.pop()
- if obj.prefix:
- line_str = "[%s] %s" % (
- utils.irc.color(obj.prefix, color), line_str)
- method = self._command_method(server, target)
-
- if not method in ["PRIVMSG", "NOTICE"]:
- raise ValueError("Unknown command-method '%s'" % method)
-
- line = IRCLine.ParsedLine(method, [target_str, line_str],
- tags=tags)
- valid, trunc = line.truncate(server.hostmask(),
- margin=STR_MORE_LEN)
-
- if trunc:
- if not trunc[0] in WORD_BOUNDARIES:
- for boundary in WORD_BOUNDARIES:
- left, *right = valid.rsplit(boundary, 1)
- if right:
- valid = left
- trunc = right[0]+trunc
- obj.insert("%s %s" % (STR_CONTINUED, trunc))
- valid = valid+STR_MORE
- line = IRCLine.parse_line(valid)
- server.send(line)
-
- @utils.hook("preprocess.command")
- def _check_min_args(self, event):
- min_args = event["hook"].get_kwarg("min_args")
- if min_args and len(event["args_split"]) < min_args:
- usage = self._get_usage(event["hook"], event["command"],
- event["command_prefix"])
- error = None
- if usage:
- error = "Not enough arguments, usage: %s" % usage
- else:
- error = "Not enough arguments (minimum: %d)" % min_args
- return utils.consts.PERMISSION_HARD_FAIL, error
-
- def _command_prefix(self, server, channel):
- return channel.get_setting("command-prefix",
- server.get_setting("command-prefix", "!"))
-
- @utils.hook("received.message.channel", priority=EventManager.PRIORITY_LOW)
- def channel_message(self, event):
- commands_enabled = event["channel"].get_setting("commands", True)
- if not commands_enabled:
- return
-
- command_prefix = self._command_prefix(event["server"], event["channel"])
- command = None
- args = ""
- if event["message_split"][0].startswith(command_prefix):
- if not event["channel"].get_setting("prefixed-commands",True):
- return
- command = event["message_split"][0].replace(
- command_prefix, "", 1).lower()
- if " " in event["message"]:
- args = event["message"].split(" ", 1)[1]
- elif len(event["message_split"]) > 1 and self.is_highlight(
- event["server"], event["message_split"][0]):
- command = event["message_split"][1].lower()
- if event["message"].count(" ") > 1:
- args = event["message"].split(" ", 2)[2]
-
- hook = None
- args_split = []
- if command:
- try:
- hook, command, args_split = self._find_command_hook(
- event["server"], event["channel"], True, command, args)
- except BadContextException:
- event["channel"].send_message(
- "%s: That command is not valid in a channel" %
- event["user"].nickname)
- return
-
- if hook:
- if event["action"]:
- return
-
- if hook:
- self.command(event["server"], event["channel"],
- event["target_str"], True, event["user"], command,
- args_split, event["line"], hook,
- command_prefix=command_prefix,
- buffer_line=event["buffer_line"])
- else:
- self.events.on("unknown.command").call(server=event["server"],
- target=event["channel"], user=event["user"],
- command=command, command_prefix=command_prefix,
- is_channel=True)
- else:
- regex_hooks = self.events.on("command.regex").get_hooks()
- for hook in regex_hooks:
- if event["action"] and hook.get_kwarg("ignore_action", True):
- continue
-
- pattern = hook.get_kwarg("pattern", None)
- if pattern:
- match = re.search(pattern, event["message"])
- if match:
- command = hook.get_kwarg("command", "")
- res = self.command(event["server"], event["channel"],
- event["target_str"], True, event["user"], command,
- "", event["line"], hook, match=match,
- message=event["message"], command_prefix="",
- action=event["action"],
- buffer_line=event["buffer_line"])
-
- if res:
- break
-
- @utils.hook("received.message.private", priority=EventManager.PRIORITY_LOW)
- def private_message(self, event):
- if event["message_split"] and not event["action"]:
- command = event["message_split"][0].lower()
-
- # this should help catch commands when people try to do prefixed
- # commands ('!help' rather than 'help') in PM
- command = command.lstrip("".join(NON_ALPHANUMERIC))
-
- args = ""
- if " " in event["message"]:
- args = event["message"].split(" ", 1)[1]
-
- try:
- hook, command, args_split = self._find_command_hook(
- event["server"], event["user"], False, command, args)
- except BadContextException:
- event["user"].send_message(
- "That command is not valid in a PM")
- return
-
- if hook:
- self.command(event["server"], event["user"],
- event["user"].nickname, False, event["user"], command,
- args_split, event["line"], hook, command_prefix="",
- buffer_line=event["buffer_line"])
- else:
- self.events.on("unknown.command").call(server=event["server"],
- target=event["user"], user=event["user"], command=command,
- command_prefix="", is_channel=False)
-
- def _get_usage(self, hook, command, command_prefix=""):
- command = "%s%s" % (command_prefix, command)
- usages = hook.get_kwargs("usage")
-
- if usages:
- return " | ".join(
- "%s %s" % (command, usage) for usage in usages)
- return None
-
- def _get_prefix(self, hook):
- return hook.get_kwarg("prefix", None)
- def _get_alias_of(self, hook):
- return hook.get_kwarg("alias_of", None)
-
- @utils.hook("send.stdout")
- def _stdout(self, event):
- self._send_out(event, OutType.OUT)
- @utils.hook("send.stderr")
- def _stderr(self, event):
- self._send_out(event, OutType.ERR)
-
- def _send_out(self, event, type):
- target = event["target"]
- stdout = outs.StdOut(event["module_name"])
- stdout.write(event["message"])
- if event.get("hide_prefix", False):
- stdout.prefix = None
-
- target_str = event.get("target_str", target.name)
- self._out(event["server"], target, target_str, stdout,
- type, {})
-
- @utils.hook("check.command.self")
- def check_command_self(self, event):
- if event["server"].irc_lower(event["request_args"][0]
- ) == event["user"].name:
- return utils.consts.PERMISSION_FORCE_SUCCESS, None
- else:
- return (utils.consts.PERMISSION_ERROR,
- "You do not have permission to do this")
-
- @utils.hook("check.command.is-channel")
- def check_command_is_channel(self, event):
- if event["is_channel"]:
- return utils.consts.PERMISSION_FORCE_SUCCESS, None
- else:
- return (utils.consts.PERMISSION_ERROR,
- "This command can only be used in-channel")
diff --git a/modules/commands/outs.py b/modules/commands/outs.py
deleted file mode 100644
index e82ceefd..00000000
--- a/modules/commands/outs.py
+++ /dev/null
@@ -1,28 +0,0 @@
-import re
-from src import IRCLine, utils
-
-class StdOut(object):
- def __init__(self, prefix):
- self.prefix = prefix
- self._lines = []
- self._assured = False
-
- def assure(self):
- self._assured = True
-
- def write(self, text):
- self.write_lines(
- text.replace("\r", "").replace("\n\n", "\n").split("\n"))
- def write_lines(self, lines):
- self._lines += list(filter(None, lines))
-
- def get_all(self):
- return self._lines.copy()
- def pop(self):
- return self._lines.pop(0)
- def insert(self, text):
- self._lines.insert(0, text)
-
- def has_text(self):
- return bool(self._lines)
-
diff --git a/modules/config.py b/modules/config.py
deleted file mode 100644
index 710a5dd6..00000000
--- a/modules/config.py
+++ /dev/null
@@ -1,244 +0,0 @@
-#--depends-on channel_access
-#--depends-on check_mode
-#--depends-on commands
-#--depends-on permissions
-
-import enum
-from src import ModuleManager, utils
-
-class ConfigInvalidValue(Exception):
- def __init__(self, message: str=None):
- self.message = message
-class ConfigSettingInexistent(Exception):
- pass
-
-class ConfigResults(enum.Enum):
- Changed = 1
- Retrieved = 2
- Removed = 3
- Unchanged = 4
-
-class ConfigResult(object):
- def __init__(self, result, data=None):
- self.result = result
- self.data = data
-
-class ConfigChannelTarget(object):
- def __init__(self, bot, server, channel_name):
- self._bot = bot
- self._server = server
- self._channel_name = channel_name
- def _get_id(self):
- return self._server.channels.get_id(self._channel_name)
- def set_setting(self, setting, value):
- channel_id = self._get_id()
- self._bot.database.channel_settings.set(channel_id, setting, value)
- def get_setting(self, setting, default=None):
- channel_id = self._get_id()
- return self._bot.database.channel_settings.get(channel_id, setting,
- default)
- def del_setting(self, setting):
- channel_id = self._get_id()
- self._bot.database.channel_settings.delete(channel_id, setting)
-
- def get_user_setting(self, user_id, setting, default=None):
- return self._bot.database.user_channel_settings.get(user_id,
- self._get_id(), setting, default)
-
-class Module(ModuleManager.BaseModule):
- def _to_context(self, server, channel, user, context_desc):
- context_desc_lower = context_desc.lower()
-
- if context_desc == "*":
- if channel == user:
- # we're in PM
- return user, "set", None
- else:
- #we're in a channel
- return channel, "channelset", None
- elif server.is_channel(context_desc):
- return context_desc, "channelset", context_desc
- elif server.irc_lower(context_desc) == user.nickname_lower:
- return user, "set", None
- elif "user".startswith(context_desc_lower):
- return user, "set", None
- elif "channel".startswith(context_desc_lower):
- return channel, "channelset", None
- elif "server".startswith(context_desc_lower):
- return server, "serverset", None
- elif "bot".startswith(context_desc_lower):
- return self.bot, "botset", None
- else:
- raise ValueError()
-
- @utils.hook("preprocess.command")
- def preprocess_command(self, event):
- require_setting = event["hook"].get_kwarg("require_setting", None)
- if not require_setting == None:
- require_setting_unless = event["hook"].get_kwarg(
- "require_setting_unless", None)
- if not require_setting_unless == None:
- require_setting_unless = int(require_setting_unless)
- if len(event["args_split"]) >= require_setting_unless:
- return
-
- context, _, require_setting = require_setting.rpartition(":")
- require_setting = require_setting.lower()
- channel = None
- if event["is_channel"]:
- channel = event["target"]
-
- context = context or "user"
- target, setting_context, _ = self._to_context(event["server"],
- channel, event["user"], context)
-
- export_settings = self._get_export_setting(setting_context)
- setting_info = export_settings.get(require_setting, None)
- if setting_info:
- value = target.get_setting(require_setting, None)
- if value == None:
- example = setting_info.example or "<value>"
- if context == "user":
- context = event["user"].nickname
- elif context == "channel" and not channel == None:
- context = channel.name
- else:
- context = context[0]
-
- error = "Please set %s, e.g.: %sconfig %s %s %s" % (
- require_setting, event["command_prefix"], context,
- require_setting, example)
- return utils.consts.PERMISSION_ERROR, error
-
- def _get_export_setting(self, context):
- settings = self.exports.get_all(context)
- return {setting.name.lower(): setting for setting in settings}
-
- def _config(self, export_settings, target, setting, value=None):
- if not value == None:
- setting_object = export_settings[setting]
- try:
- validated_value = setting_object.parse(value)
- except utils.settings.SettingParseException as e:
- raise ConfigInvalidValue(str(e))
-
- if not validated_value == None:
- existing_value = target.get_setting(setting, None)
- if existing_value == validated_value:
- return ConfigResult(ConfigResults.Unchanged)
- else:
- target.set_setting(setting, validated_value)
- formatted_value = setting_object.format(validated_value)
- return ConfigResult(ConfigResults.Changed, formatted_value)
- else:
- raise ConfigInvalidValue()
- else:
- unset = False
- if setting.startswith("-"):
- setting = setting[1:]
- unset = True
-
- existing_value = target.get_setting(setting, None)
- if not existing_value == None:
- if unset:
- target.del_setting(setting)
- return ConfigResult(ConfigResults.Removed)
- else:
- formatted = export_settings[setting].format(existing_value)
- return ConfigResult(ConfigResults.Retrieved, formatted)
- else:
- raise ConfigSettingInexistent()
-
- @utils.hook("received.command.c", alias_of="config")
- @utils.hook("received.command.config")
- @utils.kwarg("min_args", 1)
- @utils.kwarg("help", "Change config options")
- @utils.kwarg("usage", "<context>[:name] [-][setting [value]]")
- def config(self, event):
- arg_count = len(event["args_split"])
- context_desc, _, name = event["args_split"][0].partition(":")
-
- setting = None
- value = None
- if arg_count > 1:
- setting = event["args_split"][1].lower()
- if arg_count > 2:
- value = " ".join(event["args_split"][2:])
-
- try:
- target, context, name_override = self._to_context(event["server"],
- event["target"], event["user"], context_desc)
- except ValueError:
- raise utils.EventError(
- "Unknown context '%s'. Please provide "
- "'user', 'channel', 'server' or 'bot'" % context_desc)
-
- name = name_override or name
-
- permission_check = utils.Check("permission", "config")
-
- if context == "set":
- if name:
- event["check_assert"](
- utils.Check("self", name)|permission_check)
- target = event["server"].get_user(name)
- else:
- target = event["user"]
- elif context == "channelset":
- if name:
- if name in event["server"].channels:
- target = event["server"].channels.get(name)
- else:
- target = ConfigChannelTarget(self.bot, event["server"],
- name)
- else:
- if event["is_channel"]:
- target = event["target"]
- else:
- raise utils.EventError(
- "Cannot change config for current channel when in "
- "private message")
- event["check_assert"](permission_check|
- utils.Check("channel-access", target, "config")|
- utils.Check("channel-mode", target, "o"))
- elif context == "serverset" or context == "botset":
- event["check_assert"](permission_check)
-
- export_settings = self._get_export_setting(context)
- if not setting == None:
- if not setting.lstrip("-") in export_settings:
- raise utils.EventError("Setting not found")
-
- try:
- result = self._config(export_settings, target, setting, value)
- except ConfigInvalidValue as e:
- if not e.message == None:
- raise utils.EventError("Invalid value: %s" % e.message)
-
- example = export_settings[setting].get_example()
- if not example == None:
- raise utils.EventError("Invalid value. %s" %
- example)
- else:
- raise utils.EventError("Invalid value")
- except ConfigSettingInexistent:
- raise utils.EventError("Setting not set")
-
- for_str = ""
- if name_override:
- for_str = " for %s" % name_override
- if result.result == ConfigResults.Changed:
- event["stdout"].write("Config '%s'%s set to %s" %
- (setting, for_str, result.data))
- elif result.result == ConfigResults.Retrieved:
- event["stdout"].write("%s%s: %s" % (setting, for_str,
- result.data))
- elif result.result == ConfigResults.Removed:
- event["stdout"].write("Unset setting '%s'%s" %
- (setting.lstrip("-"), for_str))
- elif result.result == ConfigResults.Unchanged:
- event["stdout"].write("Config '%s'%s unchanged" %
- (setting, for_str))
- else:
- event["stdout"].write("Available config: %s" %
- ", ".join(export_settings.keys()))
diff --git a/modules/ctcp.py b/modules/ctcp.py
deleted file mode 100644
index 678cf833..00000000
--- a/modules/ctcp.py
+++ /dev/null
@@ -1,29 +0,0 @@
-#--depends-on config
-
-import datetime
-from src import IRCBot, ModuleManager, utils
-
-
-@utils.export("serverset", utils.BoolSetting("ctcp-responses",
- "Set whether I respond to CTCPs on this server"))
-class Module(ModuleManager.BaseModule):
- @utils.hook("received.ctcp.request.version")
- def ctcp_version(self, event):
- default = "BitBot %s (%s)" % (IRCBot.VERSION, IRCBot.SOURCE)
-
- event["user"].send_ctcp_response("VERSION",
- self.bot.config.get("ctcp-version", default))
-
- @utils.hook("received.ctcp.request.source")
- def ctcp_source(self, event):
- event["user"].send_ctcp_response("SOURCE",
- self.bot.config.get("ctcp-source", IRCBot.SOURCE))
-
- @utils.hook("received.ctcp.request.ping")
- def ctcp_ping(self, event):
- event["user"].send_ctcp_response("PING", event["message"])
-
- @utils.hook("received.ctcp.request.time")
- def ctcp_time(self, event):
- event["user"].send_ctcp_response("TIME",
- datetime.datetime.now().strftime("%c"))
diff --git a/modules/deferred_read.py b/modules/deferred_read.py
deleted file mode 100644
index c891e860..00000000
--- a/modules/deferred_read.py
+++ /dev/null
@@ -1,23 +0,0 @@
-from src import EventManager, ModuleManager, utils
-
-# postpone parsing SOME lines until after 001
-
-class Module(ModuleManager.BaseModule):
- @utils.hook("new.server")
- def new_server(self, event):
- event["server"]._deferred_read = []
-
- @utils.hook("raw.received.001", priority=EventManager.PRIORITY_LOW)
- def on_001(self, event):
- lines = event["server"]._deferred_read[:]
- event["server"]._deferred_read.clear()
- for line in lines:
- self.events.on("raw.received").call(line=line,
- server=event["server"])
-
- @utils.hook("raw.received.mode", priority=EventManager.PRIORITY_HIGH)
- def defer(self, event):
- if not event["server"].connected:
- event.eat()
- event["server"]._deferred_read.append(event["line"])
-
diff --git a/modules/fake_echo.py b/modules/fake_echo.py
deleted file mode 100644
index bb7fbf43..00000000
--- a/modules/fake_echo.py
+++ /dev/null
@@ -1,13 +0,0 @@
-from src import EventManager, IRCLine, ModuleManager, utils
-
-class Module(ModuleManager.BaseModule):
- @utils.hook("raw.send.privmsg", priority=EventManager.PRIORITY_MONITOR)
- @utils.hook("raw.send.notice", priority=EventManager.PRIORITY_MONITOR)
- def send_message(self, event):
- our_hostmask = IRCLine.parse_hostmask(event["server"].hostmask())
-
- echo = IRCLine.ParsedLine(event["line"].command, event["line"].args,
- source=our_hostmask, tags=event["line"].tags)
- echo.id = event["line"].id
-
- self.events.on("raw.received").call(line=echo, server=event["server"])
diff --git a/modules/format_activity.py b/modules/format_activity.py
deleted file mode 100644
index 1d93eb94..00000000
--- a/modules/format_activity.py
+++ /dev/null
@@ -1,285 +0,0 @@
-import datetime
-from src import EventManager, ModuleManager, utils
-
-class Module(ModuleManager.BaseModule):
- def _color(self, nickname):
- return utils.irc.hash_colorize(nickname)
-
- def _event(self, type, server, line, context, minimal=None, pretty=None,
- channel=None, user=None, **kwargs):
- self.events.on("formatted").on(type).call(server=server,
- context=context, line=line, channel=channel, user=user,
- minimal=minimal, pretty=pretty, **kwargs)
-
- def _mode_symbols(self, user, channel, server):
- modes = list(channel.get_user_modes(user))
- if modes:
- modes = [mode for mode in modes if mode in server.prefix_modes]
- modes.sort(key=lambda x: list(server.prefix_modes.keys()).index(x))
- return server.prefix_modes[modes[0]]
- return ""
-
- def _privmsg(self, event, channel, user):
- symbols = ""
- if channel:
- symbols = self._mode_symbols(user, channel, event["server"])
-
- if event["action"]:
- format = "* %s%s %s"
- else:
- format = "<%s%s> %s"
-
- minimal = format % ("", user.nickname, event["message"])
- normal = format % (symbols, user.nickname, event["message"])
- pretty = format % (symbols, self._color(user.nickname),
- event["message"])
-
- return minimal, normal, pretty
-
- @utils.hook("send.message.channel")
- @utils.hook("received.message.channel")
- def channel_message(self, event):
- minimal, normal, pretty = self._privmsg(event, event["channel"],
- event["user"])
-
- self._event("message.channel", event["server"], normal,
- event["channel"].name, channel=event["channel"], user=event["user"],
- parsed_line=event["line"], minimal=minimal, pretty=pretty)
-
- def _on_notice(self, event, user, channel):
- symbols = ""
- if channel:
- symbols = self._mode_symbols(user, channel, event["server"])
-
- format = "-%s%s- %s"
- minimal = format % ("", user.nickname, event["message"])
- normal = format % (symbols, user.nickname, event["message"])
- pretty = format % (symbols, self._color(user.nickname),
- event["message"])
-
- return minimal, normal, pretty
- def _channel_notice(self, event, user, channel):
- minimal, normal, pretty = self._on_notice(event, user, channel)
- self._event("notice.channel", event["server"], normal,
- event["channel"].name, parsed_line=event["line"], channel=channel,
- user=event["user"], minimal=minimal, pretty=pretty)
-
- @utils.hook("received.notice.channel")
- @utils.hook("send.notice.channel")
- def channel_notice(self, event):
- self._channel_notice(event, event["user"], event["channel"])
-
- @utils.hook("received.notice.private")
- @utils.hook("send.notice.private")
- def private_notice(self, event):
- minimal, normal, pretty = self._on_notice(event, event["user"], None)
- self._event("notice.private", event["server"], normal,
- event["target"].nickname, parsed_line=event["line"],
- user=event["user"], minimal=minimal, pretty=pretty)
-
- def _on_join(self, event, user):
- channel_name = event["channel"].name
-
- minimal = "%s joined %s" % (user.nickname, channel_name)
-
- normal_format = "- %s (%s) joined %s"
- normal = normal_format % (user.nickname, user.userhost(), channel_name)
- pretty = normal_format % (self._color(user.nickname), user.userhost(),
- channel_name)
-
- self._event("join", event["server"], normal, event["channel"].name,
- channel=event["channel"], user=user, minimal=minimal,
- pretty=pretty)
- @utils.hook("received.join")
- def join(self, event):
- self._on_join(event, event["user"])
- @utils.hook("self.join")
- def self_join(self, event):
- self._on_join(event, event["server"].get_user(event["server"].nickname))
-
- @utils.hook("received.chghost")
- def _on_chghost(self, event):
- username = event["username"]
- hostname = event["hostname"]
-
- format = "%s changed host to %s@%s"
- minimal = format % (event["user"].nickname, username, hostname)
-
- normal_format = "- %s" % format
- normal = normal_format % (event["user"].nickname, username, hostname)
- pretty = normal_format % (self._color(event["user"].nickname), username,
- hostname)
-
- self._event("chghost", event["server"], normal, None,
- user=event["user"], minimal=minimal, pretty=pretty)
-
- def _on_part(self, event, user):
- channel_name = event["channel"].name
- reason = event["reason"]
- reason = "" if not reason else " (%s)" % reason
-
- format = "%s left %s%s"
- minimal = format % (user.nickname, channel_name, reason)
-
- normal_format = "- %s" % format
- normal = normal_format % (user.nickname, channel_name, reason)
- pretty = normal_format % (self._color(user.nickname), channel_name,
- reason)
-
- self._event("part", event["server"], normal, event["channel"].name,
- channel=event["channel"], user=user, minimal=minimal, pretty=pretty)
- @utils.hook("received.part")
- def part(self, event):
- self._on_part(event, event["user"])
- @utils.hook("self.part")
- def self_part(self, event):
- self._on_part(event, event["server"].get_user(event["server"].nickname))
-
- def _on_nick(self, event, user):
- old_nickname = event["old_nickname"]
- new_nickname = event["new_nickname"]
-
- format = "%s changed nickname to %s"
- minimal = format % (old_nickname, new_nickname)
-
- normal_format = "- %s" % format
- normal = normal_format % (old_nickname, new_nickname)
- pretty = normal_format % (
- self._color(old_nickname), self._color(new_nickname))
-
- self._event("nick", event["server"], normal, None, user=user,
- minimal=minimal, pretty=pretty)
- @utils.hook("received.nick")
- def nick(self, event):
- self._on_nick(event, event["user"])
- @utils.hook("self.nick")
- def self_nick(self, event):
- self._on_nick(event, event["server"].get_user(event["server"].nickname))
-
- @utils.hook("received.server-notice")
- def server_notice(self, event):
- line = "(server notice) %s" % event["message"]
- self._event("server-notice", event["server"], line, None)
-
- @utils.hook("received.invite")
- def invite(self, event):
- format = "%s invited %s to %s"
-
- sender = event["user"].nickname
- target = event["target_user"].nickname
- channel_name = event["target_channel"]
-
- minimal = format % (sender, target, channel_name)
- normal = "- %s" % minimal
- pretty = format % (self._color(sender), target, channel_name)
-
- self._event("invite", event["server"], normal, event["target_channel"],
- minimal=minimal, pretty=pretty)
-
- @utils.hook("received.mode.channel")
- def mode(self, event):
- modes = "".join(event["modes_str"])
- args = " ".join(event["args_str"])
- if args:
- args = " %s" % args
-
- format = "%s set mode %s%s"
- minimal = format % (event["user"].nickname, modes, args)
-
- normal_format = "- %s" % format
- normal = normal_format % (event["user"].nickname, modes, args)
- pretty = normal_format % (self._color(event["user"].nickname), modes,
- args)
-
- self._event("mode.channel", event["server"], normal,
- event["channel"].name, channel=event["channel"], user=event["user"],
- minimal=minimal, pretty=pretty)
-
- def _on_topic(self, event, nickname, action, topic):
- format = "topic %s by %s: %s"
- minimal = format % (action, nickname, topic)
-
- normal_format = "- %s" % format
- normal = normal_format % (action, nickname, topic)
- pretty = normal_format % (action, self._color(nickname), topic)
-
- self._event("topic", event["server"], normal, event["channel"].name,
- channel=event["channel"], user=event.get("user", None),
- minimal=minimal, pretty=pretty)
- @utils.hook("received.topic")
- def on_topic(self, event):
- self._on_topic(event, event["user"].nickname, "changed",
- event["topic"])
- @utils.hook("received.333")
- def on_333(self, event):
- self._on_topic(event, event["setter"].nickname, "set",
- event["channel"].topic)
-
- dt = utils.datetime.iso8601_format(
- utils.datetime.datetime_timestamp(event["set_at"]))
-
- minimal = "topic set at %s" % dt
- normal = "- %s" % minimal
-
- self._event("topic-timestamp", event["server"], normal,
- event["channel"].name, channel=event["channel"], minimal=minimal)
-
- def _on_kick(self, event, kicked_nickname):
- sender_nickname = event["user"].nickname
- channel_name = event["channel"].name
-
- reason = ""
- if event["reason"]:
- reason = " (%s)" % event["reason"]
-
- format = "%s kicked %s from %s%s"
- minimal = format % (sender_nickname, kicked_nickname, channel_name,
- reason)
-
- normal_format = "- %s" % format
- normal = normal_format % (sender_nickname, kicked_nickname,
- channel_name, reason)
- pretty = normal_format % (self._color(sender_nickname),
- self._color(kicked_nickname), channel_name, reason)
-
- self._event("kick", event["server"], normal, event["channel"].name,
- channel=event["channel"], user=event.get("user", None),
- minimal=minimal, pretty=pretty)
- @utils.hook("received.kick")
- def kick(self, event):
- self._on_kick(event, event["target_user"].nickname)
- @utils.hook("self.kick")
- def self_kick(self, event):
- self._on_kick(event, event["server"].nickname)
-
- def _quit(self, event, user, reason):
- reason = "" if not reason else " (%s)" % reason
-
- format = "%s quit%s"
- minimal = format % (user.nickname, reason)
-
- normal_format = "- %s" % format
- normal = normal_format % (user.nickname, reason)
- pretty = normal_format % (self._color(user.nickname), reason)
-
- self._event("quit", event["server"], normal, None, user=user,
- minimal=minimal, pretty=pretty)
- @utils.hook("received.quit")
- def on_quit(self, event):
- self._quit(event, event["user"], event["reason"])
- @utils.hook("send.quit")
- def send_quit(self, event):
- self._quit(event, event["server"].get_user(event["server"].nickname),
- event["reason"])
-
- @utils.hook("received.rename")
- def rename(self, event):
- line = "%s was renamed to %s" % (event["old_name"], event["new_name"])
- self._event("rename", event["server"], line, event["old_name"],
- channel=event["channel"])
-
- @utils.hook("received.376")
- def motd_end(self, event):
- for line in event["server"].motd_lines:
- line = "[MOTD] %s" % line
- self._event("motd", event["server"], line, None)
diff --git a/modules/help.py b/modules/help.py
deleted file mode 100644
index 58659d9d..00000000
--- a/modules/help.py
+++ /dev/null
@@ -1,124 +0,0 @@
-#--depends-on commands
-from src import IRCBot, ModuleManager, utils
-
-class Module(ModuleManager.BaseModule):
- def _get_help(self, hook):
- return hook.get_kwarg("help", None) or hook.docstring.description
- def _get_usage(self, hook, command, command_prefix=""):
- command = "%s%s" % (command_prefix, command)
- usage = hook.get_kwarg("usage", None)
- if usage:
- usages = [usage]
- else:
- usages = hook.docstring.var_items.get("usage", None)
-
- if usages:
- return " | ".join(
- "%s %s" % (command, usage) for usage in usages)
- return usage
-
- def _get_hook(self, command):
- hooks = self.events.on("received.command").on(command).get_hooks()
- if hooks:
- return hooks[0]
- else:
- return None
-
- @utils.hook("received.command.help")
- def help(self, event):
- if event["args"]:
- command = event["args_split"][0].lower()
- hook = self._get_hook(command)
-
- if hook == None:
- raise utils.EventError("Unknown command '%s'" % command)
- help = self._get_help(hook)
- usage = self._get_usage(hook, command, event["command_prefix"])
-
- out = help
- if usage:
- out += ". Usage: %s" % usage
-
- if out:
- event["stdout"].write("%s: %s" % (command, out))
- else:
- event["stderr"].write("No help for %s" % command)
- else:
- modules_command = utils.irc.bold(
- "%smodules" % event["command_prefix"])
- commands_command = utils.irc.bold(
- "%scommands <module>" % event["command_prefix"])
- help_command = utils.irc.bold(
- "%shelp <command>" % event["command_prefix"])
-
- event["stdout"].write("I'm %s. use '%s' to list modules, "
- "'%s' to list commands and "
- "'%s' to see help text for a command" %
- (IRCBot.URL, modules_command, commands_command, help_command))
-
- def _all_command_hooks(self):
- all_hooks = {}
- for child_name in self.events.on("received.command").get_children():
- hooks = self.events.on("received.command").on(child_name
- ).get_hooks()
- if hooks:
- all_hooks[child_name.lower()] = hooks[0]
- return all_hooks
-
- @utils.hook("received.command.modules")
- def modules(self, event):
- contexts = {}
- for command, command_hook in self._all_command_hooks().items():
- if not command_hook.context in contexts:
- module = self.bot.modules.from_context(command_hook.context)
- contexts[module.context] = module.name
-
- modules_available = sorted(contexts.values())
- event["stdout"].write("Modules: %s" % ", ".join(modules_available))
-
- @utils.hook("received.command.commands", min_args=1)
- def commands(self, event):
- module_name = event["args_split"][0]
- module = self.bot.modules.from_name(module_name)
- if module == None:
- raise utils.EventError("No such module '%s'" % module_name)
-
- commands = []
- for command, command_hook in self._all_command_hooks().items():
- if command_hook.context == module.context:
- commands.append(command)
-
- event["stdout"].write("Commands for %s module: %s" % (
- module.name, ", ".join(commands)))
-
- @utils.hook("received.command.which")
- @utils.kwarg("min_args", 1)
- @utils.kwarg("help", "Find where a command is provided")
- @utils.kwarg("usage", "<command>")
- def which(self, event):
- command = event["args_split"][0].lower()
- hooks = self.events.on("received.command").on(command).get_hooks()
- if not hooks:
- raise utils.EventError("Unknown command '%s'" % command)
-
- hook = hooks[0]
- module = self.bot.modules.from_context(hook.context)
- event["stdout"].write("%s%s is provided by %s.%s" % (
- event["command_prefix"], command, module.name,
- hook.function.__name__))
-
- @utils.hook("received.command.apropos")
- @utils.kwarg("min_args", 1)
- @utils.kwarg("help", "Show commands with a given string in them")
- @utils.kwarg("usage", "<query>")
- def apropos(self, event):
- query = event["args_split"][0]
- query_lower = query.lower()
-
- commands = []
- for command, hook in self._all_command_hooks().items():
- if query_lower in command.lower():
- commands.append("%s%s" % (event["command_prefix"], command))
- if commands:
- event["stdout"].write("Apropos of '%s': %s" %
- (query, ", ".join(commands)))
diff --git a/modules/ignore.py b/modules/ignore.py
deleted file mode 100644
index 11ad58f3..00000000
--- a/modules/ignore.py
+++ /dev/null
@@ -1,163 +0,0 @@
-#--depends-on commands
-#--depends-on permissions
-
-from src import EventManager, ModuleManager, utils
-
-class Module(ModuleManager.BaseModule):
- def _user_ignored(self, user):
- return user.get_setting("ignore", False)
- def _user_command_ignored(self, user, command):
- return user.get_setting("ignore-%s" % command, False)
- def _user_channel_ignored(self, channel, user):
- return channel.get_user_setting(user.get_id(), "ignore", False)
- def _server_command_ignored(self, server, command):
- return server.get_setting("ignore-%s" % command, False)
-
- def _is_command_ignored(self, server, user, command):
- if self._user_command_ignored(user, command):
- return True
- elif self._server_command_ignored(server, command):
- return True
-
- @utils.hook("received.message.private")
- @utils.hook("received.message.channel")
- @utils.hook("received.notice.private")
- @utils.hook("received.notice.channel")
- @utils.kwarg("priority", EventManager.PRIORITY_HIGH)
- def message(self, event):
- if self._user_ignored(event["user"]):
- event.eat()
- elif event["is_channel"] and self._user_channel_ignored(event["target"],
- event["user"]):
- event.eat()
-
- @utils.hook("preprocess.command")
- def preprocess_command(self, event):
- if self._user_ignored(event["user"]):
- return utils.consts.PERMISSION_HARD_FAIL, None
- elif event["is_channel"] and self._user_channel_ignored(event["target"],
- event["user"]):
- return utils.consts.PERMISSION_HARD_FAIL, None
- elif self._is_command_ignored(event["server"], event["user"],
- event["command"]):
- return utils.consts.PERMISSION_HARD_FAIL, None
-
- @utils.hook("received.command.ignore", min_args=1)
- def ignore(self, event):
- """
- :help: Ignore commands from a given user
- :usage: <nickname> [command]
- :permission: ignore
- """
- time, args = utils.parse.timed_args(event["args_split"], 1)
-
- setting = "ignore"
- for_str = ""
- if len(args) > 1:
- command = args[1].lower()
- setting = "ignore-%s" % command
- for_str = " for '%s'" % command
-
- user = event["server"].get_user(args[0])
- if user.get_setting(setting, False):
- event["stderr"].write("I'm already ignoring '%s'%s" %
- (user.nickname, for_str))
- else:
- user.set_setting(setting, True)
- event["stdout"].write("Now ignoring '%s'%s" %
- (user.nickname, for_str))
-
- if not time == None:
- self.timers.add_persistent("unignore", time,
- user_id=user.get_id(), setting=setting)
- @utils.hook("timer.unignore")
- def _timer_unignore(self, event):
- self.bot.database.user_settings.delete(
- event["user_id"], event["setting"])
-
- @utils.hook("received.command.unignore", min_args=1)
- def unignore(self, event):
- """
- :help: Unignore commands from a given user
- :usage: <nickname> [command]
- :permission: unignore
- """
- setting = "ignore"
- for_str = ""
- if len(event["args_split"]) > 1:
- command = event["args_split"][1].lower()
- setting = "ignore-%s" % command
- for_str = " for '%s'" % command
-
- user = event["server"].get_user(event["args_split"][0])
- if not user.get_setting(setting, False):
- event["stderr"].write("I'm not ignoring '%s'%s" %
- (user.nickname, for_str))
- else:
- user.del_setting(setting)
- event["stdout"].write("Removed ignore for '%s'%s" %
- (user.nickname, for_str))
-
- @utils.hook("received.command.cignore",
- help="Ignore a user in this channel")
- @utils.hook("received.command.cunignore",
- help="Unignore a user in this channel")
- @utils.kwarg("channel_only", True)
- @utils.kwarg("min_args", 1)
- @utils.kwarg("usage", "<nickname>")
- @utils.kwarg("permission", "cignore")
- @utils.kwarg("require_mode", "o")
- @utils.kwarg("require_access", "cignore")
- def cignore(self, event):
- remove = event["command"] == "cunignore"
-
- target_user = event["server"].get_user(event["args_split"][0])
- is_ignored = event["target"].get_user_setting(target_user.get_id(),
- "ignore", False)
-
- if remove:
- if not is_ignored:
- raise utils.EventError("I'm not ignoring %s in this channel" %
- target_user.nickname)
- event["target"].del_user_setting(target_user.get_id(), "ignore")
- event["stdout"].write("Unignored %s" % target_user.nickname)
- else:
- if is_ignored:
- raise utils.EventError("I'm already ignoring %s in this channel"
- % target_user.nickname)
- event["target"].set_user_setting(target_user.get_id(), "ignore",
- True)
- event["stdout"].write("Ignoring %s" % target_user.nickname)
-
- @utils.hook("received.command.serverignore", min_args=1)
- def server_ignore(self, event):
- """
- :permission: server-ignore
- """
- command = event["args_split"][0].lower()
- setting = "ignore-%s" % command
-
- if event["server"].get_setting(setting, False):
- event["stderr"].write("I'm already ignoring '%s' for %s" %
- (command, str(event["server"])))
- else:
- event["server"].set_setting(setting, True)
- event["stdout"].write("Now ignoring '%s' for %s" %
- (command, str(event["server"])))
-
- @utils.hook("received.command.serverunignore", min_args=1)
- def server_unignore(self, event):
- """
- :permission: server-unignore
- """
- command = event["args_split"][0].lower()
- setting = "ignore-%s" % command
-
- if not event["server"].get_setting(setting, False):
- event["stderr"].write("I'm not ignoring '%s' for %s" %
- (command, str(event["server"])))
- else:
- event["server"].del_setting(setting)
- event["stdout"].write("No longer ignoring '%s' for %s" %
- (command, str(event["server"])))
-
diff --git a/modules/ircv3_chathistory.py b/modules/ircv3_chathistory.py
deleted file mode 100644
index e540673a..00000000
--- a/modules/ircv3_chathistory.py
+++ /dev/null
@@ -1,36 +0,0 @@
-#--depends-on ircv3_msgid
-
-from src import ModuleManager, utils
-
-TAG = utils.irc.MessageTag("msgid", "draft/msgid")
-CHATHISTORY_BATCH = utils.irc.BatchType("chathistory")
-
-EVENTPLAYBACK_CAP = utils.irc.Capability(None, "draft/event-playback",
- alias="event-playback")
-HISTORY_BATCH = utils.irc.BatchType("history")
-
-@utils.export("cap", EVENTPLAYBACK_CAP)
-class Module(ModuleManager.BaseModule):
- @utils.hook("received.batch.end")
- def batch_end(self, event):
- if (CHATHISTORY_BATCH.match(event["batch"].type) or
- HISTORY_BATCH.match(event["batch"].type)):
- target_name = event["batch"].args[0]
- if target_name in event["server"].channels:
- target = event["server"].channels.get(target_name)
- else:
- target = event["server"].get_user(target_name)
-
- last_msgid = target.get_setting("last-msgid", None)
- if not last_msgid == None:
- lines = event["batch"].get_lines()
- stop_index = -1
-
- for i, line in enumerate(lines):
- msgid = TAG.get_value(line.tags)
- if msgid == last_msgid:
- stop_index = i
- break
-
- if not stop_index == -1:
- return lines[stop_index+1:]
diff --git a/modules/ircv3_echo_message.py b/modules/ircv3_echo_message.py
deleted file mode 100644
index 276ac554..00000000
--- a/modules/ircv3_echo_message.py
+++ /dev/null
@@ -1,21 +0,0 @@
-from src import EventManager, ModuleManager, utils
-
-CAP = utils.irc.Capability("echo-message", depends_on=["labeled-response"])
-
-@utils.export("cap", CAP)
-class Module(ModuleManager.BaseModule):
- @utils.hook("raw.send.privmsg", priority=EventManager.PRIORITY_LOW)
- @utils.hook("raw.send.notice", priority=EventManager.PRIORITY_LOW)
- def send_message(self, event):
- if event["server"].has_capability(CAP):
- event.eat()
-
- @utils.hook("preprocess.send.privmsg")
- @utils.hook("preprocess.send.notice")
- @utils.hook("preprocess.send.tagmsg")
- def preprocess_send(self, event):
- if event["server"].has_capability(CAP):
- event["events"].on("labeled-response").hook(self.on_echo)
-
- def on_echo(self, event):
- event["responses"][0].id = event["line"].id
diff --git a/modules/ircv3_labeled_responses.py b/modules/ircv3_labeled_responses.py
deleted file mode 100644
index 7dd04b5c..00000000
--- a/modules/ircv3_labeled_responses.py
+++ /dev/null
@@ -1,67 +0,0 @@
-import uuid
-from src import ModuleManager, utils
-
-CAP = utils.irc.Capability(None, "draft/labeled-response-0.2",
- alias="labeled-response", depends_on=["batch"])
-TAG = utils.irc.MessageTag(None, "draft/label")
-BATCH = utils.irc.BatchType(None, "draft/labeled-response")
-
-CAP_TO_TAG = {
- "draft/labeled-response-0.2": "draft/label"
-}
-
-class WaitingForLabel(object):
- def __init__(self, line, events):
- self.line = line
- self.events = events
- self.labels_since = 0
-
-@utils.export("cap", CAP)
-class Module(ModuleManager.BaseModule):
- @utils.hook("new.server")
- def new_server(self, event):
- event["server"]._label_cache = {}
-
- @utils.hook("preprocess.send")
- def raw_send(self, event):
- available_cap = event["server"].available_capability(CAP)
-
- if available_cap:
- label = TAG.get_value(event["line"].tags)
- if label == None:
- tag_key = CAP_TO_TAG[available_cap]
- label = str(uuid.uuid4())
- event["line"].tags[tag_key] = label
-
- event["server"]._label_cache[label] = WaitingForLabel(event["line"],
- event["events"])
-
- @utils.hook("raw.received")
- def raw_recv(self, event):
- if not event["line"].command == "BATCH":
- label = TAG.get_value(event["line"].tags)
- if not label == None:
- self._recv(event["server"], label, [event["line"]])
-
- @utils.hook("received.batch.end")
- def batch_end(self, event):
- if BATCH.match(event["batch"].type):
- label = TAG.get_value(event["batch"].tags)
- self._recv(event["server"], label, event["batch"].get_lines())
-
- def _recv(self, server, label, lines):
- if not label in server._label_cache:
- self.log.debug("unknown label received on %s: %s",
- [str(server), label])
- return
-
- cached = server._label_cache.pop(label)
- cached.events.on("labeled-response").call(line=cached.line,
- responses=lines)
-
- for label, other_cached in server._label_cache.items():
- other_cached.labels_since += 1
- if other_cached.labels_since == 10:
- self.log.debug(
- "%d labels seen while waiting for response to %s on %s",
- [other_cached.labels_since, label, str(server)])
diff --git a/modules/ircv3_message_tracking.py b/modules/ircv3_message_tracking.py
deleted file mode 100644
index 3f4ad88c..00000000
--- a/modules/ircv3_message_tracking.py
+++ /dev/null
@@ -1,17 +0,0 @@
-from src import ModuleManager, utils
-
-MSGID_TAG = "draft/msgid"
-READ_TAG = "+draft/read"
-DELIVERED_TAG = "+draft/delivered"
-MESSAGE_TAG_CAPS = set(["draft/message-tags-0.2", "message-tags"])
-
-class Module(ModuleManager.BaseModule):
- @utils.hook("received.message.private")
- @utils.hook("received.notice.private")
- def privmsg(self, event):
- if MSGID_TAG in event["tags"] and (
- event["server"].agreed_capabilities & MESSAGE_TAG_CAPS):
- target = event.get("channel", event["user"])
- msgid = event["tags"][MSGID_TAG]
- tags = {DELIVERED_TAG: msgid, READ_TAG: msgid}
- target.send_tagmsg(tags)
diff --git a/modules/ircv3_metadata.py b/modules/ircv3_metadata.py
deleted file mode 100644
index e0e6d387..00000000
--- a/modules/ircv3_metadata.py
+++ /dev/null
@@ -1,16 +0,0 @@
-from src import IRCBot, ModuleManager, utils
-
-CAP = utils.irc.Capability(None, "draft/metadata", alias="metadata")
-
-class Module(ModuleManager.BaseModule):
- @utils.hook("received.cap.new")
- @utils.hook("received.cap.ls")
- def on_cap(self, event):
- cap = CAP.copy()
- cap.on_ack(lambda: self._ack(event["server"]))
- return cap
-
- def _ack(self, server):
- url = self.bot.get_setting("bot-url", IRCBot.SOURCE)
- server.send_raw("METADATA * SET bot BitBot")
- server.send_raw("METADATA * SET homepage :%s" % url)
diff --git a/modules/ircv3_msgid.py b/modules/ircv3_msgid.py
deleted file mode 100644
index f95f9fd4..00000000
--- a/modules/ircv3_msgid.py
+++ /dev/null
@@ -1,31 +0,0 @@
-from src import ModuleManager, utils
-
-TAG = utils.irc.MessageTag("msgid", "draft/msgid")
-
-class Module(ModuleManager.BaseModule):
- def _on_channel(self, channel, tags):
- msgid = TAG.get_value(tags)
- if not msgid == None:
- channel.set_setting("last-msgid", msgid)
-
- @utils.hook("received.message.channel")
- @utils.hook("send.message.channel")
- @utils.hook("received.notice.channel")
- @utils.hook("send.notice.channel")
- @utils.hook("received.tagmsg.channel")
- @utils.hook("send.tagmsg.channel")
- def on_channel(self, event):
- self._on_channel(event["channel"], event["tags"])
-
- @utils.hook("received.ctcp.request")
- @utils.hook("received.ctcp.response")
- def ctcp(self, event):
- if event["is_channel"]:
- self._on_channel(event["target"], event["tags"])
-
- @utils.hook("postprocess.command")
- def postprocess_command(self, event):
- msgid = TAG.get_value(event["line"].tags)
- if msgid:
- event["tags"]["+draft/reply"] = msgid
- event["tags"]["+draft/reply"] = msgid
diff --git a/modules/ircv3_sasl/README.md b/modules/ircv3_sasl/README.md
deleted file mode 100644
index 30a51e08..00000000
--- a/modules/ircv3_sasl/README.md
+++ /dev/null
@@ -1,46 +0,0 @@
-# Configuring SASL
-
-You can either configure SASL through `!serverset sasl` from an registered and identified admin account or directly through sqlite.
-
-## USERPASS Mechanism
-
-BitBot supports a special SASL mechanism name: `USERPASS`. This internally
-represents "pick the strongest username:password algorithm"
-
-## !serverset sasl
-
-These commands are to be executed from a registered admin account
-
-#### USERPASS
-> !serverset sasl userpass &lt;username>:&lt;password>
-
-#### PLAIN
-> !serverset sasl plain &lt;username>:&lt;password>
-
-#### SCRAM-SHA-1
-> !serverset sasl scram-sha-1 &lt;username>:&lt;password>
-
-#### SCRAM-SHA-256
-> !serverset sasl scram-sha-256 &lt;username>:&lt;password>
-
-#### EXTERNAL
-> !serverset sasl external
-
-## sqlite
-
-Execute these against the current bot database file (e.g. `$ sqlite3 databases/bot.db`)
-
-#### USERPASS
-> INSERT INTO server_settings (&lt;serverid>, 'sasl', '{"mechanism": "userpass", "args": "&lt;username>:&lt;password>"}');
-
-#### PLAIN
-> INSERT INTO server_settings (&lt;serverid>, 'sasl', '{"mechanism": "plain", "args": "&lt;username>:&lt;password>"}');
-
-#### SCRAM-SHA-1
-> INSERT INTO server_settings (&lt;serverid>, 'sasl', '{"mechanism": "scram-sha-1", "args": "&lt;username>:&lt;password>"}');
-
-#### SCRAM-SHA-256
-> INSERT INTO server_settings (&lt;serverid>, 'sasl', '{"mechanism": "scram-sha-256", "args": "&lt;username>:&lt;password>"}');
-
-#### external
-> INSERT INTO server_settings (&lt;serverid>, 'sasl', '{"mechanism": "external"}');
diff --git a/modules/ircv3_sasl/__init__.py b/modules/ircv3_sasl/__init__.py
deleted file mode 100644
index 9f7fac5f..00000000
--- a/modules/ircv3_sasl/__init__.py
+++ /dev/null
@@ -1,195 +0,0 @@
-#--depends-on config
-
-import base64, hashlib, hmac, typing, uuid
-from src import ModuleManager, utils
-from . import scram
-
-CAP = utils.irc.Capability("sasl")
-
-USERPASS_MECHANISMS = [
- "SCRAM-SHA-512",
- "SCRAM-SHA-256",
- "SCRAM-SHA-1",
- "PLAIN"
-]
-ALL_MECHANISMS = USERPASS_MECHANISMS+["EXTERNAL"]
-
-def _parse(value):
- mechanism, _, arguments = value.partition(" ")
- mechanism = mechanism.upper()
-
- if mechanism in ALL_MECHANISMS:
- return {"mechanism": mechanism.upper(), "args": arguments}
- else:
- raise utils.settings.SettingParseException(
- "Unknown SASL mechanism '%s'" % mechanism)
-
-SASL_TIMEOUT = 15 # 15 seconds
-
-HARDFAIL = utils.BoolSetting("sasl-hard-fail",
- "Set whether a SASL failure should cause a disconnect")
-
-@utils.export("serverset", utils.FunctionSetting(_parse, "sasl",
- "Set the sasl username/password for this server",
- example="PLAIN BitBot:hunter2", format=utils.sensitive_format))
-@utils.export("serverset", HARDFAIL)
-@utils.export("botset", HARDFAIL)
-class Module(ModuleManager.BaseModule):
- @utils.hook("new.server")
- def new_server(self, event):
- event["server"]._sasl_timeout = None
- event["server"]._sasl_retry = False
-
- def _best_userpass_mechanism(self, mechanisms):
- for potential_mechanism in USERPASS_MECHANISMS:
- if potential_mechanism in mechanisms:
- return potential_mechanism
-
- def _mech_match(self, server, server_mechanisms):
- our_sasl = server.get_setting("sasl", None)
- if not our_sasl:
- return None
-
- our_mechanism = our_sasl["mechanism"].upper()
-
- if not server_mechanisms and our_mechanism in ALL_MECHANISMS:
- return our_mechanism
- elif our_mechanism in server_mechanisms:
- return our_mechanism
- elif our_mechanism == "USERPASS":
- if server_mechanisms:
- return self._best_userpass_mechanism(server_mechanisms)
- else:
- return USERPASS_MECHANISMS[0]
- return None
-
- @utils.hook("received.cap.new")
- @utils.hook("received.cap.ls")
- def on_cap(self, event):
- has_sasl = "sasl" in event["capabilities"]
- if has_sasl:
- server_mechanisms = event["capabilities"]["sasl"]
- if server_mechanisms:
- server_mechanisms = server_mechanisms.split(",")
- else:
- server_mechanisms = []
-
- mechanism = self._mech_match(event["server"], server_mechanisms)
-
- if mechanism:
- cap = CAP.copy()
- cap.on_ack(
- lambda: self._sasl_ack(event["server"], mechanism))
- return cap
-
- def _sasl_ack(self, server, mechanism):
- server.send_authenticate(mechanism)
- server._sasl_timeout = self.timers.add("sasl-timeout",
- self._sasl_timeout, SASL_TIMEOUT, server=server)
- server._sasl_mechanism = mechanism
-
- server.wait_for_capability("sasl")
-
- def _sasl_timeout(self, timer):
- server = timer.kwargs["server"]
- self._panic(server, "SASL handshake timed out")
-
- @utils.hook("received.authenticate")
- def on_authenticate(self, event):
- sasl = event["server"].get_setting("sasl")
- mechanism = event["server"]._sasl_mechanism
-
- auth_text = None
- if mechanism == "PLAIN":
- if event["message"] != "+":
- event["server"].send_authenticate("*")
- else:
- sasl_username, sasl_password = sasl["args"].split(":", 1)
- auth_text = ("%s\0%s\0%s" % (
- sasl_username, sasl_username, sasl_password)).encode("utf8")
-
- elif mechanism == "EXTERNAL":
- if event["message"] != "+":
- event["server"].send_authenticate("*")
- else:
- auth_text = "+"
-
- elif mechanism.startswith("SCRAM-"):
-
- if event["message"] == "+":
- # start SCRAM handshake
-
- # create SCRAM helper
- sasl_username, sasl_password = sasl["args"].split(":", 1)
- algo = mechanism.split("SCRAM-", 1)[1]
- event["server"]._scram = scram.SCRAM(
- algo, sasl_username, sasl_password)
-
- # generate client-first-message
- auth_text = event["server"]._scram.client_first()
- else:
- current_scram = event["server"]._scram
- data = base64.b64decode(event["message"])
- if current_scram.state == scram.SCRAMState.ClientFirst:
- # use server-first-message to generate client-final-message
- auth_text = current_scram.server_first(data)
- elif current_scram.state == scram.SCRAMState.ClientFinal:
- # use server-final-message to check server proof
- verified = current_scram.server_final(data)
- del event["server"]._scram
-
- if verified:
- auth_text = "+"
- else:
- if current_scram.state == scram.SCRAMState.VerifyFailed:
- # server gave a bad verification so we should panic
- self._panic(event["server"], "SCRAM VerifyFailed")
-
- else:
- raise ValueError("unknown sasl mechanism '%s'" % mechanism)
-
- if not auth_text == None:
- if not auth_text == "+":
- auth_text = base64.b64encode(auth_text)
- auth_text = auth_text.decode("utf8")
- event["server"].send_authenticate(auth_text)
-
- def _end_sasl(self, server):
- server.capability_done("sasl")
- if not server._sasl_timeout == None:
- server._sasl_timeout.cancel()
- server._sasl_timeout = None
-
- @utils.hook("received.908")
- def sasl_mechanisms(self, event):
- server_mechanisms = event["line"].args[1].split(",")
- mechanism = self._mech_match(event["server"], server_mechanisms)
- if mechanism:
- event["server"]._sasl_mechanism = mechanism
- event["server"].send_authenticate(mechanism)
- event["server"]._sasl_retry = True
-
- @utils.hook("received.903")
- def sasl_success(self, event):
- self._end_sasl(event["server"])
- @utils.hook("received.904")
- def sasl_failure(self, event):
- if not event["server"]._sasl_retry:
- self._panic(event["server"], "ERR_SASLFAIL (%s)" %
- event["line"].args[1])
- else:
- event["server"]._sasl_retry = False
-
- @utils.hook("received.907")
- def sasl_already(self, event):
- self._end_sasl(event["server"])
-
- def _panic(self, server, message):
- if server.get_setting("sasl-hard-fail",
- self.bot.get_setting("sasl-hard-fail", False)):
- message = "SASL panic for %s: %s" % (str(server), message)
- self.log.error(message)
- self.bot.disconnect(server)
- else:
- self.log.warn("SASL failure for %s: %s" % (str(server), message))
- self._end_sasl(server)
diff --git a/modules/ircv3_sasl/scram.py b/modules/ircv3_sasl/scram.py
deleted file mode 100644
index f243d1e6..00000000
--- a/modules/ircv3_sasl/scram.py
+++ /dev/null
@@ -1,130 +0,0 @@
-import base64, enum, hashlib, hmac, os, typing
-
-# IANA Hash Function Textual Names
-# https://tools.ietf.org/html/rfc5802#section-4
-# https://www.iana.org/assignments/hash-function-text-names/
-# MD2 has been removed as it's unacceptably weak
-ALGORITHMS = [
- "MD5", "SHA-1", "SHA-224", "SHA-256", "SHA-384", "SHA-512"]
-
-SCRAM_ERRORS = [
- "invalid-encoding",
- "extensions-not-supported", # unrecognized 'm' value
- "invalid-proof",
- "channel-bindings-dont-match",
- "server-does-support-channel-binding",
- "channel-binding-not-supported",
- "unsupported-channel-binding-type",
- "unknown-user",
- "invalid-username-encoding", # invalid utf8 or bad SASLprep
- "no-resources"
-]
-
-def _scram_nonce() -> bytes:
- return base64.b64encode(os.urandom(32))
-def _scram_escape(s: bytes) -> bytes:
- return s.replace(b"=", b"=3D").replace(b",", b"=2C")
-def _scram_unescape(s: bytes) -> bytes:
- return s.replace(b"=3D", b"=").replace(b"=2C", b",")
-def _scram_xor(s1: bytes, s2: bytes) -> bytes:
- return bytes(a ^ b for a, b in zip(s1, s2))
-
-class SCRAMState(enum.Enum):
- Uninitialised = 0
- ClientFirst = 1
- ClientFinal = 2
- Success = 3
- Failed = 4
- VerifyFailed = 5
-
-class SCRAMError(Exception):
- pass
-
-class SCRAM(object):
- def __init__(self, algo: str, username: str, password: str):
- if not algo in ALGORITHMS:
- raise ValueError("Unknown SCRAM algorithm '%s'" % algo)
-
- self._algo = algo.replace("-", "") # SHA-1 -> SHA1
- self._username = username.encode("utf8")
- self._password = password.encode("utf8")
-
- self.state = SCRAMState.Uninitialised
- self.error = ""
- self.raw_error = ""
-
- self._client_first = b""
- self._salted_password = b""
- self._auth_message = b""
-
- def _get_pieces(self, data: bytes) -> typing.Dict[bytes, bytes]:
- pieces = (piece.split(b"=", 1) for piece in data.split(b","))
- return dict((piece[0], piece[1]) for piece in pieces)
-
- def _hmac(self, key: bytes, msg: bytes) -> bytes:
- return hmac.new(key, msg, self._algo).digest()
- def _hash(self, msg: bytes) -> bytes:
- return hashlib.new(self._algo, msg).digest()
-
- def _constant_time_compare(self, b1: bytes, b2: bytes):
- return hmac.compare_digest(b1, b2)
-
- def client_first(self) -> bytes:
- self.state = SCRAMState.ClientFirst
- self._client_first = b"n=%s,r=%s" % (
- _scram_escape(self._username), _scram_nonce())
-
- # n,,n=<username>,r=<nonce>
- return b"n,,%s" % self._client_first
-
- def server_first(self, data: bytes) -> bytes:
- self.state = SCRAMState.ClientFinal
-
- pieces = self._get_pieces(data)
- nonce = pieces[b"r"] # server combines your nonce with it's own
- salt = base64.b64decode(pieces[b"s"]) # salt is b64encoded
- iterations = int(pieces[b"i"])
-
- salted_password = hashlib.pbkdf2_hmac(self._algo, self._password,
- salt, iterations, dklen=None)
- self._salted_password = salted_password
-
- client_key = self._hmac(salted_password, b"Client Key")
- stored_key = self._hash(client_key)
-
- channel = base64.b64encode(b"n,,")
- auth_noproof = b"c=%s,r=%s" % (channel, nonce)
- auth_message = b"%s,%s,%s" % (self._client_first, data, auth_noproof)
- self._auth_message = auth_message
-
- client_signature = self._hmac(stored_key, auth_message)
- client_proof_xor = _scram_xor(client_key, client_signature)
- client_proof = base64.b64encode(client_proof_xor)
-
- # c=<b64encode("n,,")>,r=<nonce>,p=<proof>
- return b"%s,p=%s" % (auth_noproof, client_proof)
-
- def server_final(self, data: bytes) -> bool:
- pieces = self._get_pieces(data)
- if b"e" in pieces:
- error = pieces[b"e"].decode("utf8")
- self.raw_error = error
- if error in SCRAM_ERRORS:
- self.error = error
- else:
- self.error = "other-error"
-
- self.state = SCRAMState.Failed
- return False
-
- verifier = base64.b64decode(pieces[b"v"])
-
- server_key = self._hmac(self._salted_password, b"Server Key")
- server_signature = self._hmac(server_key, self._auth_message)
-
- if server_signature == verifier:
- self.state = SCRAMState.Success
- return True
- else:
- self.state = SCRAMState.VerifyFailed
- return False
diff --git a/modules/ircv3_server_time.py b/modules/ircv3_server_time.py
deleted file mode 100644
index c9790d95..00000000
--- a/modules/ircv3_server_time.py
+++ /dev/null
@@ -1,12 +0,0 @@
-from src import ModuleManager, utils
-
-CAP = utils.irc.Capability("server-time")
-TAG = utils.irc.MessageTag("time")
-
-@utils.export("cap", CAP)
-class Module(ModuleManager.BaseModule):
- @utils.hook("raw.received")
- def raw_recv(self, event):
- server_time = TAG.get_value(event["line"].tags)
- if not server_time == None:
- event["server"].set_setting("last-server-time", server_time)
diff --git a/modules/ircv3_sts.py b/modules/ircv3_sts.py
deleted file mode 100644
index aeeac1f1..00000000
--- a/modules/ircv3_sts.py
+++ /dev/null
@@ -1,70 +0,0 @@
-import time
-from src import ModuleManager, utils
-
-CAP = utils.irc.Capability("sts", "draft/sts")
-
-class Module(ModuleManager.BaseModule):
- def _get_policy(self, server):
- return server.get_setting("sts-policy", None)
- def _set_policy(self, server, policy):
- self.log.info("Setting STS policy for '%s': %s", [str(server), policy])
- server.set_setting("sts-policy", policy)
- def _remove_policy(self, server):
- server.del_setting("sts-policy")
-
- def set_policy(self, server, port, duration):
- expiration = None
- self._set_policy(server, {
- "port": port,
- "from": time.time(),
- "duration": duration})
- def change_duration(self, server, info):
- duration = int(info["duration"])
- if duration == 0:
- self._remove_policy(server)
- else:
- port = server.connection_params.port
- if "port" in info:
- port = int(info["port"])
- self.set_policy(server, port, duration)
-
- @utils.hook("received.cap.ls")
- def on_cap_ls(self, event):
- sts = CAP.available(event["capabilities"])
- if sts:
- info = utils.parse.keyvalue(event["capabilities"][sts],
- delimiter=",")
- if not event["server"].connection_params.tls:
- if "port" in info:
- self.set_policy(event["server"], int(info["port"]), None)
- event["server"].disconnect()
- self.bot.reconnect(event["server"].id,
- event["server"].connection_params)
- else:
- self.change_duration(event["server"], info)
-
- @utils.hook("received.cap.new")
- def on_cap_new(self, event):
- if CAP.available(event["capabilities"]
- ) and event["server"].connection_params.tls:
- info = utils.parse.keyvalue(sts, delimiter=",")
- self.change_duration(event["server"], info)
-
- @utils.hook("new.server")
- def new_server(self, event):
- sts_policy = self._get_policy(event["server"])
- if sts_policy:
- if not event["server"].connection_params.tls:
- if not sts_policy["duration"] or time.time() <= (
- sts_policy["from"]+sts_policy["duration"]):
- self.log.info("Applying STS policy for '%s'",
- [str(event["server"])])
- event["server"].connection_params.tls = True
- event["server"].connection_params.port = sts_policy["port"]
-
- @utils.hook("server.disconnect")
- def on_disconnect(self, event):
- sts_policy = self._get_policy(event["server"])
- if sts_policy and sts_policy["duration"]:
- sts_policy["from"] = time.time()
- self._set_policy(event["server"], sts_policy)
diff --git a/modules/line_handler/__init__.py b/modules/line_handler/__init__.py
deleted file mode 100644
index ddea6fdc..00000000
--- a/modules/line_handler/__init__.py
+++ /dev/null
@@ -1,260 +0,0 @@
-import enum
-from src import EventManager, IRCLine, ModuleManager, utils
-from . import channel, core, ircv3, message, user
-
-class Module(ModuleManager.BaseModule):
- def _handle(self, server, line):
- hooks = self.events.on("raw.received").on(line.command).get_hooks()
- default_events = []
- for hook in hooks:
- default_events.append(hook.get_kwarg("default_event", False))
-
- kwargs = {"server": server, "line": line,
- "direction": utils.Direction.Recv}
-
- self.events.on("raw.received").on(line.command).call_unsafe(**kwargs)
- if any(default_events) or not hooks:
- self.events.on("received").on(line.command).call(**kwargs)
-
- @utils.hook("raw.received")
- def handle_raw(self, event):
- if ("batch" in event["line"].tags and
- event["line"].tags["batch"] in event["server"].batches):
- event["server"].batches[event["line"].tags["batch"]].add_line(
- event["line"])
- else:
- self._handle(event["server"], event["line"])
-
- @utils.hook("raw.send")
- def handle_send(self, event):
- self.events.on("raw.send").on(event["line"].command).call_unsafe(
- server=event["server"], direction=utils.Direction.Send,
- line=event["line"])
-
- # ping from the server
- @utils.hook("raw.received.ping")
- def ping(self, event):
- core.ping(event)
-
- @utils.hook("raw.received.error")
- def error(self, event):
- self.log.error("ERROR received from %s: %s",
- [str(event["server"]), event["line"].args[0]])
- @utils.hook("raw.received.fail")
- def fail(self, event):
- command = event["line"].args[0]
- error_code = event["line"].args[1]
- context = event["line"].args[2:-1]
- description = event["line"].args[-1]
-
- self.log.warn("FAIL (%s %s) received on %s: %s",
- [command, error_code, str(event["server"]), description])
- self.events.on("received.fail").on(command).call(error_code=error_code,
- context=context, description=description, server=event["server"])
-
- # first numeric line the server sends
- @utils.hook("raw.received.001", default_event=True)
- def handle_001(self, event):
- core.handle_001(event)
-
- # server telling us what it supports
- @utils.hook("raw.received.005")
- def handle_005(self, event):
- core.handle_005(self.events, event)
-
- # RPL_MYINFO
- @utils.hook("raw.received.004")
- def handle_004(self, event):
- core.handle_004(event)
-
- # whois respose (nickname, username, realname, hostname)
- @utils.hook("raw.received.311", default_event=True)
- def handle_311(self, event):
- user.handle_311(event)
-
- # on-join channel topic line
- @utils.hook("raw.received.332")
- def handle_332(self, event):
- channel.handle_332(self.events, event)
-
- # channel topic changed
- @utils.hook("raw.received.topic")
- def topic(self, event):
- channel.topic(self.events, event)
-
- # on-join channel topic set by/at
- @utils.hook("raw.received.333")
- def handle_333(self, event):
- channel.handle_333(self.events, event)
-
- # /names response, also on-join user list
- @utils.hook("raw.received.353", default_event=True)
- def handle_353(self, event):
- channel.handle_353(event)
-
- # on-join user list has finished
- @utils.hook("raw.received.366", default_event=True)
- def handle_366(self, event):
- channel.handle_366(event)
-
- @utils.hook("raw.received.375", priority=EventManager.PRIORITY_HIGH)
- def motd_start(self, event):
- core.motd_start(event)
-
- @utils.hook("raw.received.372")
- @utils.hook("raw.received.375")
- def motd_line(self, event):
- core.motd_line(event)
-
- # on user joining channel
- @utils.hook("raw.received.join")
- def join(self, event):
- channel.join(self.events, event)
-
- # on user parting channel
- @utils.hook("raw.received.part")
- def part(self, event):
- channel.part(self.events, event)
-
- # unknown command sent by us, oops!
- @utils.hook("raw.received.421", default_event=True)
- def handle_421(self, event):
- self.bot.log.warn("We sent an unknown command to %s: %s",
- [str(event["server"]), event["line"].args[1]])
-
- # a user has disconnected!
- @utils.hook("raw.received.quit")
- @utils.hook("raw.send.quit")
- def quit(self, event):
- user.quit(self.events, event)
-
- # the server is telling us about its capabilities!
- @utils.hook("raw.received.cap")
- def cap(self, event):
- ircv3.cap(self.exports, self.events, event)
-
- # the server is asking for authentication
- @utils.hook("raw.received.authenticate")
- def authenticate(self, event):
- ircv3.authenticate(self.events, event)
-
- # someone has changed their nickname
- @utils.hook("raw.received.nick")
- def nick(self, event):
- user.nick(self.events, event)
-
- # something's mode has changed
- @utils.hook("raw.received.mode")
- def mode(self, event):
- core.mode(self.events, event)
- # server telling us our own modes
- @utils.hook("raw.received.221")
- def umodeis(self, event):
- core.handle_221(event)
-
- # someone (maybe me!) has been invited somewhere
- @utils.hook("raw.received.invite")
- def invite(self, event):
- core.invite(self.events, event)
-
- # we've received/sent a PRIVMSG, NOTICE or TAGMSG
- @utils.hook("raw.received.privmsg")
- @utils.hook("raw.received.notice")
- @utils.hook("raw.received.tagmsg")
- def message(self, event):
- message.message(self.events, event)
-
- # IRCv3 AWAY, used to notify us that a client we can see has changed /away
- @utils.hook("raw.received.away")
- def away(self, event):
- user.away(self.events, event)
-
- @utils.hook("raw.received.batch")
- def batch(self, event):
- identifier = event["line"].args[0]
- modifier, identifier = identifier[0], identifier[1:]
-
- if modifier == "+":
- batch_type = event["line"].args[1]
- args = event["line"].args[2:]
-
- batch = IRCLine.IRCBatch(identifier, batch_type, args,
- event["line"].tags, source=event["line"].source)
- event["server"].batches[identifier] = batch
-
- self.events.on("received.batch.start").call(batch=batch,
- server=event["server"])
- else:
- batch = event["server"].batches[identifier]
- del event["server"].batches[identifier]
-
- lines = batch.get_lines()
-
- results = self.events.on("received.batch.end").call(batch=batch,
- server=event["server"])
-
- for result in results:
- if not result == None:
- lines = result
- break
-
- for line in lines:
- self._handle(event["server"], line)
-
- # IRCv3 CHGHOST, a user's username and/or hostname has changed
- @utils.hook("raw.received.chghost")
- def chghost(self, event):
- user.chghost(self.events, event)
-
- # IRCv3 SETNAME, to change a user's realname
- @utils.hook("raw.received.setname")
- def setname(self, event):
- user.setname(event)
-
- @utils.hook("raw.received.account")
- def account(self, event):
- user.account(self.events, event)
-
- # response to a WHO command for user information
- @utils.hook("raw.received.352", default_event=True)
- def handle_352(self, event):
- core.handle_352(self.events, event)
-
- # response to a WHOX command for user information, including account name
- @utils.hook("raw.received.354", default_event=True)
- def handle_354(self, event):
- core.handle_354(self.events, event)
-
- # response to an empty mode command
- @utils.hook("raw.received.324")
- def handle_324(self, event):
- channel.handle_324(self.events, event)
-
- # channel creation unix timestamp
- @utils.hook("raw.received.329", default_event=True)
- def handle_329(self, event):
- channel.handle_329(event)
-
- # nickname already in use
- @utils.hook("raw.received.433", default_event=True)
- def handle_433(self, event):
- core.handle_433(event)
- # nickname/channel is temporarily unavailable
- @utils.hook("raw.received.437")
- def handle_437(self, event):
- core.handle_437(event)
-
- # we need a registered nickname for this channel
- @utils.hook("raw.received.477", default_event=True)
- def handle_477(self, event):
- channel.handle_477(self.timers, event)
-
- # someone's been kicked from a channel
- @utils.hook("raw.received.kick")
- def kick(self, event):
- channel.kick(self.events, event)
-
- # a channel has been renamed
- @utils.hook("raw.received.rename")
- def rename(self, event):
- channel.rename(self.events, event)
diff --git a/modules/line_handler/channel.py b/modules/line_handler/channel.py
deleted file mode 100644
index 91150839..00000000
--- a/modules/line_handler/channel.py
+++ /dev/null
@@ -1,160 +0,0 @@
-from src import IRCLine, utils
-
-def handle_332(events, event):
- channel = event["server"].channels.get(event["line"].args[1])
- topic = event["line"].args.get(2)
- channel.set_topic(topic)
- events.on("received.332").call(channel=channel, server=event["server"],
- topic=topic)
-
-def topic(events, event):
- user = event["server"].get_user(event["line"].source.nickname)
- channel = event["server"].channels.get(event["line"].args[0])
- topic = event["line"].args.get(1)
- channel.set_topic(topic)
- events.on("received.topic").call(channel=channel, server=event["server"],
- topic=topic, user=user)
-
-def handle_333(events, event):
- channel = event["server"].channels.get(event["line"].args[1])
-
- topic_setter = IRCLine.parse_hostmask(event["line"].args[2])
- topic_time = int(event["line"].args[3])
-
- channel.set_topic_setter(topic_setter)
- channel.set_topic_time(topic_time)
- events.on("received.333").call(channel=channel,
- setter=topic_setter, set_at=topic_time, server=event["server"])
-
-def handle_353(event):
- channel = event["server"].channels.get(event["line"].args[2])
- nicknames = event["line"].args.get(3).split(" ")
-
- # there can sometimes be a dangling space at the end of a 353
- if nicknames and not nicknames[-1]:
- nicknames.pop(-1)
-
- for nickname in nicknames:
- modes = set([])
-
- while nickname[0] in event["server"].prefix_symbols:
- modes.add(event["server"].prefix_symbols[nickname[0]])
- nickname = nickname[1:]
-
- if event["server"].has_capability_str("userhost-in-names"):
- hostmask = IRCLine.parse_hostmask(nickname)
- nickname = hostmask.nickname
- user = event["server"].get_user(hostmask.nickname,
- username=hostmask.username, hostname=hostmask.hostname)
- else:
- user = event["server"].get_user(nickname)
- user.join_channel(channel)
- channel.add_user(user)
-
- for mode in modes:
- channel.add_mode(mode, nickname)
-
-def handle_366(event):
- event["server"].send_whox(event["line"].args[1], "n", "ahnrtu", "111")
-
-def join(events, event):
- account = None
- realname = None
- channel_name = event["line"].args[0]
-
- if len(event["line"].args) == 3:
- if not event["line"].args[1] == "*":
- account = event["line"].args[1]
- realname = event["line"].args[2]
-
- user = event["server"].get_user(event["line"].source.nickname,
- username=event["line"].source.username,
- hostname=event["line"].source.hostname)
-
- if account:
- user.account = account
- if realname:
- user.realname = realname
-
- is_self = event["server"].is_own_nickname(event["line"].source.nickname)
- if is_self:
- channel = event["server"].channels.add(channel_name)
- else:
- channel = event["server"].channels.get(channel_name)
-
-
- channel.add_user(user)
- user.join_channel(channel)
-
- if is_self:
- events.on("self.join").call(channel=channel, server=event["server"],
- account=account, realname=realname)
- channel.send_mode()
- else:
- events.on("received.join").call(channel=channel, user=user,
- server=event["server"], account=account, realname=realname)
-
-def part(events, event):
- channel = event["server"].channels.get(event["line"].args[0])
- user = event["server"].get_user(event["line"].source.nickname)
- reason = event["line"].args.get(1)
-
- channel.remove_user(user)
- user.part_channel(channel)
- if not len(user.channels):
- event["server"].remove_user(user)
-
- if not event["server"].is_own_nickname(event["line"].source.nickname):
- events.on("received.part").call(channel=channel, reason=reason,
- user=user, server=event["server"])
- else:
- event["server"].channels.remove(channel)
- events.on("self.part").call(channel=channel, reason=reason,
- server=event["server"])
-
-def handle_324(events, event):
- if event["line"].args[1] in event["server"].channels:
- channel = event["server"].channels.get(event["line"].args[1])
- modes = event["line"].args[2]
- args = event["line"].args[3:]
- new_modes = channel.parse_modes(modes, args[:])
- events.on("received.324").call(modes=new_modes,
- channel=channel, server=event["server"], mode_str=modes,
- args_str=args)
-
-def handle_329(event):
- channel = event["server"].channels.get(event["line"].args[1])
- channel.creation_timestamp = int(event["line"].args[2])
-
-def handle_477(timers, event):
- pass
-
-def kick(events, event):
- user = event["server"].get_user(event["line"].source.nickname)
- target = event["line"].args[1]
- channel = event["server"].channels.get(event["line"].args[0])
- reason = event["line"].args.get(2)
- target_user = event["server"].get_user(target)
-
- if not event["server"].is_own_nickname(target):
- events.on("received.kick").call(channel=channel, reason=reason,
- target_user=target_user, user=user, server=event["server"])
- else:
- event["server"].channels.remove(channel)
- events.on("self.kick").call(channel=channel, reason=reason, user=user,
- server=event["server"])
-
- channel.remove_user(target_user)
- target_user.part_channel(channel)
- if not len(target_user.channels):
- event["server"].remove_user(target_user)
-
-def rename(events, event):
- old_name = event["line"].args[0]
- new_name = event["line"].args[1]
- channel = event["server"].channels.get(old_name)
-
- event["server"].channels.rename(old_name, new_name)
- events.on("received.rename").call(channel=channel, old_name=old_name,
- new_name=new_name, reason=event["line"].args.get(2),
- server=event["server"])
diff --git a/modules/line_handler/core.py b/modules/line_handler/core.py
deleted file mode 100644
index d72bf223..00000000
--- a/modules/line_handler/core.py
+++ /dev/null
@@ -1,154 +0,0 @@
-import codecs, re
-
-RE_ISUPPORT_ESCAPE = re.compile(r"\\x(\d\d)", re.I)
-RE_MODES = re.compile(r"[-+]\w+")
-
-def ping(event):
- event["server"].send_pong(event["line"].args[0])
-
-def handle_001(event):
- event["server"].socket.enable_write_throttle()
- event["server"].name = event["line"].source.hostmask
- event["server"].set_own_nickname(event["line"].args[0])
- event["server"].send_whois(event["server"].nickname)
- event["server"].send_mode(event["server"].nickname)
- event["server"].connected = True
-
-def handle_005(events, event):
- isupport_list = event["line"].args[1:-1]
- isupport = {}
-
- for i, item in enumerate(isupport_list):
- key, sep, value = item.partition("=")
- if value:
- for match in RE_ISUPPORT_ESCAPE.finditer(value):
- char = codecs.decode(match.group(1), "hex").decode("ascii")
- value.replace(match.group(0), char)
-
- if sep:
- isupport[key] = value
- else:
- isupport[key] = None
- event["server"].isupport.update(isupport)
-
- if "NAMESX" in isupport and not event["server"].has_capability_str(
- "multi-prefix"):
- event["server"].send_raw("PROTOCTL NAMESX")
-
- if "PREFIX" in isupport:
- modes, symbols = isupport["PREFIX"][1:].split(")", 1)
- event["server"].prefix_symbols.clear()
- event["server"].prefix_modes.clear()
- for symbol, mode in zip(symbols, modes):
- event["server"].prefix_symbols[symbol] = mode
- event["server"].prefix_modes[mode] = symbol
-
- if "CHANMODES" in isupport:
- modes = isupport["CHANMODES"].split(",", 3)
- event["server"].channel_list_modes = list(modes[0])
- event["server"].channel_parametered_modes = list(modes[1])
- event["server"].channel_setting_modes = list(modes[2])
- event["server"].channel_modes = list(modes[3])
- if "CHANTYPES" in isupport:
- event["server"].channel_types = list(isupport["CHANTYPES"])
- if "CASEMAPPING" in isupport:
- event["server"].case_mapping = isupport["CASEMAPPING"]
- if "STATUSMSG" in isupport:
- event["server"].statusmsg = list(isupport["STATUSMSG"])
-
- events.on("received.005").call(isupport=isupport,
- server=event["server"])
-
-def handle_004(event):
- event["server"].version = event["line"].args[2]
-
-def motd_start(event):
- event["server"].motd_lines.clear()
-def motd_line(event):
- event["server"].motd_lines.append(event["line"].args[1])
-
-def _own_modes(server, modes):
- mode_chunks = RE_MODES.findall(modes)
- for chunk in mode_chunks:
- remove = chunk[0] == "-"
- for mode in chunk[1:]:
- server.change_own_mode(remove, mode)
-
-def mode(events, event):
- user = event["server"].get_user(event["line"].source.nickname)
- target = event["line"].args[0]
- is_channel = event["server"].is_channel(target)
- if is_channel:
- channel = event["server"].channels.get(target)
- modes = event["line"].args[1]
- args = event["line"].args[2:]
-
- new_modes = channel.parse_modes(modes, args[:])
-
- events.on("received.mode.channel").call(modes=new_modes,
- channel=channel, server=event["server"], user=user, modes_str=modes,
- args_str=args)
- elif event["server"].is_own_nickname(target):
- modes = event["line"].args[1]
- _own_modes(event["server"], modes)
-
- events.on("self.mode").call(modes=modes, server=event["server"])
- event["server"].send_who(event["server"].nickname)
-
-def handle_221(event):
- _own_modes(event["server"], event["line"].args[1])
-
-def invite(events, event):
- target_channel = event["line"].args[1]
- user = event["server"].get_user(event["line"].source.nickname)
- target_user = event["server"].get_user(event["line"].args[0])
- events.on("received.invite").call(user=user, target_channel=target_channel,
- server=event["server"], target_user=target_user)
-
-def handle_352(events, event):
- nickname = event["line"].args[5]
- username = event["line"].args[2]
- hostname = event["line"].args[3]
-
- if event["server"].is_own_nickname(nickname):
- event["server"].username = username
- event["server"].hostname = hostname
-
- target = event["server"].get_user(nickname)
- target.username = username
- target.hostname = hostname
- events.on("received.who").call(server=event["server"],
- user=target)
-
-def handle_354(events, event):
- if event["line"].args[1] == "111":
- nickname = event["line"].args[4]
- username = event["line"].args[2]
- hostname = event["line"].args[3]
- realname = event["line"].args[6]
- account = event["line"].args[5]
-
- if event["server"].is_own_nickname(nickname):
- event["server"].username = username
- event["server"].hostname = hostname
- event["server"].realname = realname
-
- target = event["server"].get_user(nickname)
- target.username = username
- target.hostname = hostname
- target.realname = realname
- if not account == "0":
- target.account = account
- else:
- target.account = None
- events.on("received.whox").call(server=event["server"],
- user=target)
-
-def _nick_in_use(server):
- new_nick = "%s|" % server.connection_params.nickname
- server.send_nick(new_nick)
-
-def handle_433(event):
- _nick_in_use(event["server"])
-def handle_437(event):
- _nick_in_use(event["server"])
diff --git a/modules/line_handler/ircv3.py b/modules/line_handler/ircv3.py
deleted file mode 100644
index a9d740ed..00000000
--- a/modules/line_handler/ircv3.py
+++ /dev/null
@@ -1,138 +0,0 @@
-from src import utils
-
-CAPABILITIES = [
- utils.irc.Capability("multi-prefix"),
- utils.irc.Capability("chghost"),
- utils.irc.Capability("invite-notify"),
- utils.irc.Capability("account-tag"),
- utils.irc.Capability("account-notify"),
- utils.irc.Capability("extended-join"),
- utils.irc.Capability("away-notify"),
- utils.irc.Capability("userhost-in-names"),
- utils.irc.Capability("message-tags", "draft/message-tags-0.2"),
- utils.irc.Capability("cap-notify"),
- utils.irc.Capability("batch"),
- utils.irc.Capability(None, "draft/rename", alias="rename"),
- utils.irc.Capability(None, "draft/setname", alias="setname")
-]
-
-def _cap_depend_sort(caps, server_caps):
- sorted_caps = []
-
- caps_copy = {alias: cap.copy() for alias, cap in caps.items()}
-
- for cap in caps.values():
- if not cap.available(server_caps):
- del caps_copy[cap.alias]
-
- while True:
- remove = []
- for alias, cap in caps_copy.items():
- for depend_alias in cap.depends_on:
- if not depend_alias in caps_copy:
- remove.append(alias)
- if remove:
- for alias in remove:
- del caps_copy[alias]
- else:
- break
-
- while caps_copy:
- fulfilled = []
- for cap in caps_copy.values():
- remove = []
- for depend_alias in cap.depends_on:
- if depend_alias in sorted_caps:
- remove.append(depend_alias)
- for remove_cap in remove:
- cap.depends_on.remove(remove_cap)
-
- if not cap.depends_on:
- fulfilled.append(cap.alias)
- for fulfilled_cap in fulfilled:
- del caps_copy[fulfilled_cap]
- sorted_caps.append(fulfilled_cap)
- return [caps[alias] for alias in sorted_caps]
-
-def _cap_match(server, caps):
- matched_caps = {}
- blacklist = server.get_setting("blacklisted-caps", [])
-
- cap_aliases = {}
- for cap in caps:
- if not cap.alias in blacklist:
- cap_aliases[cap.alias] = cap
-
- sorted_caps = _cap_depend_sort(cap_aliases, server.server_capabilities)
-
- for cap in sorted_caps:
- available = cap.available(server.server_capabilities)
- if available and not server.has_capability(cap):
- matched_caps[available] = cap
- return matched_caps
-
-def cap(exports, events, event):
- capabilities = utils.parse.keyvalue(event["line"].args[-1])
- subcommand = event["line"].args[1].upper()
- is_multiline = len(event["line"].args) > 3 and event["line"].args[2] == "*"
-
- if subcommand == "DEL":
- for capability in capabilities.keys():
- event["server"].agreed_capabilities.discard(capability)
- if capability in event["server"].server_capabilities:
- del event["server"].server_capabilities[capability]
-
- events.on("received.cap.del").call(server=event["server"],
- capabilities=capabilities)
- elif subcommand == "ACK":
- for cap_name, cap_args in capabilities.items():
- if cap_name[0] == "-":
- event["server"].agreed_capabilities.discard(cap_name[1:])
- else:
- event["server"].agreed_capabilities.add(cap_name)
-
- events.on("received.cap.ack").call(capabilities=capabilities,
- server=event["server"])
-
- if subcommand == "LS" or subcommand == "NEW":
- event["server"].server_capabilities.update(capabilities)
- if not is_multiline:
- server_caps = list(event["server"].server_capabilities.keys())
- all_caps = CAPABILITIES[:]
-
- export_caps = [cap.copy() for cap in exports.get_all("cap")]
- all_caps.extend(export_caps)
-
- module_caps = events.on("received.cap.ls").call(
- capabilities=event["server"].server_capabilities,
- server=event["server"])
- module_caps = list(filter(None, module_caps))
- all_caps.extend(module_caps)
-
- matched_caps = _cap_match(event["server"], all_caps)
- event["server"].capability_queue.update(matched_caps)
-
- if event["server"].capability_queue:
- event["server"].send_capability_queue()
- else:
- event["server"].send_capability_end()
-
-
- if subcommand == "ACK" or subcommand == "NAK":
- ack = subcommand == "ACK"
- for capability in capabilities:
- if capability in event["server"].capabilities_requested:
- cap_obj = event["server"].capabilities_requested[capability]
- del event["server"].capabilities_requested[capability]
- if ack:
- cap_obj.ack()
- else:
- cap_obj.nak()
-
- if (not event["server"].capabilities_requested and
- not event["server"].waiting_for_capabilities()):
- event["server"].send_capability_end()
-
-def authenticate(events, event):
- events.on("received.authenticate").call(message=event["line"].args[0],
- server=event["server"])
diff --git a/modules/line_handler/message.py b/modules/line_handler/message.py
deleted file mode 100644
index fa36dbc2..00000000
--- a/modules/line_handler/message.py
+++ /dev/null
@@ -1,109 +0,0 @@
-from src import IRCBuffer, utils
-
-def _from_self(server, source):
- if source:
- return server.is_own_nickname(source.nickname)
- else:
- return False
-
-def message(events, event):
- from_self = _from_self(event["server"], event["line"].source)
- if from_self == None:
- return
-
- direction = "send" if from_self else "received"
-
- target_str = event["line"].args[0]
-
- message = None
- if len(event["line"].args) > 1:
- message = event["line"].args[1]
-
- if not from_self and (
- not event["line"].source or
- not event["server"].name or
- event["line"].source.hostmask == event["server"].name or
- target_str == "*"):
- if event["line"].source:
- event["server"].name = event["line"].source.hostmask
-
- events.on("received.server-notice").call(message=message,
- message_split=message.split(" "), server=event["server"])
- return
-
- if from_self:
- user = event["server"].get_user(event["server"].nickname)
- else:
- user = event["server"].get_user(event["line"].source.nickname,
- username=event["line"].source.username,
- hostname=event["line"].source.hostname)
-
- # strip prefix_symbols from the start of target, for when people use
- # e.g. 'PRIVMSG +#channel :hi' which would send a message to only
- # voiced-or-above users
- target = target_str.lstrip("".join(event["server"].statusmsg))
-
- is_channel = event["server"].is_channel(target)
-
- if is_channel:
- if not target in event["server"].channels:
- return
- target_obj = event["server"].channels.get(target)
- else:
- target_obj = event["server"].get_user(target)
-
- kwargs = {"server": event["server"], "target": target_obj,
- "target_str": target_str, "user": user, "tags": event["line"].tags,
- "is_channel": is_channel, "from_self": from_self, "line": event["line"]}
-
- action = False
-
- if message:
- ctcp_message = utils.irc.parse_ctcp(message)
-
- if ctcp_message:
- if (not ctcp_message.command == "ACTION" or not
- event["line"].command == "PRIVMSG"):
- if event["line"].command == "PRIVMSG":
- ctcp_action = "request"
- else:
- ctcp_action = "response"
- events.on(direction).on("ctcp").on(ctcp_action).call(
- message=ctcp_message.message, **kwargs)
- events.on(direction).on("ctcp").on(ctcp_action).on(
- ctcp_message.command).call(message=ctcp_message.message,
- **kwargs)
- return
- else:
- message = ctcp_message.message
- action = True
-
- if not message == None:
- kwargs["message"] = message
- kwargs["message_split"] = message.split(" ")
- kwargs["action"] = action
-
- event_type = event["line"].command.lower()
- if event_type == "privmsg":
- event_type = "message"
-
- context = "channel" if is_channel else "private"
- hook = events.on(direction).on(event_type).on(context)
-
- buffer_line = None
- if message:
- buffer_line = IRCBuffer.BufferLine(user.nickname, message, action,
- event["line"].tags, from_self, event["line"].command)
-
- buffer_obj = target_obj
- if is_channel:
- hook.call(channel=target_obj, buffer_line=buffer_line, **kwargs)
- else:
- buffer_obj = target_obj
- if not from_self:
- buffer_obj = user
-
- hook.call(buffer_line=buffer_line, **kwargs)
-
- if buffer_line:
- buffer_obj.buffer.add(buffer_line)
diff --git a/modules/line_handler/user.py b/modules/line_handler/user.py
deleted file mode 100644
index d1592cd7..00000000
--- a/modules/line_handler/user.py
+++ /dev/null
@@ -1,102 +0,0 @@
-from src import utils
-
-def handle_311(event):
- nickname = event["line"].args[1]
- username = event["line"].args[2]
- hostname = event["line"].args[3]
- realname = event["line"].args[4]
-
- if event["server"].is_own_nickname(nickname):
- event["server"].username = username
- event["server"].hostname = hostname
- event["server"].realname = realname
-
- target = event["server"].get_user(nickname)
- target.username = username
- target.hostname = hostname
- target.realname = realname
-
-def quit(events, event):
- nickname = None
- if event["direction"] == utils.Direction.Recv:
- nickname = event["line"].source.nickname
- reason = event["line"].args.get(0)
-
- if event["direction"] == utils.Direction.Recv:
- nickname = event["line"].source.nickname
- if (not event["server"].is_own_nickname(nickname) and
- not event["line"].source.hostmask == "*"):
- user = event["server"].get_user(nickname)
- events.on("received.quit").call(reason=reason, user=user,
- server=event["server"])
- event["server"].remove_user(user)
- else:
- event["server"].disconnect()
- else:
- events.on("send.quit").call(reason=reason, server=event["server"])
-
-def nick(events, event):
- new_nickname = event["line"].args.get(0)
- user = event["server"].get_user(event["line"].source.nickname)
- old_nickname = user.nickname
- user.set_nickname(new_nickname)
- event["server"].change_user_nickname(old_nickname, new_nickname)
-
- if not event["server"].is_own_nickname(event["line"].source.nickname):
- events.on("received.nick").call(new_nickname=new_nickname,
- old_nickname=old_nickname, user=user, server=event["server"])
- else:
- events.on("self.nick").call(server=event["server"],
- new_nickname=new_nickname, old_nickname=old_nickname)
- event["server"].set_own_nickname(new_nickname)
-
-def away(events, event):
- user = event["server"].get_user(event["line"].source.nickname)
- message = event["line"].args.get(0)
- if message:
- user.away = True
- user.away_message = message
- events.on("received.away.on").call(user=user, server=event["server"],
- message=message)
- else:
- user.away = False
- user.away_message = None
- events.on("received.away.off").call(user=user, server=event["server"])
-
-def chghost(events, event):
- nickname = event["line"].source.nickname
- username = event["line"].args[0]
- hostname = event["line"].args[1]
-
- if event["server"].is_own_nickname(nickname):
- event["server"].username = username
- event["server"].hostname = hostname
-
- target = event["server"].get_user(nickname)
- events.on("received.chghost").call(user=target, server=event["server"],
- username=username, hostname=hostname)
-
- target.username = username
- target.hostname = hostname
-
-def setname(event):
- nickname = event["line"].source.nickname
- realname = event["line"].args[0]
-
- user = event["server"].get_user(nickname)
- user.realname = realname
-
- if event["server"].is_own_nickname(nickname):
- event["server"].realname = realname
-
-def account(events, event):
- user = event["server"].get_user(event["line"].source.nickname)
-
- if not event["line"].args[0] == "*":
- user.account = event["line"].args[0]
- events.on("received.account.login").call(user=user,
- server=event["server"], account=event["line"].args[0])
- else:
- user.account = None
- events.on("received.account.logout").call(user=user,
- server=event["server"])
diff --git a/modules/modules.py b/modules/modules.py
deleted file mode 100644
index a93afaea..00000000
--- a/modules/modules.py
+++ /dev/null
@@ -1,122 +0,0 @@
-#--depends-on commands
-#--depends-on permissions
-
-from src import ModuleManager, utils
-
-class Module(ModuleManager.BaseModule):
- def _catch(self, name, func):
- try:
- return func()
- except ModuleManager.ModuleNotFoundException:
- raise utils.EventError("Module '%s' not found" % name)
- except ModuleManager.ModuleNotLoadedException:
- raise utils.EventError("Module '%s' isn't loaded" % name)
- except ModuleManager.ModuleWarning as warning:
- raise utils.EventError("Module '%s' not loaded: %s" % (
- name, str(warning)))
- except Exception as e:
- raise utils.EventError("Failed to reload module '%s': %s" % (
- name, str(e)))
-
- @utils.hook("received.command.loadmodule", min_args=1)
- def load(self, event):
- """
- :help: Load a module
- :usage: <module name>
- :permission: load-module
- """
- name = event["args_split"][0].lower()
- if name in self.bot.modules.modules:
- raise utils.EventError("Module '%s' is already loaded" % name)
- definition = self._catch(name,
- lambda: self.bot.modules.find_module(name))
-
- self._catch(name, lambda: self.bot.modules.load_module(self.bot, definition))
- event["stdout"].write("Loaded '%s'" % name)
-
- @utils.hook("received.command.unloadmodule", min_args=1)
- def unload(self, event):
- """
- :help: Unload a module
- :usage: <module name>
- :permission: unload-module
- """
- name = event["args_split"][0].lower()
- if not name in self.bot.modules.modules:
- raise utils.EventError("Module '%s' isn't loaded" % name)
-
- self._catch(name, lambda: self.bot.modules.unload_module(name))
- event["stdout"].write("Unloaded '%s'" % name)
-
- def _reload(self, name):
- self.bot.modules.unload_module(name)
- definition = self._catch(name,
- lambda: self.bot.modules.find_module(name))
- self.bot.modules.load_module(self.bot, definition)
- @utils.hook("received.command.reloadmodule", min_args=1)
- def reload(self, event):
- """
- :help: Reload a module
- :usage: <module name>
- :permission: reload-module
- """
- name = event["args_split"][0].lower()
-
- self._catch(name, lambda: self._reload(name))
- event["stdout"].write("Reloaded '%s'" % name)
-
- @utils.hook("received.command.reloadallmodules")
- def reload_all(self, event):
- """
- :help: Reload all modules
- :permission: reload-all-modules
- """
- result = self.bot.try_reload_modules()
- if result.success:
- event["stdout"].write(result.message)
- else:
- event["stderr"].write(result.message)
-
- def _get_blacklist(self):
- return self.bot.config.get_list("module-blacklist")
- def _save_blacklist(self, modules):
- self.bot.config.set_list("module-blacklist", modules)
- self.bot.config.save()
-
- @utils.hook("received.command.enablemodule")
- @utils.kwarg("min_args", 1)
- @utils.kwarg("help", "Remove a module from the module blacklist")
- @utils.kwarg("usage", "<module>")
- @utils.kwarg("permission", "enable-module")
- def enable(self, event):
- name = event["args_split"][0].lower()
-
- blacklist = self._get_blacklist()
- if not name in blacklist:
- raise utils.EventError("Module '%s' isn't disabled" % name)
-
- blacklist.remove(name)
- self._save_blacklist(blacklist)
- event["stdout"].write("Module '%s' has been enabled and can now "
- "be loaded" % name)
-
- @utils.hook("received.command.disablemodule")
- @utils.kwarg("min_args", 1)
- @utils.kwarg("help", "Add a module to the module blacklist")
- @utils.kwarg("usage", "<module>")
- @utils.kwarg("permission", "disable-module")
- def disable(self, event):
- name = event["args_split"][0].lower()
- and_unloaded = ""
- if name in self.bot.modules.modules:
- self.bot.modules.unload_module(name)
- and_unloaded = " and unloaded"
-
- blacklist = self._get_blacklist()
- if name in blacklist:
- raise utils.EventError("Module '%s' is already disabled" % name)
-
- blacklist.append(name)
- self._save_blacklist(blacklist)
- event["stdout"].write("Module '%s' has been disabled%s" % (
- name, and_unloaded))
diff --git a/modules/more.py b/modules/more.py
deleted file mode 100644
index 52849938..00000000
--- a/modules/more.py
+++ /dev/null
@@ -1,23 +0,0 @@
-from src import EventManager, ModuleManager, utils
-
-class Module(ModuleManager.BaseModule):
- @utils.hook("new.user")
- @utils.hook("new.channel")
- def new(self, event):
- obj = event.get("user", event.get("channel", None))
- obj._last_stdout = None
- obj._last_stderr = None
-
- @utils.hook("postprocess.command")
- @utils.kwarg("priority", EventManager.PRIORITY_MONITOR)
- def postprocess(self, event):
- if event["stdout"].has_text():
- event["target"]._last_stdout = event["stdout"]
- if event["stderr"].has_text():
- event["target"]._last_stderr = event["stderr"]
-
- @utils.hook("received.command.more")
- def more(self, event):
- last_stdout = event["target"]._last_stdout
- if last_stdout and last_stdout.has_text():
- event["stdout"].write_lines(last_stdout.get_all())
diff --git a/modules/nick_regain.py b/modules/nick_regain.py
deleted file mode 100644
index cf1dfa48..00000000
--- a/modules/nick_regain.py
+++ /dev/null
@@ -1,48 +0,0 @@
-from src import ModuleManager, utils
-
-class Module(ModuleManager.BaseModule):
- def _done_connecting(self, server):
- target_nick = server.connection_params.nickname
- if not server.irc_equals(server.nickname, target_nick):
- if "MONITOR" in server.isupport:
- server.send_raw("MONITOR + %s" % target_nick)
- else:
- self.timers.add("ison-check", self._ison_check, 30,
- server=server)
-
- @utils.hook("received.376")
- def end_of_motd(self, event):
- self._done_connecting(event["server"])
- @utils.hook("received.422")
- def no_motd(self, event):
- self._done_connecting(event["server"])
-
- @utils.hook("self.nick")
- def self_nick(self, event):
- target_nick = event["server"].connection_params.nickname
- if event["server"].irc_equals(event["new_nickname"], target_nick):
- if "MONITOR" in event["server"].isupport:
- event["server"].send_raw("MONITOR - %s " % target_nick)
-
- @utils.hook("received.731")
- def mon_offline(self, event):
- target_nick = event["server"].connection_params.nickname
- nicks = event["line"].args[1].split(",")
- nicks = [event["server"].irc_lower(n) for n in nicks]
- if event["server"].irc_lower(target_nick) in nicks:
- event["server"].send_nick(target_nick)
-
- def _ison_check(self, timer):
- server = timer.kwargs["server"]
- target_nick = server.connection_params.nickname
- if not server.irc_equals(server.nickname, target_nick):
- server.send_raw("ISON %s" % target_nick)
- timer.redo()
-
- @utils.hook("received.303")
- def ison_response(self, event):
- target_nick = event["server"].connection_params.nickname
- if not event["line"].args[1] and not event["server"].irc_equals(
- event["server"].nickname, target_nick):
- event["server"].send_nick(target_nick)
-
diff --git a/modules/perform.py b/modules/perform.py
deleted file mode 100644
index 832cab54..00000000
--- a/modules/perform.py
+++ /dev/null
@@ -1,76 +0,0 @@
-#--depends-on commands
-#--depends-on permissions
-
-from src import EventManager, IRCLine, ModuleManager, utils
-
-class Module(ModuleManager.BaseModule):
- def _execute(self, server, commands, **kwargs):
- for command in commands:
- line = command.format(**kwargs)
- if IRCLine.is_human(line):
- line = IRCLine.parse_human(line)
- else:
- line = IRCLine.parse_line(line)
- server.send(line)
-
- @utils.hook("received.001", priority=EventManager.PRIORITY_URGENT)
- def on_connect(self, event):
- commands = event["server"].get_setting("perform", [])
- self._execute(event["server"], commands, NICK=event["server"].nickname)
-
- @utils.hook("self.join", priority=EventManager.PRIORITY_URGENT)
- def on_join(self, event):
- commands = event["channel"].get_setting("perform", [])
- self._execute(event["server"], commands, NICK=event["server"].nickname,
- CHAN=event["channel"].name)
-
- def _perform(self, target, args_split):
- subcommand = args_split[0].lower()
- current_perform = target.get_setting("perform", [])
- if subcommand == "list":
- return "Configured commands: %s" % ", ".join(current_perform)
-
- message = None
- if subcommand == "add":
- if not len(args_split) > 1:
- raise utils.EventError("Please provide a raw command to add")
- current_perform.append(" ".join(args_split[1:]))
- message = "Added command"
- elif subcommand == "remove":
- if not len(args_split) > 1:
- raise utils.EventError("Please provide an index to remove")
- if not args_split[1].isdigit():
- raise utils.EventError("Please provide a number")
- index = int(args_split[1])
- if not index < len(current_perform):
- raise utils.EventError("Index out of bounds")
- current_perform.pop(index)
- message = "Removed command"
- else:
- raise utils.EventError("Unknown subcommand '%s'" % subcommand)
-
- target.set_setting("perform", current_perform)
- return message
-
- @utils.hook("received.command.perform", min_args=1)
- @utils.kwarg("min_args", 1)
- @utils.kwarg("help", "Edit on-connect command configuration")
- @utils.kwarg("usage", "list")
- @utils.kwarg("usage", "add <raw command>")
- @utils.kwarg("usage", "remove <index>")
- @utils.kwarg("permission", "perform")
- def perform(self, event):
- event["stdout"].write(self._perform(event["server"],
- event["args_split"]))
-
- @utils.hook("received.command.cperform", min_args=1)
- @utils.kwarg("min_args", 1)
- @utils.kwarg("channel_only", True)
- @utils.kwarg("help", "Edit channel on-join command configuration")
- @utils.kwarg("usage", "list")
- @utils.kwarg("usage", "add <raw command>")
- @utils.kwarg("usage", "remove <index>")
- @utils.kwarg("permission", "cperform")
- def cperform(self, event):
- event["stdout"].write(self._perform(event["target"],
- event["args_split"]))
diff --git a/modules/permissions/__init__.py b/modules/permissions/__init__.py
deleted file mode 100644
index 0559774c..00000000
--- a/modules/permissions/__init__.py
+++ /dev/null
@@ -1,357 +0,0 @@
-#--depends-on commands
-
-import base64, binascii, os
-import scrypt
-from src import ModuleManager, utils
-
-HOSTMASKS_SETTING = "hostmask-account"
-NO_PERMISSION = "You do not have permission to do that"
-
-class Module(ModuleManager.BaseModule):
- def on_load(self):
- self.exports.add("is-identified", self._is_identified)
- self.exports.add("account-name", self._account_name)
-
- @utils.hook("new.server")
- def new_server(self, event):
- event["server"]._hostmasks = {}
-
- for account, user_hostmasks in event["server"].get_all_user_settings(
- HOSTMASKS_SETTING):
- for hostmask in user_hostmasks:
- self._add_hostmask(event["server"],
- utils.irc.hostmask_parse(hostmask), account)
-
- def _add_hostmask(self, server, hostmask, account):
- server._hostmasks[hostmask.original] = (hostmask, account)
- def _remove_hostmask(self, server, hostmask):
- if hostmask in server._hostmasks:
- del server._hostmasks[hostmask]
-
- def _make_salt(self):
- return base64.b64encode(os.urandom(64)).decode("utf8")
-
- def _random_password(self):
- return binascii.hexlify(os.urandom(32)).decode("utf8")
-
- def _make_hash(self, password, salt=None):
- salt = salt or self._make_salt()
- hash = base64.b64encode(scrypt.hash(password, salt)).decode("utf8")
- return hash, salt
-
- def _get_hash(self, server, account):
- hash, salt = server.get_user(account).get_setting("authentication",
- (None, None))
- return hash, salt
-
- def _master_password(self):
- master_password = self._random_password()
- hash, salt = self._make_hash(master_password)
- self.bot.set_setting("master-password", [hash, salt])
- return master_password
- @utils.hook("control.master-password")
- def command_line(self, event):
- master_password = self._master_password()
- return "One-time master password: %s" % master_password
-
- def _has_identified(self, server, user, account):
- user._id_override = server.get_user_id(account)
- def _is_identified(self, user):
- return not user._id_override == None
- def _signout(self, user):
- user._id_override = None
-
- def _find_hostmask(self, server, user):
- user_hostmask = user.hostmask()
- for hostmask, (hostmask_pattern, account) in server._hostmasks.items():
- if utils.irc.hostmask_match(user_hostmask, hostmask_pattern):
- return (hostmask, account)
- def _specific_hostmask(self, server, hostmask, account):
- for user in server.users.values():
- if utils.irc.hostmask_match(user.hostmask(), hostmask):
- if account == None:
- user._hostmask_account = None
- self._signout(user)
- else:
- user._hostmask_account = (hostmask, account)
- self._has_identified(server, user, account)
-
- def _account_name(self, user):
- if not user.account == None:
- return user.account
- elif not user._account_override == None:
- return user._account_override
- elif not user._hostmask_account == None:
- return user._hostmask_account[1]
-
- @utils.hook("new.user")
- def new_user(self, event):
- event["user"]._hostmask_account = None
- event["user"]._account_override = None
- event["user"]._master_admin = False
-
- def _set_hostmask(self, server, user):
- account = self._find_hostmask(server, user)
- if not account == None:
- hostmask, account = account
- user._hostmask_account = (hostmask, account)
- self._has_identified(server, user, account)
-
- @utils.hook("received.chghost")
- @utils.hook("received.nick")
- @utils.hook("received.who")
- @utils.hook("received.whox")
- @utils.hook("received.message.private")
- def chghost(self, event):
- if not self._is_identified(event["user"]):
- self._set_hostmask(event["server"], event["user"])
- @utils.hook("received.whox")
- @utils.hook("received.account")
- @utils.hook("received.account.login")
- @utils.hook("received.account.logout")
- @utils.hook("received.join")
- def check_account(self, event):
- if not self._is_identified(event["user"]):
- if event["user"].account:
- self._has_identified(event["server"], event["user"],
- event["user"].account)
- else:
- self._set_hostmask(event["server"], event["user"])
-
- def _get_permissions(self, user):
- if self._is_identified(user):
- return user.get_setting("permissions", [])
- return []
-
- def _has_permission(self, user, permission):
- if user._master_admin:
- return True
-
- permissions = self._get_permissions(user)
- if permission in permissions:
- return True
- else:
- permission_parts = permission.split(".")
- for user_permission in permissions:
- user_permission_parts = user_permission.split(".")
- for i, part in enumerate(permission_parts):
- last = i==(len(permission_parts)-1)
- user_last = i==(len(user_permission_parts)-1)
- if not permission_parts[i] == user_permission_parts[i]:
- if user_permission_parts[i] == "*" and user_last:
- return True
- else:
- break
- else:
- if last and user_last:
- return True
- return False
-
- @utils.hook("received.command.masterlogin")
- @utils.kwarg("min_args", 1)
- @utils.kwarg("private_only", True)
- def master_login(self, event):
- saved_hash, saved_salt = self.bot.get_setting("master-password",
- (None, None))
- if saved_hash and saved_salt:
- given_hash, _ = self._make_hash(event["args"], saved_salt)
- if utils.security.constant_time_compare(given_hash, saved_hash):
- self.bot.del_setting("master-password")
- event["user"]._master_admin = True
- event["stdout"].write("Master login successful")
- return
- event["stderr"].write("Master login failed")
-
- @utils.hook("received.command.mypermissions")
- @utils.kwarg("authenticated", True)
- def my_permissions(self, event):
- """
- :help: Show your permissions
- """
- permissions = event["user"].get_setting("permissions", [])
- event["stdout"].write("Your permissions: %s" % ", ".join(permissions))
-
-
- @utils.hook("received.command.register", private_only=True, min_args=1)
- @utils.kwarg("min_args", 1)
- @utils.kwarg("private_only", True)
- @utils.kwarg("help", "Register your nickname")
- @utils.kwarg("usage", "<password>")
- def register(self, event):
- hash, salt = self._get_hash(event["server"], event["user"].nickname)
- if not hash and not salt:
- password = event["args"]
- hash, salt = self._make_hash(password)
- event["user"].set_setting("authentication", [hash, salt])
-
- event["user"]._account_override = event["user"].nickname
- self._has_identified(event["server"], event["user"],
- event["user"].nickname)
-
- event["stdout"].write("Nickname registered successfully")
- else:
- event["stderr"].write("This nickname is already registered")
-
- @utils.hook("received.command.identify", private_only=True, min_args=1)
- @utils.kwarg("min_args", 1)
- @utils.kwarg("private_only", True)
- @utils.kwarg("help", "Identify for your current nickname")
- @utils.kwarg("usage", "[account] <password>")
- def identify(self, event):
- if not event["user"].channels:
- raise utils.EventError("You must share at least one channel "
- "with me before you can identify")
-
- if not self._is_identified(event["user"]):
- if len(event["args_split"]) > 1:
- account = event["args_split"][0]
- password = " ".join(event["args_split"][1:])
- else:
- account = event["user"].nickname
- password = event["args"]
-
- hash, salt = self._get_hash(event["server"], account)
- if hash and salt:
- attempt, _ = self._make_hash(password, salt)
- if utils.security.constant_time_compare(attempt, hash):
- event["user"]._account_override = account
- self._has_identified(event["server"], event["user"], account)
-
- event["stdout"].write("Correct password, you have "
- "been identified as %s." % account)
- self.events.on("internal.identified").call(
- user=event["user"])
- else:
- event["stderr"].write("Incorrect password for '%s'" %
- account)
- else:
- event["stderr"].write("Account '%s' is not registered" %
- account)
- else:
- event["stderr"].write("You are already identified as %s" %
- self._account_name(event["user"]))
-
- @utils.hook("received.command.permission")
- @utils.kwarg("min_args", 2)
- @utils.kwarg("usage", "list <account>")
- @utils.kwarg("usage", "clear <account>")
- @utils.kwarg("usage", "add <account> <permission>")
- @utils.kwarg("usage", "remove <account> <permission>")
- @utils.kwarg("permission", "permissions.change")
- def permission(self, event):
- subcommand = event["args_split"][0].lower()
- account = event["args_split"][1]
- target_user = event["server"].get_user(account)
-
- if subcommand == "list":
- event["stdout"].write("Permissions for %s: %s" % (
- account, ", ".join(self._get_permissions(target_user))))
- elif subcommand == "clear":
- if not self._get_permissions(target_user):
- raise utils.EventError("%s has no permissions" % account)
- target_user.del_setting("permissions")
- event["stdout"].write("Cleared permissions for %s" % account)
- else:
- permissions = event["args_split"][2:]
- if not permissions:
- raise utils.EventError("Please provide at least 1 permission")
- user_permissions = self._get_permissions(target_user)
-
- if subcommand == "add":
- new = list(set(permissions)-set(user_permissions))
- if not new:
- raise utils.EventError("No new permissions to give")
- target_user.set_setting("permissions", user_permissions+new)
- event["stdout"].write("Gave %s new permissions: %s" %
- (account, ", ".join(new)))
- elif subcommand == "remove":
- permissions_set = set(permissions)
- user_permissions_set = set(user_permissions)
- removed = list(user_permissions_set&permissions_set)
- if not (user_permissions_set & permissions_set):
- raise utils.EventError("New permissions to remove")
- change = list(user_permissions_set - permissions_set)
-
- if not change:
- target_user.del_setting("permissions")
- else:
- target_user.set_setting("permissions", change)
- event["stdout"].write("Removed permissions from %s: %s" %
- (account, ", ".join(change)))
- else:
- raise utils.EventError("Unknown subcommand %s" % subcommand)
-
- @utils.hook("received.command.hostmask")
- @utils.kwarg("min_args", 1)
- @utils.kwarg("authenticated", True)
- @utils.kwarg("usage", "list")
- @utils.kwarg("usage", "add [hostmask]")
- @utils.kwarg("usage", "remove [hostmask]")
- def hostmask(self, event):
- subcommand = event["args_split"][0].lower()
- hostmasks = event["user"].get_setting(HOSTMASKS_SETTING, [])
-
- if subcommand == "list":
- event["stdout"].write("Your hostmasks: %s" % ", ".join(hostmasks))
- else:
- if event["args_split"][1:]:
- hostmask = event["args_split"][1]
- else:
- hostmask = "*!%s" % event["user"].userhost()
- account = self._account_name(event["user"])
-
- if subcommand == "add":
- if hostmask in hostmasks:
- raise utils.EventError(
- "Hostmask %s is already on your account" % hostmask)
- hostmasks.append(hostmask)
- event["user"].set_setting(HOSTMASKS_SETTING, hostmasks)
-
- hostmask_obj = utils.irc.hostmask_parse(hostmaks)
- self._specific_hostmask(event["server"], hostmask_obj, account)
- self._add_hostmask(event["server"], hostmask_obj, account)
-
- event["stdout"].write("Added %s to your hostmasks" % hostmask)
- elif subcommand == "remove":
- if not hostmask in hostmasks:
- raise utils.EventError("Hostmask %s is not on your account"
- % hostmask)
- while hostmask in hostmasks:
- hostmasks.remove(hostmask)
- event["user"].set_setting(HOSTMASKS_SETTING, hostmasks)
-
- self._specific_hostmask(event["server"], hostmask, None)
- self._remove_hostmask(event["server"], hostmask)
-
- event["stdout"].write("Removed %s from your hostmasks"
- % hostmask)
- else:
- raise utils.EventError("Unknown subcommand %s" % subcommand)
-
- def _assert(self, allowed):
- if allowed:
- return utils.consts.PERMISSION_FORCE_SUCCESS, None
- else:
- return utils.consts.PERMISSION_ERROR, NO_PERMISSION
-
- @utils.hook("preprocess.command")
- def preprocess_command(self, event):
- allowed = None
- permission = event["hook"].get_kwarg("permission", None)
- authenticated = event["hook"].get_kwarg("authenticated", False)
- if not permission == None:
- allowed = self._has_permission(event["user"], permission)
- elif authenticated:
- allowed = self._is_identified(event["user"])
- else:
- return
-
- return self._assert(allowed)
-
- @utils.hook("check.command.permission")
- def check_permission(self, event):
- return self._assert(
- self._has_permission(event["user"], event["request_args"][0]))
- @utils.hook("check.command.authenticated")
- def check_authenticated(self, event):
- return self._assert(self._is_identified(event["user"]))
diff --git a/modules/print_activity.py b/modules/print_activity.py
deleted file mode 100644
index e6a34992..00000000
--- a/modules/print_activity.py
+++ /dev/null
@@ -1,48 +0,0 @@
-#--depends-on config
-#--depends-on format_activity
-
-import datetime
-from src import EventManager, ModuleManager, utils
-
-@utils.export("botset",
- utils.BoolSetting("print-motd", "Set whether I print /motd"))
-@utils.export("botset", utils.BoolSetting("pretty-activity",
- "Whether or not to pretty print activity"))
-@utils.export("channelset", utils.BoolSetting("print",
- "Whether or not to print activity a channel to logs"))
-class Module(ModuleManager.BaseModule):
- def _print(self, event):
- if (event["channel"] and
- not event["channel"].get_setting("print", True)):
- return
-
- line = event["line"]
- if event["pretty"] and self.bot.get_setting("pretty-activity", False):
- line = event["pretty"]
-
- context = (":%s" % event["context"]) if event["context"] else ""
- self.bot.log.info("%s%s | %s", [
- str(event["server"]), context, utils.irc.parse_format(line)])
-
- @utils.hook("formatted.message.channel")
- @utils.hook("formatted.notice.channel")
- @utils.hook("formatted.notice.private")
- @utils.hook("formatted.join")
- @utils.hook("formatted.part")
- @utils.hook("formatted.nick")
- @utils.hook("formatted.server-notice")
- @utils.hook("formatted.invite")
- @utils.hook("formatted.mode.channel")
- @utils.hook("formatted.topic")
- @utils.hook("formatted.topic-timestamp")
- @utils.hook("formatted.kick")
- @utils.hook("formatted.quit")
- @utils.hook("formatted.rename")
- @utils.hook("formatted.chghost")
- def formatted(self, event):
- self._print(event)
-
- @utils.hook("formatted.motd")
- def motd(self, event):
- if self.bot.get_setting("print-motd", True):
- self._print(event)
diff --git a/modules/proxy.py b/modules/proxy.py
deleted file mode 100644
index 1bcaebd1..00000000
--- a/modules/proxy.py
+++ /dev/null
@@ -1,38 +0,0 @@
-import typing, urllib.parse
-import socks
-from src import ModuleManager, utils
-
-TYPES = {
- "socks4": socks.SOCKS4,
- "socks5": socks.SOCKS5,
- "http": socks.HTTP
-}
-
-def _parse(value):
- parsed = urllib.parse.urlparse(value)
- if parsed.scheme in TYPES and parsed.hostname:
- return value
-
-@utils.export("serverset", utils.FunctionSetting(_parse, "proxy",
- "Proxy configuration for the current server",
- example="socks5://localhost:9050"))
-class Module(ModuleManager.BaseModule):
- @utils.hook("preprocess.connect")
- def new_server(self, event):
- proxy = event["server"].get_setting("proxy", None)
- if proxy:
- proxy_parsed = urllib.parse.urlparse(proxy)
- type = TYPES.get(proxy_parsed.scheme)
-
- if type == None:
- raise ValueError("Invalid proxy type '%s' for '%s'" %
- (proxy_parsed.scheme, str(event["server"])))
-
- event["server"].socket._make_socket = self._socket_factory(
- type, proxy_parsed.hostname, proxy_parsed.port)
-
- def _socket_factory(self, ptype, phost, pport):
- def _(host, port, bind, timeout):
- return socks.create_connection((host, port), timeout, bind,
- ptype, phost, pport)
- return _
diff --git a/modules/signals.py b/modules/signals.py
deleted file mode 100644
index 921b483c..00000000
--- a/modules/signals.py
+++ /dev/null
@@ -1,65 +0,0 @@
-import signal, sys
-from src import Config, IRCLine, ModuleManager, utils
-
-class Module(ModuleManager.BaseModule):
- def on_load(self):
- self._exited = False
- signal.signal(signal.SIGINT, self.SIGINT)
- signal.signal(signal.SIGUSR1, self.SIGUSR1)
- signal.signal(signal.SIGHUP, self.SIGHUP)
-
- def SIGINT(self, signum, frame):
- print()
- self.bot.trigger(lambda: self._kill(signum))
-
- def _kill(self, signum):
- if self._exited:
- return
- self._exited = True
-
- self.events.on("signal.interrupt").call(signum=signum)
-
- written = False
- for server in list(self.bot.servers.values()):
- if server.connected:
- server.socket.clear_send_buffer()
-
- line = IRCLine.ParsedLine("QUIT", ["Shutting down"])
- sent_line = server.send(line, immediate=True)
- sent_line.events.on("send").hook(self._make_hook(server))
-
- server.send_enabled = False
- written = True
-
- if not written:
- sys.exit()
-
- def _make_hook(self, server):
- return lambda e: self._disconnect_hook(server)
- def _disconnect_hook(self, server):
- self.bot.disconnect(server)
- if not self.bot.servers:
- sys.exit()
-
- def SIGUSR1(self, signum, frame):
- self.bot.trigger(self._reload_config)
-
- def SIGHUP(self, signum, frame):
- self.bot.trigger(self._SIGHUP)
- def _SIGHUP(self):
- self._reload_config()
- self._reload_modules()
-
- def _reload_config(self):
- self.bot.log.info("Reloading config file")
- self.bot.config.load()
- self.bot.log.info("Reloaded config file")
-
- def _reload_modules(self):
- self.bot.log.info("Reloading modules")
-
- result = self.bot.try_reload_modules()
- if result.success:
- self.bot.log.info(result.message)
- else:
- self.bot.log.warn(result.message)
diff --git a/modules/silence.py b/modules/silence.py
deleted file mode 100644
index 42990921..00000000
--- a/modules/silence.py
+++ /dev/null
@@ -1,70 +0,0 @@
-#--depends-on commands
-#--depends-on permissions
-
-import time
-from src import EventManager, ModuleManager, utils
-
-SILENCE_TIME = 60*5 # 5 minutes
-
-class Module(ModuleManager.BaseModule):
- def on_load(self):
- self.exports.add("is-silenced", self._is_silenced)
-
- def _is_silenced(self, target):
- silence_until = target.get_setting("silence-until", None)
- if not silence_until == None:
- if time.time()<silence_until:
- return True
- else:
- target.del_setting("silence-until")
- return False
-
- @utils.hook("received.command.silence")
- @utils.kwarg("channel_only", True)
- @utils.kwarg("help", "Prevent me saying anything for a period of time "
- "(default: 5 minutes)")
- @utils.kwarg("usage", "[+time]")
- @utils.kwarg("require_mode", "high")
- @utils.kwarg("require_access", "silence")
- @utils.kwarg("permission", "silence")
- def silence(self, event):
- duration = SILENCE_TIME
- if event["args"] and event["args_split"][0].startswith("+"):
- duration = utils.datetime.from_pretty_time(
- event["args_split"][0][1:])
- if duration == None:
- raise utils.EventError("Invalid duration provided")
-
- silence_until = time.time()+duration
- event["target"].set_setting("silence-until", silence_until)
- event["stdout"].write("Ok, I'll be back")
-
- @utils.hook("received.command.unsilence")
- @utils.kwarg("help", "Unsilence me")
- @utils.kwarg("unsilence", True)
- @utils.kwarg("channel_only", True)
- @utils.kwarg("require_mode", "high")
- @utils.kwarg("require_access", "unsilence")
- @utils.kwarg("permission", "unsilence")
- def unsiltence(self, event):
- silence_until = event["target"].get_setting("silence-until", None)
- if not silence_until == None:
- event["target"].del_setting("silence-until")
- event["stdout"].write("Ok. I've been unsilenced")
- else:
- event["stderr"].write("I am not silenced")
-
- @utils.hook("preprocess.command", priority=EventManager.PRIORITY_HIGH)
- def preprocess_command(self, event):
- if event["is_channel"] and not event["hook"].get_kwarg(
- "unsilence", False):
- silence_until = event["target"].get_setting("silence-until", None)
- if silence_until:
- if self._is_silenced(event["target"]):
- return utils.consts.PERMISSION_HARD_FAIL, None
-
- @utils.hook("unknown.command")
- @utils.kwarg("priority", EventManager.PRIORITY_HIGH)
- def unknown_command(self, event):
- if event["is_channel"] and self._is_silenced(event["target"]):
- event.eat()
diff --git a/modules/strip_color.py b/modules/strip_color.py
deleted file mode 100644
index 736d066e..00000000
--- a/modules/strip_color.py
+++ /dev/null
@@ -1,22 +0,0 @@
-#--depends-on config
-
-from src import ModuleManager, utils
-
-@utils.export("serverset", utils.BoolSetting("strip-color",
- "Set whether I strip colors from my messages on this server"))
-@utils.export("channelset", utils.BoolSetting("strip-color",
- "Set whether I strip colors from my messages on in this channel"))
-class Module(ModuleManager.BaseModule):
- @utils.hook("preprocess.send.privmsg")
- @utils.hook("preprocess.send.notice")
- def preprocess(self, event):
- if len(event["line"].args) > 1:
- strip_color = event["server"].get_setting("strip-color", False)
- target = event["line"].args[0]
- if not strip_color and target in event["server"].channels:
- channel = event["server"].channels.get(target)
- strip_color = channel.get_setting("strip-color", False)
-
- if strip_color:
- message = event["line"].args[1]
- event["line"].args[1] = utils.irc.strip_font(message)
diff --git a/modules/strip_otr.py b/modules/strip_otr.py
deleted file mode 100644
index bdb273a5..00000000
--- a/modules/strip_otr.py
+++ /dev/null
@@ -1,15 +0,0 @@
-from src import EventManager, ModuleManager, utils
-
-# Strip magic whitespace string from the end of messages.
-# OTR uses this string to advertise, over plaintext, that the sending user
-# supports OTR.
-
-MAGIC = " \t \t\t\t\t \t \t \t \t\t \t \t"
-
-class Module(ModuleManager.BaseModule):
- @utils.hook("raw.received.privmsg")
- @utils.kwarg("priority", EventManager.PRIORITY_HIGH)
- def on_message(self, event):
- message = event["line"].args.get(1)
- if message.endswith(MAGIC):
- event["line"].args[1] = message.rsplit(MAGIC, 1)[0]
diff --git a/modules/throttle.py b/modules/throttle.py
deleted file mode 100644
index e204cc34..00000000
--- a/modules/throttle.py
+++ /dev/null
@@ -1,17 +0,0 @@
-from src import ModuleManager, utils
-
-def _parse(value):
- lines, _, seconds = value.partition(":")
- if lines.isdigit() and seconds.isdigit():
- return [int(lines), int(seconds)]
- return None
-
-@utils.export("serverset", utils.FunctionSetting(_parse, "throttle",
- "Configure lines:seconds throttle for the current server", example="4:2"))
-class Module(ModuleManager.BaseModule):
- @utils.hook("received.001")
- def connect(self, event):
- throttle = event["server"].get_setting("throttle", None)
- if throttle:
- lines, seconds = throttle
- event["server"].socket.set_throttle(lines, seconds)