Ejemplo n.º 1
0
def kick(bot, trigger):
    """
    Kick a user from the channel.
    """
    if bot.privileges[trigger.sender][trigger.nick] < OP:
        return
    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.nick:
        bot.write(['KICK', channel, nick, reason])
Ejemplo n.º 2
0
def collectlines(bot, trigger):
    """Create a temporary log of what people say"""

    # Don't log things in PM
    if trigger.is_privmsg:
        return

    # Add a log for the channel and nick, if there isn't already one
    if trigger.sender not in bot.memory['find_lines']:
        bot.memory['find_lines'][trigger.sender] = WillieMemory()
    if Identifier(
            trigger.nick) not in bot.memory['find_lines'][trigger.sender]:
        bot.memory['find_lines'][trigger.sender][Identifier(
            trigger.nick)] = list()

    # Create a temporary list of the user's lines in a channel
    templist = bot.memory['find_lines'][trigger.sender][Identifier(
        trigger.nick)]
    line = trigger.group()
    if line.startswith("s/"):  # Don't remember substitutions
        return
    elif line.startswith("\x01ACTION"):  # For /me messages
        line = line[:-1]
        templist.append(line)
    else:
        templist.append(line)

    del templist[:-10]  # Keep the log to 10 lines per person

    bot.memory['find_lines'][trigger.sender][Identifier(
        trigger.nick)] = templist
Ejemplo n.º 3
0
def ban(bot, trigger):
    """
    This give admins the ability to ban a user.
    The bot must be a Channel Operator for this command to work.
    """
    if bot.privileges[trigger.sender][trigger.nick] < OP:
        return
    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])
    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])
Ejemplo n.º 4
0
def receive_info(bot, trigger):
    if trigger.sender != 'NickServ':
        return

    account = Identifier(trigger.group(2))
    nick = Identifier(trigger.group(1))

    try:
        bot.db.alias_nick(account, nick)
    except ValueError as e:
        try:
            bot.db.alias_nick(nick, account)
        except ValueError as e:
            if nick in force:
                bot.db.merge_nick_groups(account, nick)
                first_id = bot.db.get_nick_id(Identifier(account))
                second_id = bot.db.get_nick_id(Identifier(nick))
                bot.db.execute('UPDATE nicknames SET nick_id = ? WHERE nick_id = ?',
                     [first_id, second_id])
                bot.msg(nick, 'Merged {0} and {1}. If conflicting values were found' \
                    ' between accounts, values from {0} were used.'.format(account, nick))
                del force[nick]
            else:
                extra = ''
                if nick.lower() != account.lower():
                    extra = 'If you wish to merge data' \
                    ' from {0} to {1}, you may do so by using `.alias merge`. Please note that doing so' \
                    ' will overwrite conflicting values with those found in {0}. '.format(account, nick)
                bot.msg(nick, 'Sorry, I was unable to alias your nick' \
                    ' to your account -- it might have already been aliased. {1}({0})'.format(e.message, extra))
                return

    bot.msg(nick, 'Successfully aliased ' + nick + ' to account ' + account)
Ejemplo n.º 5
0
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])
Ejemplo n.º 6
0
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])
Ejemplo n.º 7
0
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][trigger.nick] < OP:
        return
    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', opt, '-q', quietmask])
Ejemplo n.º 8
0
def seen(bot, trigger):
    """Reports when and where the user was last seen."""
    if not trigger.group(2):
        bot.say(".seen <nick> - Reports when <nick> was last seen.")
        return
    nick = Identifier(trigger.group(2).strip())
    if nick in seen_dict:
        timestamp = seen_dict[nick]['timestamp']
        channel = seen_dict[nick]['channel']
        message = seen_dict[nick]['message']

        tz = get_timezone(bot.db, bot.config, None, trigger.nick,
                          trigger.sender)
        saw = datetime.datetime.utcfromtimestamp(timestamp)
        timestamp = format_time(bot.db, bot.config, tz, trigger.nick,
                                trigger.sender, saw)

        msg = "I last saw {} at {}".format(nick, timestamp)
        if Identifier(channel) == trigger.sender:
            msg = msg + " in here, saying " + message
        else:
            msg += " in another channel."
        bot.say(str(trigger.nick) + ': ' + msg)
    else:
        bot.say("Sorry, I haven't seen %s around." % nick)
