From c9bf69bbfdda0ee29122e6ba6d3d2bba40886a8a Mon Sep 17 00:00:00 2001 From: "Schimon Jehudah, Adv." Date: Thu, 21 Nov 2024 12:11:11 +0200 Subject: [PATCH] Automate installation of configurations; Update document README. --- README.md | 6 -- kaikout/__main__.py | 76 ++++++++++++++----- kaikout/config.py | 31 ++++---- kaikout/{assets => configs}/accounts.toml | 4 +- kaikout/database.py | 5 +- kaikout/utilities.py | 91 ++++++++++++----------- kaikout/version.py | 4 +- kaikout/xmpp/groupchat.py | 5 ++ kaikout/xmpp/muc.py | 3 + 9 files changed, 137 insertions(+), 88 deletions(-) rename kaikout/{assets => configs}/accounts.toml (95%) diff --git a/README.md b/README.md index 809343c..149d5b3 100644 --- a/README.md +++ b/README.md @@ -99,12 +99,6 @@ Start by executing the command `kaikout` and enter Username and Password of an e $ kaikout ``` -You can also start KaikOut as follows: - -``` -$ kaikout --jid ACCOUNT_JABBER_ID --password ACCOUNT_PASSWORD -``` - It is advised to use a dedicated extra account for KaikOut. ## Recommended Clients diff --git a/kaikout/__main__.py b/kaikout/__main__.py index 9534e5e..bb4d44b 100644 --- a/kaikout/__main__.py +++ b/kaikout/__main__.py @@ -6,17 +6,37 @@ # See the file LICENSE for copying permission. # from kaikout.about import Documentation -from kaikout.utilities import Config +from kaikout.utilities import Config, Toml # from kaikout.xmpp.chat import XmppChat from kaikout.xmpp.client import XmppClient from getpass import getpass from argparse import ArgumentParser import logging -# import os +import os +import shutil # import slixmpp # import sys def main(): + + directory = os.path.dirname(__file__) + + # Copy data files + directory_data = Config.get_default_config_directory() + # TODO Utilize the actual data directory + #directory_data = Config.get_default_data_directory() + if not os.path.exists(directory_data): + directory_assets = os.path.join(directory, 'assets') + directory_assets_new = shutil.copytree(directory_assets, directory_data) + print(f'Data directory {directory_assets_new} has been created and populated.') + + # Copy settings files + directory_settings = Config.get_default_config_directory() + if not os.path.exists(directory_settings): + directory_configs = os.path.join(directory, 'configs') + directory_settings_new = shutil.copytree(directory_configs, directory_settings) + print(f'Configuration directory {directory_settings_new} has been created and populated.') + # Setup the command line arguments. parser = ArgumentParser(description=XmppClient.__doc__) @@ -28,32 +48,52 @@ def main(): action="store_const", dest="loglevel", const=logging.DEBUG, default=logging.INFO) - # JID and password options. - parser.add_argument("-j", "--jid", dest="jid", - help="JID to use") - parser.add_argument("-p", "--password", dest="password", - help="password to use") - args = parser.parse_args() # Setup logging. logging.basicConfig(level=args.loglevel, format='%(levelname)-8s %(message)s') - account_xmpp = Config.get_values('accounts.toml', 'xmpp') + # Configure settings file + file_settings = os.path.join(directory_settings, 'accounts.toml') + if not os.path.exists(file_settings): + directory_configs = os.path.join(directory, 'configs') + file_settings_empty = os.path.join(directory_configs, 'accounts.toml') + shutil.copyfile(file_settings_empty, file_settings) - if args.jid is None and not account_xmpp['client']['jid']: - args.jid = input("Username: ") - if args.password is None and not account_xmpp['client']['password']: - args.password = getpass("Password: ") + data_settings = Toml.open_file(file_settings) + + # Configure account + data_settings_account = data_settings['xmpp']['client'] + + settings_account = { + 'alias': 'Set an Alias', + 'jid': 'Set a Jabber ID', + 'password': 'Input Password' + } + + for key in settings_account: + data_settings_account_value = data_settings_account[key] + if not data_settings_account_value: + settings_account_message = settings_account[key] + while not data_settings_account_value: + if key == 'password': + data_settings_account_value = getpass(f'{settings_account_message}: ') + else: + data_settings_account_value = input(f'{settings_account_message}: ') + data_settings_account[key] = data_settings_account_value + + Toml.save_file(file_settings, data_settings) # Try configuration file + account_xmpp = Config.get_values('accounts.toml', 'xmpp') if 'client' in account_xmpp: - jid = account_xmpp['client']['jid'] - password = account_xmpp['client']['password'] - alias = account_xmpp['client']['alias'] if 'alias' in account_xmpp['client'] else None - hostname = account_xmpp['client']['hostname'] if 'hostname' in account_xmpp['client'] else None - port = account_xmpp['client']['port'] if 'port' in account_xmpp['client'] else None + account_xmpp_client = account_xmpp['client'] + jid = account_xmpp_client['jid'] + password = account_xmpp_client['password'] + alias = account_xmpp_client['alias'] if 'alias' in account_xmpp_client else None + hostname = account_xmpp_client['hostname'] if 'hostname' in account_xmpp_client else None + port = account_xmpp_client['port'] if 'port' in account_xmpp_client else None XmppClient(jid, password, hostname, port, alias) if __name__ == '__main__': diff --git a/kaikout/config.py b/kaikout/config.py index 75cf85a..2a6761a 100644 --- a/kaikout/config.py +++ b/kaikout/config.py @@ -16,16 +16,16 @@ class Config: def get_default_data_directory(): - if os.environ.get('HOME'): - data_home = os.path.join(os.environ.get('HOME'), '.local', 'share') + directory_home = os.environ.get('HOME') + if directory_home: + data_home = os.path.join(directory_home, '.local', 'share') return os.path.join(data_home, 'kaikout') elif sys.platform == 'win32': data_home = os.environ.get('APPDATA') if data_home is None: - return os.path.join( - os.path.dirname(__file__) + '/kaikout_data') + return 'kaikout_data' else: - return os.path.join(os.path.dirname(__file__) + '/kaikout_data') + return 'kaikout_data' def get_default_config_directory(): @@ -42,19 +42,20 @@ class Config: str Path to configuration directory. """ - # config_home = xdg.BaseDirectory.xdg_config_home - config_home = os.environ.get('XDG_CONFIG_HOME') - if config_home is None: - if os.environ.get('HOME') is None: + # directory_config_home = xdg.BaseDirectory.xdg_config_home + directory_config_home = os.environ.get('XDG_CONFIG_HOME') + if directory_config_home is None: + directory_home = os.environ.get('HOME') + if directory_home is None: if sys.platform == 'win32': - config_home = os.environ.get('APPDATA') - if config_home is None: - return os.path.abspath('.') + directory_config_home = os.environ.get('APPDATA') + if directory_config_home is None: + return 'kaikout_config' else: - return os.path.abspath('.') + return 'kaikout_config' else: - config_home = os.path.join(os.environ.get('HOME'), '.config') - return os.path.join(config_home, 'kaikout') + directory_config_home = os.path.join(directory_home, '.config') + return os.path.join(directory_config_home, 'kaikout') def get_values(filename, key=None): diff --git a/kaikout/assets/accounts.toml b/kaikout/configs/accounts.toml similarity index 95% rename from kaikout/assets/accounts.toml rename to kaikout/configs/accounts.toml index b1a4b5d..f03783e 100644 --- a/kaikout/assets/accounts.toml +++ b/kaikout/configs/accounts.toml @@ -26,8 +26,8 @@ BDAY = "20 June 2024" #DESC = "" [xmpp.client] -alias = "KaikOut" -jid = "/KaikOut" +alias = "" +jid = "" password = "" [tox] diff --git a/kaikout/database.py b/kaikout/database.py index 4ba775f..a1bceb2 100644 --- a/kaikout/database.py +++ b/kaikout/database.py @@ -482,10 +482,9 @@ class Toml: elif sys.platform == 'win32': data_home = os.environ.get('APPDATA') if data_home is None: - return os.path.join( - os.path.dirname(__file__), 'kaikout_data') + return 'kaikout_data' else: - return os.path.join(os.path.dirname(__file__), 'kaikout_data') + return 'kaikout_data' def get_data_file(data_dir, room): diff --git a/kaikout/utilities.py b/kaikout/utilities.py index 60cef2f..190d63a 100644 --- a/kaikout/utilities.py +++ b/kaikout/utilities.py @@ -37,16 +37,16 @@ class Config: str Path to data directory. """ - if os.environ.get('HOME'): - data_home = os.path.join(os.environ.get('HOME'), '.local', 'share') + directory_home = os.environ.get('HOME') + if directory_home: + data_home = os.path.join(directory_home, '.local', 'share') return os.path.join(data_home, 'kaikout') elif sys.platform == 'win32': data_home = os.environ.get('APPDATA') if data_home is None: - return os.path.join( - os.path.dirname(__file__), 'kaikout_data') + return 'kaikout_data' else: - return os.path.join(os.path.dirname(__file__), 'kaikout_data') + return 'kaikout_data' def get_default_config_directory(): @@ -63,21 +63,20 @@ class Config: str Path to configuration directory. """ - # config_home = xdg.BaseDirectory.xdg_config_home - config_home = os.environ.get('XDG_CONFIG_HOME') - if config_home is None: - if os.environ.get('HOME') is None: + # directory_config_home = xdg.BaseDirectory.xdg_config_home + directory_config_home = os.environ.get('XDG_CONFIG_HOME') + if directory_config_home is None: + directory_home = os.environ.get('HOME') + if directory_home is None: if sys.platform == 'win32': - config_home = os.environ.get('APPDATA') - if config_home is None: - return os.path.abspath('.') + directory_config_home = os.environ.get('APPDATA') + if directory_config_home is None: + return 'kaikout_config' else: - return os.path.abspath('.') + return 'kaikout_config' else: - config_home = os.path.join( - os.environ.get('HOME'), '.config' - ) - return os.path.join(config_home, 'kaikout') + directory_config_home = os.path.join(directory_home, '.config') + return os.path.join(directory_config_home, 'kaikout') def get_setting_value(db_file, key): @@ -349,33 +348,8 @@ class BlockList: filename = BlockList.get_filename() with open(filename, 'w') as f: f.write(content) - -class Url: - - - def check_xmpp_uri(uri): - """ - Check validity of XMPP URI. - - Parameters - ---------- - uri : str - URI. - - Returns - ------- - jid : str - JID or None. - """ - jid = urlsplit(uri).path - if parseaddr(jid)[1] != jid: - jid = False - return jid - - class String: - def md5_hash(url): """ Hash URL string to MD5 checksum. @@ -394,3 +368,36 @@ class String: url_hashed = hashlib.md5(url_encoded) url_digest = url_hashed.hexdigest() return url_digest + +class Toml: + + def open_file(filename: str) -> dict: + with open(filename, mode="rb") as fn: + data = tomllib.load(fn) + return data + + def save_file(filename: str, data: dict) -> None: + with open(filename, 'w') as fn: + data_as_string = tomli_w.dumps(data) + fn.write(data_as_string) + +class Url: + + def check_xmpp_uri(uri): + """ + Check validity of XMPP URI. + + Parameters + ---------- + uri : str + URI. + + Returns + ------- + jid : str + JID or None. + """ + jid = urlsplit(uri).path + if parseaddr(jid)[1] != jid: + jid = False + return jid diff --git a/kaikout/version.py b/kaikout/version.py index f2bc63c..64ca029 100644 --- a/kaikout/version.py +++ b/kaikout/version.py @@ -1,2 +1,2 @@ -__version__ = '0.0.6' -__version_info__ = (0, 0, 6) +__version__ = '0.0.7' +__version_info__ = (0, 0, 7) diff --git a/kaikout/xmpp/groupchat.py b/kaikout/xmpp/groupchat.py index 287e5ae..584b3d5 100644 --- a/kaikout/xmpp/groupchat.py +++ b/kaikout/xmpp/groupchat.py @@ -20,6 +20,7 @@ from kaikout.xmpp.bookmark import XmppBookmark from kaikout.xmpp.muc import XmppMuc from kaikout.xmpp.status import XmppStatus from kaikout.log import Logger, Message +import random logger = Logger(__name__) @@ -37,12 +38,16 @@ class XmppGroupchat: alias = bookmark["nick"] room = bookmark["jid"] Message.printer('Joining to MUC {} ...'.format(room)) + result = await XmppMuc.join(self, room, alias) if result == 'ban': await XmppBookmark.remove(self, room) logger.warning('{} is banned from {}'.format(self.alias, room)) logger.warning('Groupchat {} has been removed from bookmarks' .format(room)) + elif result == 'conflict': + number = str(random.randrange(1000, 5000)) + await XmppMuc.join(self, room, alias + '_' + number) else: mucs_join_success.append(room) logger.info('Autojoin groupchat\n' diff --git a/kaikout/xmpp/muc.py b/kaikout/xmpp/muc.py index 6b6447f..9c79b5e 100644 --- a/kaikout/xmpp/muc.py +++ b/kaikout/xmpp/muc.py @@ -156,6 +156,9 @@ class XmppMuc: e.presence['error']['code'] == '403'): logger.warning('{} is banned from {}'.format(self.alias, jid)) result = 'ban' + elif e.condition == 'conflict': + logger.warning(e.presence['error']['text']) + result = 'conflict' else: result = 'error' except Exception as e: