[SVN] bump to version 2.0 [UPD] now transport working with telethon 0.15.5 and sleekxmpp 1.3.2 [FIX] fixed everlasting authorization requests. if you got deauth message — ignore it, FROM subscription is enough. [ADD] implemented roster exchange via XEP-0144 [ADD] we will send authorization request when unknown contact sent us a message [ADD] correct presence handling for transport and users [ADD] fixed presence spam (by default, we updating presence once for 60 seconds -- look at `status_update_interval` in mtproto.py) [ADD] we will automatically connect to all actual sessions after transport start
606 lines
27 KiB
Python
606 lines
27 KiB
Python
import sqlite3
|
||
import re
|
||
import sys
|
||
|
||
import sleekxmpp
|
||
from sleekxmpp.componentxmpp import ComponentXMPP
|
||
import xml.etree.ElementTree as ET
|
||
|
||
from telethon.tl.functions.messages import GetDialogsRequest, SendMessageRequest
|
||
from telethon.tl.functions.account import UpdateStatusRequest, GetAuthorizationsRequest
|
||
from telethon.tl.types import InputPeerEmpty, InputPeerUser, InputPeerChat, InputPeerChannel
|
||
from telethon.tl.types import PeerChannel, PeerChat, PeerUser, Chat, ChatForbidden, Channel, ChannelForbidden
|
||
from telethon.tl.types import UserStatusOnline, UserStatusRecently, UserStatusOffline
|
||
from telethon.tl.types import Updates, UpdateShortSentMessage, UpdateMessageID
|
||
from telethon.tl.types.messages import Dialogs, DialogsSlice
|
||
|
||
from telethon.helpers import generate_random_long
|
||
from telethon.errors import SessionPasswordNeededError
|
||
|
||
from xmpp_tg.mtproto import TelegramGateClient
|
||
from xmpp_tg.utils import var_dump, display_tg_name
|
||
import xmpp_tg.monkey # Патчим баги в библиотеках
|
||
|
||
class XMPPTelegram(ComponentXMPP):
|
||
"""
|
||
Класс XMPP компонента транспорта между Telegram и Jabber
|
||
"""
|
||
|
||
def __init__(self, config_dict):
|
||
"""
|
||
Инициализация, подключение плагинов и регистрация событий
|
||
:param config_dict:
|
||
"""
|
||
|
||
ComponentXMPP.__init__(self, config_dict['jid'], config_dict['secret'], config_dict['server'],
|
||
config_dict['port'])
|
||
|
||
self.auto_authorize = True
|
||
self.auto_subscribe = True
|
||
|
||
self.config = config_dict
|
||
self.tg_connections = dict()
|
||
self.tg_phones = dict()
|
||
self.tg_dialogs = dict()
|
||
|
||
self.contact_list = dict()
|
||
|
||
self.db_connection = self.init_database()
|
||
|
||
self.register_plugin('xep_0030') # Service discovery
|
||
self.register_plugin('xep_0054') # VCard-temp
|
||
self.register_plugin('xep_0172') # NickNames
|
||
|
||
self.add_event_handler('message', self.message)
|
||
self.add_event_handler('presence', self.event_presence)
|
||
self.add_event_handler('presence_unsubscribe', self.event_presence_unsub)
|
||
self.add_event_handler('presence_unsubscribed', self.event_presence_unsub)
|
||
self.add_event_handler('got_online', self.handle_online)
|
||
self.add_event_handler('got_offline', self.handle_offline)
|
||
self.add_event_handler('session_start', self.handle_start)
|
||
|
||
self.plugin['xep_0030'].add_identity(
|
||
category='gateway',
|
||
itype='telegram',
|
||
name=self.config['title'],
|
||
node=self.boundjid.node,
|
||
jid=self.boundjid.bare,
|
||
lang='no'
|
||
)
|
||
|
||
vcard = self.plugin['xep_0054'].make_vcard()
|
||
vcard['FN'] = self.config['title']
|
||
vcard['DESC'] = 'Send /help for information'
|
||
self.plugin['xep_0054'].publish_vcard(jid=self.boundjid.bare, vcard=vcard)
|
||
|
||
def __del__(self):
|
||
"""
|
||
Деструктор. Теоретически.
|
||
:return:
|
||
"""
|
||
self.db_connection.close()
|
||
|
||
def handle_start(self, arg):
|
||
"""
|
||
Обработчик события успешного подключения компонента к Jabber серверу
|
||
:param arg:
|
||
:return:
|
||
"""
|
||
users = self.db_connection.execute("SELECT * FROM accounts").fetchall()
|
||
for usr in users:
|
||
print('Sending presence...')
|
||
self.send_presence(pto=usr['jid'], pfrom=self.boundjid.bare, ptype='probe')
|
||
|
||
def message(self, iq):
|
||
"""
|
||
Обработчик входящих сообщений из XMPP
|
||
:param iq:
|
||
:return:
|
||
"""
|
||
jid = iq['from'].bare
|
||
|
||
if iq['to'] == self.config['jid'] and iq['type'] == 'chat': # Пишут транспорту
|
||
if iq['body'].startswith('!'):
|
||
self.process_command(iq)
|
||
else:
|
||
self.gate_reply_message(iq, 'Only commands accepted. Try !help for more info.')
|
||
else: # Пишут в Telegram
|
||
if jid in self.tg_connections and self.tg_connections[jid].is_user_authorized():
|
||
if iq['body'].startswith('!'): # Команда из чата
|
||
print('command received')
|
||
if iq['to'].bare.startswith('u'):
|
||
self.process_chat_user_command(iq)
|
||
elif iq['to'].bare.startswith('g') or iq['to'].bare.startswith('s'):
|
||
self.process_chat_group_command(iq)
|
||
else:
|
||
self.gate_reply_message(iq, 'Error.')
|
||
else: # Обычное сообщение
|
||
print('sent message')
|
||
tg_id = int(iq['to'].node[1:])
|
||
tg_peer = None
|
||
msg = iq['body']
|
||
reply_mid = None
|
||
|
||
if msg.startswith('>'): # Проверка на цитирование
|
||
msg_lines = msg.split('\n')
|
||
matched = re.match(r'>[ ]*(?P<mid>[\d]+)[ ]*', msg_lines[0]).groupdict()
|
||
|
||
if 'mid' in matched: # Если нашли ID сообщения, то указываем ответ
|
||
reply_mid = int(matched['mid'])
|
||
msg = '\n'.join(msg_lines[1:])
|
||
|
||
if iq['to'].bare.startswith('u'): # Обычный пользователь
|
||
tg_peer = InputPeerUser(tg_id, self.tg_dialogs[jid]['users'][tg_id].access_hash)
|
||
elif iq['to'].bare.startswith('g'): # Обычная группа
|
||
tg_peer = InputPeerChat(tg_id)
|
||
elif iq['to'].bare.startswith('s') or iq['to'].bare.startswith('c'): # Супергруппа
|
||
tg_peer = InputPeerChannel(tg_id, self.tg_dialogs[jid]['supergroups'][tg_id].access_hash)
|
||
|
||
print(tg_peer)
|
||
|
||
if tg_peer:
|
||
# Отправляем сообщение и получаем новый апдейт
|
||
result = self.tg_connections[jid].invoke(
|
||
SendMessageRequest(tg_peer, msg, generate_random_long(), reply_to_msg_id=reply_mid)
|
||
)
|
||
msg_id = None
|
||
|
||
# Ищем ID отправленного сообщения
|
||
if type(result) is Updates: # Супегруппа / канал
|
||
for upd in result.updates:
|
||
if type(upd) is UpdateMessageID:
|
||
msg_id = upd.id
|
||
elif type(result) is UpdateShortSentMessage: # ЛС / Группа
|
||
msg_id = result.id
|
||
|
||
# if msg_id:
|
||
# # Отправляем ответ с ID отправленного сообщения
|
||
# self.send_message(mto=iq['from'], mfrom=iq['to'], mtype='chat',
|
||
# mbody='[Your MID:{}]'.format(msg_id))
|
||
|
||
def event_presence_unsub(self, presence):
|
||
print('defense')
|
||
return
|
||
|
||
def event_presence(self, presence):
|
||
"""
|
||
Обработчик события subscribe
|
||
:param presence:
|
||
:return:
|
||
"""
|
||
ptype = presence['type']
|
||
|
||
if ptype == 'subscribe':
|
||
print('Send SUBSCRIBED')
|
||
self.send_presence(pto=presence['from'].bare, pfrom=presence['to'].bare, ptype='subscribed')
|
||
elif ptype == 'subscribed':
|
||
self.send_presence(pto=presence['from'].bare, pfrom=presence['to'].bare, ptype='subscribee')
|
||
pass
|
||
elif ptype == 'unsubscribe':
|
||
pass
|
||
elif ptype == 'unsubscribed':
|
||
pass
|
||
elif ptype == 'probe':
|
||
self.send_presence(pto=presence['from'], pfrom=presence['to'], ptype='available')
|
||
pass
|
||
elif ptype == 'unavailable':
|
||
pass
|
||
else:
|
||
# self.send_presence(pto=presence['from'], pfrom=presence['to'])
|
||
pass
|
||
|
||
def handle_online(self, event):
|
||
"""
|
||
Обработчик события online. Подключается к Telegram при наличии авторизации.
|
||
:param event:
|
||
:return:
|
||
"""
|
||
jid = event['from'].bare
|
||
|
||
if jid not in self.tg_connections:
|
||
result = self.db_connection.execute("SELECT * FROM accounts WHERE jid = ?", (jid,)).fetchone()
|
||
|
||
if result is not None:
|
||
self.spawn_tg_client(jid, result['tg_phone'])
|
||
else:
|
||
if not (self.tg_connections[jid].is_connected()):
|
||
self.tg_connections[jid].connect()
|
||
self.tg_connections[jid].invoke(UpdateStatusRequest(offline=False))
|
||
self.send_presence(pto=jid, pfrom=self.boundjid.bare, ptype='online', pstatus='connected')
|
||
self.tg_process_dialogs(jid)
|
||
|
||
|
||
def handle_offline(self, event):
|
||
"""
|
||
Обработчик события offline. Отключается от Telegram, если было создано подключение.
|
||
:param event:
|
||
:return:
|
||
"""
|
||
jid = event['from'].bare
|
||
|
||
if jid in self.tg_connections:
|
||
self.tg_connections[jid].invoke(UpdateStatusRequest(offline=True))
|
||
self.tg_connections[jid].disconnect()
|
||
|
||
def handle_interrupt(self, signal, frame):
|
||
|
||
for jid in self.tg_connections:
|
||
print('Disconnecting: %s' % jid)
|
||
self.tg_connections[jid].invoke(UpdateStatusRequest(offline=True))
|
||
self.tg_connections[jid].disconnect()
|
||
for contact_jid, contact_nickname in self.contact_list[jid].items():
|
||
self.send_presence(pto=jid, pfrom=contact_jid, ptype='unavailable')
|
||
self.send_presence(pto=jid, pfrom=self.boundjid.bare, ptype='unavailable')
|
||
sys.exit(0)
|
||
|
||
def process_command(self, iq):
|
||
"""
|
||
Обработчик общих команд транспорта
|
||
:param iq:
|
||
:return:
|
||
"""
|
||
parced = iq['body'].split(' ')
|
||
jid = iq['from'].bare
|
||
|
||
if parced[0] == '!help':
|
||
self.gate_reply_message(iq, 'Available command:\n\n'
|
||
'!help - Displays this text\n'
|
||
'!login +123456789 - Initiates Telegram session\n'
|
||
'!code 12345 - Entering one-time code during auth\n'
|
||
'!password abc123 - Entering password during two-factor auth\n'
|
||
'!list_sessions - List all created sessions at Telegram servers\n'
|
||
'!delete_session 123 - Delete session\n'
|
||
'!logout - Deletes current Telegram session at gate\n'
|
||
'!reload_dialogs - Reloads dialogs list from Telegram\n\n'
|
||
'!create_group - Initiates group creation\n'
|
||
'!create_channel - Initiates channel creation\n\n'
|
||
'!change_name first last - Changes your name in Telegram\n'
|
||
'!change_username username - Changes your @username in Telegram\n'
|
||
# '!blocked_users_list\n'
|
||
# '!blocked_users_add\n'
|
||
# '!blocked_users_remove\n'
|
||
# '!last_seen_privacy_status\n'
|
||
# '!last_seen_privacy_set\n'
|
||
# '!last_seen_privacy_never_add\n'
|
||
# '!last_seen_privacy_never_remove\n'
|
||
# '!last_seen_privacy_always_add\n'
|
||
# '!last_seen_privacy_always_remove\n'
|
||
# '!group_invite_settings_status\n'
|
||
# '!group_invite_settings_set\n'
|
||
# '!group_invite_settings_add\n'
|
||
# '!group_invite_settings_remove\n'
|
||
# '!group_invite_settings_add\n'
|
||
# '!group_invite_settings_remove\n'
|
||
# '!account_selfdestruct_setting_status\n'
|
||
# '!account_selfdestruct_setting_set\n'
|
||
)
|
||
elif parced[0] == '!login': # --------------------------------------------------
|
||
self.gate_reply_message(iq, 'Please wait...')
|
||
self.spawn_tg_client(jid, parced[1])
|
||
|
||
if self.tg_connections[jid].is_user_authorized():
|
||
self.send_presence(pto=jid, pfrom=self.boundjid.bare, ptype='online', pstatus='connected')
|
||
self.gate_reply_message(iq, 'You are already authenticated in Telegram.')
|
||
else:
|
||
self.tg_connections[jid].send_code_request(parced[1])
|
||
self.gate_reply_message(iq, 'Gate is connected. Telegram should send SMS message to you.')
|
||
self.gate_reply_message(iq, 'Please enter one-time code via !code 12345.')
|
||
elif parced[0] in ['!code', '!password']: # --------------------------------------------------
|
||
if not self.tg_connections[jid].is_user_authorized():
|
||
if parced[0] == '!code':
|
||
try:
|
||
self.gate_reply_message(iq, 'Trying authenticate...')
|
||
self.tg_connections[jid].sign_in(self.tg_phones[jid], parced[1])
|
||
except SessionPasswordNeededError:
|
||
self.gate_reply_message(iq, 'Two-factor authentication detected.')
|
||
self.gate_reply_message(iq, 'Please enter your password via !password abc123.')
|
||
return
|
||
|
||
if parced[0] == '!password':
|
||
self.gate_reply_message(iq, 'Checking password...')
|
||
self.tg_connections[jid].sign_in(password=parced[1])
|
||
|
||
if self.tg_connections[jid].is_user_authorized():
|
||
self.send_presence(pto=jid, pfrom=self.boundjid.bare, ptype='online', pstatus='connected')
|
||
self.gate_reply_message(iq, 'Authentication successful. Initiating Telegram...')
|
||
self.init_tg(jid)
|
||
self.db_connection.execute("INSERT INTO accounts VALUES(?, ?)", (jid, self.tg_phones[jid],))
|
||
else:
|
||
self.gate_reply_message(iq, 'Authentication failed.')
|
||
else:
|
||
self.gate_reply_message(iq, 'You are already authenticated. Please use !logout before new login.')
|
||
elif parced[0] == '!list_sessions': # --------------------------------------------------
|
||
if not self.tg_connections[jid].is_user_authorized():
|
||
self.gate_reply_message(iq, 'Error.')
|
||
return
|
||
|
||
sessions = self.tg_connections[jid].invoke(GetAuthorizationsRequest())
|
||
print(sessions.__dict__)
|
||
elif parced[0] == '!reload_dialogs':
|
||
if not self.tg_connections[jid].is_user_authorized():
|
||
self.gate_reply_message(iq, 'Error.')
|
||
return
|
||
self.tg_process_dialogs(jid)
|
||
self.gate_reply_message(iq, 'Dialogs reloaded.')
|
||
elif parced[0] == '!logout': # --------------------------------------------------
|
||
self.tg_connections[jid].log_out()
|
||
self.db_connection.execute("DELETE FROM accounts WHERE jid = ?", (jid,))
|
||
self.gate_reply_message(iq, 'Your Telegram session was deleted')
|
||
else: # --------------------------------------------------
|
||
self.gate_reply_message(iq, 'Unknown command. Try !help for list all commands.')
|
||
|
||
def process_chat_user_command(self, iq):
|
||
parced = []
|
||
|
||
if parced[0] == '!search':
|
||
pass
|
||
elif parced[0] == '!get_history':
|
||
pass
|
||
elif parced[0] == '!forward_messages':
|
||
pass
|
||
elif parced[0] == '!delete_messages':
|
||
pass
|
||
elif parced[0] == '!block_status':
|
||
pass
|
||
elif parced[0] == '!block_set':
|
||
pass
|
||
elif parced[0] == '!block_unser':
|
||
pass
|
||
elif parced[0] == '!clear_history':
|
||
pass
|
||
elif parced[0] == '!delete_conversation':
|
||
pass
|
||
elif parced[0] == '!help':
|
||
pass
|
||
|
||
def process_chat_group_command(self, iq):
|
||
parced = []
|
||
|
||
if parced[0] == '!search':
|
||
pass
|
||
elif parced[0] == '!get_history':
|
||
pass
|
||
elif parced[0] == '!forward_messages':
|
||
pass
|
||
elif parced[0] == '!delete_messages':
|
||
pass
|
||
elif parced[0] == '!pin_message':
|
||
pass
|
||
elif parced[0] == '!unpin_message':
|
||
pass
|
||
elif parced[0] == '!leave_group':
|
||
pass
|
||
elif parced[0] == '!add_members':
|
||
pass
|
||
elif parced[0] == '!bans_list':
|
||
pass
|
||
elif parced[0] == '!ban_user':
|
||
pass
|
||
elif parced[0] == '!unban_user':
|
||
pass
|
||
elif parced[0] == '!restrict_user':
|
||
pass
|
||
elif parced[0] == '!unrestrict_user':
|
||
pass
|
||
elif parced[0] == '!get_recent_actions':
|
||
pass
|
||
elif parced[0] == '!get_recent_actions':
|
||
pass
|
||
|
||
def spawn_tg_client(self, jid, phone):
|
||
"""
|
||
Создает и инициализирует подключение к Telegram
|
||
:param jid:
|
||
:param phone:
|
||
:return:
|
||
"""
|
||
client = TelegramGateClient('a_'+phone, int(self.config['tg_api_id']), self.config['tg_api_hash'],
|
||
self, jid, phone)
|
||
client.connect()
|
||
|
||
self.tg_connections[jid] = client
|
||
self.tg_phones[jid] = phone
|
||
|
||
if client.is_user_authorized():
|
||
self.init_tg(jid)
|
||
self.send_presence(pto=jid, pfrom=self.boundjid.bare, ptype='online', pstatus='connected')
|
||
|
||
def init_tg(self, jid):
|
||
"""
|
||
Инициализация транспорта для конкретного пользователя после подключения к Telegram
|
||
:param jid:
|
||
:return:
|
||
"""
|
||
# Устанавливаем, что пользователь онлайн
|
||
self.tg_connections[jid].invoke(UpdateStatusRequest(offline=False))
|
||
|
||
# Получаем и обрабатываем список диалогов
|
||
self.tg_process_dialogs(jid)
|
||
|
||
# Регистрируем обработчик обновлений в Telegram
|
||
self.tg_connections[jid].add_update_handler(self.tg_connections[jid].xmpp_update_handler)
|
||
|
||
def roster_exchange(self, tojid, contacts):
|
||
|
||
message = sleekxmpp.Message()
|
||
message['from'] = self.boundjid.bare
|
||
message['to'] = tojid
|
||
rawxml = "<x xmlns='http://jabber.org/protocol/rosterx'>"
|
||
for jid, nick in contacts.items():
|
||
c = "<item action='add' jid='%s' name='%s'><group>Telegram</group></item>" % (jid, nick)
|
||
rawxml = rawxml + c
|
||
|
||
rawxml = rawxml + "</x>"
|
||
message.appendxml(ET.fromstring(rawxml))
|
||
|
||
return message
|
||
|
||
def tg_process_dialogs(self, jid):
|
||
|
||
print('! -- Process Dialogs -- !')
|
||
# Инициализируем словари для диалогов
|
||
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
|
||
|
||
# roster exchange #
|
||
self.contact_list[jid] = dict()
|
||
|
||
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:
|
||
rostername = "Deleted Account"
|
||
vcard['FN'] = 'Deleted account'
|
||
vcard['DESC'] = 'This user no longer exists in Telegram'
|
||
else:
|
||
rostername = display_tg_name(usr.first_name, usr.last_name)
|
||
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')
|
||
self.contact_list[jid][u_jid] = rostername
|
||
|
||
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
|
||
|
||
rostername = '[{}] {}'.format(g_type, cht.title)
|
||
|
||
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.contact_list[jid][c_jid] = rostername
|
||
#self.send_presence(pto=jid, pfrom=c_jid, ptype='subscribe')
|
||
self.send_presence(pto=jid, pfrom=c_jid)
|
||
|
||
if len(dlgs.dialogs) == 0: # Если все диалоги получены - прерываем цикл
|
||
rosterxchange = self.roster_exchange(jid, self.contact_list[jid])
|
||
self.send(rosterxchange)
|
||
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)
|
||
|
||
def tg_process_unread_messages(self):
|
||
pass
|
||
|
||
def gate_reply_message(self, iq, msg):
|
||
"""
|
||
Отправляет ответное сообщение от имени транспорта
|
||
:param iq:
|
||
:param msg:
|
||
:return:
|
||
"""
|
||
self.send_message(mto=iq['from'], mfrom=self.config['jid'], mtype='chat', mbody=msg)
|
||
|
||
def init_database(self):
|
||
"""
|
||
Инициализация БД
|
||
:return:
|
||
"""
|
||
def dict_factory(cursor, row):
|
||
d = {}
|
||
for idx, col in enumerate(cursor.description):
|
||
d[col[0]] = row[idx]
|
||
return d
|
||
|
||
conn = sqlite3.connect(self.config['db_connect'], isolation_level=None, check_same_thread=False)
|
||
conn.row_factory = dict_factory
|
||
|
||
conn.execute("CREATE TABLE IF NOT EXISTS accounts("
|
||
"jid VARCHAR(255),"
|
||
"tg_phone VARCHAR(25)"
|
||
")")
|
||
|
||
# conn.execute("CREATE TABLE IF NOT EXISTS roster("
|
||
# "")
|
||
|
||
return conn
|