diff --git a/doc/apps.rst b/doc/apps.rst index 007ea6cc..4aa89dd8 100644 --- a/doc/apps.rst +++ b/doc/apps.rst @@ -1,27 +1,21 @@ .. _libervia-app-config: -Libervia Apps -============= +================================= +Libervia App Configuration (YAML) +================================= -Libervia Apps are third party software, embedded and integrated in Libervia, usually as -containers (Podman, Docker). +The Libervia application uses a YAML configuration file to define various aspects of the +application's behavior, environment, and settings. -Each app is defined by a YAML configuration file, which describes how to run it and which -settings are exposed. App files are named ``libervia_app_.yaml`` and are discovered -from the app manager plugin directories. +The file will be parsed by `PyYAML`_ which is a full-featured YAML implementation. Check +its documentation for details. -Below is the documentation of each field of the YAML file. +Below is the documentation explaining the structure and functionality of each field in the +YAML file. ------------------ +================= Root-Level Fields ------------------ - -- ``name``: Human readable name of the application. The file name (without the - ``libervia_app_`` prefix) is used when not specified. - -- ``single_instance``: When ``True`` (default), only one instance of the application can - be started at a time, and its data are kept between restarts. When ``False``, each start - creates a new temporary instance directory, removed when the backend is unloaded. +================= - ``type``: Specifies the type of the application. See :ref:`libervia-app_type`. @@ -33,18 +27,16 @@ Root-Level Fields - ``expose``: Specifies configurations exposed to frontends or administrators. See :ref:`libervia-app_expose`. ------------------- +================== Detailed Sections ------------------- +=================== .. _libervia-app_type: type ^^^^ -Currently, the only supported type is ``docker-compose``. The container engine is chosen -with the ``engine`` plugin setting: ``auto`` (default, Podman is tried first), ``docker`` -or ``podman``. +Currently, the only supported type is ``docker-compose``. .. _libervia-app_prepare: @@ -54,7 +46,7 @@ prepare The ``prepare`` section specifies things like git repositories to be cloned before running the application. Example -~~~~~~~ +------- Cloning the repository at `https://example.org/some/repository.git` to prepare the app: .. code-block:: yaml @@ -73,7 +65,7 @@ The YAML key is the name of the file to be created, and the content specified wi populate that file. Example -~~~~~~~ +------- Creating a file named `settings-override.py` with the content `USE_X_FORWARDED_HOST = True`: .. code-block:: yaml @@ -94,7 +86,7 @@ creates a ``docker-compose.override.yml`` file that will be merged with the defa `_. Example -~~~~~~~ +------- Overriding the `ports` for the `example_app` service to expose port `8080`: .. code-block:: yaml @@ -110,31 +102,9 @@ Overriding the `ports` for the `example_app` service to expose port `8080`: Exposing Data ^^^^^^^^^^^^^ -The ``expose`` section specifies the data exposed to users, frontends or administrators. - -The following keys are used by the Web frontend: - -url_prefix - The internal URL where the app will be served. -web_label - Label which will be used in the Web frontend. -web_url_path - Public facing URL path which will be used in the Web frontend to access the app. -web_external - If True, the Web frontend will open the app in a separated page instead of embedding - it. -front_url - Whole URL to access the app, useful when it has its own domain or subdomain. The - ``https`` scheme is added if not specified. - -Ports and generated passwords are exposed in dicts, respectively at the ``ports`` and -``passwords`` keys. Each entry of ``ports`` maps a name to the compose ``service`` and -``private`` (container) port, it is resolved to the exposed ``host:port`` when the app is -running. Each entry of ``passwords`` maps a name to the list of keys leading to the value -to expose in the application data. - -``url_prefix`` and ``front_url`` can also be specified as a list of keys leading to the -value in the application data. +The `expose` section specifies the configurations that are exposed to users or frontends. +See :ref:`libervia-app_param` for a reference of some exposed data. Ports and generated +passwords are exposed in dicts, respectively at the ``ports`` and ``passwords`` key. .. _libervia-app_yaml-tags: @@ -146,49 +116,32 @@ The following YAML tags can be used in the Libervia App configuration file: .. _libervia-app_conf: !libervia_conf -^^^^^^^^^^^^^^ +++++++++++++++ -Get a value from the Libervia configuration. It takes a list of 1 to 4 items: +Get a value from Libervia configuration. A list is expected with either: -- ``[NAME]``: the ``NAME`` option of the ``[common]`` section -- ``[SECTION, NAME]``: the ``NAME`` option of the section named ``SECTION`` -- ``[SECTION, NAME, DEFAULT]``: use ``DEFAULT`` if the option is not set -- ``[SECTION, NAME, DEFAULT, FILTER]``: apply a filter to the value (see below) +- `name` of a config parameter +- `section` and `name` of a config parameter +- `section`, `name`, and `default` value of a config parameter +- `section`, `name`, `default` value, and `filter` (either `first` or `not`) -The ``application.`` section refers to the configuration section of the -```` application (e.g. ``application.peertube``). +Filter options: -Available filters: +- `first`: get the first item of the value +- `not`: get the opposite value (to be used with booleans) -- ``first``: get the first item of the value -- ``not``: get the opposite value (to be used with booleans) - -Examples -~~~~~~~~ -Getting a value from an application configuration section: +Example +------- +Getting a value from Libervia configuration: .. code-block:: yaml - !libervia_conf [application.peertube, hostname] - -Getting the SMTP server from the ``[email]`` section (an empty default is -used when the option is not set): - -.. code-block:: yaml - - !libervia_conf [email, server, ""] - -Getting the first email of the ``[common]`` section admin list (using the -``first`` filter): - -.. code-block:: yaml - - !libervia_conf [common, email_admins_list, "", first] + !libervia_conf [section, name, default] .. _libervia-app_generate_pwd: !libervia_generate_pwd -^^^^^^^^^^^^^^^^^^^^^^ ++++++++++++++++++++++ Generate a password and store it in persistent data. If the password has already been generated previously, it is reused. @@ -199,7 +152,7 @@ Arguments: - `size` (int): Size of the password to generate. Default to 30 Example -~~~~~~~ +------- Generating a password named ``some_password`` with a size of 32 characters: .. code-block:: yaml @@ -209,23 +162,35 @@ Generating a password named ``some_password`` with a size of 32 characters: .. _libervia-app_param: !libervia_param -^^^^^^^^^^^^^^^ +++++++++++++++ Get a parameter specified when starting the application. The value can be either the name of the parameter to get, or a list as `[name, default_value]`. + + Available parameters: url_prefix - The internal URL where the app will be served, it is given by the Web frontend. -front_url_path - The URL path which will be used in the Web frontend to access the app. + The internal URL where the app will be served. +web_label + Label which will be used in Web frontend. +web_url_path + Public facing URL path which will be used in the web frontend to access the app. +web_external + If True, the web frontend will open the app in a separated page instead of embedding + it. +front_url + Whole URL to access the app. It is specified when the app has its own domain or + subdomain. Example -~~~~~~~ +------- Getting a parameter: .. code-block:: yaml !libervia_param [url_prefix, /some_app] +.. _PyYAML: https://pyyaml.org/ + diff --git a/doc/components.rst b/doc/components.rst index dc3d99a8..4611faf4 100644 --- a/doc/components.rst +++ b/doc/components.rst @@ -1,8 +1,8 @@ .. _components: -========== -Components -========== +=================== +Libervia Components +=================== Libervia can act as an XMPP server component, which can be seen as a generic plugin for XMPP servers. @@ -38,20 +38,23 @@ OpenFire Prosody https://prosody.im/doc/components -.. Tigase documentation is down (2026-11-03, the whole docs.tigase.net site is 404), - uncomment once it's back: -.. Tigase -.. https://docs.tigase.net/en/latest/Tigase_Administration/Components/_Components.html#external-component-configuration +Tigase + https://docs.tigase.net/en/latest/Tigase_Administration/Components/_Components.html#external-component-configuration Simplified Component Configuration ================================== Most user will want to use this simplified configuration. To set up a component, you -simply need to create a configuration section named after the entry point, with dashes -replaced by underscores (e.g. the ``email-gateway`` entry point uses the -``[component.email_gateway]`` section), where you'll set the ``jid`` and ``secret`` -options. Everything will be automatically configured on backend startup, and the -component will start automatically. +simply need to create a configuration section with ``[component.]`` where +you'll set the ``jid`` and ``secret`` options. Everything will be automatically configured +on backend startup, and the component will start automatically. + +settings +-------- + +In ``[component.]``: + +.. autopydantic_settings:: libervia.backend.tools.config.ComponentSettings example ------- @@ -66,10 +69,6 @@ find that it's ``pubsub``, then you simply put in your configuration (usually jid = "pubsub.example.org" secret = "your_shared_secret" -To run the component in an isolated backend instance (e.g. as a dedicated systemd -service), see :ref:`installation_system`. To work with such an instance from the CLI, -use the ``-i/--isolation`` option (see :ref:`li_isolation`). - Manual Component Configuration ============================== @@ -109,14 +108,6 @@ wants to connect it immediately, she can use:: $ li profile connect -cp ap-gateway -Common Component Settings -========================= - -Besides component specific options (see the component sections below), every -component supports these common options in its configuration section: - -.. autopydantic_settings:: libervia.backend.tools.config.ComponentSettings - Available Components ==================== @@ -148,7 +139,7 @@ entities (JIDs). Permissions can be set through Ad-Hoc Commands. Configuration ~~~~~~~~~~~~~ -All options are to be set in ``[component.file_sharing]`` section. +All options are to be set in ``[components.file_sharing]`` section. ``http_upload_port`` port to use for HTTP File Upload @@ -225,13 +216,7 @@ documentation to find how this must be done. Configuration ~~~~~~~~~~~~~ -All options are to be set in ``[component.ap_gateway]`` section: - -.. autopydantic_settings:: libervia.backend.plugins.plugin_comp_ap_gateway.settings.APGatewaySettings - -By default, the HTTP server uses HTTPS, thus a TLS certificate is required, either in the -``tls`` option or in the global ``[tls]`` section. If an HTTPS proxy already handles TLS, -use ``http_connection_type = "http"`` instead. +All options are to be set in ``[components.ap_gateway]`` section. .. _ap-actor-from-xmpp: @@ -760,7 +745,7 @@ any kind of extra informations) while AP only indicates if one will attend or no event. -.. _Mobilizon: https://mobilizon.org/ +.. _Mobilizon: https://joinmobilizon.org/ Using the Component (for developers) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -827,8 +812,6 @@ All options are to be set in the ``[component.conferences]`` section. .. _Galène project: https://galene.org/ -.. _email-gateway: - Email Gateway ------------- diff --git a/doc/conf.py b/doc/conf.py index d8ff1d9b..9224fa1e 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -60,9 +60,6 @@ rst_prolog = """ # ones. extensions = ["sphinx.ext.autodoc", "docstring", "sphinxcontrib.autodoc_pydantic"] -# do not show pydantic field constraints (custom validators are not meaningful here) -autodoc_pydantic_field_show_constraints = False - # Add any paths that contain templates here, relative to this directory. templates_path = [".templates"] @@ -85,8 +82,7 @@ language = "en" # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. # This pattern also affects html_static_path and html_extra_path. -# the TUI is temporarily on hold and broken, its documentation is excluded -exclude_patterns = [".build", "Thumbs.db", ".DS_Store", "libervia-tui"] +exclude_patterns = [".build", "Thumbs.db", ".DS_Store"] # The name of the Pygments (syntax highlighting) style to use. pygments_style = None @@ -124,7 +120,7 @@ html_static_path = [".static"] # -- Options for HTMLHelp output --------------------------------------------- # Output file base name for HTML help builder. -htmlhelp_basename = "LiberviaBackenddoc" +htmlhelp_basename = "SalutToidoc" # -- Options for LaTeX output ------------------------------------------------ @@ -148,13 +144,7 @@ latex_elements = { # (source start file, target name, title, # author, documentclass [howto, manual, or own class]). latex_documents = [ - ( - master_doc, - "LiberviaBackend.tex", - "Libervia Backend Documentation", - "Libervia team", - "manual", - ), + (master_doc, "SalutToi.tex", "Libervia Documentation", "Libervia team", "manual"), ] @@ -173,10 +163,10 @@ man_pages = [(master_doc, "saluttoi", "Libervia Documentation", [author], 1)] texinfo_documents = [ ( master_doc, - "LiberviaBackend", - "Libervia Backend Documentation", + "SalutToi", + "Libervia Documentation", author, - "LiberviaBackend", + "SalutToi", "One line description of project.", "Miscellaneous", ), diff --git a/doc/howto_backup.rst b/doc/howto_backup.rst index 192aeb03..22bc4392 100644 --- a/doc/howto_backup.rst +++ b/doc/howto_backup.rst @@ -20,7 +20,7 @@ A backup is made of data *types*, included or excluded with ``-i/--include`` and - ``private``: private storage: PEP-like client data, OMEMO crypto keys, PGP trust state - ``roster``: contact lists (from the roster cache in the database, kept up to date on every connection) -- ``pep``: client PEP nodes and items (nick, avatar metadata, …) +- ``pep``: client PEP nodes and items (nick, avatar metadata, ...) - ``gpg``: GPG home per profile (public and secret keys) - ``files``: shared files (the blobs of ``~/.sat/files/``) - ``db``: full copy of the database (not portable, SQLite only) diff --git a/doc/howto_email_gateway.rst b/doc/howto_email_gateway.rst index 19e43539..d0c21eab 100644 --- a/doc/howto_email_gateway.rst +++ b/doc/howto_email_gateway.rst @@ -4,23 +4,18 @@ How-To: Email Gateway ===================== -This document explains how to configure and use the Libervia Email Gateway component. +This document explains how to configure and use the Libervia Email Gateway component. **Note that the Libervia backend must be installed first** (see :ref:`installation`). -The Email Gateway component allows users to send and receive emails through XMPP clients -and connect mailing lists to XMPP forums. It connects to IMAP/SMTP servers using -credentials provided by users during registration. - -For the supported features and other details, refer to the :ref:`email-gateway` section -of the components documentation. +The Email Gateway component allows users to send and receive emails through XMPP clients and convert mailing list to XMPP forums. It connects to IMAP/SMTP servers using credentials provided by users during registration. Prerequisites ------------- Before configuring the Email Gateway, ensure you have: -1. Libervia backend installed and working (see :ref:`installation`) -2. An XMPP server configured with component support (such as Prosody, Ejabberd, - Openfire, Tigase, MongooseIM, etc). +1. Libervia backend installed and running (see :ref:`installation`) +2. An XMPP server configured with component support (such as Prosody, Ejabberd, Openfire, + Tigase, MongooseIM, etc). Configuration Steps ------------------- @@ -35,7 +30,7 @@ Configuration Steps -- Add to /etc/prosody/prosody.cfg.lua Component "email.example.org" - component_secret = "secret" + component_secret = "your_unique_secret" *For Ejabberd:* @@ -51,26 +46,30 @@ Configuration Steps module: ejabberd_service hosts: "email.example.org": - password: "secret" + password: "your_unique_secret" - Of course replace ``email.example.org`` with your actual domain and ``secret`` with a - secure random string (you may use ``openssl rand -hex 16`` to generate one). + **Important:** Replace `email.example.org` with your actual domain and `your_unique_secret` with a secure random string (you may use `openssl rand -hex 16` to generate). -2. **Configure the Email Gateway Component in Libervia** +2. **Create Libervia Profile for Email Gateway** - Add the following section to your Libervia configuration file (usually - ``libervia.toml``), using the same JID and shared secret as the ones configured on - your XMPP server: + Use the Libervia CLI to create the gateway profile: - .. code-block:: toml + .. code-block:: bash - [component.email_gateway] - jid = "email.example.org" - secret = "secret" + $ li profile create email-gateway \ + -j email.example.org \ + -p "" \ + -x "your_unique_secret" \ + -C email-gateway \ + -A - The component profile is then created automatically on backend startup, and the - component starts automatically. See :ref:`components` for details about the - components configuration. + This creates a profile named `email-gateway` with: + + - JID: `email.example.org` + - No profile password (`-p ""`), to avoid password prompts during Libervia backend startup. + - XMPP server shared secret (`-x "your_unique_secret"`) + - Component entry point (`-C email-gateway`) + - Auto-connect enabled (`-A`) 3. **User Registration** @@ -82,7 +81,7 @@ Configuration Steps .. code-block:: bash - $ li gateway register -c -p your_user_profile email.example.org + $ li gateway register -cp your_user_profile email.example.org **Registration Fields** @@ -118,16 +117,55 @@ Configuration Steps SMTP Password Password for SMTP authentication - .. note:: + **Important Notes** - - Ensure your IMAP/SMTP servers are accessible from the Libervia backend - - The IMAP server must support the IDLE extension for real-time notifications + - Ensure your IMAP/SMTP servers are accessible from the Libervia backend + - The IMAP server must support the IDLE extension for real-time notifications Configuration ------------- -Besides the component configuration described above, no other configuration is needed: -the gateway uses user-specific data provided during registration. +The Email Gateway uses user-specific registration data - **no additional configuration is needed** in Libervia's main config file. All settings are stored per-user during registration. + +Supported Features +------------------ + +- **Normal Email Conversion**: Standard email messages are converted to XMPP chat + messages. Each email appears as a regular message in the user's XMPP client. + +- **Mailing List Handling**: Mailing list emails are converted to PubSub blog nodes + (microblogging) using XEP-0277: + + * Each mailing list becomes a separate pubsub node + * Each email in the list becomes a blog item + * Replies to specific topics appear as comments to the corresponding item + * Title tags within square brackets (e.g., `[tag]`) are converted to blog categories + * Only the recipient JID associated with the mailing list can access the pubsub node by + default. + +- **Extended Addressing Support**: Properly handles email addressing metadata (To, CC, + BCC) via XEP‑0033, converting it into XMPP addressing information for correct delivery. + This allows multi‑party discussions without relying on group chat (XEP‑0045 MUC), which + can be tricky to implement in email‑based communication. + +- **Header Conversion**: Converts important email headers to XMPP metadata, such as: + + * Keywords → XMPP "Keywords" header (XEP-0131) + * Importance → XMPP "Urgency" header (XEP-0131) + +- **Message Cleaning**: Automatically detects noisy elements in mailing list emails + (quoted replies, signatures) and tags them with a CSS class named "noise" so XMPP + clients can selectively hide or visually distinguish these parts of the message. + +- **Attachment Management**: Allows users to retrieve and delete email attachments via + PubSub File Sharing (XEP-0498). + + .. note:: + Attachments cannot yet be sent with messages (this + functionality is in development). + +- **End-to-End Encryption**: Supports Gateway Relayed Encryption (not yet an official XEP) + for encrypted email messages. Requires XMPP clients that implement this specification. Troubleshooting --------------- @@ -140,33 +178,37 @@ Troubleshooting - Solution * - XMPP component connection failed - Verify the shared secret matches on **both** Libervia and the XMPP server. - The component JID must *exactly* match the JID configured on the XMPP server - (e.g. "email.example.org" in Prosody must match the JID you set in the Libervia - configuration). + The component JID must *exactly* match the JID configured on the XMPP server (e.g. + “email.example.org” in Prosody must match the JID you set when creating the + Libervia profile). * - User registration fails - - * Check the IMAP credentials and make sure the IMAP server is reachable from the + - * Check the IMAP/SMTP credentials and make sure the servers are reachable from the Libervia host. * Verify that the IMAP server supports the **IDLE** extension (required for - real-time notifications). - * If you use self-signed certificates, add them to the system trust store. + real‑time notifications). + * If you use self‑signed certificates, add them to the system trust store. * - Email not received - - * Confirm the user's email credentials (you can re-register to check). + - * Confirm the user’s email credentials (you can re-register to check). * Check Libervia Backend logs to ensure that the IMAP connection succeeded. - * Verify that messages are arriving in the user's INBOX. - * - Email not sent - - * Check the SMTP credentials and make sure the SMTP server is reachable from the - Libervia host. - * Check the Libervia backend logs for the sending error. + * Verify that messages are arriving in the user’s INBOX. + * - “DBus not launched” error + - Follow :ref:`installation_dbus` instructions for headless servers – the + Libervia backend relies on D‑Bus to run. * - Attachments not appearing - The Email Gateway can *retrieve* attachments, but does not yet deliver them with outgoing messages (feature work in progress). * - Encrypted emails not working - - "Gateway Relayed Encryption" is a work-in-progress extension (not yet an official - XEP). Use a client that implements this specification. + - “Gateway Relayed Encryption” is a work‑in‑progress extension (not yet an official XEP). + Use a client that implements this specification. * - Mailing lists not converted - - Verify that the incoming e-mail contains a **valid "List-ID"** header. The value + - Verify that the incoming e‑mail contains a **valid “List‑ID”** header. The value must match the format expected for PubSub node creation. .. note:: The Email Gateway is under active development. Some features may have limitations. + +See Also +-------- + +- For Libervia components overview: :ref:`components` diff --git a/doc/libervia-cli/backup.rst b/doc/libervia-cli/backup.rst index 11313b50..50cb5945 100644 --- a/doc/libervia-cli/backup.rst +++ b/doc/libervia-cli/backup.rst @@ -11,7 +11,7 @@ Libervia-specific sections, so a backup remains readable by future Libervia vers A backup is made of data *types*, selected with ``-i/--include`` and ``-e/--exclude`` (repeatable): ``params``, ``private``, ``roster``, ``pep``, ``gpg``, ``files`` and ``db`` (full copy of the database, included by default on export). A backup is complete by -default (passwords, OMEMO keys, GPG secret keys…), so the archive should be kept +default (passwords, OMEMO keys, GPG secret keys...), so the archive should be kept private: it is written with mode 0600, and ``--encrypt`` can be used for untrusted storage. diff --git a/doc/libervia-cli/common_arguments.rst b/doc/libervia-cli/common_arguments.rst index 1c9fcc30..38fdca40 100644 --- a/doc/libervia-cli/common_arguments.rst +++ b/doc/libervia-cli/common_arguments.rst @@ -38,7 +38,7 @@ The common arguments for profile are: history of your shell. If the profile password is needed and not specified, it will be prompted (with echo disabled). If you are on a shared machine or if anybody can access your shell history at some point, you should either connect first your profile with an - other frontend (Libervia TUI for instance), or avoid the ``--pwd`` option and use the + other frontend (Primitivus for instance), or avoid the ``--pwd`` option and use the prompt instead. .. _pubsub_common: diff --git a/doc/libervia-cli/gateway.rst b/doc/libervia-cli/gateway.rst index a8417a69..31799ed2 100644 --- a/doc/libervia-cli/gateway.rst +++ b/doc/libervia-cli/gateway.rst @@ -1,6 +1,6 @@ -=========================== +========================== gateway: Gateway management -=========================== +========================== ``gateway`` command allows you to list, register, and unregister from gateways (usually used to access other networks like ActivityPub or Email) on an XMPP server. diff --git a/doc/libervia-cli/index.rst b/doc/libervia-cli/index.rst index 0da081aa..fe3ea519 100644 --- a/doc/libervia-cli/index.rst +++ b/doc/libervia-cli/index.rst @@ -37,29 +37,37 @@ After the commands come the options. For instance if you want to send a message, get the available options with ``--help`` as explained above:: $ li message send --help - usage: li message send [-h] [-p PROFILE] [--pwd PASSWORD] [-c] + usage: li message send [-h] [-p PROFILE] [--pwd PASSWORD] [-c] [-l LANG] [-s] + [-n] [-S SUBJECT] [-L SUBJECT_LANG] [-t {chat,error,groupchat,headline,normal,auto}] - [-e ALGORITHM] [--encrypt-noreplace] […] + [-e ALGORITHM] [--encrypt-noreplace] [-x | -r] jid positional arguments: jid the destination jid - options: + optional arguments: -h, --help show this help message and exit - -p, --profile PROFILE + -p PROFILE, --profile PROFILE Use PROFILE profile key (default: @DEFAULT@) --pwd PASSWORD Password used to connect profile, if necessary -c, --connect Connect the profile before doing anything else - -t, --type {chat,error,groupchat,headline,normal,auto} + -l LANG, --lang LANG language of the message + -s, --separate separate xmpp messages: send one message per line + instead of one message alone. + -n, --new-line add a new line at the beginning of the input (usefull + for ascii art ;)) + -S SUBJECT, --subject SUBJECT + subject of the message + -L SUBJECT_LANG, --subject_lang SUBJECT_LANG + language of subject + -t {chat,error,groupchat,headline,normal,auto}, --type {chat,error,groupchat,headline,normal,auto} type of the message - -e, --encrypt ALGORITHM + -e ALGORITHM, --encrypt ALGORITHM encrypt message using given algorithm - --encrypt-noreplace don't replace encryption algorithm if another one is + --encrypt-noreplace don't replace encryption algorithm if an other one is already used - […] - -The output above has been shortened: use ``--help`` to see the full list of options. + -x, --xhtml XHTML body If you want to send a message to, say, ``pierre@example.net``, and encrypt it with OMEMO, just do the following:: @@ -69,25 +77,6 @@ just do the following:: (note that with OMEMO, you need to have previously validated fingerprint of your contact for this to work). -.. _li_isolation: - -Isolation ---------- - -Several Libervia instances can run side by side, each with its own data, this is called -isolation (see :ref:`configuration_isolation` for details). The instance to work with is -selected with the ``-i/--isolation NAME`` option, which must be used before the command: - -.. code-block:: console - - $ li -i pubsub profile list - -.. note:: - - If the ``LIBERVIA_ISOLATION`` environment variable is already set, this option is not - needed, unless you want to work with another instance (the option takes priority over - the environment variable). - The different commands are explained in dedicated sections. .. toctree:: diff --git a/doc/libervia-tui/index.rst b/doc/libervia-tui/index.rst index 132734a5..d4c77a5e 100644 --- a/doc/libervia-tui/index.rst +++ b/doc/libervia-tui/index.rst @@ -1,26 +1,26 @@ -.. _libervia-tui-documentation: +.. _primitivus-documentation: -============ -Libervia TUI -============ +========== +Primitivus +========== -``Libervia TUI`` is the TUI (Terminal User Interface) frontend of Libervia +``Primitivus`` is the TUI (Terminal User Interface) frontend of Libervia Overview ======== -``Libervia TUI`` is a text based frontend. It is specially adapted for systems without +``Primitivus`` is a text based frontend. It is specially adapted for systems without graphical environments (e.g. servers), for low bandwidth remote shells (e.g. ssh) or for people who like straightforward interfaces without distracting images or animations. -For the moment, Libervia TUI implements one 2 one chat, group chat (also called *MUC* for +For the moment, Primitivus implements one 2 one chat, group chat (also called *MUC* for Multi-Users Chat), and some related features (end 2 end encryption, bookmarks, gateways interaction, file sending, etc.). Usage ===== -Libervia TUI is modal (vi-like), one can switch from one mode to another +Primitivus is modal (vi-like), one can switch from one mode to another in the same way as in vi/vim: - From any mode, press ``[Esc]`` to switch to normal mode. @@ -28,7 +28,7 @@ in the same way as in vi/vim: - From normal mode, press ``i`` to switch to insert mode – the one you use to write messages to your contacts. -Libervia TUI can be handled either with the mouse, in a very intuitive way, or with the +Primitivus can be handled either with the mouse, in a very intuitive way, or with the keyboard. Below, the keyboard shortcuts are explained. Keyboard handling @@ -46,8 +46,8 @@ Main keys ``[Tab]`` and/or ``CTRL + up/down arrows`` change focus -``CTRL + X`` - quit Libervia TUI +``CTRL + X`` + quit Primitivus ``CTRL + F, 1`` or ``CTRL + F, M`` focus on the menu ``CTRL + F, 2`` or ``CTRL + F, B`` @@ -128,12 +128,12 @@ The following commands must be typed in command mode (type ``[Esc]`` to switch t mode, then the ``:`` at the beginning of the command will switch to command mode). ``:quit`` - quit Libervia TUI + quit Primitivus ``:messages`` display log messages (see also the logging configuration) .. - FIXME: :presence and :status are currently disabled in Libervia TUI + FIXME: :presence and :status are currently disabled in Primitivus ``:presence [status]`` set your presence status. Invoked without argument, a pop-up will allow you to choose your presence status; otherwise, you can use the following arguments: - ``online`` diff --git a/doc/overview.rst b/doc/overview.rst index ab4ce36a..7c082a57 100644 --- a/doc/overview.rst +++ b/doc/overview.rst @@ -113,25 +113,24 @@ The `official Libervia website`_ is made with Libervia web framework. .. _Jinja2: http://jinja.pocoo.org/ .. _official Libervia website: https://salut-a-toi.org -Libervia TUI ------------- +Libervia TUI (Primitivus) +------------------------- -Libervia TUI is the Terminal User Interface. In other words, it works in console and is -intended for people at ease with it. Its text only interface has several advantages: you -get rid of many distracting things (like images), it works without graphical environment -installed (which is often the case on servers) and it works on distant shell (like `ssh`_) -while staying gentle with your bandwidth. +Libervia TUI (alias ``Primitivus``) is the Terminal User Interface. In other words, it +works in console and is intended for people at ease with it. Its text only interface has +several advantages: you get rid of many distracting things (like images), it works without +graphical environment installed (which is often the case on servers) and it works on +distant shell (like `ssh`_) while staying gentle with your bandwidth. -Libervia TUI is shipped with the backend, so it should be always available once Libervia -is installed (but some distributions may provide it separately). +Primitivus is shipped with the backend, so it should be always available once Libervia is +installed (but some distributions may provide it separately). -.. The TUI is temporarily on hold and broken, its documentation is not -.. included in the build for the moment. +You can check :doc:`Libervia TUI documentation ` for more details. .. _ssh: https://en.wikipedia.org/wiki/Secure_Shell -Libervia CLI ------------- +Libervia CLI (jp) +----------------- Libervia CLI (alias ``li`` or ``jp``) is the Command Line Interface. It's a powerful tool which allows to do nearly everything you can do with other frontends. diff --git a/libervia/backend/plugins/plugin_misc_account.py b/libervia/backend/plugins/plugin_misc_account.py index 6d944ad2..d6d904dd 100644 --- a/libervia/backend/plugins/plugin_misc_account.py +++ b/libervia/backend/plugins/plugin_misc_account.py @@ -145,7 +145,7 @@ class MiscAccount(object): host.bridge.add_method( "credentials_xmpp_connect", ".plugin", - in_sign="ssb", + in_sign="ss", out_sign="b", method=self.credentials_xmpp_connect, async_=True, @@ -293,11 +293,11 @@ class MiscAccount(object): # there is no email when an existing XMPP account is used body = f"New account created on {domain}: {profile} [{email or ''}]" d_admin = sat_email.send_email( + self.get_email_conf(), self.host.memory.config, admins_emails, subject, body, - email_settings=self.get_email_conf(), ) admins_emails_txt = ", ".join(["<" + addr + ">" for addr in admins_emails]) @@ -326,13 +326,7 @@ class MiscAccount(object): # XXX: this will not fail when the email address doesn't exist # FIXME: check email reception to validate email given by the user # FIXME: delete the profile if the email could not been sent? - d_user = sat_email.send_email( - self.host.memory.config, - [email], - subject, - body, - email_settings=self.get_email_conf(), - ) + d_user = sat_email.send_email(self.get_email_conf, [email], subject, body) d_user.addCallbacks( lambda __: log.debug( "Account creation confirmation sent to <{}>".format(email) @@ -695,13 +689,12 @@ class MiscAccount(object): d.addCallbacks(deleted, errback) return d - def credentials_xmpp_connect(self, jid_s, password, send_email=True): + def credentials_xmpp_connect(self, jid_s, password): """Create and connect a new SàT profile using the given XMPP credentials. Re-use given JID and XMPP password for the profile name and profile password. @param jid_s (unicode): JID @param password (unicode): XMPP password - @param send_email (bool): send the administrator notification email @return Deferred(bool) @raise exceptions.PasswordError, exceptions.ConflictError """ @@ -723,8 +716,7 @@ class MiscAccount(object): ) def connected(result): - if send_email: - self.send_emails(None, profile=jid_s) + self.send_emails(None, profile=jid_s) return result def remove_profile( diff --git a/libervia/backend/tools/common/email.py b/libervia/backend/tools/common/email.py index cfad14f0..2a7be733 100644 --- a/libervia/backend/tools/common/email.py +++ b/libervia/backend/tools/common/email.py @@ -34,7 +34,6 @@ def send_email( subject: str = "", body: str = "", from_email: str | None = None, - email_settings: tools_config.EmailSettings | None = None, ) -> defer.Deferred: """Send an email using Libervia configuration @@ -44,14 +43,12 @@ def send_email( @param subject: subject of the message @param body: body of the message @param from_email: address of the sender - @param email_settings: ``EmailSettings`` to use, default to ``config.email`` @return:Same as smtp.sendmail. """ if isinstance(to_emails, str): to_emails = to_emails.split() - settings = email_settings or config.email - email_host = settings.server - email_from = from_email or settings.from_ + email_host = config.email.server + email_from = from_email or config.email.from_ # we suppose that email domain and XMPP domain are identical domain = config.common.xmpp_domain @@ -63,12 +60,12 @@ def send_email( if email_from is None: email_from = "no_reply@" + domain - email_sender_domain = settings.sender_domain or domain - email_port = settings.port - email_username = settings.username - email_password = settings.password - email_auth = settings.auth - email_starttls = settings.starttls + email_sender_domain = config.email.sender_domain or domain + email_port = config.email.port + email_username = config.email.username + email_password = config.email.password + email_auth = config.email.auth + email_starttls = config.email.starttls msg = MIMEText(body, "plain", "UTF-8") msg["Subject"] = subject diff --git a/libervia/frontends/quick_frontend/quick_app.py b/libervia/frontends/quick_frontend/quick_app.py index 418b9afc..88cc9e72 100644 --- a/libervia/frontends/quick_frontend/quick_app.py +++ b/libervia/frontends/quick_frontend/quick_app.py @@ -349,12 +349,7 @@ class QuickApp: log.warning(_("Can't retrieve encryption plugins: {msg}").format(msg=failure_)) def on_bridge_connected(self): - d = self.bridge.ready_get() - d.addErrback(self._ready_get_eb) - d.addCallback(lambda __: self.on_backend_ready()) - - def _ready_get_eb(self, failure_): - log.error("Can't check backend readiness: {msg}".format(msg=failure_)) + self.bridge.ready_get(self.on_backend_ready) def _bridge_cb(self): self.register_signal("connected") diff --git a/libervia/frontends/quick_frontend/quick_bridge.py b/libervia/frontends/quick_frontend/quick_bridge.py deleted file mode 100644 index 53999743..00000000 --- a/libervia/frontends/quick_frontend/quick_bridge.py +++ /dev/null @@ -1,118 +0,0 @@ -#!/usr/bin/env python3 - -# Libervia: an XMPP client -# Copyright (C) 2009-2026 Jérôme Poisson (goffi@goffi.org) - -# 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 . - -"""Adapte the legacy callback/errback bridge API to bridges""" - -import asyncio -import inspect -from typing import Any, Callable - -from twisted.internet import defer -from twisted.python.failure import Failure - -from libervia.backend.core.log import getLogger - -log = getLogger(__name__) - - -class QuickBridgeAdapter: - """Adapt legacy callback/errback to bridges - - @param bridge: bridge instance - """ - - def __init__(self, bridge: Any) -> None: - self._bridge = bridge - - def __getattr__(self, name: str) -> Any: - attr = getattr(self._bridge, name) - if not callable(attr): - return attr - - def wrapper(*args: Any, **kwargs: Any) -> Any: - callback = kwargs.pop("callback", None) - errback = kwargs.pop("errback", None) - result = attr(*args, **kwargs) - if inspect.iscoroutine(result): - result = asyncio.ensure_future(result) - if isinstance(result, asyncio.Future): - # async bridges (e.g. AIOBridge) return asyncio futures - result = defer.Deferred.fromFuture(result) - if (callback is None and errback is None) or not hasattr( - result, "addCallback" - ): - return result - if callback is not None: - result.addCallback(callback) - if errback is not None: - result.addErrback(errback) - return result - - return wrapper - - def register_signal(self, name: str, handler: Callable, iface: str = "core") -> None: - """Register a signal handler, adapting sync handlers to async bridges - - @param name: signal name - @param handler: signal handler, sync or async - @param iface: bridge interface ("core" or "plugin") - """ - if not inspect.iscoroutinefunction(handler): - - async def async_handler(*args: Any, - _handler: Callable = handler) -> None: - _handler(*args) - - handler = async_handler - - try: - self._bridge.register_signal(name, handler, iface) - except AttributeError: - log.warning(f"Signal {name} is not available on the bridge") - - def bridge_connect(self, callback: Callable | None = None, - errback: Callable | None = None) -> None: - """Connect to the bridge - - @param callback: called when the bridge is connected - @param errback: called with a twisted Failure on connection error - """ - - async def _connect() -> None: - try: - await self._bridge.bridge_connect() - except Exception as e: - if errback is not None: - errback(Failure(e)) - else: - if callback is not None: - callback() - - try: - asyncio.get_running_loop() - except RuntimeError: - # the event loop is not running yet (frontends usually call connect_bridge() - # before starting their loop) - try: - loop = asyncio.get_event_loop() - except RuntimeError: - loop = asyncio.new_event_loop() - asyncio.set_event_loop(loop) - loop.call_soon(asyncio.ensure_future, _connect()) - else: - asyncio.ensure_future(_connect()) diff --git a/libervia/frontends/quick_frontend/quick_profile_manager.py b/libervia/frontends/quick_frontend/quick_profile_manager.py index 90631e23..880ee6eb 100644 --- a/libervia/frontends/quick_frontend/quick_profile_manager.py +++ b/libervia/frontends/quick_frontend/quick_profile_manager.py @@ -233,16 +233,9 @@ class QuickProfileManager(object): def refill_profiles(self): """Rebuild the list of profiles""" - self.host.bridge.profiles_list_get( - callback=self._profiles_loaded, - errback=self._profiles_list_eb, - ) - - def _profiles_loaded(self, profiles): - self.set_profiles(sorted(profiles)) - - def _profiles_list_eb(self, failure_): - log.error("Can't get profiles list: {msg}".format(msg=failure_)) + profiles = self.host.bridge.profiles_list_get() + profiles.sort() + self.set_profiles(profiles) ## Method which must be implemented by frontends ## diff --git a/libervia/tui/base.py b/libervia/tui/base.py index 2f2a7724..7b3a4daa 100644 --- a/libervia/tui/base.py +++ b/libervia/tui/base.py @@ -28,10 +28,9 @@ from libervia.backend.core import log as logging log = logging.getLogger(__name__) from libervia.backend.tools import config as tools_config import urwid -from urwid import is_wide_char +from urwid.util import is_wide_char from urwid_satext import sat_widgets from libervia.frontends.quick_frontend.quick_app import QuickApp -from libervia.frontends.quick_frontend import quick_bridge from libervia.frontends.quick_frontend import quick_utils from libervia.frontends.quick_frontend import quick_chat from libervia.tui.profile_manager import ProfileManager @@ -46,7 +45,6 @@ from libervia.tui.keys import action_key_map as a_key from libervia.frontends.tools.misc import InputHistory from libervia.backend.tools.common import dynamic_import from libervia.frontends.tools import jid -import asyncio import signal import sys @@ -69,19 +67,10 @@ class TUISettings(tools_config.FrontendSettings, key="tui"): ## bridge handling # we get bridge name from conf and initialise the right class accordingly main_config = tools_config.parse_main_conf(ignore_cache=True) -bridge_name = next(iter(main_config.bridges)).type +bridge_name = next(iter(main_config.common.bridges)).type if "dbus" not in bridge_name: print("only D-Bus bridge is currently supported") sys.exit(3) -# install the asyncio twisted reactor -try: - asyncio.get_event_loop() -except RuntimeError: - loop = asyncio.new_event_loop() - asyncio.set_event_loop(loop) -from twisted.internet import asyncioreactor - -asyncioreactor.install() class EditBar(sat_widgets.ModalEdit): @@ -349,7 +338,9 @@ class LiberviaTUIApp(QuickApp, InputHistory): AVATARS_HANDLER = False def __init__(self): - bridge_module = dynamic_import.import_bridge(bridge_name) + bridge_module = dynamic_import.import_bridge( + bridge_name, "libervia.frontends.bridge" + ) if bridge_module is None: log.error("Can't import {} bridge".format(bridge_name)) sys.exit(3) @@ -357,18 +348,16 @@ class LiberviaTUIApp(QuickApp, InputHistory): log.debug("Loading {} bridge".format(bridge_name)) QuickApp.__init__( self, - # AIOBridge is the only bridge compatible with the asyncio loop - bridge_factory=lambda: quick_bridge.QuickBridgeAdapter( - bridge_module.AIOBridge() - ), + bridge_factory=bridge_module.bridge, xmlui=xmlui, check_options=quick_utils.check_options, connect_bridge=False, ) self.tui_settings = main_config.get_settings(TUISettings) ## main loop setup ## - # the new D-Bus bridge is twisted based (txdbus) - event_loop = urwid.TwistedEventLoop + event_loop = ( + urwid.GLibEventLoop if "dbus" in bridge_name else urwid.TwistedEventLoop + ) self.loop = urwid.MainLoop( urwid.SolidFill(), C.PALETTE, @@ -384,10 +373,6 @@ class LiberviaTUIApp(QuickApp, InputHistory): def on_bridge_connected(self): ##misc setup## - self._version = None - self.bridge.version_get( - callback=self._version_get_cb, errback=lambda __: None - ) self._visible_widgets = set() self.notif_bar = sat_widgets.NotificationBar() urwid.connect_signal(self.notif_bar, "change", self.on_notification) @@ -415,9 +400,6 @@ class LiberviaTUIApp(QuickApp, InputHistory): self.loop.widget = self.main_widget = ProfileManager(self) self.post_init() - def _version_get_cb(self, version): - self._version = version - @property def visible_widgets(self): return self._visible_widgets @@ -597,7 +579,7 @@ class LiberviaTUIApp(QuickApp, InputHistory): self.__saved_overlay = None elif ( - input_ == a_key["DEBUG"] and ".dev0" in (self._version or "") + input_ == a_key["DEBUG"] and ".dev0" in self.bridge.version_get() ): # Debug only for dev versions self.debug() elif input_ == a_key["CONTACTS_HIDE"]: # user wants to (un)hide the contact lists @@ -632,9 +614,6 @@ class LiberviaTUIApp(QuickApp, InputHistory): def add_menus(self, menu, type_filter, menu_data=None): """Add cached menus to instance - - The menus are retrieved asynchronously from the bridge. - @param menu: sat_widgets.Menu instance @param type_filter: menu type like is sat.core.sat_main.import_menu @param menu_data: data to send with these menus @@ -644,24 +623,16 @@ class LiberviaTUIApp(QuickApp, InputHistory): def add_menu_cb(callback_id): self.action_launch(callback_id, menu_data, profile=self.current_profile) - def menus_get_cb(menus): - for id_, type_, path, path_i18n, extra in menus: # TODO: manage extra - if type_ != type_filter: - continue - if len(path) != 2: - raise NotImplementedError( - "Menu with a path != 2 are not implemented yet" - ) - menu.add_menu( - path_i18n[0], path_i18n[1], lambda dummy, id_=id_: add_menu_cb(id_) - ) - - def menus_get_eb(failure): - log.error("Can't get menus: {}".format(failure)) - - self.bridge.menus_get( - "", C.NO_SECURITY_LIMIT, callback=menus_get_cb, errback=menus_get_eb - ) + for id_, type_, path, path_i18n, extra in self.bridge.menus_get( + "", C.NO_SECURITY_LIMIT + ): # TODO: manage extra + if type_ != type_filter: + continue + if len(path) != 2: + raise NotImplementedError("Menu with a path != 2 are not implemented yet") + menu.add_menu( + path_i18n[0], path_i18n[1], lambda dummy, id_=id_: add_menu_cb(id_) + ) def _build_menu_roller(self): menu = sat_widgets.Menu(self.loop) @@ -1045,25 +1016,19 @@ class LiberviaTUIApp(QuickApp, InputHistory): def on_join_room_request(self, menu): """User wants to join a MUC room""" - - def show_join_dialog(default_service): - pop_up_widget = sat_widgets.InputDialog( - _("Entering a MUC room"), - _("Please enter MUC's JID"), - default_txt=default_service, - ok_cb=self.on_join_room, - ) - pop_up_widget.set_callback( - "cancel", lambda dummy: self.remove_pop_up(pop_up_widget) - ) - self.show_pop_up(pop_up_widget) - - self.bridge.muc_get_default_service( - callback=show_join_dialog, errback=lambda __: show_join_dialog("") + pop_up_widget = sat_widgets.InputDialog( + _("Entering a MUC room"), + _("Please enter MUC's JID"), + default_txt=self.bridge.muc_get_default_service(), + ok_cb=self.on_join_room, ) + pop_up_widget.set_callback( + "cancel", lambda dummy: self.remove_pop_up(pop_up_widget) + ) + self.show_pop_up(pop_up_widget) def on_about_request(self, menu): - self.alert(_("About"), C.APP_NAME + " v" + (self._version or "")) + self.alert(_("About"), C.APP_NAME + " v" + self.bridge.version_get()) # MISC CALLBACKS# diff --git a/libervia/tui/game_tarot.py b/libervia/tui/game_tarot.py index 82d4c1f9..c303ff61 100644 --- a/libervia/tui/game_tarot.py +++ b/libervia/tui/game_tarot.py @@ -174,13 +174,10 @@ class Card(TarotCard): return CardDisplayer(self) -class Table(urwid.Widget): +class Table(urwid.FlowWidget): """Represent the cards currently on the table""" - _sizing = frozenset([urwid.Sizing.FLOW]) - def __init__(self): - super().__init__() self.top = self.left = self.bottom = self.right = None def put_card(self, location, card): @@ -316,7 +313,7 @@ class TarotGame(QuickTarotGame, urwid.WidgetWrap): if not winners and not loosers: title = _("Draw game") else: - title = _("You win \\o/") if self.player_nick in winners else _("You loose :(") + title = _("You win \o/") if self.player_nick in winners else _("You loose :(") form = xmlui.create( self.parent.host, xml_data, diff --git a/libervia/tui/notify.py b/libervia/tui/notify.py index 096ac031..f34b7c17 100644 --- a/libervia/tui/notify.py +++ b/libervia/tui/notify.py @@ -17,10 +17,7 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . -try: - import dbus -except ImportError: - dbus = None +import dbus class Notify(object): diff --git a/libervia/tui/profile_manager.py b/libervia/tui/profile_manager.py index 7d4cac61..46ab7411 100644 --- a/libervia/tui/profile_manager.py +++ b/libervia/tui/profile_manager.py @@ -37,11 +37,11 @@ class ProfileManager(QuickProfileManager, urwid.WidgetWrap): self.pass_wid = sat_widgets.Password(_("Password:"), align="center") style = ["no_first_select"] + profiles = host.bridge.profiles_list_get() + profiles.sort() self.list_profile = sat_widgets.List( - [], style=style, align="center", on_change=self.on_profile_change + profiles, style=style, align="center", on_change=self.on_profile_change ) - # the profiles list is retrieved asynchronously - self.refill_profiles() # new & delete buttons buttons = [ diff --git a/libervia/tui/progress.py b/libervia/tui/progress.py index 88ef0c3a..9614d8dd 100644 --- a/libervia/tui/progress.py +++ b/libervia/tui/progress.py @@ -54,31 +54,24 @@ class Progress(urwid.WidgetWrap, quick_widgets.QuickWidget): def progress_cb(self, loop, data): progress_id, message, profile = data + data = self.host.bridge.progress_get(progress_id, profile) + pbar = self.progress_dict[(progress_id, profile)]["progress"] + if data: + if self.progress_dict[(progress_id, profile)]["state"] == "init": + # first answer, we must construct the bar + self.progress_dict[(progress_id, profile)]["state"] = "progress" + pbar.done = float(data["size"]) - def progress_get_cb(data): - entry = self.progress_dict.get((progress_id, profile)) - if entry is None: - # the bar has been removed in the meantime - return - pbar = entry["progress"] - if data: - if entry["state"] == "init": - # first answer, we must construct the bar - entry["state"] = "progress" - pbar.done = float(data["size"]) - - pbar.set_completion(float(data["position"])) + pbar.set_completion(float(data["position"])) + self.update_not_bar() + else: + if self.progress_dict[(progress_id, profile)]["state"] == "progress": + self.progress_dict[(progress_id, profile)]["state"] = "done" + pbar.set_completion(pbar.done) self.update_not_bar() - else: - if entry["state"] == "progress": - entry["state"] = "done" - pbar.set_completion(pbar.done) - self.update_not_bar() - return + return - loop.set_alarm_in(0.2, self.progress_cb, (progress_id, message, profile)) - - self.host.bridge.progress_get(progress_id, profile, callback=progress_get_cb) + loop.set_alarm_in(0.2, self.progress_cb, (progress_id, message, profile)) def _remove_bar(self, progress_id, profile): wid = self.progress_dict[(progress_id, profile)]["full"] diff --git a/libervia/tui/status.py b/libervia/tui/status.py index 94228701..2aafca1d 100644 --- a/libervia/tui/status.py +++ b/libervia/tui/status.py @@ -45,44 +45,34 @@ class StatusBar(urwid.Columns): urwid.connect_signal(self.status, "click", self.on_status_click) def on_presence_click(self, sender=None): - def show_presence_popup(connected): - if not connected: - return - options = [ - commonConst.PRESENCE[presence] for presence in commonConst.PRESENCE - ] - list_widget = sat_widgets.GenericList( - options=options, - option_type=sat_widgets.ClickableText, - on_click=self.on_change, - ) - decorated = sat_widgets.LabelLine( - list_widget, sat_widgets.SurroundedText(_("Set your presence")) - ) - self.host.show_pop_up(decorated) - - # FIXME: manage multi-profiles - self.host.bridge.is_connected( - self.host.current_profile, callback=show_presence_popup + if not self.host.bridge.is_connected( + self.host.current_profile + ): # FIXME: manage multi-profiles + return + options = [commonConst.PRESENCE[presence] for presence in commonConst.PRESENCE] + list_widget = sat_widgets.GenericList( + options=options, + option_type=sat_widgets.ClickableText, + on_click=self.on_change, ) + decorated = sat_widgets.LabelLine( + list_widget, sat_widgets.SurroundedText(_("Set your presence")) + ) + self.host.show_pop_up(decorated) def on_status_click(self, sender=None): - def show_status_popup(connected): - if not connected: - return - pop_up_widget = sat_widgets.InputDialog( - _("Set your status"), - _("New status"), - default_txt=self.status.get_text(), - cancel_cb=lambda _: self.host.remove_pop_up(), - ok_cb=self.on_change, - ) - self.host.show_pop_up(pop_up_widget) - - # FIXME: manage multi-profiles - self.host.bridge.is_connected( - self.host.current_profile, callback=show_status_popup + if not self.host.bridge.is_connected( + self.host.current_profile + ): # FIXME: manage multi-profiles + return + pop_up_widget = sat_widgets.InputDialog( + _("Set your status"), + _("New status"), + default_txt=self.status.get_text(), + cancel_cb=lambda _: self.host.remove_pop_up(), + ok_cb=self.on_change, ) + self.host.show_pop_up(pop_up_widget) def on_change(self, sender=None, user_data=None): new_value = user_data.get_text() diff --git a/pyproject.toml b/pyproject.toml index 4fa94510..b9474811 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -57,7 +57,7 @@ dependencies = [ "twisted[tls] >= 22.10", "twomemo >= 1.0.0, < 2", "txdbus", - "urwid >= 4.2.5, < 5", + "urwid >= 1.2.0, < 3", "urwid-satext", "xmlschema < 4.3.1", "tx-xmpp>=0.15",