コード例 #1
0
def unquiet(bot, trigger):
    """Unquiet a user. The bot must be a channel operator for this command to work.
    """
    chanops = get_chanops(bot, trigger)
    if bot.channels[trigger.sender].privileges[
            bot.nick] < OP and trigger.account in chanops:
        bot.say('Please wait...')
        bot.say('op ' + trigger.sender, 'ChanServ')
        time.sleep(1)
    text = trigger.group().split()
    argc = len(text)
    if argc < 2:
        return
    opt = Identifier(text[1])
    quietmask = opt
    channel = trigger.sender
    if not opt.is_nick():
        if argc < 3:
            return
        quietmask = text[2]
        channel = opt
    quietmask = configureHostMask(quietmask)
    if quietmask == '':
        return
    if trigger.account in chanops:
        bot.write(['MODE', channel, '-q', quietmask])
    else:
        bot.reply(
            'Access Denied. If in error, please contact the channel founder.')
コード例 #2
0
def kick(bot, trigger):
    """Kick a user from the channel."""
    chanops = get_chanops(bot, trigger)
    if bot.channels[trigger.sender].privileges[
            bot.nick] < OP and trigger.nick in chanops:
        bot.say('doing...')
        bot.say('op ' + trigger.sender, 'ChanServ')
        time.sleep(1)
    text = trigger.group().split()
    argc = len(text)
    if argc < 2:
        return
    opt = Identifier(text[1])
    nick = opt
    channel = trigger.sender
    reasonidx = 2
    if not opt.is_nick():
        if argc < 3:
            return
        nick = text[2]
        channel = opt
        reasonidx = 3
    reason = ' '.join(text[reasonidx:])
    if nick != bot.config.core.nick and trigger.nick in chanops:
        bot.write(['KICK', channel, nick, ':' + reason])
    else:
        bot.reply('Log in as a Channel Operator to change this setting')
コード例 #3
0
ファイル: adminchannel.py プロジェクト: atherra/sopel
def kickban(bot, trigger):
    """
    This gives admins the ability to kickban a user.
    The bot must be a Channel Operator for this command to work.
    .kickban [#chan] user1 user!*@* get out of here
    """
    if bot.privileges[trigger.sender][bot.nick] < HALFOP:
        return bot.reply("I'm not a channel operator!")
    text = trigger.group().split()
    argc = len(text)
    if argc < 4:
        return
    opt = Identifier(text[1])
    nick = opt
    mask = text[2]
    reasonidx = 3
    if not opt.is_nick():
        if argc < 5:
            return
        channel = opt
        nick = text[2]
        mask = text[3]
        reasonidx = 4
    reason = ' '.join(text[reasonidx:])
    mask = configureHostMask(mask)
    if mask == '':
        return
    bot.write(['MODE', channel, '+b', mask])
    bot.write(['KICK', channel, nick, ' :', reason])
コード例 #4
0
ファイル: db.py プロジェクト: kwaaak/sopel
 def get_nick_or_channel_value(self, name, key, default=None):
     """Gets the value `key` associated to the nick or channel  `name`."""
     name = Identifier(name)
     if name.is_nick():
         return self.get_nick_value(name, key, default)
     else:
         return self.get_channel_value(name, key, default)
コード例 #5
0
def kick(bot, trigger):
    """Kick a user from the channel."""
    chanops = get_chanops(bot, trigger)
    if bot.channels[trigger.sender].privileges[
            bot.nick] < OP and trigger.account in chanops:
        bot.say('Please wait...')
        bot.say('op ' + trigger.sender, 'ChanServ')
        time.sleep(1)
    text = trigger.group().split()
    argc = len(text)
    if argc < 2:
        return
    opt = Identifier(text[1])
    nick = opt
    channel = trigger.sender
    reasonidx = 2
    if not opt.is_nick():
        if argc < 3:
            return
        nick = text[2]
        channel = opt
        reasonidx = 3
    reason = ' '.join(text[reasonidx:])
    if nick != bot.config.core.nick and trigger.account in chanops:
        bot.write(['KICK', channel, nick, ':' + reason])
    else:
        bot.reply(
            'Access Denied. If in error, please contact the channel founder.')
