示例#1
0
    def _process_forward_msg(message, users, channels):
        """
        Обрабатывает информацию в пересланном сообщении (от кого оно и/или из какого канала). Требует дополнительно
        предоставление информации об пользователях/каналах.
        :param message:
        :param users:
        :param channels:
        :return:
        """
        if message.fwd_from.from_id:  # От пользователя
            fwd_user_id = message.fwd_from.from_id
            fwd_user = users[fwd_user_id]
            fwd_user_nickname = display_tg_name(fwd_user.first_name,
                                                fwd_user.last_name)

        if message.fwd_from.channel_id:  # От канала
            fwd_channel_id = message.fwd_from.channel_id
            fwd_channel_title = channels[fwd_channel_id].title

        # Теперь строим
        if message.fwd_from.from_id and message.fwd_from.channel_id:  # Неанонимное сообщение в канале
            fwd_reply = '|Forwarded from [{}] (UID:{}) at [{}] (CID:{})|Views: {}'\
                .format(fwd_user_nickname, fwd_user_id, fwd_channel_title, fwd_channel_id, message.views)
        elif message.fwd_from.from_id:  # Сообщение пользователя
            fwd_reply = '|Forwarded from [{}] (UID:{})'.format(
                fwd_user_nickname, fwd_user_id)
        elif message.fwd_from.channel_id:  # Анонимное сообщение в канале
            fwd_reply = '|Forwarded from [{}] (CID:{})|Views: {}' \
                .format(fwd_channel_title, fwd_channel_id, message.views)

        return fwd_reply
示例#2
0
文件: mtproto.py 项目: vitlav/tg4xmpp
    def _process_forward_msg(self, message):
        """
        Process forward message to find out from what user message is forwarded.
        :param message:
        :param users:
        :param channels:
        :return:
        """
        if message.fwd_from.from_id:  # from user

            usr = self._get_user_information(message.fwd_from.from_id)
            fwd_from = display_tg_name(usr)

        if message.fwd_from.channel_id:  # from channel
            fwd_from = 'Channel {}'.format(message.fwd_from.channel_id)

        # let's construct
        fwd_reply = '|Forwarded from [{}]|'.format(fwd_from)
        return fwd_reply