Ejemplo n.º 9
0
def test_get_nick_id(db):
    conn = sqlite3.connect(db_filename)
    tests = [
        [None, 'embolalia', Identifier('Embolalia')],
        # Ensures case conversion is handled properly
        [None, '[][]', Identifier('[]{}')],
        # Unicode, just in case
        [None, 'embölaliå', Identifier('EmbölaliÅ')],
    ]

    for test in tests:
        test[0] = db.get_nick_id(test[2])
        nick_id, slug, nick = test
        with conn:
            cursor = conn.cursor()
            registered = cursor.execute(
                'SELECT nick_id, slug, canonical FROM nicknames WHERE canonical IS ?',
                [nick]).fetchall()
            assert len(registered) == 1
            assert registered[0][1] == slug and registered[0][2] == nick

    # Check that each nick ended up with a different id
    assert len(set(test[0] for test in tests)) == len(tests)

    # Check that the retrieval actually is idempotent
    for test in tests:
        nick_id = test[0]
        new_id = db.get_nick_id(test[2])
        assert nick_id == new_id

    # Even if the case is different
    for test in tests:
        nick_id = test[0]
        new_id = db.get_nick_id(Identifier(test[2].upper()))
        assert nick_id == new_id
Ejemplo n.º 10
0
def bomb_glue(bot, trigger):
    old = trigger.nick
    new = Identifier(trigger)
    with lock:
        if old.lower() in BOMBS:
            BOMBS[new.lower()] = BOMBS.pop(old.lower())
            bot.notice("There's still a bomb in your pants, %s!" % new, new)
Ejemplo n.º 11
0
 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)
Ejemplo n.º 12
0
 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)
Ejemplo n.º 13
0
Archivo: db.py Proyecto: dkg/willie
 def get_nick_value(self, nick, key):
     """Retrieves the value for a given key associated with a nick."""
     nick = Identifier(nick)
     result = self.execute(
         'SELECT value FROM nicknames, nick_values WHERE slug = ? AND key = ?',
         [nick.lower(), key]).fetchone()
     if result is not None:
         result = result[0]
     return _deserialize(result)
Ejemplo n.º 14
0
def get_count(bot, user, chan):
    chan_count = bot.memory['pls_count']
    # only do something if there is conversation to work with
    if chan not in chan_count:
        return 0
    if Identifier(user) not in chan_count[chan]:
        return 0

    return chan_count[chan][Identifier(user)]
Ejemplo n.º 15
0
def start(bot, trigger):
    """
    Put a bomb in the specified user's pants. They will be kicked if they
     don't guess the right wire fast enough.
    """
    if not trigger.group(3):
        bot.say("Who do you want to bomb?")
        return NOLIMIT
    if bot.db.get_channel_value(trigger.sender, 'bombs_disabled'):
        bot.notice("An admin has disabled bombing in %s." % trigger.sender, trigger.nick)
        return NOLIMIT
    since_last = time_since_bomb(bot, trigger.nick)
    if since_last < TIMEOUT and not trigger.admin:
        bot.notice("You must wait %.0f seconds before you can bomb someone again." % (TIMEOUT - since_last),
                   trigger.nick)
        return
    global BOMBS
    target = Identifier(trigger.group(3))
    target_unbombable = bot.db.get_nick_value(target, 'unbombable')
    if target == bot.nick:
        bot.say("You thought you could trick me into bombing myself?!")
        return NOLIMIT
    if target == trigger.nick:
        bot.say("%s pls. Bomb a friend if you have to!" % trigger.nick)
        return NOLIMIT
    if target.lower() not in bot.privileges[trigger.sender.lower()]:
        bot.say("You can't bomb imaginary people!")
        return NOLIMIT
    if target_unbombable and not trigger.admin:
        bot.say("I'm not allowed to bomb %s, sorry." % target)
        return NOLIMIT
    if bot.db.get_nick_value(trigger.nick, 'unbombable'):
        bot.say("Try again when you're bombable yourself, %s." % trigger.nick)
        return NOLIMIT
    with lock:
        if target.lower() in BOMBS:
            bot.say("I can't fit another bomb in %s's pants!" % target)
            return NOLIMIT
        wires = [COLORS[i] for i in sorted(sample(xrange(len(COLORS)), randrange(3, 5)))]
        num_wires = len(wires)
        wires_list = [formatting.color(str(wire), str(wire)) for wire in wires]
        wires_list = ", ".join(wires_list[:-2] + [" and ".join(wires_list[-2:])]).replace('Light_', '')
        wires = [wire.replace('Light_', '') for wire in wires]
        color = choice(wires)
        bot.say("Hey, %s! I think there's a bomb in your pants. %s timer, %d wires: %s. "
                "Which wire would you like to cut? (respond with %scutwire color)"
                % (target, FUSE_TEXT, num_wires, wires_list, bot.config.core.help_prefix or '.'))
        bot.notice("Hey, don't tell %s, but it's the %s wire." % (target, color), trigger.nick)
        if target_unbombable:
            bot.notice("Just so you know, %s is marked as unbombable." % target, trigger.nick)
        timer = Timer(FUSE, explode, (bot, trigger))
        BOMBS[target.lower()] = (wires, color, timer, target)
        timer.start()
    bombs_planted = bot.db.get_nick_value(trigger.nick, 'bombs_planted') or 0
    bot.db.set_nick_value(trigger.nick, 'bombs_planted', bombs_planted + 1)
    bot.db.set_nick_value(trigger.nick, 'bomb_last_planted', time.time())
