From 87ac49ce41165dcdd1d0eb6e867e9bb400950fbb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20unbrot=20P=C3=A4tzold?= Date: Sat, 2 May 2026 10:24:20 +0200 Subject: [PATCH 1/6] 0110_nextcloud_talk_app: restore D-Bus and KWallet access via flatpak override Ensures session bus socket and kwalletd5/6 talk permissions are set at logon, so Flatseal or a missing manifest entry cannot silently break Talk's credential storage and Plasma integration. Co-Authored-By: Claude Sonnet 4.6 --- client_software/0110_nextcloud_talk_app/user_run.sh | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/client_software/0110_nextcloud_talk_app/user_run.sh b/client_software/0110_nextcloud_talk_app/user_run.sh index 5314e80..12f7f57 100755 --- a/client_software/0110_nextcloud_talk_app/user_run.sh +++ b/client_software/0110_nextcloud_talk_app/user_run.sh @@ -5,6 +5,11 @@ if [[ $? -eq 0 ]]; then /usr/bin/flatpak uninstall -y --user com.nextcloud.talk fi +# Ensure session bus and KWallet D-Bus access (may be blocked by Flatseal or missing from manifest) +/usr/bin/flatpak override --user --socket=session-bus \ + --talk-name=org.kde.kwalletd5 --talk-name=org.kde.kwalletd6 \ + com.nextcloud.talk + # Start Nextcloud Talk in Background #Current Version of Talk is dumping Core echo "Starting Nextcloud Talk in Background." -- 2.52.0 From d95136459c032fc13cf0ce8f70b4fd96314c3014 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20unbrot=20P=C3=A4tzold?= Date: Sat, 2 May 2026 10:59:32 +0200 Subject: [PATCH 2/6] 0020_nextcloud_mozilla_pre: auto-provision Thunderbird IMAP account at logon MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds SERVERFQDN_IMAP and TB_MAIL_FULLNAME to setup_system.conf.dist. On each logon the script checks if an IMAP account for DAVTOKEN_USER@TLDOMAIN already exists in prefs.js; if not it writes the server, identity, and account entries and registers it with accountmanager. Idempotent — skipped when the account is already present. Co-Authored-By: Claude Sonnet 4.6 --- .../0020_nextcloud_mozilla_pre/user_run.sh | 82 +++++++++++++++++++ config/setup_system.conf.dist | 4 + 2 files changed, 86 insertions(+) diff --git a/client_software/0020_nextcloud_mozilla_pre/user_run.sh b/client_software/0020_nextcloud_mozilla_pre/user_run.sh index b266be2..d561817 100755 --- a/client_software/0020_nextcloud_mozilla_pre/user_run.sh +++ b/client_software/0020_nextcloud_mozilla_pre/user_run.sh @@ -4,6 +4,7 @@ # # Will prepare local mozilla and thunderbird folders with given tar.files # +import re import sys import subprocess import certifi @@ -106,4 +107,85 @@ if 'PROFILE_TB_SRC' in environ: # Check and setup mozilla print("Done.") #Next sync will be executed by logon script +# Check and auto-provision IMAP account for DAVTOKEN_USER@TLDOMAIN in Thunderbird +if ('PROFILE_TB_DST' in environ and 'TLDOMAIN' in environ and + 'SERVERFQDN_IMAP' in environ and 'DAVTOKEN_USER' in environ): + prefs_path = environ['PROFILE_TB_DST'] + "/default/prefs.js" + mail_user = environ['DAVTOKEN_USER'] + "@" + environ['TLDOMAIN'] + mail_user_url = mail_user.replace('@', '%40') + imap_host = environ['SERVERFQDN_IMAP'] + full_name = environ.get('TB_MAIL_FULLNAME', environ['DAVTOKEN_USER']) + profile_dir = environ['PROFILE_TB_DST'] + "/default" + + if not os.path.exists(prefs_path): + print("Thunderbird prefs.js not found, skipping mail account setup.") + else: + with open(prefs_path, 'r') as f: + prefs = f.read() + + account_exists = bool(re.search( + r'mail\.server\.server\d+\.userName",\s*"' + re.escape(mail_user) + '"', + prefs + )) + if account_exists: + print(f"Thunderbird IMAP account for {mail_user} already configured.") + else: + print(f"Adding Thunderbird IMAP account for {mail_user} ...") + + server_nums = [int(x) for x in re.findall(r'mail\.server\.server(\d+)\.type', prefs)] + account_nums = [int(x) for x in re.findall(r'mail\.account\.account(\d+)\.server', prefs)] + id_nums = [int(x) for x in re.findall(r'mail\.identity\.id(\d+)\.useremail', prefs)] + + ns = (max(server_nums) + 1) if server_nums else 1 + na = (max(account_nums) + 1) if account_nums else 1 + ni = (max(id_nums) + 1) if id_nums else 1 + sn, an, idn = f"server{ns}", f"account{na}", f"id{ni}" + + new_lines = [ + f'user_pref("mail.server.{sn}.check_new_mail", true);', + f'user_pref("mail.server.{sn}.cleanup_inbox_on_exit", true);', + f'user_pref("mail.server.{sn}.directory", "{profile_dir}/ImapMail/{imap_host}");', + f'user_pref("mail.server.{sn}.directory-rel", "[ProfD]ImapMail/{imap_host}");', + f'user_pref("mail.server.{sn}.hostname", "{imap_host}");', + f'user_pref("mail.server.{sn}.login_at_startup", true);', + f'user_pref("mail.server.{sn}.max_cached_connections", 5);', + f'user_pref("mail.server.{sn}.name", "{mail_user}");', + f'user_pref("mail.server.{sn}.port", 993);', + f'user_pref("mail.server.{sn}.socketType", 3);', + f'user_pref("mail.server.{sn}.storeContractID", "@mozilla.org/msgstore/maildirstore;1");', + f'user_pref("mail.server.{sn}.timeout", 29);', + f'user_pref("mail.server.{sn}.trash_folder_name", "Trash");', + f'user_pref("mail.server.{sn}.type", "imap");', + f'user_pref("mail.server.{sn}.userName", "{mail_user}");', + f'user_pref("mail.identity.{idn}.draft_folder", "imap://{mail_user_url}@{imap_host}/Drafts");', + f'user_pref("mail.identity.{idn}.drafts_folder_picker_mode", "0");', + f'user_pref("mail.identity.{idn}.fcc_folder", "imap://{mail_user_url}@{imap_host}/Sent");', + f'user_pref("mail.identity.{idn}.fcc_folder_picker_mode", "0");', + f'user_pref("mail.identity.{idn}.fullName", "{full_name}");', + f'user_pref("mail.identity.{idn}.reply_on_top", 1);', + f'user_pref("mail.identity.{idn}.stationery_folder", "imap://{mail_user_url}@{imap_host}/Templates");', + f'user_pref("mail.identity.{idn}.tmpl_folder_picker_mode", "0");', + f'user_pref("mail.identity.{idn}.useremail", "{mail_user}");', + f'user_pref("mail.identity.{idn}.valid", true);', + f'user_pref("mail.account.{an}.identities", "{idn}");', + f'user_pref("mail.account.{an}.server", "{sn}");', + ] + + # Append account to mail.accountmanager.accounts + m = re.search(r'(mail\.accountmanager\.accounts",\s*")([^"]+)(")', prefs) + if m: + prefs = prefs[:m.start(2)] + m.group(2) + ',' + an + prefs[m.end(2):] + else: + new_lines.append(f'user_pref("mail.accountmanager.accounts", "{an}");') + + # Update mail.account.lastKey + m = re.search(r'(mail\.account\.lastKey",\s*)(\d+)', prefs) + if m: + prefs = prefs[:m.start(2)] + str(max(int(m.group(2)), na)) + prefs[m.end(2):] + + prefs = prefs.rstrip('\n') + '\n' + '\n'.join(new_lines) + '\n' + with open(prefs_path, 'w') as f: + f.write(prefs) + print(f"Thunderbird IMAP account for {mail_user} added successfully.") + sys.exit(0) diff --git a/config/setup_system.conf.dist b/config/setup_system.conf.dist index 8c04d4a..df0653f 100644 --- a/config/setup_system.conf.dist +++ b/config/setup_system.conf.dist @@ -77,6 +77,10 @@ if [ "$EUID" -ne 0 ]; then #Thunderbird Profiles export PROFILE_TB_SRC="mozilla_profiles/thunderbird" export PROFILE_TB_DST="${DECRYPTEDDATADIR}/thunderbird" + + # Mail account auto-provisioning for DAVTOKEN_USER@TLDOMAIN in Thunderbird + export SERVERFQDN_IMAP="imap.${TLDOMAIN}" # IMAP server hostname (e.g. imap.strato.de) + export TB_MAIL_FULLNAME="${USER}" # Display name written to the Thunderbird identity fi #Basic commons not needing change -- 2.52.0 From 51ee27f514589194ec3bb931f1d2cc13c3cc864c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20unbrot=20P=C3=A4tzold?= Date: Sat, 2 May 2026 12:21:13 +0200 Subject: [PATCH 3/6] 0020_nextcloud_mozilla_pre: auto-provision Thunderbird IMAP account at logon Fetches user_full_name (givenname + sn) and user_email from FreeIPA via ipalib and writes them into the Thunderbird IMAP account prefs. Adds ipalib availability check to logon_script.sh. Drops TB_MAIL_FULLNAME config variable. Co-Authored-By: Claude Sonnet 4.6 --- .../0020_nextcloud_mozilla_pre/test_api.sh | 14 ++++++ .../0020_nextcloud_mozilla_pre/user_run.sh | 45 +++++++++++-------- config/setup_system.conf.dist | 1 - system_setup/logon_script.sh | 7 +++ 4 files changed, 48 insertions(+), 19 deletions(-) create mode 100755 client_software/0020_nextcloud_mozilla_pre/test_api.sh diff --git a/client_software/0020_nextcloud_mozilla_pre/test_api.sh b/client_software/0020_nextcloud_mozilla_pre/test_api.sh new file mode 100755 index 0000000..bf94cd5 --- /dev/null +++ b/client_software/0020_nextcloud_mozilla_pre/test_api.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env python3 +from ipalib import api +from os import environ + +api.bootstrap(context="cli", in_server=False) +api.finalize() +api.Backend.rpcclient.connect() + +result = api.Command.user_show(environ['USER']) +user_email = result['result']['mail'][0] +user_full_name = result['result']['givenname'][0] + " " + result['result']['sn'][0] +print(result) +print(f"user_email: {user_email}") +print(f"user_full_name: {user_full_name}") diff --git a/client_software/0020_nextcloud_mozilla_pre/user_run.sh b/client_software/0020_nextcloud_mozilla_pre/user_run.sh index d561817..76c6304 100755 --- a/client_software/0020_nextcloud_mozilla_pre/user_run.sh +++ b/client_software/0020_nextcloud_mozilla_pre/user_run.sh @@ -12,6 +12,8 @@ import tarfile import shutil import os from os import environ +#see FreeIPA APIs: https://freeipa.readthedocs.io/en/latest/api/basic_usage.html +from ipalib import api # See https://pypi.org/project/webdavclient3/ # needs pip install webdavclient3 from webdav3.client import Client @@ -79,6 +81,7 @@ if 'PROFILE_FIREFOX_SRC' in environ: # Check and setup mozilla #Next sync will be executed by logon script #Thunderbird first profile setup +tb_profile_dir = environ['PROFILE_TB_DST'] + "/default" if 'PROFILE_TB_SRC' in environ: # Check and setup mozilla pathstr = environ['PROFILE_TB_SRC'] + "/default" if not client.check(pathstr): @@ -94,8 +97,8 @@ if 'PROFILE_TB_SRC' in environ: # Check and setup mozilla client.execute_request("mkdir", "/" + pathstr) print("Done.") #Check and create local Folder - if not os.path.exists(environ['PROFILE_TB_DST'] + "/default"): - os.makedirs(environ['PROFILE_TB_DST'] + "/default") + if not os.path.exists(tb_profile_dir): + os.makedirs(tb_profile_dir) #First sync to initialise sync-db print("Call " + environ['SYSCONFIGPATH'] + "/system_setup/mozilla_starter.sh thunderbird sync") retstr = subprocess.call(['sh', environ['SYSCONFIGPATH'] + '/system_setup/mozilla_starter.sh', 'thunderbird', 'sync']) @@ -111,11 +114,17 @@ if 'PROFILE_TB_SRC' in environ: # Check and setup mozilla if ('PROFILE_TB_DST' in environ and 'TLDOMAIN' in environ and 'SERVERFQDN_IMAP' in environ and 'DAVTOKEN_USER' in environ): prefs_path = environ['PROFILE_TB_DST'] + "/default/prefs.js" - mail_user = environ['DAVTOKEN_USER'] + "@" + environ['TLDOMAIN'] - mail_user_url = mail_user.replace('@', '%40') imap_host = environ['SERVERFQDN_IMAP'] - full_name = environ.get('TB_MAIL_FULLNAME', environ['DAVTOKEN_USER']) - profile_dir = environ['PROFILE_TB_DST'] + "/default" + account_name = environ['DAVTOKEN_USER'] + "@" + environ['TLDOMAIN'] + + #Call IPA api to get the Values + api.bootstrap(context="cli", in_server=False) + api.finalize() + api.Backend.rpcclient.connect() + api_userinfo = api.Command.user_show(environ['DAVTOKEN_USER']) + + user_full_name = api_userinfo['result']['givenname'][0] + " " + api_userinfo['result']['sn'][0] + user_email = api_userinfo['result']['mail'][0] if not os.path.exists(prefs_path): print("Thunderbird prefs.js not found, skipping mail account setup.") @@ -124,13 +133,13 @@ if ('PROFILE_TB_DST' in environ and 'TLDOMAIN' in environ and prefs = f.read() account_exists = bool(re.search( - r'mail\.server\.server\d+\.userName",\s*"' + re.escape(mail_user) + '"', + r'mail\.server\.server\d+\.userName",\s*"' + re.escape(account_name) + '"', prefs )) if account_exists: - print(f"Thunderbird IMAP account for {mail_user} already configured.") + print(f"Thunderbird IMAP account {account_name} already configured.") else: - print(f"Adding Thunderbird IMAP account for {mail_user} ...") + print(f"Adding Thunderbird IMAP account {account_name} ...") server_nums = [int(x) for x in re.findall(r'mail\.server\.server(\d+)\.type', prefs)] account_nums = [int(x) for x in re.findall(r'mail\.account\.account(\d+)\.server', prefs)] @@ -144,28 +153,28 @@ if ('PROFILE_TB_DST' in environ and 'TLDOMAIN' in environ and new_lines = [ f'user_pref("mail.server.{sn}.check_new_mail", true);', f'user_pref("mail.server.{sn}.cleanup_inbox_on_exit", true);', - f'user_pref("mail.server.{sn}.directory", "{profile_dir}/ImapMail/{imap_host}");', + f'user_pref("mail.server.{sn}.directory", "{tb_profile_dir}/ImapMail/{imap_host}");', f'user_pref("mail.server.{sn}.directory-rel", "[ProfD]ImapMail/{imap_host}");', f'user_pref("mail.server.{sn}.hostname", "{imap_host}");', f'user_pref("mail.server.{sn}.login_at_startup", true);', f'user_pref("mail.server.{sn}.max_cached_connections", 5);', - f'user_pref("mail.server.{sn}.name", "{mail_user}");', + f'user_pref("mail.server.{sn}.name", "{account_name}");', f'user_pref("mail.server.{sn}.port", 993);', f'user_pref("mail.server.{sn}.socketType", 3);', f'user_pref("mail.server.{sn}.storeContractID", "@mozilla.org/msgstore/maildirstore;1");', f'user_pref("mail.server.{sn}.timeout", 29);', f'user_pref("mail.server.{sn}.trash_folder_name", "Trash");', f'user_pref("mail.server.{sn}.type", "imap");', - f'user_pref("mail.server.{sn}.userName", "{mail_user}");', - f'user_pref("mail.identity.{idn}.draft_folder", "imap://{mail_user_url}@{imap_host}/Drafts");', + f'user_pref("mail.server.{sn}.userName", "{environ["DAVTOKEN_USER"]}");', + f'user_pref("mail.identity.{idn}.draft_folder", "imap://{environ["DAVTOKEN_USER"]}@{imap_host}/Drafts");', f'user_pref("mail.identity.{idn}.drafts_folder_picker_mode", "0");', - f'user_pref("mail.identity.{idn}.fcc_folder", "imap://{mail_user_url}@{imap_host}/Sent");', + f'user_pref("mail.identity.{idn}.fcc_folder", "imap://{environ["DAVTOKEN_USER"]}@{imap_host}/Sent");', f'user_pref("mail.identity.{idn}.fcc_folder_picker_mode", "0");', - f'user_pref("mail.identity.{idn}.fullName", "{full_name}");', + f'user_pref("mail.identity.{idn}.fullName", "{user_full_name}");', f'user_pref("mail.identity.{idn}.reply_on_top", 1);', - f'user_pref("mail.identity.{idn}.stationery_folder", "imap://{mail_user_url}@{imap_host}/Templates");', + f'user_pref("mail.identity.{idn}.stationery_folder", "imap://{environ["DAVTOKEN_USER"]}@{imap_host}/Templates");', f'user_pref("mail.identity.{idn}.tmpl_folder_picker_mode", "0");', - f'user_pref("mail.identity.{idn}.useremail", "{mail_user}");', + f'user_pref("mail.identity.{idn}.useremail", "{user_email}");', f'user_pref("mail.identity.{idn}.valid", true);', f'user_pref("mail.account.{an}.identities", "{idn}");', f'user_pref("mail.account.{an}.server", "{sn}");', @@ -186,6 +195,6 @@ if ('PROFILE_TB_DST' in environ and 'TLDOMAIN' in environ and prefs = prefs.rstrip('\n') + '\n' + '\n'.join(new_lines) + '\n' with open(prefs_path, 'w') as f: f.write(prefs) - print(f"Thunderbird IMAP account for {mail_user} added successfully.") + print(f"Thunderbird IMAP account {account_name} added successfully.") sys.exit(0) diff --git a/config/setup_system.conf.dist b/config/setup_system.conf.dist index df0653f..6cb1fcd 100644 --- a/config/setup_system.conf.dist +++ b/config/setup_system.conf.dist @@ -80,7 +80,6 @@ if [ "$EUID" -ne 0 ]; then # Mail account auto-provisioning for DAVTOKEN_USER@TLDOMAIN in Thunderbird export SERVERFQDN_IMAP="imap.${TLDOMAIN}" # IMAP server hostname (e.g. imap.strato.de) - export TB_MAIL_FULLNAME="${USER}" # Display name written to the Thunderbird identity fi #Basic commons not needing change diff --git a/system_setup/logon_script.sh b/system_setup/logon_script.sh index 3dad6b2..a2431cb 100755 --- a/system_setup/logon_script.sh +++ b/system_setup/logon_script.sh @@ -18,11 +18,18 @@ if [ "$EUID" -eq 0 ]; then fi #Check for needed python-modules +#For WEBDAV python -c "import webdav3">/dev/null 2>&1 if [[ $? -ne 0 ]]; then echo "Installing pip module webdav3" pip install webdavclient3>/dev/null fi +#For IPA (system package python3-ipaclient, cannot be pip-installed) +python -c "import ipalib">/dev/null 2>&1 +if [[ $? -ne 0 ]]; then + echo "Error: python3-ipaclient is not installed. Please install it via: sudo dnf install python3-ipaclient" +fi + #TODO C: Check if Desktop is KDE/Plasma and support other Displays # Make kdesu use sudo -- 2.52.0 From c4448caa5f76b4fa2250f1113c0d2136fb61dc2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20unbrot=20P=C3=A4tzold?= Date: Sat, 2 May 2026 13:43:32 +0200 Subject: [PATCH 4/6] mozilla pre: renamed test_api to test_ipaapi --- .../0020_nextcloud_mozilla_pre/{test_api.sh => test_ipaapi.sh} | 0 client_software/0020_nextcloud_mozilla_pre/user_run.sh | 1 - 2 files changed, 1 deletion(-) rename client_software/0020_nextcloud_mozilla_pre/{test_api.sh => test_ipaapi.sh} (100%) diff --git a/client_software/0020_nextcloud_mozilla_pre/test_api.sh b/client_software/0020_nextcloud_mozilla_pre/test_ipaapi.sh similarity index 100% rename from client_software/0020_nextcloud_mozilla_pre/test_api.sh rename to client_software/0020_nextcloud_mozilla_pre/test_ipaapi.sh diff --git a/client_software/0020_nextcloud_mozilla_pre/user_run.sh b/client_software/0020_nextcloud_mozilla_pre/user_run.sh index 76c6304..5fee70d 100755 --- a/client_software/0020_nextcloud_mozilla_pre/user_run.sh +++ b/client_software/0020_nextcloud_mozilla_pre/user_run.sh @@ -122,7 +122,6 @@ if ('PROFILE_TB_DST' in environ and 'TLDOMAIN' in environ and api.finalize() api.Backend.rpcclient.connect() api_userinfo = api.Command.user_show(environ['DAVTOKEN_USER']) - user_full_name = api_userinfo['result']['givenname'][0] + " " + api_userinfo['result']['sn'][0] user_email = api_userinfo['result']['mail'][0] -- 2.52.0 From b37bd8faddd9157fe8561ea94139a223a248e4e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20unbrot=20P=C3=A4tzold?= Date: Sat, 2 May 2026 13:50:47 +0200 Subject: [PATCH 5/6] Add pycache to gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index e1390fd..fcfa0ac 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ .Trash* *.kdev4 .kdev4/* +*__pycache__* client_software/.sync_*.db client_software/setup_system.conf config/setup_system.conf -- 2.52.0 From b233601e16f7cc4a9fba1dbe3419468915ae0517 Mon Sep 17 00:00:00 2001 From: Brot der Bot Date: Sat, 2 May 2026 13:57:59 +0200 Subject: [PATCH 6/6] undo pycache in gitignore --- .gitignore | 1 - 1 file changed, 1 deletion(-) diff --git a/.gitignore b/.gitignore index fcfa0ac..e1390fd 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,6 @@ .Trash* *.kdev4 .kdev4/* -*__pycache__* client_software/.sync_*.db client_software/setup_system.conf config/setup_system.conf -- 2.52.0