mirror of
https://github.com/jlu5/PyLink.git
synced 2024-11-30 14:49:28 +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:
|
else:
|
||||||
self.channels[target].modes = modelist
|
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
|
### State checking functions
|
||||||
def nickToUid(self, nick):
|
def nickToUid(self, nick):
|
||||||
"""Looks up the UID of a user with the given nick, if one is present."""
|
"""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!
|
# Only show this to opers!
|
||||||
if sourceisOper:
|
if sourceisOper:
|
||||||
f(server, 378, source, "%s :is connecting from %s@%s %s" % (nick, user.ident, user.realhost, user.ip))
|
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
|
# 301: used to show away information if present
|
||||||
away_text = user.away
|
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.
|
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' % \
|
f('\x02Protocol UID\x02: %s; \x02Real host\x02: %s; \x02IP\x02: %s' % \
|
||||||
(u, userobj.realhost, userobj.ip))
|
(u, userobj.realhost, userobj.ip))
|
||||||
channels = sorted(userobj.channels)
|
channels = sorted(userobj.channels)
|
||||||
@ -141,7 +141,7 @@ def showchan(irc, source, args):
|
|||||||
f('\x02Channel topic\x02: %s' % c.topic)
|
f('\x02Channel topic\x02: %s' % c.topic)
|
||||||
f('\x02Channel creation time\x02: %s (%s)' % (ctime(c.ts), c.ts))
|
f('\x02Channel creation time\x02: %s (%s)' % (ctime(c.ts), c.ts))
|
||||||
# Show only modes that aren't list-style modes.
|
# 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)
|
f('\x02Channel modes\x02: %s' % modes)
|
||||||
if verbose:
|
if verbose:
|
||||||
nicklist = []
|
nicklist = []
|
||||||
|
@ -1022,7 +1022,7 @@ def handle_mode(irc, numeric, command, args):
|
|||||||
if checkClaim(irc, target, numeric, chanobj=oldchan):
|
if checkClaim(irc, target, numeric, chanobj=oldchan):
|
||||||
relayModes(irc, remoteirc, numeric, target, modes)
|
relayModes(irc, remoteirc, numeric, target, modes)
|
||||||
else: # Mode change blocked by CLAIM.
|
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).',
|
log.debug('(%s) relay.handle_mode: Reversing mode changes of %r with %r (CLAIM).',
|
||||||
irc.name, modes, reversed_modes)
|
irc.name, modes, reversed_modes)
|
||||||
irc.proto.mode(irc.pseudoclient.uid, target, reversed_modes)
|
irc.proto.mode(irc.pseudoclient.uid, target, reversed_modes)
|
||||||
|
@ -108,7 +108,7 @@ class HybridProtocol(TS6Protocol):
|
|||||||
ts = ts or int(time.time())
|
ts = ts or int(time.time())
|
||||||
realname = realname or self.irc.botdata['realname']
|
realname = realname or self.irc.botdata['realname']
|
||||||
realhost = realhost or host
|
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,
|
u = self.irc.users[uid] = IrcUser(nick, ts, uid, ident=ident, host=host, realname=realname,
|
||||||
realhost=realhost, ip=ip, manipulatable=manipulatable)
|
realhost=realhost, ip=ip, manipulatable=manipulatable)
|
||||||
self.irc.applyModes(uid, modes)
|
self.irc.applyModes(uid, modes)
|
||||||
|
@ -55,7 +55,7 @@ class InspIRCdProtocol(TS6BaseProtocol):
|
|||||||
ts = ts or int(time.time())
|
ts = ts or int(time.time())
|
||||||
realname = realname or self.irc.botdata['realname']
|
realname = realname or self.irc.botdata['realname']
|
||||||
realhost = realhost or host
|
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,
|
u = self.irc.users[uid] = IrcUser(nick, ts, uid, ident=ident, host=host, realname=realname,
|
||||||
realhost=realhost, ip=ip, manipulatable=manipulatable, opertype=opertype)
|
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']]
|
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(
|
self._send(server, "FJOIN {channel} {ts} {modes} :,{uid}".format(
|
||||||
ts=self.irc.channels[channel].ts, uid=client, channel=channel,
|
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.channels[channel].users.add(client)
|
||||||
self.irc.users[client].channels.add(channel)
|
self.irc.users[client].channels.add(channel)
|
||||||
|
|
||||||
@ -136,7 +136,7 @@ class InspIRCdProtocol(TS6BaseProtocol):
|
|||||||
namelist = ' '.join(namelist)
|
namelist = ' '.join(namelist)
|
||||||
self._send(server, "FJOIN {channel} {ts} {modes} :{users}".format(
|
self._send(server, "FJOIN {channel} {ts} {modes} :{users}".format(
|
||||||
ts=ts, users=namelist, channel=channel,
|
ts=ts, users=namelist, channel=channel,
|
||||||
modes=utils.joinModes(modes)))
|
modes=self.irc.joinModes(modes)))
|
||||||
self.irc.channels[channel].users.update(uids)
|
self.irc.channels[channel].users.update(uids)
|
||||||
|
|
||||||
def _operUp(self, target, opertype=None):
|
def _operUp(self, target, opertype=None):
|
||||||
@ -178,7 +178,7 @@ class InspIRCdProtocol(TS6BaseProtocol):
|
|||||||
# Servers need a special command to set umode +o on people.
|
# Servers need a special command to set umode +o on people.
|
||||||
self._operUp(target)
|
self._operUp(target)
|
||||||
self.irc.applyModes(target, modes)
|
self.irc.applyModes(target, modes)
|
||||||
joinedmodes = utils.joinModes(modes)
|
joinedmodes = self.irc.joinModes(modes)
|
||||||
if utils.isChannel(target):
|
if utils.isChannel(target):
|
||||||
ts = ts or self.irc.channels[utils.toLower(self.irc, target)].ts
|
ts = ts or self.irc.channels[utils.toLower(self.irc, target)].ts
|
||||||
self._send(numeric, 'FMODE %s %s %s' % (target, ts, joinedmodes))
|
self._send(numeric, 'FMODE %s %s %s' % (target, ts, joinedmodes))
|
||||||
|
@ -262,7 +262,7 @@ class P10Protocol(Protocol):
|
|||||||
ts = ts or int(time.time())
|
ts = ts or int(time.time())
|
||||||
realname = realname or self.irc.botdata['realname']
|
realname = realname or self.irc.botdata['realname']
|
||||||
realhost = realhost or host
|
realhost = realhost or host
|
||||||
raw_modes = utils.joinModes(modes)
|
raw_modes = self.irc.joinModes(modes)
|
||||||
|
|
||||||
# Initialize an IrcUser instance
|
# Initialize an IrcUser instance
|
||||||
u = self.irc.users[uid] = IrcUser(nick, ts, uid, ident=ident, host=host, realname=realname,
|
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
|
send_ts = False
|
||||||
|
|
||||||
while modes[:12]:
|
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:]
|
modes = modes[12:]
|
||||||
self._send(numeric, 'M %s %s%s' % (target, joinedmodes, ' %s' % ts if send_ts else ''))
|
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.
|
if modes: # Only send modes if there are any.
|
||||||
self._send(server, "B {channel} {ts} {modes} :{users}".format(
|
self._send(server, "B {channel} {ts} {modes} :{users}".format(
|
||||||
ts=ts, users=namelist, channel=channel,
|
ts=ts, users=namelist, channel=channel,
|
||||||
modes=utils.joinModes(modes)))
|
modes=self.irc.joinModes(modes)))
|
||||||
else:
|
else:
|
||||||
self._send(server, "B {channel} {ts} :{users}".format(
|
self._send(server, "B {channel} {ts} :{users}".format(
|
||||||
ts=ts, users=namelist, channel=channel))
|
ts=ts, users=namelist, channel=channel))
|
||||||
|
@ -50,7 +50,7 @@ class TS6Protocol(TS6BaseProtocol):
|
|||||||
ts = ts or int(time.time())
|
ts = ts or int(time.time())
|
||||||
realname = realname or self.irc.botdata['realname']
|
realname = realname or self.irc.botdata['realname']
|
||||||
realhost = realhost or host
|
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,
|
u = self.irc.users[uid] = IrcUser(nick, ts, uid, ident=ident, host=host, realname=realname,
|
||||||
realhost=realhost, ip=ip, manipulatable=manipulatable, opertype=opertype)
|
realhost=realhost, ip=ip, manipulatable=manipulatable, opertype=opertype)
|
||||||
|
|
||||||
@ -135,7 +135,7 @@ class TS6Protocol(TS6BaseProtocol):
|
|||||||
namelist = ' '.join(namelist)
|
namelist = ' '.join(namelist)
|
||||||
self._send(server, "SJOIN {ts} {channel} {modes} :{users}".format(
|
self._send(server, "SJOIN {ts} {channel} {modes} :{users}".format(
|
||||||
ts=ts, users=namelist, channel=channel,
|
ts=ts, users=namelist, channel=channel,
|
||||||
modes=utils.joinModes(modes)))
|
modes=self.irc.joinModes(modes)))
|
||||||
self.irc.channels[channel].users.update(uids)
|
self.irc.channels[channel].users.update(uids)
|
||||||
if ts <= orig_ts:
|
if ts <= orig_ts:
|
||||||
# Only save our prefix modes in the channel state if our TS is lower than or equal to theirs.
|
# 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]:
|
while modes[:9]:
|
||||||
# Seriously, though. If you send more than 10 mode parameters in
|
# Seriously, though. If you send more than 10 mode parameters in
|
||||||
# a line, charybdis will silently REJECT the entire command!
|
# 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:]
|
modes = modes[9:]
|
||||||
self._send(numeric, 'TMODE %s %s %s' % (ts, target, joinedmodes))
|
self._send(numeric, 'TMODE %s %s %s' % (ts, target, joinedmodes))
|
||||||
else:
|
else:
|
||||||
joinedmodes = utils.joinModes(modes)
|
joinedmodes = self.irc.joinModes(modes)
|
||||||
self._send(numeric, 'MODE %s %s' % (target, joinedmodes))
|
self._send(numeric, 'MODE %s %s' % (target, joinedmodes))
|
||||||
|
|
||||||
def kill(self, numeric, target, reason):
|
def kill(self, numeric, target, reason):
|
||||||
|
@ -80,7 +80,7 @@ class UnrealProtocol(TS6BaseProtocol):
|
|||||||
ts = ts or int(time.time())
|
ts = ts or int(time.time())
|
||||||
realname = realname or self.irc.botdata['realname']
|
realname = realname or self.irc.botdata['realname']
|
||||||
realhost = realhost or host
|
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,
|
u = self.irc.users[uid] = IrcUser(nick, ts, uid, ident=ident, host=host, realname=realname,
|
||||||
realhost=realhost, ip=ip, manipulatable=manipulatable, opertype=opertype)
|
realhost=realhost, ip=ip, manipulatable=manipulatable, opertype=opertype)
|
||||||
self.irc.applyModes(uid, modes)
|
self.irc.applyModes(uid, modes)
|
||||||
@ -216,7 +216,7 @@ class UnrealProtocol(TS6BaseProtocol):
|
|||||||
raise LookupError('No such PyLink client/server exists.')
|
raise LookupError('No such PyLink client/server exists.')
|
||||||
|
|
||||||
self.irc.applyModes(target, modes)
|
self.irc.applyModes(target, modes)
|
||||||
joinedmodes = utils.joinModes(modes)
|
joinedmodes = self.irc.joinModes(modes)
|
||||||
if utils.isChannel(target):
|
if utils.isChannel(target):
|
||||||
# The MODE command is used for channel mode changes only
|
# The MODE command is used for channel mode changes only
|
||||||
ts = ts or self.irc.channels[utils.toLower(self.irc, target)].ts
|
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)
|
log.warning("(%s) utils.applyModes is deprecated. Use irc.applyModes() instead!", irc.name)
|
||||||
return irc.applyModes(target, changedmodes)
|
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):
|
def isOper(irc, uid, allowAuthed=True, allowOper=True):
|
||||||
"""
|
"""
|
||||||
Returns whether the given user has operator status on PyLink. This can be achieved
|
Returns whether the given user has operator status on PyLink. This can be achieved
|
||||||
|
Loading…
Reference in New Issue
Block a user