# -*- coding: utf-8 -*- # # Copyright (C) 2021 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. import base64 import cPickle as pickle import re from earwigbot.commands import Command from earwigbot.config.permissions import User class PartWhen(Command): """Ask the bot to part the channel when a condition is met.""" name = "partwhen" commands = ["partwhen", "unpartwhen"] hooks = ["join", "msg"] def setup(self): self._conds = self._load_conditions() def check(self, data): if data.is_command and data.command in self.commands: return True try: if data.line[1] == "JOIN": if data.chan in self._conds and "join" in self._conds[data.chan]: return True except IndexError: pass return False def process(self, data): if data.line[1] == "JOIN": self._handle_join(data) return if not self.config.irc["permissions"].is_admin(data): self.reply(data, "You must be a bot admin to use this command.") return channel = data.chan args = data.args if args and args[0].startswith("#"): # "!partwhen #channel ..." channel = args[0] args = args[1:] if data.command == "unpartwhen": if self._conds.get(channel): del self._conds[channel] self._save_conditions() self.reply(data, "Cleared part conditions for {0}.".format( "this channel" if channel == data.chan else channel)) else: self.reply(data, "No part conditions set.") return if not args: conds = self._conds.get(channel, {}) existing = "; ".join("{0} {1}".format(cond, ", ".join(str(user) for user in users)) for cond, users in conds.iteritems()) if existing: status = "Current part conditions: {0}.".format(existing) else: status = "No part conditions set for {0}.".format( "this channel" if channel == data.chan else channel) self.reply(data, "{0} Usage: !{1} [] ...".format( status, data.command)) return event = args[0] args = args[1:] if event == "join": if not args: self.reply(data, "Join event requires an argument for the user joining, " "in nick!ident@host syntax.") return cond = args[0] match = re.match(r"(.*?)!(.*?)@(.*?)$", cond) if not match: self.reply(data, "User join pattern is invalid; should use " "nick!ident@host syntax.") return conds = self._conds.setdefault(channel, {}).setdefault("join", []) conds.append(User(match.group(1), match.group(2), match.group(3))) self._save_conditions() self.reply(data, "Okay, I will leave {0} when {1} joins.".format( "the channel" if channel == data.chan else channel, cond)) else: self.reply(data, "Unknown event: {0} (valid events: join).".format(event)) def _handle_join(self, data): user = User(data.nick, data.ident, data.host) conds = self._conds.get(data.chan, {}).get("join", {}) for cond in conds: if user in cond: self.logger.info("Parting {0} because {1} met join condition {2}".format( data.chan, str(user), str(cond))) self.part(data.chan, "Requested to leave when {0} joined".format(data.nick)) break def _load_conditions(self): permdb = self.config.irc["permissions"] try: raw = permdb.get_attr("command:partwhen", "data") except KeyError: return {} return pickle.loads(base64.b64decode(raw)) def _save_conditions(self): permdb = self.config.irc["permissions"] raw = base64.b64encode(pickle.dumps(self._conds, pickle.HIGHEST_PROTOCOL)) permdb.set_attr("command:partwhen", "data", raw)