示例#3
0
文件: mtproto.py 项目: vitlav/tg4xmpp
    def xmpp_update_handler(self, obj):
        """
        Main function: Telegram update handler.
        :param media:
        :return:
        """
        # print("We have received update for <%s>" % self.jid)
        # print(obj)

        # we have received some updates, so we're logined and can get <me> object and start mtd / upd threads #
        if not self.me:
            me = self.get_me()
            self.me = InputPeerUser(me.id, me.access_hash)
            self._media_thread.start()
            self._status_update_thread.start()

        nl = '\n'

        try:

            # message from normal chat #
            if type(obj) in [UpdateShortMessage] and not obj.out:

                fwd_from = self._process_forward_msg(
                    obj) if obj.fwd_from else ''  # process forward messages
                self.gate_send_message(mfrom='u' + str(obj.user_id),
                                       mbody='[MSG {}] {}{}'.format(
                                           obj.id, fwd_from, obj.message))
                usr = self._get_user_information(
                    obj.user_id)  # get peer information
                self.invoke(
                    ReadHistoryRequest(InputPeerUser(usr.id, usr.access_hash),
                                       obj.id))  # delivery report

            # message from normal group #
            if type(obj) in [UpdateShortChatMessage] and not obj.out:
                fwd_from = self._process_forward_msg(
                    obj) if obj.fwd_from else ''  # process forward messages
                usr = self._get_user_information(obj.from_id)
                nickname = display_tg_name(usr)

                # send message
                self.gate_send_message(mfrom='g' + str(obj.chat_id),
                                       mbody='[MSG {}] [User: {}] {}{}'.format(
                                           obj.id, nickname, fwd_from,
                                           obj.message))
                self.invoke(
                    ReadHistoryRequest(InputPeerChat(obj.chat_id), obj.id))

            # message from supergroup or media message #
            if type(obj) in [
                    UpdateNewMessage, UpdateNewChannelMessage,
                    UpdateEditMessage, UpdateEditChannelMessage
            ] and not obj.message.out:

                cid = None
                msg = ''
                fwd_from = ''
                mid = obj.message.id

                # detect message type
                is_user = type(obj.message.to_id) is PeerUser
                is_group = type(obj.message.to_id) is PeerChat
                is_supergroup = type(obj.message.to_id) is PeerChannel

                # detect from id
                if is_user:
                    cid = obj.message.from_id
                    user = self._get_user_information(cid)
                    peer = InputPeerUser(user.id, user.access_hash)
                    prefix = 'u'
                    prefix = 'b' if user.bot else prefix
                elif is_group:
                    cid = obj.message.to_id.chat_id
                    peer = InputPeerChat(cid)
                    prefix = 'g'
                elif is_supergroup:
                    cid = obj.message.to_id.channel_id
                    peer = InputPeerChannel(
                        cid, self.xmpp_gate.tg_dialogs[self.jid]['supergroups']
                        [cid].access_hash) if cid in self.xmpp_gate.tg_dialogs[
                            self.jid]['supergroups'] else None
                    prefix = 's'

                # our message #
                if type(obj.message) == MessageService:
                    obj.message.fwd_from, obj.message.post, obj.message.edit_date, obj.message.media = None, None, None, None
                    msg = self._process_info_msg(obj.message, peer)
                elif type(obj.message) == Message:
                    msg = obj.message.message

                # is forwarded?
                if obj.message.fwd_from:
                    fwd_from = self._process_forward_msg(obj.message)

                # maybe its channel? #
                if obj.message.post:
                    prefix = 'c'

                # get sender information from chat info #
                if not is_user and not obj.message.post:
                    usr = self._get_user_information(obj.message.from_id)
                    nickname = display_tg_name(usr)
                    msg = '[User: {}] {}'.format(nickname, msg)

                # message media #
                if obj.message.media:
                    msg = '{} {}'.format(
                        msg, self._process_media_msg(obj.message.media))

                # edited #
                if obj.message.edit_date:
                    msg = '[Edited] {}'.format(msg)

                # send message #
                self.gate_send_message(prefix + str(cid),
                                       mbody='[MSG {}] {}{}'.format(
                                           mid, fwd_from, msg))

                # delivery report
                if is_supergroup:
                    self.invoke(ReadHistoryChannel(peer, mid))
                else:
                    self.invoke(ReadHistoryRequest(peer, mid))

            # Status Updates #
            if type(obj) is UpdateUserStatus:
                # process status update #
                if type(obj.status) is UserStatusOnline:
                    self._status_updates[str(obj.user_id)] = {
                        'status': None,
                        'message': 'Online'
                    }
                elif type(obj.status) is UserStatusOffline:
                    status = 'away' if datetime.datetime.utcnow(
                    ) - obj.status.was_online < datetime.timedelta(
                        hours=self.xmpp_gate.accounts[
                            self.jid]['status_xa_interval']) else 'xa'
                    self._status_updates[str(obj.user_id)] = {
                        'status':
                        status,
                        'message':
                        localtime(obj.status.was_online).strftime(
                            'Last seen at %H:%M %d/%m/%Y')
                    }
                elif type(obj.status) is UserStatusRecently:
                    self._status_updates[str(obj.user_id)] = {
                        'status': 'dnd',
                        'message': 'Last seen recently'
                    }
                else:
                    pass

        except Exception:
            print('Exception occurs!')
            print(traceback.format_exc())
示例#4
0
文件: mtproto.py 项目: vitlav/tg4xmpp
    def _process_info_msg(self, message, peer):
        """
        Information messages.
        :param message:
        :param users:
        :return:
        """

        msg = ''
        usr = self._get_user_information(message.from_id)
        nickname = display_tg_name(usr)

        # supergroup created #
        if type(message.action) is MessageActionChannelCreate:
            pass

        # group created #
        elif type(message.action) is MessageActionChatCreate:
            pass

        # user added #
        elif type(message.action) is MessageActionChatAddUser:
            added_users = []
            for user_id in message.action.users:
                usr = self._get_user_information(user_id)
                added_users.append(display_tg_name(usr))

            msg = 'User [{}] has just invited [{}]'.format(
                nickname, ','.join(added_users))

        # user exit #
        elif type(message.action) is MessageActionChatDeleteUser:
            usr = self._get_user_information(message.action.user_id)
            msg = 'User [{}] has just left the room'.format(
                display_tg_name(usr))

        # user joined #
        elif type(message.action) is MessageActionChatJoinedByLink:
            usr = self._get_user_information(message.action.user_id)
            msg = 'User [{}] joined the room'.format(display_tg_name(usr))

        # chat name modified #
        elif type(message.action) is MessageActionChatEditTitle:
            msg = 'User [{}] changed title to [{}]'.format(
                nickname, message.action.title)

        # pinned message
        elif type(message.action) is MessageActionPinMessage:
            pinned_mid = message.reply_to_msg_id  # target message
            message_req = self.invoke(GetMessagesRequest(peer, [pinned_mid]))
            if len(message_req.messages) > 0:
                pinned_message = message_req.messages[0].message
                pinned_from = self._get_user_information(
                    message_req.messages[0].from_id)
                msg = 'User [{}] pinned message: [{}]: {}'.format(
                    nickname, display_tg_name(pinned_from), pinned_message)

        # group converted to supergroup
        elif type(message.action) in [
                MessageActionChatMigrateTo, MessageActionChannelMigrateFrom
        ]:
            pass

        return msg