コード例 #6
0
ファイル: db.py プロジェクト: MirahezeBots/sopel
    def get_nick_or_channel_value(self, name, key, default=None):
        """Get a value from the key-value store for ``name``.

        :param str name: nick or channel whose values to access
        :param str key: the name by which the desired value was saved
        :param mixed default: value to return if ``key`` does not have a value
                              set (optional)
        :raise ~sqlalchemy.exc.SQLAlchemyError: if there is a database error

        .. versionadded:: 7.0

            The ``default`` parameter.

        This is useful for common logic that is shared between both users and
        channels, as it will fetch the appropriate value based on what type of
        ``name`` it is given.

        .. seealso::

            To get a value for a nick specifically, use :meth:`get_nick_value`.

            To get a value for a channel specifically, use
            :meth:`get_channel_value`.

        """
        name = Identifier(name)
        if name.is_nick():
            return self.get_nick_value(name, key, default)
        else:
            return self.get_channel_value(name, key, default)
コード例 #7
0
ファイル: db.py プロジェクト: sopel-irc/sopel
 def get_nick_or_channel_value(self, name, key):
     """Gets the value `key` associated to the nick or channel  `name`."""
     name = Identifier(name)
     if name.is_nick():
         return self.get_nick_value(name, key)
     else:
         return self.get_channel_value(name, key)
コード例 #8
0
ファイル: adminchannel.py プロジェクト: Cnwauche/sopel
def kickban(bot, trigger):
    """
    This gives admins the ability to kickban a user.
    The bot must be a Channel Operator for this command to work.
    .kickban [#chan] user1 user!*@* get out of here
    """
    if bot.privileges[trigger.sender][bot.nick] < HALFOP:
        return bot.reply("I'm not a channel operator!")
    text = trigger.group().split()
    argc = len(text)
    if argc < 4:
        return
    opt = Identifier(text[1])
    nick = opt
    mask = text[2]
    channel = trigger.sender
    reasonidx = 3
    if not opt.is_nick():
        if argc < 5:
            return
        channel = opt
        nick = text[2]
        mask = text[3]
        reasonidx = 4
    reason = ' '.join(text[reasonidx:])
    mask = configureHostMask(mask)
    if mask == '':
        return
    bot.write(['MODE', channel, '+b', mask])
    bot.write(['KICK', channel, nick], reason)
コード例 #9
0
def kickban(bot, trigger):
    """Kick and ban a user from the channel

    The bot must be a channel operator for this command to work.
    """
    if bot.channels[trigger.sender].privileges[bot.nick] < HALFOP:
        return bot.reply("I'm not a channel operator!")
    text = trigger.group().split()
    argc = len(text)
    if argc < 4:
        return
    opt = Identifier(text[1])
    nick = opt
    mask = text[2]
    channel = trigger.sender
    reasonidx = 3
    if not opt.is_nick():
        if argc < 5:
            return
        channel = opt
        nick = text[2]
        mask = text[3]
        reasonidx = 4
    reason = ' '.join(text[reasonidx:])
    mask = configureHostMask(mask)
    if mask == '':
        return
    bot.write(['MODE', channel, '+b', mask])
    bot.write(['KICK', channel, nick], reason)
コード例 #10
0
def unquiet(bot, trigger):
    """Unquiet a user. The bot must be a channel operator for this command to work.
    """
    chanops = get_chanops(bot, trigger)
    if bot.channels[trigger.sender].privileges[
            bot.nick] < OP and trigger.nick in chanops:
        bot.say('doing...')
        bot.say('op ' + trigger.sender, 'ChanServ')
        time.sleep(1)
    text = trigger.group().split()
    argc = len(text)
    if argc < 2:
        return
    opt = Identifier(text[1])
    quietmask = opt
    channel = trigger.sender
    if not opt.is_nick():
        if argc < 3:
            return
        quietmask = text[2]
        channel = opt
    quietmask = configureHostMask(quietmask)
    if quietmask == '':
        return
    if trigger.nick in chanops:
        bot.write(['MODE', channel, '-q', quietmask])
    else:
        bot.reply('Log in as a Channel Operator to change this setting')
コード例 #11
0
def kickban(bot, trigger):
    """Kick and ban a user from the channel. The bot must be a channel operator for this command to work.
    """
    chanops = get_chanops(bot, trigger)
    if bot.channels[trigger.sender].privileges[
            bot.nick] < OP and trigger.nick in chanops:
        bot.say('doing...')
        bot.say('op ' + trigger.sender, 'ChanServ')
        time.sleep(1)
    text = trigger.group().split()
    argc = len(text)
    if argc < 3:
        return
    opt = Identifier(text[1])
    nick = opt
    mask = text[2] if any([s in text[2] for s in "!@*"]) else ''
    channel = trigger.sender
    reasonidx = 3 if mask != '' else 2
    if not opt.is_nick():
        if argc < 5:
            return
        channel = opt
        nick = text[2]
        mask = text[3] if any([s in text[3] for s in "!@*"]) else ''
        reasonidx = 4 if mask != '' else 3
    reason = ' '.join(text[reasonidx:])
    mask = configureHostMask(mask)
    if mask == '':
        mask = nick + '!*@*'
    if trigger.nick in chanops:
        bot.write(['MODE', channel, '+b', mask])
        bot.write(['KICK', channel, nick, ':' + reason])
    else:
        bot.reply('Log in as a Channel Operator to change this setting')
