Beispiel #1
0
 def topicServer(self, numeric, target, text):
     """Sends a TOPIC change from a PyLink server."""
     if not utils.isInternalServer(self.irc, numeric):
         raise LookupError('No such PyLink server exists.')
     self._send(numeric, 'TOPIC %s :%s' % (target, text))
     self.irc.channels[target].topic = text
     self.irc.channels[target].topicset = True
Beispiel #2
0
def kick(irc, source, args):
    """<source> <channel> <user> [<reason>]

    Admin-only. Kicks <user> from <channel> via <source>, where <source> is the nick of a PyLink client."""
    utils.checkAuthenticated(irc, source, allowOper=False)
    try:
        nick = args[0]
        channel = args[1]
        target = args[2]
        reason = ' '.join(args[3:])
    except IndexError:
        irc.reply(
            "Error: Not enough arguments. Needs 3-4: source nick, channel, target, reason (optional)."
        )
        return
    u = utils.nickToUid(irc, nick) or nick
    targetu = utils.nickToUid(irc, target)
    if not utils.isChannel(channel):
        irc.reply("Error: Invalid channel name %r." % channel)
        return
    if utils.isInternalServer(irc, u):
        irc.proto.kickServer(u, channel, targetu, reason)
    else:
        irc.proto.kickClient(u, channel, targetu, reason)
    irc.callHooks([
        u, 'PYLINK_BOTSPLUGIN_KICK', {
            'channel': channel,
            'target': targetu,
            'text': reason,
            'parse_as': 'KICK'
        }
    ])
Beispiel #3
0
 def spawnServer(self, name, sid=None, uplink=None, desc=None):
     """
     Spawns a server off a PyLink server. desc (server description)
     defaults to the one in the config. uplink defaults to the main PyLink
     server, and sid (the server ID) is automatically generated if not
     given.
     """
     # -> :0AL SERVER test.server * 1 0AM :some silly pseudoserver
     uplink = uplink or self.irc.sid
     name = name.lower()
     # "desc" defaults to the configured server description.
     desc = desc or self.irc.serverdata.get(
         'serverdesc') or self.irc.botdata['serverdesc']
     if sid is None:  # No sid given; generate one!
         sid = self.sidgen.next_sid()
     assert len(sid) == 3, "Incorrect SID length"
     if sid in self.irc.servers:
         raise ValueError('A server with SID %r already exists!' % sid)
     for server in self.irc.servers.values():
         if name == server.name:
             raise ValueError('A server named %r already exists!' % name)
     if not utils.isInternalServer(self.irc, uplink):
         raise ValueError(
             'Server %r is not a PyLink internal PseudoServer!' % uplink)
     if not utils.isServerName(name):
         raise ValueError('Invalid server name %r' % name)
     self._send(uplink, 'SERVER %s * 1 %s :%s' % (name, sid, desc))
     self.irc.servers[sid] = IrcServer(uplink,
                                       name,
                                       internal=True,
                                       desc=desc)
     self._send(sid, 'ENDBURST')
     return sid
Beispiel #4
0
 def modeServer(self, numeric, target, modes, ts=None):
     """
     Sends mode changes from a PyLink server. The mode list should be
     a list of (mode, arg) tuples, i.e. the format of utils.parseModes() output.
     """
     if not utils.isInternalServer(self.irc, numeric):
         raise LookupError('No such PyLink server exists.')
     self._sendModes(numeric, target, modes, ts=ts)
Beispiel #5
0
 def topicServer(self, numeric, target, text):
     """Sends a topic change from a PyLink server. This is usually used on burst."""
     if not utils.isInternalServer(self.irc, numeric):
         raise LookupError('No such PyLink PseudoServer exists.')
     ts = int(time.time())
     servername = self.irc.servers[numeric].name
     self._send(numeric,
                'FTOPIC %s %s %s :%s' % (target, ts, servername, text))
     self.irc.channels[target].topic = text
     self.irc.channels[target].topicset = True
