#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ TODO 1) Deprecate "add" (see above) and make it interactive. Slixfeed: Do you still want to add this URL to subscription list? See: case _ if command_lowercase.startswith("add"): 2) If subscription is inadequate (see XmppPresence.request), send a message that says so. elif not self.client_roster[jid]["to"]: breakpoint() message.reply("Share online status to activate bot.").send() return 3) Set timeout for moderator interaction. If moderator interaction has been made, and moderator approves the bot, then the bot will add the given groupchat to bookmarks; otherwise, the bot will send a message that it was not approved and therefore leaves the groupchat. """ import asyncio import os from pathlib import Path from random import randrange # pending_tasks: Use a list and read the first index (i.e. index 0). import slixfeed.config as config from slixfeed.config import Config import slixfeed.fetch as fetch from slixfeed.fetch import Http from slixfeed.log import Logger import slixfeed.sqlite as sqlite from slixfeed.syndication import FeedTask from slixfeed.utilities import Documentation, Html, MD, Task, Url from slixfeed.xmpp.commands import XmppCommands from slixfeed.xmpp.message import XmppMessage from slixfeed.xmpp.presence import XmppPresence from slixfeed.xmpp.status import XmppStatusTask from slixfeed.xmpp.upload import XmppUpload from slixfeed.xmpp.utilities import XmppUtilities from slixmpp import JID from slixmpp.stanza import Message import sys import time from typing import Optional try: from slixfeed.xmpp.encryption import XmppOmemo except Exception as e: print('Encryption of type OMEMO is not enabled. Reason: ' + str(e)) logger = Logger(__name__) # for task in main_task: # task.cancel() # Deprecated in favour of event "presence_available" # if not main_task: # await select_file() class XmppChat: async def process_message(self, message: Message, allow_untrusted: bool = False) -> None: """ Process incoming message stanzas. Be aware that this also includes MUC messages and error messages. It is usually a good practice to check the messages's type before processing or sending replies. Parameters ---------- message : str The received message stanza. See the documentation for stanza objects and the Message stanza to see how it may be used. """ message_from = message['from'] message_type = message['type'] if message_type in ('chat', 'groupchat', 'normal'): jid_bare = message_from.bare command = ' '.join(message['body'].split()) command_time_start = time.time() # if (message_type == 'groupchat' and # message['muc']['nick'] == self.alias): # return # FIXME Code repetition. See below. # TODO Check alias by nickname associated with conference if message_type == 'groupchat': alias = message['muc']['nick'] if (alias == self.alias): return if not XmppUtilities.is_moderator(self, jid_bare, alias): return # nick = message['from'][message['from'].index('/')+1:] # nick = str(message['from']) # nick = nick[nick.index('/')+1:] alias_of_slixfeed = XmppUtilities.get_self_alias(self, jid_bare) if (alias == self.alias or not message['body'].startswith(alias_of_slixfeed)): return # token = await initdb( # jid_bare, # sqlite.get_setting_value, # 'token' # ) # if token == 'accepted': # operator = await initdb( # jid_bare, # sqlite.get_setting_value, # 'masters' # ) # if operator: # if nick not in operator: # return # approved = False if not XmppUtilities.is_moderator(self, jid_bare, alias): return # if role == 'moderator': # approved = True # TODO Implement a list of temporary operators # Once an operator is appointed, the control would last # untile the participant has been disconnected from MUC # An operator is a function to appoint non moderators. # Changing nickname is fine and consist of no problem. # if not approved: # operator = await initdb( # jid_bare, # sqlite.get_setting_value, # 'masters' # ) # if operator: # if nick in operator: # approved = True # if not approved: # return # # Begin processing new JID # # Deprecated in favour of event 'presence_available' # db_dir = config.get_default_data_directory() # os.chdir(db_dir) # if jid + '.db' not in os.listdir(): # await task_jid(jid) # await compose.message(self, jid_bare, message) if self.omemo_present and self['xep_0384'].is_encrypted(message): command, omemo_decrypted = await XmppOmemo.decrypt( self, message) else: omemo_decrypted = None if message_type == 'groupchat': # Adding one to the length because of # assumption that a comma or a dot is added alias_of_slixfeed_length = len(alias_of_slixfeed) + 1 command = command[alias_of_slixfeed_length:].lstrip() if isinstance(command, Message): command = command['body'] command_lowercase = command.lower() # This is a work-around to empty messages that are caused by function # self.register_handler(CoroutineCallback( of module client.py. # The code was taken from the cho bot xample of slixmpp-omemo. #if not command_lowercase: return logger.debug([message_from.full, ':', command]) # Support private message via groupchat # See https://codeberg.org/poezio/slixmpp/issues/3506 if message_type == 'chat' and message.get_plugin('muc', check=True): # jid_bare = message_from.bare jid_full = message_from.full if (jid_bare == jid_full[:jid_full.index('/')]): # TODO Count and alert of MUC-PM attempts return response = None db_file = config.get_pathname_to_database(jid_bare) match command_lowercase: case 'help': command_list = XmppCommands.print_help() response = ('Available command keys:\n' '```\n{}\n```\n' 'Usage: `help `' .format(command_list)) case 'help all': command_list = Documentation.manual('commands.toml', section='all') response = ('Complete list of commands:\n' '```\n{}\n```' .format(command_list)) case _ if command_lowercase.startswith('help'): command = command[5:].lower() command = command.split(' ') if len(command) == 2: command_root = command[0] command_name = command[1] command_list = Documentation.manual( 'commands.toml', section=command_root, command=command_name) if command_list: command_list = ''.join(command_list) response = (command_list) else: response = ('KeyError for {} {}' .format(command_root, command_name)) elif len(command) == 1: command = command[0] command_list = Documentation.manual('commands.toml', command) if command_list: command_list = ' '.join(command_list) response = ('Available command `{}` keys:\n' '```\n{}\n```\n' 'Usage: `help {} `' .format(command, command_list, command)) else: response = 'KeyError for {}'.format(command) else: response = ('Invalid. Enter command key ' 'or command key & name') case 'info': entries = XmppCommands.print_info_list(self) response = ('Available command options:\n' '```\n{}\n```\n' 'Usage: `info