mirror of
				https://github.com/jlu5/PyLink.git
				synced 2025-11-04 00:47:21 +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…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user