diff --git a/classes.py b/classes.py index 9170365..41d26b2 100644 --- a/classes.py +++ b/classes.py @@ -287,8 +287,10 @@ class Irc(): hook_func(self, numeric, command, parsed_args) except Exception: # We don't want plugins to crash our servers... - log.exception('(%s) Unhandled exception caught in %r', - self.name, hook_func) + log.exception('(%s) Unhandled exception caught in hook %r from plugin "%s"', + self.name, hook_func, hook_func.__module__) + log.error('(%s) The offending hook data was: %s', self.name, + hook_args) continue def send(self, data): @@ -488,6 +490,18 @@ class Protocol(): log.debug('Removing client %s from self.irc.servers[%s].users', numeric, sid) self.irc.servers[sid].users.discard(numeric) + def updateTS(self, channel, their_ts): + our_ts = self.irc.channels[channel].ts + if their_ts < our_ts: + # Channel timestamp was reset on burst + log.debug('(%s) Setting channel TS of %s to %s from %s', + self.irc.name, channel, their_ts, our_ts) + self.irc.channels[channel].ts = their_ts + # When TS is reset, clear all modes we currently have + self.irc.channels[channel].modes.clear() + for p in self.irc.channels[channel].prefixmodes.values(): + p.clear() + class FakeProto(Protocol): """Dummy protocol module for testing purposes.""" def handle_events(self, data): diff --git a/protocols/inspircd.py b/protocols/inspircd.py index 5a377d2..8bc0863 100644 --- a/protocols/inspircd.py +++ b/protocols/inspircd.py @@ -92,17 +92,10 @@ class InspIRCdProtocol(TS6BaseProtocol): log.debug('(%s) sjoinServer: got %r for users', self.irc.name, users) if not server: raise LookupError('No such PyLink PseudoClient exists.') + orig_ts = self.irc.channels[channel].ts - ts = ts or orig_ts - if ts < orig_ts: - # If the TS we're sending is lower than the one that existing, clear the - # mode lists from our channel state and reset the timestamp. - log.debug('(%s) sjoinServer: resetting TS of %r from %s to %s (clearing modes)', - self.irc.name, channel, orig_ts, ts) - self.irc.channels[channel].ts = ts - self.irc.channels[channel].modes.clear() - for p in self.irc.channels[channel].prefixmodes.values(): - p.clear() + self.updateTS(channel, ts or orig_ts) + log.debug("sending SJOIN to %s%s with ts %s (that's %r)", channel, self.irc.name, ts, time.strftime("%c", time.localtime(ts))) # Strip out list-modes, they shouldn't ever be sent in FJOIN (protocol rules). @@ -426,16 +419,11 @@ class InspIRCdProtocol(TS6BaseProtocol): channel = utils.toLower(self.irc, args[0]) # InspIRCd sends each channel's users in the form of 'modeprefix(es),UID' userlist = args[-1].split() - our_ts = self.irc.channels[channel].ts + their_ts = int(args[1]) - if their_ts < our_ts: - # Channel timestamp was reset on burst - log.debug('(%s) Setting channel TS of %s to %s from %s', - self.irc.name, channel, their_ts, our_ts) - self.irc.channels[channel].ts = their_ts - self.irc.channels[channel].modes.clear() - for p in self.irc.channels[channel].prefixmodes.values(): - p.clear() + our_ts = self.irc.channels[channel].ts + self.updateTS(channel, their_ts) + modestring = args[2:-1] or args[2] parsedmodes = utils.parseModes(self.irc, channel, modestring) utils.applyModes(self.irc, channel, parsedmodes) diff --git a/protocols/ts6.py b/protocols/ts6.py index 40fe271..a32bfbd 100644 --- a/protocols/ts6.py +++ b/protocols/ts6.py @@ -89,17 +89,10 @@ class TS6Protocol(TS6BaseProtocol): log.debug('(%s) sjoinServer: got %r for users', self.irc.name, users) if not server: raise LookupError('No such PyLink PseudoClient exists.') + orig_ts = self.irc.channels[channel].ts - ts = ts or orig_ts - if ts < orig_ts: - # If the TS we're sending is lower than the one that existing, clear the - # mode lists from our channel state and reset the timestamp. - log.debug('(%s) sjoinServer: resetting TS of %r from %s to %s (clearing modes)', - self.irc.name, channel, orig_ts, ts) - self.irc.channels[channel].ts = ts - self.irc.channels[channel].modes.clear() - for p in self.irc.channels[channel].prefixmodes.values(): - p.clear() + self.updateTS(channel, ts or orig_ts) + log.debug("(%s) sending SJOIN to %s with ts %s (that's %r)", self.irc.name, channel, ts, time.strftime("%c", time.localtime(ts))) modes = [m for m in self.irc.channels[channel].modes if m[0] not in self.irc.cmodes['*A']] @@ -497,16 +490,11 @@ class TS6Protocol(TS6BaseProtocol): # parameters: channelTS, channel, simple modes, opt. mode parameters..., nicklist channel = utils.toLower(self.irc, args[1]) userlist = args[-1].split() - our_ts = self.irc.channels[channel].ts their_ts = int(args[0]) - if their_ts < our_ts: - # Channel timestamp was reset on burst - log.debug('(%s) Setting channel TS of %s to %s from %s', - self.irc.name, channel, their_ts, our_ts) - self.irc.channels[channel].ts = their_ts - self.irc.channels[channel].modes.clear() - for p in self.irc.channels[channel].prefixmodes.values(): - p.clear() + our_ts = self.irc.channels[channel].ts + + self.updateTS(channel, their_ts) + modestring = args[2:-1] or args[2] parsedmodes = utils.parseModes(self.irc, channel, modestring) utils.applyModes(self.irc, channel, parsedmodes) @@ -548,14 +536,7 @@ class TS6Protocol(TS6BaseProtocol): return {'channels': oldchans, 'text': 'Left all channels.', 'parse_as': 'PART'} else: channel = utils.toLower(self.irc, args[1]) - our_ts = self.irc.channels[channel].ts - if ts < our_ts: - # Channel timestamp was reset on burst - log.debug('(%s) Setting channel TS of %s to %s from %s', - self.irc.name, channel, ts, our_ts) - self.irc.channels[channel].ts = ts - self.irc.channels[channel].users.add(numeric) - self.irc.users[numeric].channels.add(channel) + self.updateTS(channel, ts) # We send users and modes here because SJOIN and JOIN both use one hook, # for simplicity's sake (with plugins). return {'channel': channel, 'users': [numeric], 'modes':