Beispiel #1
0
def handle_mode(irc, source, command, args):
    """Protect against forced deoper attempts."""
    target = args['target']
    modes = args['modes']
    # If the sender is not a PyLink client, and the target IS a protected
    # client, revert any forced deoper attempts.
    if utils.isInternalClient(irc, target) and not utils.isInternalClient(irc, source):
        if ('-o', None) in modes and (target == irc.pseudoclient.uid or not utils.isManipulatableClient(irc, target)):
            irc.proto.modeServer(irc.sid, target, {('+o', None)})
Beispiel #2
0
 def _sendKill(self, numeric, target, reason):
     self._send(numeric, 'KILL %s :%s' % (target, reason))
     # We only need to call removeClient here if the target is one of our
     # clients, since any remote servers will send a QUIT from
     # their target if the command succeeds.
     if utils.isInternalClient(self.irc, target):
         self.removeClient(target)
Beispiel #3
0
 def killClient(self, numeric, target, reason):
     """Sends a kill from a PyLink client."""
     if not utils.isInternalClient(self.irc, numeric):
         raise LookupError('No such PyLink PseudoClient exists.')
     assert target in self.irc.users, "Unknown target %r for killClient!" % target
     self._send(numeric, 'KILL %s :Killed (%s)' % (target, reason))
     self.removeClient(target)
Beispiel #4
0
 def topicClient(self, numeric, target, text):
     """Sends a TOPIC change from a PyLink client."""
     if not utils.isInternalClient(self.irc, numeric):
         raise LookupError('No such PyLink PseudoClient exists.')
     self._send(numeric, 'TOPIC %s :%s' % (target, text))
     self.irc.channels[target].topic = text
     self.irc.channels[target].topicset = True
Beispiel #5
0
 def quitClient(self, numeric, reason):
     """Quits a PyLink client."""
     if utils.isInternalClient(self.irc, numeric):
         self._send(numeric, "QUIT :%s" % reason)
         self.removeClient(numeric)
     else:
         raise LookupError("No such PyLink PseudoClient exists.")
Beispiel #6
0
 def joinClient(self, client, channel):
     """Joins a PyLink client to a channel."""
     # InspIRCd doesn't distinguish between burst joins and regular joins,
     # so what we're actually doing here is sending FJOIN from the server,
     # on behalf of the clients that are joining.
     channel = utils.toLower(self.irc, channel)
     server = utils.isInternalClient(self.irc, client)
     if not server:
         log.error(
             '(%s) Error trying to join client %r to %r (no such pseudoclient exists)',
             self.irc.name, client, channel)
         raise LookupError('No such PyLink PseudoClient exists.')
     # Strip out list-modes, they shouldn't be ever sent in FJOIN.
     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)))
     self.irc.channels[channel].users.add(client)
     self.irc.users[client].channels.add(channel)
Beispiel #7
0
 def inviteClient(self, numeric, target, channel):
     """Sends an INVITE from a PyLink client.."""
     if not utils.isInternalClient(self.irc, numeric):
         raise LookupError('No such PyLink PseudoClient exists.')
     self._send(
         numeric, 'INVITE %s %s %s' %
         (target, channel, self.irc.channels[channel].ts))
Beispiel #8
0
 def joinClient(self, client, channel):
     """Joins a PyLink client to a channel."""
     channel = utils.toLower(self.irc, channel)
     if not utils.isInternalClient(self.irc, client):
         raise LookupError('No such PyLink client exists.')
     self._send(client, "JOIN %s" % channel)
     self.irc.channels[channel].users.add(client)
     self.irc.users[client].channels.add(channel)
Beispiel #9
0
 def modeClient(self, numeric, target, modes, ts=None):
     """
     Sends mode changes from a PyLink client. The mode list should be
     a list of (mode, arg) tuples, i.e. the format of utils.parseModes() output.
     """
     if not utils.isInternalClient(self.irc, numeric):
         raise LookupError('No such PyLink client exists.')
     self._sendModes(numeric, target, modes, ts=ts)
Beispiel #10
0
 def knockClient(self, numeric, target, text):
     """Sends a KNOCK from a PyLink client."""
     if 'KNOCK' not in self.irc.caps:
         log.debug(
             '(%s) knockClient: Dropping KNOCK to %r since the IRCd '
             'doesn\'t support it.', self.irc.name, target)
         return
     if not utils.isInternalClient(self.irc, numeric):
         raise LookupError('No such PyLink PseudoClient exists.')
     # No text value is supported here; drop it.
     self._send(numeric, 'KNOCK %s' % target)
Beispiel #11
0
 def partClient(self, client, channel, reason=None):
     """Sends a part from a PyLink client."""
     channel = utils.toLower(self.irc, channel)
     if not utils.isInternalClient(self.irc, client):
         log.error(
             '(%s) Error trying to part client %r to %r (no such pseudoclient exists)',
             self.irc.name, client, channel)
         raise LookupError('No such PyLink PseudoClient exists.')
     msg = "PART %s" % channel
     if reason:
         msg += " :%s" % reason
     self._send(client, msg)
     self.handle_part(client, 'PART', [channel])
