[SVN] updated version to 0.3.0
[FIX] fixed sending subscription request from groups that are removed or from what you've been left and also fixed double auth request
[UPD] now using telethon version == 0.18
[UPD] code optimized and reworked
[UPD] status updates are moved to separate thread to use timer
[UPD] slightly changed status handling (now Available has "Online" status message, "Last seen recently" now is away, not XA, "Last seen ..." is now XA, "Last seen long time ago" is now DND, chats are ffc)
[UPD] command "!del" removed and replaced with another, see above
[UPD] configuration options `xmpp_use_roster_exchange` and `xmpp_keep_online` was removed from configuration file
[UPD] [BREAK] database structure was changed; please, remove and re-create db.sqlite
[ADD] [BREAK] new options in config file: `logfile` (please, specify it!), and unneccessarry `tg_server_ip`, `tg_server_port`, `tg_server_dc`
[ADD] per-user configuration, parameters stored in database. configurable params:
- use_roster_exchange: use XEP-0144 for roster import (default: false) (recommended: true, if your client supports that XEP)
- keep_online: keep telegram session even if jabber goes offline (default: false) (recommended: true, if you wants to receive all events as offline messages when you will go online)
- status_update_interval: interval (sec.) in what we will update all contact statuses to prevent presence spamming, because telegram sending status updates every fucking second (default: 60)
To modify your personal config, please, send !configure to gateway
[ADD] added new commands to gateway:
!configure (for configuration update)
!add @contact (to find Telegram contact and try to start conversation; any format accepted (t.me link, @username or maybe phone, I don't know... )
!join t.me/joinchat/secret (to join Telegram conference via invite link, https://t.me/joinchat/xxxxx accepted)
!group name @contact (try to create normal group with @contact; you can add more later) [UNTESTED]
!supergroup name (try to create supergroup) [UNTESTED]
!channel name (try to create channel) [UNTESTED]
!name first last (change telegram name)
!username usernme (change telegram @username)
!about some about text (change about text)
[ADD] added new commands to dialogs with normal users:
!help
!block (blacklists user)
!unblock (unblacklists user)
[ADD] added new commands to group/channel dialogs:
!help
!leave (leave current group or supergroup)
!invite (invite @user to current group/supergroup)
!kick (kicks @user to/from group/supergroup)
... and also small fixes and improvements
This commit is contained in:
@@ -4,6 +4,7 @@ CONFIG = {
|
|||||||
'title': 'XMPP <-> Telegram Gate',
|
'title': 'XMPP <-> Telegram Gate',
|
||||||
|
|
||||||
'debug': True,
|
'debug': True,
|
||||||
|
'logfile': '/dev/null',
|
||||||
|
|
||||||
'jid': 'tlgrm.localhost',
|
'jid': 'tlgrm.localhost',
|
||||||
'secret': 'secret',
|
'secret': 'secret',
|
||||||
@@ -15,6 +16,10 @@ CONFIG = {
|
|||||||
'tg_api_id': '17349', # Telegram Desktop (GitHub)
|
'tg_api_id': '17349', # Telegram Desktop (GitHub)
|
||||||
'tg_api_hash': '344583e45741c457fe1862106095a5eb',
|
'tg_api_hash': '344583e45741c457fe1862106095a5eb',
|
||||||
|
|
||||||
|
#'tg_server_ip': '149.154.167.50',
|
||||||
|
#'tg_server_port': 443,
|
||||||
|
#'tg_server_dc': 2,
|
||||||
|
|
||||||
'db_connect': 'db.sqlite',
|
'db_connect': 'db.sqlite',
|
||||||
|
|
||||||
'media_web_link_prefix': 'http://tlgrm.localhost/media/',
|
'media_web_link_prefix': 'http://tlgrm.localhost/media/',
|
||||||
|
|||||||
4
start.py
4
start.py
@@ -44,7 +44,7 @@ logging.basicConfig(
|
|||||||
level=logging.DEBUG if CONFIG['debug'] else logging.INFO,
|
level=logging.DEBUG if CONFIG['debug'] else logging.INFO,
|
||||||
format='%(asctime)s :: %(levelname)s:%(name)s :: %(message)s',
|
format='%(asctime)s :: %(levelname)s:%(name)s :: %(message)s',
|
||||||
datefmt='%m/%d/%Y %I:%M:%S %p',
|
datefmt='%m/%d/%Y %I:%M:%S %p',
|
||||||
handlers=[logging.handlers.RotatingFileHandler(filename='gate.log'), logging.StreamHandler(sys.stdout)]
|
handlers=[logging.handlers.RotatingFileHandler(filename=CONFIG['logfile']), logging.StreamHandler(sys.stdout)]
|
||||||
)
|
)
|
||||||
|
|
||||||
# Создаем логгеры и перехватчики для STDOUT/STDERR
|
# Создаем логгеры и перехватчики для STDOUT/STDERR
|
||||||
@@ -62,7 +62,7 @@ print('--- Telegram (MTProto) <---> XMPP Gateway ---')
|
|||||||
print('----------------------------------------------------------------------')
|
print('----------------------------------------------------------------------')
|
||||||
print()
|
print()
|
||||||
print('Starting...')
|
print('Starting...')
|
||||||
print('Gate build: rev{}'.format(xmpp_tg.__version__))
|
print('Gate version: {}'.format(xmpp_tg.__version__))
|
||||||
print('Process pid: {}'.format(os.getpid()))
|
print('Process pid: {}'.format(os.getpid()))
|
||||||
print('Using Telethon v{} and SleekXMPP v{}'.format(telethon.TelegramClient.__version__, sleekxmpp.__version__))
|
print('Using Telethon v{} and SleekXMPP v{}'.format(telethon.TelegramClient.__version__, sleekxmpp.__version__))
|
||||||
print()
|
print()
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
from xmpp_tg.xmpp import XMPPTelegram
|
from xmpp_tg.xmpp import XMPPTelegram
|
||||||
|
|
||||||
__version__ = 15
|
__version__ = '0.3.0'
|
||||||
|
|||||||
@@ -42,30 +42,32 @@ class TelegramGateClient(TelegramClient):
|
|||||||
self.xmpp_gate = xmpp_gate
|
self.xmpp_gate = xmpp_gate
|
||||||
self.jid = jid
|
self.jid = jid
|
||||||
self.phone = phone
|
self.phone = phone
|
||||||
self.user_options = {'nl_after_info': True, 'status_update_interval': 60}
|
|
||||||
|
|
||||||
self._media_queue = queue.Queue()
|
self._media_queue = queue.Queue()
|
||||||
self._media_thread = threading.Thread(name='MediaDownloaderThread', target=self.media_thread_downloader)
|
self._media_thread = threading.Thread(name='MediaDownloaderThread', target=self.media_thread_downloader)
|
||||||
self._media_thread.start()
|
|
||||||
|
self._status_updates = dict()
|
||||||
|
self._status_update_thread = threading.Thread(name = 'StatusUpdateThread', target = self.status_updater_thread)
|
||||||
|
|
||||||
self._groups_users = dict()
|
self._groups_users = dict()
|
||||||
self._message_cache_users = dict()
|
self._message_cache_users = dict()
|
||||||
self._message_cache_groups = dict()
|
self._message_cache_groups = dict()
|
||||||
self._message_cache_supergroups = dict()
|
self._message_cache_supergroups = dict()
|
||||||
|
|
||||||
self._status_last = dict()
|
|
||||||
|
|
||||||
self._del_pts = 0
|
self._del_pts = 0
|
||||||
|
|
||||||
|
|
||||||
def xmpp_update_handler(self, obj):
|
def xmpp_update_handler(self, obj):
|
||||||
print('new update for ' + self.jid)
|
|
||||||
print(type(obj), obj.__dict__)
|
print("We have received update for <%s>" % self.jid)
|
||||||
|
print(obj)
|
||||||
|
|
||||||
# link to self-user #
|
# we have received some updates, so we're logined and can get <me> object and start mtd / upd threads #
|
||||||
if not self.me:
|
if not self.me:
|
||||||
me = self.get_me()
|
me = self.get_me()
|
||||||
self.me = InputPeerUser(me.id, me.access_hash)
|
self.me = InputPeerUser(me.id, me.access_hash)
|
||||||
|
self._media_thread.start()
|
||||||
|
self._status_update_thread.start()
|
||||||
|
|
||||||
'''
|
'''
|
||||||
Боты
|
Боты
|
||||||
@@ -80,7 +82,7 @@ class TelegramGateClient(TelegramClient):
|
|||||||
|
|
||||||
# Здесь будет очень длинный пиздец ^__^
|
# Здесь будет очень длинный пиздец ^__^
|
||||||
|
|
||||||
nl = '\n' if self.user_options['nl_after_info'] else ''
|
nl = '\n'
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
|
||||||
@@ -95,16 +97,8 @@ class TelegramGateClient(TelegramClient):
|
|||||||
# message from normal group #
|
# message from normal group #
|
||||||
if type(obj) in [UpdateShortChatMessage] and not obj.out:
|
if type(obj) in [UpdateShortChatMessage] and not obj.out:
|
||||||
fwd_from = self._process_forward_msg(obj) if obj.fwd_from else '' # process forward messages
|
fwd_from = self._process_forward_msg(obj) if obj.fwd_from else '' # process forward messages
|
||||||
nickname = ''
|
usr = self._get_user_information(obj.from_id)
|
||||||
|
nickname = display_tg_name(usr)
|
||||||
# get sender information from chat info
|
|
||||||
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)
|
|
||||||
|
|
||||||
# send message
|
# send message
|
||||||
self.gate_send_message(mfrom='g' + str(obj.chat_id), mbody ='[MSG {}] [User: {}] {}{}'.format(obj.id, nickname, fwd_from, obj.message) )
|
self.gate_send_message(mfrom='g' + str(obj.chat_id), mbody ='[MSG {}] [User: {}] {}{}'.format(obj.id, nickname, fwd_from, obj.message) )
|
||||||
@@ -159,7 +153,7 @@ class TelegramGateClient(TelegramClient):
|
|||||||
# get sender information from chat info #
|
# get sender information from chat info #
|
||||||
if not is_user and not obj.message.post:
|
if not is_user and not obj.message.post:
|
||||||
usr = self._get_user_information(obj.message.from_id)
|
usr = self._get_user_information(obj.message.from_id)
|
||||||
nickname = display_tg_name(usr.first_name, usr.last_name)
|
nickname = display_tg_name(usr)
|
||||||
msg = '[User: {}] {}'.format(nickname, msg)
|
msg = '[User: {}] {}'.format(nickname, msg)
|
||||||
|
|
||||||
|
|
||||||
@@ -183,34 +177,24 @@ class TelegramGateClient(TelegramClient):
|
|||||||
# Status Updates #
|
# Status Updates #
|
||||||
if type(obj) is UpdateUserStatus:
|
if type(obj) is UpdateUserStatus:
|
||||||
|
|
||||||
# save last update time #
|
|
||||||
if (obj.user_id in self._status_last) and ( (time.time() - self._status_last[obj.user_id]['time'] < self.user_options['status_update_interval']) or self._status_last[obj.user_id]['status'] == obj.status ):
|
|
||||||
return
|
|
||||||
|
|
||||||
self._status_last[obj.user_id] = {'status': obj.status, 'time': time.time()}
|
|
||||||
|
|
||||||
# process status update #
|
# process status update #
|
||||||
if type(obj.status) is UserStatusOnline:
|
if type(obj.status) is UserStatusOnline:
|
||||||
self.xmpp_gate.send_presence( pto=self.jid, pfrom='u'+str(obj.user_id)+'@'+self.xmpp_gate.config['jid'])
|
self._status_updates[str(obj.user_id)] = { 'status': None, 'message': 'Online' }
|
||||||
elif type(obj.status) is UserStatusOffline:
|
elif type(obj.status) is UserStatusOffline:
|
||||||
self.xmpp_gate.send_presence( pto=self.jid, pfrom='u'+str(obj.user_id)+'@'+self.xmpp_gate.config['jid'], ptype='xa', pstatus=obj.status.was_online.strftime('Last seen at %H:%M %d/%m/%Y') )
|
self._status_updates[str(obj.user_id)] = { 'status': 'xa', 'message': obj.status.was_online.strftime('Last seen at %H:%M %d/%m/%Y') }
|
||||||
elif type(obj.status) is UserStatusRecently:
|
elif type(obj.status) is UserStatusRecently:
|
||||||
self.xmpp_gate.send_presence( pto=self.jid, pfrom='u' + str(obj.user_id) + '@' + self.xmpp_gate.config['jid'], pstatus='Last seen recently' )
|
self._status_updates[str(obj.user_id)] = { 'status': 'away', 'message': 'Last seen recently' }
|
||||||
else:
|
else:
|
||||||
print(type(obj.status))
|
pass
|
||||||
print(obj.update.status.__dict__)
|
|
||||||
|
|
||||||
|
|
||||||
except Exception:
|
except Exception:
|
||||||
print('Exception occurs!')
|
print('Exception occurs!')
|
||||||
print(traceback.format_exc())
|
print(traceback.format_exc())
|
||||||
|
|
||||||
print(' ')
|
|
||||||
|
|
||||||
def gate_send_message(self, mfrom, mbody):
|
def gate_send_message(self, mfrom, mbody):
|
||||||
tg_from = int(mfrom[1:])
|
tg_from = int(mfrom[1:])
|
||||||
if not tg_from in self.xmpp_gate.tg_dialogs[self.jid]['users'] and not tg_from in self.xmpp_gate.tg_dialogs[self.jid]['groups'] and not tg_from in self.xmpp_gate.tg_dialogs[self.jid]['supergroups']:
|
if not tg_from in self.xmpp_gate.tg_dialogs[self.jid]['users'] and not tg_from in self.xmpp_gate.tg_dialogs[self.jid]['groups'] and not tg_from in self.xmpp_gate.tg_dialogs[self.jid]['supergroups']: # new contact appeared
|
||||||
print('Re-init dialog list...')
|
|
||||||
self.xmpp_gate.tg_process_dialogs( self.jid )
|
self.xmpp_gate.tg_process_dialogs( self.jid )
|
||||||
|
|
||||||
self.xmpp_gate.send_message( mto=self.jid, mfrom=mfrom + '@' + self.xmpp_gate.config['jid'], mtype='chat', mbody=mbody)
|
self.xmpp_gate.send_message( mto=self.jid, mfrom=mfrom + '@' + self.xmpp_gate.config['jid'], mtype='chat', mbody=mbody)
|
||||||
@@ -279,7 +263,7 @@ class TelegramGateClient(TelegramClient):
|
|||||||
if message.fwd_from.from_id: # От пользователя
|
if message.fwd_from.from_id: # От пользователя
|
||||||
|
|
||||||
usr = self._get_user_information(message.fwd_from.from_id)
|
usr = self._get_user_information(message.fwd_from.from_id)
|
||||||
fwd_from = display_tg_name(usr.first_name, usr.last_name)
|
fwd_from = display_tg_name(usr)
|
||||||
|
|
||||||
if message.fwd_from.channel_id: # От канала
|
if message.fwd_from.channel_id: # От канала
|
||||||
fwd_from = 'Channel {}'.format(message.fwd_from.channel_id)
|
fwd_from = 'Channel {}'.format(message.fwd_from.channel_id)
|
||||||
@@ -296,7 +280,6 @@ class TelegramGateClient(TelegramClient):
|
|||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
msg = ''
|
msg = ''
|
||||||
# print(var_dump(media))
|
|
||||||
|
|
||||||
if type(media) is MessageMediaDocument: # Документ или замаскированная сущность
|
if type(media) is MessageMediaDocument: # Документ или замаскированная сущность
|
||||||
attributes = media.document.attributes
|
attributes = media.document.attributes
|
||||||
@@ -378,7 +361,7 @@ class TelegramGateClient(TelegramClient):
|
|||||||
|
|
||||||
msg = ''
|
msg = ''
|
||||||
usr = self._get_user_information(message.from_id)
|
usr = self._get_user_information(message.from_id)
|
||||||
nickname = display_tg_name(usr.first_name, usr.last_name)
|
nickname = display_tg_name(usr)
|
||||||
|
|
||||||
# supergroup created #
|
# supergroup created #
|
||||||
if type(message.action) is MessageActionChannelCreate:
|
if type(message.action) is MessageActionChannelCreate:
|
||||||
@@ -393,19 +376,19 @@ class TelegramGateClient(TelegramClient):
|
|||||||
added_users = []
|
added_users = []
|
||||||
for user_id in message.action.users:
|
for user_id in message.action.users:
|
||||||
usr = self._get_user_information(user_id)
|
usr = self._get_user_information(user_id)
|
||||||
added_users.append(display_tg_name(usr.first_name, usr.last_name))
|
added_users.append(display_tg_name(usr))
|
||||||
|
|
||||||
msg = 'User [{}] has just invited [{}]'.format(nickname, ','.join(added_users))
|
msg = 'User [{}] has just invited [{}]'.format(nickname, ','.join(added_users))
|
||||||
|
|
||||||
# user exit #
|
# user exit #
|
||||||
elif type(message.action) is MessageActionChatDeleteUser:
|
elif type(message.action) is MessageActionChatDeleteUser:
|
||||||
usr = self._get_user_information(message.action.user_id)
|
usr = self._get_user_information(message.action.user_id)
|
||||||
msg = 'User [{}] has just left the room'.format(display_tg_name(usr.first_name, usr.last_name))
|
msg = 'User [{}] has just left the room'.format(display_tg_name(usr))
|
||||||
|
|
||||||
# user joined #
|
# user joined #
|
||||||
elif type(message.action) is MessageActionChatJoinedByLink:
|
elif type(message.action) is MessageActionChatJoinedByLink:
|
||||||
usr = self._get_user_information(message.action.user_id)
|
usr = self._get_user_information(message.action.user_id)
|
||||||
msg = 'User [{}] joined the room'.format(display_tg_name(usr.first_name, usr.last_name))
|
msg = 'User [{}] joined the room'.format(display_tg_name(usr))
|
||||||
|
|
||||||
# chat name modified #
|
# chat name modified #
|
||||||
elif type(message.action) is MessageActionChatEditTitle:
|
elif type(message.action) is MessageActionChatEditTitle:
|
||||||
@@ -418,7 +401,7 @@ class TelegramGateClient(TelegramClient):
|
|||||||
if len(message_req.messages) > 0:
|
if len(message_req.messages) > 0:
|
||||||
pinned_message = message_req.messages[0].message
|
pinned_message = message_req.messages[0].message
|
||||||
pinned_from = self._get_user_information(message_req.messages[0].from_id)
|
pinned_from = self._get_user_information(message_req.messages[0].from_id)
|
||||||
msg = 'User [{}] pinned message: [{}]: {}'.format(nickname, display_tg_name(pinned_from.first_name, pinned_from.last_name), pinned_message)
|
msg = 'User [{}] pinned message: [{}]: {}'.format(nickname, display_tg_name(pinned_from), pinned_message)
|
||||||
|
|
||||||
# group converted to supergroup
|
# group converted to supergroup
|
||||||
elif type(message.action) in [MessageActionChatMigrateTo, MessageActionChannelMigrateFrom]:
|
elif type(message.action) in [MessageActionChatMigrateTo, MessageActionChannelMigrateFrom]:
|
||||||
@@ -446,3 +429,16 @@ class TelegramGateClient(TelegramClient):
|
|||||||
print('MTD ::: Media downloaded')
|
print('MTD ::: Media downloaded')
|
||||||
except Exception:
|
except Exception:
|
||||||
print(traceback.format_exc())
|
print(traceback.format_exc())
|
||||||
|
|
||||||
|
def status_updater_thread(self):
|
||||||
|
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
if len(self._status_updates) > 0:
|
||||||
|
for uid, status in self._status_updates.items():
|
||||||
|
self.xmpp_gate.send_presence( pto=self.jid, pfrom='u'+str(uid)+'@'+self.xmpp_gate.config['jid'], pshow = status['status'], pstatus = status['message'] )
|
||||||
|
except Exception:
|
||||||
|
print(traceback.format_exc())
|
||||||
|
|
||||||
|
self._status_updates = dict()
|
||||||
|
time.sleep( self.xmpp_gate.accounts[self.jid]['status_update_interval'])
|
||||||
|
|||||||
@@ -6,23 +6,35 @@ import types
|
|||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
|
|
||||||
def display_tg_name(first_name, last_name):
|
def display_tg_name(peer):
|
||||||
if first_name and last_name:
|
if hasattr(peer,'title') and hasattr(peer,'broadcast') and peer.broadcast: # channel
|
||||||
return '{} {}'.format(first_name, last_name)
|
return '[C] ' + peer.title
|
||||||
elif first_name:
|
elif hasattr(peer,'title') and hasattr(peer,'broadcast') and not peer.broadcast: # supergroup
|
||||||
return first_name
|
return '[SG] ' + peer.title
|
||||||
elif last_name:
|
elif hasattr(peer,'title'): # normal group
|
||||||
return last_name
|
return '[G] ' + peer.title
|
||||||
|
elif peer.first_name and peer.last_name: # user with first and last name
|
||||||
|
return '{} {}'.format(peer.first_name, peer.last_name)
|
||||||
|
elif peer.first_name: # user with firstname only
|
||||||
|
return peer.first_name
|
||||||
|
elif peer.last_name: # user with lastname only
|
||||||
|
return peer.last_name
|
||||||
|
elif peer.username: # user with username only
|
||||||
|
return peer.username
|
||||||
|
else: # no match, unknown contact
|
||||||
|
return '[Unknown]'
|
||||||
|
|
||||||
|
def get_contact_jid(peer, gatejid):
|
||||||
|
if peer.id and hasattr(peer,'title') and hasattr(peer, 'broadcast') and peer.broadcast: # channel
|
||||||
|
return 'c' + str(peer.id) + '@' + gatejid
|
||||||
|
elif peer.id and hasattr(peer,'title') and hasattr(peer,'broadcast') and not peer.broadcast: # supergroup
|
||||||
|
return 's' + str(peer.id) + '@' + gatejid
|
||||||
|
elif peer.id and hasattr(peer,'title'): # normal group
|
||||||
|
return 'g' + str(peer.id) + '@' + gatejid
|
||||||
|
elif peer.id and not peer.bot: # it is... user?
|
||||||
|
return 'u' + str(peer.id) + '@' + gatejid
|
||||||
else:
|
else:
|
||||||
return '[No name]'
|
return None
|
||||||
|
|
||||||
|
|
||||||
def make_gate_jid():
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
def parse_gate_jid():
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
def var_dump(obj, depth=7, l=""):
|
def var_dump(obj, depth=7, l=""):
|
||||||
@@ -60,4 +72,4 @@ def var_dump(obj, depth=7, l=""):
|
|||||||
objdict[a] = str(e)
|
objdict[a] = str(e)
|
||||||
|
|
||||||
return name + "{\n" + "\n".join(l + repr(k) + ": " + var_dump(v, depth=depth - 1, l=l + " ") + "," for k, v in
|
return name + "{\n" + "\n".join(l + repr(k) + ": " + var_dump(v, depth=depth - 1, l=l + " ") + "," for k, v in
|
||||||
objdict.items()) + "\n" + l + "}"
|
objdict.items()) + "\n" + l + "}"
|
||||||
|
|||||||
350
xmpp_tg/xmpp.py
350
xmpp_tg/xmpp.py
@@ -1,28 +1,30 @@
|
|||||||
import sqlite3
|
import sqlite3
|
||||||
import re
|
import re
|
||||||
import sys
|
import sys
|
||||||
|
import time
|
||||||
|
|
||||||
import sleekxmpp
|
import sleekxmpp
|
||||||
from sleekxmpp.componentxmpp import ComponentXMPP
|
from sleekxmpp.componentxmpp import ComponentXMPP
|
||||||
import xml.etree.ElementTree as ET
|
import xml.etree.ElementTree as ET
|
||||||
|
|
||||||
from telethon.tl.functions.messages import GetDialogsRequest, SendMessageRequest
|
from telethon.tl.functions.messages import GetDialogsRequest, SendMessageRequest, ImportChatInviteRequest, GetFullChatRequest, AddChatUserRequest, DeleteChatUserRequest, CreateChatRequest
|
||||||
from telethon.tl.functions.account import UpdateStatusRequest, GetAuthorizationsRequest
|
from telethon.tl.functions.account import UpdateStatusRequest, GetAuthorizationsRequest, UpdateProfileRequest, UpdateUsernameRequest
|
||||||
from telethon.tl.functions.contacts import DeleteContactRequest
|
from telethon.tl.functions.contacts import DeleteContactRequest, BlockRequest, UnblockRequest
|
||||||
from telethon.tl.functions.channels import JoinChannelRequest, LeaveChannelRequest
|
from telethon.tl.functions.channels import JoinChannelRequest, LeaveChannelRequest, InviteToChannelRequest, EditBannedRequest, CreateChannelRequest
|
||||||
|
|
||||||
from telethon.tl.types import InputPeerEmpty, InputPeerUser, InputPeerChat, InputPeerChannel
|
from telethon.tl.types import InputPeerEmpty, InputPeerUser, InputPeerChat, InputPeerChannel
|
||||||
from telethon.tl.types import User, Chat, Channel
|
from telethon.tl.types import User, Chat, Channel
|
||||||
from telethon.tl.types import PeerChannel, PeerChat, PeerUser, Chat, ChatForbidden, Channel, ChannelForbidden
|
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 UserStatusOnline, UserStatusRecently, UserStatusOffline
|
||||||
from telethon.tl.types import Updates, UpdateShortSentMessage, UpdateMessageID
|
from telethon.tl.types import Updates, UpdateShortSentMessage, UpdateMessageID
|
||||||
|
from telethon.tl.types import ChannelBannedRights
|
||||||
from telethon.tl.types.messages import Dialogs, DialogsSlice
|
from telethon.tl.types.messages import Dialogs, DialogsSlice
|
||||||
|
|
||||||
from telethon.helpers import generate_random_long
|
from telethon.helpers import generate_random_long
|
||||||
from telethon.errors import SessionPasswordNeededError
|
from telethon.errors import SessionPasswordNeededError
|
||||||
|
|
||||||
from xmpp_tg.mtproto import TelegramGateClient
|
from xmpp_tg.mtproto import TelegramGateClient
|
||||||
from xmpp_tg.utils import var_dump, display_tg_name
|
from xmpp_tg.utils import var_dump, display_tg_name, get_contact_jid
|
||||||
import xmpp_tg.monkey # Патчим баги в библиотеках
|
import xmpp_tg.monkey # Патчим баги в библиотеках
|
||||||
|
|
||||||
class XMPPTelegram(ComponentXMPP):
|
class XMPPTelegram(ComponentXMPP):
|
||||||
@@ -40,9 +42,10 @@ class XMPPTelegram(ComponentXMPP):
|
|||||||
config_dict['port'])
|
config_dict['port'])
|
||||||
|
|
||||||
self.auto_authorize = True
|
self.auto_authorize = True
|
||||||
self.auto_subscribe = True
|
# self.auto_subscribe = True
|
||||||
|
|
||||||
self.config = config_dict
|
self.config = config_dict
|
||||||
|
self.accounts = dict() # personal configuration per JID
|
||||||
self.tg_connections = dict()
|
self.tg_connections = dict()
|
||||||
self.tg_phones = dict()
|
self.tg_phones = dict()
|
||||||
self.tg_dialogs = dict()
|
self.tg_dialogs = dict()
|
||||||
@@ -92,7 +95,7 @@ class XMPPTelegram(ComponentXMPP):
|
|||||||
"""
|
"""
|
||||||
users = self.db_connection.execute("SELECT * FROM accounts").fetchall()
|
users = self.db_connection.execute("SELECT * FROM accounts").fetchall()
|
||||||
for usr in users:
|
for usr in users:
|
||||||
print('Sending presence...')
|
self.accounts[usr['jid']] = usr
|
||||||
self.send_presence(pto=usr['jid'], pfrom=self.boundjid.bare, ptype='probe')
|
self.send_presence(pto=usr['jid'], pfrom=self.boundjid.bare, ptype='probe')
|
||||||
|
|
||||||
def message(self, iq):
|
def message(self, iq):
|
||||||
@@ -111,15 +114,13 @@ class XMPPTelegram(ComponentXMPP):
|
|||||||
else: # Пишут в Telegram
|
else: # Пишут в Telegram
|
||||||
if jid in self.tg_connections and self.tg_connections[jid].is_user_authorized():
|
if jid in self.tg_connections and self.tg_connections[jid].is_user_authorized():
|
||||||
if iq['body'].startswith('!'): # Команда из чата
|
if iq['body'].startswith('!'): # Команда из чата
|
||||||
print('command received')
|
|
||||||
if iq['to'].bare.startswith('u'):
|
if iq['to'].bare.startswith('u'):
|
||||||
self.process_chat_user_command(iq)
|
self.process_chat_user_command(iq)
|
||||||
elif iq['to'].bare.startswith('g') or iq['to'].bare.startswith('s'):
|
elif iq['to'].bare.startswith('g') or iq['to'].bare.startswith('s') or iq['to'].bare.startswith('c'):
|
||||||
self.process_chat_group_command(iq)
|
self.process_chat_group_command(iq)
|
||||||
else:
|
else:
|
||||||
self.gate_reply_message(iq, 'Error.')
|
self.gate_reply_message(iq, 'Error.')
|
||||||
else: # Обычное сообщение
|
else: # Обычное сообщение
|
||||||
print('sent message')
|
|
||||||
tg_id = int(iq['to'].node[1:])
|
tg_id = int(iq['to'].node[1:])
|
||||||
tg_peer = None
|
tg_peer = None
|
||||||
msg = iq['body']
|
msg = iq['body']
|
||||||
@@ -140,8 +141,6 @@ class XMPPTelegram(ComponentXMPP):
|
|||||||
elif iq['to'].bare.startswith('s') or iq['to'].bare.startswith('c'): # Супергруппа
|
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)
|
tg_peer = InputPeerChannel(tg_id, self.tg_dialogs[jid]['supergroups'][tg_id].access_hash)
|
||||||
|
|
||||||
print(tg_peer)
|
|
||||||
|
|
||||||
if tg_peer:
|
if tg_peer:
|
||||||
# Отправляем сообщение и получаем новый апдейт
|
# Отправляем сообщение и получаем новый апдейт
|
||||||
result = self.tg_connections[jid].invoke(
|
result = self.tg_connections[jid].invoke(
|
||||||
@@ -163,7 +162,6 @@ class XMPPTelegram(ComponentXMPP):
|
|||||||
# mbody='[Your MID:{}]'.format(msg_id))
|
# mbody='[Your MID:{}]'.format(msg_id))
|
||||||
|
|
||||||
def event_presence_unsub(self, presence):
|
def event_presence_unsub(self, presence):
|
||||||
print('defense')
|
|
||||||
return
|
return
|
||||||
|
|
||||||
def event_presence(self, presence):
|
def event_presence(self, presence):
|
||||||
@@ -177,11 +175,11 @@ class XMPPTelegram(ComponentXMPP):
|
|||||||
|
|
||||||
# handle "online" to transport:
|
# handle "online" to transport:
|
||||||
if ptype == 'available' and presence['to'].bare == self.boundjid.bare:
|
if ptype == 'available' and presence['to'].bare == self.boundjid.bare:
|
||||||
self.handle_online(presence)
|
self.handle_online(presence, False) # handle online
|
||||||
elif ptype == 'subscribe':
|
elif ptype == 'subscribe':
|
||||||
self.send_presence(pto=presence['from'].bare, pfrom=presence['to'].bare, ptype='subscribed')
|
self.send_presence(pto=presence['from'].bare, pfrom=presence['to'].bare, ptype='subscribed')
|
||||||
elif ptype == 'subscribed':
|
elif ptype == 'subscribed':
|
||||||
self.send_presence(pto=presence['from'].bare, pfrom=presence['to'].bare, ptype='subscribee')
|
pass
|
||||||
elif ptype == 'unsubscribe':
|
elif ptype == 'unsubscribe':
|
||||||
pass
|
pass
|
||||||
elif ptype == 'unsubscribed':
|
elif ptype == 'unsubscribed':
|
||||||
@@ -194,7 +192,7 @@ class XMPPTelegram(ComponentXMPP):
|
|||||||
# self.send_presence(pto=presence['from'], pfrom=presence['to'])
|
# self.send_presence(pto=presence['from'], pfrom=presence['to'])
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def handle_online(self, event):
|
def handle_online(self, event, sync_roster = True):
|
||||||
"""
|
"""
|
||||||
Обработчик события online. Подключается к Telegram при наличии авторизации.
|
Обработчик события online. Подключается к Telegram при наличии авторизации.
|
||||||
:param event:
|
:param event:
|
||||||
@@ -202,7 +200,7 @@ class XMPPTelegram(ComponentXMPP):
|
|||||||
"""
|
"""
|
||||||
jid = event['from'].bare
|
jid = event['from'].bare
|
||||||
to = event['to'].bare
|
to = event['to'].bare
|
||||||
|
|
||||||
# maybe if i'll ignore it — it will go ahead
|
# maybe if i'll ignore it — it will go ahead
|
||||||
if to != self.boundjid.bare:
|
if to != self.boundjid.bare:
|
||||||
return
|
return
|
||||||
@@ -218,7 +216,7 @@ class XMPPTelegram(ComponentXMPP):
|
|||||||
self.tg_connections[jid].invoke(UpdateStatusRequest(offline=False))
|
self.tg_connections[jid].invoke(UpdateStatusRequest(offline=False))
|
||||||
|
|
||||||
self.send_presence(pto=jid, pfrom=self.boundjid.bare, ptype='online', pstatus='connected')
|
self.send_presence(pto=jid, pfrom=self.boundjid.bare, ptype='online', pstatus='connected')
|
||||||
self.tg_process_dialogs(jid)
|
self.tg_process_dialogs(jid, sync_roster) # do not sync roster if we already have connection!
|
||||||
|
|
||||||
|
|
||||||
def handle_offline(self, event):
|
def handle_offline(self, event):
|
||||||
@@ -230,7 +228,7 @@ class XMPPTelegram(ComponentXMPP):
|
|||||||
jid = event['from'].bare
|
jid = event['from'].bare
|
||||||
|
|
||||||
# keep telegram online ?
|
# keep telegram online ?
|
||||||
if self.config['xmpp_keep_online']:
|
if self.accounts[jid]['keep_online']:
|
||||||
return
|
return
|
||||||
|
|
||||||
if jid in self.tg_connections:
|
if jid in self.tg_connections:
|
||||||
@@ -258,39 +256,38 @@ class XMPPTelegram(ComponentXMPP):
|
|||||||
jid = iq['from'].bare
|
jid = iq['from'].bare
|
||||||
|
|
||||||
if parsed[0] == '!help':
|
if parsed[0] == '!help':
|
||||||
self.gate_reply_message(iq, 'Available command:\n\n'
|
self.gate_reply_message(iq, '=== Available gateway commands ===:\n\n'
|
||||||
'!help - Displays this text\n'
|
'!help - Displays this text\n'
|
||||||
'!login +123456789 - Initiates Telegram session\n'
|
'!login +123456789 - Initiates Telegram session\n'
|
||||||
'!code 12345 - Entering one-time code during auth\n'
|
'!code 12345 - Entering one-time code during auth\n'
|
||||||
#'!password abc123 - Entering password during two-factor auth\n'
|
'!password abc123 - Entering password during two-factor auth\n'
|
||||||
'!list_sessions - List all created sessions at Telegram servers\n'
|
'!configure - Configure transport settings\n'
|
||||||
|
#'!list_sessions - List all created sessions at Telegram servers\n'
|
||||||
#'!delete_session 123 - Delete session\n'
|
#'!delete_session 123 - Delete session\n'
|
||||||
'!logout - Deletes current Telegram session at gate\n'
|
'!logout - Deletes current Telegram session at gate\n'
|
||||||
'!reload_dialogs - Reloads dialogs list from Telegram\n\n'
|
'!reload_dialogs - Reloads dialogs list from Telegram\n\n'
|
||||||
'!add - Find and add Telegram contact. Any formats accepted (nickname or t.me link)\n\n'
|
'!add - Find and add Telegram contact. Any formats accepted (nickname or t.me link)\n\n'
|
||||||
'!del - Removes Telegram contact or leaves a chat. Any formats accepted (nickname or t.me link) \n\n'
|
'!join - Join Telegram conference via invite link \n\n'
|
||||||
#'!create_group - Initiates group creation\n'
|
'!group GroupName @InviteContact - Create a normal group\n'
|
||||||
#'!create_channel - Initiates channel creation\n\n'
|
'!supergroup SupergroupName - Create a supergroup\n'
|
||||||
#'!change_name first last - Changes your name in Telegram\n'
|
'!channel ChannelName - Create a channel\n\n'
|
||||||
#'!change_username username - Changes your @username in Telegram\n'
|
'!name first last - Change your name in Telegram\n'
|
||||||
# '!blocked_users_list\n'
|
'!about text - Change about text in Telegram\n'
|
||||||
# '!blocked_users_add\n'
|
'!username - Changes your @username in Telegram\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 parsed[0] == '!configure':
|
||||||
|
config_exclude = ['jid', 'tg_phone']
|
||||||
|
if len(parsed) > 2 and parsed[1] not in config_exclude:
|
||||||
|
self.db_connection.execute("update accounts set {} = ? where jid = ?".format(parsed[1]), (parsed[2],jid,) )
|
||||||
|
self.accounts[jid] = self.db_connection.execute("SELECT * FROM accounts where jid = ?", (jid,) ).fetchone()
|
||||||
|
|
||||||
|
message = "=== Your current configuration ===\n\n"
|
||||||
|
for param, value in self.accounts[jid].items():
|
||||||
|
message = message + "<%s>: %s" % (param, value) + "\n"
|
||||||
|
message = message + "\nTo modify some option, please, send !configure param value"
|
||||||
|
self.gate_reply_message(iq, message)
|
||||||
|
|
||||||
|
|
||||||
elif parsed[0] == '!login': # --------------------------------------------------
|
elif parsed[0] == '!login': # --------------------------------------------------
|
||||||
self.gate_reply_message(iq, 'Please wait...')
|
self.gate_reply_message(iq, 'Please wait...')
|
||||||
self.spawn_tg_client(jid, parsed[1])
|
self.spawn_tg_client(jid, parsed[1])
|
||||||
@@ -320,8 +317,10 @@ class XMPPTelegram(ComponentXMPP):
|
|||||||
if self.tg_connections[jid].is_user_authorized():
|
if self.tg_connections[jid].is_user_authorized():
|
||||||
self.send_presence(pto=jid, pfrom=self.boundjid.bare, ptype='online', pstatus='connected')
|
self.send_presence(pto=jid, pfrom=self.boundjid.bare, ptype='online', pstatus='connected')
|
||||||
self.gate_reply_message(iq, 'Authentication successful. Initiating Telegram...')
|
self.gate_reply_message(iq, 'Authentication successful. Initiating Telegram...')
|
||||||
|
self.db_connection.execute("INSERT INTO accounts(jid, tg_phone) VALUES(?, ?)", (jid, self.tg_phones[jid],))
|
||||||
|
self.accounts[jid] = self.db_connection.execute("SELECT * FROM accounts where jid = ?", (jid,) ).fetchone()
|
||||||
self.init_tg(jid)
|
self.init_tg(jid)
|
||||||
self.db_connection.execute("INSERT INTO accounts VALUES(?, ?)", (jid, self.tg_phones[jid],))
|
|
||||||
else:
|
else:
|
||||||
self.gate_reply_message(iq, 'Authentication failed.')
|
self.gate_reply_message(iq, 'Authentication failed.')
|
||||||
else:
|
else:
|
||||||
@@ -332,7 +331,6 @@ class XMPPTelegram(ComponentXMPP):
|
|||||||
return
|
return
|
||||||
|
|
||||||
sessions = self.tg_connections[jid].invoke(GetAuthorizationsRequest())
|
sessions = self.tg_connections[jid].invoke(GetAuthorizationsRequest())
|
||||||
print(sessions.__dict__)
|
|
||||||
elif parsed[0] == '!reload_dialogs':
|
elif parsed[0] == '!reload_dialogs':
|
||||||
if not self.tg_connections[jid].is_user_authorized():
|
if not self.tg_connections[jid].is_user_authorized():
|
||||||
self.gate_reply_message(iq, 'Error.')
|
self.gate_reply_message(iq, 'Error.')
|
||||||
@@ -356,88 +354,124 @@ class XMPPTelegram(ComponentXMPP):
|
|||||||
return
|
return
|
||||||
|
|
||||||
self.tg_process_dialogs(jid)
|
self.tg_process_dialogs(jid)
|
||||||
|
|
||||||
|
elif parsed[0] == '!join': # join chat by link
|
||||||
|
link = parsed[1].split('/') # https://t.me/joinchat/HrCmckx_SkMbSGFLhXCvSg
|
||||||
|
self.tg_connections[jid].invoke(ImportChatInviteRequest(link[4]))
|
||||||
|
time.sleep(1)
|
||||||
|
self.tg_process_dialogs(jid)
|
||||||
|
|
||||||
|
elif parsed[0] == '!group' and len(parsed) >= 3: # create new group
|
||||||
|
# group name? #
|
||||||
|
groupname = parsed[1]
|
||||||
|
|
||||||
|
# group users? #
|
||||||
|
groupuser = self.tg_connections[jid].get_entity(parsed[2])
|
||||||
|
|
||||||
elif parsed[0] == '!del': # add user
|
# we re ready to make group
|
||||||
result = self.tg_connections[jid].get_entity(parsed[1])
|
self.tg_connections[jid].invoke(CreateChatRequest([groupusers], groupname))
|
||||||
if type(result) == User:
|
self.tg_process_dialogs(jid)
|
||||||
tg_peer = InputPeerUser( result.id, result.access_hash )
|
|
||||||
req = self.tg_connections[jid].invoke( DeleteContactRequest(tg_peer) )
|
elif parsed[0] == '!channel' and len(parsed) >= 2: # create new channel
|
||||||
print(req)
|
groupname = parsed[1]
|
||||||
prefix = 'u'
|
self.tg_connections[jid].invoke(CreateChannelRequest(groupname, groupname, broadcast = True))
|
||||||
elif type(result) == Channel:
|
self.tg_process_dialogs(jid)
|
||||||
tg_peer = InputPeerChannel( result.id, result.access_hash )
|
|
||||||
self.tg_connections[jid].invoke(LeaveChannelRequest( InputPeerChannel(result.id, result.access_hash) ) )
|
elif parsed[0] == '!supergroup' and len(parsed) >= 2: # create new channel
|
||||||
prefix = 'c' if result.broadcast else 's'
|
groupname = parsed[1]
|
||||||
else:
|
self.tg_connections[jid].invoke(CreateChannelRequest(groupname, groupname, megagroup = True))
|
||||||
self.gate_reply_message(iq, 'Sorry, nothing found.')
|
self.tg_process_dialogs(jid)
|
||||||
return
|
|
||||||
|
elif parsed[0] == '!username' and len(parsed) >= 2: # create new channel
|
||||||
presence_from = prefix + str(result.id) + '@' + self.boundjid.bare
|
username = parsed[1]
|
||||||
self.send_presence(pto=jid, pfrom=presence_from, ptype='unavailable')
|
self.tg_connections[jid].invoke(UpdateUsernameRequest(username))
|
||||||
self.send_presence(pto=jid, pfrom=presence_from, ptype='unsubscribed')
|
|
||||||
self.send_presence(pto=jid, pfrom=presence_from, ptype='unsubscribe')
|
elif parsed[0] == '!name' and len(parsed) >= 2: # create new channel
|
||||||
|
firstname = parsed[1]
|
||||||
|
lastname = parsed[2] if len(parsed) > 2 else None
|
||||||
|
self.tg_connections[jid].invoke(UpdateProfileRequest(first_name = firstname, last_name = lastname))
|
||||||
|
|
||||||
|
elif parsed[0] == '!about' and len(parsed) >= 2: # create new channel
|
||||||
|
about = iq['body'][7:]
|
||||||
|
self.tg_connections[jid].invoke(UpdateProfileRequest(about = about))
|
||||||
|
|
||||||
else: # --------------------------------------------------
|
else: # --------------------------------------------------
|
||||||
self.gate_reply_message(iq, 'Unknown command. Try !help for list all commands.')
|
self.gate_reply_message(iq, 'Unknown command. Try !help for list all commands.')
|
||||||
|
|
||||||
def process_chat_user_command(self, iq):
|
def process_chat_user_command(self, iq):
|
||||||
parsed = []
|
parsed = iq['body'].split(' ')
|
||||||
|
jid = iq['from'].bare
|
||||||
|
|
||||||
if parsed[0] == '!search':
|
if parsed[0] == '!help':
|
||||||
pass
|
self.gate_reply_message(iq, '=== Available dialog commands ===:\n\n'
|
||||||
elif parsed[0] == '!get_history':
|
'!help - Displays this text\n'
|
||||||
pass
|
'!block - Blacklists current user\n'
|
||||||
elif parsed[0] == '!forward_messages':
|
'!unblock - Unblacklists current user\n'
|
||||||
pass
|
)
|
||||||
elif parsed[0] == '!delete_messages':
|
elif parsed[0] == '!block':
|
||||||
pass
|
tg_id = int(iq['to'].node[1:])
|
||||||
elif parsed[0] == '!block_status':
|
nickname = display_tg_name(self.tg_dialogs[jid]['users'][tg_id])
|
||||||
pass
|
self.tg_connections[jid].invoke(BlockRequest( InputPeerUser(tg_id, self.tg_dialogs[jid]['users'][tg_id].access_hash) ) )
|
||||||
elif parsed[0] == '!block_set':
|
self.gate_reply_message(iq, 'User %s blacklisted!' % nickname)
|
||||||
pass
|
|
||||||
elif parsed[0] == '!block_unser':
|
elif parsed[0] == '!unblock':
|
||||||
pass
|
tg_id = int(iq['to'].node[1:])
|
||||||
elif parsed[0] == '!clear_history':
|
nickname = display_tg_name(self.tg_dialogs[jid]['users'][tg_id])
|
||||||
pass
|
self.tg_connections[jid].invoke(UnblockRequest( InputPeerUser(tg_id, self.tg_dialogs[jid]['users'][tg_id].access_hash) ) )
|
||||||
elif parsed[0] == '!delete_conversation':
|
self.gate_reply_message(iq, 'User %s unblacklisted!' % nickname)
|
||||||
pass
|
|
||||||
elif parsed[0] == '!help':
|
|
||||||
pass
|
|
||||||
|
|
||||||
def process_chat_group_command(self, iq):
|
def process_chat_group_command(self, iq):
|
||||||
parsed = []
|
parsed = iq['body'].split(' ')
|
||||||
|
jid = iq['from'].bare
|
||||||
|
|
||||||
if parsed[0] == '!search':
|
if parsed[0] == '!help':
|
||||||
pass
|
self.gate_reply_message(iq, '=== Available chat commands ===:\n\n'
|
||||||
elif parsed[0] == '!get_history':
|
'!help - Displays this text\n'
|
||||||
pass
|
'!leave - Leaves current group or supergroup\n'
|
||||||
elif parsed[0] == '!forward_messages':
|
'!invite - Invites user to group\n'
|
||||||
pass
|
'!kick - Kicks user to group\n'
|
||||||
elif parsed[0] == '!delete_messages':
|
)
|
||||||
pass
|
elif parsed[0] == '!leave':
|
||||||
elif parsed[0] == '!pin_message':
|
tg_id = int(iq['to'].node[1:])
|
||||||
pass
|
if tg_id in self.tg_dialogs[jid]['supergroups']:
|
||||||
elif parsed[0] == '!unpin_message':
|
self.tg_connections[jid].invoke(LeaveChannelRequest( InputPeerChannel(tg_id, self.tg_dialogs[jid]['supergroups'][tg_id].access_hash) ) )
|
||||||
pass
|
c_jid = get_contact_jid(self.tg_dialogs[jid]['supergroups'][tg_id], self.boundjid.bare)
|
||||||
elif parsed[0] == '!leave_group':
|
self.send_presence(pto = jid, pfrom = c_jid, ptype = 'unavailable')
|
||||||
pass
|
self.send_presence(pto = jid, pfrom = c_jid, ptype = 'unsubscribed')
|
||||||
elif parsed[0] == '!add_members':
|
self.send_presence(pto = jid, pfrom = c_jid, ptype = 'unsubscribe')
|
||||||
pass
|
if tg_id in self.tg_dialogs[jid]['groups']:
|
||||||
elif parsed[0] == '!bans_list':
|
self.tg_connections[jid].invoke( DeleteChatUserRequest(tg_id, self.tg_connections[jid].me) )
|
||||||
pass
|
c_jid = get_contact_jid(self.tg_dialogs[jid]['groups'][tg_id], self.boundjid.bare)
|
||||||
elif parsed[0] == '!ban_user':
|
self.send_presence(pto = jid, pfrom = c_jid, ptype = 'unavailable')
|
||||||
pass
|
self.send_presence(pto = jid, pfrom = c_jid, ptype = 'unsubscribed')
|
||||||
elif parsed[0] == '!unban_user':
|
self.send_presence(pto = jid, pfrom = c_jid, ptype = 'unsubscribe')
|
||||||
pass
|
|
||||||
elif parsed[0] == '!restrict_user':
|
elif parsed[0] == '!invite':
|
||||||
pass
|
tg_id = int(iq['to'].node[1:])
|
||||||
elif parsed[0] == '!unrestrict_user':
|
if tg_id in self.tg_dialogs[jid]['supergroups']:
|
||||||
pass
|
invited_user = self.tg_connections[jid].get_entity(parsed[1])
|
||||||
elif parsed[0] == '!get_recent_actions':
|
if type(invited_user) == User:
|
||||||
pass
|
self.tg_connections[jid].invoke(EditBannedRequest( InputPeerChannel(tg_id, self.tg_dialogs[jid]['supergroups'][tg_id].access_hash), invited_user, ChannelBannedRights(until_date=None,view_messages=False) ) )
|
||||||
elif parsed[0] == '!get_recent_actions':
|
self.tg_connections[jid].invoke(InviteToChannelRequest( InputPeerChannel(tg_id, self.tg_dialogs[jid]['supergroups'][tg_id].access_hash), [invited_user] ) )
|
||||||
pass
|
if tg_id in self.tg_dialogs[jid]['groups']:
|
||||||
|
invited_user = self.tg_connections[jid].get_entity(parsed[1])
|
||||||
|
if type(invited_user) == User:
|
||||||
|
self.tg_connections[jid].invoke( AddChatUserRequest(tg_id, invited_user, 0) )
|
||||||
|
|
||||||
|
elif parsed[0] == '!kick':
|
||||||
|
tg_id = int(iq['to'].node[1:])
|
||||||
|
if tg_id in self.tg_dialogs[jid]['supergroups']:
|
||||||
|
kicked_user = self.tg_connections[jid].get_entity(parsed[1])
|
||||||
|
if type(invited_user) == User:
|
||||||
|
self.tg_connections[jid].invoke(EditBannedRequest( InputPeerChannel(tg_id, self.tg_dialogs[jid]['supergroups'][tg_id].access_hash), kicked_user, ChannelBannedRights(until_date=None,view_messages=True) ) )
|
||||||
|
if tg_id in self.tg_dialogs[jid]['groups']:
|
||||||
|
kicked_user = self.tg_connections[jid].get_entity(parsed[1])
|
||||||
|
if type(invited_user) == User:
|
||||||
|
self.tg_connections[jid].invoke( DeleteChatUserRequest(tg_id, kicked_user) )
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def spawn_tg_client(self, jid, phone):
|
def spawn_tg_client(self, jid, phone):
|
||||||
"""
|
"""
|
||||||
@@ -446,8 +480,9 @@ class XMPPTelegram(ComponentXMPP):
|
|||||||
:param phone:
|
:param phone:
|
||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
client = TelegramGateClient('a_'+phone, int(self.config['tg_api_id']), self.config['tg_api_hash'],
|
client = TelegramGateClient('a_'+phone, int(self.config['tg_api_id']), self.config['tg_api_hash'], self, jid, phone)
|
||||||
self, jid, phone)
|
if 'tg_server_ip' in self.config and 'tg_server_dc' in self.config and 'tg_server_port' in self.config:
|
||||||
|
client.session.set_dc(self.config['tg_server_dc'], self.config['tg_server_ip'], self.config['tg_server_port'])
|
||||||
client.connect()
|
client.connect()
|
||||||
|
|
||||||
self.tg_connections[jid] = client
|
self.tg_connections[jid] = client
|
||||||
@@ -498,9 +533,8 @@ class XMPPTelegram(ComponentXMPP):
|
|||||||
self.send(presence)
|
self.send(presence)
|
||||||
|
|
||||||
|
|
||||||
def tg_process_dialogs(self, jid):
|
def tg_process_dialogs(self, jid, sync_roster = True):
|
||||||
|
|
||||||
print('! -- Process Dialogs -- !')
|
|
||||||
# Инициализируем словари для диалогов
|
# Инициализируем словари для диалогов
|
||||||
self.tg_dialogs[jid] = dict()
|
self.tg_dialogs[jid] = dict()
|
||||||
self.tg_dialogs[jid]['raw'] = list()
|
self.tg_dialogs[jid]['raw'] = list()
|
||||||
@@ -534,15 +568,15 @@ class XMPPTelegram(ComponentXMPP):
|
|||||||
if type(dlg.peer) is PeerUser:
|
if type(dlg.peer) is PeerUser:
|
||||||
usr = self.tg_dialogs[jid]['users'][dlg.peer.user_id]
|
usr = self.tg_dialogs[jid]['users'][dlg.peer.user_id]
|
||||||
vcard = self.plugin['xep_0054'].make_vcard()
|
vcard = self.plugin['xep_0054'].make_vcard()
|
||||||
u_jid = 'u' + str(usr.id) + '@' + self.boundjid.bare
|
u_jid = get_contact_jid(usr, self.boundjid.bare)
|
||||||
|
|
||||||
if usr.deleted:
|
if usr.deleted:
|
||||||
rostername = "Deleted Account"
|
rostername = "Deleted Account"
|
||||||
vcard['FN'] = 'Deleted account'
|
vcard['FN'] = 'Deleted account'
|
||||||
vcard['DESC'] = 'This user no longer exists in Telegram'
|
vcard['DESC'] = 'This user no longer exists in Telegram'
|
||||||
else:
|
else:
|
||||||
rostername = display_tg_name(usr.first_name, usr.last_name)
|
rostername = display_tg_name(usr)
|
||||||
vcard['FN'] = display_tg_name(usr.first_name, usr.last_name)
|
vcard['FN'] = display_tg_name(usr)
|
||||||
if usr.first_name:
|
if usr.first_name:
|
||||||
vcard['N']['GIVEN'] = usr.first_name
|
vcard['N']['GIVEN'] = usr.first_name
|
||||||
if usr.last_name:
|
if usr.last_name:
|
||||||
@@ -559,62 +593,50 @@ class XMPPTelegram(ComponentXMPP):
|
|||||||
self.plugin['xep_0054'].publish_vcard(jid=u_jid, vcard=vcard)
|
self.plugin['xep_0054'].publish_vcard(jid=u_jid, vcard=vcard)
|
||||||
self.plugin['xep_0172'].publish_nick(nick=vcard['FN'], ifrom=u_jid)
|
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
|
self.contact_list[jid][u_jid] = rostername
|
||||||
|
|
||||||
if usr.bot:
|
if usr.bot:
|
||||||
self.send_presence(pto=jid, pfrom=u_jid, pstatus='Bot')
|
self.send_presence(pto=jid, pfrom=u_jid, pshow = 'chat', pstatus='Bot')
|
||||||
else:
|
else:
|
||||||
if type(usr.status) is UserStatusOnline:
|
if type(usr.status) is UserStatusOnline:
|
||||||
self.send_presence(pto=jid, pfrom=u_jid)
|
self.send_presence(pto=jid, pfrom=u_jid, pstatus = 'Online' )
|
||||||
elif type(usr.status) is UserStatusRecently:
|
elif type(usr.status) is UserStatusRecently:
|
||||||
self.send_presence(pto=jid, pfrom=u_jid, pshow='away', pstatus='Last seen recently')
|
self.send_presence(pto=jid, pfrom=u_jid, pshow='away', pstatus='Last seen recently')
|
||||||
elif type(usr.status) is UserStatusOffline:
|
elif type(usr.status) is UserStatusOffline:
|
||||||
self.send_presence(
|
self.send_presence(pto=jid, pfrom=u_jid, pshow='xa', pstatus=usr.status.was_online.strftime('Last seen at %H:%M %d/%m/%Y') )
|
||||||
pto=jid,
|
|
||||||
pfrom=u_jid,
|
|
||||||
ptype='xa',
|
|
||||||
pstatus=usr.status.was_online.strftime('Last seen at %H:%M %d/%m/%Y')
|
|
||||||
)
|
|
||||||
else:
|
else:
|
||||||
self.send_presence(pto=jid, pfrom=u_jid, ptype='unavailable',
|
self.send_presence(pto=jid, pfrom=u_jid, pshow='dnd', pstatus='Last seen a long time ago')
|
||||||
pstatus='Last seen a long time ago')
|
|
||||||
|
|
||||||
if type(dlg.peer) in [PeerChat, PeerChannel]:
|
if type(dlg.peer) in [PeerChat, PeerChannel]:
|
||||||
g_type = ''
|
|
||||||
cht = None
|
cht = None
|
||||||
|
|
||||||
if type(dlg.peer) is PeerChat: # Старая группа
|
if type(dlg.peer) is PeerChat: # Старая группа
|
||||||
cht = self.tg_dialogs[jid]['groups'][dlg.peer.chat_id]
|
cht = self.tg_connections[jid].invoke(GetFullChatRequest(dlg.peer.chat_id))
|
||||||
c_jid = 'g' + str(cht.id) + '@' + self.boundjid.bare
|
cht = cht.chats[0]
|
||||||
g_type = 'G'
|
if cht.deactivated or cht.left:
|
||||||
|
cht = None
|
||||||
elif type(dlg.peer) is PeerChannel: # Супергруппа
|
elif type(dlg.peer) is PeerChannel: # Супергруппа
|
||||||
cht = self.tg_dialogs[jid]['supergroups'][dlg.peer.channel_id]
|
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)
|
if cht and cht.id:
|
||||||
|
rostername = display_tg_name(cht)
|
||||||
|
c_jid = get_contact_jid(cht, self.boundjid.bare)
|
||||||
|
|
||||||
vcard = self.plugin['xep_0054'].make_vcard()
|
vcard = self.plugin['xep_0054'].make_vcard()
|
||||||
vcard['FN'] = '[{}] {}'.format(g_type, cht.title)
|
vcard['FN'] = rostername
|
||||||
vcard['NICKNAME'] = vcard['FN']
|
vcard['NICKNAME'] = rostername
|
||||||
vcard['JABBERID'] = c_jid
|
vcard['JABBERID'] = c_jid
|
||||||
self.plugin['xep_0054'].publish_vcard(jid=c_jid, vcard=vcard)
|
self.plugin['xep_0054'].publish_vcard(jid=c_jid, vcard=vcard)
|
||||||
self.plugin['xep_0172'].publish_nick(nick=vcard['FN'], ifrom=c_jid)
|
self.plugin['xep_0172'].publish_nick(nick=vcard['FN'], ifrom=c_jid)
|
||||||
|
|
||||||
self.contact_list[jid][c_jid] = rostername
|
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, pshow = 'chat', pstatus = cht.title)
|
||||||
self.send_presence(pto=jid, pfrom=c_jid)
|
|
||||||
|
|
||||||
if len(dlgs.dialogs) == 0: # Если все диалоги получены - прерываем цикл
|
if len(dlgs.dialogs) == 0: # Если все диалоги получены - прерываем цикл
|
||||||
if self.config['xmpp_use_roster_exchange']:
|
if sync_roster and 'use_roster_exchange' in self.accounts[jid] and self.accounts[jid]['use_roster_exchange'] == 'true':
|
||||||
self.roster_exchange(jid, self.contact_list[jid])
|
self.roster_exchange(jid, self.contact_list[jid])
|
||||||
else:
|
elif sync_roster:
|
||||||
self.roster_fill(jid, self.contact_list[jid])
|
self.roster_fill(jid, self.contact_list[jid])
|
||||||
break
|
break
|
||||||
else: # Иначе строим оффсеты
|
else: # Иначе строим оффсеты
|
||||||
@@ -632,7 +654,7 @@ class XMPPTelegram(ComponentXMPP):
|
|||||||
elif type(last_peer) in [Channel, ChannelForbidden]: # Супергруппа
|
elif type(last_peer) in [Channel, ChannelForbidden]: # Супергруппа
|
||||||
access_hash = self.tg_dialogs[jid]['supergroups'][last_peer.channel_id].access_hash
|
access_hash = self.tg_dialogs[jid]['supergroups'][last_peer.channel_id].access_hash
|
||||||
last_peer = InputPeerChannel(last_peer.channel_id, access_hash)
|
last_peer = InputPeerChannel(last_peer.channel_id, access_hash)
|
||||||
|
|
||||||
def tg_process_unread_messages(self):
|
def tg_process_unread_messages(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@@ -659,12 +681,6 @@ class XMPPTelegram(ComponentXMPP):
|
|||||||
conn = sqlite3.connect(self.config['db_connect'], isolation_level=None, check_same_thread=False)
|
conn = sqlite3.connect(self.config['db_connect'], isolation_level=None, check_same_thread=False)
|
||||||
conn.row_factory = dict_factory
|
conn.row_factory = dict_factory
|
||||||
|
|
||||||
conn.execute("CREATE TABLE IF NOT EXISTS accounts("
|
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)")
|
||||||
"jid VARCHAR(255),"
|
|
||||||
"tg_phone VARCHAR(25)"
|
|
||||||
")")
|
|
||||||
|
|
||||||
# conn.execute("CREATE TABLE IF NOT EXISTS roster("
|
|
||||||
# "")
|
|
||||||
|
|
||||||
return conn
|
return conn
|
||||||
|
|||||||
Reference in New Issue
Block a user