コード例 #12
0
ファイル: coretasks.py プロジェクト: jbrunink/sopel
def track_modes(bot, trigger):
    """Track usermode changes and keep our lists of ops up to date."""
    # Mode message format: <channel> *( ( "-" / "+" ) *<modes> *<modeparams> )
    channel = Identifier(trigger.args[0])
    line = trigger.args[1:]

    # If the first character of where the mode is being set isn't a #
    # then it's a user mode, not a channel mode, so we'll ignore it.
    if channel.is_nick():
        return

    mapping = {
        'v': sopel.module.VOICE,
        'h': sopel.module.HALFOP,
        'o': sopel.module.OP,
        'a': sopel.module.ADMIN,
        'q': sopel.module.OWNER
    }

    modes = []
    for arg in line:
        if len(arg) == 0:
            continue
        if arg[0] in '+-':
            # There was a comment claiming IRC allows e.g. MODE +aB-c foo, but
            # I don't see it in any RFCs. Leaving in the extra parsing for now.
            sign = ''
            modes = []
            for char in arg:
                if char == '+' or char == '-':
                    sign = char
                else:
                    modes.append(sign + char)
        else:
            arg = Identifier(arg)
            for mode in modes:
                priv = bot.channels[channel].privileges.get(arg, 0)
                # Log a warning if the two privilege-tracking data structures
                # get out of sync. That should never happen.
                # This is a good place to verify that bot.channels is doing
                # what it's supposed to do before ultimately removing the old,
                # deprecated bot.privileges structure completely.
                ppriv = bot.privileges[channel].get(arg, 0)
                if priv != ppriv:
                    LOGGER.warning("Privilege data error! Please share Sopel's"
                                   "raw log with the developers, if enabled. "
                                   "(Expected {} == {} for {} in {}.)".format(
                                       priv, ppriv, arg, channel))
                value = mapping.get(mode[1])
                if value is not None:
                    if mode[0] == '+':
                        priv = priv | value
                    else:
                        priv = priv & ~value
                    bot.privileges[channel][arg] = priv
                    bot.channels[channel].privileges[arg] = priv
コード例 #13
0
ファイル: coretasks.py プロジェクト: neonobjclash/sopel
def track_modes(bot, trigger):
    """Track usermode changes and keep our lists of ops up to date."""
    # Mode message format: <channel> *( ( "-" / "+" ) *<modes> *<modeparams> )
    channel = Identifier(trigger.args[0])
    line = trigger.args[1:]

    # If the first character of where the mode is being set isn't a #
    # then it's a user mode, not a channel mode, so we'll ignore it.
    if channel.is_nick():
        return

    mapping = {'v': sopel.module.VOICE,
               'h': sopel.module.HALFOP,
               'o': sopel.module.OP,
               'a': sopel.module.ADMIN,
               'q': sopel.module.OWNER}

    modes = []
    for arg in line:
        if len(arg) == 0:
            continue
        if arg[0] in '+-':
            # There was a comment claiming IRC allows e.g. MODE +aB-c foo, but
            # I don't see it in any RFCs. Leaving in the extra parsing for now.
            sign = ''
            modes = []
            for char in arg:
                if char == '+' or char == '-':
                    sign = char
                else:
                    modes.append(sign + char)
        else:
            arg = Identifier(arg)
            for mode in modes:
                priv = bot.channels[channel].privileges.get(arg, 0)
                # Log a warning if the two privilege-tracking data structures
                # get out of sync. That should never happen.
                # This is a good place to verify that bot.channels is doing
                # what it's supposed to do before ultimately removing the old,
                # deprecated bot.privileges structure completely.
                ppriv = bot.privileges[channel].get(arg, 0)
                if priv != ppriv:
                    LOGGER.warning("Privilege data error! Please share Sopel's"
                                   "raw log with the developers, if enabled. "
                                   "(Expected {} == {} for {} in {}.)"
                                   .format(priv, ppriv, arg, channel))
                value = mapping.get(mode[1])
                if value is not None:
                    if mode[0] == '+':
                        priv = priv | value
                    else:
                        priv = priv & ~value
                    bot.privileges[channel][arg] = priv
                    bot.channels[channel].privileges[arg] = priv
