diff --git a/src/channels.py b/src/channels.py index 076bc00..a25db5f 100644 --- a/src/channels.py +++ b/src/channels.py @@ -67,6 +67,7 @@ class Channel(IRCContext): self.modes = {} self.timestamp = None self.state = _States.NotJoined + self._pending = [] def __del__(self): self.users.clear() @@ -81,6 +82,12 @@ class Channel(IRCContext): def __repr__(self): return "{self.__class__.__name__}({self.name!r})".format(self=self) + def queue(self, name, params, args): + if self._pending is None: + Event(name, params).dispatch(*args) + else: + self._pending.append((name, params, args)) + def join(self, key=""): if self.state in (_States.NotJoined, _States.Left): self.state = _States.PendingJoin @@ -151,7 +158,7 @@ class Channel(IRCContext): self.client.send("MODE", self.name, "".join(final)) - def update_modes(self, rawnick, mode, targets): + def update_modes(self, actor, mode, targets): """Update the channel's mode registry with the new modes. This is called whenever a MODE event is received. All of the @@ -184,7 +191,7 @@ class Channel(IRCContext): elif c in list_modes: # stuff like bans, quiets, and ban and invite exempts if c not in self.modes: self.modes[c] = {} - self.modes[c][targets[i]] = (rawnick, set_time) + self.modes[c][targets[i]] = (actor.rawnick, set_time) i += 1 else: diff --git a/src/hooks.py b/src/hooks.py index 0adc8d2..3a72a2a 100644 --- a/src/hooks.py +++ b/src/hooks.py @@ -6,7 +6,7 @@ further in the relevant hook functions. """ -from src.decorators import hook +from src.decorators import event_listener, hook from src.context import Features from src.events import Event from src.logger import plog @@ -144,6 +144,16 @@ def end_who(cli, bot_server, bot_nick, target, rest): """ + try: + chan = channels.get(target) + except KeyError: + pass + else: + if chan._pending is not None: + for name, params, args in chan._pending: + Event(name, params).dispatch(*args) + chan._pending = None + Event("who_end", {}).dispatch(var, target) ### Server PING handling @@ -278,9 +288,13 @@ def mode_change(cli, rawnick, chan, mode, *targets): return target = channels.add(chan, cli) - target.update_modes(rawnick, mode, targets) + target.queue("mode_change", {"mode": mode, "targets": targets}, (var, actor, target)) - Event("mode_change", {}).dispatch(var, actor, target) +@event_listener("mode_change", 0) # This should fire before anything else! +def apply_mode_changes(evt, var, actor, target): + """Apply all mode changes before any other event.""" + + target.update_modes(actor, evt.data.pop("mode"), evt.data.pop("targets")) ### List modes handling (bans, quiets, ban and invite exempts) @@ -369,7 +383,7 @@ def handle_endlistmode(cli, chan, mode): """Handle the end of a list mode listing.""" ch = channels.add(chan, cli) - Event("end_listmode", {}).dispatch(var, ch, mode) + ch.queue("end_listmode", {}, (var, ch, mode)) @hook("endofbanlist") def end_banlist(cli, server, bot_nick, chan, message):