Exemplo n.º 1
0
    def handle_fjoin(self, servernumeric, command, args):
        """Handles incoming FJOIN commands (InspIRCd equivalent of JOIN/SJOIN)."""
        # :70M FJOIN #chat 1423790411 +AFPfjnt 6:5 7:5 9:5 :o,1SRAABIT4 v,1IOAAF53R <...>
        channel = utils.toLower(self.irc, args[0])
        # InspIRCd sends each channel's users in the form of 'modeprefix(es),UID'
        userlist = args[-1].split()

        their_ts = int(args[1])
        our_ts = self.irc.channels[channel].ts
        self.updateTS(channel, their_ts)

        modestring = args[2:-1] or args[2]
        parsedmodes = utils.parseModes(self.irc, channel, modestring)
        utils.applyModes(self.irc, channel, parsedmodes)
        namelist = []
        for user in userlist:
            modeprefix, user = user.split(',', 1)
            namelist.append(user)
            self.irc.users[user].channels.add(channel)
            if their_ts <= our_ts:
                utils.applyModes(self.irc, channel,
                                 [('+%s' % mode, user) for mode in modeprefix])
            self.irc.channels[channel].users.add(user)
        return {
            'channel': channel,
            'users': namelist,
            'modes': parsedmodes,
            'ts': their_ts
        }
Exemplo n.º 2
0
    def handle_mode(self, numeric, command, args):
        # <- :unreal.midnight.vpn MODE #endlessvoid +bb test!*@* *!*@bad.net
        # <- :unreal.midnight.vpn MODE #endlessvoid +q GL 1444361345
        # <- :unreal.midnight.vpn MODE #endlessvoid +ntCo GL 1444361345
        # <- :unreal.midnight.vpn MODE #endlessvoid +mntClfo 5 [10t]:5  GL 1444361345
        # <- :GL MODE #services +v GL

        # This seems pretty relatively inconsistent - why do some commands have a TS at the end while others don't?
        # Answer: the first syntax (MODE sent by SERVER) is used for channel bursts - according to Unreal 3.2 docs,
        # the last argument should be interpreted as a timestamp ONLY if it is a number and the sender is a server.
        # Ban bursting does not give any TS, nor do normal users setting modes. SAMODE is special though, it will
        # send 0 as a TS argument (which should be ignored unless breaking the internal channel TS is desired).

        # Also, we need to get rid of that extra space following the +f argument. :|
        if utils.isChannel(args[0]):
            channel = utils.toLower(self.irc, args[0])
            oldobj = self.irc.channels[channel].deepcopy()
            modes = list(filter(None, args[1:]))  # normalize whitespace
            parsedmodes = utils.parseModes(self.irc, channel, modes)
            if parsedmodes:
                utils.applyModes(self.irc, channel, parsedmodes)
            if numeric in self.irc.servers and args[-1].isdigit():
                # Sender is a server AND last arg is number. Perform TS updates.
                their_ts = int(args[-1])
                if their_ts > 0:
                    self.updateTS(channel, their_ts)
            return {'target': channel, 'modes': parsedmodes, 'oldchan': oldobj}
        else:
            log.warning("(%s) received MODE for non-channel target: %r",
                        self.irc.name, args)
            raise NotImplementedError
Exemplo n.º 3
0
    def handle_euid(self, numeric, command, args):
        """Handles incoming EUID commands (user introduction)."""
        # <- :42X EUID GL 1 1437505322 +ailoswz ~gl 127.0.0.1 127.0.0.1 42XAAAAAB * * :realname
        nick = args[0]
        ts, modes, ident, host, ip, uid, realhost = args[2:9]
        if realhost == '*':
            realhost = None
        realname = args[-1]
        log.debug(
            '(%s) handle_euid got args: nick=%s ts=%s uid=%s ident=%s '
            'host=%s realname=%s realhost=%s ip=%s', self.irc.name, nick, ts,
            uid, ident, host, realname, realhost, ip)

        self.irc.users[uid] = IrcUser(nick, ts, uid, ident, host, realname,
                                      realhost, ip)
        parsedmodes = utils.parseModes(self.irc, uid, [modes])
        log.debug('Applying modes %s for %s', parsedmodes, uid)
        utils.applyModes(self.irc, uid, parsedmodes)
        self.irc.servers[numeric].users.add(uid)
        # Call the OPERED UP hook if +o is being added to the mode list.
        if ('+o', None) in parsedmodes:
            otype = 'Server_Administrator' if (
                '+a', None) in parsedmodes else 'IRC_Operator'
            self.irc.callHooks([uid, 'PYLINK_CLIENT_OPERED', {'text': otype}])
        return {
            'uid': uid,
            'ts': ts,
            'nick': nick,
            'realhost': realhost,
            'host': host,
            'ident': ident,
            'ip': ip
        }
Exemplo n.º 4
0
 def handle_svsmode(self, numeric, command, args):
     """Handle SVSMODE/SVS2MODE, used for setting user modes on others (services)."""
     # <- :source SVSMODE target +usermodes
     target = self._getNick(args[0])
     modes = args[1:]
     parsedmodes = utils.parseModes(self.irc, target, modes)
     utils.applyModes(self.irc, target, parsedmodes)
     return {'target': numeric, 'modes': parsedmodes}