Ejemplo n.º 16
0
 def get_nick_value(self, nick, key):
     """Retrieves the value for a given key associated with a nick."""
     nick = Identifier(nick)
     result = self.execute(
         'SELECT value FROM nicknames, nick_values WHERE slug = ? AND key = ?',
         [nick.lower(), key]
     ).fetchone()
     if result is not None:
         result = result[0]
     return _deserialize(result)
Ejemplo n.º 17
0
    def unalias_nick(self, alias):
        """Removes an alias.

        Raises ValueError if there is not at least one other nick in the group.
        To delete an entire group, use `delete_group`.
        """
        alias = Identifier(alias)
        nick_id = self.get_nick_id(alias, False)
        count = self.execute("SELECT COUNT(*) FROM nicknames WHERE nick_id = ?", [nick_id]).fetchone()[0]
        if count == 0:
            raise ValueError("Given alias is the only entry in its group.")
        self.execute("DELETE FROM nicknames WHERE slug = ?", [alias.lower()])
Ejemplo n.º 18
0
Archivo: db.py Proyecto: whonut/willie
    def unalias_nick(self, alias):
        """Removes an alias.

        Raises ValueError if there is not at least one other nick in the group.
        To delete an entire group, use `delete_group`.
        """
        alias = Identifier(alias)
        nick_id = self.get_nick_id(alias, False)
        count = self.execute('SELECT COUNT(*) FROM nicknames WHERE nick_id = ?',
                             [nick_id]).fetchone()[0]
        if count == 0:
            raise ValueError('Given alias is the only entry in its group.')
        self.execute('DELETE FROM nicknames WHERE slug = ?', [alias.lower()])
Ejemplo n.º 19
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 = Identifier(tellee)

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

    if len(tellee) > 20:
        return bot.reply('That nickname is too long.')
    if tellee == bot.nick:
        return bot.reply("I'm here now, you can tell me whatever you want!")

    if not tellee in (Identifier(teller), bot.nick, 'me'):
        tz = willie.tools.get_timezone(bot.db, bot.config, None, tellee)
        timenow = willie.tools.format_time(bot.db, bot.config, tz, tellee)
        bot.memory['tell_lock'].acquire()
        try:
            if not tellee in bot.memory['reminders']:
                bot.memory['reminders'][tellee] = [(teller, verb, timenow, msg)
                                                   ]
            else:
                bot.memory['reminders'][tellee].append(
                    (teller, verb, timenow, msg))
        finally:
            bot.memory['tell_lock'].release()

        response = "I'll pass that on when %s is around." % tellee

        bot.reply(response)
    elif Identifier(teller) == tellee:
        bot.say('You can %s yourself that.' % verb)
    else:
        bot.say("Hey, I'm not as stupid as Monty you know!")

    dumpReminders(bot.tell_filename, bot.memory['reminders'],
                  bot.memory['tell_lock'])  # @@ tell