Beispiel #6
0
    def spawnClient(self,
                    nick,
                    ident='null',
                    host='null',
                    realhost=None,
                    modes=set(),
                    server=None,
                    ip='0.0.0.0',
                    realname=None,
                    ts=None,
                    opertype=None,
                    manipulatable=False):
        """Spawns a client with nick <nick> on the given IRC connection.

        Note: No nick collision / valid nickname checks are done here; it is
        up to plugins to make sure they don't introduce anything invalid."""
        server = server or self.irc.sid
        if not utils.isInternalServer(self.irc, server):
            raise ValueError(
                'Server %r is not a PyLink internal PseudoServer!' % server)
        # Create an UIDGenerator instance for every SID, so that each gets
        # distinct values.
        uid = self.uidgen.setdefault(server,
                                     utils.TS6UIDGenerator(server)).next_uid()
        # EUID:
        # parameters: nickname, hopcount, nickTS, umodes, username,
        # visible hostname, IP address, UID, real hostname, account name, gecos
        ts = ts or int(time.time())
        realname = realname or self.irc.botdata['realname']
        realhost = realhost or host
        raw_modes = utils.joinModes(modes)
        u = self.irc.users[uid] = IrcUser(nick,
                                          ts,
                                          uid,
                                          ident=ident,
                                          host=host,
                                          realname=realname,
                                          realhost=realhost,
                                          ip=ip,
                                          manipulatable=manipulatable)
        utils.applyModes(self.irc, uid, modes)
        self.irc.servers[server].users.add(uid)
        self._send(
            server, "EUID {nick} 1 {ts} {modes} {ident} {host} {ip} {uid} "
            "{realhost} * :{realname}".format(ts=ts,
                                              host=host,
                                              nick=nick,
                                              ident=ident,
                                              uid=uid,
                                              modes=raw_modes,
                                              ip=ip,
                                              realname=realname,
                                              realhost=realhost))
        return u
Beispiel #7
0
    def killServer(self, numeric, target, reason):
        """Sends a kill from a PyLink server."""
        # <- :GL KILL 38QAAAAAA :hidden-1C620195!GL (test)
        if not utils.isInternalServer(self.irc, numeric):
            raise LookupError('No such PyLink server exists.')

        assert target in self.irc.users, "Unknown target %r for killServer!" % target
        # The killpath doesn't really matter here...
        self._send(
            numeric, 'KILL %s :%s!PyLink (%s)' %
            (target, self.irc.serverdata['hostname'], reason))
        self.removeClient(target)
Beispiel #8
0
 def topicServer(self, numeric, target, text):
     """Sends a topic change from a PyLink server. This is usually used on burst."""
     if not utils.isInternalServer(self.irc, numeric):
         raise LookupError('No such PyLink PseudoServer exists.')
     # TB
     # capab: TB
     # source: server
     # propagation: broadcast
     # parameters: channel, topicTS, opt. topic setter, topic
     ts = self.irc.channels[target].ts
     servername = self.irc.servers[numeric].name
     self._send(numeric, 'TB %s %s %s :%s' % (target, ts, servername, text))
     self.irc.channels[target].topic = text
     self.irc.channels[target].topicset = True
Beispiel #9
0
    def killServer(self, numeric, target, reason):
        """Sends a kill from a PyLink server."""
        if not utils.isInternalServer(self.irc, numeric):
            raise LookupError('No such PyLink PseudoServer exists.')
        # KILL:
        # parameters: target user, path

        # The format of the path parameter is some sort of description of the source of
        # the kill followed by a space and a parenthesized reason. To avoid overflow,
        # it is recommended not to add anything to the path.

        assert target in self.irc.users, "Unknown target %r for killServer!" % target
        self._send(numeric, 'KILL %s :Killed (%s)' % (target, reason))
        self.removeClient(target)
Beispiel #10
0
    def handle_ping(self, source, command, args):
        """Handles incoming PING commands."""
        # PING:
        # source: any
        # parameters: origin, opt. destination server
        # PONG:
        # source: server
        # parameters: origin, destination

        # Sends a PING to the destination server, which will reply with a PONG. If the
        # destination server parameter is not present, the server receiving the message
        # must reply.
        try:
            destination = args[1]
        except IndexError:
            destination = self.irc.sid
        if utils.isInternalServer(self.irc, destination):
            self._send(destination, 'PONG %s %s' % (destination, source))
