Exemplo n.º 1
0
    def replyOne(self, message, gen_reply):
        if self.whitelist and getSender(message) not in self.whitelist:
            if getSender(message) > CONF_START:
                return
            if self.users[message['user_id']]['first_name'] + ' ' + self.users[message['user_id']]['last_name'] not in self.whitelist:
                return
        if message['user_id'] == self.self_id:  # chat with myself
            return
        if 'chat_id' in message and not self.checkConf(message['chat_id']):
            return
        try:
            if self.tm.isBusy(getSender(message)) and not self.tm.get(getSender(message)).attr['unimportant']:
                return
        except Exception:
            return
        if message['id'] < self.last_message.bySender(getSender(message)).get('id', 0):
            return

        try:
            ans = gen_reply(message)
        except Exception as e:
            ans = None
            logging.exception('local {}: {}'.format(e.__class__.__name__, str(e)))
            time.sleep(1)
        if ans:
            self.replyMessage(message, ans[0], ans[1])
Exemplo n.º 2
0
def getBotReply(message):
    message['body'] = escape(message['body'])
    raw_answer = bot.interact('{} {} {} | {}'.format(('conf' if message.get('chat_id') else 'user'), message['user_id'], limiter_cache.get(getSender(message)), message['body']))
    if '|' in raw_answer:
        limiters, answer = raw_answer.split('|', maxsplit=1)
    else:
        limiters = ''
        answer = raw_answer
    limiter_cache.add(getSender(message), limiters)

    if answer == '$noans' and not (message.get('_is_sticker') and message.get('chat_id')):
        if (message['body'].upper() == message['body'].lower() and '?' not in message['body']) or message.get('_is_sticker'):
            answer = random.choice(smiles)
        else:
            answer = noans[0]
            next_ans = random.randint(1, len(noans) - 1)
            noans[0], noans[next_ans] = noans[next_ans], noans[0]
    elif answer == '$blacklisted' or answer == '$noans':
        answer = ''

    console_message = ''

    if '{' in answer:
        answer, gender = applyGender(answer, message['user_id'])
        console_message += ' (' + gender + ')'

    while '\\' in answer:
        sticker = _sticker_re.match(answer)
        if sticker:
            console_message += ' (' + answer + ')'
            answer = ''
            message['_sticker_id'] = int(sticker.group(1))
            break
        res = _cmd_re.sub(lambda m: preprocessReply(m.group(1), m.group(2).strip('][').split(']['),
                          message['user_id'], message.setdefault('_onsend_actions', [])), answer)
        console_message += ' (' + answer + ')'
        answer = res

    if '_old_body' not in message:
        message['_old_body'] = message['body']
    if message['_old_body'] and message['_old_body'][0].isdigit() and message['_old_body'] == message['_old_body'].lower():
        message['_old_body'] = ''
    if message['_old_body'] == message['_old_body'].lower() and message['_old_body'] != message['_old_body'].upper():
        last_reply_lower.add(message['user_id'])
        answer = answer.lower()
    elif message['_old_body'].upper() == message['_old_body'].lower() and message['user_id'] in last_reply_lower:
        answer = answer.lower()
    else:
        last_reply_lower.discard(message['user_id'])

    if message.get('_method'):
        console_message += ' (' + message['_method'] + ')'
    text_msg = '({}) {} : {}{}'.format(vk.printableSender(message, False), message['body'], renderSmile(answer), console_message)
    html_msg = '({}) {} : {}{}'.format(vk.printableSender(message, True), html.escape(message['body']), renderSmile(answer).replace('&', '&amp;'),
                                       console_message)
    logging.info(text_msg, extra={'db': html_msg})
    return answer
Exemplo n.º 3
0
    def lastDialogs(self):

        def cb(req, resp):
            d.append((req['peer_id'], resp['count']))

        dialogs = self.api.messages.getDialogs(count=self.stats_dialog_count, preview_length=1)
        d = []
        confs = {}
        try:
            items = list(dialogs['items'])
            for dialog in items:
                if getSender(dialog['message']) in self.banned:
                    continue
                self.api.messages.getHistory.delayed(peer_id=getSender(dialog['message']), count=0).callback(cb)
                if 'title' in dialog['message']:
                    confs[getSender(dialog['message'])] = dialog['message']['title']
            self.api.sync()
        except TypeError:
            logging.warning('Unable to fetch dialogs')
            return (None, None, None)
        return (dialogs['count'], d, confs)