コード例 #14
0
ファイル: votemode.py プロジェクト: aletheist/willie-modules
def votemode(bot, trigger, mode):
    make_user_active(bot, trigger)
    channel = trigger.sender
    account = trigger.account
    if account is None:
        bot.say("You must be authed to use this command")
        return
    if bot.privileges[trigger.sender][bot.nick] < OP:
        return bot.reply("I'm not a channel operator!")
    quota = calculate_quota(bot, trigger, bot.memory['mode_threshold'][mode])
    # This isn't per user but it's probably an OK heuristic
    if datetime.now() - bot.memory['last_vote'] > timedelta(minutes=5):
        clear_votes(bot)
    # Quota is 50% of active users plus one
    if trigger.group(2):
        target = Identifier(str(trigger.group(2)).split()[0].strip().lower())
        if not target.is_nick():
            return bot.reply("That is not a valid nick")
        if target not in bot.privileges[channel]:
            return bot.reply("I don't see %s." % target)
        target_privs = bot.privileges[channel][target]
        if target_privs > 0:
            return bot.reply("You cannot vote" + mode + " privileged users")

        if target in bot.memory['votes'][mode]:
            if str(account) not in bot.memory['votes'][mode][target]:
                bot.memory['votes'][mode][target].append(str(account))
        else:
            bot.memory['votes'][mode][target] = [str(account)]

        bot.reply("Vote recorded. (%s more votes for action)" % str(max(0, quota - len(bot.memory['votes'][mode][target])+1)))

        if len(bot.memory['votes'][mode][target]) > quota:
            bot.memory['vote_methods'][mode](bot, channel, target)
        bot.memory['last_vote'] = datetime.now()
    elif mode == "registered" or mode == "moderated":
        if str(account) not in bot.memory['votes'][mode]:
            bot.memory['votes'][mode].append(str(account))
        else:
            bot.memory['votes'][mode] = [str(account)]
        bot.reply("Vote recorded. (%s more votes for action)" % str(max(0, quota - len(bot.memory['votes'][mode])+1)))
        if len(bot.memory['votes'][mode]) > quota:
            bot.memory['vote_methods'][mode](bot, channel)
        bot.memory['last_vote'] = datetime.now()
    else:
        bot.say("Current active vote%s (%s needed to %s): " % (mode, str(quota + 1), mode))
        for ballot in bot.memory['votes'][mode]:
            bot.say("%s has %s %s votes." % (ballot, len(bot.memory['votes'][mode][ballot]), mode))
        return
コード例 #15
0
def write_log(bot, event, channel):
    if bot.config.chanlogs2.allow_toggle:
        if not bot.db.get_channel_value(channel, 'logging'):
            return

    if not isinstance(channel, Identifier):
        channel = Identifier(channel)

    if channel.is_nick() and not bot.config.chanlogs2.privmsg:
        return  # Don't log if we are configured not to log PMs

    if bot.config.chanlogs2.backend == 'postgres':
        write_db_line(bot, event, channel)
    else:
        write_log_line(bot, event, channel)
コード例 #16
0
def track_modes(bot, trigger):
    """Track usermode changes and keep our lists of ops up to date."""
    # Mode message format: <channel> *( ( "-" / "+" ) *<modes> *<modeparams> )
    channel = Identifier(trigger.args[0])
    line = trigger.args[1:]

    # If the first character of where the mode is being set isn't a #
    # then it's a user mode, not a channel mode, so we'll ignore it.
    if channel.is_nick():
        return

    mapping = {
        'v': sopel.module.VOICE,
        'h': sopel.module.HALFOP,
        'o': sopel.module.OP,
        'a': sopel.module.ADMIN,
        'q': sopel.module.OWNER
    }

    modes = []
    for arg in line:
        if len(arg) == 0:
            continue
        if arg[0] in '+-':
            # There was a comment claiming IRC allows e.g. MODE +aB-c foo, but
            # I don't see it in any RFCs. Leaving in the extra parsing for now.
            sign = ''
            modes = []
            for char in arg:
                if char == '+' or char == '-':
                    sign = char
                else:
                    modes.append(sign + char)
        else:
            arg = Identifier(arg)
            for mode in modes:
                priv = bot.privileges[channel].get(arg, 0)
                value = mapping.get(mode[1])
                if value is not None:
                    if mode[0] == '+':
                        priv = priv | value
                    else:
                        priv = priv & ~value
                    bot.privileges[channel][arg] = priv
