Exemple #1
0
def invite_handler(bot, sender, user, channel):
    """Common control logic for invite commands received from anywhere."""
    sender = tools.Identifier(sender)
    user = tools.Identifier(user)
    channel = tools.Identifier(channel)

    # Sanity checks, in case someone reuses this function from outside the plugin
    if not sender.is_nick():
        raise ValueError("Invite sender must be a nick, not a channel.")
    if not user.is_nick():
        raise ValueError("User to invite must be a nick, not a channel.")
    if channel.is_nick():
        raise ValueError("Target channel name must not be a nick.")

    # Sopel must be in the target channel
    if channel not in bot.channels or bot.nick not in bot.channels[channel].privileges:
        return bot.reply("I'm not in {}!".format(channel))

    privs = bot.channels[channel].privileges

    # Sopel must have sufficient privileges in the target channel to send invites
    if privs[bot.nick] < MIN_PRIV:
        return bot.reply("I don't have permission to invite anyone into {}.".format(channel))

    # The sender must be in the target channel
    if sender not in privs:
        return bot.reply("You're not in {}.".format(channel))

    # The sender must have sufficient privileges in the target channel to send invites
    if privs[sender] < MIN_PRIV:
        return bot.reply("You don't have permission to invite anyone into {}.".format(channel))

    # Sopel and the sender both passed permission checks.
    # DDDDOOOO IIIITTTT
    bot.write(['INVITE', user, channel])
Exemple #2
0
def is_self(bot, nick, target):
    nick = tools.Identifier(nick)
    target = tools.Identifier(target)
    if nick == target:
        return True  # shortcut to catch common goofballs
    try:
        nick_id = bot.db.get_nick_id(nick, False)
        target_id = bot.db.get_nick_id(target, False)
    except ValueError:
        return False  # if either nick doesn't have an ID, they can't be in a group
    return nick_id == target_id
Exemple #3
0
def f_remind(bot, trigger):
    """Give someone a message the next time they're seen"""
    teller = trigger.nick
    verb = trigger.group(1)

    if not trigger.group(3):
        bot.reply("%s whom?" % verb)
        return

    tellee = trigger.group(3).rstrip('.,:;')
    msg = trigger.group(2).lstrip(tellee).lstrip()

    if not msg:
        bot.reply("%s %s what?" % (verb, tellee))
        return

    tellee = tools.Identifier(tellee)

    if not os.path.exists(bot.tell_filename):
        return

    if len(tellee) > 30:  # TODO: use server NICKLEN here when available
        bot.reply('That nickname is too long.')
        return

    if tellee[0] == '@':
        tellee = tellee[1:]

    if tellee == bot.nick:
        bot.reply("I'm here now; you can tell me whatever you want!")
        return

    if tellee not in (tools.Identifier(teller), bot.nick, 'me'):
        tz = get_timezone(bot.db, bot.config, None, tellee)
        timenow = format_time(bot.db, bot.config, tz, tellee)
        with bot.memory['tell_lock']:
            if tellee not in bot.memory['reminders']:
                bot.memory['reminders'][tellee] = [(teller, verb, timenow, msg)
                                                   ]
            else:
                bot.memory['reminders'][tellee].append(
                    (teller, verb, timenow, msg))
            # save the reminders
            dump_reminders(bot.tell_filename, bot.memory['reminders'])

        response = "I'll pass that on when %s is around." % tellee
        bot.reply(response)
    elif tools.Identifier(teller) == tellee:
        bot.reply('You can %s yourself that.' % verb)
    else:
        bot.reply("Hey, I'm not as stupid as Monty you know!")
Exemple #4
0
def seen(bot, trigger):
    """Reports when and where the user was last seen."""
    if not trigger.group(2):
        bot.reply("Use `%sseen <nick>` to know when <nick> was last seen." %
                  bot.settings.core.help_prefix)
        return

    nick = trigger.group(2).strip()
    if nick == bot.nick:
        bot.reply("I'm right here!")
        return

    timestamp = bot.db.get_nick_value(nick, 'seen_timestamp')
    if not timestamp:
        bot.reply("Sorry, I haven't seen {nick} around.".format(nick=nick))
        return

    channel = bot.db.get_nick_value(nick, 'seen_channel')
    message = bot.db.get_nick_value(nick, 'seen_message')
    action = bot.db.get_nick_value(nick, 'seen_action')

    saw = datetime.datetime.utcfromtimestamp(timestamp)
    delta = seconds_to_human((trigger.time - saw).total_seconds())

    msg = "I last saw " + nick
    if tools.Identifier(channel) == trigger.sender:
        if action:
            msg += " in here {since}, doing: {nick} {action}".format(
                since=delta, nick=nick, action=message)
        else:
            msg += " in here {since}, saying: {message}".format(
                since=delta, message=message)
    else:
        msg += " in another channel {since}.".format(since=delta)
    bot.say(msg)
def take_comment(bot, trigger):
    """
    Log a comment, to be shown with other comments when a chair uses .comments.
    Intended to allow commentary from those outside the primary group of people
    in the meeting.

    Used in private message only, as `.comment <#channel> <comment to add>`

    See [meetbot module usage]({% link _usage/meetbot-module.md %})
    """
    if not trigger.group(4):  # <2 arguements were given
        bot.say(
            "Usage: {}comment <#channel> <comment to add>".format(
                bot.config.core.help_prefix
            )
        )
        return

    target, message = trigger.group(2).split(None, 1)
    target = tools.Identifier(target)
    if not is_meeting_running(target):
        bot.say("There is no active meeting in that channel.")
    else:
        meetings_dict[trigger.group(3)]["comments"].append((trigger.nick, message))
        bot.say(
            "Your comment has been recorded. It will be shown when the "
            "chairs tell me to show the comments."
        )
        bot.say(
            "A new comment has been recorded.", meetings_dict[trigger.group(3)]["head"]
        )
Exemple #6
0
def insult(bot, trigger):
    """Insults another user."""
    url = "https://evilinsult.com/generate_insult.php"
    params = {"lang": "en", "type": "json"}
    target = trigger.group(3)

    if not target:
        bot.reply("I need someone to insult, dipshit.")
        return
    target = tools.Identifier(target)

    if target == bot.nick:
        bot.reply("Nice try, retard.")
        return

    if target not in bot.channels[trigger.sender].users:
        bot.reply("I need someone to insult, dipshit.")
        return

    try:
        insult = requests.get(url, params=params).json()['insult']
        insult_escaped = html.unescape(insult)
        bot.say("{}: {}".format(target, insult_escaped))
    except:
        bot.reply("There was an error. F**k you.")
Exemple #7
0
def trigger_account(bot):
    line = '@account=egg :[email protected] PRIVMSG #Sopel :Hello, world'
    return Trigger(
        bot.config,
        PreTrigger(tools.Identifier('egg'), line),
        None,
        'egg')
Exemple #8
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.
    """
    text = trigger.group().split()
    argc = len(text)
    if argc < 4:
        return
    opt = tools.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.kick(nick, channel, reason)
Exemple #9
0
def check_money(bot, trigger):
    """Check how much money you or another user has."""
    # We're not using gambling_checks() because it's
    # tuned for most other commands in this plugin.
    # Channel Check
    if trigger.sender == GCHAN:
        pass
    else:
        return bot.reply("This command can only be used in {}".format(GCHAN))

    # Target Check
    target = plain(trigger.group(3) or trigger.nick)
    if not target:
        return bot.reply(
            "If you're seeing this message...everything is horribly broken.")

    target = tools.Identifier(target)

    if target == bot.nick:
        return bot.reply("I just run the place; I don't participate.")
    if target not in bot.channels[trigger.sender].users:
        return bot.reply("Please provide a valid user.")

    # Actual Currency Check
    currency_amount = bot.db.get_nick_value(target, "currency_amount")
    if currency_amount is not None:
        balance = "${:,}".format(currency_amount)
        bot.say("{} has {}".format(target, bold(balance)))
    else:
        bot.say("{} needs to run `.iwantmoney` first.".format(target))
Exemple #10
0
    def __init__(self, settings):
        # private properties: access as read-only properties
        self._nick = tools.Identifier(settings.core.nick)
        self._user = settings.core.user
        self._name = settings.core.name
        self._isupport = ISupport()
        self._myinfo = None

        self.backend = None
        """IRC Connection Backend."""
        self.connection_registered = False
        """Is the IRC Connection registered yet?"""
        self.settings = settings
        """Bot settings."""
        self.enabled_capabilities = set()
        """A set containing the IRCv3 capabilities that the bot has enabled."""
        self._cap_reqs = dict()
        """A dictionary of capability names to a list of requests."""

        # internal machinery
        self.sending = threading.RLock()
        self.last_error_timestamp = None
        self.error_count = 0
        self.stack = {}
        self.hasquit = False
        self.last_raw_line = ''  # last raw line received
Exemple #11
0
def gambling_checks(bot, trigger):
    # Set keys to None for checks
    data = {"bet": None, "msg": None, "target": None}

    # Channel Checker – perhaps make this configurable in the future
    if trigger.sender == GCHAN:
        pass
    else:
        data["msg"] = "This command can only be used in {}".format(GCHAN)
        return data

    # Target Check
    # NOTE: This is not near as "universal" as originally thought out...
    #     Could definitely use some improvement in the future.
    # PROBLEM: This code is basically useless for all of the
    #     actual gambling commands. Unfortunately, just swapping
    #     trigger.group(4) and trigger.nick comes with another set of
    #     issues to deal with.
    target = plain(trigger.group(4) or trigger.nick)
    if not target:
        data["msg"] = "If you're seeing this message...everything is horribly broken."
        return data
    if target == bot.nick:
        data["msg"] = "I just run the place; I don't participate."
        return data
    data["target"] = tools.Identifier(target)

    # "Bet" Parsing and Checking
    # We're calling everything a "bet" for simplicity.
    # Many commands below don't involve betting.
    try:
        bet = plain(trigger.group(3).replace(",", "").replace("$", ""))
        if bet.isdigit():
            data["bet"] = int(bet)
    except AttributeError:
        bet = None
    if not bet:
        data["msg"] = "I need an amount of money."
        return data
    else:
        try:
            # Checks for bets made with letters
            # Large thanks to @Nachtalb
            match = re.match("([\\d.]+)([ckmbt])", bet, re.IGNORECASE)
            # TODO: should be some logic for "all" bet
            calc = {
                "C": 1e2, "c": 1e2,
                "K": 1e3, "k": 1e3,
                "M": 1e6, "m": 1e6,
                "B": 1e9, "b": 1e9,
                "T": 1e12, "t": 1e12
            }
            num, size = match.groups()
            data["bet"] = int(float(num) * calc[size])
        except (AttributeError, ValueError):
            data["msg"] = "I need an amount of money."
            return data

    # return keys: 'msg', 'target', and 'bet'
    return data
Exemple #12
0
def literal_dick_measuring(bot, trigger):
    """100% accurate penis measuring."""
    target = trigger.group(3) or trigger.nick

    if not target:
        bot.reply("How in the hell did you do this?")
        return

    # Set Case Insensitivity
    target = tools.Identifier(target)

    # Lock in the random state
    state = random.getstate()

    # Check user is in channel
    if target not in bot.channels[trigger.sender].users:
        bot.reply("I need someone in chat to measure. ( ͡° ͜ʖ ͡°)")
        return

    # Get dick length
    if target == bot.nick:
        length = 20
    else:
        random.seed(str(target).lower())
        length = random.randint(0, 10)

    dick_length = "8{}D".format("=" * length)

    # Restore random state
    random.setstate(state)

    # Tell user their dick length
    bot.say("{}'s dick size: {}".format(target, dick_length))
def test_bot_legacy_permissions(configfactory, botfactory, triggerfactory):
    """
    Make sure permissions match after being updated from both RPL_NAMREPLY
    and RPL_WHOREPLY, #1482
    """
    mockbot = botfactory(configfactory('default.cfg', TMP_CONFIG))
    nick = tools.Identifier("Admin")

    # RPL_NAMREPLY
    mockwrapper = triggerfactory.wrapper(
        mockbot, ":test.example.com 353 Foo = #test :Foo ~@Admin")
    coretasks.handle_names(mockwrapper, mockwrapper._trigger)

    assert '#test' in mockbot.channels
    assert nick in mockbot.channels["#test"].privileges

    assert '#test' in mockbot.privileges
    assert nick in mockbot.privileges["#test"]

    channel_privileges = mockbot.channels["#test"].privileges[nick]
    privileges = mockbot.privileges["#test"][nick]

    assert channel_privileges == privileges

    # RPL_WHOREPLY
    mockwrapper = triggerfactory.wrapper(
        mockbot, ":test.example.com 352 Foo #test "
        "~Admin adminhost test.example.com Admin Hr~ :0 Admin")
    coretasks.recv_who(mockwrapper, mockwrapper._trigger)

    channel_privileges = mockbot.channels["#test"].privileges[nick]
    privileges = mockbot.privileges["#test"][nick]

    assert channel_privileges == privileges
    assert mockbot.users.get(nick) is not None
Exemple #14
0
def weather(bot, trigger):
    if not bot.config.climacell.climacell_api_key or bot.config.climacell.climacell_api_key == '':
        return bot.reply(
            "No ClimaCell API key found, please configure this plugin.")
    if not bot.config.climacell.google_api_key or bot.config.climacell.google_api_key == '':
        return bot.reply(
            "No Google API key found, please configure this plugin.")

    location = trigger.group(2)
    if not location:
        latitude = bot.db.get_nick_value(trigger.nick, 'latitude')
        longitude = bot.db.get_nick_value(trigger.nick, 'longitude')
        location = bot.db.get_nick_value(trigger.nick, 'location')
        if not location:
            return bot.say(
                ("I don't know where you live. "
                 "Give me a location, like {pfx}{command} London, "
                 "or tell me where you live by saying {pfx}setlocation "
                 "London, for example.").format(
                     command=trigger.group(1),
                     pfx=bot.config.core.help_prefix))
    else:
        user_input = trigger.group(2).strip().lower()
        if user_input == "chaz":
            user_input = "capitol hill seattle"
        latitude, longitude, location = get_latlon(
            user_location=user_input,
            api_key=bot.config.climacell.google_api_key,
        )
        if not latitude:
            bot.reply("I couldn't find a location by that name.")
            return NOLIMIT

    api_key = bot.config.climacell.climacell_api_key

    channel_or_nick = tools.Identifier(trigger.nick)
    zone = _get_timezone(latitude, longitude,
                         pendulum.now().int_timestamp,
                         bot.config.climacell.google_api_key)

    bundle = {
        'location': location,
        'latitude': latitude,
        'longitude': longitude,
        'api_key': api_key,
        'fields': ",".join(bot.config.climacell.now_info_items),
        'units': bot.config.climacell.units,
        'tz': zone
    }

    reply = get_weather(bundle)
    if len(repr(reply)) > 475:
        reply = reply.split(' | ')
        div = int(len(reply) / 2)
        bot.say(' | '.join(reply[:div]))
        bot.say(' | '.join(reply[div:]))
        return
    else:
        return bot.say(reply)
Exemple #15
0
    def change_current_nick(self, new_nick):
        """Change the current nick without configuration modification.

        :param str new_nick: new nick to be used by the bot
        """
        self._nick = tools.Identifier(new_nick)
        LOGGER.debug('Sending nick "%s"', self.nick)
        self.backend.send_nick(self.nick)
Exemple #16
0
def verified_nick(bot, nick, channel):
    # Stolen and slightly modified from my sopel-rep plugin
    if not all([nick, channel]):
        # `bot` is always going to be a thing, but `nick` or `channel` could be empty
        # and that means verification should immediately fail
        return ''  # not None; see below

    nick = re.search(r_nick, nick).group(0)
    if not nick:
        return ''  # returning None would mean the returned value can't be compared with ==
    nick = tools.Identifier(nick)
    if nick.lower() not in bot.channels[channel.lower()].privileges:
        if nick.endswith('--'):
            if tools.Identifier(nick[:-2]).lower() in bot.channels[
                    channel.lower()].privileges:
                return tools.Identifier(nick[:-2])
        return ''  # see above
    return nick
Exemple #17
0
def spacex(bot, trigger):
    """Fetches next scheduled SpaceX rocket launch."""

    args = trigger.group(2)
    if args: args = args.split()
    zone = None
    if args:
        tmp_args = args
        for idx, arg in enumerate(tmp_args):
            if arg.strip().lower() == "--utc":
                zone = "UTC"
                args.pop(idx)
    channel_or_nick = tools.Identifier(trigger.nick)
    zone = zone or get_nick_timezone(bot.db, channel_or_nick)
    if not zone:
        channel_or_nick = tools.Identifier(trigger.sender)
        zone = get_channel_timezone(bot.db, channel_or_nick)

    b_url = "https://spacelaunchnow.me/api/3.3.0/launch/upcoming/?format=json&limit=3&search=spacex"
    try:
        data = requests.get(b_url).json()
    except:
        return bot.reply("I couldn't fetch data from the API")

    if not data.get("results"):
        return bot.reply("No results returned from the API")

    if args:
        tmp_args = " ".join(args)
        try:
            parsed_data = _parse_results(data,
                                         "SpaceX",
                                         idx=int(tmp_args.strip()) - 1,
                                         tz=zone)
        except:
            parsed_data = _parse_results(data, "SpaceX", tz=zone)
    else:
        parsed_data = _parse_results(data, "SpaceX", tz=zone)

    for line in parsed_data:
        bot.say(line, max_messages=2)
Exemple #18
0
def unexclude(bot, trigger):
    """
    Re-enable other users' ability to duel you (admins: or another user)
    """
    if not trigger.group(3):
        target = trigger.nick
    else:
        target = tools.Identifier(trigger.group(3))
    if not trigger.admin and target != trigger.nick:
        bot.say("Only bot admins can mark other users as duelable.")
        return
    set_unduelable(bot, target, False)
    bot.say("Enabled duels for %s." % target)
Exemple #19
0
def timely_reset(bot, trigger):
    """Reset a user's timely timer for whatever reason."""
    target = trigger.group(3)

    if not target:
        return bot.reply("I need someone's timely timer to reset.")

    target = tools.Identifier(target)
    if target not in bot.channels[trigger.sender].users:
        return bot.reply("Please provide a valid user.")

    bot.db.delete_nick_value(target, "currency_timely")
    bot.say("{}'s timely timer has been reset.".format(target))
Exemple #20
0
 def kick(self, bot, trigger):
     if trigger.nick != self.owner and not trigger.admin:
         bot.say(STRINGS['CANT_KICK'] % self.owner)
         return
     player = tools.Identifier(trigger.group(3))
     with lock:
         if player not in self.players:
             return
         if player == trigger.nick:
             return self.quit(bot, trigger)
         playernum = self.playerOrder.index(player) + 1
         bot.say(STRINGS['PLAYER_KICK'] % (player, playernum, trigger.nick))
         return self.remove_player(bot, player)
Exemple #21
0
def delete_money(bot, trigger):
    """Bot admin can make it so a user never had any money."""
    # We want to be able to delete money regardless of any checks.
    # Could be the user is gone from the server/channel.
    target = trigger.group(3)

    if not target:
        return bot.reply("I need someone's wealth to eliminate.")

    target = tools.Identifier(target)

    bot.db.delete_nick_value(target, "currency_amount")
    bot.db.delete_nick_value(target, "currency_timely")
    bot.say("{}'s wealth has been deleted from existence.".format(target))
Exemple #22
0
def test_sopel_identifier_memory_channel_str():
    channel = tools.Identifier('#adminchannel')
    memory = tools.SopelIdentifierMemory()
    test_value = 'perfect'

    memory['#adminchannel'] = test_value
    assert channel in memory
    assert '#adminchannel' in memory
    assert '#AdminChannel' in memory
    assert 'adminchannel' not in memory
    assert 'Exirel' not in memory

    assert memory[channel] == test_value
    assert memory['#adminchannel'] == test_value
    assert memory['#AdminChannel'] == test_value