Ejemplo n.º 20
0
    def alias_nick(self, nick, alias):
        """Create an alias for a nick.

        Raises ValueError if the alias already exists. If nick does not already
        exist, it will be added along with the alias."""
        nick = Identifier(nick)
        alias = Identifier(alias)
        nick_id = self.get_nick_id(nick)
        sql = "INSERT INTO nicknames (nick_id, slug, canonical) VALUES (?, ?, ?)"
        values = [nick_id, alias.lower(), alias]
        try:
            self.execute(sql, values)
        except sqlite3.IntegrityError as e:
            raise ValueError("Alias already exists.")
Ejemplo n.º 21
0
def receive_info(bot, trigger):
    if trigger.sender != 'NickServ':
        return

    account = Identifier(trigger.group(2))
    nick = Identifier(trigger.group(1))

    try:
        bot.db.alias_nick(account, nick)
    except ValueError as e:
        try:
            bot.db.alias_nick(nick, account)
        except ValueError as e:
            if nick in force:
                bot.db.merge_nick_groups(account, nick)
                first_id = bot.db.get_nick_id(Identifier(account))
                second_id = bot.db.get_nick_id(Identifier(nick))
                bot.db.execute(
                    'UPDATE nicknames SET nick_id = ? WHERE nick_id = ?',
                    [first_id, second_id])
                bot.msg(nick, 'Merged {0} and {1}. If conflicting values were found' \
                    ' between accounts, values from {0} were used.'.format(account, nick))
                del force[nick]
            else:
                extra = ''
                if nick.lower() != account.lower():
                    extra = 'If you wish to merge data' \
                    ' from {0} to {1}, you may do so by using `.alias merge`. Please note that doing so' \
                    ' will overwrite conflicting values with those found in {0}. '.format(account, nick)
                bot.msg(nick, 'Sorry, I was unable to alias your nick' \
                    ' to your account -- it might have already been aliased. {1}({0})'.format(e.message, extra))
                return

    bot.msg(nick, 'Successfully aliased ' + nick + ' to account ' + account)
Ejemplo n.º 22
0
    def alias_nick(self, nick, alias):
        """Create an alias for a nick.

        Raises ValueError if the alias already exists. If nick does not already
        exist, it will be added along with the alias."""
        nick = Identifier(nick)
        alias = Identifier(alias)
        nick_id = self.get_nick_id(nick)
        sql = 'INSERT INTO nicknames (nick_id, slug, canonical) VALUES (?, ?, ?)'
        values = [nick_id, alias.lower(), alias]
        try:
            self.execute(sql, values)
        except sqlite3.IntegrityError as e:
            raise ValueError('Alias already exists.')
Ejemplo n.º 23
0
def watch(bot, trigger):
    """Receive a notification when a user speaks. Use * on the end of [nick] to match multiple nicks (e.g Tell*)"""
    
    if trigger.is_privmsg is False:
        return bot.reply("This command only works in PMs.")
        
    teller = trigger.nick
    verb = trigger.group(1)
    
    if not trigger.group(3):
        bot.reply("%s whom?" % verb)
        return
        
    tellee = trigger.group(3).rstrip('.,:;')
    
    tellee = Identifier(tellee)

    if len(tellee) > 20:
        return bot.reply('That nickname is too long.')
    if tellee == bot.nick or tellee == 'Cashy':
        return bot.reply("[-_-]")

    if not tellee in (Identifier(teller), bot.nick, 'me'):
        timenow = time.time()
        bot.memory['tell_lock'].acquire()
        try:
            if not tellee in bot.memory['tell_dict']:
                bot.memory['tell_dict'][tellee] = [(teller, verb, timenow, '')]
            else:
                found = False
                for (_teller, _verb, _datetime, _msg) in bot.memory['tell_dict'][tellee]:
                    if verb.lower()=='watch':
                        if _teller == teller:
                            found = True
                            break
                if found:
                    return bot.say("You already have me watching for %s." % tellee)
                else:
                    bot.memory['tell_dict'][tellee].append((teller, verb, timenow, ''))
        finally:
            bot.memory['tell_lock'].release()

        bot.reply("I'll let you know when I see %s." % tellee)
    elif Identifier(teller) == tellee:
        bot.say('[-_-]')
    else:
        bot.say("[-_-]")

    storage.put('tell',bot.memory['tell_dict'])