コード例 #17
0
ファイル: coretasks.py プロジェクト: duk3luk3/sopel
def track_modes(bot, trigger):
    """Track usermode changes and keep our lists of ops up to date."""
    # Mode message format: <channel> *( ( "-" / "+" ) *<modes> *<modeparams> )
    channel = Identifier(trigger.args[0])
    line = trigger.args[1:]

    # If the first character of where the mode is being set isn't a #
    # then it's a user mode, not a channel mode, so we'll ignore it.
    if channel.is_nick():
        return

    mapping = {
        "v": sopel.module.VOICE,
        "h": sopel.module.HALFOP,
        "o": sopel.module.OP,
        "a": sopel.module.ADMIN,
        "q": sopel.module.OWNER,
    }

    modes = []
    for arg in line:
        if len(arg) == 0:
            continue
        if arg[0] in "+-":
            # There was a comment claiming IRC allows e.g. MODE +aB-c foo, but
            # I don't see it in any RFCs. Leaving in the extra parsing for now.
            sign = ""
            modes = []
            for char in arg:
                if char == "+" or char == "-":
                    sign = char
                else:
                    modes.append(sign + char)
        else:
            arg = Identifier(arg)
            for mode in modes:
                priv = bot.privileges[channel].get(arg, 0)
                value = mapping.get(mode[1])
                if value is not None:
                    if mode[0] == "+":
                        priv = priv | value
                    else:
                        priv = priv & ~value
                    bot.privileges[channel][arg] = priv
コード例 #18
0
ファイル: adminchannel.py プロジェクト: nbanmp/ev1lf0x
def invite(bot, trigger):
    """
    Invite a user to the channel.
    """
    if bot.privileges[trigger.sender][bot.nick] < HALFOP:
        return bot.reply("I'm not a channel operator!")
    text = trigger.group().split()
    argc = len(text)
    if argc < 2:
        return
    opt = Identifier(text[1])
    nick = opt
    channel = trigger.sender
    if not opt.is_nick():
        nick = text[2]
        channel = opt
    invitemask = '$a:' + nick
    bot.write(['MODE', channel, '+I', invitemask])
    bot.msg('ChanServ', 'flags {0} {1} +iV'.format(channel, nick))
    bot.write(['INVITE', nick])
コード例 #19
0
def kick(bot, trigger):
    """Kick a user from the channel."""
    if bot.channels[trigger.sender].privileges[bot.nick] < HALFOP:
        return bot.reply("I'm not a channel operator!")
    text = trigger.group().split()
    argc = len(text)
    if argc < 2:
        return
    opt = Identifier(text[1])
    nick = opt
    channel = trigger.sender
    reasonidx = 2
    if not opt.is_nick():
        if argc < 3:
            return
        nick = text[2]
        channel = opt
        reasonidx = 3
    reason = ' '.join(text[reasonidx:])
    if nick != bot.config.core.nick:
        bot.write(['KICK', channel, nick], reason)
コード例 #20
0
ファイル: adminchannel.py プロジェクト: xnaas/sopel
def kick(bot, trigger):
    """Kick a user from the channel."""
    if bot.channels[trigger.sender].privileges[bot.nick] < plugin.HALFOP:
        bot.reply(ERROR_MESSAGE_NOT_OP)
        return
    text = trigger.group().split()
    argc = len(text)
    if argc < 2:
        return
    opt = Identifier(text[1])
    nick = opt
    channel = trigger.sender
    reasonidx = 2
    if not opt.is_nick():
        if argc < 3:
            return
        nick = text[2]
        channel = opt
        reasonidx = 3
    reason = ' '.join(text[reasonidx:])
    if nick != bot.config.core.nick:
        bot.kick(nick, channel, reason)
コード例 #21
0
def ban(bot, trigger):
    """Ban a user from the channel

    The bot must be a channel operator for this command to work.
    """
    if bot.channels[trigger.sender].privileges[bot.nick] < HALFOP:
        return bot.reply("I'm not a channel operator!")
    text = trigger.group().split()
    argc = len(text)
    if argc < 2:
        return
    opt = Identifier(text[1])
    banmask = opt
    channel = trigger.sender
    if not opt.is_nick():
        if argc < 3:
            return
        channel = opt
        banmask = text[2]
    banmask = configureHostMask(banmask)
    if banmask == '':
        return
    bot.write(['MODE', channel, '+b', banmask])
コード例 #22
0
def unquiet(bot, trigger):
    """Unquiet a user

    The bot must be a channel operator for this command to work.
    """
    if bot.channels[trigger.sender].privileges[bot.nick] < OP:
        return bot.reply("I'm not a channel operator!")
    text = trigger.group().split()
    argc = len(text)
    if argc < 2:
        return
    opt = Identifier(text[1])
    quietmask = opt
    channel = trigger.sender
    if not opt.is_nick():
        if argc < 3:
            return
        quietmask = text[2]
        channel = opt
    quietmask = configureHostMask(quietmask)
    if quietmask == '':
        return
    bot.write(['MODE', channel, '-q', quietmask])