示例#5
0
    def xmpp_update_handler(self, obj):
        print('new update for ' + self.jid)
        print(type(obj), obj.__dict__)
        '''
        Боты
        Сделать запоминание ростера в бд
        Сделать лучше хендлинг ошибок
        Доделать все типы информационных сообщений
        Сделать джойны по линкам в чаты/каналы
        Сделать поиск и добавление пользователей
        Сделать листание истории
        Сделать отправку всех непрочтенных сообщений при входе
        '''

        # Здесь будет очень длинный пиздец ^__^

        nl = '\n' if self.user_options['nl_after_info'] else ''

        try:
            if type(
                    obj
            ) is Updates:  # Какой-то общий тип обновления (всегда большое со списками)
                print('Updates')

                # Делаем разбор пользователей/чатов, которые учавствуют в апдейте
                updates_users = {usr.id: usr for usr in obj.users}
                updates_groups = {}
                updates_channels = {}
                updates_supergroups = {}
                updates_type_channels = {}  # Супегруппы и каналы вместе

                for chat in obj.chats:
                    if type(chat) is Chat:  # Обычная группа
                        updates_groups[chat.id] = chat
                    elif type(chat) is Channel:
                        if chat.broadcast:  # Канал
                            updates_channels[chat.id] = chat
                        else:  # Супегруппа
                            updates_supergroups[chat.id] = chat
                        updates_type_channels[chat.id] = chat

                # -------------------------------------------------------------------------------------------

                for update in obj.updates:  # Апдейт содержит список с апдейтами
                    # Новое сообщение или отредактированное в супегруппе или канале
                    # А так же отредактированные и новые сообщения с медиа в ЛС и группах
                    if type(update) in [
                            UpdateNewChannelMessage, UpdateEditChannelMessage,
                            UpdateNewMessage, UpdateEditMessage
                    ]:
                        if update.message.out:  # Игнорируем исходящее сообщение
                            return

                        uid = update.message.from_id  # Будет None, если канал, а так же post=True
                        mid = update.message.id
                        cid = None
                        is_post = update.message.post
                        usr = updates_users[uid] if uid else None
                        nickname = display_tg_name(
                            usr.first_name, usr.last_name) if usr else None

                        from_type = 'c' if is_post else 's'
                        msg = ''
                        alt_msg = None
                        edited = ''
                        fwd_reply = ''
                        orig_msg = None

                        is_user = type(update.message.to_id) is PeerUser
                        is_group = type(update.message.to_id) is PeerChat
                        is_supergroup = type(
                            update.message.to_id) is PeerChannel

                        if is_user:
                            cid = update.message.from_id
                        elif is_group:
                            cid = update.message.to_id.chat_id
                        elif is_supergroup:
                            cid = update.message.to_id.channel_id

                        if type(
                                update.message
                        ) is MessageService:  # Сервисные уведомления в чате
                            print('messageService detected')
                            with open(
                                    '/home/sofia/tgdebug/' + str(mid) + '.txt',
                                    'w') as f:
                                f.write(var_dump(obj))
                            ##################################################################
                            alt_msg = self._process_info_msg(
                                update.message, obj.users)
                        else:  # Обычное сообщение в чате
                            msg = update.message.message

                            if update.message.media:
                                print('media detected')
                                #######################################################
                                msg = '[{}] {}'.format(
                                    update.message.media.__class__.__name__,
                                    '{} {}'.format(
                                        self._process_media_msg(
                                            update.message.media), msg))

                            if update.message.reply_to_msg_id:
                                fwd_reply = '|Reply to MID: {}'.format(
                                    update.message.reply_to_msg_id)
                                reply_mid = update.message.reply_to_msg_id
                                orig_msg = self.get_cached_message(
                                    cid, reply_mid, is_user, is_group,
                                    is_supergroup)

                            if update.message.fwd_from:  # Пересланное сообщение
                                fwd_reply = self._process_forward_msg(
                                    update.message, updates_users,
                                    updates_channels)

                        if update.message.edit_date:  # Если новое - отмечаем прочитанным
                            edited = '|Edited'

                        if alt_msg is None:
                            if is_post or type(
                                    update.message.to_id) is PeerUser:
                                header = '[MID:{}{}{}] '.format(
                                    mid, fwd_reply, edited)
                            else:
                                header = '[User: {}|UID:{}|MID:{}{}{}] {}'\
                                    .format(nickname, uid, mid, fwd_reply, edited, nl)

                            alt_msg = '{}{}'.format(header, msg)

                            self.set_cached_message(  # Кэшируем без цитаты
                                cid,
                                mid,
                                alt_msg,
                                user=is_user,
                                group=is_group,
                                supergroup=is_supergroup)

                            if orig_msg is not None:  # Перестраиваем сообщение уже с цитатой
                                alt_msg = '{}> {}\n{}'.format(
                                    header, orig_msg.replace('\n', '\n> '),
                                    msg)

                        if is_user:
                            self.gate_send_message(mfrom='u' + str(cid),
                                                   mbody=alt_msg)

                            if False:  # Зарезервируем рекурсивные цитаты под опцию
                                self.set_cached_message(cid,
                                                        mid,
                                                        alt_msg,
                                                        user=True)

                            if not update.message.edit_date:
                                self.invoke(
                                    ReadHistoryRequest(  # Отмечаем прочитанным
                                        InputPeerUser(usr.id, usr.access_hash),
                                        mid))
                        elif is_group:
                            self.gate_send_message(
                                mfrom='g' + str(update.message.to_id.chat_id),
                                mbody=alt_msg)

                            if False:  # ...
                                self.set_cached_message(cid,
                                                        mid,
                                                        alt_msg,
                                                        group=True)

                            if not update.message.edit_date:
                                self.invoke(
                                    ReadHistoryRequest(InputPeerChat(cid),
                                                       mid))
                        elif is_supergroup:
                            self.gate_send_message(mfrom=from_type + str(cid),
                                                   mbody=alt_msg)

                            if False:  # ...
                                self.set_cached_message(cid,
                                                        mid,
                                                        alt_msg,
                                                        supergroup=True)

                            if not update.message.edit_date:
                                access_hash = updates_type_channels[
                                    cid].access_hash
                                self.invoke(
                                    ReadHistoryChannel(
                                        InputPeerChannel(cid, access_hash),
                                        mid))
                    elif type(
                            update
                    ) is UpdateDeleteChannelMessages:  # Удаленные сообщения в супергруппе/канале
                        channel_id = update.channel_id
                        channel_type = 's'

                        if self.xmpp_gate.tg_dialogs[self.jid]['supergroups'][
                                channel_id].broadcast:  # А может канал?
                            channel_type = 'c'

                        self.gate_send_message(
                            mfrom=channel_type + str(channel_id),
                            mbody='[Deleted messages IDs: {}]'.format(
                                ', '.join(
                                    [str(mid) for mid in update.messages])))
                    elif type(update) is UpdateDeleteMessages:
                        # Этот ивент обновления присылается при удалении сообщения в личном сообщении или группе.
                        # Только id сообщения. Нет информации об диалоге/пользователе/группе.
                        pass

                if type(obj.updates) is list and type(
                        obj.updates[0]) is UpdateChannelTooLong:
                    print('too long')

            # ***^__^***^__^***^__^***^__^***^__^***^__^***^__^***^__^***^__^***^__^***^__^***^__^***^__^***^__^***

            if type(
                    obj
            ) is UpdateShort:  # Тоже какой-то общий тип обновления (всегда маленькое)
                if type(
                        obj.update
                ) is UpdateUserStatus:  # Обновление статуса пользователя в сети Tg
                    print('UpdateUserStatus')

                    if type(obj.update.status) is UserStatusOnline:
                        self.xmpp_gate.send_presence(
                            pto=self.jid,
                            pfrom='u' + str(obj.update.user_id) + '@' +
                            self.xmpp_gate.config['jid'])
                    elif type(obj.update.status) is UserStatusOffline:
                        self.xmpp_gate.send_presence(
                            pto=self.jid,
                            pfrom='u' + str(obj.update.user_id) + '@' +
                            self.xmpp_gate.config['jid'],
                            ptype='xa',
                            pstatus=obj.update.status.was_online.strftime(
                                'Last seen at %H:%M %d/%m/%Y'))
                    elif type(obj.update.status) is UserStatusRecently:
                        self.xmpp_gate.send_presence(
                            pto=self.jid,
                            pfrom='u' + str(obj.update.user_id) + '@' +
                            self.xmpp_gate.config['jid'],
                            pstatus='Last seen recently')
                    else:
                        print(type(obj.update.status))
                        print(obj.update.status.__dict__)

                elif type(
                        obj.update
                ) is UpdateDeleteChannelMessages:  # Удаленное сообщение в супергруппе
                    if obj.update.pts > self._del_pts:  # Фильтруем дубли обновлений
                        channel_id = obj.update.channel_id
                        channel_type = 's'

                        if self.xmpp_gate.tg_dialogs[
                                self.jid]['supergroups'][channel_id].broadcast:
                            channel_type = 'c'

                        msg = '[Deleted messages IDs: {}]'.format(', '.join(
                            [str(mid) for mid in obj.update.messages]))

                        self.gate_send_message(mfrom=channel_type +
                                               str(channel_id),
                                               mbody=msg)

                    self._del_pts = obj.update.pts

            # ***^__^***^__^***^__^***^__^***^__^***^__^***^__^***^__^***^__^***^__^***^__^***^__^***^__^***^__^***

            # Входящее сообщение в ЛС или группу (без медиа вложений)
            if type(obj) in [UpdateShortMessage, UpdateShortChatMessage
                             ] and not obj.out:
                fwd_reply = ''
                nickname = ''

                if type(obj) is UpdateShortChatMessage:
                    # Так как в апдейте есть только ID пользователя, то запрашиваем с сервера информацию о группе
                    if obj.from_id not in self._groups_users:
                        chat_info = self.invoke(GetFullChatRequest(
                            obj.chat_id))

                        for usr in chat_info.users:
                            self._groups_users[usr.id] = usr

                    nickname = display_tg_name(
                        self._groups_users[obj.from_id].first_name,
                        self._groups_users[obj.from_id].last_name)

                if obj.reply_to_msg_id:
                    fwd_reply = '|Reply to MID: {}'.format(obj.reply_to_msg_id)

                if obj.fwd_from:
                    full_update = self.invoke(
                        GetDifferenceRequest(obj.pts - 1, obj.date, -1, 1))

                    fwd_reply = self._process_forward_msg(
                        full_update.new_messages[0],
                        {usr.id: usr
                         for usr in full_update.users}, {})

                if type(obj) is UpdateShortMessage:
                    self.gate_send_message(mfrom='u' + str(obj.user_id),
                                           mbody='[MID:{}{}] {}'.format(
                                               obj.id, fwd_reply, obj.message))

                    if obj.user_id in self.xmpp_gate.tg_dialogs[
                            self.jid]['users']:
                        usr = self.xmpp_gate.tg_dialogs[self.jid]['users'][
                            obj.user_id]
                        self.invoke(
                            ReadHistoryRequest(  # Отмечаем прочитанным
                                InputPeerUser(usr.id, usr.access_hash),
                                obj.id))
                elif type(obj) is UpdateShortChatMessage:
                    self.gate_send_message(
                        mfrom='g' + str(obj.chat_id),
                        mbody='[User: {}|UID:{}|MID:{}{}] {}'.format(
                            nickname, obj.from_id, obj.id, fwd_reply,
                            obj.message))

                    self.invoke(
                        ReadHistoryRequest(InputPeerChat(obj.chat_id), obj.id))

        except Exception:
            print('Exception occurs!')
            print(traceback.format_exc())

        print(' ')
