From 638eee0d685c06d258cb55287204ca97bca7c344 Mon Sep 17 00:00:00 2001 From: jesopo Date: Tue, 10 Dec 2019 05:27:35 +0000 Subject: move core modules to src/core_modules, make them uneffected by white/black list --- src/core_modules/line_handler/__init__.py | 260 ++++++++++++++++++++++++++++++ src/core_modules/line_handler/channel.py | 160 ++++++++++++++++++ src/core_modules/line_handler/core.py | 154 ++++++++++++++++++ src/core_modules/line_handler/ircv3.py | 138 ++++++++++++++++ src/core_modules/line_handler/message.py | 109 +++++++++++++ src/core_modules/line_handler/user.py | 102 ++++++++++++ 6 files changed, 923 insertions(+) create mode 100644 src/core_modules/line_handler/__init__.py create mode 100644 src/core_modules/line_handler/channel.py create mode 100644 src/core_modules/line_handler/core.py create mode 100644 src/core_modules/line_handler/ircv3.py create mode 100644 src/core_modules/line_handler/message.py create mode 100644 src/core_modules/line_handler/user.py (limited to 'src/core_modules/line_handler') diff --git a/src/core_modules/line_handler/__init__.py b/src/core_modules/line_handler/__init__.py new file mode 100644 index 00000000..ddea6fdc --- /dev/null +++ b/src/core_modules/line_handler/__init__.py @@ -0,0 +1,260 @@ +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/src/core_modules/line_handler/channel.py b/src/core_modules/line_handler/channel.py new file mode 100644 index 00000000..91150839 --- /dev/null +++ b/src/core_modules/line_handler/channel.py @@ -0,0 +1,160 @@ +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/src/core_modules/line_handler/core.py b/src/core_modules/line_handler/core.py new file mode 100644 index 00000000..d72bf223 --- /dev/null +++ b/src/core_modules/line_handler/core.py @@ -0,0 +1,154 @@ +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/src/core_modules/line_handler/ircv3.py b/src/core_modules/line_handler/ircv3.py new file mode 100644 index 00000000..a9d740ed --- /dev/null +++ b/src/core_modules/line_handler/ircv3.py @@ -0,0 +1,138 @@ +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/src/core_modules/line_handler/message.py b/src/core_modules/line_handler/message.py new file mode 100644 index 00000000..fa36dbc2 --- /dev/null +++ b/src/core_modules/line_handler/message.py @@ -0,0 +1,109 @@ +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/src/core_modules/line_handler/user.py b/src/core_modules/line_handler/user.py new file mode 100644 index 00000000..d1592cd7 --- /dev/null +++ b/src/core_modules/line_handler/user.py @@ -0,0 +1,102 @@ +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"]) -- cgit v1.3.1-10-gc9f91