3
0
mirror of https://github.com/jlu5/PyLink.git synced 2025-01-11 20:52:42 +01:00

core: make inbound SJOINs also respect the updateTS() rules

This commit is contained in:
James Lu 2016-06-22 22:26:25 -07:00
parent 90ee20ee8b
commit f2b139c828
5 changed files with 77 additions and 42 deletions

View File

@ -497,10 +497,6 @@ class Irc():
else: else:
log.debug('(%s) Using self.cmodes for this query: %s', self.name, self.cmodes) log.debug('(%s) Using self.cmodes for this query: %s', self.name, self.cmodes)
if target not in self.channels:
log.warning('(%s) Possible desync! Mode target %s is not in the channels index.', self.name, target)
return []
supported_modes = self.cmodes supported_modes = self.cmodes
oldmodes = self.channels[target].modes oldmodes = self.channels[target].modes
res = [] res = []
@ -1067,17 +1063,12 @@ class Protocol():
log.debug('Removing client %s from self.irc.servers[%s].users', numeric, sid) log.debug('Removing client %s from self.irc.servers[%s].users', numeric, sid)
self.irc.servers[sid].users.discard(numeric) self.irc.servers[sid].users.discard(numeric)
def updateTS(self, channel, their_ts, modes=[]): def updateTS(self, channel, their_ts, modes=[], outbound=True):
""" """
Merges modes of a channel given the remote TS and a list of modes. Merges modes of a channel given the remote TS and a list of modes.
This returns True when our modes apply (our TS <= theirs)
""" """
our_ts = self.irc.channels[channel].ts def _clear():
if their_ts < our_ts:
# Their TS is older than ours. Clear all modes.
log.debug('(%s) Setting channel TS of %s to %s from %s', log.debug('(%s) Setting channel TS of %s to %s from %s',
self.irc.name, channel, their_ts, our_ts) self.irc.name, channel, their_ts, our_ts)
self.irc.channels[channel].ts = their_ts self.irc.channels[channel].ts = their_ts
@ -1086,17 +1077,36 @@ class Protocol():
for p in self.irc.channels[channel].prefixmodes.values(): for p in self.irc.channels[channel].prefixmodes.values():
p.clear() p.clear()
return False def _apply():
self.irc.applyModes(channel, modes)
our_ts = self.irc.channels[channel].ts
if their_ts < our_ts:
# Their TS is older than ours. If we're receiving a mode change, we should
# clear our stored modes for the channel and apply theirs. Otherwise, if we're
# the one setting modes, just drop them.
log.debug("(%s/%s) remote TS of %s is lower than ours %s; outbound mode: %s; setting modes %s",
self.irc.name, channel, their_ts, our_ts, outbound, modes)
if not outbound:
_clear()
_apply()
elif their_ts == our_ts: elif their_ts == our_ts:
log.debug("(%s/%s) remote TS of %s is equal to ours %s; outbound mode: %s; setting modes %s",
self.irc.name, channel, their_ts, our_ts, outbound, modes)
# Their TS is equal to ours. Merge modes. # Their TS is equal to ours. Merge modes.
self.irc.applyModes(channel, modes) _apply()
return True
elif their_ts > our_ts: elif their_ts > our_ts:
# Their TS is younger than ours. Replace their modes with ours. log.debug("(%s/%s) remote TS of %s is higher than ours %s; outbound mode: %s; setting modes %s",
self.irc.channels[channel].modes.clear() self.irc.name, channel, their_ts, our_ts, outbound, modes)
self.irc.applyModes(channel, modes) # Their TS is younger than ours. If we're setting modes, clear the state
return True # and replace the modes for the channel with ours. Otherwise, just ignore the
# remote's changes.
if outbound:
_clear()
_apply()
def _getSid(self, sname): def _getSid(self, sname):
"""Returns the SID of a server with the given name, if present.""" """Returns the SID of a server with the given name, if present."""

View File