Exemple #23
0
def test_sopel_identifier_memory_id():
    user = tools.Identifier('Exirel')
    memory = tools.SopelIdentifierMemory()
    test_value = 'king'

    memory[user] = test_value
    assert user in memory
    assert 'Exirel' in memory
    assert 'exirel' in memory
    assert 'exi' not in memory
    assert '#channel' not in memory

    assert memory[user] == test_value
    assert memory['Exirel'] == test_value
    assert memory['exirel'] == test_value
Exemple #24
0
def kick(bot, trigger):
    """Kick a user from the channel."""
    text = trigger.group().split()
    argc = len(text)
    if argc < 2:
        return
    opt = tools.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)
Exemple #25
0
def unquiet(bot, trigger):
    """Unquiet a user

    The bot must be a channel operator for this command to work.
    """
    text = trigger.group().split()
    argc = len(text)
    if argc < 2:
        return
    opt = tools.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])
Exemple #26
0
def unban(bot, trigger):
    """Unban a user from the channel

    The bot must be a channel operator for this command to work.
    """
    text = trigger.group().split()
    argc = len(text)
    if argc < 2:
        return
    opt = tools.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])
Exemple #27
0
 def convert_score_file(self, bot):
     scores = {}
     with lock:
         try:
             with open(self.scoreFile, 'r+') as scorefile:
                 for line in scorefile:
                     tokens = line.replace('\n', '').split(' ')
                     if len(tokens) < 4:
                         continue
                     if len(tokens) == 4:
                         tokens.append(0)
                     scores[tools.Identifier(tokens[0])] = {
                         'games':    int(tokens[1]),
                         'wins':     int(tokens[2]),
                         'points':   int(tokens[3]),
                         'playtime': int(tokens[4]),
                     }
         except Exception, e:
             bot.say("Score conversion error: %s" % e)
             return
         else:
Exemple #28
0
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 = tools.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)
Exemple #29
0
    def __init__(self, nick, admin=False, owner=False):
        self.nick = nick
        self.user = "******"

        channel = tools.Identifier("#Sopel")
        self.channels = tools.SopelIdentifierMemory()
        self.channels[channel] = tools.target.Channel(channel)

        self.users = tools.SopelIdentifierMemory()
        self.privileges = tools.SopelMemory()

        self.memory = tools.SopelMemory()
        self.memory['url_callbacks'] = tools.SopelMemory()

        self.config = MockConfig()
        self._init_config()

        self.output = []

        if admin:
            self.config.core.admins = [self.nick]
        if owner:
            self.config.core.owner = self.nick
Exemple #30
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] < plugin.OP:
        bot.reply(ERROR_MESSAGE_NOT_OP)
        return
    text = trigger.group().split()
    argc = len(text)
    if argc < 2:
        return
    opt = tools.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])