コード例 #23
0
ファイル: adminchannel.py プロジェクト: Cnwauche/sopel
def kick(bot, trigger):
    """
    Kick a user from the channel.
    """
    if bot.privileges[trigger.sender][bot.nick] < HALFOP:
        return bot.reply("I'm not a channel operator!")
    text = trigger.group().split()
    argc = len(text)
    if argc < 2:
        return
    opt = Identifier(text[1])
    nick = opt
    channel = trigger.sender
    reasonidx = 2
    if not opt.is_nick():
        if argc < 3:
            return
        nick = text[2]
        channel = opt
        reasonidx = 3
    reason = ' '.join(text[reasonidx:])
    if nick != bot.config.core.nick:
        bot.write(['KICK', channel, nick], reason)
コード例 #24
0
ファイル: adminchannel.py プロジェクト: Cnwauche/sopel
def unquiet(bot, trigger):
    """
    This gives admins the ability to unquiet a user.
    The bot must be a Channel Operator for this command to work.
    """
    if bot.privileges[trigger.sender][bot.nick] < OP:
        return bot.reply("I'm not a channel operator!")
    text = trigger.group().split()
    argc = len(text)
    if argc < 2:
        return
    opt = Identifier(text[1])
    quietmask = opt
    channel = trigger.sender
    if not opt.is_nick():
        if argc < 3:
            return
        quietmask = text[2]
        channel = opt
    quietmask = configureHostMask(quietmask)
    if quietmask == '':
        return
    bot.write(['MODE', channel, '-q', quietmask])
コード例 #25
0
def kickban(bot, trigger):
    """Kick and ban a user from the channel. The bot must be a channel operator for this command to work.
    """
    chanops = get_chanops(bot, trigger)
    if bot.channels[trigger.sender].privileges[
            bot.nick] < OP and trigger.account in chanops:
        bot.say('Please wait...')
        bot.say('op ' + trigger.sender, 'ChanServ')
        time.sleep(1)
    text = trigger.group().split()
    argc = len(text)
    if argc < 3:
        bot.reply('Syntax is: .kickban <nick> <reason>')
        return
    opt = Identifier(text[1])
    nick = opt
    mask = text[2] if any([s in text[2] for s in "!@*"]) else ''
    channel = trigger.sender
    reasonidx = 3 if mask != '' else 2
    if not opt.is_nick():
        if argc < 5:
            bot.reply('Syntax is: .kickban <nick> <reason>')
            return
        channel = opt
        nick = text[2]
        mask = text[3] if any([s in text[3] for s in "!@*"]) else ''
        reasonidx = 4 if mask != '' else 3
    reason = ' '.join(text[reasonidx:])
    mask = configureHostMask(mask)
    if mask == '':
        mask = nick + '!*@*'
    if trigger.account in chanops:
        bot.write(['MODE', channel, '+b', mask])
        bot.write(['KICK', channel, nick, ':' + reason])
    else:
        bot.reply(
            'Access Denied. If in error, please contact the channel founder.')