Exemplo n.º 5
0
    def handle_uid(self, numeric, command, args):
        # <- :001 UID GL 0 1441306929 gl localhost 0018S7901 0 +iowx * midnight-1C620195 fwAAAQ== :realname
        # <- :001 UID GL| 0 1441389007 gl 10.120.0.6 001ZO8F03 0 +iwx * 391A9CB9.26A16454.D9847B69.IP CngABg== :realname
        # arguments: nick, hopcount???, ts, ident, real-host, UID, number???, modes,
        #            displayed host, cloaked (+x) host, base64-encoded IP, and realname
        # TODO: find out what all the "???" fields mean.
        nick = args[0]
        ts, ident, realhost, uid = args[2:6]
        modestring = args[7]
        host = args[8]
        if host == '*':
            # A single * means that there is no displayed/virtual host, and
            # that it's the same as the real host
            host = args[9]
        raw_ip = args[10].encode()  # codecs.decode only takes bytes, not str
        if raw_ip == b'*':  # Dummy IP (for services, etc.)
            ip = '0.0.0.0'
        else:
            # First, decode the Base64 string into a packed binary IP address.
            ip = codecs.decode(raw_ip, "base64")

            try:  # IPv4 address.
                ip = socket.inet_ntop(socket.AF_INET, ip)
            except ValueError:  # IPv6 address.
                ip = socket.inet_ntop(socket.AF_INET6, ip)
                # HACK: make sure a leading ":" in the IPv6 address (e.g. ::1)
                # doesn't cause it to be misinterpreted as the last argument
                # in a line, should it be mirrored to other networks.
                if ip.startswith(':'):
                    ip = '0' + ip
            else:
                raise ProtocolError(
                    "Invalid number of bits in IP address field (got %s, expected 4 or 16)."
                    % len(ipbits))
        realname = args[-1]
        self.irc.users[uid] = IrcUser(nick, ts, uid, ident, host, realname,
                                      realhost, ip)
        parsedmodes = utils.parseModes(self.irc, uid, [modestring])
        utils.applyModes(self.irc, uid, parsedmodes)
        self.irc.servers[numeric].users.add(uid)

        # The cloaked (+x) host is completely separate from the displayed host
        # and real host in that it is ONLY shown if the user is +x (cloak mode
        # enabled) but NOT +t (vHost set). We'll store this separately for now,
        # but more handling is needed so that plugins can update the cloak host
        # appropriately.
        self.irc.users[uid].cloaked_host = args[9]

        return {
            'uid': uid,
            'ts': ts,
            'nick': nick,
            'realhost': realhost,
            'host': host,
            'ident': ident,
            'ip': ip
        }
Exemplo n.º 6
0
 def handle_mode(self, numeric, command, args):
     """Handles incoming user mode changes."""
     # In InspIRCd, MODE is used for setting user modes and
     # FMODE is used for channel modes:
     # <- :70MAAAAAA MODE 70MAAAAAA -i+xc
     target = args[0]
     modestrings = args[1:]
     changedmodes = utils.parseModes(self.irc, numeric, modestrings)
     utils.applyModes(self.irc, target, changedmodes)
     return {'target': target, 'modes': changedmodes}
Exemplo n.º 7
0
 def handle_fmode(self, numeric, command, args):
     """Handles the FMODE command, used for channel mode changes."""
     # <- :70MAAAAAA FMODE #chat 1433653462 +hhT 70MAAAAAA 70MAAAAAD
     channel = utils.toLower(self.irc, args[0])
     oldobj = self.irc.channels[channel].deepcopy()
     modes = args[2:]
     changedmodes = utils.parseModes(self.irc, channel, modes)
     utils.applyModes(self.irc, channel, changedmodes)
     ts = int(args[1])
     return {
         'target': channel,
         'modes': changedmodes,
         'ts': ts,
         'oldchan': oldobj
     }
Exemplo n.º 8
0
 def handle_tmode(self, numeric, command, args):
     """Handles incoming TMODE commands (channel mode change)."""
     # <- :42XAAAAAB TMODE 1437450768 #endlessvoid -c+lkC 3 agte4
     channel = utils.toLower(self.irc, args[1])
     oldobj = self.irc.channels[channel].deepcopy()
     modes = args[2:]
     changedmodes = utils.parseModes(self.irc, channel, modes)
     utils.applyModes(self.irc, channel, changedmodes)
     ts = int(args[0])
     return {
         'target': channel,
         'modes': changedmodes,
         'ts': ts,
         'oldchan': oldobj
     }