示例#6
0
    def _process_info_msg(message, users):
        """
        Обрабатывает информационные сообщения в групповых чатах. Возвращает готовое для вывода сообщение.
        :param message:
        :param users:
        :return:
        """
        alt_msg = None
        nickname = display_tg_name(users[0].first_name, users[0].last_name)
        uid = users[0].id

        # MessageActionChatEditPhoto

        # Создана супергруппа
        if type(message.action) is MessageActionChannelCreate:
            # Пока нет смысла - поддержка каналов не реализована
            pass
        # Создана группа
        elif type(message.action) is MessageActionChatCreate:
            pass
        # Добавлен пользователь в чат
        elif type(message.action) is MessageActionChatAddUser:
            if len(users) == 2:  # Кто-то добавил другого пользователя
                j_name = display_tg_name(users[1].first_name,
                                         users[1].last_name)
                j_uid = users[1].id
                alt_msg = 'User [{}] (UID:{}) added [{}] (UID:{})'.format(
                    nickname, uid, j_name, j_uid)
            else:  # Пользователь вошел сам
                alt_msg = 'User [{}] (UID:{}) joined'.format(nickname, uid)
        # Пользователь удален/вышел/забанен
        elif type(message.action) is MessageActionChatDeleteUser:
            pass
        # Пользователь вошел по инвайт ссылке
        elif type(message.action) is MessageActionChatJoinedByLink:
            alt_msg = 'User [{}] (UID:{}) joined via invite link'.format(
                nickname, uid)
        # Изменено название чата
        elif type(message.action) is MessageActionChatEditTitle:
            g_title = message.action.title
            alt_msg = 'User [{}] (UID:{}) changed title to [{}]'.format(
                nickname, uid, g_title)
        # Прикреплено сообщение в чате
        elif type(message.action) is MessageActionPinMessage:
            # Notify all members реализовано путем указания, что пользователя упомянули,
            # то есть флаг mentioned=True. Но для транспорта он не имеет смысла.
            p_mid = message.reply_to_msg_id  # Наркоманы
            alt_msg = 'User [{}] (UID:{}) pinned message with MID:{}'.format(
                nickname, uid, p_mid)
        # Группа была преобразована в супергруппу
        elif type(message.action) is MessageActionChatMigrateTo:
            # Это сложный ивент, который ломает текущую реализацию хендлинга
            # (ибо в доках, которых нет, не сказано, что так можно было)
            # Пусть полежит до рефакторинга
            pass
        # Супергруппа была технически создана из группы
        elif type(message.action) is MessageActionChannelMigrateFrom:
            # ---...---...---
            # ---...---...---
            # ---...---...---
            pass

        return alt_msg
