From f0ef3abb9c5456f977eb83d56f634c60594b237c Mon Sep 17 00:00:00 2001 From: annelin Date: Mon, 2 Jul 2018 00:51:22 +0000 Subject: [PATCH] [SVN] Release 0.3.2 [FIX] Fixed roster exchange request after transport boot-up [ADD] Added optional profile pictures downloading to V-Cards; you need to add `enable_avatars`(bool) to database or just remove and re-create db file to enable it --- xmpp_tg/__init__.py | 2 +- xmpp_tg/mtproto.py | 4 +-- xmpp_tg/xmpp.py | 67 ++++++++++++++++++++++++++++++++++++++------- 3 files changed, 60 insertions(+), 13 deletions(-) diff --git a/xmpp_tg/__init__.py b/xmpp_tg/__init__.py index 88ddf29..df6c300 100644 --- a/xmpp_tg/__init__.py +++ b/xmpp_tg/__init__.py @@ -1,3 +1,3 @@ from xmpp_tg.xmpp import XMPPTelegram -__version__ = '0.3.1' +__version__ = '0.3.2' diff --git a/xmpp_tg/mtproto.py b/xmpp_tg/mtproto.py index 1845ba7..a692289 100644 --- a/xmpp_tg/mtproto.py +++ b/xmpp_tg/mtproto.py @@ -59,8 +59,8 @@ class TelegramGateClient(TelegramClient): def xmpp_update_handler(self, obj): - print("We have received update for <%s>" % self.jid) - print(obj) + # print("We have received update for <%s>" % self.jid) + # print(obj) # we have received some updates, so we're logined and can get object and start mtd / upd threads # if not self.me: diff --git a/xmpp_tg/xmpp.py b/xmpp_tg/xmpp.py index ecf9dd0..64ef1a2 100644 --- a/xmpp_tg/xmpp.py +++ b/xmpp_tg/xmpp.py @@ -1,7 +1,10 @@ import sqlite3 import re import sys +import os +import io import time +import hashlib import sleekxmpp from sleekxmpp.componentxmpp import ComponentXMPP @@ -49,7 +52,6 @@ class XMPPTelegram(ComponentXMPP): self.tg_connections = dict() self.tg_phones = dict() self.tg_dialogs = dict() - self.contact_list = dict() self.db_connection = self.init_database() @@ -65,6 +67,7 @@ class XMPPTelegram(ComponentXMPP): 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', @@ -526,7 +529,7 @@ class XMPPTelegram(ComponentXMPP): self.tg_connections[jid].invoke(UpdateStatusRequest(offline=False)) # Получаем и обрабатываем список диалогов - self.tg_process_dialogs(jid) + self.tg_process_dialogs(jid, sync_roster = False) # Регистрируем обработчик обновлений в Telegram self.tg_connections[jid].add_update_handler(self.tg_connections[jid].xmpp_update_handler) @@ -559,6 +562,8 @@ class XMPPTelegram(ComponentXMPP): def tg_process_dialogs(self, jid, sync_roster = True): + print('Processing dialogs...') + # Инициализируем словари для диалогов self.tg_dialogs[jid] = dict() self.tg_dialogs[jid]['raw'] = list() @@ -594,6 +599,9 @@ class XMPPTelegram(ComponentXMPP): vcard = self.plugin['xep_0054'].make_vcard() u_jid = get_contact_jid(usr, self.boundjid.bare) + # make vcard # + vcard['JABBERID'] = u_jid + if usr.deleted: rostername = "Deleted Account" vcard['FN'] = 'Deleted account' @@ -612,11 +620,18 @@ class XMPPTelegram(ComponentXMPP): vcard['DESC'] += ' [Bot]' vcard['NICKNAME'] = vcard['FN'] + + # add photo to VCard # + photo, photosha1hash = self.get_peer_photo(jid, usr) if sync_roster else (None, None) + if photo: + vcard['PHOTO']['TYPE'] = 'image/jpeg' + vcard['PHOTO']['BINVAL'] = photo - 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.publish_photo(jid, u_jid, photosha1hash) if photosha1hash else None + # add it to contect list & avatar download queue # self.contact_list[jid][u_jid] = rostername if usr.bot: @@ -645,17 +660,25 @@ class XMPPTelegram(ComponentXMPP): if cht and cht.id: rostername = display_tg_name(cht) - c_jid = get_contact_jid(cht, self.boundjid.bare) + u_jid = get_contact_jid(cht, self.boundjid.bare) vcard = self.plugin['xep_0054'].make_vcard() vcard['FN'] = rostername vcard['NICKNAME'] = rostername - 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) + vcard['JABBERID'] = u_jid + + # add photo to VCard # + photo, photosha1hash = self.get_peer_photo(jid, cht) if sync_roster else (None, None) + if photo: + vcard['PHOTO']['TYPE'] = 'image/jpeg' + vcard['PHOTO']['BINVAL'] = photo + self.plugin['xep_0054'].publish_vcard(jid=u_jid, vcard=vcard) + self.plugin['xep_0172'].publish_nick(nick=vcard['FN'], ifrom=u_jid) + self.publish_photo(jid, u_jid, photosha1hash) if photosha1hash else None - self.contact_list[jid][c_jid] = rostername - self.send_presence(pto=jid, pfrom=c_jid, pshow = 'chat', pstatus = cht.title) + self.contact_list[jid][u_jid] = rostername + self.send_presence(pto=jid, pfrom=u_jid, pshow = 'chat', pstatus = cht.title) + if len(dlgs.dialogs) == 0: # Если все диалоги получены - прерываем цикл if sync_roster and 'use_roster_exchange' in self.accounts[jid] and self.accounts[jid]['use_roster_exchange'] == 'true': @@ -691,6 +714,30 @@ class XMPPTelegram(ComponentXMPP): """ self.send_message(mto=iq['from'], mfrom=self.config['jid'], mtype='chat', mbody=msg) + def get_peer_photo(self, jid, peer): + + # we are able to disable this shit # + if not 'enable_avatars' in self.accounts[jid] or self.accounts[jid]['enable_avatars'] != 'true': + return (None, None) + + data = io.BytesIO() + self.tg_connections[jid].download_profile_photo(peer, file = data) + data.flush() + if isinstance(data, io.BytesIO) and data.getbuffer().nbytes > 0: + image = data.getvalue() + image_sha1 = hashlib.sha1(image).hexdigest() + return (image, image_sha1) + else: + return (None, None) + + def publish_photo(self, jid, fromjid, photo): + presence = sleekxmpp.Presence() + presence['to'] = jid + presence['from'] = fromjid + presence.appendxml(ET.fromstring("%s" % photo)) + self.send(presence) + + def init_database(self): """ Инициализация БД @@ -705,6 +752,6 @@ class XMPPTelegram(ComponentXMPP): 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), use_roster_exchange BOOLEAN default false, keep_online BOOLEAN default false, status_update_interval INTEGER default 60)") + conn.execute("CREATE TABLE IF NOT EXISTS accounts(jid VARCHAR(255), tg_phone VARCHAR(25), use_roster_exchange BOOLEAN default false, keep_online BOOLEAN default false, status_update_interval INTEGER default 60, enable_avatars BOOLEAN default false)") return conn