@ -498,14 +498,14 @@ class InspIRCdProtocol(TS6BaseProtocol):
# InspIRCd sends each channel's users in the form of 'modeprefix(es),UID' # InspIRCd sends each channel's users in the form of 'modeprefix(es),UID'
userlist = args[-1].split() userlist = args[-1].split()
their_ts = int(args[1])
our_ts = self.irc.channels[channel].ts
self.updateTS(channel, their_ts)
modestring = args[2:-1] or args[2] modestring = args[2:-1] or args[2]
parsedmodes = self.irc.parseModes(channel, modestring) parsedmodes = self.irc.parseModes(channel, modestring)
self.irc.applyModes(channel, parsedmodes) self.irc.applyModes(channel, parsedmodes)
namelist = [] namelist = []
# Keep track of other modes that are added due to prefix modes being joined too.
changedmodes = set(parsedmodes)
for user in userlist: for user in userlist:
modeprefix, user = user.split(',', 1) modeprefix, user = user.split(',', 1)
@ -517,9 +517,17 @@ class InspIRCdProtocol(TS6BaseProtocol):
namelist.append(user) namelist.append(user)
self.irc.users[user].channels.add(channel) self.irc.users[user].channels.add(channel)
if their_ts <= our_ts:
self.irc.applyModes(channel, [('+%s' % mode, user) for mode in modeprefix]) # Only save mode changes if the remote has lower TS than us.
changedmodes |= {('+%s' % mode, user) for mode in modeprefix}
self.irc.channels[channel].users.add(user) self.irc.channels[channel].users.add(user)
# Statekeeping with timestamps
their_ts = int(args[1])
our_ts = self.irc.channels[channel].ts
self.updateTS(channel, their_ts, changedmodes, outbound=False)
return {'channel': channel, 'users': namelist, 'modes': parsedmodes, 'ts': their_ts} return {'channel': channel, 'users': namelist, 'modes': parsedmodes, 'ts': their_ts}
def handle_uid(self, numeric, command, args): def handle_uid(self, numeric, command, args):

View File

@ -938,10 +938,6 @@ class P10Protocol(Protocol):
channel = self.irc.toLower(args[0]) channel = self.irc.toLower(args[0])
userlist = args[-1].split() userlist = args[-1].split()
their_ts = int(args[1])
our_ts = self.irc.channels[channel].ts
self.updateTS(channel, their_ts)
bans = [] bans = []
if args[-1].startswith('%'): if args[-1].startswith('%'):
@ -972,6 +968,9 @@ class P10Protocol(Protocol):
else: else:
parsedmodes = [] parsedmodes = []
# Keep track of other modes that are added due to prefix modes being joined too.
changedmodes = set(parsedmodes)
# Add the ban list to the list of modes to process. # Add the ban list to the list of modes to process.
parsedmodes.extend(bans) parsedmodes.extend(bans)
@ -1006,11 +1005,16 @@ class P10Protocol(Protocol):
self.irc.users[user].channels.add(channel) self.irc.users[user].channels.add(channel)
if their_ts <= our_ts: # Only save mode changes if the remote has lower TS than us.
self.irc.applyModes(channel, [('+%s' % mode, user) for mode in prefixes]) changedmodes |= {('+%s' % mode, user) for mode in prefixes}
self.irc.channels[channel].users.add(user) self.irc.channels[channel].users.add(user)
# Statekeeping with timestamps
their_ts = int(args[1])
our_ts = self.irc.channels[channel].ts
self.updateTS(channel, their_ts, changedmodes, outbound=False)
return {'channel': channel, 'users': namelist, 'modes': parsedmodes, 'ts': their_ts} return {'channel': channel, 'users': namelist, 'modes': parsedmodes, 'ts': their_ts}
def handle_join(self, source, command, args): def handle_join(self, source, command, args):

View File