Ejemplo n.º 24
0
def seen(bot, trigger):
    """Reports when and where the user was last seen."""
    if not trigger.group(2):
        bot.say(".seen <nick> - Reports when <nick> was last seen.")
        return
    nick = trigger.group(2).strip()
    timestamp = bot.db.get_nick_value(nick, 'seen_timestamp')
    if timestamp:
        channel = bot.db.get_nick_value(nick, 'seen_channel')
        message = bot.db.get_nick_value(nick, 'seen_message')

        tz = get_timezone(bot.db, bot.config, None, trigger.nick,
                          trigger.sender)
        saw = datetime.datetime.utcfromtimestamp(timestamp)
        timestamp = format_time(bot.db, bot.config, tz, trigger.nick,
                                trigger.sender, saw)

        msg = "I last saw {} at {}".format(nick, timestamp)
        if Identifier(channel) == trigger.sender:
            msg = msg + " in here, saying " + message
        else:
            msg += " in another channel."
        bot.say(str(trigger.nick) + ': ' + msg)
    else:
        bot.say("Sorry, I haven't seen {} around.".format(nick))
Ejemplo n.º 25
0
def check_alias(bot, trigger):
    if not trigger.group(3):
        bot.reply('alias usage: .alias <add|merge|list>')
        return

    if (trigger.group(3).lower() == 'add'):
        bot.write(['PRIVMSG', 'NickServ', ':info', trigger.nick])
        bot.reply('Fetching NickServ info... I will get back to you in a PM')

    elif (trigger.group(3).lower() == 'merge'):
        force[trigger.nick] = True
        bot.write(['PRIVMSG', 'NickServ', ':info', trigger.nick])
        bot.reply('Fetching NickServ info... I will get back to you in a PM')

    elif (trigger.group(3).lower() == 'list'):
        try:
            alias = Identifier(trigger.nick)
            nick_id = bot.db.get_nick_id(alias, False)
            nicks = bot.db.execute(
                'SELECT DISTINCT canonical FROM nicknames WHERE nick_id = ?',
                [nick_id]).fetchall()
            bot.say('{}, your aliases are: {}'.format(
                trigger.nick, ' '.join([nick[0] for nick in nicks])))
        except:
            bot.say(
                'Something went wrong, perhaps you haven\'t aliased any nicks?'
            )
Ejemplo n.º 26
0
def explode(bot, trigger):
    target = Identifier(trigger.group(3))
    orig_target = target
    with lock:
        if target.lower() not in BOMBS:  # nick change happened
            for nick in BOMBS.keys():
                if BOMBS[nick][3] == target:
                    target = Identifier(nick)
                    break
        bot.say("%s pls, you could've at least picked one! Now you're dead. You see that? "
                "Guts, all over the place. (You should've picked the %s wire.)" %
                (target, BOMBS[target.lower()][1]))
        kickboom(bot, trigger, target)
        BOMBS.pop(target.lower())
    timeouts = bot.db.get_nick_value(orig_target, 'bomb_timeouts') or 0
    bot.db.set_nick_value(orig_target, 'bomb_timeouts', timeouts + 1)
Ejemplo n.º 27
0
def test_merge_nick_groups(db):
    conn = sqlite3.connect(db_filename)
    aliases = ['Embolalia', 'Embo']
    for nick_id, alias in enumerate(aliases):
        conn.execute('INSERT INTO nicknames VALUES (?, ?, ?)',
                     [nick_id, Identifier(alias).lower(), alias])
    conn.commit()

    finals = (('foo', 'bar'), ('bar', 'blue'), ('spam', 'eggs'))

    db.set_nick_value(aliases[0], finals[0][0], finals[0][1])
    db.set_nick_value(aliases[0], finals[1][0], finals[1][1])
    db.set_nick_value(aliases[1], 'foo', 'baz')
    db.set_nick_value(aliases[1], finals[2][0], finals[2][1])

    db.merge_nick_groups(aliases[0], aliases[1])

    nick_id = conn.execute('SELECT nick_id FROM nicknames').fetchone()[0]
    alias_id = conn.execute('SELECT nick_id FROM nicknames').fetchone()[0]
    assert nick_id == alias_id

    for key, value in finals:
        found = conn.execute(
            'SELECT value FROM nick_values WHERE nick_id = ? AND key = ?',
            [nick_id, key]).fetchone()[0]
        assert json.loads(unicode(found)) == value
