# -*- coding: future_fstrings -*- # Friendly Telegram (telegram userbot) # Copyright (C) 2018-2019 The Authors # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Affero General Public License for more details. # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see <https://www.gnu.org/licenses/>. import logging import inspect import itertools import ast import telethon from .. import loader, utils tlfuns = dict(filter(lambda mod: mod[1].__module__.startswith("telethon.tl.functions"), itertools.chain.from_iterable([inspect.getmembers(mod[1], inspect.isclass) for mod in inspect.getmembers(telethon.tl.functions, inspect.ismodule)]))) logger = logging.getLogger(__name__) def register(cb): cb(RemoteMod()) @loader.tds class RemoteMod(loader.Module): """Operate on other accounts""" strings = {"name": "Remote Control", "account_cfg_doc": "What to call this account in .remote commands", "what_account": "<b>What account and operation should be performed?</b>", "bad_command": "<b>Invalid command</b>", "bad_account": "<b>Invalid account</b>", "what_client_command": "<b>What custom client command should be executed?</b>", "bad_client_command": "<b>That custom client command does not exist!</b>", "what_ftg_command": "<b>What command should be executed?</b>", "what_raw_command": "<b>What raw MTProto command should be executed?</b>", "bad_raw_command": "<b>Invalid MTProto function</b>"} def __init__(self): self.config = loader.ModuleConfig("ACCOUNT_NAME", None, lambda: self.strings["account_cfg_doc"]) def config_complete(self): self.name = self.strings["name"] async def remotecmd(self, message): """Execute remote command""" # Validation args = utils.get_args(message) if len(args) < 2: await utils.answer(message, self.strings["what_account"]) return account = args[0].strip() command = getattr(self, args[1] + "_command", None) if not callable(command): await utils.answer(message, self.strings["bad_command"]) return account = await self.find_account(account) if account is None: await utils.answer(message, self.strings["bad_account"]) return await command(account, args[2:], message) async def find_account(self, account): # phone, id, username, first name, last name, full name clients = [] for client in self.allclients: clients += [[client, await client.get_me()]] for client, client_me in clients: if client_me.phone == account: return client for client, client_me in clients: if str(client_me.id) == account: return client for client, client_me in clients: if client_me.username == account: return client for client, client_me in clients: if client_me.first_name == account: return client for client, client_me in clients: if client_me.last_name and client_me.last_name == account: return client # Commands async def send_command(self, client, args, message): await client.send_message(args[0], " ".join(args[1:])) async def custom_command(self, client, args, message): if len(args) < 1: await utils.answer(message, self.strings["what_client_command"]) return cmd = getattr(client, args[0], None) if not callable(cmd): await utils.answer(message, self.strings["bad_client_command"]) return fargs = [] for arg in args[1:]: try: fargs.append(ast.literal_eval(arg)) except (ValueError, SyntaxError): fargs.append(arg) logger.debug(fargs) await cmd(*fargs) async def cmd_command(self, client, args, message): if len(args) < 1: await utils.answer(message, self.strings["what_ftg_command"]) return for load in self.allloaders: if load.client is client: break # This will always be fulfilled at some point logger.debug(args) message.message = " ".join(args[1:]) msg = await message.client.send_message(args[0], message) msg.message, func = load.dispatch(msg.message) await func(msg) async def raw_command(self, client, args, message): if len(args) < 1: await utils.answer(message, self.strings["what_raw_command"]) return if not args[0] in tlfuns.keys(): await utils.answer(message, self.strings["bad_raw_command"]) return func = tlfuns[args[0]] await client(func())