Exemplo n.º 4
0
    def lastDialogs(self):
        def cb(req, resp):
            if resp:
                d.append((req['peer_id'], resp['count']))

        dialogs = self.api.messages.getDialogs(count=self.stats_dialog_count,
                                               preview_length=1)
        d = []
        confs = {}
        try:
            items = list(dialogs['items'])
            for dialog in items:
                if getSender(dialog['message']) in self.banned:
                    continue
                self.api.messages.getHistory.delayed(peer_id=getSender(
                    dialog['message']),
                                                     count=0).callback(cb)
                if 'title' in dialog['message']:
                    confs[getSender(
                        dialog['message'])] = dialog['message']['title']
            self.confs.load([i - CONF_START for i in confs])
            invited = {}
            for i in confs:
                if self.confs[i - CONF_START] and self.confs[
                        i - CONF_START].get('invited_by'):
                    invited[i] = self.confs[i - CONF_START]['invited_by']
            self.users.load(invited.values())
            for i in invited.copy():
                invited[i] = [
                    invited[i],
                    self.printableName(invited[i], '{name}'),
                    self.users[invited[i]]['sex'] == 1
                ]
            self.api.sync()
        except TypeError:
            logging.warning('Unable to fetch dialogs')
            return (None, None, None, None)
        return (dialogs['count'], d, confs, invited)
Exemplo n.º 5
0
    def replyMessage(self, message, answer, skip_mark_as_read=False):
        sender = getSender(message)
        sender_msg = self.last_message.bySender(sender)
        if 'id' in message and message['id'] <= sender_msg.get('id', 0):
            return

        if not answer:
            if self.tm.isBusy(sender):
                return
            if not sender_msg or time.time() - sender_msg['time'] > self.forget_interval:
                tl = Timeline().sleep(self.delay_on_first_reply).do(lambda: self.api.messages.markAsRead(peer_id=sender))
                tl.attr['unimportant'] = True
                self.tm.run(sender, tl, tl.terminate)
            elif answer is None:  # ignored
                self.api.messages.markAsRead.delayed(peer_id=sender, _once=True)
            else:
                tl = Timeline().sleep((self.delay_on_reply - 1) * random.random() + 1).do(lambda: self.api.messages.markAsRead(peer_id=sender))
                tl.attr['unimportant'] = True
                self.tm.run(sender, tl, tl.terminate)
            if answer is not None:
                self.last_message.byUser(message['user_id'])['text'] = message['body']
            self.last_message.updateTime(sender)
            if sender > CONF_START and 'action' not in message:
                sender_msg.setdefault('ignored', {})[message['user_id']] = time.time()
            return

        typing_time = 0
        if not answer.startswith('&#'):
            typing_time = len(answer) / self.chars_per_second

        resend = False
        # answer is not empty
        if sender_msg.get('reply', '').upper() == answer.upper() and sender_msg['user_id'] == message['user_id']:
            logging.info('Resending')
            typing_time = 0
            resend = True

        def _send(attr):
            if not set(sender_msg.get('ignored', [])) <= {message['user_id']}:
                ctime = time.time()
                for uid, ts in sender_msg['ignored'].items():
                    if uid != message['user_id'] and ctime - ts < self.same_conf_interval * 3:
                        attr['reply'] = True
            try:
                if resend:
                    res = self.sendMessage(sender, '', sender_msg['id'])
                elif attr.get('reply'):
                    res = self.sendMessage(sender, answer, message['id'])
                else:
                    res = self.sendMessage(sender, answer)
                if res is None:
                    del self.users[sender]
                    self.logSender('Failed to send a message to %sender%', message)
                    return
                msg = self.last_message.add(sender, message, res, answer)
                if resend:
                    msg['resent'] = True
            except Exception as e:
                logging.exception('thread {}: {}'.format(e.__class__.__name__, str(e)))

        cur_delay = (self.delay_on_reply - 1) * random.random() + 1
        send_time = cur_delay + typing_time
        user_delay = 0
        if sender_msg and sender != self.admin:
            user_delay = sender_msg['time'] - time.time() + (self.same_user_interval if sender < CONF_START else self.same_conf_interval)
            # can be negative
        tl = Timeline(max(send_time, user_delay))
        if 'chat_id' in message:
            tl.attr['user_id'] = message['user_id']
        if not sender_msg or time.time() - sender_msg['time'] > self.forget_interval:
            if not skip_mark_as_read:
                tl.sleep(self.delay_on_first_reply)
                tl.do(lambda: self.api.messages.markAsRead(peer_id=sender))
        else:
            tl.sleepUntil(send_time, (self.delay_on_reply - 1) * random.random() + 1)
            if not skip_mark_as_read:
                tl.do(lambda: self.api.messages.markAsRead(peer_id=sender))

        tl.sleep(cur_delay)
        if message.get('_onsend_actions'):
            for i in message['_onsend_actions']:
                tl.do(i)
                tl.sleep(cur_delay)
        if typing_time:
            tl.doEveryFor(vkapi.utils.TYPING_INTERVAL, lambda: self.api.messages.setActivity(type='typing', user_id=sender), typing_time)
        tl.do(_send, True)
        self.tm.run(sender, tl, tl.terminate)