Ejemplo n.º 28
0
 def delete_nick_group(self, nick):
     """Removes a nickname, and all associated aliases and settings.
     """
     nick = Identifier(nick)
     nick_id = self.get_nick_id(nick, False)
     self.execute('DELETE FROM nicknames WHERE nick_id = ?', [nick_id])
     self.execute('DELETE FROM nick_values WHERE nick_id = ?', [nick_id])
Ejemplo n.º 29
0
 def set_nick_value(self, nick, key, value):
     """Sets the value for a given key to be associated with the nick."""
     nick = Identifier(nick)
     value = json.dumps(value, ensure_ascii=False)
     nick_id = self.get_nick_id(nick)
     self.execute('INSERT OR REPLACE INTO nick_values VALUES (?, ?, ?)',
                  [nick_id, key, value])
Ejemplo n.º 30
0
def format_count(bot, trigger):
    if trigger.is_privmsg:
        return

    user = Identifier(trigger.group(2) or trigger.nick)

    user = Identifier(user.strip())

    count = get_count(bot, user, trigger.sender)
    since = bot.memory['pls_count_time']

    timezone = get_timezone(bot.db, bot.config, None, trigger.nick)
    if not timezone:
        timezone = 'UTC'
    time = format_time(bot.db, bot.config, timezone, trigger.nick, trigger.sender, datetime.datetime.fromtimestamp(since))

    bot.say('{} has said pls in {} {} time(s) since {}'.format(user, trigger.sender, count, time))
Ejemplo n.º 31
0
def tell(bot, trigger):
    """Give someone a message the next time they're seen. Use * on the end of [recipient] to match multiple nicks (e.g Tell*)"""
    
    if trigger.is_privmsg is False:
        return bot.reply("This command only works in PMs.")

    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 = Identifier(tellee)

    if len(tellee) > 20:
        return bot.reply('That nickname is too long.')
    if tellee == bot.nick or tellee == 'Cashy':
        return bot.reply("I'm right here.")

    if not tellee in (Identifier(teller), bot.nick, 'me'):
        timenow = time.time()
        bot.memory['tell_lock'].acquire()
        try:
            if not tellee in bot.memory['tell_dict']:
                bot.memory['tell_dict'][tellee] = [(teller, verb, timenow, msg)]
            else:
                bot.memory['tell_dict'][tellee].append((teller, verb, timenow, msg))
        finally:
            bot.memory['tell_lock'].release()

        bot.reply("I'll pass that on when %s is around." % tellee)
    elif Identifier(teller) == tellee:
        bot.say('You can %s yourself that.' % verb)
    else:
        bot.say("[-_-]")

    storage.put('tell',bot.memory['tell_dict'])
Ejemplo n.º 32
0
 def get_channel_value(self, channel, key):
     """Retrieves the value for a given key associated with a channel."""
     channel = Identifier(channel).lower()
     result = self.execute(
         'SELECT value FROM channel_values WHERE channel = ? AND key = ?',
         [channel, key]).fetchone()
     if result is not None:
         result = result[0]
     return _deserialize(result)
Ejemplo n.º 33
0
def promote_karma(bot, trigger):
    """
    Update karma status for specify IRC user if get '++' message.
    """
    if (trigger.is_privmsg):
        return bot.say('People like it when you tell them good things.')
    if (bot.db.get_nick_id(Identifier(trigger.group(1))) == bot.db.get_nick_id(
            Identifier(trigger.nick))):
        return bot.say('You may not give yourself karma!')
    current_karma = bot.db.get_nick_value(trigger.group(1), 'karma')
    if not current_karma:
        current_karma = 0
    else:
        current_karma = int(current_karma)
    current_karma += 1

    bot.db.set_nick_value(trigger.group(1), 'karma', current_karma)
    bot.say(trigger.group(1) + ' == ' + str(current_karma))