Beispiel #11
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'
        }
    ])
Beispiel #12
0
    def spawnClient(self,
                    nick,
                    ident='null',
                    host='null',
                    realhost=None,
                    modes=set(),
                    server=None,
                    ip='0.0.0.0',
                    realname=None,
                    ts=None,
                    opertype=None,
                    manipulatable=False):
        """Spawns a client with nick <nick> on the given IRC connection.

        Note: No nick collision / valid nickname checks are done here; it is
        up to plugins to make sure they don't introduce anything invalid."""
        server = server or self.irc.sid
        if not utils.isInternalServer(self.irc, server):
            raise ValueError(
                'Server %r is not a PyLink internal PseudoServer!' % server)
        # Unreal 3.4 uses TS6-style UIDs. They don't start from AAAAAA like other IRCd's
        # do, but we can do that fine...
        uid = self.uidgen.setdefault(server,
                                     utils.TS6UIDGenerator(server)).next_uid()
        ts = ts or int(time.time())
        realname = realname or self.irc.botdata['realname']
        realhost = realhost or host
        raw_modes = utils.joinModes(modes)
        u = self.irc.users[uid] = IrcUser(nick,
                                          ts,
                                          uid,
                                          ident=ident,
                                          host=host,
                                          realname=realname,
                                          realhost=realhost,
                                          ip=ip,
                                          manipulatable=manipulatable)
        utils.applyModes(self.irc, uid, modes)
        self.irc.servers[server].users.add(uid)

        # UnrealIRCd requires encoding the IP by first packing it into a binary format,
        # and then encoding the binary with Base64.
        if ip == '0.0.0.0':  # Dummy IP (for services, etc.) use a single *.
            encoded_ip = '*'
        else:
            try:  # Try encoding as IPv4 first.
                binary_ip = socket.inet_pton(socket.AF_INET, ip)
            except OSError:
                try:  # That failed, try IPv6 next.
                    binary_ip = socket.inet_pton(socket.AF_INET6, ip)
                except OSError:
                    raise ValueError("Invalid IPv4 or IPv6 address %r." % ip)

            # Encode in Base64.
            encoded_ip = codecs.encode(binary_ip, "base64")
            # Now, strip the trailing \n and decode into a string again.
            encoded_ip = encoded_ip.strip().decode()

        # <- :001 UID GL 0 1441306929 gl localhost 0018S7901 0 +iowx * midnight-1C620195 fwAAAQ== :realname
        self._send(
            server, "UID {nick} 0 {ts} {ident} {realhost} {uid} 0 {modes} "
            "{host} * {ip} :{realname}".format(ts=ts,
                                               host=host,
                                               nick=nick,
                                               ident=ident,
                                               uid=uid,
                                               modes=raw_modes,
                                               realname=realname,
                                               realhost=realhost,
                                               ip=encoded_ip))

        # Force the virtual hostname to show correctly by running SETHOST on
        # the user. Otherwise, Unreal will show the real host of the person
        # instead, which is probably not what we want.
        self.updateClient(uid, 'HOST', host)

        return u
Beispiel #13
0
 def handle_ping(self, source, command, args):
     """Handles incoming PING commands, so we don't time out."""
     # <- :70M PING 70M 0AL
     # -> :0AL PONG 0AL 70M
     if utils.isInternalServer(self.irc, args[1]):
         self._send(args[1], 'PONG %s %s' % (args[1], source))
Beispiel #14
0
 def killServer(self, numeric, target, reason):
     """Sends a kill from a PyLink server."""
     if not utils.isInternalServer(self.irc, numeric):
         raise LookupError('No such PyLink PseudoServer exists.')
     self._sendKill(numeric, target, reason)
Beispiel #15
0
 def kickServer(self, numeric, channel, target, reason=None):
     """Sends a kick from a PyLink server."""
     if not utils.isInternalServer(self.irc, numeric):
         raise LookupError('No such PyLink PseudoServer exists.')
     self._sendKick(numeric, channel, target, reason=reason)