Exemplo n.º 9
0
 def handle_mode(self, numeric, command, args):
     """Handles incoming user mode changes."""
     # <- :70MAAAAAA MODE 70MAAAAAA -i+xc
     target = args[0]
     modestrings = args[1:]
     changedmodes = utils.parseModes(self.irc, numeric, modestrings)
     utils.applyModes(self.irc, target, changedmodes)
     # Call the OPERED UP hook if +o is being set.
     if ('+o', None) in changedmodes:
         otype = 'Server_Administrator' if (
             'a', None) in self.irc.users[target].modes else 'IRC_Operator'
         self.irc.callHooks(
             [target, 'PYLINK_CLIENT_OPERED', {
                 'text': otype
             }])
     return {'target': target, 'modes': changedmodes}
Exemplo n.º 10
0
    def handle_sjoin(self, servernumeric, command, args):
        """Handles incoming SJOIN commands."""
        # parameters: channelTS, channel, simple modes, opt. mode parameters..., nicklist
        channel = utils.toLower(self.irc, args[1])
        userlist = args[-1].split()
        their_ts = int(args[0])
        our_ts = self.irc.channels[channel].ts

        self.updateTS(channel, their_ts)

        modestring = args[2:-1] or args[2]
        parsedmodes = utils.parseModes(self.irc, channel, modestring)
        utils.applyModes(self.irc, channel, parsedmodes)
        namelist = []
        log.debug('(%s) handle_sjoin: got userlist %r for %r', self.irc.name,
                  userlist, channel)
        for userpair in userlist:
            # charybdis sends this in the form "@+UID1, +UID2, UID3, @UID4"
            r = re.search(r'([^\d]*)(.*)', userpair)
            user = r.group(2)
            modeprefix = r.group(1) or ''
            finalprefix = ''
            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)
            for m in modeprefix:
                # Iterate over the mapping of prefix chars to prefixes, and
                # find the characters that match.
                for char, prefix in self.irc.prefixmodes.items():
                    if m == prefix:
                        finalprefix += char
            namelist.append(user)
            self.irc.users[user].channels.add(channel)
            if their_ts <= our_ts:
                utils.applyModes(self.irc, channel, [('+%s' % mode, user)
                                                     for mode in finalprefix])
            self.irc.channels[channel].users.add(user)
        return {
            'channel': channel,
            'users': namelist,
            'modes': parsedmodes,
            'ts': their_ts
        }
Exemplo n.º 11
0
 def handle_uid(self, numeric, command, args):
     """Handles incoming UID commands (user introduction)."""
     # :70M UID 70MAAAAAB 1429934638 GL 0::1 hidden-7j810p.9mdf.lrek.0000.0000.IP gl 0::1 1429934638 +Wioswx +ACGKNOQXacfgklnoqvx :realname
     uid, ts, nick, realhost, host, ident, ip = args[0:7]
     realname = args[-1]
     self.irc.users[uid] = IrcUser(nick, ts, uid, ident, host, realname,
                                   realhost, ip)
     parsedmodes = utils.parseModes(self.irc, uid, [args[8], args[9]])
     log.debug('Applying modes %s for %s', parsedmodes, uid)
     utils.applyModes(self.irc, uid, parsedmodes)
     self.irc.servers[numeric].users.add(uid)
     return {
         'uid': uid,
         'ts': ts,
         'nick': nick,
         'realhost': realhost,
         'host': host,
         'ident': ident,
         'ip': ip
     }
Exemplo n.º 12
0
def mode(irc, source, args):
    """<source> <target> <modes>

    Admin-only. Sets modes <modes> on <target> from <source>, where <source> is either the nick of a PyLink client, or the SID of a PyLink server. <target> can be either a nick or a channel."""
    utils.checkAuthenticated(irc, source, allowOper=False)
    try:
        modesource, target, modes = args[0], args[1], args[2:]
    except IndexError:
        irc.reply(
            'Error: Not enough arguments. Needs 3: source nick, target, modes to set.'
        )
        return
    target = utils.nickToUid(irc, target) or target
    extclient = target in irc.users and not utils.isInternalClient(irc, target)
    parsedmodes = utils.parseModes(irc, target, modes)
    ischannel = target in irc.channels
    if not (target in irc.users or ischannel):
        irc.reply("Error: Invalid channel or nick %r." % target)
        return
    elif not parsedmodes:
        irc.reply("Error: No valid modes were given.")
        return
    elif not (ischannel or utils.isManipulatableClient(irc, target)):
        irc.reply(
            "Error: Can only set modes on channels or non-protected PyLink clients."
        )
        return
    if utils.isInternalServer(irc, modesource):
        # Setting modes from a server.
        irc.proto.modeServer(modesource, target, parsedmodes)
    else:
        # Setting modes from a client.
        modesource = utils.nickToUid(irc, modesource)
        irc.proto.modeClient(modesource, target, parsedmodes)
    irc.callHooks([
        modesource, 'PYLINK_BOTSPLUGIN_MODE', {
            'target': target,
            'modes': parsedmodes,
            'parse_as': 'MODE'
        }
    ])
Exemplo n.º 13
0
 def handle_umode2(self, numeric, command, args):
     """Handles UMODE2, used to set user modes on oneself."""
     # <- :GL UMODE2 +W
     parsedmodes = utils.parseModes(self.irc, numeric, args)
     utils.applyModes(self.irc, numeric, parsedmodes)
     return {'target': numeric, 'modes': parsedmodes}