Beispiel #12
0
 def joinClient(self, client, channel):
     """Joins a PyLink client to a channel."""
     channel = utils.toLower(self.irc, channel)
     # JOIN:
     # parameters: channelTS, channel, '+' (a plus sign)
     if not utils.isInternalClient(self.irc, client):
         log.error(
             '(%s) Error trying to join client %r to %r (no such pseudoclient exists)',
             self.irc.name, client, channel)
         raise LookupError('No such PyLink PseudoClient exists.')
     self._send(
         client,
         "JOIN {ts} {channel} +".format(ts=self.irc.channels[channel].ts,
                                        channel=channel))
     self.irc.channels[channel].users.add(client)
     self.irc.users[client].channels.add(channel)
Beispiel #13
0
def handle_fantasy(irc, source, command, args):
    """Fantasy command handler."""
    try:  # First, try to fetch the config-defined prefix.
        prefixes = [irc.botdata["prefix"]]
    except KeyError:  # Config option is missing.
        prefixes = []

    if irc.botdata.get("respondtonick"):
        # If responding to nick is enabled, add variations of the current nick
        # to the prefix list: "<nick>," and "<nick>:"
        nick = irc.pseudoclient.nick
        prefixes += [nick + ',', nick + ':']

    if not prefixes:
        # We finished with an empty prefixes list, meaning fantasy is misconfigured!
        log.warning(
            "(%s) Fantasy prefix was not set in configuration - "
            "fantasy commands will not work!", irc.name)
        return

    channel = args['target']
    text = args['text']
    for prefix in prefixes:  # Cycle through the prefixes list we finished with.
        # The following conditions must be met for an incoming message for
        # fantasy to trigger:
        #   1) The message target is a channel.
        #   2) The message starts with one of our fantasy prefixes.
        #   3) The main PyLink client is in the channel where the command was
        #      called.
        #   4) The sender is NOT a PyLink client (this prevents infinite
        #      message loops).
        if utils.isChannel(channel) and text.startswith(prefix) and \
                irc.pseudoclient.uid in irc.channels[channel].users and not \
                utils.isInternalClient(irc, source):

            # Cut off the length of the prefix from the text.
            text = text[len(prefix):]

            # Set the "place last command was called in" variable to the
            # channel in question, so that replies from fantasy-supporting
            # plugins get forwarded to it.
            irc.called_by = channel

            # Finally, call the bot command and break.
            irc.callCommand(source, text)
            break
Beispiel #14
0
 def _sendModes(self, numeric, target, modes, ts=None):
     """Internal function to send mode changes from a PyLink client/server."""
     # <- :unreal.midnight.vpn MODE #endlessvoid +ntCo GL 1444361345
     utils.applyModes(self.irc, target, modes)
     joinedmodes = utils.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
         self._send(numeric, 'MODE %s %s %s' % (target, joinedmodes, ts))
     else:
         # For user modes, the only way to set modes (for non-U:Lined servers)
         # is through UMODE2, which sets the modes on the caller.
         # U:Lines can use SVSMODE/SVS2MODE, but I won't expect people to
         # U:Line a PyLink daemon...
         if not utils.isInternalClient(self.irc, target):
             raise ProtocolError(
                 'Cannot force mode change on external clients!')
         self._send(target, 'UMODE2 %s' % joinedmodes)
Beispiel #15
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 #16
0
 def killClient(self, numeric, target, reason):
     """Sends a kill from a PyLink client."""
     if not utils.isInternalClient(self.irc, numeric):
         raise LookupError('No such PyLink PseudoClient exists.')
     self._sendKill(numeric, target, reason)
Beispiel #17
0
 def kickClient(self, numeric, channel, target, reason=None):
     """Sends a kick from a PyLink client."""
     if not utils.isInternalClient(self.irc, numeric):
         raise LookupError('No such PyLink PseudoClient exists.')
     self._sendKick(numeric, channel, target, reason=reason)
Beispiel #18
0
def handle_commands(irc, source, command, args):
    """Handle commands sent to the PyLink client (PRIVMSG)."""
    if args['target'] == irc.pseudoclient.uid and not utils.isInternalClient(irc, source):
        irc.called_by = source
        irc.callCommand(source, args['text'])
Beispiel #19
0
 def nickClient(self, numeric, newnick):
     """Changes the nick of a PyLink client."""
     if not utils.isInternalClient(self.irc, numeric):
         raise LookupError('No such PyLink PseudoClient exists.')
     self._send(numeric, 'NICK %s %s' % (newnick, int(time.time())))
     self.irc.users[numeric].nick = newnick
Beispiel #20
0
 def messageClient(self, numeric, target, text):
     """Sends a PRIVMSG from a PyLink client."""
     if not utils.isInternalClient(self.irc, numeric):
         raise LookupError('No such PyLink PseudoClient exists.')
     self._send(numeric, 'PRIVMSG %s :%s' % (target, text))
Beispiel #21
0
 def knockClient(self, numeric, target, text):
     """Sends a KNOCK from a PyLink client."""
     if not utils.isInternalClient(self.irc, numeric):
         raise LookupError('No such PyLink PseudoClient exists.')
     self._send(numeric, 'ENCAP * KNOCK %s :%s' % (target, text))
Beispiel #22
0
 def noticeClient(self, numeric, target, text):
     """Sends a NOTICE from a PyLink client."""
     if not utils.isInternalClient(self.irc, numeric):
         raise LookupError('No such PyLink PseudoClient exists.')
     self._send(numeric, 'NOTICE %s :%s' % (target, text))