Ejemplo n.º 34
0
def demote_karma(bot, trigger):
    """
    Update karma status for specify IRC user if get '--' message.
    """
    if (trigger.is_privmsg):
        return bot.say('Say it to their face!')
    if (bot.db.get_nick_id(Identifier(trigger.group(1))) == bot.db.get_nick_id(
            Identifier(trigger.nick))):
        return bot.say('You may not reduce your own karma!')
    current_karma = bot.db.get_nick_value(trigger.group(1), 'karma')
    if not current_karma:
        current_karma = 0
    else:
        current_karma = int(current_karma)
    current_karma -= 1

    bot.db.set_nick_value(trigger.group(1), 'karma', current_karma)
    bot.say(trigger.group(1) + ' == ' + str(current_karma))
Ejemplo n.º 35
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': willie.module.VOICE,
        'h': willie.module.HALFOP,
        'o': willie.module.OP,
        'a': willie.module.ADMIN,
        'q': willie.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
Ejemplo n.º 36
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": willie.module.VOICE,
        "h": willie.module.HALFOP,
        "o": willie.module.OP,
        "a": willie.module.ADMIN,
        "q": willie.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
Ejemplo n.º 37
0
def test_unalias_nick(db):
    conn = sqlite3.connect(db_filename)
    nick = 'Embolalia'
    nick_id = 42
    conn.execute('INSERT INTO nicknames VALUES (?, ?, ?)',
                 [nick_id, Identifier(nick).lower(), nick])
    aliases = ['EmbölaliÅ', 'Embo`work', 'Embo']
    for alias in aliases:
        conn.execute('INSERT INTO nicknames VALUES (?, ?, ?)',
                     [nick_id, Identifier(alias).lower(), alias])
    conn.commit()

    for alias in aliases:
        db.unalias_nick(alias)

    for alias in aliases:
        found = conn.execute('SELECT * FROM nicknames WHERE nick_id = ?',
                             [nick_id]).fetchall()
        assert len(found) == 1
Ejemplo n.º 38
0
def format_count(bot, trigger):
    if trigger.is_privmsg:
        return

    user = Identifier(trigger.group(2) or trigger.nick)

    user = Identifier(user.strip())

    count = get_count(bot, user, trigger.sender)
    since = bot.memory['pls_count_time']

    timezone = get_timezone(bot.db, bot.config, None, trigger.nick)
    if not timezone:
        timezone = 'UTC'
    time = format_time(bot.db, bot.config, timezone, trigger.nick,
                       trigger.sender, datetime.datetime.fromtimestamp(since))

    bot.say('{} has said pls in {} {} time(s) since {}'.format(
        user, trigger.sender, count, time))
Ejemplo n.º 39
0
 def _nick_blocked(self, nick):
     bad_nicks = self.config.core.get_list('nick_blocks')
     for bad_nick in bad_nicks:
         bad_nick = bad_nick.strip()
         if not bad_nick:
             continue
         if (re.match(bad_nick + '$', nick, re.IGNORECASE)
                 or Identifier(bad_nick) == nick):
             return True
     return False
Ejemplo n.º 40
0
    def merge_nick_groups(self, first_nick, second_nick):
        """Merges the nick groups for the specified nicks.

        Takes two nicks, which may or may not be registered.  Unregistered
        nicks will be registered. Keys which are set for only one of the given
        nicks will be preserved. Where multiple nicks have values for a given
        key, the value set for the first nick will be used.

        Note that merging of data only applies to the native key-value store.
        If modules define their own tables which rely on the nick table, they
        will need to have their merging done separately."""
        first_id = self.get_nick_id(Identifier(first_nick))
        second_id = self.get_nick_id(Identifier(second_nick))
        self.execute(
            'UPDATE OR IGNORE nick_values SET nick_id = ? WHERE nick_id = ?',
            [first_id, second_id])
        self.execute('DELETE FROM nick_values WHERE nick_id = ?', [second_id])
        self.execute('UPDATE nicknames SET nick_id = ? WHERE nick_id = ?',
                     [first_id, second_id])