示例#7
0
    def tg_process_dialogs(self, jid):
        # Инициализируем словари для диалогов
        self.tg_dialogs[jid] = dict()
        self.tg_dialogs[jid]['raw'] = list()
        self.tg_dialogs[jid]['users'] = dict()
        self.tg_dialogs[jid]['groups'] = dict()
        self.tg_dialogs[jid]['supergroups'] = dict()

        # Оффсеты для получения диалогов
        last_peer = InputPeerEmpty()
        last_msg_id = 0
        last_date = None

        while True:  # В цикле по кускам получаем все диалоги
            dlgs = self.tg_connections[jid].invoke(
                GetDialogsRequest(offset_date=last_date,
                                  offset_id=last_msg_id,
                                  offset_peer=last_peer,
                                  limit=100))

            self.tg_dialogs[jid]['raw'].append(dlgs)

            for usr in dlgs.users:
                self.tg_dialogs[jid]['users'][usr.id] = usr
            for cht in dlgs.chats:
                if type(cht) in [Chat, ChatForbidden]:  # Старая группа
                    self.tg_dialogs[jid]['groups'][cht.id] = cht
                elif type(cht) in [Channel, ChannelForbidden]:  # Супергруппа
                    self.tg_dialogs[jid]['supergroups'][cht.id] = cht

            for dlg in dlgs.dialogs:
                if type(dlg.peer) is PeerUser:
                    usr = self.tg_dialogs[jid]['users'][dlg.peer.user_id]
                    vcard = self.plugin['xep_0054'].make_vcard()
                    u_jid = 'u' + str(usr.id) + '@' + self.boundjid.bare

                    if usr.deleted:
                        vcard['FN'] = 'Deleted account'
                        vcard[
                            'DESC'] = 'This user no longer exists in Telegram'
                    else:
                        vcard['FN'] = display_tg_name(usr.first_name,
                                                      usr.last_name)
                        if usr.first_name:
                            vcard['N']['GIVEN'] = usr.first_name
                        if usr.last_name:
                            vcard['N']['FAMILY'] = usr.last_name
                        if usr.username:
                            vcard[
                                'DESC'] = 'Telegram Username: @' + usr.username

                            if usr.bot:
                                vcard['DESC'] += ' [Bot]'

                        vcard['NICKNAME'] = vcard['FN']

                    vcard['JABBERID'] = u_jid
                    self.plugin['xep_0054'].publish_vcard(jid=u_jid,
                                                          vcard=vcard)
                    self.plugin['xep_0172'].publish_nick(nick=vcard['FN'],
                                                         ifrom=u_jid)

                    self.send_presence(pto=jid, pfrom=u_jid, ptype='subscribe')

                    if usr.bot:
                        self.send_presence(pto=jid, pfrom=u_jid, pstatus='Bot')
                    else:
                        if type(usr.status) is UserStatusOnline:
                            self.send_presence(pto=jid, pfrom=u_jid)
                        elif type(usr.status) is UserStatusRecently:
                            self.send_presence(pto=jid,
                                               pfrom=u_jid,
                                               pshow='away',
                                               pstatus='Last seen recently')
                        elif type(usr.status) is UserStatusOffline:
                            self.send_presence(
                                pto=jid,
                                pfrom=u_jid,
                                ptype='xa',
                                pstatus=usr.status.was_online.strftime(
                                    'Last seen at %H:%M %d/%m/%Y'))
                        else:
                            self.send_presence(
                                pto=jid,
                                pfrom=u_jid,
                                ptype='unavailable',
                                pstatus='Last seen a long time ago')

                if type(dlg.peer) in [PeerChat, PeerChannel]:
                    g_type = ''
                    cht = None

                    if type(dlg.peer) is PeerChat:  # Старая группа
                        cht = self.tg_dialogs[jid]['groups'][dlg.peer.chat_id]
                        c_jid = 'g' + str(cht.id) + '@' + self.boundjid.bare
                        g_type = 'G'
                    elif type(dlg.peer) is PeerChannel:  # Супергруппа
                        cht = self.tg_dialogs[jid]['supergroups'][
                            dlg.peer.channel_id]

                        if cht.broadcast:
                            g_type = 'C'
                            c_jid = 'c' + str(
                                cht.id) + '@' + self.boundjid.bare
                        else:
                            g_type = 'SG'
                            c_jid = 's' + str(
                                cht.id) + '@' + self.boundjid.bare

                    vcard = self.plugin['xep_0054'].make_vcard()
                    vcard['FN'] = '[{}] {}'.format(g_type, cht.title)
                    vcard['NICKNAME'] = vcard['FN']
                    vcard['JABBERID'] = c_jid
                    self.plugin['xep_0054'].publish_vcard(jid=c_jid,
                                                          vcard=vcard)
                    self.plugin['xep_0172'].publish_nick(nick=vcard['FN'],
                                                         ifrom=c_jid)

                    self.send_presence(pto=jid, pfrom=c_jid, ptype='subscribe')
                    self.send_presence(pto=jid, pfrom=c_jid)

            if len(dlgs.dialogs
                   ) == 0:  # Если все диалоги получены - прерываем цикл
                break
            else:  # Иначе строим оффсеты
                last_msg_id = dlgs.dialogs[
                    -1].top_message  # Нужен последний id сообщения. Наркоманы.
                last_peer = dlgs.dialogs[-1].peer

                last_date = next(
                    msg for msg in dlgs.messages  # Ищем дату среди сообщений
                    if type(msg.to_id) is type(last_peer)
                    and msg.id == last_msg_id).date

                if type(last_peer) is PeerUser:  # Пользователь
                    access_hash = self.tg_dialogs[jid]['users'][
                        last_peer.user_id].access_hash
                    last_peer = InputPeerUser(last_peer.user_id, access_hash)
                elif type(last_peer) in [Chat, ChatForbidden]:  # Группа
                    last_peer = InputPeerChat(last_peer.chat_id)
                elif type(last_peer) in [Channel,
                                         ChannelForbidden]:  # Супергруппа
                    access_hash = self.tg_dialogs[jid]['supergroups'][
                        last_peer.channel_id].access_hash
                    last_peer = InputPeerChannel(last_peer.channel_id,
                                                 access_hash)