コード例 #26
0
def _parse_modes(bot, args, clear=False):
    """Parse MODE message and apply changes to internal state."""
    channel_name = Identifier(args[0])
    if channel_name.is_nick():
        # We don't do anything with user modes
        LOGGER.debug("Ignoring user modes: %r", args)
        return

    channel = bot.channels[channel_name]

    # Unreal 3 sometimes sends an extraneous trailing space. If we're short an
    # arg, we'll find out later.
    if args[-1] == "":
        args.pop()
    # If any args are still empty, that's something we may not be prepared for,
    # but let's continue anyway hoping they're trailing / not important.
    if len(args) < 2 or not all(args):
        LOGGER.debug("The server sent a possibly malformed MODE message: %r",
                     args)

    modestring = args[1]
    params = args[2:]

    mapping = {
        "v": plugin.VOICE,
        "h": plugin.HALFOP,
        "o": plugin.OP,
        "a": plugin.ADMIN,
        "q": plugin.OWNER,
        "y": plugin.OPER,
        "Y": plugin.OPER,
    }

    modes = {}
    if not clear:
        # Work on a copy for some thread safety
        modes.update(channel.modes)

    # Process modes
    sign = ""
    param_idx = 0
    chanmodes = bot.isupport.CHANMODES
    for char in modestring:
        # Are we setting or unsetting
        if char in "+-":
            sign = char
            continue

        if char in chanmodes["A"]:
            # Type A (beI, etc) have a nick or address param to add/remove
            if char not in modes:
                modes[char] = set()
            if sign == "+":
                modes[char].add(params[param_idx])
            elif params[param_idx] in modes[char]:
                modes[char].remove(params[param_idx])
            param_idx += 1
        elif char in chanmodes["B"]:
            # Type B (k, etc) always have a param
            if sign == "+":
                modes[char] = params[param_idx]
            elif char in modes:
                modes.pop(char)
            param_idx += 1
        elif char in chanmodes["C"]:
            # Type C (l, etc) have a param only when setting
            if sign == "+":
                modes[char] = params[param_idx]
                param_idx += 1
            elif char in modes:
                modes.pop(char)
        elif char in chanmodes["D"]:
            # Type D (aciLmMnOpqrRst, etc) have no params
            if sign == "+":
                modes[char] = True
            elif char in modes:
                modes.pop(char)
        elif char in mapping and ("PREFIX" not in bot.isupport
                                  or char in bot.isupport.PREFIX):
            # User privs modes, always have a param
            nick = Identifier(params[param_idx])
            priv = channel.privileges.get(nick, 0)
            value = mapping.get(char)
            if value is not None:
                if sign == "+":
                    priv = priv | value
                else:
                    priv = priv & ~value
                channel.privileges[nick] = priv
            param_idx += 1
        else:
            # Might be in a mode block past A/B/C/D, but we don't speak those.
            # Send a WHO to ensure no user priv modes we're skipping are lost.
            LOGGER.warning(
                "Unknown MODE message, sending WHO. Message was: %r",
                args,
            )
            _send_who(bot, channel_name)
            return

    if param_idx != len(params):
        LOGGER.warning(
            "Too many arguments received for MODE: args=%r chanmodes=%r",
            args,
            chanmodes,
        )

    channel.modes = modes

    LOGGER.info("Updated mode for channel: %s", channel.name)
    LOGGER.debug("Channel %r mode: %r", str(channel.name), channel.modes)
コード例 #27
0
def track_modes(bot, trigger):
    """Track usermode changes and keep our lists of ops up to date."""
    # Mode message format: <channel> *( ( "-" / "+" ) *<modes> *<modeparams> )
    if len(trigger.args) < 3:
        # We need at least [channel, mode, nickname] to do anything useful
        # MODE messages with fewer args won't help us
        LOGGER.info("Received an apparently useless MODE message: {}"
                    .format(trigger.raw))
        return
    # Our old MODE parsing code checked if any of the args was empty.
    # Somewhere around here would be a good place to re-implement that if it's
    # actually necessary to guard against some non-compliant IRCd. But for now
    # let's just log malformed lines to the debug log.
    if not all(trigger.args):
        LOGGER.debug("The server sent a possibly malformed MODE message: {}"
                     .format(trigger.raw))

    # From here on, we will make a (possibly dangerous) assumption that the
    # received MODE message is more-or-less compliant
    channel = Identifier(trigger.args[0])
    # If the first character of where the mode is being set isn't a #
    # then it's a user mode, not a channel mode, so we'll ignore it.
    # TODO: Handle CHANTYPES from ISUPPORT numeric (005)
    # (Actually, most of this function should be rewritten again when we parse
    # ISUPPORT...)
    if channel.is_nick():
        return

    modestring = trigger.args[1]
    nicks = [Identifier(nick) for nick in trigger.args[2:]]

    mapping = {'v': sopel.module.VOICE,
               'h': sopel.module.HALFOP,
               'o': sopel.module.OP,
               'a': sopel.module.ADMIN,
               'q': sopel.module.OWNER}

    # Parse modes before doing anything else
    modes = []
    sign = ''
    for char in modestring:
        # There was a comment claiming IRC allows e.g. MODE +aB-c foo, but it
        # doesn't seem to appear in any RFCs. But modern.ircdocs.horse shows
        # it, so we'll leave in the extra parsing for now.
        if char in '+-':
            sign = char
        elif char in mapping:
            # Filter out unexpected modes and hope they don't have parameters
            modes.append(sign + char)

    # Try to map modes to arguments, after sanity-checking
    if len(modes) != len(nicks) or not all([nick.is_nick() for nick in nicks]):
        # Something fucky happening, like unusual batching of non-privilege
        # modes together with the ones we expect. Way easier to just re-WHO
        # than try to account for non-standard parameter-taking modes.
        _send_who(bot, channel)
        return
    pairs = dict(zip(modes, nicks))

    for (mode, nick) in pairs.items():
        priv = bot.channels[channel].privileges.get(nick, 0)
        # Log a warning if the two privilege-tracking data structures
        # get out of sync. That should never happen.
        # This is a good place to verify that bot.channels is doing
        # what it's supposed to do before ultimately removing the old,
        # deprecated bot.privileges structure completely.
        ppriv = bot.privileges[channel].get(nick, 0)
        if priv != ppriv:
            LOGGER.warning("Privilege data error! Please share Sopel's"
                           "raw log with the developers, if enabled. "
                           "(Expected {} == {} for {} in {}.)"
                           .format(priv, ppriv, nick, channel))
        value = mapping.get(mode[1])
        if value is not None:
            if mode[0] == '+':
                priv = priv | value
            else:
                priv = priv & ~value
            bot.privileges[channel][nick] = priv
            bot.channels[channel].privileges[nick] = priv