@ -436,15 +436,15 @@ class TS6Protocol(TS6BaseProtocol):
# <- :0UY SJOIN 1451041566 #channel +nt :@0UYAAAAAB # <- :0UY SJOIN 1451041566 #channel +nt :@0UYAAAAAB
channel = self.irc.toLower(args[1]) channel = self.irc.toLower(args[1])
userlist = args[-1].split() userlist = args[-1].split()
their_ts = int(args[0])
our_ts = self.irc.channels[channel].ts
self.updateTS(channel, their_ts)
modestring = args[2:-1] or args[2] modestring = args[2:-1] or args[2]
parsedmodes = self.irc.parseModes(channel, modestring) parsedmodes = self.irc.parseModes(channel, modestring)
self.irc.applyModes(channel, parsedmodes) self.irc.applyModes(channel, parsedmodes)
namelist = [] namelist = []
# Keep track of other modes that are added due to prefix modes being joined too.
changedmodes = set(parsedmodes)
log.debug('(%s) handle_sjoin: got userlist %r for %r', self.irc.name, userlist, channel) log.debug('(%s) handle_sjoin: got userlist %r for %r', self.irc.name, userlist, channel)
for userpair in userlist: for userpair in userlist:
# charybdis sends this in the form "@+UID1, +UID2, UID3, @UID4" # charybdis sends this in the form "@+UID1, +UID2, UID3, @UID4"
@ -469,9 +469,16 @@ class TS6Protocol(TS6BaseProtocol):
finalprefix += char finalprefix += char
namelist.append(user) namelist.append(user)
self.irc.users[user].channels.add(channel) self.irc.users[user].channels.add(channel)
if their_ts <= our_ts:
self.irc.applyModes(channel, [('+%s' % mode, user) for mode in finalprefix]) # Only save mode changes if the remote has lower TS than us.
changedmodes |= {('+%s' % mode, user) for mode in finalprefix}
self.irc.channels[channel].users.add(user) self.irc.channels[channel].users.add(user)
# Statekeeping with timestamps
their_ts = int(args[0])
our_ts = self.irc.channels[channel].ts
self.updateTS(channel, their_ts, changedmodes, outbound=False)
return {'channel': channel, 'users': namelist, 'modes': parsedmodes, 'ts': their_ts} return {'channel': channel, 'users': namelist, 'modes': parsedmodes, 'ts': their_ts}
def handle_join(self, numeric, command, args): def handle_join(self, numeric, command, args):

View File

@ -556,12 +556,12 @@ class UnrealProtocol(TS6BaseProtocol):
channel = self.irc.toLower(args[1]) channel = self.irc.toLower(args[1])
userlist = args[-1].split() userlist = args[-1].split()
our_ts = self.irc.channels[channel].ts
their_ts = int(args[0])
self.updateTS(channel, their_ts)
namelist = [] namelist = []
log.debug('(%s) handle_sjoin: got userlist %r for %r', self.irc.name, userlist, channel) log.debug('(%s) handle_sjoin: got userlist %r for %r', self.irc.name, userlist, channel)
# Keep track of other modes that are added due to prefix modes being joined too.
changedmodes = set(self.irc.channels[channel].modes)
for userpair in userlist: for userpair in userlist:
if userpair.startswith("&\"'"): # TODO: handle ban bursts too if userpair.startswith("&\"'"): # TODO: handle ban bursts too
# &, ", and ' entries are used for bursting bans: # &, ", and ' entries are used for bursting bans:
@ -583,10 +583,16 @@ class UnrealProtocol(TS6BaseProtocol):
finalprefix += char finalprefix += char
namelist.append(user) namelist.append(user)
self.irc.users[user].channels.add(channel) self.irc.users[user].channels.add(channel)
# Only merge the remote's prefix modes if their TS is smaller or equal to ours. # Only merge the remote's prefix modes if their TS is smaller or equal to ours.
if their_ts <= our_ts: changedmodes |= {('+%s' % mode, user) for mode in finalprefix}
self.irc.applyModes(channel, [('+%s' % mode, user) for mode in finalprefix])
self.irc.channels[channel].users.add(user) self.irc.channels[channel].users.add(user)
our_ts = self.irc.channels[channel].ts
their_ts = int(args[0])
self.updateTS(channel, their_ts, changedmodes, outbound=False)
return {'channel': channel, 'users': namelist, 'modes': self.irc.channels[channel].modes, 'ts': their_ts} return {'channel': channel, 'users': namelist, 'modes': self.irc.channels[channel].modes, 'ts': their_ts}
def handle_nick(self, numeric, command, args): def handle_nick(self, numeric, command, args):