3
0
mirror of https://github.com/jlu5/PyLink.git synced 2024-11-30 14:49:28 +01:00

unreal: add joinClient + sjoinServer, support +qaohv properly

This commit is contained in:
James Lu 2015-10-12 19:38:38 -07:00
parent f0ff14fda9
commit dbe24973d5

View File

@ -23,6 +23,7 @@ class UnrealProtocol(TS6BaseProtocol):
self.uidgen = {} self.uidgen = {}
self.caps = {} self.caps = {}
self.irc.prefixmodes = {'q': '~', 'a': '&', 'o': '@', 'h': '%', 'v': '+'}
self._unrealCmodes = {'l': 'limit', 'c': 'blockcolor', 'G': 'censor', self._unrealCmodes = {'l': 'limit', 'c': 'blockcolor', 'G': 'censor',
'D': 'delayjoin', 'n': 'noextmsg', 's': 'secret', 'D': 'delayjoin', 'n': 'noextmsg', 's': 'secret',
'T': 'nonotice', 'z': 'sslonly', 'b': 'ban', 'V': 'noinvite', 'T': 'nonotice', 'z': 'sslonly', 'b': 'ban', 'V': 'noinvite',
@ -65,7 +66,75 @@ class UnrealProtocol(TS6BaseProtocol):
return u return u
def joinClient(self, client, channel): def joinClient(self, client, channel):
pass """Joins a PyLink client to a channel."""
channel = utils.toLower(self.irc, channel)
if not utils.isInternalClient(self.irc, client):
raise LookupError('No such PyLink client exists.')
self._send(client, "JOIN %s" % channel)
self.irc.channels[channel].users.add(client)
self.irc.users[client].channels.add(channel)
def sjoinServer(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:
sjoinServer('100', '#test', [('', '100AAABBC'), ('o', 100AAABBB'), ('v', '100AAADDD')])
sjoinServer(self.irc.sid, '#test', [('o', self.irc.pseudoclient.uid)])
Note that for UnrealIRCd, no mode data is sent in an SJOIN command, only
The channel name, TS, and user list.
"""
# <- :001 SJOIN 1444361345 #endlessvoid :001DJ1O02
# The nicklist consists of users joining the channel, with status prefixes for
# their status ('@+', '@', '+' or ''), for example:
# '@+1JJAAAAAB +2JJAAAA4C 1JJAAAADS'.
channel = utils.toLower(self.irc, channel)
server = server or self.irc.sid
assert users, "sjoinServer: No users sent?"
if not server:
raise LookupError('No such PyLink server 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()
changedmodes = []
uids = []
namelist = []
for userpair in users:
assert len(userpair) == 2, "Incorrect format of userpair: %r" % userpair
prefixes, user = userpair
# Unreal uses slightly different prefixes in SJOIN. +q is * instead of ~,
# and +a is ~ instead of &.
# &, ", and ' are used for bursting bans.
sjoin_prefixes = {'q': '*', 'a': '~', 'o': '@', 'h': '%', 'v': '+'}
prefixchars = ''.join([sjoin_prefixes.get(prefix, '') for prefix in prefixes])
if prefixchars:
changedmodes + [('+%s' % prefix, user) for prefix in prefixes]
namelist.append(prefixchars+user)
uids.append(user)
try:
self.irc.users[user].channels.add(channel)
except KeyError: # Not initialized yet?
log.debug("(%s) sjoinServer: KeyError trying to add %r to %r's channel list?", self.irc.name, channel, user)
namelist = ' '.join(namelist)
self._send(server, "SJOIN {ts} {channel} :{users}".format(
ts=ts, users=namelist, channel=channel))
self.irc.channels[channel].users.update(uids)
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)
def pingServer(self, source=None, target=None): def pingServer(self, source=None, target=None):
"""Sends a PING to a target server. Periodic PINGs are sent to our uplink """Sends a PING to a target server. Periodic PINGs are sent to our uplink
@ -223,12 +292,14 @@ class UnrealProtocol(TS6BaseProtocol):
self.caps['NOQUIT'] = True self.caps['NOQUIT'] = True
elif cap == 'SJ3': elif cap == 'SJ3':
self.caps['SJ3'] = True self.caps['SJ3'] = True
self.irc.cmodes.update({'halfop': 'h', 'admin': 'a', 'owner': 'q',
'op': 'o', 'voice': 'v'})
def _getNick(self, target): def _getNick(self, target):
"""Converts a nick argument to its matching UID. This differs from utils.nickToUid() """Converts a nick argument to its matching UID. This differs from utils.nickToUid()
in that it returns the original text instead of None, if no matching nick is found.""" in that it returns the original text instead of None, if no matching nick is found."""
target = utils.nickToUid(self.irc, target) or target target = utils.nickToUid(self.irc, target) or target
if target not in self.irc.users: if target not in self.irc.users and not utils.isChannel(target):
log.warning("(%s) Possible desync? Got command target %s, who " log.warning("(%s) Possible desync? Got command target %s, who "
"isn't in our user list!", self.irc.name, target) "isn't in our user list!", self.irc.name, target)
return target return target
@ -324,9 +395,15 @@ class UnrealProtocol(TS6BaseProtocol):
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)
for userpair in userlist: for userpair in userlist:
if userpair.startswith("&\"'"): # TODO: handle ban bursts too
# &, ", and ' entries are used for bursting bans:
# https://www.unrealircd.org/files/docs/technical/serverprotocol.html#S5_1
break
r = re.search(r'([^\d]*)(.*)', userpair) r = re.search(r'([^\d]*)(.*)', userpair)
user = r.group(2) user = r.group(2)
modeprefix = r.group(1) or '' # Unreal uses slightly different prefixes in SJOIN. +q is * instead of ~,
# and +a is ~ instead of &.
modeprefix = (r.group(1) or '').replace("~", "&").replace("*", "~")
finalprefix = '' finalprefix = ''
assert user, 'Failed to get the UID from %r; our regex needs updating?' % userpair assert user, 'Failed to get the UID from %r; our regex needs updating?' % userpair
log.debug('(%s) handle_sjoin: got modeprefix %r for user %r', self.irc.name, modeprefix, user) log.debug('(%s) handle_sjoin: got modeprefix %r for user %r', self.irc.name, modeprefix, user)