Exemplo n.º 6
0
def reply(message):
    if getSender(message) in banign.banned or getSender(message) < 0:
        vk.banned_list.append(getSender(message))
        return None
    uid = message['user_id']
    if getSender(message) in friend_controller.noadd or uid in friend_controller.noadd:
        return (None, False)
    if 'deactivated' in vk.users[uid] or vk.users[uid]['blacklisted'] or vk.users[uid]['blacklisted_by_me']:
        return (None, False)

    if 'body' not in message:
        message['body'] = ''
    if message['body'] is None:
        return (None, False)

    if 'id' not in message:  # friendship request
        message['body'] = message['message']
        message['_method'] = 'friendship request'
        return (getBotReply(message), True)

    if isBotMessage(message['body']):
        vk.logSender('(%sender%) {} - ignored (bot message)'.format(message['body']), message)
        if 'chat_id' in message and not vk.no_leave_conf:
            bot_users[uid] = bot_users.get(uid, 0) + 1
            if bot_users[uid] >= 3:
                logging.info('Too many bot messages')
                log.write('conf', vk.loggableConf(message['chat_id']) + ' (bot messages)')
                vk.leaveConf(message['chat_id'])
        return ('', False)
    elif uid in bot_users:
        del bot_users[uid]

    message['body'] = preprocessMessage(message)

    if message['body'] is None:
        return ('', False)

    if message['body']:
        if message.get('_is_sticker') and config.get('vkbot.ignore_stickers', 'b'):
            vk.logSender('(%sender%) {} - ignored'.format(message['body']), message)
            return ('', False)
        if message.get('_is_voice') and 'chat_id' in message:
            vk.logSender('(%sender%) {} - ignored'.format(message['body']), message)
            return ('', False)
        user_msg = vk.last_message.byUser(uid)
        if message['body'] == user_msg.get('text') and message['body'] != '..':
            user_msg['count'] = user_msg.get('count', 0) + 1  # this modifies the cache entry too
            if message.get('_is_voice') and user_msg == vk.last_message.bySender(getSender(message)) and not user_msg.get('resent'):
                vk.logSender('(%sender%) {} - voice again'.format(message['body']), message)
                return (user_msg.get('reply'), False)
            if message.get('_is_sticker'):
                return ('', False)
            if user_msg['count'] == 5:
                noaddUsers([uid], reason='flood')
            elif user_msg['count'] < 5:
                vk.logSender('(%sender%) {} - ignored (repeated)'.format(message['body']), message)
            return ('', False)

        if 'reply' in user_msg and message['body'].upper() == user_msg['reply'].upper() and len(message['body'].split()) > 1:
            vk.logSender('(%sender%) {} - ignored (my reply)'.format(message['body']), message)
            user_msg['text'] = user_msg['reply']  # this modifies the cache entry too
            # user_msg['count'] = 1  # do we need it?
            return ('', False)

        t = evalExpression(message['body'])
        if t:
            if getBotReplyFlat(message['body']):
                return ('', False)
            vk.logSender('(%sender%) {} = {} (calculated)'.format(message['body'], t), message)
            log.write('calc', '{}: "{}" = {}'.format(vk.loggableName(uid), message['body'], t))
            return (t, False)
        tbody = message['body'].replace('<br>', '')
        if tbody.upper() == tbody and sum(i.isalpha() for i in tbody) > 1 and config.get('vkbot.ignore_caps', 'b'):
            vk.logSender('(%sender%) {} - ignored (caps)'.format(message['body']), message)
            return ('', False)

    return (getBotReply(message), False)