3
0
mirror of https://github.com/jlu5/PyLink.git synced 2024-11-01 09:19:23 +01:00

nefarious: implement outgoing SJOIN (via BURST)

This commit is contained in:
James Lu 2016-04-16 17:49:59 -07:00
parent 25ca2f8399
commit 1892dd5fb4

View File

@ -365,6 +365,90 @@ class P10Protocol(Protocol):
else: else:
raise LookupError("No such PyLink client exists.") raise LookupError("No such PyLink client exists.")
def sjoin(self, server, channel, users, ts=None):
"""Sends an SJOIN for a group of users to a channel.
The sender should always be a Server ID (SID). TS is optional, and defaults
to the one we've stored in the channel state if not given.
<users> is a list of (prefix mode, UID) pairs:
Example uses:
sjoin('100', '#test', [('', '100AAABBC'), ('o', 100AAABBB'), ('v', '100AAADDD')])
sjoin(self.irc.sid, '#test', [('o', self.irc.pseudoclient.uid)])
"""
# <- AB B #test 1460742014 +tnl 10 ABAAB,ABAAA:o :%*!*@other.bad.host ~ *!*@bad.host
channel = utils.toLower(self.irc, channel)
server = server or self.irc.sid
assert users, "sjoin: No users sent?"
log.debug('(%s) sjoin: got %r for users', self.irc.name, users)
if not server:
raise LookupError('No such PyLink client exists.')
orig_ts = self.irc.channels[channel].ts
ts = ts or orig_ts
self.updateTS(channel, ts)
# Only send non-list modes in BURST. TODO: burst bans and banexempts too
modes = [m for m in self.irc.channels[channel].modes if m[0] not in self.irc.cmodes['*A']]
changedmodes = []
changedusers = []
namelist = []
# This is annoying because we have to sort our users by access before sending...
# Joins should look like: A0AAB,A0AAC,ABAAA:v,ABAAB:o,ABAAD,ACAAA:ov
# XXX: there HAS to be a better way of doing this
def access_sort(key):
prefixes, user = key
# This is some hocus pocus. Add the prefixes given for each userpair,
# giving each one a set value. This ensures that 'ohv' > 'oh' > 'ov' > 'o' > 'hv' > 'h' > 'v' > ''
accesses = {'o': 100, 'h': 10, 'v': 1}
num = 0
for prefix in prefixes:
num += accesses.get(prefix, 0)
return num
users = sorted(users, key=access_sort)
for userpair in users:
# We take <users> as a list of (prefixmodes, uid) pairs.
assert len(userpair) == 2, "Incorrect format of userpair: %r" % userpair
prefixes, user = userpair
# Keep track of all the users and modes that are added. namelist is used
# to track what we actually send to the IRCd.
changedusers.append(user)
log.debug('(%s) sjoin: adding %s:%s to namelist', self.irc.name, user, prefixes)
if prefixes:
namelist.append('%s:%s' % (user, prefixes))
else:
namelist.append(user)
if prefixes:
for prefix in prefixes:
changedmodes.append(('+%s' % prefix, user))
self.irc.users[user].channels.add(channel)
namelist = ','.join(namelist)
log.debug('(%s) sjoin: got %r for namelist', self.irc.name, namelist)
if modes: # Only send modes if there are any.
self._send(server, "B {channel} {ts} {modes} :{users}".format(
ts=ts, users=namelist, channel=channel,
modes=utils.joinModes(modes)))
else:
self._send(server, "B {channel} {ts} :{users}".format(
ts=ts, users=namelist, channel=channel))
self.irc.channels[channel].users.update(changedusers)
if ts <= orig_ts:
# Only save our prefix modes in the channel state if our TS is lower than or equal to theirs.
utils.applyModes(self.irc, channel, changedmodes)
### HANDLERS ### HANDLERS
def connect(self): def connect(self):