mirror of
https://github.com/jlu5/PyLink.git
synced 2024-11-01 01:09:22 +01:00
core: move reverseModes, joinModes into Irc
This commit is contained in:
parent
05752d9f60
commit
064cb9b6aa
128
classes.py
128
classes.py
@ -653,6 +653,134 @@ class Irc():
|
||||
else:
|
||||
self.channels[target].modes = modelist
|
||||
|
||||
@staticmethod
|
||||
def _flip(mode):
|
||||
"""Flips a mode character."""
|
||||
# Make it a list first, strings don't support item assignment
|
||||
mode = list(mode)
|
||||
if mode[0] == '-': # Query is something like "-n"
|
||||
mode[0] = '+' # Change it to "+n"
|
||||
elif mode[0] == '+':
|
||||
mode[0] = '-'
|
||||
else: # No prefix given, assume +
|
||||
mode.insert(0, '-')
|
||||
return ''.join(mode)
|
||||
|
||||
def reverseModes(self, target, modes, oldobj=None):
|
||||
"""Reverses/Inverts the mode string or mode list given.
|
||||
|
||||
Optionally, an oldobj argument can be given to look at an earlier state of
|
||||
a channel/user object, e.g. for checking the op status of a mode setter
|
||||
before their modes are processed and added to the channel state.
|
||||
|
||||
This function allows both mode strings or mode lists. Example uses:
|
||||
"+mi-lk test => "-mi+lk test"
|
||||
"mi-k test => "-mi+k test"
|
||||
[('+m', None), ('+r', None), ('+l', '3'), ('-o', 'person')
|
||||
=> {('-m', None), ('-r', None), ('-l', None), ('+o', 'person')})
|
||||
{('s', None), ('+o', 'whoever') => {('-s', None), ('-o', 'whoever')})
|
||||
"""
|
||||
origtype = type(modes)
|
||||
# If the query is a string, we have to parse it first.
|
||||
if origtype == str:
|
||||
modes = self.parseModes(target, modes.split(" "))
|
||||
# Get the current mode list first.
|
||||
if utils.isChannel(target):
|
||||
c = oldobj or self.channels[target]
|
||||
oldmodes = c.modes.copy()
|
||||
possible_modes = self.cmodes.copy()
|
||||
# For channels, this also includes the list of prefix modes.
|
||||
possible_modes['*A'] += ''.join(self.prefixmodes)
|
||||
for name, userlist in c.prefixmodes.items():
|
||||
try:
|
||||
oldmodes.update([(self.cmodes[name], u) for u in userlist])
|
||||
except KeyError:
|
||||
continue
|
||||
else:
|
||||
oldmodes = self.users[target].modes
|
||||
possible_modes = self.umodes
|
||||
newmodes = []
|
||||
log.debug('(%s) reverseModes: old/current mode list for %s is: %s', self.name,
|
||||
target, oldmodes)
|
||||
for char, arg in modes:
|
||||
# Mode types:
|
||||
# A = Mode that adds or removes a nick or address to a list. Always has a parameter.
|
||||
# B = Mode that changes a setting and always has a parameter.
|
||||
# C = Mode that changes a setting and only has a parameter when set.
|
||||
# D = Mode that changes a setting and never has a parameter.
|
||||
mchar = char[-1]
|
||||
if mchar in possible_modes['*B'] + possible_modes['*C']:
|
||||
# We need to find the current mode list, so we can reset arguments
|
||||
# for modes that have arguments. For example, setting +l 30 on a channel
|
||||
# that had +l 50 set should give "+l 30", not "-l".
|
||||
oldarg = [m for m in oldmodes if m[0] == mchar]
|
||||
if oldarg: # Old mode argument for this mode existed, use that.
|
||||
oldarg = oldarg[0]
|
||||
mpair = ('+%s' % oldarg[0], oldarg[1])
|
||||
else: # Not found, flip the mode then.
|
||||
# Mode takes no arguments when unsetting.
|
||||
if mchar in possible_modes['*C'] and char[0] != '-':
|
||||
arg = None
|
||||
mpair = (self._flip(char), arg)
|
||||
else:
|
||||
mpair = (self._flip(char), arg)
|
||||
if char[0] != '-' and (mchar, arg) in oldmodes:
|
||||
# Mode is already set.
|
||||
log.debug("(%s) reverseModes: skipping reversing '%s %s' with %s since we're "
|
||||
"setting a mode that's already set.", self.name, char, arg, mpair)
|
||||
continue
|
||||
elif char[0] == '-' and (mchar, arg) not in oldmodes and mchar in possible_modes['*A']:
|
||||
# We're unsetting a prefixmode that was never set - don't set it in response!
|
||||
# Charybdis lacks verification for this server-side.
|
||||
log.debug("(%s) reverseModes: skipping reversing '%s %s' with %s since it "
|
||||
"wasn't previously set.", self.name, char, arg, mpair)
|
||||
continue
|
||||
newmodes.append(mpair)
|
||||
|
||||
log.debug('(%s) reverseModes: new modes: %s', self.name, newmodes)
|
||||
if origtype == str:
|
||||
# If the original query is a string, send it back as a string.
|
||||
return self.joinModes(newmodes)
|
||||
else:
|
||||
return set(newmodes)
|
||||
|
||||
@staticmethod
|
||||
def joinModes(modes):
|
||||
"""Takes a list of (mode, arg) tuples in parseModes() format, and
|
||||
joins them into a string.
|
||||
|
||||
See testJoinModes in tests/test_utils.py for some examples."""
|
||||
prefix = '+' # Assume we're adding modes unless told otherwise
|
||||
modelist = ''
|
||||
args = []
|
||||
for modepair in modes:
|
||||
mode, arg = modepair
|
||||
assert len(mode) in (1, 2), "Incorrect length of a mode (received %r)" % mode
|
||||
try:
|
||||
# If the mode has a prefix, use that.
|
||||
curr_prefix, mode = mode
|
||||
except ValueError:
|
||||
# If not, the current prefix stays the same; move on to the next
|
||||
# modepair.
|
||||
pass
|
||||
else:
|
||||
# If the prefix of this mode isn't the same as the last one, add
|
||||
# the prefix to the modestring. This prevents '+nt-lk' from turning
|
||||
# into '+n+t-l-k' or '+ntlk'.
|
||||
if prefix != curr_prefix:
|
||||
modelist += curr_prefix
|
||||
prefix = curr_prefix
|
||||
modelist += mode
|
||||
if arg is not None:
|
||||
args.append(arg)
|
||||
if not modelist.startswith(('+', '-')):
|
||||
# Our starting mode didn't have a prefix with it. Assume '+'.
|
||||
modelist = '+' + modelist
|
||||
if args:
|
||||
# Add the args if there are any.
|
||||
modelist += ' %s' % ' '.join(args)
|
||||
return modelist
|
||||
|
||||
### State checking functions
|
||||
def nickToUid(self, nick):
|
||||
"""Looks up the UID of a user with the given nick, if one is present."""
|
||||
|
@ -121,7 +121,7 @@ def handle_whois(irc, source, command, args):
|
||||
# Only show this to opers!
|
||||
if sourceisOper:
|
||||
f(server, 378, source, "%s :is connecting from %s@%s %s" % (nick, user.ident, user.realhost, user.ip))
|
||||
f(server, 379, source, '%s :is using modes %s' % (nick, utils.joinModes(user.modes)))
|
||||
f(server, 379, source, '%s :is using modes %s' % (nick, irc.joinModes(user.modes)))
|
||||
|
||||
# 301: used to show away information if present
|
||||
away_text = user.away
|
||||
|
@ -101,7 +101,7 @@ def showuser(irc, source, args):
|
||||
|
||||
if verbose: # Oper only data: user modes, channels on, account info, etc.
|
||||
|
||||
f('\x02User modes\x02: %s' % utils.joinModes(userobj.modes))
|
||||
f('\x02User modes\x02: %s' % irc.joinModes(userobj.modes))
|
||||
f('\x02Protocol UID\x02: %s; \x02Real host\x02: %s; \x02IP\x02: %s' % \
|
||||
(u, userobj.realhost, userobj.ip))
|
||||
channels = sorted(userobj.channels)
|
||||
@ -141,7 +141,7 @@ def showchan(irc, source, args):
|
||||
f('\x02Channel topic\x02: %s' % c.topic)
|
||||
f('\x02Channel creation time\x02: %s (%s)' % (ctime(c.ts), c.ts))
|
||||
# Show only modes that aren't list-style modes.
|
||||
modes = utils.joinModes([m for m in c.modes if m[0] not in irc.cmodes['*A']])
|
||||
modes = irc.joinModes([m for m in c.modes if m[0] not in irc.cmodes['*A']])
|
||||
f('\x02Channel modes\x02: %s' % modes)
|
||||
if verbose:
|
||||
nicklist = []
|
||||
|
@ -1022,7 +1022,7 @@ def handle_mode(irc, numeric, command, args):
|
||||
if checkClaim(irc, target, numeric, chanobj=oldchan):
|
||||
relayModes(irc, remoteirc, numeric, target, modes)
|
||||
else: # Mode change blocked by CLAIM.
|
||||
reversed_modes = utils.reverseModes(irc, target, modes, oldobj=oldchan)
|
||||
reversed_modes = irc.reverseModes(target, modes, oldobj=oldchan)
|
||||
log.debug('(%s) relay.handle_mode: Reversing mode changes of %r with %r (CLAIM).',
|
||||
irc.name, modes, reversed_modes)
|
||||
irc.proto.mode(irc.pseudoclient.uid, target, reversed_modes)
|
||||
|
@ -108,7 +108,7 @@ class HybridProtocol(TS6Protocol):
|
||||
ts = ts or int(time.time())
|
||||
realname = realname or self.irc.botdata['realname']
|
||||
realhost = realhost or host
|
||||
raw_modes = utils.joinModes(modes)
|
||||
raw_modes = self.irc.joinModes(modes)
|
||||
u = self.irc.users[uid] = IrcUser(nick, ts, uid, ident=ident, host=host, realname=realname,
|
||||
realhost=realhost, ip=ip, manipulatable=manipulatable)
|
||||
self.irc.applyModes(uid, modes)
|
||||
|
@ -55,7 +55,7 @@ class InspIRCdProtocol(TS6BaseProtocol):
|
||||
ts = ts or int(time.time())
|
||||
realname = realname or self.irc.botdata['realname']
|
||||
realhost = realhost or host
|
||||
raw_modes = utils.joinModes(modes)
|
||||
raw_modes = self.irc.joinModes(modes)
|
||||
u = self.irc.users[uid] = IrcUser(nick, ts, uid, ident=ident, host=host, realname=realname,
|
||||
realhost=realhost, ip=ip, manipulatable=manipulatable, opertype=opertype)
|
||||
|
||||
@ -85,7 +85,7 @@ class InspIRCdProtocol(TS6BaseProtocol):
|
||||
modes = [m for m in self.irc.channels[channel].modes if m[0] not in self.irc.cmodes['*A']]
|
||||
self._send(server, "FJOIN {channel} {ts} {modes} :,{uid}".format(
|
||||
ts=self.irc.channels[channel].ts, uid=client, channel=channel,
|
||||
modes=utils.joinModes(modes)))
|
||||
modes=self.irc.joinModes(modes)))
|
||||
self.irc.channels[channel].users.add(client)
|
||||
self.irc.users[client].channels.add(channel)
|
||||
|
||||
@ -136,7 +136,7 @@ class InspIRCdProtocol(TS6BaseProtocol):
|
||||
namelist = ' '.join(namelist)
|
||||
self._send(server, "FJOIN {channel} {ts} {modes} :{users}".format(
|
||||
ts=ts, users=namelist, channel=channel,
|
||||
modes=utils.joinModes(modes)))
|
||||
modes=self.irc.joinModes(modes)))
|
||||
self.irc.channels[channel].users.update(uids)
|
||||
|
||||
def _operUp(self, target, opertype=None):
|
||||
@ -178,7 +178,7 @@ class InspIRCdProtocol(TS6BaseProtocol):
|
||||
# Servers need a special command to set umode +o on people.
|
||||
self._operUp(target)
|
||||
self.irc.applyModes(target, modes)
|
||||
joinedmodes = utils.joinModes(modes)
|
||||
joinedmodes = self.irc.joinModes(modes)
|
||||
if utils.isChannel(target):
|
||||
ts = ts or self.irc.channels[utils.toLower(self.irc, target)].ts
|
||||
self._send(numeric, 'FMODE %s %s %s' % (target, ts, joinedmodes))
|
||||
|
@ -262,7 +262,7 @@ class P10Protocol(Protocol):
|
||||
ts = ts or int(time.time())
|
||||
realname = realname or self.irc.botdata['realname']
|
||||
realhost = realhost or host
|
||||
raw_modes = utils.joinModes(modes)
|
||||
raw_modes = self.irc.joinModes(modes)
|
||||
|
||||
# Initialize an IrcUser instance
|
||||
u = self.irc.users[uid] = IrcUser(nick, ts, uid, ident=ident, host=host, realname=realname,
|
||||
@ -393,7 +393,7 @@ class P10Protocol(Protocol):
|
||||
send_ts = False
|
||||
|
||||
while modes[:12]:
|
||||
joinedmodes = utils.joinModes([m for m in modes[:12]])
|
||||
joinedmodes = self.irc.joinModes([m for m in modes[:12]])
|
||||
modes = modes[12:]
|
||||
self._send(numeric, 'M %s %s%s' % (target, joinedmodes, ' %s' % ts if send_ts else ''))
|
||||
|
||||
@ -526,7 +526,7 @@ class P10Protocol(Protocol):
|
||||
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)))
|
||||
modes=self.irc.joinModes(modes)))
|
||||
else:
|
||||
self._send(server, "B {channel} {ts} :{users}".format(
|
||||
ts=ts, users=namelist, channel=channel))
|
||||
|
@ -50,7 +50,7 @@ class TS6Protocol(TS6BaseProtocol):
|
||||
ts = ts or int(time.time())
|
||||
realname = realname or self.irc.botdata['realname']
|
||||
realhost = realhost or host
|
||||
raw_modes = utils.joinModes(modes)
|
||||
raw_modes = self.irc.joinModes(modes)
|
||||
u = self.irc.users[uid] = IrcUser(nick, ts, uid, ident=ident, host=host, realname=realname,
|
||||
realhost=realhost, ip=ip, manipulatable=manipulatable, opertype=opertype)
|
||||
|
||||
@ -135,7 +135,7 @@ class TS6Protocol(TS6BaseProtocol):
|
||||
namelist = ' '.join(namelist)
|
||||
self._send(server, "SJOIN {ts} {channel} {modes} :{users}".format(
|
||||
ts=ts, users=namelist, channel=channel,
|
||||
modes=utils.joinModes(modes)))
|
||||
modes=self.irc.joinModes(modes)))
|
||||
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.
|
||||
@ -163,11 +163,11 @@ class TS6Protocol(TS6BaseProtocol):
|
||||
while modes[:9]:
|
||||
# Seriously, though. If you send more than 10 mode parameters in
|
||||
# a line, charybdis will silently REJECT the entire command!
|
||||
joinedmodes = utils.joinModes(modes = [m for m in modes[:9] if m[0] not in self.irc.cmodes['*A']])
|
||||
joinedmodes = self.irc.joinModes(modes = [m for m in modes[:9] if m[0] not in self.irc.cmodes['*A']])
|
||||
modes = modes[9:]
|
||||
self._send(numeric, 'TMODE %s %s %s' % (ts, target, joinedmodes))
|
||||
else:
|
||||
joinedmodes = utils.joinModes(modes)
|
||||
joinedmodes = self.irc.joinModes(modes)
|
||||
self._send(numeric, 'MODE %s %s' % (target, joinedmodes))
|
||||
|
||||
def kill(self, numeric, target, reason):
|
||||
|
@ -80,7 +80,7 @@ class UnrealProtocol(TS6BaseProtocol):
|
||||
ts = ts or int(time.time())
|
||||
realname = realname or self.irc.botdata['realname']
|
||||
realhost = realhost or host
|
||||
raw_modes = utils.joinModes(modes)
|
||||
raw_modes = self.irc.joinModes(modes)
|
||||
u = self.irc.users[uid] = IrcUser(nick, ts, uid, ident=ident, host=host, realname=realname,
|
||||
realhost=realhost, ip=ip, manipulatable=manipulatable, opertype=opertype)
|
||||
self.irc.applyModes(uid, modes)
|
||||
@ -216,7 +216,7 @@ class UnrealProtocol(TS6BaseProtocol):
|
||||
raise LookupError('No such PyLink client/server exists.')
|
||||
|
||||
self.irc.applyModes(target, modes)
|
||||
joinedmodes = utils.joinModes(modes)
|
||||
joinedmodes = self.irc.joinModes(modes)
|
||||
if utils.isChannel(target):
|
||||
# The MODE command is used for channel mode changes only
|
||||
ts = ts or self.irc.channels[utils.toLower(self.irc, target)].ts
|
||||
|
126
utils.py
126
utils.py
@ -132,132 +132,6 @@ def applyModes(irc, target, changedmodes):
|
||||
log.warning("(%s) utils.applyModes is deprecated. Use irc.applyModes() instead!", irc.name)
|
||||
return irc.applyModes(target, changedmodes)
|
||||
|
||||
def joinModes(modes):
|
||||
"""Takes a list of (mode, arg) tuples in parseModes() format, and
|
||||
joins them into a string.
|
||||
|
||||
See testJoinModes in tests/test_utils.py for some examples."""
|
||||
prefix = '+' # Assume we're adding modes unless told otherwise
|
||||
modelist = ''
|
||||
args = []
|
||||
for modepair in modes:
|
||||
mode, arg = modepair
|
||||
assert len(mode) in (1, 2), "Incorrect length of a mode (received %r)" % mode
|
||||
try:
|
||||
# If the mode has a prefix, use that.
|
||||
curr_prefix, mode = mode
|
||||
except ValueError:
|
||||
# If not, the current prefix stays the same; move on to the next
|
||||
# modepair.
|
||||
pass
|
||||
else:
|
||||
# If the prefix of this mode isn't the same as the last one, add
|
||||
# the prefix to the modestring. This prevents '+nt-lk' from turning
|
||||
# into '+n+t-l-k' or '+ntlk'.
|
||||
if prefix != curr_prefix:
|
||||
modelist += curr_prefix
|
||||
prefix = curr_prefix
|
||||
modelist += mode
|
||||
if arg is not None:
|
||||
args.append(arg)
|
||||
if not modelist.startswith(('+', '-')):
|
||||
# Our starting mode didn't have a prefix with it. Assume '+'.
|
||||
modelist = '+' + modelist
|
||||
if args:
|
||||
# Add the args if there are any.
|
||||
modelist += ' %s' % ' '.join(args)
|
||||
return modelist
|
||||
|
||||
def _flip(mode):
|
||||
"""Flips a mode character."""
|
||||
# Make it a list first, strings don't support item assignment
|
||||
mode = list(mode)
|
||||
if mode[0] == '-': # Query is something like "-n"
|
||||
mode[0] = '+' # Change it to "+n"
|
||||
elif mode[0] == '+':
|
||||
mode[0] = '-'
|
||||
else: # No prefix given, assume +
|
||||
mode.insert(0, '-')
|
||||
return ''.join(mode)
|
||||
|
||||
def reverseModes(irc, target, modes, oldobj=None):
|
||||
"""Reverses/Inverts the mode string or mode list given.
|
||||
|
||||
Optionally, an oldobj argument can be given to look at an earlier state of
|
||||
a channel/user object, e.g. for checking the op status of a mode setter
|
||||
before their modes are processed and added to the channel state.
|
||||
|
||||
This function allows both mode strings or mode lists. Example uses:
|
||||
"+mi-lk test => "-mi+lk test"
|
||||
"mi-k test => "-mi+k test"
|
||||
[('+m', None), ('+r', None), ('+l', '3'), ('-o', 'person')
|
||||
=> {('-m', None), ('-r', None), ('-l', None), ('+o', 'person')})
|
||||
{('s', None), ('+o', 'whoever') => {('-s', None), ('-o', 'whoever')})
|
||||
"""
|
||||
origtype = type(modes)
|
||||
# If the query is a string, we have to parse it first.
|
||||
if origtype == str:
|
||||
modes = parseModes(irc, target, modes.split(" "))
|
||||
# Get the current mode list first.
|
||||
if isChannel(target):
|
||||
c = oldobj or irc.channels[target]
|
||||
oldmodes = c.modes.copy()
|
||||
possible_modes = irc.cmodes.copy()
|
||||
# For channels, this also includes the list of prefix modes.
|
||||
possible_modes['*A'] += ''.join(irc.prefixmodes)
|
||||
for name, userlist in c.prefixmodes.items():
|
||||
try:
|
||||
oldmodes.update([(irc.cmodes[name], u) for u in userlist])
|
||||
except KeyError:
|
||||
continue
|
||||
else:
|
||||
oldmodes = irc.users[target].modes
|
||||
possible_modes = irc.umodes
|
||||
newmodes = []
|
||||
log.debug('(%s) reverseModes: old/current mode list for %s is: %s', irc.name,
|
||||
target, oldmodes)
|
||||
for char, arg in modes:
|
||||
# Mode types:
|
||||
# A = Mode that adds or removes a nick or address to a list. Always has a parameter.
|
||||
# B = Mode that changes a setting and always has a parameter.
|
||||
# C = Mode that changes a setting and only has a parameter when set.
|
||||
# D = Mode that changes a setting and never has a parameter.
|
||||
mchar = char[-1]
|
||||
if mchar in possible_modes['*B'] + possible_modes['*C']:
|
||||
# We need to find the current mode list, so we can reset arguments
|
||||
# for modes that have arguments. For example, setting +l 30 on a channel
|
||||
# that had +l 50 set should give "+l 30", not "-l".
|
||||
oldarg = [m for m in oldmodes if m[0] == mchar]
|
||||
if oldarg: # Old mode argument for this mode existed, use that.
|
||||
oldarg = oldarg[0]
|
||||
mpair = ('+%s' % oldarg[0], oldarg[1])
|
||||
else: # Not found, flip the mode then.
|
||||
# Mode takes no arguments when unsetting.
|
||||
if mchar in possible_modes['*C'] and char[0] != '-':
|
||||
arg = None
|
||||
mpair = (_flip(char), arg)
|
||||
else:
|
||||
mpair = (_flip(char), arg)
|
||||
if char[0] != '-' and (mchar, arg) in oldmodes:
|
||||
# Mode is already set.
|
||||
log.debug("(%s) reverseModes: skipping reversing '%s %s' with %s since we're "
|
||||
"setting a mode that's already set.", irc.name, char, arg, mpair)
|
||||
continue
|
||||
elif char[0] == '-' and (mchar, arg) not in oldmodes and mchar in possible_modes['*A']:
|
||||
# We're unsetting a prefixmode that was never set - don't set it in response!
|
||||
# Charybdis lacks verification for this server-side.
|
||||
log.debug("(%s) reverseModes: skipping reversing '%s %s' with %s since it "
|
||||
"wasn't previously set.", irc.name, char, arg, mpair)
|
||||
continue
|
||||
newmodes.append(mpair)
|
||||
|
||||
log.debug('(%s) reverseModes: new modes: %s', irc.name, newmodes)
|
||||
if origtype == str:
|
||||
# If the original query is a string, send it back as a string.
|
||||
return joinModes(newmodes)
|
||||
else:
|
||||
return set(newmodes)
|
||||
|
||||
def isOper(irc, uid, allowAuthed=True, allowOper=True):
|
||||
"""
|
||||
Returns whether the given user has operator status on PyLink. This can be achieved
|
||||
|
Loading…
Reference in New Issue
Block a user