Ejemplo n.º 41
0
def track_nicks(bot, trigger):
    """Track nickname changes and maintain our chanops list accordingly."""
    old = trigger.nick
    new = Identifier(trigger)

    # Give debug mssage, and PM the owner, if the bot's own nick changes.
    if old == bot.nick:
        privmsg = ("Hi, I'm your bot, %s."
                   "Something has made my nick change. "
                   "This can cause some problems for me, "
                   "and make me do weird things. "
                   "You'll probably want to restart me, "
                   "and figure out what made that happen "
                   "so you can stop it happening again. "
                   "(Usually, it means you tried to give me a nick "
                   "that's protected by NickServ.)") % bot.nick
        debug_msg = (
            "Nick changed by server. "
            "This can cause unexpected behavior. Please restart the bot.")
        LOGGER.critical(debug_msg)
        bot.msg(bot.config.core.owner, privmsg)
        return

    for channel in bot.privileges:
        channel = Identifier(channel)
        if old in bot.privileges[channel]:
            value = bot.privileges[channel].pop(old)
            bot.privileges[channel][new] = value

    # Old privilege maintenance
    for channel in bot.halfplus:
        if old in bot.halfplus[channel]:
            bot.del_halfop(channel, old)
            bot.add_halfop(channel, new)
    for channel in bot.ops:
        if old in bot.ops[channel]:
            bot.del_op(channel, old)
            bot.add_op(channel, new)
    for channel in bot.voices:
        if old in bot.voices[channel]:
            bot.del_voice(channel, old)
            bot.add_voice(channel, new)
Ejemplo n.º 42
0
def cutwire(bot, trigger):
    """
    Tells willie to cut a wire when you've been bombed.
    """
    global BOMBS
    target = Identifier(trigger.nick)
    with lock:
        if target.lower() != bot.nick.lower() and target.lower() not in BOMBS:
            bot.say("You can't cut a wire until someone bombs you, %s." % target)
            return
        if not trigger.group(3):
            bot.say("You have to choose a wire to cut.")
            return
        # Remove target from bomb list temporarily
        wires, color, timer, orig_target = BOMBS.pop(target.lower())
        wirecut = trigger.group(3)
        if wirecut.lower() in ('all', 'all!'):
            timer.cancel()  # defuse timer, execute premature detonation
            bot.say("Cutting ALL the wires! (You should've picked the %s wire.)" % color)
            kickboom(bot, trigger, target)
            alls = bot.db.get_nick_value(orig_target, 'bomb_alls') or 0
            bot.db.set_nick_value(orig_target, 'bomb_alls', alls + 1)
        elif wirecut.capitalize() not in wires:
            bot.say("That wire isn't here, %s! You sure you're picking the right one?" % target)
            # Add the target back onto the bomb list
            BOMBS[target.lower()] = (wires, color, timer, orig_target)
        elif wirecut.capitalize() == color:
            bot.say("You did it, %s! I'll be honest, I thought you were dead. "
                    "But nope, you did it. You picked the right one. Well done." % target)
            timer.cancel()  # defuse bomb
            defuses = bot.db.get_nick_value(orig_target, 'bomb_defuses') or 0
            bot.db.set_nick_value(orig_target, 'bomb_defuses', defuses + 1)
        else:
            timer.cancel()  # defuse timer, execute premature detonation
            bot.say("Nope, wrong wire! Aww, now you've gone and killed yourself. "
                    "Wow. Sorry. (You should've picked the %s wire.)" % color)
            kickboom(bot, trigger, target)
            wrongs = bot.db.get_nick_value(orig_target, 'bomb_wrongs') or 0
            bot.db.set_nick_value(orig_target, 'bomb_wrongs', wrongs + 1)
Ejemplo n.º 43
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

    def handle_old_modes(nick, mode):
        #Old mode maintenance. Drop this crap in 5.0.
        if mode[1] == 'o' or mode[1] == 'q' or mode[1] == 'a':
            if mode[0] == '+':
                bot.add_op(channel, nick)
            else:
                bot.del_op(channel, nick)
        elif mode[1] == 'h':  # Halfop
            if mode[0] == '+':
                bot.add_halfop(channel, nick)
            else:
                bot.del_halfop(channel, nick)
        elif mode[1] == 'v':
            if mode[0] == '+':
                bot.add_voice(channel, nick)
            else:
                bot.del_voice(channel, nick)

    mapping = {'v': willie.module.VOICE,
               'h': willie.module.HALFOP,
               'o': willie.module.OP,
               'a': willie.module.ADMIN,
               'q': willie.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
                handle_old_modes(arg, mode)