コード例 #28
0
ファイル: coretasks.py プロジェクト: Sickmantella/sopel
def _parse_modes(bot, args):
    """Parse MODE message and apply changes to internal state."""
    channel_name = Identifier(args[0])
    if channel_name.is_nick():
        # We don't do anything with user modes
        return
    channel = bot.channels[channel_name]
    # Our old MODE parsing code checked for empty args. This would be a good
    # place to re-implement that if necessary for a non-compliant IRCd, but for
    # now just log malformed lines. After this we'll make a (possibly dangerous)
    # assumption that the MODE message is more-or-less compliant.
    if len(args) < 2 or not all(args):
        LOGGER.debug("The server sent a possibly malformed MODE message: %r",
                     args)

    modestring = args[1]
    params = args[2:]

    mapping = {
        "v": module.VOICE,
        "h": module.HALFOP,
        "o": module.OP,
        "a": module.ADMIN,
        "q": module.OWNER,
        "y": module.OPER,
        "Y": module.OPER,
    }

    # Process modes
    sign = ""
    param_idx = 0
    chanmodes = bot.isupport.CHANMODES
    for char in modestring:
        # Are we setting or unsetting
        if char in "+-":
            sign = char
            continue

        if char in chanmodes["A"]:
            # Type A (beI, etc) have a nick or address param to add/remove
            if char not in channel.modes:
                channel.modes[char] = set()
            if sign == "+":
                channel.modes[char].add(params[param_idx])
            elif params[param_idx] in channel.modes[char]:
                channel.modes[char].remove(params[param_idx])
            param_idx += 1
        elif char in chanmodes["B"]:
            # Type B (k, etc) always have a param
            if sign == "+":
                channel.modes[char] = params[param_idx]
            elif char in channel.modes:
                channel.modes.pop(char)
            param_idx += 1
        elif char in chanmodes["C"]:
            # Type C (l, etc) have a param only when setting
            if sign == "+":
                channel.modes[char] = params[param_idx]
                param_idx += 1
            elif char in channel.modes:
                channel.modes.pop(char)
        elif char in chanmodes["D"]:
            # Type D (aciLmMnOpqrRst, etc) have no params
            if sign == "+":
                channel.modes[char] = True
            elif char in channel.modes:
                channel.modes.pop(char)
        elif char in mapping and ("PREFIX" not in bot.isupport
                                  or char in bot.isupport.PREFIX):
            # User privs modes, always have a param
            nick = Identifier(params[param_idx])
            priv = channel.privileges.get(nick, 0)
            # Log a warning if the two privilege-tracking data structures
            # get out of sync. That should never happen.
            # This is a good place to verify that bot.channels is doing
            # what it's supposed to do before ultimately removing the old,
            # deprecated bot.privileges structure completely.
            ppriv = bot.privileges[channel_name].get(nick, 0)
            if priv != ppriv:
                LOGGER.warning(
                    ("Privilege data error! Please share Sopel's "
                     "raw log with the developers, if enabled. "
                     "(Expected %s == %s for %r in %r)"),
                    priv,
                    ppriv,
                    nick,
                    channel,
                )
            value = mapping.get(char)
            if value is not None:
                if sign == "+":
                    priv = priv | value
                else:
                    priv = priv & ~value
                bot.privileges[channel_name][nick] = priv
                channel.privileges[nick] = priv
            param_idx += 1
        else:
            # Might be in a mode block past A/B/C/D, but we don't speak those.
            # Send a WHO to ensure no user priv modes we're skipping are lost.
            LOGGER.warning(
                "Unknown MODE message, sending WHO. Message was: %r",
                args,
            )
            _send_who(bot, channel_name)
            return