[Pkg-mozext-maintainers] Bug#1116196: trixie-pu: package tbsync/4.16-1~deb13u1

Mechtilde Stehmann mechtilde at debian.org
Wed Sep 24 10:49:44 BST 2025


Package: release.debian.org
Severity: normal
Tags: trixie
X-Debbugs-Cc: tbsync at packages.debian.org, mechtilde at debian.org
Control: affects -1 + src:tbsync
User: release.debian.org at packages.debian.org
Usertags: pu

[ Reason ]
Thunderbird will come with a new version (>=140.3) into stable.
This need an update for the Add-Ons (here: tbsync), too.

[ Impact ]
If the update isn't approved the user can't anymore use
the connection to the calender of an exchange server.

[ Tests ]
The same upstream code works with thunderbird >= 140.3 in testing.

[ Risks ]
Code is trivial so no risk

[ Checklist ]
  [X] *all* changes are documented in the d/changelog
  [X] I reviewed all changes and I approve them
  [X] attach debdiff against the package in (old)stable
  [X] the issue is verified as fixed in unstable

[ Changes ]
The new version of thunderbird needs a new version of webext-tbsync.

[ Other info ]
The only reason is the new upcomming version of the thunderbird.
With the proposed update we should wait until the (security-) update of
Thunderbird to 140.x
-------------- next part --------------
diffstat for tbsync-4.12 tbsync-4.16

 CONTRIBUTORS.md                                     |   33 
 LICENSE                                             |  746 +++---
 Makebeta                                            |   37 
 Makefile.bat                                        |   19 
 README.md                                           |   88 
 UPDATE68.md                                         |   24 
 _locales/Readme.txt                                 |   16 
 _locales/bg/messages.json                           |  736 +++---
 _locales/cs/messages.json                           |  736 +++---
 _locales/de/messages.json                           |  736 +++---
 _locales/en-US/messages.json                        |  736 +++---
 _locales/es/messages.json                           |  736 +++---
 _locales/et/messages.json                           |  736 +++---
 _locales/fr/messages.json                           |  736 +++---
 _locales/gl/messages.json                           |  736 +++---
 _locales/hu/messages.json                           |  736 +++---
 _locales/it/messages.json                           |  736 +++---
 _locales/ja/messages.json                           |  736 +++---
 _locales/ko/messages.json                           |  736 +++---
 _locales/pl/messages.json                           |  736 +++---
 _locales/pt_BR/messages.json                        |  736 +++---
 _locales/ro/messages.json                           |  736 +++---
 _locales/ru/messages.json                           |  736 +++---
 _locales/sv/messages.json                           |  736 +++---
 api/LegacyHelper/README.md                          |   50 
 api/LegacyHelper/implementation.js                  |  118 +
 api/LegacyHelper/schema.json                        |   42 
 api/TbSync/implementation.js                        |   57 
 api/TbSync/schema.json                              |   19 
 background.js                                       |   25 
 beta-release-channel-update.json                    |   13 
 content/OverlayManager.jsm                          |  513 ----
 content/OverlayManager.sys.mjs                      |  511 ++++
 content/api/BootstrapLoader/CHANGELOG.md            |   79 
 content/api/BootstrapLoader/README.md               |    1 
 content/api/BootstrapLoader/implementation.js       |  915 -------
 content/api/BootstrapLoader/schema.json             |   61 
 content/manager/accountManager.js                   |  279 +-
 content/manager/accountManager.xhtml                |   54 
 content/manager/accounts.js                         | 1003 ++++----
 content/manager/accounts.xhtml                      |  238 +-
 content/manager/addonoptions.xhtml                  |   15 
 content/manager/catman.xhtml                        |   50 
 content/manager/editAccount.js                      |  789 +++---
 content/manager/editAccount.xhtml                   |  174 -
 content/manager/eventlog/eventlog.js                |  323 +-
 content/manager/eventlog/eventlog.xhtml             |   42 
 content/manager/help.xhtml                          |  116 -
 content/manager/installProvider.xhtml               |   70 
 content/manager/manageProvider.js                   |   89 
 content/manager/manager.css                         |   76 
 content/manager/missingProvider.xhtml               |   42 
 content/manager/noaccounts.xhtml                    |   34 
 content/manager/support-wizard/support-wizard.xhtml |   88 
 content/manager/supporter.xhtml                     |  154 -
 content/modules/addressbook.js                      | 2288 ++++++++++----------
 content/modules/core.js                             |  684 +++--
 content/modules/db.js                               |  842 +++----
 content/modules/eventlog.js                         |  317 +-
 content/modules/io.js                               |  101 
 content/modules/lightning.js                        | 1549 ++++++-------
 content/modules/manager.js                          |  801 +++----
 content/modules/messenger.js                        |  217 +
 content/modules/network.js                          |  239 +-
 content/modules/passwordManager.js                  |  168 -
 content/modules/providers.js                        |  382 +--
 content/modules/public.js                           | 1522 ++++++-------
 content/modules/tools.js                            |  172 -
 content/overlays/messenger.js                       |   53 
 content/overlays/messenger.xhtml                    |   40 
 content/passwordPrompt/passwordPrompt.css           |   26 
 content/passwordPrompt/passwordPrompt.js            |   94 
 content/passwordPrompt/passwordPrompt.xhtml         |   64 
 content/scripts/bootstrap.js                        |   87 
 content/scripts/locales.js                          |   15 
 content/skin/ab.css                                 |   16 
 content/skin/browserOverlay.css                     |   20 
 content/skin/fix_dropdown_1534697.css               |    8 
 content/skin/src/LICENSE                            |  260 +-
 content/tbsync.jsm                                  |  156 -
 content/tbsync.sys.mjs                              |  154 +
 crowdin.yml                                         |    5 
 debian/changelog                                    |   30 
 debian/control                                      |    9 
 debian/copyright                                    |    4 
 debian/dpb.conf                                     |   18 
 debian/gbp.conf                                     |    5 
 debian/upstream/metadata                            |    6 
 debian/watch                                        |    6 
 manifest.json                                       |   99 
 90 files changed, 14629 insertions(+), 15343 deletions(-)

diff -Nru tbsync-4.12/api/LegacyHelper/implementation.js tbsync-4.16/api/LegacyHelper/implementation.js
--- tbsync-4.12/api/LegacyHelper/implementation.js	1970-01-01 01:00:00.000000000 +0100
+++ tbsync-4.16/api/LegacyHelper/implementation.js	2024-10-07 12:07:08.000000000 +0200
@@ -0,0 +1,118 @@
+/*
+ * This file is provided by the webext-support repository at
+ * https://github.com/thunderbird/webext-support
+ *
+ * Version 1.1
+ * - registerGlobalUrls() is now async, to be able to properly await registration
+ *
+ * Version 1.0
+ * - initial release
+ *
+ * Author:
+ * - John Bieling (john at thunderbird.net)
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+"use strict";
+
+// Using a closure to not leak anything but the API to the outside world.
+(function (exports) {
+
+  const aomStartup = Cc[
+    "@mozilla.org/addons/addon-manager-startup;1"
+  ].getService(Ci.amIAddonManagerStartup);
+  const resProto = Cc[
+    "@mozilla.org/network/protocol;1?name=resource"
+  ].getService(Ci.nsISubstitutingProtocolHandler);
+
+  const chromeHandlers = [];
+  const resourceUrls = [];
+
+  var LegacyHelper = class extends ExtensionCommon.ExtensionAPI {
+    getAPI(context) {
+      return {
+        LegacyHelper: {
+          registerGlobalUrls(data) {
+            const manifestURI = Services.io.newURI(
+              "manifest.json",
+              null,
+              context.extension.rootURI
+            );
+
+            for (let entry of data) {
+              // [ "resource", "shortname" , "path" ]
+
+              switch (entry[0]) {
+                case "resource":
+                  {
+                    let uri = Services.io.newURI(
+                      entry[2],
+                      null,
+                      context.extension.rootURI
+                    );
+                    resProto.setSubstitutionWithFlags(
+                      entry[1],
+                      uri,
+                      resProto.ALLOW_CONTENT_ACCESS
+                    );
+                    resourceUrls.push(entry[1]);
+                  }
+                  break;
+
+                case "content":
+                case "locale":
+                  {
+                    let handle = aomStartup.registerChrome(
+                      manifestURI,
+                      [entry]
+                    );
+                    chromeHandlers.push(handle);
+                  }
+                  break;
+                
+                default:
+                  console.warn(`LegacyHelper: Unsupported url type: ${entry[0]}`)
+              } 
+            }
+          },
+
+          openDialog(name, path) {
+            let window = Services.wm.getMostRecentWindow("mail:3pane");
+            window.openDialog(
+              path,
+              name,
+              "chrome,resizable,centerscreen"
+            );
+          },
+        },
+      };
+    }
+
+    onShutdown(isAppShutdown) {
+      if (isAppShutdown) {
+        return; // the application gets unloaded anyway
+      }
+
+      for (let chromeHandler of chromeHandlers) {
+        if (chromeHandler) {
+          chromeHandler.destruct();
+          chromeHandler = null;
+        }
+      }
+
+      for (let resourceUrl of resourceUrls) {
+        resProto.setSubstitution(
+          resourceUrl,
+          null
+        );
+      }
+
+      // Flush all caches.
+      Services.obs.notifyObservers(null, "startupcache-invalidate");
+    }
+  };
+  exports.LegacyHelper = LegacyHelper;
+})(this);
\ Kein Zeilenumbruch am Dateiende.
diff -Nru tbsync-4.12/api/LegacyHelper/README.md tbsync-4.16/api/LegacyHelper/README.md
--- tbsync-4.12/api/LegacyHelper/README.md	1970-01-01 01:00:00.000000000 +0100
+++ tbsync-4.16/api/LegacyHelper/README.md	2024-09-18 15:41:50.000000000 +0200
@@ -0,0 +1,50 @@
+## Objective
+
+This API is a temporary helper while converting legacy extensions to modern WebExtensions. It allows to register `resource://` URLs, which are needed to load custom system modules (*.sys.mjs), and `chrome://` URLs, which are needed to open legacy XUL dialogs.
+
+## Usage
+
+Add the [LegacyHelper API](https://github.com/thunderbird/webext-support/tree/master/experiments/LegacyHelper) to your add-on. Your `manifest.json` needs an entry like this:
+
+```json
+  "experiment_apis": {
+    "LegacyHelper": {
+      "schema": "api/LegacyHelper/schema.json",
+      "parent": {
+        "scopes": ["addon_parent"],
+        "paths": [["LegacyHelper"]],
+        "script": "api/LegacyHelper/implementation.js"
+      }
+    }
+  },
+```
+
+## API Functions
+
+This API provides the following functions:
+
+### async registerGlobalUrls(data)
+
+Register `chrome://*/content/` and `resource://*/` URLs. The function accepts a `data` parameter, which is an array of URL definition items. For example:
+
+```javascript
+await browser.LegacyHelper.registerGlobalUrls([
+  ["content", "myaddon", "chrome/content/"],
+  ["resource", "myaddon", "modules/"],
+]);
+```
+
+This registers the following URLs:
+* `chrome://myaddon/content/` pointing to the `/chrome/content/` folder (the `/content/` part in the URL is fix and does not depend on the name of the folder it is pointing to)
+* `resource://myaddon/` pointing to the `/modules/` folder. To register a `resource://` URL which points to the root folder, use `.` instead".
+
+### async openDialog(name, path)
+
+Open a XUL dialog. The `name` parameter is a unique name identifying the dialog. If the dialog with that name is already open, it will be focused instead of being re-opened. The `path` parameter is a `chrome://*/content/` URL pointing to the XUL dialog file (*.xul or *.xhtml).
+
+```javascript
+browser.LegacyHelper.openDialog(
+  "XulAddonOptions",
+  "chrome://myaddon/content/options.xhtml"
+);
+```
diff -Nru tbsync-4.12/api/LegacyHelper/schema.json tbsync-4.16/api/LegacyHelper/schema.json
--- tbsync-4.12/api/LegacyHelper/schema.json	1970-01-01 01:00:00.000000000 +0100
+++ tbsync-4.16/api/LegacyHelper/schema.json	2024-10-07 10:22:32.000000000 +0200
@@ -0,0 +1,42 @@
+[
+  {
+    "namespace": "LegacyHelper",
+    "functions": [
+      {
+        "name": "registerGlobalUrls",
+        "type": "function",
+        "async": true,
+        "description": "Register folders which should be available as legacy chrome:// urls or resource:// urls",
+        "parameters": [
+          {
+            "name": "data",
+            "type": "array",
+            "items": {
+              "type": "array",
+              "items": {
+                "type": "string"
+              }
+            },
+            "description": "Array of manifest url definitions (content, locale or resource)"
+          }
+        ]
+      },
+      {
+        "name": "openDialog",
+        "type": "function",
+        "parameters": [
+          {
+            "name": "name",
+            "type": "string",
+            "description": "name of the new dialog"
+          },
+          {
+            "name": "path",
+            "type": "string",
+            "description": "path of the dialog to be opened"
+          }
+        ]
+      }
+    ]
+  }
+]
\ Kein Zeilenumbruch am Dateiende.
diff -Nru tbsync-4.12/api/TbSync/implementation.js tbsync-4.16/api/TbSync/implementation.js
--- tbsync-4.12/api/TbSync/implementation.js	1970-01-01 01:00:00.000000000 +0100
+++ tbsync-4.16/api/TbSync/implementation.js	2025-03-15 23:52:50.000000000 +0100
@@ -0,0 +1,57 @@
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+"use strict";
+
+// Using a closure to not leak anything but the API to the outside world.
+(function (exports) {
+
+  var { AddonManager } = ChromeUtils.importESModule(
+    "resource://gre/modules/AddonManager.sys.mjs"
+  );
+  var { ExtensionParent } = ChromeUtils.importESModule(
+    "resource://gre/modules/ExtensionParent.sys.mjs"
+  );
+  
+  var tbsyncExtension = ExtensionParent.GlobalManager.getExtension(
+    "tbsync at jobisoft.de"
+  );
+  var { TbSync: TbSyncModule } = ChromeUtils.importESModule(
+    `chrome://tbsync/content/tbsync.sys.mjs?${tbsyncExtension.manifest.version}`
+  );
+  
+  let defaults = Services.prefs.getDefaultBranch("extensions.tbsync.");
+  defaults.setBoolPref("debug.testoptions", false);
+  defaults.setBoolPref("log.toconsole", false);
+  defaults.setIntPref("log.userdatalevel", 0); //0 - off   1 - userdata only on errors   2 - including full userdata,  3 - extra infos
+
+  var TbSync = class extends ExtensionCommon.ExtensionAPI {
+    getAPI(context) {
+      return {
+        TbSync: {
+          async load() {
+            if (!TbSyncModule.enabled) {
+              let addon = await AddonManager.getAddonByID(context.extension.id);
+              TbSyncModule.load(addon, context.extension);
+            }
+          },
+          openManagerWindow() {
+            TbSyncModule.manager.openManagerWindow();
+          }
+        },
+      };
+    }
+
+    onShutdown(isAppShutdown) {
+      if (isAppShutdown) {
+        return; // the application gets unloaded anyway
+      }
+      TbSyncModule.enabled = false;
+      TbSyncModule.unload();
+    }
+  };
+  exports.TbSync = TbSync;
+})(this);
\ Kein Zeilenumbruch am Dateiende.
diff -Nru tbsync-4.12/api/TbSync/schema.json tbsync-4.16/api/TbSync/schema.json
--- tbsync-4.12/api/TbSync/schema.json	1970-01-01 01:00:00.000000000 +0100
+++ tbsync-4.16/api/TbSync/schema.json	2025-03-15 23:09:00.000000000 +0100
@@ -0,0 +1,19 @@
+[
+  {
+    "namespace": "TbSync",
+    "functions": [
+      {
+        "name": "load",
+        "type": "function",
+        "async": true,
+        "parameters": []
+      },
+      {
+        "name": "openManagerWindow",
+        "type": "function",
+        "async": true,
+        "parameters": []
+      }
+    ]
+  }
+]
\ Kein Zeilenumbruch am Dateiende.
diff -Nru tbsync-4.12/background.js tbsync-4.16/background.js
--- tbsync-4.12/background.js	2024-08-27 18:32:08.000000000 +0200
+++ tbsync-4.16/background.js	2025-05-23 07:49:28.000000000 +0200
@@ -1,16 +1,9 @@
-function handleUpdateAvailable(details) {
-  console.log("Update available for TbSync");
-}
-
-async function main() {
-  // just by registering this listener, updates will not install until next restart
-  //messenger.runtime.onUpdateAvailable.addListener(handleUpdateAvailable);
-
-  await messenger.BootstrapLoader.registerChromeUrl([ ["content", "tbsync", "content/"] ]);
-  await messenger.BootstrapLoader.registerOptionsPage("chrome://tbsync/content/manager/addonoptions.xhtml");
-  await messenger.BootstrapLoader.registerBootstrapScript("chrome://tbsync/content/scripts/bootstrap.js");  
-}
-
-main();
-
-messenger.browserAction.onClicked.addListener(tab => { messenger.BootstrapLoader.openOptionsDialog(tab.windowId); });
+await browser.LegacyHelper.registerGlobalUrls([
+  ["content", "tbsync", "content/"],
+]);
+
+await browser.TbSync.load();
+
+messenger.browserAction.onClicked.addListener(tab => {
+  browser.TbSync.openManagerWindow();
+});
diff -Nru tbsync-4.12/beta-release-channel-update.json tbsync-4.16/beta-release-channel-update.json
--- tbsync-4.12/beta-release-channel-update.json	2024-08-27 18:32:08.000000000 +0200
+++ tbsync-4.16/beta-release-channel-update.json	1970-01-01 01:00:00.000000000 +0100
@@ -1,13 +0,0 @@
-{
-  "addons": {
-    "tbsync at jobisoft.de": {
-      "updates": [
-        { "version": "%VERSION%",
-          "update_info_url": "https://github.com/jobisoft/TbSync/releases",
-          "update_link": "%LINK%",
-          "applications": {
-            "gecko": { "strict_min_version": "78.0" } } }
-      ]
-    }
-  }
-}
\ Kein Zeilenumbruch am Dateiende.
diff -Nru tbsync-4.12/content/api/BootstrapLoader/CHANGELOG.md tbsync-4.16/content/api/BootstrapLoader/CHANGELOG.md
--- tbsync-4.12/content/api/BootstrapLoader/CHANGELOG.md	2024-08-27 18:32:08.000000000 +0200
+++ tbsync-4.16/content/api/BootstrapLoader/CHANGELOG.md	1970-01-01 01:00:00.000000000 +0100
@@ -1,79 +0,0 @@
-Version: 1.22
--------------
-- adjusted to Thunderbird Supernova (Services is now in globalThis)
-
-Version: 1.21
--------------
-- Explicitly set hasAddonManagerEventListeners flag to false on uninstall
-
-Version: 1.20
--------------
-- hard fork BootstrapLoader v1.19 implementation and continue to serve it for
-  Thunderbird 111 and older
-- BootstrapLoader v1.20 has removed a lot of unnecessary code used for backward
-  compatibility
-
-Version: 1.19
--------------
-- fix race condition which could prevent the AOM tab to be monkey patched correctly
-
-Version: 1.18
--------------
-- be precise on which revision the wrench symbol should be displayed, instead of
-  the options button
-
-Version: 1.17
--------------
-- fix "ownerDoc.getElementById() is undefined" bug
-
-Version: 1.16
--------------
-- fix "tab.browser is undefined" bug
-
-Version 1.15
-------------
-- clear cache only if add-on is uninstalled/updated, not on app shutdown
-
-Version 1.14
-------------
-- fix for TB90 ("view-loaded" event) and TB78.10 (wrench icon for options)
-
-Version 1.13
-------------
-- removed notifyTools and move it into its own NotifyTools API
-
-Version 1.12
-------------
-- add support for notifyExperiment and onNotifyBackground
-
-Version 1.11
-------------
-- add openOptionsDialog()
-
-Version 1.10
-------------
-- fix for 68
-
-Version 1.7
------------
-- fix for beta 87
-
-Version 1.6
------------
-- add support for options button/menu in add-on manager and fix 68 double menu entry
-
-Version 1.5
------------
-- fix for e10s
-
-Version 1.4
------------
-- add registerOptionsPage
-
-Version 1.3
------------
-- flush cache
-
-Version 1.2
------------
-- add support for resource urls
diff -Nru tbsync-4.12/content/api/BootstrapLoader/implementation.js tbsync-4.16/content/api/BootstrapLoader/implementation.js
--- tbsync-4.12/content/api/BootstrapLoader/implementation.js	2024-08-27 18:32:08.000000000 +0200
+++ tbsync-4.16/content/api/BootstrapLoader/implementation.js	1970-01-01 01:00:00.000000000 +0100
@@ -1,915 +0,0 @@
-/*
- * This file is provided by the addon-developer-support repository at
- * https://github.com/thundernest/addon-developer-support
- *
- * Version 1.22
- *
- * Author: John Bieling (john at thunderbird.net)
- *
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/.
- */
-
-// Get various parts of the WebExtension framework that we need.
-var { ExtensionSupport } = ChromeUtils.import("resource:///modules/ExtensionSupport.jsm");
-var { AddonManager } = ChromeUtils.import("resource://gre/modules/AddonManager.jsm");
-
-function getThunderbirdVersion() {
-  let parts = Services.appinfo.version.split(".");
-  return {
-    major: parseInt(parts[0]),
-    minor: parseInt(parts[1]),
-    revision: parts.length > 2 ? parseInt(parts[2]) : 0,
-  }
-}
-
-function getMessenger(context) {
-  let apis = ["storage", "runtime", "extension", "i18n"];
-
-  function getStorage() {
-    let localstorage = null;
-    try {
-      localstorage = context.apiCan.findAPIPath("storage");
-      localstorage.local.get = (...args) =>
-        localstorage.local.callMethodInParentProcess("get", args);
-      localstorage.local.set = (...args) =>
-        localstorage.local.callMethodInParentProcess("set", args);
-      localstorage.local.remove = (...args) =>
-        localstorage.local.callMethodInParentProcess("remove", args);
-      localstorage.local.clear = (...args) =>
-        localstorage.local.callMethodInParentProcess("clear", args);
-    } catch (e) {
-      console.info("Storage permission is missing");
-    }
-    return localstorage;
-  }
-
-  let messenger = {};
-  for (let api of apis) {
-    switch (api) {
-      case "storage":
-        ChromeUtils.defineLazyGetter(messenger, "storage", () =>
-          getStorage()
-        );
-        break;
-
-      default:
-        ChromeUtils.defineLazyGetter(messenger, api, () =>
-          context.apiCan.findAPIPath(api)
-        );
-    }
-  }
-  return messenger;
-}
-
-var BootstrapLoader_102 = class extends ExtensionCommon.ExtensionAPI {
-  getCards(e) {
-    // This gets triggered by real events but also manually by providing the outer window.
-    // The event is attached to the outer browser, get the inner one.
-    let doc;
-
-    // 78,86, and 87+ need special handholding. *Yeah*.
-    if (getThunderbirdVersion().major < 86) {
-      let ownerDoc = e.document || e.target.ownerDocument;
-      doc = ownerDoc.getElementById("html-view-browser").contentDocument;
-    } else if (getThunderbirdVersion().major < 87) {
-      let ownerDoc = e.document || e.target;
-      doc = ownerDoc.getElementById("html-view-browser").contentDocument;
-    } else {
-      doc = e.document || e.target;
-    }
-    return doc.querySelectorAll("addon-card");
-  }
-
-  // Add pref entry to 68
-  add68PrefsEntry(event) {
-    let id = this.menu_addonPrefs_id + "_" + this.uniqueRandomID;
-
-    // Get the best size of the icon (16px or bigger)
-    let iconSizes = this.extension.manifest.icons
-      ? Object.keys(this.extension.manifest.icons)
-      : [];
-    iconSizes.sort((a, b) => a - b);
-    let bestSize = iconSizes.filter(e => parseInt(e) >= 16).shift();
-    let icon = bestSize ? this.extension.manifest.icons[bestSize] : "";
-
-    let name = this.extension.manifest.name;
-    let entry = icon
-      ? event.target.ownerGlobal.MozXULElement.parseXULToFragment(
-        `<menuitem class="menuitem-iconic" id="${id}" image="${icon}" label="${name}" />`)
-      : event.target.ownerGlobal.MozXULElement.parseXULToFragment(
-        `<menuitem id="${id}" label="${name}" />`);
-
-    event.target.appendChild(entry);
-    let noPrefsElem = event.target.querySelector('[disabled="true"]');
-    // using collapse could be undone by core, so we use display none
-    // noPrefsElem.setAttribute("collapsed", "true");
-    noPrefsElem.style.display = "none";
-    event.target.ownerGlobal.document.getElementById(id).addEventListener("command", this);
-  }
-
-  // Event handler for the addon manager, to update the state of the options button.
-  handleEvent(e) {
-    switch (e.type) {
-      // 68 add-on options menu showing
-      case "popupshowing": {
-        this.add68PrefsEntry(e);
-      }
-        break;
-
-      // 78/88 add-on options menu/button click
-      case "click": {
-        e.preventDefault();
-        e.stopPropagation();
-        let BL = {}
-        BL.extension = this.extension;
-        BL.messenger = getMessenger(this.context);
-        let w = Services.wm.getMostRecentWindow("mail:3pane");
-        w.openDialog(this.pathToOptionsPage, "AddonOptions", "chrome,resizable,centerscreen", BL);
-      }
-        break;
-
-      // 68 add-on options menu command
-      case "command": {
-        let BL = {}
-        BL.extension = this.extension;
-        BL.messenger = getMessenger(this.context);
-        e.target.ownerGlobal.openDialog(this.pathToOptionsPage, "AddonOptions", "chrome,resizable,centerscreen", BL);
-      }
-        break;
-
-      // update, ViewChanged and manual call for add-on manager options overlay
-      default: {
-        let cards = this.getCards(e);
-        for (let card of cards) {
-          // Setup either the options entry in the menu or the button
-          if (card.addon.id == this.extension.id) {
-            let optionsMenu =
-              (getThunderbirdVersion().major > 78 && getThunderbirdVersion().major < 88) ||
-              (getThunderbirdVersion().major == 78 && getThunderbirdVersion().minor < 10) ||
-              (getThunderbirdVersion().major == 78 && getThunderbirdVersion().minor == 10 && getThunderbirdVersion().revision < 2);
-            if (optionsMenu) {
-              // Options menu in 78.0-78.10 and 79-87
-              let addonOptionsLegacyEntry = card.querySelector(".extension-options-legacy");
-              if (card.addon.isActive && !addonOptionsLegacyEntry) {
-                let addonOptionsEntry = card.querySelector("addon-options panel-list panel-item[action='preferences']");
-                addonOptionsLegacyEntry = card.ownerDocument.createElement("panel-item");
-                addonOptionsLegacyEntry.setAttribute("data-l10n-id", "preferences-addon-button");
-                addonOptionsLegacyEntry.classList.add("extension-options-legacy");
-                addonOptionsEntry.parentNode.insertBefore(
-                  addonOptionsLegacyEntry,
-                  addonOptionsEntry
-                );
-                card.querySelector(".extension-options-legacy").addEventListener("click", this);
-              } else if (!card.addon.isActive && addonOptionsLegacyEntry) {
-                addonOptionsLegacyEntry.remove();
-              }
-            } else {
-              // Add-on button in 88
-              let addonOptionsButton = card.querySelector(".extension-options-button2");
-              if (card.addon.isActive && !addonOptionsButton) {
-                addonOptionsButton = card.ownerDocument.createElement("button");
-                addonOptionsButton.classList.add("extension-options-button2");
-                addonOptionsButton.style["min-width"] = "auto";
-                addonOptionsButton.style["min-height"] = "auto";
-                addonOptionsButton.style["width"] = "24px";
-                addonOptionsButton.style["height"] = "24px";
-                addonOptionsButton.style["margin"] = "0";
-                addonOptionsButton.style["margin-inline-start"] = "8px";
-                addonOptionsButton.style["-moz-context-properties"] = "fill";
-                addonOptionsButton.style["fill"] = "currentColor";
-                addonOptionsButton.style["background-image"] = "url('chrome://messenger/skin/icons/developer.svg')";
-                addonOptionsButton.style["background-repeat"] = "no-repeat";
-                addonOptionsButton.style["background-position"] = "center center";
-                addonOptionsButton.style["padding"] = "1px";
-                addonOptionsButton.style["display"] = "flex";
-                addonOptionsButton.style["justify-content"] = "flex-end";
-                card.optionsButton.parentNode.insertBefore(
-                  addonOptionsButton,
-                  card.optionsButton
-                );
-                card.querySelector(".extension-options-button2").addEventListener("click", this);
-              } else if (!card.addon.isActive && addonOptionsButton) {
-                addonOptionsButton.remove();
-              }
-            }
-          }
-        }
-      }
-    }
-  }
-
-  // Some tab/add-on-manager related functions
-  getTabMail(window) {
-    return window.document.getElementById("tabmail");
-  }
-
-  // returns the outer browser, not the nested browser of the add-on manager
-  // events must be attached to the outer browser
-  getAddonManagerFromTab(tab) {
-    if (tab.browser && tab.mode.name == "contentTab") {
-      let win = tab.browser.contentWindow;
-      if (win && win.location.href == "about:addons") {
-        return win;
-      }
-    }
-  }
-
-  getAddonManagerFromWindow(window) {
-    let tabMail = this.getTabMail(window);
-    for (let tab of tabMail.tabInfo) {
-      let managerWindow = this.getAddonManagerFromTab(tab);
-      if (managerWindow) {
-        return managerWindow;
-      }
-    }
-  }
-
-  async getAddonManagerFromWindowWaitForLoad(window) {
-    let { setTimeout } = Services.wm.getMostRecentWindow("mail:3pane");
-
-    let tabMail = this.getTabMail(window);
-    for (let tab of tabMail.tabInfo) {
-      if (tab.browser && tab.mode.name == "contentTab") {
-        // Instead of registering a load observer, wait until its loaded. Not nice,
-        // but gets aroud a lot of edge cases.
-        while (!tab.pageLoaded) {
-          await new Promise(r => setTimeout(r, 150));
-        }
-        let managerWindow = this.getAddonManagerFromTab(tab);
-        if (managerWindow) {
-          return managerWindow;
-        }
-      }
-    }
-  }
-
-  setupAddonManager(managerWindow, forceLoad = false) {
-    if (!managerWindow) {
-      return;
-    }
-    if (
-      managerWindow &&
-      managerWindow[this.uniqueRandomID] &&
-      managerWindow[this.uniqueRandomID].hasAddonManagerEventListeners
-    ) {
-      return;
-    }
-    managerWindow.document.addEventListener("ViewChanged", this);
-    managerWindow.document.addEventListener("update", this);
-    managerWindow.document.addEventListener("view-loaded", this);
-    managerWindow[this.uniqueRandomID] = {};
-    managerWindow[this.uniqueRandomID].hasAddonManagerEventListeners = true;
-    if (forceLoad) {
-      this.handleEvent(managerWindow);
-    }
-  }
-
-  getAPI(context) {
-    this.uniqueRandomID = "AddOnNS" + context.extension.instanceId;
-    this.menu_addonPrefs_id = "addonPrefs";
-
-
-    this.pathToBootstrapScript = null;
-    this.pathToOptionsPage = null;
-    this.chromeHandle = null;
-    this.chromeData = null;
-    this.resourceData = null;
-    this.bootstrappedObj = {};
-
-    // make the extension object and the messenger object available inside
-    // the bootstrapped scope
-    this.bootstrappedObj.extension = context.extension;
-    this.bootstrappedObj.messenger = getMessenger(this.context);
-
-    this.BOOTSTRAP_REASONS = {
-      APP_STARTUP: 1,
-      APP_SHUTDOWN: 2,
-      ADDON_ENABLE: 3,
-      ADDON_DISABLE: 4,
-      ADDON_INSTALL: 5,
-      ADDON_UNINSTALL: 6, // not supported
-      ADDON_UPGRADE: 7,
-      ADDON_DOWNGRADE: 8,
-    };
-
-    const aomStartup = Cc["@mozilla.org/addons/addon-manager-startup;1"].getService(Ci.amIAddonManagerStartup);
-    const resProto = Cc["@mozilla.org/network/protocol;1?name=resource"].getService(Ci.nsISubstitutingProtocolHandler);
-
-    let self = this;
-
-    // TabMonitor to detect opening of tabs, to setup the options button in the add-on manager.
-    this.tabMonitor = {
-      onTabTitleChanged(tab) { },
-      onTabClosing(tab) { },
-      onTabPersist(tab) { },
-      onTabRestored(tab) { },
-      onTabSwitched(aNewTab, aOldTab) { },
-      async onTabOpened(tab) {
-        if (tab.browser && tab.mode.name == "contentTab") {
-          let { setTimeout } = Services.wm.getMostRecentWindow("mail:3pane");
-          // Instead of registering a load observer, wait until its loaded. Not nice,
-          // but gets aroud a lot of edge cases.
-          while (!tab.pageLoaded) {
-            await new Promise(r => setTimeout(r, 150));
-          }
-          self.setupAddonManager(self.getAddonManagerFromTab(tab));
-        }
-      },
-    };
-
-    return {
-      BootstrapLoader: {
-
-        registerOptionsPage(optionsUrl) {
-          self.pathToOptionsPage = optionsUrl.startsWith("chrome://")
-            ? optionsUrl
-            : context.extension.rootURI.resolve(optionsUrl);
-        },
-
-        openOptionsDialog(windowId) {
-          let window = context.extension.windowManager.get(windowId, context).window
-          let BL = {}
-          BL.extension = self.extension;
-          BL.messenger = getMessenger(self.context);
-          window.openDialog(self.pathToOptionsPage, "AddonOptions", "chrome,resizable,centerscreen", BL);
-        },
-
-        registerChromeUrl(data) {
-          let chromeData = [];
-          let resourceData = [];
-          for (let entry of data) {
-            if (entry[0] == "resource") resourceData.push(entry);
-            else chromeData.push(entry)
-          }
-
-          if (chromeData.length > 0) {
-            const manifestURI = Services.io.newURI(
-              "manifest.json",
-              null,
-              context.extension.rootURI
-            );
-            self.chromeHandle = aomStartup.registerChrome(manifestURI, chromeData);
-          }
-
-          for (let res of resourceData) {
-            // [ "resource", "shortname" , "path" ]
-            let uri = Services.io.newURI(
-              res[2],
-              null,
-              context.extension.rootURI
-            );
-            resProto.setSubstitutionWithFlags(
-              res[1],
-              uri,
-              resProto.ALLOW_CONTENT_ACCESS
-            );
-          }
-
-          self.chromeData = chromeData;
-          self.resourceData = resourceData;
-        },
-
-        registerBootstrapScript: async function (aPath) {
-          self.pathToBootstrapScript = aPath.startsWith("chrome://")
-            ? aPath
-            : context.extension.rootURI.resolve(aPath);
-
-          // Get the addon object belonging to this extension.
-          let addon = await AddonManager.getAddonByID(context.extension.id);
-          //make the addon globally available in the bootstrapped scope
-          self.bootstrappedObj.addon = addon;
-
-          // add BOOTSTRAP_REASONS to scope
-          for (let reason of Object.keys(self.BOOTSTRAP_REASONS)) {
-            self.bootstrappedObj[reason] = self.BOOTSTRAP_REASONS[reason];
-          }
-
-          // Load registered bootstrap scripts and execute its startup() function.
-          try {
-            if (self.pathToBootstrapScript) Services.scriptloader.loadSubScript(self.pathToBootstrapScript, self.bootstrappedObj, "UTF-8");
-            if (self.bootstrappedObj.startup) self.bootstrappedObj.startup.call(self.bootstrappedObj, self.extension.addonData, self.BOOTSTRAP_REASONS[self.extension.startupReason]);
-          } catch (e) {
-            Components.utils.reportError(e)
-          }
-
-          // Register window listener for main TB window
-          if (self.pathToOptionsPage) {
-            ExtensionSupport.registerWindowListener("injectListener_" + self.uniqueRandomID, {
-              chromeURLs: [
-                "chrome://messenger/content/messenger.xul",
-                "chrome://messenger/content/messenger.xhtml",
-              ],
-              async onLoadWindow(window) {
-                if (getThunderbirdVersion().major < 78) {
-                  let element_addonPrefs = window.document.getElementById(self.menu_addonPrefs_id);
-                  element_addonPrefs.addEventListener("popupshowing", self);
-                } else {
-                  // Add a tabmonitor, to be able to setup the options button/menu in the add-on manager.
-                  self.getTabMail(window).registerTabMonitor(self.tabMonitor);
-                  window[self.uniqueRandomID] = {};
-                  window[self.uniqueRandomID].hasTabMonitor = true;
-                  // Setup the options button/menu in the add-on manager, if it is already open.
-                  let managerWindow = await self.getAddonManagerFromWindowWaitForLoad(window);
-                  self.setupAddonManager(managerWindow, true);
-                }
-              },
-
-              onUnloadWindow(window) {
-              }
-            });
-          }
-        }
-      }
-    };
-  }
-
-  onShutdown(isAppShutdown) {
-    if (isAppShutdown) {
-      return; // the application gets unloaded anyway
-    }
-
-    //remove our entry in the add-on options menu
-    if (this.pathToOptionsPage) {
-      for (let window of Services.wm.getEnumerator("mail:3pane")) {
-        if (getThunderbirdVersion().major < 78) {
-          let element_addonPrefs = window.document.getElementById(this.menu_addonPrefs_id);
-          element_addonPrefs.removeEventListener("popupshowing", this);
-          // Remove our entry.
-          let entry = window.document.getElementById(this.menu_addonPrefs_id + "_" + this.uniqueRandomID);
-          if (entry) entry.remove();
-          // Do we have to unhide the noPrefsElement?
-          if (element_addonPrefs.children.length == 1) {
-            let noPrefsElem = element_addonPrefs.querySelector('[disabled="true"]');
-            noPrefsElem.style.display = "inline";
-          }
-        } else {
-          // Remove event listener for addon manager view changes
-          let managerWindow = this.getAddonManagerFromWindow(window);
-          if (
-            managerWindow && 
-            managerWindow[this.uniqueRandomID] && 
-            managerWindow[this.uniqueRandomID].hasAddonManagerEventListeners
-          ) {
-            managerWindow.document.removeEventListener("ViewChanged", this);
-            managerWindow.document.removeEventListener("update", this);
-            managerWindow.document.removeEventListener("view-loaded", this);
-            managerWindow[this.uniqueRandomID].hasAddonManagerEventListeners = false;
-
-            let cards = this.getCards(managerWindow);
-            if (getThunderbirdVersion().major < 88) {
-              // Remove options menu in 78-87
-              for (let card of cards) {
-                let addonOptionsLegacyEntry = card.querySelector(".extension-options-legacy");
-                if (addonOptionsLegacyEntry) addonOptionsLegacyEntry.remove();
-              }
-            } else {
-              // Remove options button in 88
-              for (let card of cards) {
-                if (card.addon.id == this.extension.id) {
-                  let addonOptionsButton = card.querySelector(".extension-options-button2");
-                  if (addonOptionsButton) addonOptionsButton.remove();
-                  break;
-                }
-              }
-            }
-          }
-
-          // Remove tabmonitor
-          if (window[this.uniqueRandomID].hasTabMonitor) {
-            this.getTabMail(window).unregisterTabMonitor(this.tabMonitor);
-            window[this.uniqueRandomID].hasTabMonitor = false;
-          }
-
-        }
-      }
-      // Stop listening for new windows.
-      ExtensionSupport.unregisterWindowListener("injectListener_" + this.uniqueRandomID);
-    }
-
-    // Execute registered shutdown()
-    try {
-      if (this.bootstrappedObj.shutdown) {
-        this.bootstrappedObj.shutdown(
-          this.extension.addonData,
-          isAppShutdown
-            ? this.BOOTSTRAP_REASONS.APP_SHUTDOWN
-            : this.BOOTSTRAP_REASONS.ADDON_DISABLE);
-      }
-    } catch (e) {
-      Components.utils.reportError(e)
-    }
-
-    if (this.resourceData) {
-      const resProto = Cc["@mozilla.org/network/protocol;1?name=resource"].getService(Ci.nsISubstitutingProtocolHandler);
-      for (let res of this.resourceData) {
-        // [ "resource", "shortname" , "path" ]
-        resProto.setSubstitution(
-          res[1],
-          null,
-        );
-      }
-    }
-
-    if (this.chromeHandle) {
-      this.chromeHandle.destruct();
-      this.chromeHandle = null;
-    }
-    // Flush all caches
-    Services.obs.notifyObservers(null, "startupcache-invalidate");
-    console.log("BootstrapLoader for " + this.extension.id + " unloaded!");
-  }
-};
-
-// Removed all extra code for backward compatibility for better maintainability.
-var BootstrapLoader_115 = class extends ExtensionCommon.ExtensionAPI {
-  getCards(e) {
-    // This gets triggered by real events but also manually by providing the outer window.
-    // The event is attached to the outer browser, get the inner one.
-    let doc = e.document || e.target;
-    return doc.querySelectorAll("addon-card");
-  }
-
-  // Event handler for the addon manager, to update the state of the options button.
-  handleEvent(e) {
-    switch (e.type) {
-      case "click": {
-        e.preventDefault();
-        e.stopPropagation();
-        let BL = {}
-        BL.extension = this.extension;
-        BL.messenger = getMessenger(this.context);
-        let w = Services.wm.getMostRecentWindow("mail:3pane");
-        w.openDialog(
-          this.pathToOptionsPage,
-          "AddonOptions",
-          "chrome,resizable,centerscreen",
-          BL
-        );
-      }
-        break;
-
-
-      // update, ViewChanged and manual call for add-on manager options overlay
-      default: {
-        let cards = this.getCards(e);
-        for (let card of cards) {
-          // Setup either the options entry in the menu or the button
-          if (card.addon.id == this.extension.id) {
-            // Add-on button
-            let addonOptionsButton = card.querySelector(
-              ".windowlistener-options-button"
-            );
-            if (card.addon.isActive && !addonOptionsButton) {
-              let origAddonOptionsButton = card.querySelector(".extension-options-button")
-              origAddonOptionsButton.setAttribute("hidden", "true");
-
-              addonOptionsButton = card.ownerDocument.createElement("button");
-              addonOptionsButton.classList.add("windowlistener-options-button");
-              addonOptionsButton.classList.add("extension-options-button");
-              card.optionsButton.parentNode.insertBefore(
-                addonOptionsButton,
-                card.optionsButton
-              );
-              card
-                .querySelector(".windowlistener-options-button")
-                .addEventListener("click", this);
-            } else if (!card.addon.isActive && addonOptionsButton) {
-              addonOptionsButton.remove();
-            }
-          }
-        }
-      }
-    }
-  }
-
-  // Some tab/add-on-manager related functions
-  getTabMail(window) {
-    return window.document.getElementById("tabmail");
-  }
-
-  // returns the outer browser, not the nested browser of the add-on manager
-  // events must be attached to the outer browser
-  getAddonManagerFromTab(tab) {
-    if (tab.browser && tab.mode.name == "contentTab") {
-      let win = tab.browser.contentWindow;
-      if (win && win.location.href == "about:addons") {
-        return win;
-      }
-    }
-  }
-
-  getAddonManagerFromWindow(window) {
-    let tabMail = this.getTabMail(window);
-    for (let tab of tabMail.tabInfo) {
-      let managerWindow = this.getAddonManagerFromTab(tab);
-      if (managerWindow) {
-        return managerWindow;
-      }
-    }
-  }
-
-  async getAddonManagerFromWindowWaitForLoad(window) {
-    let { setTimeout } = Services.wm.getMostRecentWindow("mail:3pane");
-
-    let tabMail = this.getTabMail(window);
-    for (let tab of tabMail.tabInfo) {
-      if (tab.browser && tab.mode.name == "contentTab") {
-        // Instead of registering a load observer, wait until its loaded. Not nice,
-        // but gets aroud a lot of edge cases.
-        while (!tab.pageLoaded) {
-          await new Promise(r => setTimeout(r, 150));
-        }
-        let managerWindow = this.getAddonManagerFromTab(tab);
-        if (managerWindow) {
-          return managerWindow;
-        }
-      }
-    }
-  }
-
-  setupAddonManager(managerWindow, forceLoad = false) {
-    if (!managerWindow) {
-      return;
-    }
-    if (!this.pathToOptionsPage) {
-      return;
-    }
-    if (
-      managerWindow &&
-      managerWindow[this.uniqueRandomID] &&
-      managerWindow[this.uniqueRandomID].hasAddonManagerEventListeners
-    ) {
-      return;
-    }
-    
-    managerWindow.document.addEventListener("ViewChanged", this);
-    managerWindow.document.addEventListener("update", this);
-    managerWindow.document.addEventListener("view-loaded", this);
-    managerWindow[this.uniqueRandomID] = {};
-    managerWindow[this.uniqueRandomID].hasAddonManagerEventListeners = true;
-    if (forceLoad) {
-      this.handleEvent(managerWindow);
-    }
-  }
-
-  getAPI(context) {
-    this.uniqueRandomID = "AddOnNS" + context.extension.instanceId;
-    this.menu_addonPrefs_id = "addonPrefs";
-
-
-    this.pathToBootstrapScript = null;
-    this.pathToOptionsPage = null;
-    this.chromeHandle = null;
-    this.chromeData = null;
-    this.resourceData = null;
-    this.bootstrappedObj = {};
-
-    // make the extension object and the messenger object available inside
-    // the bootstrapped scope
-    this.bootstrappedObj.extension = context.extension;
-    this.bootstrappedObj.messenger = getMessenger(this.context);
-
-    this.BOOTSTRAP_REASONS = {
-      APP_STARTUP: 1,
-      APP_SHUTDOWN: 2,
-      ADDON_ENABLE: 3,
-      ADDON_DISABLE: 4,
-      ADDON_INSTALL: 5,
-      ADDON_UNINSTALL: 6, // not supported
-      ADDON_UPGRADE: 7,
-      ADDON_DOWNGRADE: 8,
-    };
-
-    const aomStartup = Cc["@mozilla.org/addons/addon-manager-startup;1"].getService(Ci.amIAddonManagerStartup);
-    const resProto = Cc["@mozilla.org/network/protocol;1?name=resource"].getService(Ci.nsISubstitutingProtocolHandler);
-
-    let self = this;
-
-    // TabMonitor to detect opening of tabs, to setup the options button in the add-on manager.
-    this.tabMonitor = {
-      onTabTitleChanged(tab) { },
-      onTabClosing(tab) { },
-      onTabPersist(tab) { },
-      onTabRestored(tab) { },
-      onTabSwitched(aNewTab, aOldTab) { },
-      async onTabOpened(tab) {
-        if (tab.browser && tab.mode.name == "contentTab") {
-          let { setTimeout } = Services.wm.getMostRecentWindow("mail:3pane");
-          // Instead of registering a load observer, wait until its loaded. Not nice,
-          // but gets aroud a lot of edge cases.
-          while (!tab.pageLoaded) {
-            await new Promise(r => setTimeout(r, 150));
-          }
-          self.setupAddonManager(self.getAddonManagerFromTab(tab));
-        }
-      },
-    };
-
-    return {
-      BootstrapLoader: {
-
-        registerOptionsPage(optionsUrl) {
-          self.pathToOptionsPage = optionsUrl.startsWith("chrome://")
-            ? optionsUrl
-            : context.extension.rootURI.resolve(optionsUrl);
-        },
-
-        openOptionsDialog(windowId) {
-          let window = context.extension.windowManager.get(windowId, context).window
-          let BL = {}
-          BL.extension = self.extension;
-          BL.messenger = getMessenger(self.context);
-          window.openDialog(self.pathToOptionsPage, "AddonOptions", "chrome,resizable,centerscreen", BL);
-        },
-
-        registerChromeUrl(data) {
-          let chromeData = [];
-          let resourceData = [];
-          for (let entry of data) {
-            if (entry[0] == "resource") resourceData.push(entry);
-            else chromeData.push(entry)
-          }
-
-          if (chromeData.length > 0) {
-            const manifestURI = Services.io.newURI(
-              "manifest.json",
-              null,
-              context.extension.rootURI
-            );
-            self.chromeHandle = aomStartup.registerChrome(manifestURI, chromeData);
-          }
-
-          for (let res of resourceData) {
-            // [ "resource", "shortname" , "path" ]
-            let uri = Services.io.newURI(
-              res[2],
-              null,
-              context.extension.rootURI
-            );
-            resProto.setSubstitutionWithFlags(
-              res[1],
-              uri,
-              resProto.ALLOW_CONTENT_ACCESS
-            );
-          }
-
-          self.chromeData = chromeData;
-          self.resourceData = resourceData;
-        },
-
-        registerBootstrapScript: async function (aPath) {
-          self.pathToBootstrapScript = aPath.startsWith("chrome://")
-            ? aPath
-            : context.extension.rootURI.resolve(aPath);
-
-          // Get the addon object belonging to this extension.
-          let addon = await AddonManager.getAddonByID(context.extension.id);
-          //make the addon globally available in the bootstrapped scope
-          self.bootstrappedObj.addon = addon;
-
-          // add BOOTSTRAP_REASONS to scope
-          for (let reason of Object.keys(self.BOOTSTRAP_REASONS)) {
-            self.bootstrappedObj[reason] = self.BOOTSTRAP_REASONS[reason];
-          }
-
-          // Load registered bootstrap scripts and execute its startup() function.
-          try {
-            if (self.pathToBootstrapScript) Services.scriptloader.loadSubScript(self.pathToBootstrapScript, self.bootstrappedObj, "UTF-8");
-            if (self.bootstrappedObj.startup) self.bootstrappedObj.startup.call(self.bootstrappedObj, self.extension.addonData, self.BOOTSTRAP_REASONS[self.extension.startupReason]);
-          } catch (e) {
-            Components.utils.reportError(e)
-          }
-
-          // Register window listener for main TB window
-          if (self.pathToOptionsPage) {
-            ExtensionSupport.registerWindowListener("injectListener_" + self.uniqueRandomID, {
-              chromeURLs: [
-                "chrome://messenger/content/messenger.xul",
-                "chrome://messenger/content/messenger.xhtml",
-              ],
-              async onLoadWindow(window) {
-                if (getThunderbirdVersion().major < 78) {
-                  let element_addonPrefs = window.document.getElementById(self.menu_addonPrefs_id);
-                  element_addonPrefs.addEventListener("popupshowing", self);
-                } else {
-                  // Add a tabmonitor, to be able to setup the options button/menu in the add-on manager.
-                  self.getTabMail(window).registerTabMonitor(self.tabMonitor);
-                  window[self.uniqueRandomID] = {};
-                  window[self.uniqueRandomID].hasTabMonitor = true;
-                  // Setup the options button/menu in the add-on manager, if it is already open.
-                  let managerWindow = await self.getAddonManagerFromWindowWaitForLoad(window);
-                  self.setupAddonManager(managerWindow, true);
-                }
-              },
-
-              onUnloadWindow(window) {
-              }
-            });
-          }
-        }
-      }
-    };
-  }
-
-  onShutdown(isAppShutdown) {
-    if (isAppShutdown) {
-      return; // the application gets unloaded anyway
-    }
-
-    //remove our entry in the add-on options menu
-    if (this.pathToOptionsPage) {
-      for (let window of Services.wm.getEnumerator("mail:3pane")) {
-        if (getThunderbirdVersion().major < 78) {
-          let element_addonPrefs = window.document.getElementById(this.menu_addonPrefs_id);
-          element_addonPrefs.removeEventListener("popupshowing", this);
-          // Remove our entry.
-          let entry = window.document.getElementById(this.menu_addonPrefs_id + "_" + this.uniqueRandomID);
-          if (entry) entry.remove();
-          // Do we have to unhide the noPrefsElement?
-          if (element_addonPrefs.children.length == 1) {
-            let noPrefsElem = element_addonPrefs.querySelector('[disabled="true"]');
-            noPrefsElem.style.display = "inline";
-          }
-        } else {
-          // Remove event listener for addon manager view changes
-          let managerWindow = this.getAddonManagerFromWindow(window);
-          if (
-            managerWindow && 
-            managerWindow[this.uniqueRandomID] && 
-            managerWindow[this.uniqueRandomID].hasAddonManagerEventListeners
-          ) {
-            managerWindow.document.removeEventListener("ViewChanged", this);
-            managerWindow.document.removeEventListener("update", this);
-            managerWindow.document.removeEventListener("view-loaded", this);
-            managerWindow[this.uniqueRandomID].hasAddonManagerEventListeners = false;
-
-            let cards = this.getCards(managerWindow);
-            if (getThunderbirdVersion().major < 88) {
-              // Remove options menu in 78-87
-              for (let card of cards) {
-                let addonOptionsLegacyEntry = card.querySelector(".extension-options-legacy");
-                if (addonOptionsLegacyEntry) addonOptionsLegacyEntry.remove();
-              }
-            } else {
-              // Remove options button in 88
-              for (let card of cards) {
-                if (card.addon.id == this.extension.id) {
-                  let addonOptionsButton = card.querySelector(".extension-options-button2");
-                  if (addonOptionsButton) addonOptionsButton.remove();
-                  break;
-                }
-              }
-            }
-          }
-
-          // Remove tabmonitor
-          if (window[this.uniqueRandomID].hasTabMonitor) {
-            this.getTabMail(window).unregisterTabMonitor(this.tabMonitor);
-            window[this.uniqueRandomID].hasTabMonitor = false;
-          }
-
-        }
-      }
-      // Stop listening for new windows.
-      ExtensionSupport.unregisterWindowListener("injectListener_" + this.uniqueRandomID);
-    }
-
-    // Execute registered shutdown()
-    try {
-      if (this.bootstrappedObj.shutdown) {
-        this.bootstrappedObj.shutdown(
-          this.extension.addonData,
-          isAppShutdown
-            ? this.BOOTSTRAP_REASONS.APP_SHUTDOWN
-            : this.BOOTSTRAP_REASONS.ADDON_DISABLE);
-      }
-    } catch (e) {
-      Components.utils.reportError(e)
-    }
-
-    if (this.resourceData) {
-      const resProto = Cc["@mozilla.org/network/protocol;1?name=resource"].getService(Ci.nsISubstitutingProtocolHandler);
-      for (let res of this.resourceData) {
-        // [ "resource", "shortname" , "path" ]
-        resProto.setSubstitution(
-          res[1],
-          null,
-        );
-      }
-    }
-
-    if (this.chromeHandle) {
-      this.chromeHandle.destruct();
-      this.chromeHandle = null;
-    }
-    // Flush all caches
-    Services.obs.notifyObservers(null, "startupcache-invalidate");
-    console.log("BootstrapLoader for " + this.extension.id + " unloaded!");
-  }
-};
-
-var BootstrapLoader = getThunderbirdVersion().major < 111
-  ? BootstrapLoader_102
-  : BootstrapLoader_115;
diff -Nru tbsync-4.12/content/api/BootstrapLoader/README.md tbsync-4.16/content/api/BootstrapLoader/README.md
--- tbsync-4.12/content/api/BootstrapLoader/README.md	2024-08-27 18:32:08.000000000 +0200
+++ tbsync-4.16/content/api/BootstrapLoader/README.md	1970-01-01 01:00:00.000000000 +0100
@@ -1 +0,0 @@
-Usage description can be found in the [wiki](https://github.com/thundernest/addon-developer-support/wiki/Using-the-BootstrapLoader-API-to-convert-a-Legacy-Bootstrap-WebExtension-into-a-MailExtension-for-Thunderbird-78).
diff -Nru tbsync-4.12/content/api/BootstrapLoader/schema.json tbsync-4.16/content/api/BootstrapLoader/schema.json
--- tbsync-4.12/content/api/BootstrapLoader/schema.json	2024-08-27 18:32:08.000000000 +0200
+++ tbsync-4.16/content/api/BootstrapLoader/schema.json	1970-01-01 01:00:00.000000000 +0100
@@ -1,61 +0,0 @@
-[
-  {
-    "namespace": "BootstrapLoader",
-    "functions": [
-      {
-        "name": "registerOptionsPage",
-        "type": "function",
-        "parameters": [
-          {
-            "name": "aPath",
-            "type": "string",
-            "description": "Path to the options page, which should be made accessible in the (legacy) Add-On Options menu."
-          }
-        ]
-      },
-      {
-        "name": "openOptionsDialog",
-        "type": "function",
-        "parameters": [
-          {
-            "name": "windowId",
-            "type": "integer",
-            "description": "Id of the window the dialog should be opened from."
-          }
-        ]
-      },
-      {
-        "name": "registerChromeUrl",
-        "type": "function",
-        "description": "Register folders which should be available as chrome:// urls (as defined in the legacy chrome.manifest)",
-        "async": true,
-        "parameters": [
-          {
-            "name": "chromeData",
-            "type": "array",
-            "items": {
-              "type": "array",
-              "items": {
-                "type": "string"
-              }
-            },
-            "description": "Array of ChromeData Arrays."
-          }
-        ]
-      },
-      {
-        "name": "registerBootstrapScript",
-        "type": "function",
-        "description": "Register a bootstrap.js style script",
-        "async": true,
-        "parameters": [
-          {
-            "name": "aPath",
-            "type": "string",
-            "description": "Either the chrome:// path to the script or its relative location from the root of the extension,"
-          }
-        ]
-      }
-    ]
-  }
-]
\ Kein Zeilenumbruch am Dateiende.
diff -Nru tbsync-4.12/content/manager/accountManager.js tbsync-4.16/content/manager/accountManager.js
--- tbsync-4.12/content/manager/accountManager.js	2024-08-27 18:32:08.000000000 +0200
+++ tbsync-4.16/content/manager/accountManager.js	2025-03-15 23:49:58.000000000 +0100
@@ -1,139 +1,140 @@
-/*
- * This file is part of TbSync.
- *
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. 
- */
- 
-"use strict";
-
-var { TbSync } = ChromeUtils.import("chrome://tbsync/content/tbsync.jsm");
-
-var tbSyncAccountManager = {
-  
-  onloadoptions: function () {
-    window.close();
-  },    
-  
-  onunloadoptions: function () {
-    TbSync.manager.openManagerWindow(0);
-  },
-  
-  onload: function () {
-    TbSync.AccountManagerTabs = ["accounts.xhtml", "catman.xhtml", "supporter.xhtml", "help.xhtml"];
-    tbSyncAccountManager.selectTab(0);
-  },
-  
-  onunload: function () {
-    TbSync.manager.prefWindowObj = null;
-  },
-
-  selectTab: function (t) {
-    const LOAD_FLAGS_NONE = Components.interfaces.nsIWebNavigation.LOAD_FLAGS_NONE;
-
-    //set active tab (css selector for background color)
-    for (let i=0; i<TbSync.AccountManagerTabs.length; i++) {            
-      if (i==t) document.getElementById("tbSyncAccountManager.t" + i).setAttribute("active","true");
-      else document.getElementById("tbSyncAccountManager.t" + i).setAttribute("active","false");
-    }
-    TbSync.manager.prefWindowObj.document.getElementById("tbSyncAccountManager.installProvider").hidden=true;
-    
-    //load XUL
-    document.getElementById("tbSyncAccountManager.contentWindow").setAttribute("src", "chrome://tbsync/content/manager/"+TbSync.AccountManagerTabs[t]);
-  },
-  
-  
-  
-  //help tab
-  getLogPref: function() {
-    let log = document.getElementById("tbSyncAccountManager.logLevel");
-    log.value = Math.min(3, TbSync.prefs.getIntPref("log.userdatalevel"));
-  },
-  
-  toggleLogPref: function() {
-    let log = document.getElementById("tbSyncAccountManager.logLevel");
-    TbSync.prefs.setIntPref("log.userdatalevel", log.value);
-  },
-  
-  initSupportWizard: function() {
-    document.getElementById("SupportWizard").getButton("finish").disabled = true;
-
-    let menu = document.getElementById("tbsync.supportwizard.faultycomponent");
-
-    let providers = Object.keys(TbSync.providers.loadedProviders);
-    for (let i=0; i < providers.length; i++) {
-      let item = document.createXULElement("menuitem");
-      item.setAttribute("value", providers[i]);
-      item.setAttribute("label", TbSync.getString("supportwizard.provider::" + TbSync.providers[providers[i]].Base.getProviderName()));
-      menu.appendChild(item); 
-    }
-  
-    document.getElementById("tbsync.supportwizard.faultycomponent.menulist").addEventListener("select", tbSyncAccountManager.checkSupportWizard);
-    document.getElementById("tbsync.supportwizard.description").addEventListener("input", tbSyncAccountManager.checkSupportWizard);
-    document.addEventListener("wizardfinish", tbSyncAccountManager.prepareBugReport);
-
-    // bug https://bugzilla.mozilla.org/show_bug.cgi?id=1618252
-    document.getElementById('SupportWizard')._adjustWizardHeader();
-  },
-  
-  checkSupportWizard: function() {
-    let provider = document.getElementById("tbsync.supportwizard.faultycomponent").parentNode.value;
-    let subject = document.getElementById("tbsync.supportwizard.summary").value;
-    let description = document.getElementById("tbsync.supportwizard.description").value;
-
-    //just check and update button status
-    document.getElementById("SupportWizard").getButton("finish").disabled = (provider == "" || subject == "" || description== "");        
-  },
-
-  prepareBugReport: function(event) {
-    let provider = document.getElementById("tbsync.supportwizard.faultycomponent").parentNode.value;
-    let subject = document.getElementById("tbsync.supportwizard.summary").value;
-    let description = document.getElementById("tbsync.supportwizard.description").value;
-
-    if (provider == "" || subject == "" || description== "") {
-      event.preventDefault();
-      return;
-    }
-
-    //special if core is selected, which is not a provider
-    let email = (TbSync.providers.loadedProviders.hasOwnProperty(provider)) ? TbSync.providers[provider].Base.getMaintainerEmail() : "john.bieling at gmx.de";
-    let version = (TbSync.providers.loadedProviders.hasOwnProperty(provider)) ? " " + TbSync.providers.loadedProviders[provider].version : "";
-    TbSync.manager.createBugReport(email, "[" + provider.toUpperCase() + version + "] " + subject, description);
-  },
-  
-  
-  
-  //community tab
-  initCommunity: function() {
-    let listOfContributors = document.getElementById("listOfContributors");
-    let sponsors = {};
-      
-    let providers = Object.keys(TbSync.providers.loadedProviders);
-    for (let i=0; i < providers.length; i++) {
-      let provider = providers[i];
-      let template = listOfContributors.firstElementChild.cloneNode(true);
-      template.setAttribute("provider", provider);
-      template.children[0].setAttribute("src", TbSync.providers[provider].Base.getProviderIcon(48));
-      template.children[1].children[0].textContent = TbSync.providers[provider].Base.getProviderName();
-      listOfContributors.appendChild(template);
-      Object.assign(sponsors, TbSync.providers[provider].Base.getSponsors());
-    }
-    listOfContributors.removeChild(listOfContributors.firstElementChild);
-
-    let listOfSponsors = document.getElementById("listOfSponsors");
-    let sponsorlist = Object.keys(sponsors);
-    sponsorlist.sort();
-    for (let i=0; i < sponsorlist.length; i++) {
-      let sponsor = sponsors[sponsorlist[i]];
-      let template = listOfSponsors.firstElementChild.cloneNode(true);
-      if (sponsor.link) template.setAttribute("link", sponsor.link);
-      if (sponsor.icon) template.children[0].setAttribute("src", sponsor.icon);
-      template.children[1].children[0].textContent = sponsor.name;
-      template.children[1].children[1].textContent = sponsor.description;
-      listOfSponsors.appendChild(template);
-      listOfSponsors.appendChild(template);
-    }
-    listOfSponsors.removeChild(listOfSponsors.firstElementChild);
-  }        
-};
+/*
+ * This file is part of TbSync.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. 
+ */
+ 
+"use strict";
+
+var { ExtensionParent } = ChromeUtils.importESModule(
+  "resource://gre/modules/ExtensionParent.sys.mjs"
+);
+
+var tbsyncExtension = ExtensionParent.GlobalManager.getExtension(
+  "tbsync at jobisoft.de"
+);
+var { TbSync } = ChromeUtils.importESModule(
+  `chrome://tbsync/content/tbsync.sys.mjs?${tbsyncExtension.manifest.version}`
+);
+
+var tbSyncAccountManager = {
+  
+  onload: function () {
+    TbSync.AccountManagerTabs = ["accounts.xhtml", "catman.xhtml", "supporter.xhtml", "help.xhtml"];
+    tbSyncAccountManager.selectTab(0);
+  },
+  
+  onunload: function () {
+    TbSync.manager.prefWindowObj = null;
+  },
+
+  selectTab: function (t) {
+    const LOAD_FLAGS_NONE = Components.interfaces.nsIWebNavigation.LOAD_FLAGS_NONE;
+
+    //set active tab (css selector for background color)
+    for (let i=0; i<TbSync.AccountManagerTabs.length; i++) {            
+      if (i==t) document.getElementById("tbSyncAccountManager.t" + i).setAttribute("active","true");
+      else document.getElementById("tbSyncAccountManager.t" + i).setAttribute("active","false");
+    }
+    TbSync.manager.prefWindowObj.document.getElementById("tbSyncAccountManager.installProvider").hidden=true;
+    
+    //load XUL
+    document.getElementById("tbSyncAccountManager.contentWindow").setAttribute("src", "chrome://tbsync/content/manager/"+TbSync.AccountManagerTabs[t]);
+  },
+  
+  
+  
+  //help tab
+  getLogPref: function() {
+    let log = document.getElementById("tbSyncAccountManager.logLevel");
+    log.value = Math.min(3, TbSync.prefs.getIntPref("log.userdatalevel"));
+  },
+  
+  toggleLogPref: function() {
+    let log = document.getElementById("tbSyncAccountManager.logLevel");
+    TbSync.prefs.setIntPref("log.userdatalevel", log.value);
+  },
+  
+  initSupportWizard: function() {
+    document.getElementById("SupportWizard").getButton("finish").disabled = true;
+
+    let menu = document.getElementById("tbsync.supportwizard.faultycomponent");
+
+    let providers = Object.keys(TbSync.providers.loadedProviders);
+    for (let i=0; i < providers.length; i++) {
+      let item = document.createXULElement("menuitem");
+      item.setAttribute("value", providers[i]);
+      item.setAttribute("label", TbSync.getString("supportwizard.provider::" + TbSync.providers[providers[i]].Base.getProviderName()));
+      menu.appendChild(item); 
+    }
+  
+    document.getElementById("tbsync.supportwizard.faultycomponent.menulist").addEventListener("select", tbSyncAccountManager.checkSupportWizard);
+    document.getElementById("tbsync.supportwizard.description").addEventListener("input", tbSyncAccountManager.checkSupportWizard);
+    document.addEventListener("wizardfinish", tbSyncAccountManager.prepareBugReport);
+
+    // bug https://bugzilla.mozilla.org/show_bug.cgi?id=1618252
+    document.getElementById('SupportWizard')._adjustWizardHeader();
+  },
+  
+  checkSupportWizard: function() {
+    let provider = document.getElementById("tbsync.supportwizard.faultycomponent").parentNode.value;
+    let subject = document.getElementById("tbsync.supportwizard.summary").value;
+    let description = document.getElementById("tbsync.supportwizard.description").value;
+
+    //just check and update button status
+    document.getElementById("SupportWizard").getButton("finish").disabled = (provider == "" || subject == "" || description== "");        
+  },
+
+  prepareBugReport: function(event) {
+    let provider = document.getElementById("tbsync.supportwizard.faultycomponent").parentNode.value;
+    let subject = document.getElementById("tbsync.supportwizard.summary").value;
+    let description = document.getElementById("tbsync.supportwizard.description").value;
+
+    if (provider == "" || subject == "" || description== "") {
+      event.preventDefault();
+      return;
+    }
+
+    //special if core is selected, which is not a provider
+    let email = (TbSync.providers.loadedProviders.hasOwnProperty(provider)) ? TbSync.providers[provider].Base.getMaintainerEmail() : "john.bieling at gmx.de";
+    let version = (TbSync.providers.loadedProviders.hasOwnProperty(provider)) ? " " + TbSync.providers.loadedProviders[provider].version : "";
+    TbSync.manager.createBugReport(email, "[" + provider.toUpperCase() + version + "] " + subject, description);
+  },
+  
+  
+  
+  //community tab
+  initCommunity: function() {
+    let listOfContributors = document.getElementById("listOfContributors");
+    let sponsors = {};
+      
+    let providers = Object.keys(TbSync.providers.loadedProviders);
+    for (let i=0; i < providers.length; i++) {
+      let provider = providers[i];
+      let template = listOfContributors.firstElementChild.cloneNode(true);
+      template.setAttribute("provider", provider);
+      template.children[0].setAttribute("src", TbSync.providers[provider].Base.getProviderIcon(48));
+      template.children[1].children[0].textContent = TbSync.providers[provider].Base.getProviderName();
+      listOfContributors.appendChild(template);
+      Object.assign(sponsors, TbSync.providers[provider].Base.getSponsors());
+    }
+    listOfContributors.removeChild(listOfContributors.firstElementChild);
+
+    let listOfSponsors = document.getElementById("listOfSponsors");
+    let sponsorlist = Object.keys(sponsors);
+    sponsorlist.sort();
+    for (let i=0; i < sponsorlist.length; i++) {
+      let sponsor = sponsors[sponsorlist[i]];
+      let template = listOfSponsors.firstElementChild.cloneNode(true);
+      if (sponsor.link) template.setAttribute("link", sponsor.link);
+      if (sponsor.icon) template.children[0].setAttribute("src", sponsor.icon);
+      template.children[1].children[0].textContent = sponsor.name;
+      template.children[1].children[1].textContent = sponsor.description;
+      listOfSponsors.appendChild(template);
+      listOfSponsors.appendChild(template);
+    }
+    listOfSponsors.removeChild(listOfSponsors.firstElementChild);
+  }        
+};
diff -Nru tbsync-4.12/content/manager/accountManager.xhtml tbsync-4.16/content/manager/accountManager.xhtml
--- tbsync-4.12/content/manager/accountManager.xhtml	2024-08-27 18:32:08.000000000 +0200
+++ tbsync-4.16/content/manager/accountManager.xhtml	2021-08-30 18:31:42.000000000 +0200
@@ -1,27 +1,27 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<?xml-stylesheet href="chrome://global/skin/global.css" type="text/css"?>
-<?xml-stylesheet href="chrome://tbsync/content/manager/manager.css" type="text/css"?>
-
-<window
-    xmlns:html="http://www.w3.org/1999/xhtml"
-    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
-    xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
-    title="__TBSYNCMSG_manager.title__" 
-    onload="tbSyncAccountManager.onload();"
-    onunload="tbSyncAccountManager.onunload();"
-    width="760" height="620" >
-        
-    <vbox id="manager" flex="1">
-        <hbox id="tbtoolbar">
-            <vbox id="tbSyncAccountManager.t0" onmouseover="this.style.cursor='pointer'" onmouseout="this.style.cursor='default'" onclick="tbSyncAccountManager.selectTab(0)"><hbox flex="1" pack="center" style="min-width:60px"><image src="chrome://tbsync/content/skin/settings32.png" style="width: 32px; height: 32px" /></hbox><hbox flex="1"  pack="center"><label value="__TBSYNCMSG_manager.accountsettings__" /></hbox></vbox>
-            <vbox id="tbSyncAccountManager.t1" onmouseover="this.style.cursor='pointer'" onmouseout="this.style.cursor='default'" onclick="tbSyncAccountManager.selectTab(1)"><hbox flex="1" pack="center" style="min-width:60px"><image src="chrome://tbsync/content/skin/catman32.png" style="width: 32px; height: 32px" /></hbox><hbox flex="1"  pack="center"><label value="Category Manager" /></hbox></vbox>
-            <vbox id="tbSyncAccountManager.t2" onmouseover="this.style.cursor='pointer'" onmouseout="this.style.cursor='default'" onclick="tbSyncAccountManager.selectTab(2)"><hbox flex="1" pack="center" style="min-width:60px"><image src="chrome://tbsync/content/skin/group32.png" style="width: 32px; height: 32px" /></hbox><hbox flex="1"  pack="center"><label value="__TBSYNCMSG_manager.community__" /></hbox></vbox>
-            <vbox id="tbSyncAccountManager.t3" onmouseover="this.style.cursor='pointer'" onmouseout="this.style.cursor='default'" onclick="tbSyncAccountManager.selectTab(3)"><hbox flex="1" pack="center" style="min-width:60px"><image src="chrome://tbsync/content/skin/help32.png" style="width: 32px; height: 32px" /></hbox><hbox flex="1"  pack="center"><label value="__TBSYNCMSG_manager.help__" /></hbox></vbox>
-            <vbox id="tbSyncAccountManager.installProvider" onmouseover="this.style.cursor='pointer'" onmouseout="this.style.cursor='default'"  hidden="true"><hbox flex="1" pack="center" style="min-width:60px"><image src="chrome://tbsync/content/skin/provider32.png" style="width: 32px; height: 32px" /></hbox><hbox flex="1"  pack="center"><label value="__TBSYNCMSG_manager.provider__" /></hbox></vbox>
-        </hbox>
-        <browser id="tbSyncAccountManager.contentWindow" type="chrome" src="" disablehistory="true" flex="1"/>
-    </vbox>
-    
-    <script type="text/javascript" src="chrome://tbsync/content/manager/accountManager.js" /> 
-    <script type="text/javascript" src="chrome://tbsync/content/scripts/locales.js" /> 
-</window>
+<?xml version="1.0" encoding="UTF-8"?>
+<?xml-stylesheet href="chrome://global/skin/global.css" type="text/css"?>
+<?xml-stylesheet href="chrome://tbsync/content/manager/manager.css" type="text/css"?>
+
+<window
+    xmlns:html="http://www.w3.org/1999/xhtml"
+    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+    xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+    title="__TBSYNCMSG_manager.title__" 
+    onload="tbSyncAccountManager.onload();"
+    onunload="tbSyncAccountManager.onunload();"
+    width="760" height="620" >
+        
+    <vbox id="manager" flex="1">
+        <hbox id="tbtoolbar">
+            <vbox id="tbSyncAccountManager.t0" onmouseover="this.style.cursor='pointer'" onmouseout="this.style.cursor='default'" onclick="tbSyncAccountManager.selectTab(0)"><hbox flex="1" pack="center" style="min-width:60px"><image src="chrome://tbsync/content/skin/settings32.png" style="width: 32px; height: 32px" /></hbox><hbox flex="1"  pack="center"><label value="__TBSYNCMSG_manager.accountsettings__" /></hbox></vbox>
+            <vbox id="tbSyncAccountManager.t1" onmouseover="this.style.cursor='pointer'" onmouseout="this.style.cursor='default'" onclick="tbSyncAccountManager.selectTab(1)"><hbox flex="1" pack="center" style="min-width:60px"><image src="chrome://tbsync/content/skin/catman32.png" style="width: 32px; height: 32px" /></hbox><hbox flex="1"  pack="center"><label value="Category Manager" /></hbox></vbox>
+            <vbox id="tbSyncAccountManager.t2" onmouseover="this.style.cursor='pointer'" onmouseout="this.style.cursor='default'" onclick="tbSyncAccountManager.selectTab(2)"><hbox flex="1" pack="center" style="min-width:60px"><image src="chrome://tbsync/content/skin/group32.png" style="width: 32px; height: 32px" /></hbox><hbox flex="1"  pack="center"><label value="__TBSYNCMSG_manager.community__" /></hbox></vbox>
+            <vbox id="tbSyncAccountManager.t3" onmouseover="this.style.cursor='pointer'" onmouseout="this.style.cursor='default'" onclick="tbSyncAccountManager.selectTab(3)"><hbox flex="1" pack="center" style="min-width:60px"><image src="chrome://tbsync/content/skin/help32.png" style="width: 32px; height: 32px" /></hbox><hbox flex="1"  pack="center"><label value="__TBSYNCMSG_manager.help__" /></hbox></vbox>
+            <vbox id="tbSyncAccountManager.installProvider" onmouseover="this.style.cursor='pointer'" onmouseout="this.style.cursor='default'"  hidden="true"><hbox flex="1" pack="center" style="min-width:60px"><image src="chrome://tbsync/content/skin/provider32.png" style="width: 32px; height: 32px" /></hbox><hbox flex="1"  pack="center"><label value="__TBSYNCMSG_manager.provider__" /></hbox></vbox>
+        </hbox>
+        <browser id="tbSyncAccountManager.contentWindow" type="chrome" src="" disablehistory="true" flex="1"/>
+    </vbox>
+    
+    <script type="text/javascript" src="chrome://tbsync/content/manager/accountManager.js" /> 
+    <script type="text/javascript" src="chrome://tbsync/content/scripts/locales.js" /> 
+</window>
diff -Nru tbsync-4.12/content/manager/accounts.js tbsync-4.16/content/manager/accounts.js
--- tbsync-4.12/content/manager/accounts.js	2024-08-27 18:32:08.000000000 +0200
+++ tbsync-4.16/content/manager/accounts.js	2025-03-15 23:49:58.000000000 +0100
@@ -1,497 +1,506 @@
-/*
- * This file is part of TbSync.
- *
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. 
- */
- 
-"use strict";
-
-var { TbSync } = ChromeUtils.import("chrome://tbsync/content/tbsync.jsm");
-
-var tbSyncAccounts = {
-
-  selectedAccount: null,
-
-  onload: function () {
-    //scan accounts, update list and select first entry (because no id is passed to updateAccountList)
-    //the onSelect event of the List will load the selected account
-    //also update/init add menu
-    this.updateAvailableProvider(); 
-    
-    Services.obs.addObserver(tbSyncAccounts.updateProviderListObserver, "tbsync.observer.manager.updateProviderList", false);
-    Services.obs.addObserver(tbSyncAccounts.updateAccountsListObserver, "tbsync.observer.manager.updateAccountsList", false);
-    Services.obs.addObserver(tbSyncAccounts.updateAccountSyncStateObserver, "tbsync.observer.manager.updateSyncstate", false);
-    Services.obs.addObserver(tbSyncAccounts.updateAccountNameObserver, "tbsync.observer.manager.updateAccountName", false);
-    Services.obs.addObserver(tbSyncAccounts.toggleEnableStateObserver, "tbsync.observer.manager.toggleEnableState", false);
-  },
-
-  onunload: function () {
-    Services.obs.removeObserver(tbSyncAccounts.updateProviderListObserver, "tbsync.observer.manager.updateProviderList");
-    Services.obs.removeObserver(tbSyncAccounts.updateAccountsListObserver, "tbsync.observer.manager.updateAccountsList");
-    Services.obs.removeObserver(tbSyncAccounts.updateAccountSyncStateObserver, "tbsync.observer.manager.updateSyncstate");
-    Services.obs.removeObserver(tbSyncAccounts.updateAccountNameObserver, "tbsync.observer.manager.updateAccountName");
-    Services.obs.removeObserver(tbSyncAccounts.toggleEnableStateObserver, "tbsync.observer.manager.toggleEnableState");
-  },       
-  
-  hasInstalledProvider: function (accountID) {
-    let provider = TbSync.db.getAccountProperty(accountID, "provider");
-    return TbSync.providers.loadedProviders.hasOwnProperty(provider);
-  },
-
-  updateDropdown: function (selector) {
-    let accountsList = document.getElementById("tbSyncAccounts.accounts");
-    let selectedAccount = null;
-    let selectedAccountName = "";
-    let isActionsDropdown = (selector == "accountActions");
-
-    let isSyncing = false;
-    let isConnected = false;
-    let isEnabled = false;
-    let isInstalled = false;
-    
-    if (accountsList.selectedItem !== null && !isNaN(accountsList.selectedItem.value)) {
-      //some item is selected
-      let selectedItem = accountsList.selectedItem;
-      selectedAccount = selectedItem.value;
-      selectedAccountName = selectedItem.childNodes[1].getAttribute("value");
-      isSyncing = TbSync.core.isSyncing(selectedAccount);
-      isConnected = TbSync.core.isConnected(selectedAccount);
-      isEnabled = TbSync.core.isEnabled(selectedAccount);
-      isInstalled = tbSyncAccounts.hasInstalledProvider(selectedAccount);
-    }
-
-    //hide if no accounts are avail (which is identical to no account selected)
-    if (isActionsDropdown) document.getElementById(selector + "SyncAllAccounts").hidden = (selectedAccount === null);
-    
-    //hide if no account is selected
-    if (isActionsDropdown) document.getElementById(selector + "Separator").hidden = (selectedAccount === null);
-    document.getElementById(selector + "DeleteAccount").hidden = (selectedAccount === null);
-    document.getElementById(selector + "DisableAccount").hidden = (selectedAccount === null) || !isEnabled || !isInstalled;
-    document.getElementById(selector + "EnableAccount").hidden = (selectedAccount === null) || isEnabled || !isInstalled;
-    document.getElementById(selector + "SyncAccount").hidden = (selectedAccount === null) || !isConnected || !isInstalled;
-    document.getElementById(selector + "RetryConnectAccount").hidden = (selectedAccount === null) || isConnected || !isEnabled || !isInstalled;
-
-    if (document.getElementById(selector + "ShowEventLog")) {
-      document.getElementById(selector + "ShowEventLog").hidden = false;
-      document.getElementById(selector + "ShowEventLog").disabled = false;
-    }
-    
-    if (selectedAccount !== null) {
-      //disable if currently syncing (and displayed)
-      document.getElementById(selector + "DeleteAccount").disabled = isSyncing;
-      document.getElementById(selector + "DisableAccount").disabled = isSyncing;
-      document.getElementById(selector + "EnableAccount").disabled = isSyncing;
-      document.getElementById(selector + "SyncAccount").disabled = isSyncing;
-      //adjust labels - only in global actions dropdown
-      if (isActionsDropdown) document.getElementById(selector + "DeleteAccount").label = TbSync.getString("accountacctions.delete").replace("##accountname##", selectedAccountName);
-      if (isActionsDropdown) document.getElementById(selector + "SyncAccount").label = TbSync.getString("accountacctions.sync").replace("##accountname##", selectedAccountName);
-      if (isActionsDropdown) document.getElementById(selector + "EnableAccount").label = TbSync.getString("accountacctions.enable").replace("##accountname##", selectedAccountName);
-      if (isActionsDropdown) document.getElementById(selector + "DisableAccount").label = TbSync.getString("accountacctions.disable").replace("##accountname##", selectedAccountName);
-    }
-  },
-  
-  synchronizeAccount: function () {
-    let accountsList = document.getElementById("tbSyncAccounts.accounts");
-    if (accountsList.selectedItem !== null && !isNaN(accountsList.selectedItem.value)  && !TbSync.core.isSyncing(accountsList.selectedItem.value)) {            
-      if (tbSyncAccounts.hasInstalledProvider(accountsList.selectedItem.value)) {
-        TbSync.core.syncAccount(accountsList.selectedItem.value);
-      }
-    }
-  },
-
-  deleteAccount: function () {
-    let accountsList = document.getElementById("tbSyncAccounts.accounts");
-    if (accountsList.selectedItem !== null && !isNaN(accountsList.selectedItem.value)  && !TbSync.core.isSyncing(accountsList.selectedItem.value)) {
-      let nextAccount =  -1;
-      if (accountsList.selectedIndex > 0) {
-        //first try to select the item after this one, otherwise take the one before
-        if (accountsList.selectedIndex + 1 < accountsList.getRowCount()) nextAccount = accountsList.getItemAtIndex(accountsList.selectedIndex + 1).value;
-        else nextAccount = accountsList.getItemAtIndex(accountsList.selectedIndex - 1).value;
-      }
-      
-      if (!tbSyncAccounts.hasInstalledProvider(accountsList.selectedItem.value)) {
-        if (confirm(TbSync.getString("prompt.Erase").replace("##accountName##", accountsList.selectedItem.getAttribute("label")))) {
-          //delete account and all folders from db
-          TbSync.db.removeAccount(accountsList.selectedItem.value);
-          //update list
-          this.updateAccountsList(nextAccount);
-        } 
-      } else if (confirm(TbSync.getString("prompt.DeleteAccount").replace("##accountName##", accountsList.selectedItem.getAttribute("label")))) {
-        //cache all folders and remove associated targets 
-        TbSync.core.disableAccount(accountsList.selectedItem.value);
-        
-        // the following call might fail, as not all providers provide that method, it was mainly added to cleanup stored passwords
-        try  {
-          let accountData = new TbSync.AccountData(accountsList.selectedItem.value);
-          TbSync.providers[accountData.getAccountProperty("provider")].Base.onDeleteAccount(accountData);
-        } catch (e) {                Components.utils.reportError(e);}
-
-        //delete account and all folders from db
-        TbSync.db.removeAccount(accountsList.selectedItem.value);
-        //update list
-        this.updateAccountsList(nextAccount);
-      }
-    }
-  },
-
-
-
-  /* * *
-  * Observer to catch update list request (upon provider load/unload)
-  */
-  updateAccountsListObserver: {
-    observe: function (aSubject, aTopic, aData) {
-      //aData is the accountID to be selected
-      //if missing, it will try to not change selection
-      tbSyncAccounts.updateAccountsList(aData); 
-    }
-  },
-  
-  updateProviderListObserver: {
-    observe: function (aSubject, aTopic, aData) {
-      //aData is a provider
-      tbSyncAccounts.updateAvailableProvider(aData); 
-    }
-  },    
-
-  toggleEnableState: function () {
-    let accountsList = document.getElementById("tbSyncAccounts.accounts");
-    
-    if (accountsList.selectedItem !== null && !isNaN(accountsList.selectedItem.value) && !TbSync.core.isSyncing(accountsList.selectedItem.value)) {            
-      let isConnected = TbSync.core.isConnected(accountsList.selectedItem.value);
-      if (!isConnected || window.confirm(TbSync.getString("prompt.Disable"))) {           
-        tbSyncAccounts.toggleAccountEnableState(accountsList.selectedItem.value);
-      }
-    }
-  },
-
-  /* * *
-  * Observer to catch enable state toggle
-  */
-  toggleEnableStateObserver: {
-    observe: function (aSubject, aTopic, aData) {
-      tbSyncAccounts.toggleAccountEnableState(aData);
-    }
-  },
-  
-  //is not prompting, this is doing the actual toggle
-  toggleAccountEnableState: function (accountID) {
-    if (tbSyncAccounts.hasInstalledProvider(accountID)) {
-      let isEnabled = TbSync.core.isEnabled(accountID);
-      
-      if (isEnabled) {
-        //we are enabled and want to disable (do not ask, if not connected)
-        TbSync.core.disableAccount(accountID);
-        Services.obs.notifyObservers(null, "tbsync.observer.manager.updateAccountSettingsGui", accountID);
-        tbSyncAccounts.updateAccountStatus(accountID);
-      } else {
-        //we are disabled and want to enabled
-        TbSync.core.enableAccount(accountID);
-        Services.obs.notifyObservers(null, "tbsync.observer.manager.updateAccountSettingsGui", accountID);
-        TbSync.core.syncAccount(accountID);
-      }
-    }
-  },
-
-  /* * *
-  * Observer to catch synstate changes and to update account icons
-  */
-  updateAccountSyncStateObserver: {
-    observe: function (aSubject, aTopic, aData) {
-      if (aData) {
-        //since we want rotating arrows on each syncstate change, we need to run this on each syncstate
-        tbSyncAccounts.updateAccountStatus(aData);
-      }
-    }
-  },
-
-  setStatusImage: function (accountID, obj) {
-    let statusImage = this.getStatusImage(accountID, obj.src);
-    if (statusImage != obj.src) {
-      obj.src = statusImage;
-    }
-  },
-  
-  getStatusImage: function (accountID, current = "") {
-    let src = "";   
-
-    if (!tbSyncAccounts.hasInstalledProvider(accountID)) {
-      src = "error16.png";
-    } else {
-      switch (TbSync.db.getAccountProperty(accountID, "status").split(".")[0]) {
-        case "success":
-          src = "tick16.png";
-          break;
-        
-        case "disabled":
-          src = "disabled16.png";
-          break;
-        
-        case "info":
-        case "notsyncronized":
-        case "modified":
-          src = "info16.png";
-          break;
-
-        case "warning":
-          src = "warning16.png";
-          break;
-
-        case "syncing":
-          switch (current.replace("chrome://tbsync/content/skin/","")) {
-            case "sync16_1.png": 
-              src = "sync16_2.png"; 
-              break;
-            case "sync16_2.png": 
-              src = "sync16_3.png"; 
-              break;
-            case "sync16_3.png": 
-              src = "sync16_4.png"; 
-              break;
-            case "sync16_4.png": 
-              src = "sync16_1.png"; 
-              break;
-            default: 
-              src = "sync16_1.png";
-              TbSync.core.getSyncDataObject(accountID).accountManagerLastUpdated = 0;
-              break;
-          }                
-          if ((Date.now() - TbSync.core.getSyncDataObject(accountID).accountManagerLastUpdated) < 300) {
-            return current;
-          }
-          TbSync.core.getSyncDataObject(accountID).accountManagerLastUpdated = Date.now();
-          break;
-
-        default:
-          src = "error16.png";
-      }
-    }
-    
-    return "chrome://tbsync/content/skin/" + src;
-  },
-
-  updateAccountLogo: function (id) {
-    let accountData = new TbSync.AccountData(id);
-    let listItem = document.getElementById("tbSyncAccounts.accounts." + id);
-    if (listItem) {
-      let obj = listItem.childNodes[0];
-      obj.src = tbSyncAccounts.hasInstalledProvider(id) ? TbSync.providers[accountData.getAccountProperty("provider")].Base.getProviderIcon(16, accountData) : "chrome://tbsync/content/skin/provider16.png";
-    }
-  },
-
-  updateAccountStatus: function (id) {
-    let listItem = document.getElementById("tbSyncAccounts.accounts." + id);
-    if (listItem) {
-      let obj = listItem.childNodes[2];
-      this.setStatusImage(id, obj);
-    }
-  },
-
-  updateAccountNameObserver: {
-    observe: function (aSubject, aTopic, aData) {
-      let pos = aData.indexOf(":");
-      let id = aData.substring(0, pos);
-      let name = aData.substring(pos+1);
-      tbSyncAccounts.updateAccountName (id, name);
-    }
-  },
-
-  updateAccountName: function (id, name) {
-    let listItem = document.getElementById("tbSyncAccounts.accounts." + id);
-    if (listItem.childNodes[1].getAttribute("value") != name) {
-      listItem.childNodes[1].setAttribute("value", name);
-    }
-  },
-  
-  updateAvailableProvider: function (provider = null) {        
-    //either add/remove a specific provider, or rebuild the list from scratch
-    if (provider) {
-      //update single provider entry
-      tbSyncAccounts.updateAddMenuEntry(provider);
-    } else {
-      //add default providers
-      for (let provider in TbSync.providers.defaultProviders) {
-        tbSyncAccounts.updateAddMenuEntry(provider);
-      }
-      //update/add all remaining installed providers
-      for (let provider in TbSync.providers.loadedProviders) {
-        tbSyncAccounts.updateAddMenuEntry(provider);
-      }
-    }
-    
-    this.updateAccountsList();
-    
-    let selectedAccount = this.getSelectedAccount();
-    if (selectedAccount !== null && TbSync.db.getAccountProperty(selectedAccount, "provider") == provider) {
-      tbSyncAccounts.loadSelectedAccount();
-    }
-  },
-  
-  updateAccountsList: function (accountToSelect = null) {
-    let accountsList = document.getElementById("tbSyncAccounts.accounts");
-    let accounts = TbSync.db.getAccounts();
-
-    // try to keep the currently selected account, if accountToSelect is not given
-    if (accountToSelect === null) {
-      let s = accountsList.getItemAtIndex(accountsList.selectedIndex);
-      if (s) {
-        // there is an entry selected, do not change it
-        accountToSelect = s.value;
-      }
-    }
-    
-    if (accounts.allIDs.length > null) {
-
-      //get current accounts in list and remove entries of accounts no longer there
-      let listedAccounts = [];
-      for (let i=accountsList.getRowCount()-1; i>=0; i--) {
-        let item = accountsList.getItemAtIndex(i);
-        listedAccounts.push(item.value);
-        if (accounts.allIDs.indexOf(item.value) == -1) {
-          item.remove();
-        }
-      }
-
-      //accounts array is without order, extract keys (ids) and loop over keys
-      for (let i = 0; i < accounts.allIDs.length; i++) {
-
-        if (listedAccounts.indexOf(accounts.allIDs[i]) == -1) {
-          //add all missing accounts (always to the end of the list)
-          let newListItem = document.createXULElement("richlistitem");
-          newListItem.setAttribute("id", "tbSyncAccounts.accounts." + accounts.allIDs[i]);
-          newListItem.setAttribute("value", accounts.allIDs[i]);
-          newListItem.setAttribute("align", "center");
-          newListItem.setAttribute("label", accounts.data[accounts.allIDs[i]].accountname);
-          newListItem.setAttribute("style", "padding: 5px 0px;");
-          newListItem.setAttribute("ondblclick", "tbSyncAccounts.toggleEnableState();");
-          
-          //add icon (use "install provider" icon, if provider not installed)
-          let itemType = document.createXULElement("image");
-          //itemType.setAttribute("width", "16");
-          //itemType.setAttribute("height", "16");
-          itemType.setAttribute("style", "margin: 0px 0px 0px 5px; width:16px; height:16px");
-          newListItem.appendChild(itemType);
-
-          //add account name
-          let itemLabel = document.createXULElement("label");
-          itemLabel.setAttribute("flex", "1");
-          newListItem.appendChild(itemLabel);
-
-          //add account status
-          let itemStatus = document.createXULElement("image");
-          //itemStatus.setAttribute("width", "16");
-          //itemStatus.setAttribute("height", "16");
-          itemStatus.setAttribute("style", "margin: 0px 5px; width:16px; height:16px");
-          newListItem.appendChild(itemStatus);
-          
-          accountsList.appendChild(newListItem);
-        } 
-        
-        //update/set actual values
-        this.updateAccountName(accounts.allIDs[i], accounts.data[accounts.allIDs[i]].accountname);
-        this.updateAccountStatus(accounts.allIDs[i]);
-        this.updateAccountLogo(accounts.allIDs[i]);
-      }
-      
-      //find selected item
-      for (let i=0; i<accountsList.getRowCount(); i++) {
-        if (accountToSelect === null || accountToSelect == accountsList.getItemAtIndex(i).value) {
-          accountsList.selectedIndex = i;
-          accountsList.ensureIndexIsVisible(i);
-          break;
-        }
-      }
-
-    } else {
-      //No defined accounts, empty accounts list and load dummy
-      for (let i=accountsList.getRowCount()-1; i>=0; i--) {
-        accountsList.getItemAtIndex(i).remove();
-      }
-      document.getElementById("tbSyncAccounts.contentFrame").setAttribute("src", "chrome://tbsync/content/manager/noaccounts.xhtml");
-    }
-  },
-
-  updateAddMenuEntry: function (provider) {
-    let isDefault = TbSync.providers.defaultProviders.hasOwnProperty(provider);
-    let isInstalled = TbSync.providers.loadedProviders.hasOwnProperty(provider);
-    
-    let entry = document.getElementById("addMenuEntry_" + provider);
-    if (entry === null) {
-      //add basic menu entry
-      let newItem = window.document.createXULElement("menuitem");
-      newItem.setAttribute("id", "addMenuEntry_" + provider);
-      newItem.setAttribute("value",  provider);
-      newItem.setAttribute("class", "menuitem-iconic");
-      newItem.addEventListener("click", function () {tbSyncAccounts.addAccountAction(provider)}, false);
-      newItem.setAttribute("hidden", true);
-      entry = window.document.getElementById("accountActionsAddAccount").appendChild(newItem);
-    }
-    
-    //Update label, icon and hidden according to isDefault and isInstalled
-    if (isInstalled) {
-      entry.setAttribute("label",  TbSync.providers[provider].Base.getProviderName());
-      entry.setAttribute("image", TbSync.providers[provider].Base.getProviderIcon(16));
-      entry.setAttribute("hidden", false);
-    } else if (isDefault) {
-      entry.setAttribute("label", TbSync.providers.defaultProviders[provider].name);
-      entry.setAttribute("image", "chrome://tbsync/content/skin/provider16.png");                    
-      entry.setAttribute("hidden", false);
-    } else {
-      entry.setAttribute("hidden", true);
-    }
-  },
-
-  getSelectedAccount: function () {
-    let accountsList = document.getElementById("tbSyncAccounts.accounts");
-    if (accountsList.selectedItem !== null && !isNaN(accountsList.selectedItem.value)) {
-      //get id of selected account from value of selectedItem
-      return accountsList.selectedItem.value;
-    }
-    return null;
-  },
-  
-  //load the pref page for the currently selected account (triggered by onSelect)
-  loadSelectedAccount: function () {
-    let selectedAccount = this.getSelectedAccount();
-    
-    if (selectedAccount !== null) { //account id could be 0, so need to check for null explicitly
-      let provider = TbSync.db.getAccountProperty(selectedAccount, "provider");            
-      if (tbSyncAccounts.hasInstalledProvider(selectedAccount)) {
-        document.getElementById("tbSyncAccounts.contentFrame").setAttribute("src", "chrome://tbsync/content/manager/editAccount.xhtml?provider="+provider+"&id=" + selectedAccount);
-      } else {
-        document.getElementById("tbSyncAccounts.contentFrame").setAttribute("src", "chrome://tbsync/content/manager/missingProvider.xhtml?provider="+provider);
-      }
-    }
-  },
-  
-
-
-
-  addAccountAction: function (provider) {
-    let isDefault = TbSync.providers.defaultProviders.hasOwnProperty(provider);
-    let isInstalled = TbSync.providers.loadedProviders.hasOwnProperty(provider);
-    
-    if (isInstalled) {
-      tbSyncAccounts.addAccount(provider);
-    } else if (isDefault) {
-      tbSyncAccounts.installProvider(provider);
-    }
-  },
-  
-  addAccount: function (provider) {
-    TbSync.providers.loadedProviders[provider].createAccountWindow = window.openDialog(TbSync.providers[provider].Base.getCreateAccountWindowUrl(), "TbSyncNewAccountWindow", "centerscreen,resizable=no");
-    TbSync.providers.loadedProviders[provider].createAccountWindow.addEventListener("unload", function () { TbSync.manager.prefWindowObj.focus(); });
-  },
-
-  installProvider: function (provider) {
-    for (let i=0; i<TbSync.AccountManagerTabs.length; i++) {            
-       TbSync.manager.prefWindowObj.document.getElementById("tbSyncAccountManager.t" + i).setAttribute("active","false");
-    }
-    TbSync.manager.prefWindowObj.document.getElementById("tbSyncAccountManager.installProvider").hidden=false;
-    TbSync.manager.prefWindowObj.document.getElementById("tbSyncAccountManager.installProvider").setAttribute("active","true");
-    TbSync.manager.prefWindowObj.document.getElementById("tbSyncAccountManager.contentWindow").setAttribute("src", "chrome://tbsync/content/manager/installProvider.xhtml?provider="+provider);        
-  },
-      
-};
+/*
+ * This file is part of TbSync.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. 
+ */
+ 
+"use strict";
+
+var { ExtensionParent } = ChromeUtils.importESModule(
+  "resource://gre/modules/ExtensionParent.sys.mjs"
+);
+
+var tbsyncExtension = ExtensionParent.GlobalManager.getExtension(
+  "tbsync at jobisoft.de"
+);
+var { TbSync } = ChromeUtils.importESModule(
+  `chrome://tbsync/content/tbsync.sys.mjs?${tbsyncExtension.manifest.version}`
+);
+
+var tbSyncAccounts = {
+
+  selectedAccount: null,
+
+  onload: function () {
+    //scan accounts, update list and select first entry (because no id is passed to updateAccountList)
+    //the onSelect event of the List will load the selected account
+    //also update/init add menu
+    this.updateAvailableProvider(); 
+    
+    Services.obs.addObserver(tbSyncAccounts.updateProviderListObserver, "tbsync.observer.manager.updateProviderList", false);
+    Services.obs.addObserver(tbSyncAccounts.updateAccountsListObserver, "tbsync.observer.manager.updateAccountsList", false);
+    Services.obs.addObserver(tbSyncAccounts.updateAccountSyncStateObserver, "tbsync.observer.manager.updateSyncstate", false);
+    Services.obs.addObserver(tbSyncAccounts.updateAccountNameObserver, "tbsync.observer.manager.updateAccountName", false);
+    Services.obs.addObserver(tbSyncAccounts.toggleEnableStateObserver, "tbsync.observer.manager.toggleEnableState", false);
+  },
+
+  onunload: function () {
+    Services.obs.removeObserver(tbSyncAccounts.updateProviderListObserver, "tbsync.observer.manager.updateProviderList");
+    Services.obs.removeObserver(tbSyncAccounts.updateAccountsListObserver, "tbsync.observer.manager.updateAccountsList");
+    Services.obs.removeObserver(tbSyncAccounts.updateAccountSyncStateObserver, "tbsync.observer.manager.updateSyncstate");
+    Services.obs.removeObserver(tbSyncAccounts.updateAccountNameObserver, "tbsync.observer.manager.updateAccountName");
+    Services.obs.removeObserver(tbSyncAccounts.toggleEnableStateObserver, "tbsync.observer.manager.toggleEnableState");
+  },       
+  
+  hasInstalledProvider: function (accountID) {
+    let provider = TbSync.db.getAccountProperty(accountID, "provider");
+    return TbSync.providers.loadedProviders.hasOwnProperty(provider);
+  },
+
+  updateDropdown: function (selector) {
+    let accountsList = document.getElementById("tbSyncAccounts.accounts");
+    let selectedAccount = null;
+    let selectedAccountName = "";
+    let isActionsDropdown = (selector == "accountActions");
+
+    let isSyncing = false;
+    let isConnected = false;
+    let isEnabled = false;
+    let isInstalled = false;
+    
+    if (accountsList.selectedItem !== null && !isNaN(accountsList.selectedItem.value)) {
+      //some item is selected
+      let selectedItem = accountsList.selectedItem;
+      selectedAccount = selectedItem.value;
+      selectedAccountName = selectedItem.childNodes[1].getAttribute("value");
+      isSyncing = TbSync.core.isSyncing(selectedAccount);
+      isConnected = TbSync.core.isConnected(selectedAccount);
+      isEnabled = TbSync.core.isEnabled(selectedAccount);
+      isInstalled = tbSyncAccounts.hasInstalledProvider(selectedAccount);
+    }
+
+    //hide if no accounts are avail (which is identical to no account selected)
+    if (isActionsDropdown) document.getElementById(selector + "SyncAllAccounts").hidden = (selectedAccount === null);
+    
+    //hide if no account is selected
+    if (isActionsDropdown) document.getElementById(selector + "Separator").hidden = (selectedAccount === null);
+    document.getElementById(selector + "DeleteAccount").hidden = (selectedAccount === null);
+    document.getElementById(selector + "DisableAccount").hidden = (selectedAccount === null) || !isEnabled || !isInstalled;
+    document.getElementById(selector + "EnableAccount").hidden = (selectedAccount === null) || isEnabled || !isInstalled;
+    document.getElementById(selector + "SyncAccount").hidden = (selectedAccount === null) || !isConnected || !isInstalled;
+    document.getElementById(selector + "RetryConnectAccount").hidden = (selectedAccount === null) || isConnected || !isEnabled || !isInstalled;
+
+    if (document.getElementById(selector + "ShowEventLog")) {
+      document.getElementById(selector + "ShowEventLog").hidden = false;
+      document.getElementById(selector + "ShowEventLog").disabled = false;
+    }
+    
+    if (selectedAccount !== null) {
+      //disable if currently syncing (and displayed)
+      document.getElementById(selector + "DeleteAccount").disabled = isSyncing;
+      document.getElementById(selector + "DisableAccount").disabled = isSyncing;
+      document.getElementById(selector + "EnableAccount").disabled = isSyncing;
+      document.getElementById(selector + "SyncAccount").disabled = isSyncing;
+      //adjust labels - only in global actions dropdown
+      if (isActionsDropdown) document.getElementById(selector + "DeleteAccount").label = TbSync.getString("accountacctions.delete").replace("##accountname##", selectedAccountName);
+      if (isActionsDropdown) document.getElementById(selector + "SyncAccount").label = TbSync.getString("accountacctions.sync").replace("##accountname##", selectedAccountName);
+      if (isActionsDropdown) document.getElementById(selector + "EnableAccount").label = TbSync.getString("accountacctions.enable").replace("##accountname##", selectedAccountName);
+      if (isActionsDropdown) document.getElementById(selector + "DisableAccount").label = TbSync.getString("accountacctions.disable").replace("##accountname##", selectedAccountName);
+    }
+  },
+  
+  synchronizeAccount: function () {
+    let accountsList = document.getElementById("tbSyncAccounts.accounts");
+    if (accountsList.selectedItem !== null && !isNaN(accountsList.selectedItem.value)  && !TbSync.core.isSyncing(accountsList.selectedItem.value)) {            
+      if (tbSyncAccounts.hasInstalledProvider(accountsList.selectedItem.value)) {
+        TbSync.core.syncAccount(accountsList.selectedItem.value);
+      }
+    }
+  },
+
+  deleteAccount: function () {
+    let accountsList = document.getElementById("tbSyncAccounts.accounts");
+    if (accountsList.selectedItem !== null && !isNaN(accountsList.selectedItem.value)  && !TbSync.core.isSyncing(accountsList.selectedItem.value)) {
+      let nextAccount =  -1;
+      if (accountsList.selectedIndex > 0) {
+        //first try to select the item after this one, otherwise take the one before
+        if (accountsList.selectedIndex + 1 < accountsList.getRowCount()) nextAccount = accountsList.getItemAtIndex(accountsList.selectedIndex + 1).value;
+        else nextAccount = accountsList.getItemAtIndex(accountsList.selectedIndex - 1).value;
+      }
+      
+      if (!tbSyncAccounts.hasInstalledProvider(accountsList.selectedItem.value)) {
+        if (confirm(TbSync.getString("prompt.Erase").replace("##accountName##", accountsList.selectedItem.getAttribute("label")))) {
+          //delete account and all folders from db
+          TbSync.db.removeAccount(accountsList.selectedItem.value);
+          //update list
+          this.updateAccountsList(nextAccount);
+        } 
+      } else if (confirm(TbSync.getString("prompt.DeleteAccount").replace("##accountName##", accountsList.selectedItem.getAttribute("label")))) {
+        //cache all folders and remove associated targets 
+        TbSync.core.disableAccount(accountsList.selectedItem.value);
+        
+        // the following call might fail, as not all providers provide that method, it was mainly added to cleanup stored passwords
+        try  {
+          let accountData = new TbSync.AccountData(accountsList.selectedItem.value);
+          TbSync.providers[accountData.getAccountProperty("provider")].Base.onDeleteAccount(accountData);
+        } catch (e) {                Components.utils.reportError(e);}
+
+        //delete account and all folders from db
+        TbSync.db.removeAccount(accountsList.selectedItem.value);
+        //update list
+        this.updateAccountsList(nextAccount);
+      }
+    }
+  },
+
+
+
+  /* * *
+  * Observer to catch update list request (upon provider load/unload)
+  */
+  updateAccountsListObserver: {
+    observe: function (aSubject, aTopic, aData) {
+      //aData is the accountID to be selected
+      //if missing, it will try to not change selection
+      tbSyncAccounts.updateAccountsList(aData); 
+    }
+  },
+  
+  updateProviderListObserver: {
+    observe: function (aSubject, aTopic, aData) {
+      //aData is a provider
+      tbSyncAccounts.updateAvailableProvider(aData); 
+    }
+  },    
+
+  toggleEnableState: function () {
+    let accountsList = document.getElementById("tbSyncAccounts.accounts");
+    
+    if (accountsList.selectedItem !== null && !isNaN(accountsList.selectedItem.value) && !TbSync.core.isSyncing(accountsList.selectedItem.value)) {            
+      let isConnected = TbSync.core.isConnected(accountsList.selectedItem.value);
+      if (!isConnected || window.confirm(TbSync.getString("prompt.Disable"))) {           
+        tbSyncAccounts.toggleAccountEnableState(accountsList.selectedItem.value);
+      }
+    }
+  },
+
+  /* * *
+  * Observer to catch enable state toggle
+  */
+  toggleEnableStateObserver: {
+    observe: function (aSubject, aTopic, aData) {
+      tbSyncAccounts.toggleAccountEnableState(aData);
+    }
+  },
+  
+  //is not prompting, this is doing the actual toggle
+  toggleAccountEnableState: function (accountID) {
+    if (tbSyncAccounts.hasInstalledProvider(accountID)) {
+      let isEnabled = TbSync.core.isEnabled(accountID);
+      
+      if (isEnabled) {
+        //we are enabled and want to disable (do not ask, if not connected)
+        TbSync.core.disableAccount(accountID);
+        Services.obs.notifyObservers(null, "tbsync.observer.manager.updateAccountSettingsGui", accountID);
+        tbSyncAccounts.updateAccountStatus(accountID);
+      } else {
+        //we are disabled and want to enabled
+        TbSync.core.enableAccount(accountID);
+        Services.obs.notifyObservers(null, "tbsync.observer.manager.updateAccountSettingsGui", accountID);
+        TbSync.core.syncAccount(accountID);
+      }
+    }
+  },
+
+  /* * *
+  * Observer to catch synstate changes and to update account icons
+  */
+  updateAccountSyncStateObserver: {
+    observe: function (aSubject, aTopic, aData) {
+      if (aData) {
+        //since we want rotating arrows on each syncstate change, we need to run this on each syncstate
+        tbSyncAccounts.updateAccountStatus(aData);
+      }
+    }
+  },
+
+  setStatusImage: function (accountID, obj) {
+    let statusImage = this.getStatusImage(accountID, obj.src);
+    if (statusImage != obj.src) {
+      obj.src = statusImage;
+    }
+  },
+  
+  getStatusImage: function (accountID, current = "") {
+    let src = "";   
+
+    if (!tbSyncAccounts.hasInstalledProvider(accountID)) {
+      src = "error16.png";
+    } else {
+      switch (TbSync.db.getAccountProperty(accountID, "status").split(".")[0]) {
+        case "success":
+          src = "tick16.png";
+          break;
+        
+        case "disabled":
+          src = "disabled16.png";
+          break;
+        
+        case "info":
+        case "notsyncronized":
+        case "modified":
+          src = "info16.png";
+          break;
+
+        case "warning":
+          src = "warning16.png";
+          break;
+
+        case "syncing":
+          switch (current.replace("chrome://tbsync/content/skin/","")) {
+            case "sync16_1.png": 
+              src = "sync16_2.png"; 
+              break;
+            case "sync16_2.png": 
+              src = "sync16_3.png"; 
+              break;
+            case "sync16_3.png": 
+              src = "sync16_4.png"; 
+              break;
+            case "sync16_4.png": 
+              src = "sync16_1.png"; 
+              break;
+            default: 
+              src = "sync16_1.png";
+              TbSync.core.getSyncDataObject(accountID).accountManagerLastUpdated = 0;
+              break;
+          }                
+          if ((Date.now() - TbSync.core.getSyncDataObject(accountID).accountManagerLastUpdated) < 300) {
+            return current;
+          }
+          TbSync.core.getSyncDataObject(accountID).accountManagerLastUpdated = Date.now();
+          break;
+
+        default:
+          src = "error16.png";
+      }
+    }
+    
+    return "chrome://tbsync/content/skin/" + src;
+  },
+
+  updateAccountLogo: function (id) {
+    let accountData = new TbSync.AccountData(id);
+    let listItem = document.getElementById("tbSyncAccounts.accounts." + id);
+    if (listItem) {
+      let obj = listItem.childNodes[0];
+      obj.src = tbSyncAccounts.hasInstalledProvider(id) ? TbSync.providers[accountData.getAccountProperty("provider")].Base.getProviderIcon(16, accountData) : "chrome://tbsync/content/skin/provider16.png";
+    }
+  },
+
+  updateAccountStatus: function (id) {
+    let listItem = document.getElementById("tbSyncAccounts.accounts." + id);
+    if (listItem) {
+      let obj = listItem.childNodes[2];
+      this.setStatusImage(id, obj);
+    }
+  },
+
+  updateAccountNameObserver: {
+    observe: function (aSubject, aTopic, aData) {
+      let pos = aData.indexOf(":");
+      let id = aData.substring(0, pos);
+      let name = aData.substring(pos+1);
+      tbSyncAccounts.updateAccountName (id, name);
+    }
+  },
+
+  updateAccountName: function (id, name) {
+    let listItem = document.getElementById("tbSyncAccounts.accounts." + id);
+    if (listItem.childNodes[1].getAttribute("value") != name) {
+      listItem.childNodes[1].setAttribute("value", name);
+    }
+  },
+  
+  updateAvailableProvider: function (provider = null) {        
+    //either add/remove a specific provider, or rebuild the list from scratch
+    if (provider) {
+      //update single provider entry
+      tbSyncAccounts.updateAddMenuEntry(provider);
+    } else {
+      //add default providers
+      for (let provider in TbSync.providers.defaultProviders) {
+        tbSyncAccounts.updateAddMenuEntry(provider);
+      }
+      //update/add all remaining installed providers
+      for (let provider in TbSync.providers.loadedProviders) {
+        tbSyncAccounts.updateAddMenuEntry(provider);
+      }
+    }
+    
+    this.updateAccountsList();
+    
+    let selectedAccount = this.getSelectedAccount();
+    if (selectedAccount !== null && TbSync.db.getAccountProperty(selectedAccount, "provider") == provider) {
+      tbSyncAccounts.loadSelectedAccount();
+    }
+  },
+  
+  updateAccountsList: function (accountToSelect = null) {
+    let accountsList = document.getElementById("tbSyncAccounts.accounts");
+    let accounts = TbSync.db.getAccounts();
+
+    // try to keep the currently selected account, if accountToSelect is not given
+    if (accountToSelect === null) {
+      let s = accountsList.getItemAtIndex(accountsList.selectedIndex);
+      if (s) {
+        // there is an entry selected, do not change it
+        accountToSelect = s.value;
+      }
+    }
+    
+    if (accounts.allIDs.length > null) {
+
+      //get current accounts in list and remove entries of accounts no longer there
+      let listedAccounts = [];
+      for (let i=accountsList.getRowCount()-1; i>=0; i--) {
+        let item = accountsList.getItemAtIndex(i);
+        listedAccounts.push(item.value);
+        if (accounts.allIDs.indexOf(item.value) == -1) {
+          item.remove();
+        }
+      }
+
+      //accounts array is without order, extract keys (ids) and loop over keys
+      for (let i = 0; i < accounts.allIDs.length; i++) {
+
+        if (listedAccounts.indexOf(accounts.allIDs[i]) == -1) {
+          //add all missing accounts (always to the end of the list)
+          let newListItem = document.createXULElement("richlistitem");
+          newListItem.setAttribute("id", "tbSyncAccounts.accounts." + accounts.allIDs[i]);
+          newListItem.setAttribute("value", accounts.allIDs[i]);
+          newListItem.setAttribute("align", "center");
+          newListItem.setAttribute("label", accounts.data[accounts.allIDs[i]].accountname);
+          newListItem.setAttribute("style", "padding: 5px 0px;");
+          newListItem.setAttribute("ondblclick", "tbSyncAccounts.toggleEnableState();");
+          
+          //add icon (use "install provider" icon, if provider not installed)
+          let itemType = document.createXULElement("image");
+          //itemType.setAttribute("width", "16");
+          //itemType.setAttribute("height", "16");
+          itemType.setAttribute("style", "margin: 0px 0px 0px 5px; width:16px; height:16px");
+          newListItem.appendChild(itemType);
+
+          //add account name
+          let itemLabel = document.createXULElement("label");
+          itemLabel.setAttribute("flex", "1");
+          newListItem.appendChild(itemLabel);
+
+          //add account status
+          let itemStatus = document.createXULElement("image");
+          //itemStatus.setAttribute("width", "16");
+          //itemStatus.setAttribute("height", "16");
+          itemStatus.setAttribute("style", "margin: 0px 5px; width:16px; height:16px");
+          newListItem.appendChild(itemStatus);
+          
+          accountsList.appendChild(newListItem);
+        } 
+        
+        //update/set actual values
+        this.updateAccountName(accounts.allIDs[i], accounts.data[accounts.allIDs[i]].accountname);
+        this.updateAccountStatus(accounts.allIDs[i]);
+        this.updateAccountLogo(accounts.allIDs[i]);
+      }
+      
+      //find selected item
+      for (let i=0; i<accountsList.getRowCount(); i++) {
+        if (accountToSelect === null || accountToSelect == accountsList.getItemAtIndex(i).value) {
+          accountsList.selectedIndex = i;
+          accountsList.ensureIndexIsVisible(i);
+          break;
+        }
+      }
+
+    } else {
+      //No defined accounts, empty accounts list and load dummy
+      for (let i=accountsList.getRowCount()-1; i>=0; i--) {
+        accountsList.getItemAtIndex(i).remove();
+      }
+      document.getElementById("tbSyncAccounts.contentFrame").setAttribute("src", "chrome://tbsync/content/manager/noaccounts.xhtml");
+    }
+  },
+
+  updateAddMenuEntry: function (provider) {
+    let isDefault = TbSync.providers.defaultProviders.hasOwnProperty(provider);
+    let isInstalled = TbSync.providers.loadedProviders.hasOwnProperty(provider);
+    
+    let entry = document.getElementById("addMenuEntry_" + provider);
+    if (entry === null) {
+      //add basic menu entry
+      let newItem = window.document.createXULElement("menuitem");
+      newItem.setAttribute("id", "addMenuEntry_" + provider);
+      newItem.setAttribute("value",  provider);
+      newItem.setAttribute("class", "menuitem-iconic");
+      newItem.addEventListener("click", function () {tbSyncAccounts.addAccountAction(provider)}, false);
+      newItem.setAttribute("hidden", true);
+      entry = window.document.getElementById("accountActionsAddAccount").appendChild(newItem);
+    }
+    
+    //Update label, icon and hidden according to isDefault and isInstalled
+    if (isInstalled) {
+      entry.setAttribute("label",  TbSync.providers[provider].Base.getProviderName());
+      entry.setAttribute("image", TbSync.providers[provider].Base.getProviderIcon(16));
+      entry.setAttribute("hidden", false);
+    } else if (isDefault) {
+      entry.setAttribute("label", TbSync.providers.defaultProviders[provider].name);
+      entry.setAttribute("image", "chrome://tbsync/content/skin/provider16.png");                    
+      entry.setAttribute("hidden", false);
+    } else {
+      entry.setAttribute("hidden", true);
+    }
+  },
+
+  getSelectedAccount: function () {
+    let accountsList = document.getElementById("tbSyncAccounts.accounts");
+    if (accountsList.selectedItem !== null && !isNaN(accountsList.selectedItem.value)) {
+      //get id of selected account from value of selectedItem
+      return accountsList.selectedItem.value;
+    }
+    return null;
+  },
+  
+  //load the pref page for the currently selected account (triggered by onSelect)
+  loadSelectedAccount: function () {
+    let selectedAccount = this.getSelectedAccount();
+    
+    if (selectedAccount !== null) { //account id could be 0, so need to check for null explicitly
+      let provider = TbSync.db.getAccountProperty(selectedAccount, "provider");            
+      if (tbSyncAccounts.hasInstalledProvider(selectedAccount)) {
+        document.getElementById("tbSyncAccounts.contentFrame").setAttribute("src", "chrome://tbsync/content/manager/editAccount.xhtml?provider="+provider+"&id=" + selectedAccount);
+      } else {
+        document.getElementById("tbSyncAccounts.contentFrame").setAttribute("src", "chrome://tbsync/content/manager/missingProvider.xhtml?provider="+provider);
+      }
+    }
+  },
+  
+
+
+
+  addAccountAction: function (provider) {
+    let isDefault = TbSync.providers.defaultProviders.hasOwnProperty(provider);
+    let isInstalled = TbSync.providers.loadedProviders.hasOwnProperty(provider);
+    
+    if (isInstalled) {
+      tbSyncAccounts.addAccount(provider);
+    } else if (isDefault) {
+      tbSyncAccounts.installProvider(provider);
+    }
+  },
+  
+  addAccount: function (provider) {
+    TbSync.providers.loadedProviders[provider].createAccountWindow = window.openDialog(TbSync.providers[provider].Base.getCreateAccountWindowUrl(), "TbSyncNewAccountWindow", "centerscreen,resizable=no");
+    TbSync.providers.loadedProviders[provider].createAccountWindow.addEventListener("unload", function () { TbSync.manager.prefWindowObj.focus(); });
+  },
+
+  installProvider: function (provider) {
+    for (let i=0; i<TbSync.AccountManagerTabs.length; i++) {            
+       TbSync.manager.prefWindowObj.document.getElementById("tbSyncAccountManager.t" + i).setAttribute("active","false");
+    }
+    TbSync.manager.prefWindowObj.document.getElementById("tbSyncAccountManager.installProvider").hidden=false;
+    TbSync.manager.prefWindowObj.document.getElementById("tbSyncAccountManager.installProvider").setAttribute("active","true");
+    TbSync.manager.prefWindowObj.document.getElementById("tbSyncAccountManager.contentWindow").setAttribute("src", "chrome://tbsync/content/manager/installProvider.xhtml?provider="+provider);        
+  },
+      
+};
diff -Nru tbsync-4.12/content/manager/accounts.xhtml tbsync-4.16/content/manager/accounts.xhtml
--- tbsync-4.12/content/manager/accounts.xhtml	2024-08-27 18:32:08.000000000 +0200
+++ tbsync-4.16/content/manager/accounts.xhtml	2024-08-18 13:03:30.000000000 +0200
@@ -1,119 +1,119 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<?xml-stylesheet href="chrome://global/skin/global.css" type="text/css"?>
-<?xml-stylesheet href="chrome://tbsync/content/manager/manager.css" type="text/css"?>
-
-<window
-    xmlns:html="http://www.w3.org/1999/xhtml"
-    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
-    xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
-    onload="tbSyncAccounts.onload();"
-    onunload="tbSyncAccounts.onunload();"
-    title="TbSync Account Settings" >
-
-    <popupset>
-        <menupopup id="tbsync.accountmanger.ContextMenu" onpopupshowing="tbSyncAccounts.updateDropdown('contextMenu');">
-            <menuitem id="contextMenuRetryConnectAccount" 
-                    class="menuitem-iconic"
-                    image="chrome://tbsync/content/skin/connect16.png"
-                    label="__TBSYNCMSG_manager.RetryConnectAccount__" 
-                    oncommand="tbSyncAccounts.synchronizeAccount();"/>
-            <menuitem id="contextMenuSyncAccount" 
-                    class="menuitem-iconic"
-                    image="chrome://tbsync/content/skin/sync16.png"
-                    label="__TBSYNCMSG_manager.SynchronizeAccount__" 
-                    oncommand="tbSyncAccounts.synchronizeAccount();"/>
-            <menuitem id="contextMenuEnableAccount" 
-                    class="menuitem-iconic"
-                    image="chrome://tbsync/content/skin/connect16.png"
-                    label="__TBSYNCMSG_manager.EnableAccount__" 
-                    oncommand="tbSyncAccounts.toggleEnableState();"/>
-            <menuitem id="contextMenuDisableAccount" 
-                    class="menuitem-iconic"
-                    image="chrome://tbsync/content/skin/disabled16.png"
-                    label="__TBSYNCMSG_manager.DisableAccount__" 
-                    oncommand="tbSyncAccounts.toggleEnableState();"/>
-            <menuitem id="contextMenuDeleteAccount"
-                    class="menuitem-iconic"
-                    image="chrome://tbsync/content/skin/del16.png"
-                    label="__TBSYNCMSG_manager.DeleteAccount__"
-                    oncommand="tbSyncAccounts.deleteAccount();"/>
-        </menupopup>
-    </popupset>
-    
-    <hbox flex="1">
-        <vbox width="200">
-            <richlistbox 
-                id="tbSyncAccounts.accounts"
-                flex="1"
-                style="margin: 0 1px; width: 200px;"
-                seltype="single"
-                context="tbsync.accountmanger.ContextMenu"
-                onkeypress="if (event.keyCode == 46) {tbSyncAccounts.deleteAccount();}"
-                onselect="tbSyncAccounts.loadSelectedAccount();">
-                <listheader style="border-bottom: 1px solid lightgrey;">
-                    <treecol style="font-weight:bold;" label="" width="26" flex="0" />
-                    <treecol style="font-weight:bold;" label="__TBSYNCMSG_manager.accounts__" flex="1" />
-                    <treecol style="font-weight:bold;text-align:right;" label="__TBSYNCMSG_manager.status__" flex="0" />
-                </listheader>
-            </richlistbox>
-            <hbox style="margin:1ex 0 0 0">
-             <vbox style="margin:0" flex="1">
-                <button 
-                id="tbSyncAccounts.btnAccountActions"
-                label="__TBSYNCMSG_manager.AccountActions__"
-                style="margin:0"
-                type="menu">
-                        <menupopup id="accountActionsDropdown" onpopupshowing="tbSyncAccounts.updateDropdown('accountActions');">
-                            <menu
-                                class="menu-iconic"
-                                image="chrome://tbsync/content/skin/add16.png"
-                                label="__TBSYNCMSG_manager.AddAccount__">
-                                        <menupopup id="accountActionsAddAccount" />
-                            </menu>
-                            <menuitem id="accountActionsSyncAllAccounts"
-                                    class="menuitem-iconic"
-                                    image="chrome://tbsync/content/skin/sync16.png"
-                                    label="__TBSYNCMSG_manager.SyncAll__"
-                                    oncommand="TbSync.core.syncAllAccounts();"/>
-                            <menuitem id="accountActionsShowEventLog"
-                                    class="menuitem-iconic"
-                                    image="chrome://tbsync/content/skin/warning16.png"
-                                    label="__TBSYNCMSG_manager.ShowEventLog__"
-                                    oncommand="TbSync.eventlog.open()"/>
-                            <menuseparator id="accountActionsSeparator"/>
-                            <menuitem id="accountActionsDeleteAccount"
-                                    class="menuitem-iconic"
-                                    image="chrome://tbsync/content/skin/del16.png"
-                                    label="__TBSYNCMSG_manager.DeleteAccount__"
-                                    oncommand="tbSyncAccounts.deleteAccount();"/>
-                            <menuitem id="accountActionsDisableAccount" 
-                                    class="menuitem-iconic"
-                                    image="chrome://tbsync/content/skin/disabled16.png"
-                                    label="__TBSYNCMSG_manager.DisableAccount__" 
-                                    oncommand="tbSyncAccounts.toggleEnableState();"/>
-                            <menuitem id="accountActionsEnableAccount" 
-                                    class="menuitem-iconic"
-                                    image="chrome://tbsync/content/skin/connect16.png"
-                                    label="__TBSYNCMSG_manager.EnableAccount__" 
-                                    oncommand="tbSyncAccounts.toggleEnableState();"/>
-                            <menuitem id="accountActionsSyncAccount" 
-                                    class="menuitem-iconic"
-                                    image="chrome://tbsync/content/skin/sync16.png"
-                                    label="__TBSYNCMSG_manager.SynchronizeAccount__" 
-                                    oncommand="tbSyncAccounts.synchronizeAccount();"/>
-                            <menuitem id="accountActionsRetryConnectAccount" 
-                                    class="menuitem-iconic"
-                                    image="chrome://tbsync/content/skin/connect16.png"
-                                    label="__TBSYNCMSG_manager.RetryConnectAccount__" 
-                                    oncommand="tbSyncAccounts.synchronizeAccount();"/>                                    
-                        </menupopup>
-                </button>
-             </vbox>
-            </hbox>
-        </vbox>
-        <browser id="tbSyncAccounts.contentFrame" type="chrome" src="" disablehistory="true" flex="1"  style="margin-left:12px;"/>	
-    </hbox>
-
-    <script type="text/javascript" src="chrome://tbsync/content/manager/accounts.js" /> 
-    <script type="text/javascript" src="chrome://tbsync/content/scripts/locales.js" /> 
-</window>
+<?xml version="1.0" encoding="UTF-8"?>
+<?xml-stylesheet href="chrome://global/skin/global.css" type="text/css"?>
+<?xml-stylesheet href="chrome://tbsync/content/manager/manager.css" type="text/css"?>
+
+<window
+    xmlns:html="http://www.w3.org/1999/xhtml"
+    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+    xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+    onload="tbSyncAccounts.onload();"
+    onunload="tbSyncAccounts.onunload();"
+    title="TbSync Account Settings" >
+
+    <popupset>
+        <menupopup id="tbsync.accountmanger.ContextMenu" onpopupshowing="tbSyncAccounts.updateDropdown('contextMenu');">
+            <menuitem id="contextMenuRetryConnectAccount" 
+                    class="menuitem-iconic"
+                    image="chrome://tbsync/content/skin/connect16.png"
+                    label="__TBSYNCMSG_manager.RetryConnectAccount__" 
+                    oncommand="tbSyncAccounts.synchronizeAccount();"/>
+            <menuitem id="contextMenuSyncAccount" 
+                    class="menuitem-iconic"
+                    image="chrome://tbsync/content/skin/sync16.png"
+                    label="__TBSYNCMSG_manager.SynchronizeAccount__" 
+                    oncommand="tbSyncAccounts.synchronizeAccount();"/>
+            <menuitem id="contextMenuEnableAccount" 
+                    class="menuitem-iconic"
+                    image="chrome://tbsync/content/skin/connect16.png"
+                    label="__TBSYNCMSG_manager.EnableAccount__" 
+                    oncommand="tbSyncAccounts.toggleEnableState();"/>
+            <menuitem id="contextMenuDisableAccount" 
+                    class="menuitem-iconic"
+                    image="chrome://tbsync/content/skin/disabled16.png"
+                    label="__TBSYNCMSG_manager.DisableAccount__" 
+                    oncommand="tbSyncAccounts.toggleEnableState();"/>
+            <menuitem id="contextMenuDeleteAccount"
+                    class="menuitem-iconic"
+                    image="chrome://tbsync/content/skin/del16.png"
+                    label="__TBSYNCMSG_manager.DeleteAccount__"
+                    oncommand="tbSyncAccounts.deleteAccount();"/>
+        </menupopup>
+    </popupset>
+    
+    <hbox flex="1">
+        <vbox width="200">
+            <richlistbox 
+                id="tbSyncAccounts.accounts"
+                flex="1"
+                style="margin: 0 1px; width: 200px;"
+                seltype="single"
+                context="tbsync.accountmanger.ContextMenu"
+                onkeypress="if (event.keyCode == 46) {tbSyncAccounts.deleteAccount();}"
+                onselect="tbSyncAccounts.loadSelectedAccount();">
+                <listheader style="border-bottom: 1px solid lightgrey;">
+                    <treecol style="font-weight:bold;" label="" width="26" flex="0" />
+                    <treecol style="font-weight:bold;" label="__TBSYNCMSG_manager.accounts__" flex="1" />
+                    <treecol style="font-weight:bold;text-align:right;" label="__TBSYNCMSG_manager.status__" flex="0" />
+                </listheader>
+            </richlistbox>
+            <hbox style="margin:1ex 0 0 0">
+             <vbox style="margin:0" flex="1">
+                <button 
+                id="tbSyncAccounts.btnAccountActions"
+                label="__TBSYNCMSG_manager.AccountActions__"
+                style="margin:0"
+                type="menu">
+                        <menupopup id="accountActionsDropdown" onpopupshowing="tbSyncAccounts.updateDropdown('accountActions');">
+                            <menu
+                                class="menu-iconic"
+                                image="chrome://tbsync/content/skin/add16.png"
+                                label="__TBSYNCMSG_manager.AddAccount__">
+                                        <menupopup id="accountActionsAddAccount" />
+                            </menu>
+                            <menuitem id="accountActionsSyncAllAccounts"
+                                    class="menuitem-iconic"
+                                    image="chrome://tbsync/content/skin/sync16.png"
+                                    label="__TBSYNCMSG_manager.SyncAll__"
+                                    oncommand="TbSync.core.syncAllAccounts();"/>
+                            <menuitem id="accountActionsShowEventLog"
+                                    class="menuitem-iconic"
+                                    image="chrome://tbsync/content/skin/warning16.png"
+                                    label="__TBSYNCMSG_manager.ShowEventLog__"
+                                    oncommand="TbSync.eventlog.open()"/>
+                            <menuseparator id="accountActionsSeparator"/>
+                            <menuitem id="accountActionsDeleteAccount"
+                                    class="menuitem-iconic"
+                                    image="chrome://tbsync/content/skin/del16.png"
+                                    label="__TBSYNCMSG_manager.DeleteAccount__"
+                                    oncommand="tbSyncAccounts.deleteAccount();"/>
+                            <menuitem id="accountActionsDisableAccount" 
+                                    class="menuitem-iconic"
+                                    image="chrome://tbsync/content/skin/disabled16.png"
+                                    label="__TBSYNCMSG_manager.DisableAccount__" 
+                                    oncommand="tbSyncAccounts.toggleEnableState();"/>
+                            <menuitem id="accountActionsEnableAccount" 
+                                    class="menuitem-iconic"
+                                    image="chrome://tbsync/content/skin/connect16.png"
+                                    label="__TBSYNCMSG_manager.EnableAccount__" 
+                                    oncommand="tbSyncAccounts.toggleEnableState();"/>
+                            <menuitem id="accountActionsSyncAccount" 
+                                    class="menuitem-iconic"
+                                    image="chrome://tbsync/content/skin/sync16.png"
+                                    label="__TBSYNCMSG_manager.SynchronizeAccount__" 
+                                    oncommand="tbSyncAccounts.synchronizeAccount();"/>
+                            <menuitem id="accountActionsRetryConnectAccount" 
+                                    class="menuitem-iconic"
+                                    image="chrome://tbsync/content/skin/connect16.png"
+                                    label="__TBSYNCMSG_manager.RetryConnectAccount__" 
+                                    oncommand="tbSyncAccounts.synchronizeAccount();"/>                                    
+                        </menupopup>
+                </button>
+             </vbox>
+            </hbox>
+        </vbox>
+        <browser id="tbSyncAccounts.contentFrame" type="chrome" src="" disablehistory="true" flex="1"  style="margin-left:12px;"/>	
+    </hbox>
+
+    <script type="text/javascript" src="chrome://tbsync/content/manager/accounts.js" /> 
+    <script type="text/javascript" src="chrome://tbsync/content/scripts/locales.js" /> 
+</window>
diff -Nru tbsync-4.12/content/manager/addonoptions.xhtml tbsync-4.16/content/manager/addonoptions.xhtml
--- tbsync-4.12/content/manager/addonoptions.xhtml	2024-08-27 18:32:08.000000000 +0200
+++ tbsync-4.16/content/manager/addonoptions.xhtml	1970-01-01 01:00:00.000000000 +0100
@@ -1,15 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<?xml-stylesheet href="chrome://tbsync/content/manager/manager.css" type="text/css"?>
-
-<window
-    xmlns:html="http://www.w3.org/1999/xhtml"
-    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
-    xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
-    title="__TBSYNCMSG_manager.title__" 
-    onload="tbSyncAccountManager.onloadoptions();"
-    onunload="tbSyncAccountManager.onunloadoptions();"
-    width="180" height="80" >
-    
-    <script type="text/javascript" src="chrome://tbsync/content/manager/accountManager.js" /> 
-    <script type="text/javascript" src="chrome://tbsync/content/scripts/locales.js" /> 
-</window>
diff -Nru tbsync-4.12/content/manager/catman.xhtml tbsync-4.16/content/manager/catman.xhtml
--- tbsync-4.12/content/manager/catman.xhtml	2024-08-27 18:32:08.000000000 +0200
+++ tbsync-4.16/content/manager/catman.xhtml	2021-08-30 18:31:42.000000000 +0200
@@ -1,25 +1,25 @@
-<?xml version="1.0" encoding="utf-8"?>
-<?xml-stylesheet href="chrome://global/skin/global.css" type="text/css"?>
-<?xml-stylesheet href="chrome://tbsync/content/manager/manager.css" type="text/css"?>
-
-<window
-    xmlns:html="http://www.w3.org/1999/xhtml"
-    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
-    xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
-    title="Category Manager" >
-
-    <hbox flex="1" id="mainframe">
-        <vbox flex="1">
-            <html:p>
-                __TBSYNCMSG_manager.catman.text__
-            </html:p>
-            
-            <html:p onmouseover="this.style.cursor='pointer'" onmouseout="this.style.cursor='default'" onclick="TbSync.manager.openLink('https://addons.thunderbird.net/addon/categorymanager/');" style="color:blue;text-decoration: underline;padding-left:1em;">
-              https://addons.thunderbird.net/addon/categorymanager/
-            </html:p>
-        </vbox>
-    </hbox>
-    
-    <script type="text/javascript" src="chrome://tbsync/content/manager/accountManager.js" /> 
-    <script type="text/javascript" src="chrome://tbsync/content/scripts/locales.js" /> 
-</window>
+<?xml version="1.0" encoding="utf-8"?>
+<?xml-stylesheet href="chrome://global/skin/global.css" type="text/css"?>
+<?xml-stylesheet href="chrome://tbsync/content/manager/manager.css" type="text/css"?>
+
+<window
+    xmlns:html="http://www.w3.org/1999/xhtml"
+    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+    xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+    title="Category Manager" >
+
+    <hbox flex="1" id="mainframe">
+        <vbox flex="1">
+            <html:p>
+                __TBSYNCMSG_manager.catman.text__
+            </html:p>
+            
+            <html:p onmouseover="this.style.cursor='pointer'" onmouseout="this.style.cursor='default'" onclick="TbSync.manager.openLink('https://addons.thunderbird.net/addon/categorymanager/');" style="color:blue;text-decoration: underline;padding-left:1em;">
+              https://addons.thunderbird.net/addon/categorymanager/
+            </html:p>
+        </vbox>
+    </hbox>
+    
+    <script type="text/javascript" src="chrome://tbsync/content/manager/accountManager.js" /> 
+    <script type="text/javascript" src="chrome://tbsync/content/scripts/locales.js" /> 
+</window>
diff -Nru tbsync-4.12/content/manager/editAccount.js tbsync-4.16/content/manager/editAccount.js
--- tbsync-4.12/content/manager/editAccount.js	2024-08-27 18:32:08.000000000 +0200
+++ tbsync-4.16/content/manager/editAccount.js	2025-03-15 23:49:58.000000000 +0100
@@ -1,390 +1,399 @@
-/*
- * This file is part of TbSync.
- *
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. 
- */
- 
-"use strict";
-
-var { TbSync } = ChromeUtils.import("chrome://tbsync/content/tbsync.jsm");
-
-var tbSyncAccountSettings = {
-
-  accountID: null,
-  provider: null,
-  settings: null,
-  updateTimer: Components.classes["@mozilla.org/timer;1"].createInstance(Components.interfaces.nsITimer),
-
-  updateFolderListObserver: {
-    observe: function (aSubject, aTopic, aData) {
-      //only run if is request for this account and main frame is visible
-      let accountID = aData;            
-      if (accountID == tbSyncAccountSettings.accountID && !document.getElementById('tbsync.accountsettings.frame').hidden) {
-        //make sure, folderlist is visible, otherwise our updates will be discarded (may cause errors)
-        tbSyncAccountSettings.updateFolderList();
-        tbSyncAccountSettings.updateGui();
-      }
-    }
-  },
-
-  reloadAccountSettingObserver: {
-    observe: function (aSubject, aTopic, aData) {
-      //only run if is request for this account and main frame is visible
-      let data = JSON.parse(aData);
-      if (data.accountID == tbSyncAccountSettings.accountID && !document.getElementById('tbsync.accountsettings.frame').hidden) {
-        tbSyncAccountSettings.reloadSetting(data.setting);
-      }
-    }
-  },
-
-  updateGuiObserver: {
-    observe: function (aSubject, aTopic, aData) {
-      //only run if is request for this account and main frame is visible
-      let accountID = aData;            
-      if (accountID == tbSyncAccountSettings.accountID && !document.getElementById('tbsync.accountsettings.frame').hidden) {
-        tbSyncAccountSettings.updateGui();
-      }
-    }
-  },
-
-  updateSyncstateObserver: {
-    observe: function (aSubject, aTopic, aData) {
-      //only run if is request for this account and main frame is visible
-      let accountID = aData;            
-      if (accountID == tbSyncAccountSettings.accountID && !document.getElementById('tbsync.accountsettings.frame').hidden) {
-        let syncstate = TbSync.core.getSyncDataObject(accountID).getSyncState().state;
-        if (syncstate == "accountdone") {
-          tbSyncAccountSettings.updateGui();
-        } else {
-          tbSyncAccountSettings.updateSyncstate();
-        }
-      }
-    }
-  },
-
-  onload: function () {
-    //load observers
-    Services.obs.addObserver(tbSyncAccountSettings.updateFolderListObserver, "tbsync.observer.manager.updateFolderList", false);
-    Services.obs.addObserver(tbSyncAccountSettings.updateGuiObserver, "tbsync.observer.manager.updateAccountSettingsGui", false);
-    Services.obs.addObserver(tbSyncAccountSettings.reloadAccountSettingObserver, "tbsync.observer.manager.reloadAccountSetting", false);
-    Services.obs.addObserver(tbSyncAccountSettings.updateSyncstateObserver, "tbsync.observer.manager.updateSyncstate", false);
-    //get the selected account from the loaded URI
-    tbSyncAccountSettings.accountID = window.location.toString().split("id=")[1];
-    tbSyncAccountSettings.accountData = new TbSync.AccountData(tbSyncAccountSettings.accountID);
-
-    //get information for that acount
-    tbSyncAccountSettings.provider = TbSync.db.getAccountProperty(tbSyncAccountSettings.accountID, "provider");
-    tbSyncAccountSettings.settings = Object.keys(TbSync.providers.getDefaultAccountEntries(tbSyncAccountSettings.provider)).sort();
-
-    //add header to folderlist
-    let header = TbSync.providers[tbSyncAccountSettings.provider].folderList.getHeader();
-    let folderlistHeader = window.document.getElementById('tbsync.accountsettings.folderlist.header');
-    for (let h=0; h < header.length; h++) {
-      let listheader = window.document.createXULElement("treecol");
-      for (let a in header[h]) {
-        if (header[h].hasOwnProperty(a)) {
-          listheader.setAttribute(a, header[h][a]);
-        }
-      }
-      folderlistHeader.appendChild(listheader);
-    }        
-    
-    //load overlays from the provider (if any)
-    TbSync.messenger.overlayManager.injectAllOverlays(window, "chrome://tbsync/content/manager/editAccount.xhtml?provider=" + tbSyncAccountSettings.provider);
-    if (window.tbSyncEditAccountOverlay && window.tbSyncEditAccountOverlay.hasOwnProperty("onload")) {
-      tbSyncEditAccountOverlay.onload(window, new TbSync.AccountData(tbSyncAccountSettings.accountID));
-    }
-    tbSyncAccountSettings.loadSettings();
-    
-    //done, folderlist must be updated while visible
-    document.getElementById('tbsync.accountsettings.frame').hidden = false;	    
-    tbSyncAccountSettings.updateFolderList();      
-
-    if (Services.appinfo.OS == "Darwin") { //we might need to find a way to detect MacOS like styling, other themes move the header bar into the tabpanel as well
-      document.getElementById('manager.tabpanels').style["padding-top"] = "3ex";
-    }
-  },
-
-
-  onunload: function () {
-    tbSyncAccountSettings.updateTimer.cancel();
-    if (!document.getElementById('tbsync.accountsettings.frame').hidden) {
-      Services.obs.removeObserver(tbSyncAccountSettings.updateFolderListObserver, "tbsync.observer.manager.updateFolderList");
-      Services.obs.removeObserver(tbSyncAccountSettings.updateGuiObserver, "tbsync.observer.manager.updateAccountSettingsGui");
-      Services.obs.removeObserver(tbSyncAccountSettings.reloadAccountSettingObserver, "tbsync.observer.manager.reloadAccountSetting");
-      Services.obs.removeObserver(tbSyncAccountSettings.updateSyncstateObserver, "tbsync.observer.manager.updateSyncstate");
-    }
-  },
-  
-
-   folderListVisible: function () {
-    let box = document.getElementById('tbsync.accountsettings.folderlist').getBoundingClientRect();
-    let visible = box.width && box.height;
-    return visible;
-  },
-  
-
-  reloadSetting: function (setting) {
-    let pref = document.getElementById("tbsync.accountsettings.pref." + setting);
-    let label = document.getElementById("tbsync.accountsettings.label." + setting);
-
-    if (pref) {
-      //is this a checkbox?
-      if ((pref.tagName == "checkbox") || ((pref.tagName == "input") && (pref.type == "checkbox"))) {
-        //BOOL
-        if (TbSync.db.getAccountProperty(tbSyncAccountSettings.accountID, setting)) pref.setAttribute("checked", true);
-        else pref.removeAttribute("checked");
-      } else {
-        //Not BOOL
-        pref.value = TbSync.db.getAccountProperty(tbSyncAccountSettings.accountID, setting);
-      }
-    }    
-  },
-
-
-  /**
-   * Run through all defined TbSync settings and if there is a corresponding
-   * field in the settings dialog, fill it with the stored value.
-   */
-  loadSettings: function () {
-    for (let i=0; i < tbSyncAccountSettings.settings.length; i++) {
-      let pref = document.getElementById("tbsync.accountsettings.pref." + tbSyncAccountSettings.settings[i]);
-      let label = document.getElementById("tbsync.accountsettings.label." + tbSyncAccountSettings.settings[i]);
-
-      if (pref) {
-        //is this a checkbox?
-        let event = "blur";
-        if ((pref.tagName == "checkbox") || ((pref.tagName == "input") && (pref.type == "checkbox"))) {
-          //BOOL
-          if (TbSync.db.getAccountProperty(tbSyncAccountSettings.accountID, tbSyncAccountSettings.settings[i])) pref.setAttribute("checked", true);
-          else pref.removeAttribute("checked");
-          event = "command";
-        } else {
-          //Not BOOL
-          if (pref.tagName == "menulist") {
-            pref.value = TbSync.db.getAccountProperty(tbSyncAccountSettings.accountID, tbSyncAccountSettings.settings[i]);
-            event = "command";
-          } else {
-            pref.setAttribute("value", TbSync.db.getAccountProperty(tbSyncAccountSettings.accountID, tbSyncAccountSettings.settings[i]));
-          }
-        }
-        
-        pref.addEventListener(event, function() {tbSyncAccountSettings.instantSaveSetting(this)});
-      }
-    }
-    
-    tbSyncAccountSettings.updateGui();        
-  },
-
-  updateGui: function () {
-    let status = TbSync.db.getAccountProperty(tbSyncAccountSettings.accountID, "status");
-
-    let isConnected = TbSync.core.isConnected(tbSyncAccountSettings.accountID);
-    let isEnabled = TbSync.core.isEnabled(tbSyncAccountSettings.accountID);      
-    let isSyncing = TbSync.core.isSyncing(tbSyncAccountSettings.accountID);
-    
-    { //disable settings if connected or syncing
-      let items = document.getElementsByClassName("lockIfConnected");
-      for (let i=0; i < items.length; i++) {
-        if (isConnected || isSyncing || items[i].getAttribute("alwaysDisabled") == "true") {
-          items[i].setAttribute("disabled", true);
-          items[i].style["color"] =  "darkgrey";            
-        } else {
-          items[i].removeAttribute("disabled");
-          items[i].style["color"] = "black";
-        }                    
-      }
-    }
-
-    document.getElementById('tbsync.accountsettings.connectbtn.container').hidden = !(isEnabled && !isConnected && !isSyncing); 
-    //currently we use a fixed button which is hidden during sync
-    //document.getElementById('tbsync.accountsettings.connectbtn').label = TbSync.getString("manager." + (isSyncing ? "connecting" : "tryagain"));
-    
-    { //show elements if connected (this also hides/unhides the folderlist)
-      let items = document.getElementsByClassName("showIfConnected");
-      for (let i=0; i < items.length; i++) {
-        items[i].hidden = !isConnected;    
-      }
-    }
-
-    { //show elements if enabled
-      let items = document.getElementsByClassName("showIfEnabled");
-      for (let i=0; i < items.length; i++) {
-        items[i].hidden = !isEnabled;    
-      }
-    }
-    
-    document.getElementById('tbsync.accountsettings.enabled').checked = isEnabled;
-    document.getElementById('tbsync.accountsettings.enabled').disabled = isSyncing;
-    document.getElementById('tbsync.accountsettings.folderlist').disabled = isSyncing;
-    document.getElementById('tbsync.accountsettings.syncbtn').disabled = isSyncing;
-    document.getElementById('tbsync.accountsettings.connectbtn').disabled = isSyncing;
-  
-    tbSyncAccountSettings.updateSyncstate();
-  
-    //change color of syncstate according to status
-    let showEventLogButton = false;
-    switch (status) {
-      case "success":
-      case "disabled":
-      case "syncing":
-        document.getElementById("syncstate").removeAttribute("style");
-        break;
-      
-      case "notsyncronized":
-        document.getElementById("syncstate").setAttribute("style","color: red");
-        break;
-      
-      default:
-        document.getElementById("syncstate").setAttribute("style","color: red");
-        showEventLogButton = TbSync.eventlog.get(tbSyncAccountSettings.accountID).length > 0;
-    }
-    document.getElementById('tbsync.accountsettings.eventlogbtn').hidden = !showEventLogButton;
-  },
-
-  updateSyncstate: function () {
-    tbSyncAccountSettings.updateTimer.cancel();
-
-    // if this account is beeing synced, display syncstate, otherwise print status
-    let status = TbSync.db.getAccountProperty(tbSyncAccountSettings.accountID, "status");
-    let isSyncing = TbSync.core.isSyncing(tbSyncAccountSettings.accountID);
-    let isConnected = TbSync.core.isConnected(tbSyncAccountSettings.accountID);
-    let isEnabled = TbSync.core.isEnabled(tbSyncAccountSettings.accountID);
-    let syncdata = TbSync.core.getSyncDataObject(tbSyncAccountSettings.accountID);
-
-    if (isSyncing) {
-      let accounts = TbSync.db.getAccounts().data;
-      
-      let s = syncdata.getSyncState();
-      let syncstate = s.state;
-      let synctime = s.timestamp;
-
-      let msg = TbSync.getString("syncstate." + syncstate, tbSyncAccountSettings.provider);
-    
-      if (syncstate.split(".")[0] == "send") {
-        // append timeout countdown
-        let diff = Date.now() - synctime;
-        if (diff > 2000) msg = msg + " (" + Math.round((TbSync.providers[tbSyncAccountSettings.provider].Base.getConnectionTimeout(tbSyncAccountSettings.accountData) - diff)/1000) + "s)";
-        // re-schedule update, if this is a waiting syncstate
-        tbSyncAccountSettings.updateTimer.init(tbSyncAccountSettings.updateSyncstate, 1000, 0);
-      }            
-      document.getElementById("syncstate").textContent = msg;
-    } else {
-      let localized = TbSync.getString("status." + (isEnabled ? status : "disabled"), tbSyncAccountSettings.provider);
-      document.getElementById("syncstate").textContent = localized;
-    }
-        
-    
-    if (tbSyncAccountSettings.folderListVisible()) {
-      //update syncstates of folders in folderlist, if visible - remove obsolete entries while we are here
-      let folderData = TbSync.providers[tbSyncAccountSettings.provider].Base.getSortedFolders(tbSyncAccountSettings.accountData);
-      let folderList = document.getElementById("tbsync.accountsettings.folderlist");
-
-      for (let i=folderList.getRowCount()-1; i>=0; i--) {
-        let item = folderList.getItemAtIndex(i);
-        if (folderData.filter(f => f.folderID == item.folderData.folderID).length == 0) {
-          item.remove();
-        } else {
-          TbSync.providers[tbSyncAccountSettings.provider].folderList.updateRow(document, item, item.folderData);
-        }
-      }
-    }
-  },
-
-  updateFolderList: function () {
-    //get updated list of folderIDs
-    let folderData = TbSync.providers[tbSyncAccountSettings.provider].Base.getSortedFolders(tbSyncAccountSettings.accountData);
-    
-    //remove entries from folderlist, which no longer exists and build reference array with  current elements
-    let folderList = document.getElementById("tbsync.accountsettings.folderlist");
-    folderList.hidden=true;
-
-    let foldersElements = {};
-    for (let i=folderList.getRowCount()-1; i>=0; i--) {
-      if (folderData.filter(f => f.folderID == folderList.getItemAtIndex(i).folderData.folderID).length == 0) {
-        folderList.getItemAtIndex(i).remove();
-      } else {
-        foldersElements[folderList.getItemAtIndex(i).folderData.folderID] = folderList.getItemAtIndex(i);
-      }
-    }
-
-    //update folderlist
-    for (let i=0; i < folderData.length; i++) {
-      let nextItem = null;
-      
-      //if this entry does not exist, create it
-      if (foldersElements.hasOwnProperty(folderData[i].folderID)) {
-        //get reference to current element
-        nextItem = foldersElements[folderData[i].folderID];
-      } else {
-        //add new entry, attach FolderData of this folder as folderData
-        nextItem = document.createXULElement("richlistitem");
-        nextItem.folderData = folderData[i];
-        
-        //add row
-        nextItem.appendChild(TbSync.providers[tbSyncAccountSettings.provider].folderList.getRow(document, folderData[i]));
-      }
-
-      //add/move row and update its content
-      let addedItem = folderList.appendChild(nextItem);
-      TbSync.providers[tbSyncAccountSettings.provider].folderList.updateRow(document, addedItem, folderData[i]);
-
-      //ensureElementIsVisible also forces internal update of rowCount, which sometimes is not updated automatically upon appendChild
-      folderList.ensureElementIsVisible(addedItem);
-    }
-    folderList.hidden = false;
-  },
-
-
-
-
-
-  instantSaveSetting: function (field) {
-    let setting = field.id.replace("tbsync.accountsettings.pref.","");
-    let value = "";
-    
-    if ((field.tagName == "checkbox") || ((field.tagName == "input") && (field.type == "checkbox"))) {
-      if (field.checked) value = true;
-      else value = false;
-    } else {
-      value = field.value;
-    }
-    TbSync.db.setAccountProperty(tbSyncAccountSettings.accountID, setting, value);
-    
-    if (setting == "accountname") {
-      Services.obs.notifyObservers(null, "tbsync.observer.manager.updateAccountName", tbSyncAccountSettings.accountID + ":" + field.value);
-    }
-    TbSync.db.saveAccounts(); //write modified accounts to disk
-  },
-
-  toggleEnableState: function (element) {
-    if (!TbSync.core.isConnected(tbSyncAccountSettings.accountID)) {
-      //if not connected, we can toggle without prompt
-      Services.obs.notifyObservers(null, "tbsync.observer.manager.toggleEnableState", tbSyncAccountSettings.accountID);
-      return;
-    }      
-
-    if (window.confirm(TbSync.getString("prompt.Disable"))) {
-      Services.obs.notifyObservers(null, "tbsync.observer.manager.toggleEnableState", tbSyncAccountSettings.accountID);
-    } else {
-      //invalid, toggle checkbox back
-      element.setAttribute("checked", true);
-    }
-  },
-
-  
-  onFolderListContextMenuShowing: function () {
-    let folderList = document.getElementById("tbsync.accountsettings.folderlist");
-    let aFolderIsSelected = (!folderList.disabled && folderList.selectedItem !== null && folderList.selectedItem.value !== undefined);
-    let menupopup = document.getElementById("tbsync.accountsettings.FolderListContextMenu");
-    
-    if (aFolderIsSelected) {
-      TbSync.providers[tbSyncAccountSettings.provider].folderList.onContextMenuShowing(window, folderList.selectedItem.folderData);
-    } else {
-      TbSync.providers[tbSyncAccountSettings.provider].folderList.onContextMenuShowing(window, null);
-    }
-  },
-
-};
+/*
+ * This file is part of TbSync.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. 
+ */
+ 
+"use strict";
+
+var { ExtensionParent } = ChromeUtils.importESModule(
+  "resource://gre/modules/ExtensionParent.sys.mjs"
+);
+
+var tbsyncExtension = ExtensionParent.GlobalManager.getExtension(
+  "tbsync at jobisoft.de"
+);
+var { TbSync } = ChromeUtils.importESModule(
+  `chrome://tbsync/content/tbsync.sys.mjs?${tbsyncExtension.manifest.version}`
+);
+
+var tbSyncAccountSettings = {
+
+  accountID: null,
+  provider: null,
+  settings: null,
+  updateTimer: Components.classes["@mozilla.org/timer;1"].createInstance(Components.interfaces.nsITimer),
+
+  updateFolderListObserver: {
+    observe: function (aSubject, aTopic, aData) {
+      //only run if is request for this account and main frame is visible
+      let accountID = aData;            
+      if (accountID == tbSyncAccountSettings.accountID && !document.getElementById('tbsync.accountsettings.frame').hidden) {
+        //make sure, folderlist is visible, otherwise our updates will be discarded (may cause errors)
+        tbSyncAccountSettings.updateFolderList();
+        tbSyncAccountSettings.updateGui();
+      }
+    }
+  },
+
+  reloadAccountSettingObserver: {
+    observe: function (aSubject, aTopic, aData) {
+      //only run if is request for this account and main frame is visible
+      let data = JSON.parse(aData);
+      if (data.accountID == tbSyncAccountSettings.accountID && !document.getElementById('tbsync.accountsettings.frame').hidden) {
+        tbSyncAccountSettings.reloadSetting(data.setting);
+      }
+    }
+  },
+
+  updateGuiObserver: {
+    observe: function (aSubject, aTopic, aData) {
+      //only run if is request for this account and main frame is visible
+      let accountID = aData;            
+      if (accountID == tbSyncAccountSettings.accountID && !document.getElementById('tbsync.accountsettings.frame').hidden) {
+        tbSyncAccountSettings.updateGui();
+      }
+    }
+  },
+
+  updateSyncstateObserver: {
+    observe: function (aSubject, aTopic, aData) {
+      //only run if is request for this account and main frame is visible
+      let accountID = aData;            
+      if (accountID == tbSyncAccountSettings.accountID && !document.getElementById('tbsync.accountsettings.frame').hidden) {
+        let syncstate = TbSync.core.getSyncDataObject(accountID).getSyncState().state;
+        if (syncstate == "accountdone") {
+          tbSyncAccountSettings.updateGui();
+        } else {
+          tbSyncAccountSettings.updateSyncstate();
+        }
+      }
+    }
+  },
+
+  onload: function () {
+    //load observers
+    Services.obs.addObserver(tbSyncAccountSettings.updateFolderListObserver, "tbsync.observer.manager.updateFolderList", false);
+    Services.obs.addObserver(tbSyncAccountSettings.updateGuiObserver, "tbsync.observer.manager.updateAccountSettingsGui", false);
+    Services.obs.addObserver(tbSyncAccountSettings.reloadAccountSettingObserver, "tbsync.observer.manager.reloadAccountSetting", false);
+    Services.obs.addObserver(tbSyncAccountSettings.updateSyncstateObserver, "tbsync.observer.manager.updateSyncstate", false);
+    //get the selected account from the loaded URI
+    tbSyncAccountSettings.accountID = window.location.toString().split("id=")[1];
+    tbSyncAccountSettings.accountData = new TbSync.AccountData(tbSyncAccountSettings.accountID);
+
+    //get information for that acount
+    tbSyncAccountSettings.provider = TbSync.db.getAccountProperty(tbSyncAccountSettings.accountID, "provider");
+    tbSyncAccountSettings.settings = Object.keys(TbSync.providers.getDefaultAccountEntries(tbSyncAccountSettings.provider)).sort();
+
+    //add header to folderlist
+    let header = TbSync.providers[tbSyncAccountSettings.provider].folderList.getHeader();
+    let folderlistHeader = window.document.getElementById('tbsync.accountsettings.folderlist.header');
+    for (let h=0; h < header.length; h++) {
+      let listheader = window.document.createXULElement("treecol");
+      for (let a in header[h]) {
+        if (header[h].hasOwnProperty(a)) {
+          listheader.setAttribute(a, header[h][a]);
+        }
+      }
+      folderlistHeader.appendChild(listheader);
+    }        
+    
+    //load overlays from the provider (if any)
+    TbSync.messenger.overlayManager.injectAllOverlays(window, "chrome://tbsync/content/manager/editAccount.xhtml?provider=" + tbSyncAccountSettings.provider);
+    if (window.tbSyncEditAccountOverlay && window.tbSyncEditAccountOverlay.hasOwnProperty("onload")) {
+      tbSyncEditAccountOverlay.onload(window, new TbSync.AccountData(tbSyncAccountSettings.accountID));
+    }
+    tbSyncAccountSettings.loadSettings();
+    
+    //done, folderlist must be updated while visible
+    document.getElementById('tbsync.accountsettings.frame').hidden = false;	    
+    tbSyncAccountSettings.updateFolderList();      
+
+    if (Services.appinfo.OS == "Darwin") { //we might need to find a way to detect MacOS like styling, other themes move the header bar into the tabpanel as well
+      document.getElementById('manager.tabpanels').style["padding-top"] = "3ex";
+    }
+  },
+
+
+  onunload: function () {
+    tbSyncAccountSettings.updateTimer.cancel();
+    if (!document.getElementById('tbsync.accountsettings.frame').hidden) {
+      Services.obs.removeObserver(tbSyncAccountSettings.updateFolderListObserver, "tbsync.observer.manager.updateFolderList");
+      Services.obs.removeObserver(tbSyncAccountSettings.updateGuiObserver, "tbsync.observer.manager.updateAccountSettingsGui");
+      Services.obs.removeObserver(tbSyncAccountSettings.reloadAccountSettingObserver, "tbsync.observer.manager.reloadAccountSetting");
+      Services.obs.removeObserver(tbSyncAccountSettings.updateSyncstateObserver, "tbsync.observer.manager.updateSyncstate");
+    }
+  },
+  
+
+   folderListVisible: function () {
+    let box = document.getElementById('tbsync.accountsettings.folderlist').getBoundingClientRect();
+    let visible = box.width && box.height;
+    return visible;
+  },
+  
+
+  reloadSetting: function (setting) {
+    let pref = document.getElementById("tbsync.accountsettings.pref." + setting);
+    let label = document.getElementById("tbsync.accountsettings.label." + setting);
+
+    if (pref) {
+      //is this a checkbox?
+      if ((pref.tagName == "checkbox") || ((pref.tagName == "input") && (pref.type == "checkbox"))) {
+        //BOOL
+        if (TbSync.db.getAccountProperty(tbSyncAccountSettings.accountID, setting)) pref.setAttribute("checked", true);
+        else pref.removeAttribute("checked");
+      } else {
+        //Not BOOL
+        pref.value = TbSync.db.getAccountProperty(tbSyncAccountSettings.accountID, setting);
+      }
+    }    
+  },
+
+
+  /**
+   * Run through all defined TbSync settings and if there is a corresponding
+   * field in the settings dialog, fill it with the stored value.
+   */
+  loadSettings: function () {
+    for (let i=0; i < tbSyncAccountSettings.settings.length; i++) {
+      let pref = document.getElementById("tbsync.accountsettings.pref." + tbSyncAccountSettings.settings[i]);
+      let label = document.getElementById("tbsync.accountsettings.label." + tbSyncAccountSettings.settings[i]);
+
+      if (pref) {
+        //is this a checkbox?
+        let event = "blur";
+        if ((pref.tagName == "checkbox") || ((pref.tagName == "input") && (pref.type == "checkbox"))) {
+          //BOOL
+          if (TbSync.db.getAccountProperty(tbSyncAccountSettings.accountID, tbSyncAccountSettings.settings[i])) pref.setAttribute("checked", true);
+          else pref.removeAttribute("checked");
+          event = "command";
+        } else {
+          //Not BOOL
+          if (pref.tagName == "menulist") {
+            pref.value = TbSync.db.getAccountProperty(tbSyncAccountSettings.accountID, tbSyncAccountSettings.settings[i]);
+            event = "command";
+          } else {
+            pref.setAttribute("value", TbSync.db.getAccountProperty(tbSyncAccountSettings.accountID, tbSyncAccountSettings.settings[i]));
+          }
+        }
+        
+        pref.addEventListener(event, function() {tbSyncAccountSettings.instantSaveSetting(this)});
+      }
+    }
+    
+    tbSyncAccountSettings.updateGui();        
+  },
+
+  updateGui: function () {
+    let status = TbSync.db.getAccountProperty(tbSyncAccountSettings.accountID, "status");
+
+    let isConnected = TbSync.core.isConnected(tbSyncAccountSettings.accountID);
+    let isEnabled = TbSync.core.isEnabled(tbSyncAccountSettings.accountID);      
+    let isSyncing = TbSync.core.isSyncing(tbSyncAccountSettings.accountID);
+    
+    { //disable settings if connected or syncing
+      let items = document.getElementsByClassName("lockIfConnected");
+      for (let i=0; i < items.length; i++) {
+        if (isConnected || isSyncing || items[i].getAttribute("alwaysDisabled") == "true") {
+          items[i].setAttribute("disabled", true);
+          items[i].style["color"] =  "darkgrey";            
+        } else {
+          items[i].removeAttribute("disabled");
+          items[i].style["color"] = "black";
+        }                    
+      }
+    }
+
+    document.getElementById('tbsync.accountsettings.connectbtn.container').hidden = !(isEnabled && !isConnected && !isSyncing); 
+    //currently we use a fixed button which is hidden during sync
+    //document.getElementById('tbsync.accountsettings.connectbtn').label = TbSync.getString("manager." + (isSyncing ? "connecting" : "tryagain"));
+    
+    { //show elements if connected (this also hides/unhides the folderlist)
+      let items = document.getElementsByClassName("showIfConnected");
+      for (let i=0; i < items.length; i++) {
+        items[i].hidden = !isConnected;    
+      }
+    }
+
+    { //show elements if enabled
+      let items = document.getElementsByClassName("showIfEnabled");
+      for (let i=0; i < items.length; i++) {
+        items[i].hidden = !isEnabled;    
+      }
+    }
+    
+    document.getElementById('tbsync.accountsettings.enabled').checked = isEnabled;
+    document.getElementById('tbsync.accountsettings.enabled').disabled = isSyncing;
+    document.getElementById('tbsync.accountsettings.folderlist').disabled = isSyncing;
+    document.getElementById('tbsync.accountsettings.syncbtn').disabled = isSyncing;
+    document.getElementById('tbsync.accountsettings.connectbtn').disabled = isSyncing;
+  
+    tbSyncAccountSettings.updateSyncstate();
+  
+    //change color of syncstate according to status
+    let showEventLogButton = false;
+    switch (status) {
+      case "success":
+      case "disabled":
+      case "syncing":
+        document.getElementById("syncstate").removeAttribute("style");
+        break;
+      
+      case "notsyncronized":
+        document.getElementById("syncstate").setAttribute("style","color: red");
+        break;
+      
+      default:
+        document.getElementById("syncstate").setAttribute("style","color: red");
+        showEventLogButton = TbSync.eventlog.get(tbSyncAccountSettings.accountID).length > 0;
+    }
+    document.getElementById('tbsync.accountsettings.eventlogbtn').hidden = !showEventLogButton;
+  },
+
+  updateSyncstate: function () {
+    tbSyncAccountSettings.updateTimer.cancel();
+
+    // if this account is beeing synced, display syncstate, otherwise print status
+    let status = TbSync.db.getAccountProperty(tbSyncAccountSettings.accountID, "status");
+    let isSyncing = TbSync.core.isSyncing(tbSyncAccountSettings.accountID);
+    let isConnected = TbSync.core.isConnected(tbSyncAccountSettings.accountID);
+    let isEnabled = TbSync.core.isEnabled(tbSyncAccountSettings.accountID);
+    let syncdata = TbSync.core.getSyncDataObject(tbSyncAccountSettings.accountID);
+
+    if (isSyncing) {
+      let accounts = TbSync.db.getAccounts().data;
+      
+      let s = syncdata.getSyncState();
+      let syncstate = s.state;
+      let synctime = s.timestamp;
+
+      let msg = TbSync.getString("syncstate." + syncstate, tbSyncAccountSettings.provider);
+    
+      if (syncstate.split(".")[0] == "send") {
+        // append timeout countdown
+        let diff = Date.now() - synctime;
+        if (diff > 2000) msg = msg + " (" + Math.round((TbSync.providers[tbSyncAccountSettings.provider].Base.getConnectionTimeout(tbSyncAccountSettings.accountData) - diff)/1000) + "s)";
+        // re-schedule update, if this is a waiting syncstate
+        tbSyncAccountSettings.updateTimer.init(tbSyncAccountSettings.updateSyncstate, 1000, 0);
+      }            
+      document.getElementById("syncstate").textContent = msg;
+    } else {
+      let localized = TbSync.getString("status." + (isEnabled ? status : "disabled"), tbSyncAccountSettings.provider);
+      document.getElementById("syncstate").textContent = localized;
+    }
+        
+    
+    if (tbSyncAccountSettings.folderListVisible()) {
+      //update syncstates of folders in folderlist, if visible - remove obsolete entries while we are here
+      let folderData = TbSync.providers[tbSyncAccountSettings.provider].Base.getSortedFolders(tbSyncAccountSettings.accountData);
+      let folderList = document.getElementById("tbsync.accountsettings.folderlist");
+
+      for (let i=folderList.getRowCount()-1; i>=0; i--) {
+        let item = folderList.getItemAtIndex(i);
+        if (folderData.filter(f => f.folderID == item.folderData.folderID).length == 0) {
+          item.remove();
+        } else {
+          TbSync.providers[tbSyncAccountSettings.provider].folderList.updateRow(document, item, item.folderData);
+        }
+      }
+    }
+  },
+
+  updateFolderList: function () {
+    //get updated list of folderIDs
+    let folderData = TbSync.providers[tbSyncAccountSettings.provider].Base.getSortedFolders(tbSyncAccountSettings.accountData);
+    
+    //remove entries from folderlist, which no longer exists and build reference array with  current elements
+    let folderList = document.getElementById("tbsync.accountsettings.folderlist");
+    folderList.hidden=true;
+
+    let foldersElements = {};
+    for (let i=folderList.getRowCount()-1; i>=0; i--) {
+      if (folderData.filter(f => f.folderID == folderList.getItemAtIndex(i).folderData.folderID).length == 0) {
+        folderList.getItemAtIndex(i).remove();
+      } else {
+        foldersElements[folderList.getItemAtIndex(i).folderData.folderID] = folderList.getItemAtIndex(i);
+      }
+    }
+
+    //update folderlist
+    for (let i=0; i < folderData.length; i++) {
+      let nextItem = null;
+      
+      //if this entry does not exist, create it
+      if (foldersElements.hasOwnProperty(folderData[i].folderID)) {
+        //get reference to current element
+        nextItem = foldersElements[folderData[i].folderID];
+      } else {
+        //add new entry, attach FolderData of this folder as folderData
+        nextItem = document.createXULElement("richlistitem");
+        nextItem.folderData = folderData[i];
+        
+        //add row
+        nextItem.appendChild(TbSync.providers[tbSyncAccountSettings.provider].folderList.getRow(document, folderData[i]));
+      }
+
+      //add/move row and update its content
+      let addedItem = folderList.appendChild(nextItem);
+      TbSync.providers[tbSyncAccountSettings.provider].folderList.updateRow(document, addedItem, folderData[i]);
+
+      //ensureElementIsVisible also forces internal update of rowCount, which sometimes is not updated automatically upon appendChild
+      folderList.ensureElementIsVisible(addedItem);
+    }
+    folderList.hidden = false;
+  },
+
+
+
+
+
+  instantSaveSetting: function (field) {
+    let setting = field.id.replace("tbsync.accountsettings.pref.","");
+    let value = "";
+    
+    if ((field.tagName == "checkbox") || ((field.tagName == "input") && (field.type == "checkbox"))) {
+      if (field.checked) value = true;
+      else value = false;
+    } else {
+      value = field.value;
+    }
+    TbSync.db.setAccountProperty(tbSyncAccountSettings.accountID, setting, value);
+    
+    if (setting == "accountname") {
+      Services.obs.notifyObservers(null, "tbsync.observer.manager.updateAccountName", tbSyncAccountSettings.accountID + ":" + field.value);
+    }
+    TbSync.db.saveAccounts(); //write modified accounts to disk
+  },
+
+  toggleEnableState: function (element) {
+    if (!TbSync.core.isConnected(tbSyncAccountSettings.accountID)) {
+      //if not connected, we can toggle without prompt
+      Services.obs.notifyObservers(null, "tbsync.observer.manager.toggleEnableState", tbSyncAccountSettings.accountID);
+      return;
+    }      
+
+    if (window.confirm(TbSync.getString("prompt.Disable"))) {
+      Services.obs.notifyObservers(null, "tbsync.observer.manager.toggleEnableState", tbSyncAccountSettings.accountID);
+    } else {
+      //invalid, toggle checkbox back
+      element.setAttribute("checked", true);
+    }
+  },
+
+  
+  onFolderListContextMenuShowing: function () {
+    let folderList = document.getElementById("tbsync.accountsettings.folderlist");
+    let aFolderIsSelected = (!folderList.disabled && folderList.selectedItem !== null && folderList.selectedItem.value !== undefined);
+    let menupopup = document.getElementById("tbsync.accountsettings.FolderListContextMenu");
+    
+    if (aFolderIsSelected) {
+      TbSync.providers[tbSyncAccountSettings.provider].folderList.onContextMenuShowing(window, folderList.selectedItem.folderData);
+    } else {
+      TbSync.providers[tbSyncAccountSettings.provider].folderList.onContextMenuShowing(window, null);
+    }
+  },
+
+};
diff -Nru tbsync-4.12/content/manager/editAccount.xhtml tbsync-4.16/content/manager/editAccount.xhtml
--- tbsync-4.12/content/manager/editAccount.xhtml	2024-08-27 18:32:08.000000000 +0200
+++ tbsync-4.16/content/manager/editAccount.xhtml	2024-08-18 13:03:30.000000000 +0200
@@ -1,87 +1,87 @@
-<?xml version="1.0" encoding="utf-8"?>
-<?xml-stylesheet href="chrome://global/skin/global.css" type="text/css"?>
-<?xml-stylesheet href="chrome://tbsync/content/manager/manager.css" type="text/css"?>
-
-<window id="tbsync.accountsettings" 
-    xmlns:html="http://www.w3.org/1999/xhtml"
-    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
-    xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
-    omscope="tbSyncAccountSettings"
-    onload="tbSyncAccountSettings.onload()"
-    onunload="tbSyncAccountSettings.onunload()"
-    title="" >
-
-    <script type="text/javascript" src="chrome://tbsync/content/manager/editAccount.js" /> 
-    <script type="text/javascript" src="chrome://tbsync/content/scripts/locales.js" /> 
-
-    <popupset>
-        <menupopup 
-        id="tbsync.accountsettings.FolderListContextMenu" 
-        folderID=""
-        onpopupshowing="tbSyncAccountSettings.onFolderListContextMenuShowing();">
-            <menuitem 
-            class="menuitem-iconic"
-            image="chrome://tbsync/content/skin/warning16.png"
-            label="__TBSYNCMSG_manager.ShowEventLog__"
-            oncommand="TbSync.eventlog.open(tbSyncAccountSettings.accountID, this.parentNode.getAttribute('folderID'));"/>
-        </menupopup>
-    </popupset>
-    
-    <tabbox id="tbsync.accountsettings.frame" hidden="true" flex="1">
-
-        <tabs  id="manager.tabs" orient="horizontal" value="">
-            <tab id="manager.tabs.status" label="__TBSYNCMSG_manager.tabs.status__" />
-        </tabs>
-      
-        <tabpanels flex="1" id="manager.tabpanels" style="margin:0;padding:1ex;">
-            <tabpanel  id="manager.tabpanels.status" orient="vertical"><!-- STATUS -->
-                <vbox flex="1">
-                    <label class="header" style="margin-left:0; margin-bottom:1ex;" value="__TBSYNCMSG_manager.tabs.status.general__" />
-                    <checkbox id="tbsync.accountsettings.enabled" oncommand="tbSyncAccountSettings.toggleEnableState(this);" label="__TBSYNCMSG_manager.tabs.status.enableThisAccount__"  />
-
-                    <vbox class="showIfEnabled" style="height:100px; overflow-x: hidden; overflow-y:hidden">
-                        <hbox flex="1">
-                            <vbox flex="1">
-                                <label class="header" style="margin-left:0; margin-bottom:1ex; margin-top:2ex;" value="__TBSYNCMSG_manager.status__" />
-                                <description id="syncstate"></description>
-                            </vbox>
-                            <vbox flex="0">
-                                <label class="header" style="margin-left:0; margin-bottom:1ex; margin-top:1ex; visibility: hidden" value="nix" />
-                                <button id="tbsync.accountsettings.eventlogbtn" label="__TBSYNCMSG_manager.ShowEventLog__" oncommand="TbSync.eventlog.open()" />
-                            </vbox>
-                        </hbox>
-                    </vbox>
-                    
-                    <vbox flex="1">
-                        <vbox class="showIfConnected" flex="1">
-                            <label style="margin-left:0; margin-bottom: 1ex; margin-top: 2ex" class="header" value="__TBSYNCMSG_manager.tabs.status.resources__"/>
-                            <description>__TBSYNCMSG_manager.tabs.status.resources.intro__</description>
-                            <richlistbox 
-                              id="tbsync.accountsettings.folderlist"
-                              style="margin: 0 1px 1px 1ex;padding:0; height:225px; overflow-x: hidden;"
-                              context="tbsync.accountsettings.FolderListContextMenu"
-                              seltype="single">
-                                <listheader id="tbsync.accountsettings.folderlist.header" style="border-bottom: 1px solid lightgrey;">
-                                </listheader>
-                            </richlistbox>
-                            <vbox flex="0" style="margin:1ex 0 0 0;">
-                                <hbox flex="1" align="center" pack="end">
-                                    <description style="text-align:right" flex="1" control="tbsync.accountsettings.pref.autosync" tooltiptext="__TBSYNCMSG_manager.tabs.status.never__">__TBSYNCMSG_manager.tabs.status.autotime__</description>
-                                    <html:input style="width:50px;margin-bottom:0; margin-top:0" id="tbsync.accountsettings.pref.autosync" tooltiptext="__TBSYNCMSG_manager.tabs.status.never__" />
-                                    <button id="tbsync.accountsettings.syncbtn" style="margin-right:0; margin-bottom:0; margin-top:0; padding: 0 1ex;" label="__TBSYNCMSG_manager.tabs.status.sync__" oncommand="TbSync.core.syncAccount(tbSyncAccountSettings.accountID)" />
-                                </hbox>
-                            </vbox>
-                        </vbox>
-                    </vbox>
-
-                    <hbox id="tbsync.accountsettings.connectbtn.container" flex="0" style="margin:1ex 0 0 0;" pack="end">
-                        <button id="tbsync.accountsettings.connectbtn" style="margin-right:0; margin-bottom:0; margin-top:0; padding: 0 1ex;" label="__TBSYNCMSG_manager.tabs.status.tryagain__" oncommand="TbSync.core.syncAccount(tbSyncAccountSettings.accountID)" />
-                    </hbox>
-        
-                </vbox>
-            </tabpanel>
-        </tabpanels>
-
-    </tabbox>
-    
-</window>
+<?xml version="1.0" encoding="utf-8"?>
+<?xml-stylesheet href="chrome://global/skin/global.css" type="text/css"?>
+<?xml-stylesheet href="chrome://tbsync/content/manager/manager.css" type="text/css"?>
+
+<window id="tbsync.accountsettings" 
+    xmlns:html="http://www.w3.org/1999/xhtml"
+    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+    xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+    omscope="tbSyncAccountSettings"
+    onload="tbSyncAccountSettings.onload()"
+    onunload="tbSyncAccountSettings.onunload()"
+    title="" >
+
+    <script type="text/javascript" src="chrome://tbsync/content/manager/editAccount.js" /> 
+    <script type="text/javascript" src="chrome://tbsync/content/scripts/locales.js" /> 
+
+    <popupset>
+        <menupopup 
+        id="tbsync.accountsettings.FolderListContextMenu" 
+        folderID=""
+        onpopupshowing="tbSyncAccountSettings.onFolderListContextMenuShowing();">
+            <menuitem 
+            class="menuitem-iconic"
+            image="chrome://tbsync/content/skin/warning16.png"
+            label="__TBSYNCMSG_manager.ShowEventLog__"
+            oncommand="TbSync.eventlog.open(tbSyncAccountSettings.accountID, this.parentNode.getAttribute('folderID'));"/>
+        </menupopup>
+    </popupset>
+    
+    <tabbox id="tbsync.accountsettings.frame" hidden="true" flex="1">
+
+        <tabs  id="manager.tabs" orient="horizontal" value="">
+            <tab id="manager.tabs.status" label="__TBSYNCMSG_manager.tabs.status__" />
+        </tabs>
+      
+        <tabpanels flex="1" id="manager.tabpanels" style="margin:0;padding:1ex;">
+            <tabpanel  id="manager.tabpanels.status" orient="vertical"><!-- STATUS -->
+                <vbox flex="1">
+                    <label class="header" style="margin-left:0; margin-bottom:1ex;" value="__TBSYNCMSG_manager.tabs.status.general__" />
+                    <checkbox id="tbsync.accountsettings.enabled" oncommand="tbSyncAccountSettings.toggleEnableState(this);" label="__TBSYNCMSG_manager.tabs.status.enableThisAccount__"  />
+
+                    <vbox class="showIfEnabled" style="height:100px; overflow-x: hidden; overflow-y:hidden">
+                        <hbox flex="1">
+                            <vbox flex="1">
+                                <label class="header" style="margin-left:0; margin-bottom:1ex; margin-top:2ex;" value="__TBSYNCMSG_manager.status__" />
+                                <description id="syncstate"></description>
+                            </vbox>
+                            <vbox flex="0">
+                                <label class="header" style="margin-left:0; margin-bottom:1ex; margin-top:1ex; visibility: hidden" value="nix" />
+                                <button id="tbsync.accountsettings.eventlogbtn" label="__TBSYNCMSG_manager.ShowEventLog__" oncommand="TbSync.eventlog.open()" />
+                            </vbox>
+                        </hbox>
+                    </vbox>
+                    
+                    <vbox flex="1">
+                        <vbox class="showIfConnected" flex="1">
+                            <label style="margin-left:0; margin-bottom: 1ex; margin-top: 2ex" class="header" value="__TBSYNCMSG_manager.tabs.status.resources__"/>
+                            <description>__TBSYNCMSG_manager.tabs.status.resources.intro__</description>
+                            <richlistbox 
+                              id="tbsync.accountsettings.folderlist"
+                              style="margin: 0 1px 1px 1ex;padding:0; height:225px; overflow-x: hidden;"
+                              context="tbsync.accountsettings.FolderListContextMenu"
+                              seltype="single">
+                                <listheader id="tbsync.accountsettings.folderlist.header" style="border-bottom: 1px solid lightgrey;">
+                                </listheader>
+                            </richlistbox>
+                            <vbox flex="0" style="margin:1ex 0 0 0;">
+                                <hbox flex="1" align="center" pack="end">
+                                    <description style="text-align:right" flex="1" control="tbsync.accountsettings.pref.autosync" tooltiptext="__TBSYNCMSG_manager.tabs.status.never__">__TBSYNCMSG_manager.tabs.status.autotime__</description>
+                                    <html:input style="width:50px;margin-bottom:0; margin-top:0" id="tbsync.accountsettings.pref.autosync" tooltiptext="__TBSYNCMSG_manager.tabs.status.never__" />
+                                    <button id="tbsync.accountsettings.syncbtn" style="margin-right:0; margin-bottom:0; margin-top:0; padding: 0 1ex;" label="__TBSYNCMSG_manager.tabs.status.sync__" oncommand="TbSync.core.syncAccount(tbSyncAccountSettings.accountID)" />
+                                </hbox>
+                            </vbox>
+                        </vbox>
+                    </vbox>
+
+                    <hbox id="tbsync.accountsettings.connectbtn.container" flex="0" style="margin:1ex 0 0 0;" pack="end">
+                        <button id="tbsync.accountsettings.connectbtn" style="margin-right:0; margin-bottom:0; margin-top:0; padding: 0 1ex;" label="__TBSYNCMSG_manager.tabs.status.tryagain__" oncommand="TbSync.core.syncAccount(tbSyncAccountSettings.accountID)" />
+                    </hbox>
+        
+                </vbox>
+            </tabpanel>
+        </tabpanels>
+
+    </tabbox>
+    
+</window>
diff -Nru tbsync-4.12/content/manager/eventlog/eventlog.js tbsync-4.16/content/manager/eventlog/eventlog.js
--- tbsync-4.12/content/manager/eventlog/eventlog.js	2024-08-27 18:32:08.000000000 +0200
+++ tbsync-4.16/content/manager/eventlog/eventlog.js	2025-03-15 23:49:58.000000000 +0100
@@ -1,157 +1,166 @@
-/*
- * This file is part of TbSync.
- *
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. 
- */
- 
-"use strict";
-
-var { TbSync } = ChromeUtils.import("chrome://tbsync/content/tbsync.jsm");
-
-var tbSyncEventLog = {
-  
-  onload: function () {
-    Services.obs.addObserver(tbSyncEventLog.updateEventLog, "tbsync.observer.eventlog.update", false);
-
-    let eventlog = document.getElementById('tbsync.eventlog');
-    eventlog.hidden = true;
-    
-    //init list
-    let events = TbSync.eventlog.get();
-    for (let i=0; i < events.length; i++) {
-      let item = tbSyncEventLog.addLogEntry(events[i]);
-      eventlog.appendChild(item);
-    }
-    eventlog.hidden = false;
-    eventlog.ensureIndexIsVisible(eventlog.getRowCount()-1);
-    document.getElementById("tbsync.eventlog.clear").addEventListener("click", tbSyncEventLog.onclear);
-    document.getElementById("tbsync.eventlog.close").addEventListener("click", () => window.close());
-  },
-
-  onclear: function () {
-    TbSync.eventlog.clear();
-
-    let eventlog = document.getElementById('tbsync.eventlog');
-    eventlog.hidden = true;
-
-    for (let i=eventlog.getRowCount()-1; i>=0; i--) {
-      eventlog.getItemAtIndex(i).remove();
-    }
-    
-    eventlog.hidden = false;
-  },
-  
-  onunload: function () {
-    Services.obs.removeObserver(tbSyncEventLog.updateEventLog, "tbsync.observer.eventlog.update");
-  },
-
-  updateEventLog: {
-    observe: function (aSubject, aTopic, aData) {
-      let events = TbSync.eventlog.get();
-      if (events.length > 0) {
-        let eventlog = document.getElementById('tbsync.eventlog');
-        eventlog.hidden = true;
-        
-        let item = tbSyncEventLog.addLogEntry(events[events.length-1]);
-        eventlog.appendChild(item);
-
-        eventlog.hidden = false;
-        eventlog.ensureIndexIsVisible(eventlog.getRowCount()-1);
-      }
-    }
-  },
-
-  
-  addLogEntry: function (entry) {
-    
-    //left column
-    let leftColumn = document.createXULElement("vbox");
-    //leftColumn.setAttribute("width", "24");
-    leftColumn.setAttribute("style", "width: 24px;");
-
-    let image = document.createXULElement("image");
-    let src = entry.type.endsWith("_rerun") ? "sync" : entry.type;
-    image.setAttribute("src", "chrome://tbsync/content/skin/" + src + "16.png");
-    image.setAttribute("style", "margin:4px 4px 4px 4px;");
-    leftColumn.appendChild(image);
-    
-    //right column        
-    let rightColumn = document.createXULElement("vbox");
-    rightColumn.setAttribute("flex","1");
-
-    let d = new Date(entry.timestamp);
-    let timestamp = document.createXULElement("description");
-    timestamp.setAttribute("flex", "1");
-    timestamp.setAttribute("class", "header");
-    timestamp.textContent = d.toLocaleTimeString();
-    rightColumn.appendChild(timestamp);
-
-      let hBox = document.createXULElement("hbox");
-      hBox.flex = "1";
-      let vBoxLeft = document.createXULElement("vbox");
-      vBoxLeft.flex = "1";
-      let vBoxRight = document.createXULElement("vbox");
-      
-      let msg = document.createXULElement("description");
-      msg.setAttribute("flex", "1");
-      msg.setAttribute("class", "header");
-      msg.textContent = entry.message;
-      vBoxLeft.appendChild(msg);
-
-      if (entry.link) {
-        let link = document.createXULElement("button");
-        link.setAttribute("label",  TbSync.getString("manager.help"));
-        link.setAttribute("oncommand",  "TbSync.manager.openLink('" + entry.link + "')");
-        vBoxRight.appendChild(link);
-      }
-
-      hBox.appendChild(vBoxLeft);
-      hBox.appendChild(vBoxRight);
-      rightColumn.appendChild(hBox);
-    
-    if (entry.accountname || entry.provider) {
-      let account = document.createXULElement("label");
-      if (entry.accountname) account.setAttribute("value",  "Account: " + entry.accountname + (entry.provider ? " (" + entry.provider.toUpperCase() + ")" : ""));
-      else account.setAttribute("value",  "Provider: " + entry.provider.toUpperCase());
-      rightColumn.appendChild(account);
-    }
-
-    if (entry.foldername) {
-      let folder = document.createXULElement("label");
-      folder.setAttribute("value",  "Resource: " + entry.foldername);
-      rightColumn.appendChild(folder);
-    }
-
-    if (entry.details) {
-      let lines = entry.details.split("\n");
-      let line = document.createElementNS("http://www.w3.org/1999/xhtml", "textarea");
-      line.setAttribute("readonly", "true");                
-      line.setAttribute("wrap", "off");                           
-      line.setAttribute("rows", lines.length);                
-      line.setAttribute("style", "font-family: monospace; font-size: 10px;");                
-      line.setAttribute("class", "plain");                
-      line.value = entry.details.trim();
-      
-      let container = document.createXULElement("vbox");
-      container.setAttribute("style", "margin-left:1ex;margin-top:1ex;");                
-      container.appendChild(line);
-      
-      rightColumn.appendChild(container);
-    }
-    
-    //columns
-    let columns = document.createXULElement("hbox");
-    columns.setAttribute("flex", "1");
-    columns.appendChild(leftColumn);
-    columns.appendChild(rightColumn);
-    
-    //richlistitem
-    let richlistitem = document.createXULElement("richlistitem");
-    richlistitem.setAttribute("style", "padding:4px; border-bottom: 1px solid lightgrey;");
-    richlistitem.appendChild(columns);
-    
-    return richlistitem;
-  },    
-};
+/*
+ * This file is part of TbSync.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. 
+ */
+ 
+"use strict";
+
+var { ExtensionParent } = ChromeUtils.importESModule(
+  "resource://gre/modules/ExtensionParent.sys.mjs"
+);
+
+var tbsyncExtension = ExtensionParent.GlobalManager.getExtension(
+  "tbsync at jobisoft.de"
+);
+var { TbSync } = ChromeUtils.importESModule(
+  `chrome://tbsync/content/tbsync.sys.mjs?${tbsyncExtension.manifest.version}`
+);
+
+var tbSyncEventLog = {
+  
+  onload: function () {
+    Services.obs.addObserver(tbSyncEventLog.updateEventLog, "tbsync.observer.eventlog.update", false);
+
+    let eventlog = document.getElementById('tbsync.eventlog');
+    eventlog.hidden = true;
+    
+    //init list
+    let events = TbSync.eventlog.get();
+    for (let i=0; i < events.length; i++) {
+      let item = tbSyncEventLog.addLogEntry(events[i]);
+      eventlog.appendChild(item);
+    }
+    eventlog.hidden = false;
+    eventlog.ensureIndexIsVisible(eventlog.getRowCount()-1);
+    document.getElementById("tbsync.eventlog.clear").addEventListener("click", tbSyncEventLog.onclear);
+    document.getElementById("tbsync.eventlog.close").addEventListener("click", () => window.close());
+  },
+
+  onclear: function () {
+    TbSync.eventlog.clear();
+
+    let eventlog = document.getElementById('tbsync.eventlog');
+    eventlog.hidden = true;
+
+    for (let i=eventlog.getRowCount()-1; i>=0; i--) {
+      eventlog.getItemAtIndex(i).remove();
+    }
+    
+    eventlog.hidden = false;
+  },
+  
+  onunload: function () {
+    Services.obs.removeObserver(tbSyncEventLog.updateEventLog, "tbsync.observer.eventlog.update");
+  },
+
+  updateEventLog: {
+    observe: function (aSubject, aTopic, aData) {
+      let events = TbSync.eventlog.get();
+      if (events.length > 0) {
+        let eventlog = document.getElementById('tbsync.eventlog');
+        eventlog.hidden = true;
+        
+        let item = tbSyncEventLog.addLogEntry(events[events.length-1]);
+        eventlog.appendChild(item);
+
+        eventlog.hidden = false;
+        eventlog.ensureIndexIsVisible(eventlog.getRowCount()-1);
+      }
+    }
+  },
+
+  
+  addLogEntry: function (entry) {
+    
+    //left column
+    let leftColumn = document.createXULElement("vbox");
+    //leftColumn.setAttribute("width", "24");
+    leftColumn.setAttribute("style", "width: 24px;");
+
+    let image = document.createXULElement("image");
+    let src = entry.type.endsWith("_rerun") ? "sync" : entry.type;
+    image.setAttribute("src", "chrome://tbsync/content/skin/" + src + "16.png");
+    image.setAttribute("style", "margin:4px 4px 4px 4px;");
+    leftColumn.appendChild(image);
+    
+    //right column        
+    let rightColumn = document.createXULElement("vbox");
+    rightColumn.setAttribute("flex","1");
+
+    let d = new Date(entry.timestamp);
+    let timestamp = document.createXULElement("description");
+    timestamp.setAttribute("flex", "1");
+    timestamp.setAttribute("class", "header");
+    timestamp.textContent = d.toLocaleTimeString();
+    rightColumn.appendChild(timestamp);
+
+      let hBox = document.createXULElement("hbox");
+      hBox.flex = "1";
+      let vBoxLeft = document.createXULElement("vbox");
+      vBoxLeft.flex = "1";
+      let vBoxRight = document.createXULElement("vbox");
+      
+      let msg = document.createXULElement("description");
+      msg.setAttribute("flex", "1");
+      msg.setAttribute("class", "header");
+      msg.textContent = entry.message;
+      vBoxLeft.appendChild(msg);
+
+      if (entry.link) {
+        let link = document.createXULElement("button");
+        link.setAttribute("label",  TbSync.getString("manager.help"));
+        link.setAttribute("oncommand",  "TbSync.manager.openLink('" + entry.link + "')");
+        vBoxRight.appendChild(link);
+      }
+
+      hBox.appendChild(vBoxLeft);
+      hBox.appendChild(vBoxRight);
+      rightColumn.appendChild(hBox);
+    
+    if (entry.accountname || entry.provider) {
+      let account = document.createXULElement("label");
+      if (entry.accountname) account.setAttribute("value",  "Account: " + entry.accountname + (entry.provider ? " (" + entry.provider.toUpperCase() + ")" : ""));
+      else account.setAttribute("value",  "Provider: " + entry.provider.toUpperCase());
+      rightColumn.appendChild(account);
+    }
+
+    if (entry.foldername) {
+      let folder = document.createXULElement("label");
+      folder.setAttribute("value",  "Resource: " + entry.foldername);
+      rightColumn.appendChild(folder);
+    }
+
+    if (entry.details) {
+      let lines = entry.details.split("\n");
+      let line = document.createElementNS("http://www.w3.org/1999/xhtml", "textarea");
+      line.setAttribute("readonly", "true");                
+      line.setAttribute("wrap", "off");                           
+      line.setAttribute("rows", lines.length);                
+      line.setAttribute("style", "font-family: monospace; font-size: 10px;");                
+      line.setAttribute("class", "plain");                
+      line.value = entry.details.trim();
+      
+      let container = document.createXULElement("vbox");
+      container.setAttribute("style", "margin-left:1ex;margin-top:1ex;");                
+      container.appendChild(line);
+      
+      rightColumn.appendChild(container);
+    }
+    
+    //columns
+    let columns = document.createXULElement("hbox");
+    columns.setAttribute("flex", "1");
+    columns.appendChild(leftColumn);
+    columns.appendChild(rightColumn);
+    
+    //richlistitem
+    let richlistitem = document.createXULElement("richlistitem");
+    richlistitem.setAttribute("style", "padding:4px; border-bottom: 1px solid lightgrey;");
+    richlistitem.appendChild(columns);
+    
+    return richlistitem;
+  },    
+};
diff -Nru tbsync-4.12/content/manager/eventlog/eventlog.xhtml tbsync-4.16/content/manager/eventlog/eventlog.xhtml
--- tbsync-4.12/content/manager/eventlog/eventlog.xhtml	2024-08-27 18:32:08.000000000 +0200
+++ tbsync-4.16/content/manager/eventlog/eventlog.xhtml	2024-08-18 13:03:30.000000000 +0200
@@ -1,21 +1,21 @@
-<?xml version="1.0"?>
-<?xml-stylesheet href="chrome://global/skin/global.css" type="text/css"?>
-
-<window
-    title="__TBSYNCMSG_eventlog.title__"
-    onload="tbSyncEventLog.onload();"
-    onunload="tbSyncEventLog.onunload();"
-    xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" >
-
-    <script type="application/javascript" src="chrome://tbsync/content/manager/eventlog/eventlog.js"/>
-    <script type="text/javascript" src="chrome://tbsync/content/scripts/locales.js" /> 
-
-    <vbox flex="1">
-        <richlistbox id="tbsync.eventlog" style="padding:5px; height:360px" seltype="single" disabled="true"/>
-        <hbox style="padding: 5px">
-            <vbox flex="1"></vbox>
-            <button id="tbsync.eventlog.clear" label="__TBSYNCMSG_eventlog.clear__" />
-            <button id="tbsync.eventlog.close" label="__TBSYNCMSG_eventlog.close__" />
-        </hbox>
-    </vbox>
-</window>
+<?xml version="1.0"?>
+<?xml-stylesheet href="chrome://global/skin/global.css" type="text/css"?>
+
+<window
+    title="__TBSYNCMSG_eventlog.title__"
+    onload="tbSyncEventLog.onload();"
+    onunload="tbSyncEventLog.onunload();"
+    xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" >
+
+    <script type="application/javascript" src="chrome://tbsync/content/manager/eventlog/eventlog.js"/>
+    <script type="text/javascript" src="chrome://tbsync/content/scripts/locales.js" /> 
+
+    <vbox flex="1">
+        <richlistbox id="tbsync.eventlog" style="padding:5px; height:360px" seltype="single" disabled="true"/>
+        <hbox style="padding: 5px">
+            <vbox flex="1"></vbox>
+            <button id="tbsync.eventlog.clear" label="__TBSYNCMSG_eventlog.clear__" />
+            <button id="tbsync.eventlog.close" label="__TBSYNCMSG_eventlog.close__" />
+        </hbox>
+    </vbox>
+</window>
diff -Nru tbsync-4.12/content/manager/help.xhtml tbsync-4.16/content/manager/help.xhtml
--- tbsync-4.12/content/manager/help.xhtml	2024-08-27 18:32:08.000000000 +0200
+++ tbsync-4.16/content/manager/help.xhtml	2021-08-30 18:31:42.000000000 +0200
@@ -1,58 +1,58 @@
-<?xml version="1.0" encoding="utf-8"?>
-<?xml-stylesheet href="chrome://global/skin/global.css" type="text/css"?>
-<?xml-stylesheet href="chrome://tbsync/content/manager/manager.css" type="text/css"?>
-
-<window 
-    xmlns:html="http://www.w3.org/1999/xhtml"
-    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
-    xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
-    onload="tbSyncAccountManager.getLogPref();"
-    title="Help" >
-
-    <hbox flex="1" id="mainframe">
-        <vbox flex="1">
-
-            <html:p>
-                <html:b>__TBSYNCMSG_manager.help.needhelp__</html:b><html:br/><html:br/>
-                __TBSYNCMSG_manager.help.wiki__
-            </html:p>
-
-            <html:p onmouseover="this.style.cursor='pointer'" onmouseout="this.style.cursor='default'" onclick="TbSync.manager.openTranslatedLink('https://github.com/jobisoft/TbSync/wiki');" style="color:blue;text-decoration: underline;padding-left:1em;margin:0 0 24px 0">
-                https://github.com/jobisoft/TbSync/wiki
-            </html:p>
-
-            <html:p>
-                <html:b>__TBSYNCMSG_manager.help.foundabug__</html:b><html:br/><html:br/>
-                <html:span>__TBSYNCMSG_manager.help.fixit__</html:span>
-            </html:p>
-
-            <hbox align="center">
-                <label value="__TBSYNCMSG_manager.help.debugmode__" />
-                <menulist flex="0" id="tbSyncAccountManager.logLevel" oncommand="tbSyncAccountManager.toggleLogPref();">
-                  <menupopup>
-                      <menuitem label="__TBSYNCMSG_manager.help.debuglevel.0__" value="0" />
-                      <menuitem label="__TBSYNCMSG_manager.help.debuglevel.1__" value="1" />
-                      <menuitem label="__TBSYNCMSG_manager.help.debuglevel.2__" value="2" />
-                      <menuitem label="__TBSYNCMSG_manager.help.debuglevel.3__" value="3" />
-                </menupopup>
-              </menulist>
-            </hbox>
-
-            <html:p> 
-                __TBSYNCMSG_manager.help.createbugreportinfo__
-            </html:p>     
-            
-            <hbox>
-                <button style="margin:0 0 0 1em; padding: 0 1ex;" label="__TBSYNCMSG_manager.help.createbugreport__" oncommand="TbSync.manager.openBugReportWizard();" />
-                <button style="margin:0 0 0 1em; padding: 0 1ex;" label="__TBSYNCMSG_manager.help.viewdebuglog__" oncommand="TbSync.manager.viewDebugLog();" />
-            </hbox>
-            
-            <hbox flex="1">
-            </hbox>  
-
-        </vbox>
-    </hbox>
-    
-    <script type="text/javascript" src="chrome://tbsync/content/manager/accountManager.js" /> 
-    <script type="text/javascript" src="chrome://tbsync/content/scripts/locales.js" /> 
-</window>
+<?xml version="1.0" encoding="utf-8"?>
+<?xml-stylesheet href="chrome://global/skin/global.css" type="text/css"?>
+<?xml-stylesheet href="chrome://tbsync/content/manager/manager.css" type="text/css"?>
+
+<window 
+    xmlns:html="http://www.w3.org/1999/xhtml"
+    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+    xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+    onload="tbSyncAccountManager.getLogPref();"
+    title="Help" >
+
+    <hbox flex="1" id="mainframe">
+        <vbox flex="1">
+
+            <html:p>
+                <html:b>__TBSYNCMSG_manager.help.needhelp__</html:b><html:br/><html:br/>
+                __TBSYNCMSG_manager.help.wiki__
+            </html:p>
+
+            <html:p onmouseover="this.style.cursor='pointer'" onmouseout="this.style.cursor='default'" onclick="TbSync.manager.openTranslatedLink('https://github.com/jobisoft/TbSync/wiki');" style="color:blue;text-decoration: underline;padding-left:1em;margin:0 0 24px 0">
+                https://github.com/jobisoft/TbSync/wiki
+            </html:p>
+
+            <html:p>
+                <html:b>__TBSYNCMSG_manager.help.foundabug__</html:b><html:br/><html:br/>
+                <html:span>__TBSYNCMSG_manager.help.fixit__</html:span>
+            </html:p>
+
+            <hbox align="center">
+                <label value="__TBSYNCMSG_manager.help.debugmode__" />
+                <menulist flex="0" id="tbSyncAccountManager.logLevel" oncommand="tbSyncAccountManager.toggleLogPref();">
+                  <menupopup>
+                      <menuitem label="__TBSYNCMSG_manager.help.debuglevel.0__" value="0" />
+                      <menuitem label="__TBSYNCMSG_manager.help.debuglevel.1__" value="1" />
+                      <menuitem label="__TBSYNCMSG_manager.help.debuglevel.2__" value="2" />
+                      <menuitem label="__TBSYNCMSG_manager.help.debuglevel.3__" value="3" />
+                </menupopup>
+              </menulist>
+            </hbox>
+
+            <html:p> 
+                __TBSYNCMSG_manager.help.createbugreportinfo__
+            </html:p>     
+            
+            <hbox>
+                <button style="margin:0 0 0 1em; padding: 0 1ex;" label="__TBSYNCMSG_manager.help.createbugreport__" oncommand="TbSync.manager.openBugReportWizard();" />
+                <button style="margin:0 0 0 1em; padding: 0 1ex;" label="__TBSYNCMSG_manager.help.viewdebuglog__" oncommand="TbSync.manager.viewDebugLog();" />
+            </hbox>
+            
+            <hbox flex="1">
+            </hbox>  
+
+        </vbox>
+    </hbox>
+    
+    <script type="text/javascript" src="chrome://tbsync/content/manager/accountManager.js" /> 
+    <script type="text/javascript" src="chrome://tbsync/content/scripts/locales.js" /> 
+</window>
diff -Nru tbsync-4.12/content/manager/installProvider.xhtml tbsync-4.16/content/manager/installProvider.xhtml
--- tbsync-4.12/content/manager/installProvider.xhtml	2024-08-27 18:32:08.000000000 +0200
+++ tbsync-4.16/content/manager/installProvider.xhtml	2021-08-30 18:31:42.000000000 +0200
@@ -1,35 +1,35 @@
-<?xml version="1.0" encoding="utf-8"?>
-<?xml-stylesheet href="chrome://global/skin/global.css" type="text/css"?>
-<?xml-stylesheet href="chrome://tbsync/content/manager/manager.css" type="text/css"?>
-
-<window
-    xmlns:html="http://www.w3.org/1999/xhtml"
-    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
-    xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
-    onload="tbSyncManageProvider.prepInstall();"
-    title="Install additional synchronization provider for TbSync" >
-
-    <hbox flex="1" id="mainframe">
-        <vbox flex="1">
-
-            <hbox>
-              <html:p style="font-weight: bold" id="header"></html:p>
-            </hbox>
-
-            <html:p>
-                __TBSYNCMSG_manager.installprovider.link__
-            </html:p>
-            
-            <html:p id="link" onmouseover="this.style.cursor='pointer'" onmouseout="this.style.cursor='default'" onclick="TbSync.manager.prefWindowObj.tbSyncAccountManager.selectTab(0); TbSync.manager.openTBtab(this.getAttribute('link'));" style="color:blue;text-decoration: underline;padding-left:1em;">
-            </html:p>
-
-            <html:p id="warning" style="font-weight: bold">
-                __TBSYNCMSG_manager.installprovider.warning__
-            </html:p>
-
-        </vbox>
-    </hbox>
-    
-    <script type="text/javascript" src="chrome://tbsync/content/manager/manageProvider.js" /> 
-    <script type="text/javascript" src="chrome://tbsync/content/scripts/locales.js" /> 
-</window>
+<?xml version="1.0" encoding="utf-8"?>
+<?xml-stylesheet href="chrome://global/skin/global.css" type="text/css"?>
+<?xml-stylesheet href="chrome://tbsync/content/manager/manager.css" type="text/css"?>
+
+<window
+    xmlns:html="http://www.w3.org/1999/xhtml"
+    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+    xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+    onload="tbSyncManageProvider.prepInstall();"
+    title="Install additional synchronization provider for TbSync" >
+
+    <hbox flex="1" id="mainframe">
+        <vbox flex="1">
+
+            <hbox>
+              <html:p style="font-weight: bold" id="header"></html:p>
+            </hbox>
+
+            <html:p>
+                __TBSYNCMSG_manager.installprovider.link__
+            </html:p>
+            
+            <html:p id="link" onmouseover="this.style.cursor='pointer'" onmouseout="this.style.cursor='default'" onclick="TbSync.manager.prefWindowObj.tbSyncAccountManager.selectTab(0); TbSync.manager.openTBtab(this.getAttribute('link'));" style="color:blue;text-decoration: underline;padding-left:1em;">
+            </html:p>
+
+            <html:p id="warning" style="font-weight: bold">
+                __TBSYNCMSG_manager.installprovider.warning__
+            </html:p>
+
+        </vbox>
+    </hbox>
+    
+    <script type="text/javascript" src="chrome://tbsync/content/manager/manageProvider.js" /> 
+    <script type="text/javascript" src="chrome://tbsync/content/scripts/locales.js" /> 
+</window>
diff -Nru tbsync-4.12/content/manager/manageProvider.js tbsync-4.16/content/manager/manageProvider.js
--- tbsync-4.12/content/manager/manageProvider.js	2024-08-27 18:32:08.000000000 +0200
+++ tbsync-4.16/content/manager/manageProvider.js	2025-03-15 23:49:58.000000000 +0100
@@ -1,40 +1,49 @@
-/*
- * This file is part of TbSync.
- *
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. 
- */
- 
-"use strict";
-
-var { TbSync } = ChromeUtils.import("chrome://tbsync/content/tbsync.jsm");
-
-var tbSyncManageProvider = {
-  
-  prepInstall: function () {
-    let url = window.location.toString();
-    let provider = url.split("provider=")[1];
-    window.document.getElementById("header").textContent = TbSync.getString("installProvider.header::" + TbSync.providers.defaultProviders[provider].name);
-
-    window.document.getElementById("link").textContent = TbSync.providers.defaultProviders[provider].homepageUrl;
-    window.document.getElementById("link").setAttribute("link", TbSync.providers.defaultProviders[provider].homepageUrl);
-
-    window.document.getElementById("warning").hidden = TbSync.providers.defaultProviders[provider].homepageUrl.startsWith("https://addons.thunderbird.net"); 
-  },
-
-  prepMissing: function () {
-    let url = window.location.toString();
-    let provider = url.split("provider=")[1];
-
-    let e = window.document.getElementById("missing");
-    let v = e.textContent;
-    e.textContent = v.replace("##provider##", provider.toUpperCase());
-    
-    if (TbSync.providers.defaultProviders.hasOwnProperty(provider)) {
-      window.document.getElementById("link").textContent = TbSync.providers.defaultProviders[provider].homepageUrl;
-      window.document.getElementById("link").setAttribute("link", TbSync.providers.defaultProviders[provider].homepageUrl);
-    }
-    
-  },    
-};
+/*
+ * This file is part of TbSync.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. 
+ */
+ 
+"use strict";
+
+var { ExtensionParent } = ChromeUtils.importESModule(
+  "resource://gre/modules/ExtensionParent.sys.mjs"
+);
+
+var tbsyncExtension = ExtensionParent.GlobalManager.getExtension(
+  "tbsync at jobisoft.de"
+);
+var { TbSync } = ChromeUtils.importESModule(
+  `chrome://tbsync/content/tbsync.sys.mjs?${tbsyncExtension.manifest.version}`
+);
+
+var tbSyncManageProvider = {
+  
+  prepInstall: function () {
+    let url = window.location.toString();
+    let provider = url.split("provider=")[1];
+    window.document.getElementById("header").textContent = TbSync.getString("installProvider.header::" + TbSync.providers.defaultProviders[provider].name);
+
+    window.document.getElementById("link").textContent = TbSync.providers.defaultProviders[provider].homepageUrl;
+    window.document.getElementById("link").setAttribute("link", TbSync.providers.defaultProviders[provider].homepageUrl);
+
+    window.document.getElementById("warning").hidden = TbSync.providers.defaultProviders[provider].homepageUrl.startsWith("https://addons.thunderbird.net"); 
+  },
+
+  prepMissing: function () {
+    let url = window.location.toString();
+    let provider = url.split("provider=")[1];
+
+    let e = window.document.getElementById("missing");
+    let v = e.textContent;
+    e.textContent = v.replace("##provider##", provider.toUpperCase());
+    
+    if (TbSync.providers.defaultProviders.hasOwnProperty(provider)) {
+      window.document.getElementById("link").textContent = TbSync.providers.defaultProviders[provider].homepageUrl;
+      window.document.getElementById("link").setAttribute("link", TbSync.providers.defaultProviders[provider].homepageUrl);
+    }
+    
+  },    
+};
diff -Nru tbsync-4.12/content/manager/manager.css tbsync-4.16/content/manager/manager.css
--- tbsync-4.12/content/manager/manager.css	2024-08-27 18:32:08.000000000 +0200
+++ tbsync-4.16/content/manager/manager.css	2021-08-30 18:31:42.000000000 +0200
@@ -1,38 +1,38 @@
-#manager {
-    margin:8px 12px 12px 12px;
-}
-
-#tbtoolbar {
-    border:1px solid darkgrey;
-    background-color: #ffffff; 
-    padding: 0; 
-    margin:0 0 12px 0;
-}
-
-#tbtoolbar vbox  {
-    margin: 0;
-    padding:6px 6px 2px 6px;
-    background-color: #ffffff;
-}
-
-#tbtoolbar vbox:hover  {
-    background-color: #e0e8f6;
-}
-
-#tbtoolbar vbox[active="true"]  {
-    background-color: #c1d2ee;
-}
-
-#mainframe {
-    padding:0 12px;
-    margin:0;
-}
-
-.row vbox {
-    width:140px;
-}
-
-iframe {
-    margin:0;
-    padding:0;
-}
+#manager {
+    margin:8px 12px 12px 12px;
+}
+
+#tbtoolbar {
+    border:1px solid darkgrey;
+    background-color: #ffffff; 
+    padding: 0; 
+    margin:0 0 12px 0;
+}
+
+#tbtoolbar vbox  {
+    margin: 0;
+    padding:6px 6px 2px 6px;
+    background-color: #ffffff;
+}
+
+#tbtoolbar vbox:hover  {
+    background-color: #e0e8f6;
+}
+
+#tbtoolbar vbox[active="true"]  {
+    background-color: #c1d2ee;
+}
+
+#mainframe {
+    padding:0 12px;
+    margin:0;
+}
+
+.row vbox {
+    width:140px;
+}
+
+iframe {
+    margin:0;
+    padding:0;
+}
diff -Nru tbsync-4.12/content/manager/missingProvider.xhtml tbsync-4.16/content/manager/missingProvider.xhtml
--- tbsync-4.12/content/manager/missingProvider.xhtml	2024-08-27 18:32:08.000000000 +0200
+++ tbsync-4.16/content/manager/missingProvider.xhtml	2021-08-30 18:31:42.000000000 +0200
@@ -1,21 +1,21 @@
-<?xml version="1.0" encoding="utf-8"?>
-<?xml-stylesheet href="chrome://global/skin/global.css" type="text/css"?>
-
-<window
-    xmlns:html="http://www.w3.org/1999/xhtml"
-    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
-    xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
-    onload="tbSyncManageProvider.prepMissing();"
-    title="TbSync Account Settings" >
-
-    <hbox flex="1" pack="center">
-        <vbox flex="1" pack="center">
-            <description style="text-align:center" id="missing">__TBSYNCMSG_manager.missingprovider__</description>
-            <html:p id="link" onmouseover="this.style.cursor='pointer'" onmouseout="this.style.cursor='default'" onclick="TbSync.manager.openTBtab(this.getAttribute('link'));" style="color:blue; text-decoration: underline; text-align:center;"></html:p>	             
-        </vbox>
-
-    </hbox>
-
-    <script type="text/javascript" src="chrome://tbsync/content/manager/manageProvider.js" /> 
-    <script type="text/javascript" src="chrome://tbsync/content/scripts/locales.js" /> 
-</window>
+<?xml version="1.0" encoding="utf-8"?>
+<?xml-stylesheet href="chrome://global/skin/global.css" type="text/css"?>
+
+<window
+    xmlns:html="http://www.w3.org/1999/xhtml"
+    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+    xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+    onload="tbSyncManageProvider.prepMissing();"
+    title="TbSync Account Settings" >
+
+    <hbox flex="1" pack="center">
+        <vbox flex="1" pack="center">
+            <description style="text-align:center" id="missing">__TBSYNCMSG_manager.missingprovider__</description>
+            <html:p id="link" onmouseover="this.style.cursor='pointer'" onmouseout="this.style.cursor='default'" onclick="TbSync.manager.openTBtab(this.getAttribute('link'));" style="color:blue; text-decoration: underline; text-align:center;"></html:p>	             
+        </vbox>
+
+    </hbox>
+
+    <script type="text/javascript" src="chrome://tbsync/content/manager/manageProvider.js" /> 
+    <script type="text/javascript" src="chrome://tbsync/content/scripts/locales.js" /> 
+</window>
diff -Nru tbsync-4.12/content/manager/noaccounts.xhtml tbsync-4.16/content/manager/noaccounts.xhtml
--- tbsync-4.12/content/manager/noaccounts.xhtml	2024-08-27 18:32:08.000000000 +0200
+++ tbsync-4.16/content/manager/noaccounts.xhtml	2021-08-30 18:31:42.000000000 +0200
@@ -1,17 +1,17 @@
-<?xml version="1.0" encoding="utf-8"?>
-<?xml-stylesheet href="chrome://global/skin/global.css" type="text/css"?>
-
-<window
-    xmlns:html="http://www.w3.org/1999/xhtml"
-    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
-    xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
-    title="TbSync Account Settings" >
-
-    <hbox flex="1" pack="center">
-        <vbox flex="1" pack="center">
-             <description style="text-align:center">__TBSYNCMSG_manager.noaccounts__</description>	     
-        </vbox>
-    </hbox>
-    
-    <script type="text/javascript" src="chrome://tbsync/content/scripts/locales.js" /> 
-</window>
+<?xml version="1.0" encoding="utf-8"?>
+<?xml-stylesheet href="chrome://global/skin/global.css" type="text/css"?>
+
+<window
+    xmlns:html="http://www.w3.org/1999/xhtml"
+    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+    xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+    title="TbSync Account Settings" >
+
+    <hbox flex="1" pack="center">
+        <vbox flex="1" pack="center">
+             <description style="text-align:center">__TBSYNCMSG_manager.noaccounts__</description>	     
+        </vbox>
+    </hbox>
+    
+    <script type="text/javascript" src="chrome://tbsync/content/scripts/locales.js" /> 
+</window>
diff -Nru tbsync-4.12/content/manager/supporter.xhtml tbsync-4.16/content/manager/supporter.xhtml
--- tbsync-4.12/content/manager/supporter.xhtml	2024-08-27 18:32:08.000000000 +0200
+++ tbsync-4.16/content/manager/supporter.xhtml	2021-10-12 13:03:06.000000000 +0200
@@ -1,77 +1,77 @@
-<?xml version="1.0" encoding="utf-8"?>
-<?xml-stylesheet href="chrome://global/skin/global.css" type="text/css"?>
-<?xml-stylesheet href="chrome://tbsync/content/manager/manager.css" type="text/css"?>
-
-<window 
-    xmlns:html="http://www.w3.org/1999/xhtml"
-    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
-    xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
-    onload="tbSyncAccountManager.initCommunity();"
-    title="Community" >
-
-    <hbox flex="1" id="mainframe">
-        <vbox flex="1">
-            <html:p>
-                <html:b>__TBSYNCMSG_manager.supporter.contributors__</html:b>
-                <html:div id="listOfContributors" style="margin-top:10px">
-
-                  <html:div provider="" style="width:225px; margin: 0 0 10px 0; float:left;">
-                    <html:img 
-                    src="" 
-                    style="width:48px; height:48px; margin:4px 0 0 10px; float:left" 
-                    onclick="TbSync.manager.openLink(TbSync.providers.loadedProviders[this.parentNode.getAttribute('provider')].addon.homepageURL);" 
-                    onmouseover="this.style.cursor='pointer'" 
-                    onmouseout="this.style.cursor='default'" />
-                    <html:div style="padding-left: 65px;">
-                      <html:div>__TBSYNCMSG_manager.title__</html:div>
-                      <html:div style="font-style:italic">__TBSYNCMSG_manager.provider4tbsync__</html:div>
-                      <html:div style="font-style:italic;">[<html:span 
-                      onclick="TbSync.manager.openLink(TbSync.providers.loadedProviders[this.parentNode.parentNode.parentNode.getAttribute('provider')].addon.contributorsURL);" 
-                      onmouseover="this.style.cursor='pointer'" 
-                      onmouseout="this.style.cursor='default'"
-                      style="color:blue;text-decoration: underline;">__TBSYNCMSG_manager.supporter.details__</html:span>]</html:div>
-                    </html:div>
-                  </html:div>
-
-                  <html:div provider="" style="width:225px; margin: 0 0 10px 0; float:left;">
-                    <html:img 
-                    src="chrome://tbsync/content/skin/tbsync64.png" 
-                    style="width:48px; height:48px; margin:4px 0 0 10px; float:left" 
-                    onclick="TbSync.manager.openLink(TbSync.addon.homepageURL);" 
-                    onmouseover="this.style.cursor='pointer'" 
-                    onmouseout="this.style.cursor='default'" />
-                    <html:div style="padding-left: 65px;">
-                      <html:span></html:span>
-                      <html:div>TbSync</html:div>
-                      <html:div style="font-style:italic">__TBSYNCMSG_manager.shorttitle__</html:div>
-                      <html:div style="font-style:italic;">[<html:span 
-                      onclick="TbSync.manager.openLink(TbSync.addon.contributorsURL);" 
-                      onmouseover="this.style.cursor='pointer'" 
-                      onmouseout="this.style.cursor='default'"
-                      style="color:blue;text-decoration: underline;">__TBSYNCMSG_manager.supporter.details__</html:span>]</html:div>
-                    </html:div>
-                  </html:div>
-
-                </html:div> 
-            </html:p>
-
-
-            <html:p>
-                <html:b>__TBSYNCMSG_manager.supporter.sponsors__</html:b>
-                <html:div id="listOfSponsors" style="margin-top:10px">
-                  <html:div link="" style="width:225px; margin: 0 0 10px 0; float:left;">
-                    <html:img src="chrome://tbsync/content/skin/user48.png" style="width:48px; height:48px; padding:0px; margin:0 0 0 10px; border:1px solid #d3d3d3; float:left" onclick="if (this.parentNode.getAttribute('link') != '') {TbSync.manager.openLink(this.parentNode.getAttribute('link'));}" onmouseover="if (this.parentNode.getAttribute('link') != '') {this.style.cursor='pointer'}" onmouseout="this.style.cursor='default'" />
-                    <html:div style="padding-left: 65px;">
-                      <html:div >Name</html:div>
-                      <html:div style="font-style:italic">Description</html:div>
-                    </html:div>
-                  </html:div>
-                </html:div> 
-            </html:p>
-            
-        </vbox>
-    </hbox>
-    
-    <script type="text/javascript" src="chrome://tbsync/content/manager/accountManager.js" /> 
-    <script type="text/javascript" src="chrome://tbsync/content/scripts/locales.js" /> 
-</window>
+<?xml version="1.0" encoding="utf-8"?>
+<?xml-stylesheet href="chrome://global/skin/global.css" type="text/css"?>
+<?xml-stylesheet href="chrome://tbsync/content/manager/manager.css" type="text/css"?>
+
+<window 
+    xmlns:html="http://www.w3.org/1999/xhtml"
+    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+    xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+    onload="tbSyncAccountManager.initCommunity();"
+    title="Community" >
+
+    <hbox flex="1" id="mainframe">
+        <vbox flex="1">
+            <html:p>
+                <html:b>__TBSYNCMSG_manager.supporter.contributors__</html:b>
+                <html:div id="listOfContributors" style="margin-top:10px">
+
+                  <html:div provider="" style="width:225px; margin: 0 0 10px 0; float:left;">
+                    <html:img 
+                    src="" 
+                    style="width:48px; height:48px; margin:4px 0 0 10px; float:left" 
+                    onclick="TbSync.manager.openLink(TbSync.providers.loadedProviders[this.parentNode.getAttribute('provider')].addon.homepageURL);" 
+                    onmouseover="this.style.cursor='pointer'" 
+                    onmouseout="this.style.cursor='default'" />
+                    <html:div style="padding-left: 65px;">
+                      <html:div>__TBSYNCMSG_manager.title__</html:div>
+                      <html:div style="font-style:italic">__TBSYNCMSG_manager.provider4tbsync__</html:div>
+                      <html:div style="font-style:italic;">[<html:span 
+                      onclick="TbSync.manager.openLink(TbSync.providers.loadedProviders[this.parentNode.parentNode.parentNode.getAttribute('provider')].addon.contributorsURL);" 
+                      onmouseover="this.style.cursor='pointer'" 
+                      onmouseout="this.style.cursor='default'"
+                      style="color:blue;text-decoration: underline;">__TBSYNCMSG_manager.supporter.details__</html:span>]</html:div>
+                    </html:div>
+                  </html:div>
+
+                  <html:div provider="" style="width:225px; margin: 0 0 10px 0; float:left;">
+                    <html:img 
+                    src="chrome://tbsync/content/skin/tbsync64.png" 
+                    style="width:48px; height:48px; margin:4px 0 0 10px; float:left" 
+                    onclick="TbSync.manager.openLink(TbSync.addon.homepageURL);" 
+                    onmouseover="this.style.cursor='pointer'" 
+                    onmouseout="this.style.cursor='default'" />
+                    <html:div style="padding-left: 65px;">
+                      <html:span></html:span>
+                      <html:div>TbSync</html:div>
+                      <html:div style="font-style:italic">__TBSYNCMSG_manager.shorttitle__</html:div>
+                      <html:div style="font-style:italic;">[<html:span 
+                      onclick="TbSync.manager.openLink(TbSync.addon.contributorsURL);" 
+                      onmouseover="this.style.cursor='pointer'" 
+                      onmouseout="this.style.cursor='default'"
+                      style="color:blue;text-decoration: underline;">__TBSYNCMSG_manager.supporter.details__</html:span>]</html:div>
+                    </html:div>
+                  </html:div>
+
+                </html:div> 
+            </html:p>
+
+
+            <html:p>
+                <html:b>__TBSYNCMSG_manager.supporter.sponsors__</html:b>
+                <html:div id="listOfSponsors" style="margin-top:10px">
+                  <html:div link="" style="width:225px; margin: 0 0 10px 0; float:left;">
+                    <html:img src="chrome://tbsync/content/skin/user48.png" style="width:48px; height:48px; padding:0px; margin:0 0 0 10px; border:1px solid #d3d3d3; float:left" onclick="if (this.parentNode.getAttribute('link') != '') {TbSync.manager.openLink(this.parentNode.getAttribute('link'));}" onmouseover="if (this.parentNode.getAttribute('link') != '') {this.style.cursor='pointer'}" onmouseout="this.style.cursor='default'" />
+                    <html:div style="padding-left: 65px;">
+                      <html:div >Name</html:div>
+                      <html:div style="font-style:italic">Description</html:div>
+                    </html:div>
+                  </html:div>
+                </html:div> 
+            </html:p>
+            
+        </vbox>
+    </hbox>
+    
+    <script type="text/javascript" src="chrome://tbsync/content/manager/accountManager.js" /> 
+    <script type="text/javascript" src="chrome://tbsync/content/scripts/locales.js" /> 
+</window>
diff -Nru tbsync-4.12/content/manager/support-wizard/support-wizard.xhtml tbsync-4.16/content/manager/support-wizard/support-wizard.xhtml
--- tbsync-4.12/content/manager/support-wizard/support-wizard.xhtml	2024-08-27 18:32:08.000000000 +0200
+++ tbsync-4.16/content/manager/support-wizard/support-wizard.xhtml	2021-08-30 18:31:42.000000000 +0200
@@ -1,44 +1,44 @@
-<?xml version="1.0"?>
-<?xml-stylesheet href="chrome://global/skin/global.css" type="text/css"?>
-
-<window
-  width="500"
-  height="600"
-  onload="tbSyncAccountManager.initSupportWizard();"
-  xmlns:html="http://www.w3.org/1999/xhtml"
-  xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
-
-  <linkset>
-    <html:link rel="localization" href="toolkit/global/wizard.ftl"/>
-  </linkset>
-  
-  <wizard 
-    id="SupportWizard" 
-    title="__TBSYNCMSG_supportwizard.title__">
-     
-    <wizardpage onFirstPage="true" label="__TBSYNCMSG_supportwizard.pagetitle__">
-      <label value="__TBSYNCMSG_supportwizard.label.faultycomponent__"/>
-      <menulist id="tbsync.supportwizard.faultycomponent.menulist">
-        <menupopup id="tbsync.supportwizard.faultycomponent">
-          <menuitem hidden="true" selected="true" label="__TBSYNCMSG_supportwizard.label.selectcomponent__" value="" />
-          <menuitem label="__TBSYNCMSG_manager.title__" value="core" />
-        </menupopup>
-      </menulist>    
-
-      <label style="margin-top:1em" value="__TBSYNCMSG_supportwizard.label.summary__"/>
-     <html:input id="tbsync.supportwizard.summary" oninput="tbSyncAccountManager.checkSupportWizard()" />
-    
-     <label style="margin-top:1em" value="__TBSYNCMSG_supportwizard.label.description__"/>
-     <html:textarea rows="15" style="margin-left: 1ex;" id="tbsync.supportwizard.description" />
-
-     <description style="margin-top:1em">
-      __TBSYNCMSG_supportwizard.footer__
-     </description>  
-    </wizardpage>
-
-  </wizard>
-
-  <script type="text/javascript" src="chrome://tbsync/content/manager/accountManager.js" /> 
-  <script type="text/javascript" src="chrome://tbsync/content/scripts/locales.js" /> 
-
-</window>
+<?xml version="1.0"?>
+<?xml-stylesheet href="chrome://global/skin/global.css" type="text/css"?>
+
+<window
+  width="500"
+  height="600"
+  onload="tbSyncAccountManager.initSupportWizard();"
+  xmlns:html="http://www.w3.org/1999/xhtml"
+  xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+  <linkset>
+    <html:link rel="localization" href="toolkit/global/wizard.ftl"/>
+  </linkset>
+  
+  <wizard 
+    id="SupportWizard" 
+    title="__TBSYNCMSG_supportwizard.title__">
+     
+    <wizardpage onFirstPage="true" label="__TBSYNCMSG_supportwizard.pagetitle__">
+      <label value="__TBSYNCMSG_supportwizard.label.faultycomponent__"/>
+      <menulist id="tbsync.supportwizard.faultycomponent.menulist">
+        <menupopup id="tbsync.supportwizard.faultycomponent">
+          <menuitem hidden="true" selected="true" label="__TBSYNCMSG_supportwizard.label.selectcomponent__" value="" />
+          <menuitem label="__TBSYNCMSG_manager.title__" value="core" />
+        </menupopup>
+      </menulist>    
+
+      <label style="margin-top:1em" value="__TBSYNCMSG_supportwizard.label.summary__"/>
+     <html:input id="tbsync.supportwizard.summary" oninput="tbSyncAccountManager.checkSupportWizard()" />
+    
+     <label style="margin-top:1em" value="__TBSYNCMSG_supportwizard.label.description__"/>
+     <html:textarea rows="15" style="margin-left: 1ex;" id="tbsync.supportwizard.description" />
+
+     <description style="margin-top:1em">
+      __TBSYNCMSG_supportwizard.footer__
+     </description>  
+    </wizardpage>
+
+  </wizard>
+
+  <script type="text/javascript" src="chrome://tbsync/content/manager/accountManager.js" /> 
+  <script type="text/javascript" src="chrome://tbsync/content/scripts/locales.js" /> 
+
+</window>
diff -Nru tbsync-4.12/content/modules/addressbook.js tbsync-4.16/content/modules/addressbook.js
--- tbsync-4.12/content/modules/addressbook.js	2024-08-27 18:32:08.000000000 +0200
+++ tbsync-4.16/content/modules/addressbook.js	2025-03-15 23:50:32.000000000 +0100
@@ -1,1137 +1,1151 @@
-/*
- * This file is part of TbSync.
- *
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. 
- */
-
-"use strict";
-
-var { MailServices } = ChromeUtils.import("resource:///modules/MailServices.jsm");
-var { AddrBookCard } = ChromeUtils.import("resource:///modules/AddrBookCard.jsm");
-
-ChromeUtils.defineESModuleGetters(this, {
-  FileUtils: "resource://gre/modules/FileUtils.sys.mjs",
-});
-
-var addressbook = {
-
-  _notifications: [
-    "addrbook-directory-updated",
-    "addrbook-directory-deleted",
-    "addrbook-contact-created",
-    "addrbook-contact-updated",
-    "addrbook-contact-deleted",
-    "addrbook-list-member-added",
-    "addrbook-list-member-removed",
-    "addrbook-list-deleted",
-    "addrbook-list-updated",
-    "addrbook-list-created"
-  ],
-
-  load: async function () {
-    for (let topic of this._notifications) {
-      Services.obs.addObserver(this.addressbookObserver, topic);
-    }
-  },
-
-  unload: async function () {
-    for (let topic of this._notifications) {
-      Services.obs.removeObserver(this.addressbookObserver, topic);
-    }
-  },
-
-  getStringValue: function (ab, value, fallback) {
-    try {
-      return ab.getStringValue(value, fallback);
-    } catch (e) {
-      return fallback;
-    }
-  },
-
-  searchDirectory: function (uri, search) {
-    return new Promise((resolve, reject) => {
-      let listener = {
-        cards: [],
-
-        onSearchFinished(aResult, aErrorMsg) {
-          resolve(this.cards);
-        },
-        onSearchFoundCard(aCard) {
-          this.cards.push(aCard.QueryInterface(Components.interfaces.nsIAbCard));
-        }
-      }
-
-      let result = MailServices.ab.getDirectory(uri).search(search, "", listener);
-    });
-  },
-
-
-  // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
-  // * AdvancedTargetData, an extended TargetData implementation, providers
-  // * can use this as their own TargetData by extending it and just
-  // * defining the extra methods
-  // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
-
-  AdvancedTargetData: class {
-    constructor(folderData) {
-      this._folderData = folderData;
-      this._targetObj = null;
-    }
-
-
-    // Check, if the target exists and return true/false.
-    hasTarget() {
-      let target = this._folderData.getFolderProperty("target");
-      let directory = TbSync.addressbook.getDirectoryFromDirectoryUID(target);
-      return directory ? true : false;
-    }
-
-    // Returns the target obj, which TbSync should return as the target. It can
-    // be whatever you want and is returned by FolderData.targetData.getTarget().
-    // If the target does not exist, it should be created. Throw a simple Error, if that
-    // failed.
-    async getTarget() {
-      let target = this._folderData.getFolderProperty("target");
-      let directory = TbSync.addressbook.getDirectoryFromDirectoryUID(target);
-
-      if (!directory) {
-        // create a new addressbook and store its UID in folderData
-        directory = await TbSync.addressbook.prepareAndCreateAddressbook(this._folderData);
-        if (!directory)
-          throw new Error("notargets");
-      }
-
-      if (!this._targetObj || this._targetObj.UID != directory.UID)
-        this._targetObj = new TbSync.addressbook.AbDirectory(directory, this._folderData);
-
-      return this._targetObj;
-    }
-
-    /**
-     * Removes the target from the local storage. If it does not exist, return
-     * silently. A call to ``hasTarget()`` should return false, after this has
-     * been executed.
-     *
-     */
-    removeTarget() {
-      let target = this._folderData.getFolderProperty("target");
-      let directory = TbSync.addressbook.getDirectoryFromDirectoryUID(target);
-      try {
-        if (directory) {
-          MailServices.ab.deleteAddressBook(directory.URI);
-        }
-      } catch (e) { }
-
-      TbSync.db.clearChangeLog(target);
-      this._folderData.resetFolderProperty("target");
-    }
-
-    /**
-     * Disconnects the target in the local storage from this TargetData, but
-     * does not delete it, so it becomes a stale "left over" . A call
-     * to ``hasTarget()`` should return false, after this has been executed.
-     * 
-     */
-    disconnectTarget() {
-      let target = this._folderData.getFolderProperty("target");
-      let directory = TbSync.addressbook.getDirectoryFromDirectoryUID(target);
-      if (directory) {
-        let changes = TbSync.db.getItemsFromChangeLog(target, 0, "_by_user");
-        if (changes.length > 0) {
-          this.targetName = this.targetName + " (*)";
-        }
-        directory.setStringValue("tbSyncIcon", "orphaned");
-        directory.setStringValue("tbSyncProvider", "orphaned");
-        directory.setStringValue("tbSyncAccountID", "");
-      }
-      TbSync.db.clearChangeLog(target);
-      this._folderData.resetFolderProperty("target");
-    }
-
-    set targetName(newName) {
-      let target = this._folderData.getFolderProperty("target");
-      let directory = TbSync.addressbook.getDirectoryFromDirectoryUID(target);
-      if (directory) {
-        directory.dirName = newName;
-      } else {
-        throw new Error("notargets");
-      }
-    }
-
-    get targetName() {
-      let target = this._folderData.getFolderProperty("target");
-      let directory = TbSync.addressbook.getDirectoryFromDirectoryUID(target);
-      if (directory) {
-        return directory.dirName;
-      } else {
-        throw new Error("notargets");
-      }
-    }
-
-    setReadOnly(value) {
-    }
-
-
-    // * * * * * * * * * * * * * * * * *
-    // * AdvancedTargetData extension  * 
-    // * * * * * * * * * * * * * * * * *
-
-    get isAdvancedAddressbookTargetData() {
-      return true;
-    }
-
-    get folderData() {
-      return this._folderData;
-    }
-
-    // define a card property, which should be used for the changelog
-    // basically your primary key for the abItem properties
-    // UID will be used, if nothing specified
-    get primaryKeyField() {
-      return "UID";
-    }
-
-    generatePrimaryKey() {
-      return TbSync.generateUUID();
-    }
-
-    // enable or disable changelog
-    get logUserChanges() {
-      return true;
-    }
-
-    directoryObserver(aTopic) {
-      switch (aTopic) {
-        case "addrbook-directory-deleted":
-        case "addrbook-directory-updated":
-          //Services.console.logStringMessage("["+ aTopic + "] " + folderData.getFolderProperty("foldername"));
-          break;
-      }
-    }
-
-    cardObserver(aTopic, abCardItem) {
-      switch (aTopic) {
-        case "addrbook-contact-updated":
-        case "addrbook-contact-deleted":
-        case "addrbook-contact-created":
-          //Services.console.logStringMessage("["+ aTopic + "] " + abCardItem.getProperty("DisplayName"));
-          break;
-      }
-    }
-
-    listObserver(aTopic, abListItem, abListMember) {
-      switch (aTopic) {
-        case "addrbook-list-member-added":
-        case "addrbook-list-member-removed":
-          //Services.console.logStringMessage("["+ aTopic + "] MemberName: " + abListMember.getProperty("DisplayName"));
-          break;
-
-        case "addrbook-list-deleted":
-        case "addrbook-list-updated":
-          //Services.console.logStringMessage("["+ aTopic + "] ListName: " + abListItem.getProperty("ListName"));
-          break;
-
-        case "addrbook-list-created":
-          //Services.console.logStringMessage("["+ aTopic + "] Created new X-DAV-UID for List <"+abListItem.getProperty("ListName")+">");
-          break;
-      }
-    }
-
-    // replace this with your own implementation to create the actual addressbook,
-    // when this class is extended
-    async createAddressbook(newname) {
-      // https://searchfox.org/comm-central/source/mailnews/addrbook/src/nsDirPrefs.h
-      let dirPrefId = MailServices.ab.newAddressBook(newname, "", 101);
-      let directory = MailServices.ab.getDirectoryFromId(dirPrefId);
-      return directory;
-    }
-  },
-
-
-
-
-
-  // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
-  // * AbItem and AbDirectory Classes
-  // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
-
-  AbItem: class {
-    constructor(abDirectory, item) {
-      if (!abDirectory)
-        throw new Error("AbItem::constructor is missing its first parameter!");
-
-      if (!item)
-        throw new Error("AbItem::constructor is missing its second parameter!");
-
-      this._abDirectory = abDirectory;
-      this._card = null;
-      this._tempListDirectory = null;
-      this._tempProperties = null;
-      this._isMailList = false;
-
-      if (item instanceof Components.interfaces.nsIAbDirectory) {
-        this._tempListDirectory = item;
-        this._isMailList = true;
-        this._tempProperties = {};
-      } else {
-        this._card = item;
-        this._isMailList = item.isMailList;
-      }
-    }
-
-    get abDirectory() {
-      return this._abDirectory;
-    }
-
-    get isMailList() {
-      return this._isMailList;
-    }
-
-
-
-
-
-    get nativeItem() {
-      return this._card;
-    }
-
-    get UID() {
-      if (this._tempListDirectory) return this._tempListDirectory.UID;
-      return this._card.UID;
-    }
-
-    get primaryKey() {
-      //use UID as fallback
-      let key = this._abDirectory.primaryKeyField;
-      return key ? this.getProperty(key) : this.UID;
-    }
-
-    set primaryKey(value) {
-      //use UID as fallback
-      let key = this._abDirectory.primaryKeyField;
-      if (key) this.setProperty(key, value)
-      else throw ("TbSync.addressbook.AbItem.set primaryKey: UID is used as primaryKeyField but changing the UID of an item is currently not supported. Please use a custom primaryKeyField.");
-    }
-
-    clone() { //no real clone ... this is just here to match the calendar target
-      return new TbSync.addressbook.AbItem(this._abDirectory, this._card);
-    }
-
-    toString() {
-      return this._card.displayName + " (" + this._card.firstName + ", " + this._card.lastName + ") <" + this._card.primaryEmail + ">";
-    }
-
-    // mailinglist aware method to get properties of cards
-    // mailinglist properties cannot be stored in mailinglists themselves, so we store them in changelog
-    getProperty(property, fallback = "") {
-      if (property == "UID")
-        return this.UID;
-
-      if (this._isMailList) {
-        const directListProperties = {
-          ListName: "dirName",
-          ListNickName: "listNickName",
-          ListDescription: "description"
-        };
-
-        let value;
-        if (directListProperties.hasOwnProperty(property)) {
-          try {
-            let mailListDirectory = this._tempListDirectory || MailServices.ab.getDirectory(this._card.mailListURI); //this._card.asDirectory
-            value = mailListDirectory[directListProperties[property]];
-          } catch (e) {
-            // list does not exists
-          }
-        } else {
-          value = this._tempProperties ? this._tempProperties[property] : TbSync.db.getItemStatusFromChangeLog(this._abDirectory.UID + "#" + this.UID, property);
-        }
-        return value || fallback;
-      } else {
-        return this._card.getProperty(property, fallback);
-      }
-    }
-
-    // mailinglist aware method to set properties of cards
-    // mailinglist properties cannot be stored in mailinglists themselves, so we store them in changelog
-    // while the list has not been added, we keep all props in an object (UID changes on adding)
-    setProperty(property, value) {
-      // UID cannot be changed (currently)
-      if (property == "UID") {
-        throw ("TbSync.addressbook.AbItem.setProperty: UID cannot be changed currently.");
-        return;
-      }
-
-      if (this._isMailList) {
-        const directListProperties = {
-          ListName: "dirName",
-          ListNickName: "listNickName",
-          ListDescription: "description"
-        };
-
-        if (directListProperties.hasOwnProperty(property)) {
-          try {
-            let mailListDirectory = this._tempListDirectory || MailServices.ab.getDirectory(this._card.mailListURI);
-            mailListDirectory[directListProperties[property]] = value;
-          } catch (e) {
-            // list does not exists
-          }
-        } else {
-          if (this._tempProperties) {
-            this._tempProperties[property] = value;
-          } else {
-            TbSync.db.addItemToChangeLog(this._abDirectory.UID + "#" + this.UID, property, value);
-          }
-        }
-      } else {
-        this._card.setProperty(property, value);
-      }
-    }
-
-    deleteProperty(property) {
-      if (this._isMailList) {
-        if (this._tempProperties) {
-          delete this._tempProperties[property];
-        } else {
-          TbSync.db.removeItemFromChangeLog(this._abDirectory.UID + "#" + this.UID, property);
-        }
-      } else {
-        this._card.deleteProperty(property);
-      }
-    }
-
-    get changelogData() {
-      return TbSync.db.getItemDataFromChangeLog(this._abDirectory.UID, this.primaryKey);
-    }
-
-    get changelogStatus() {
-      return TbSync.db.getItemStatusFromChangeLog(this._abDirectory.UID, this.primaryKey);
-    }
-
-    set changelogStatus(status) {
-      let value = this.primaryKey;
-
-      if (value) {
-        if (!status) {
-          TbSync.db.removeItemFromChangeLog(this._abDirectory.UID, value);
-          return;
-        }
-
-        if (this._abDirectory.logUserChanges || status.endsWith("_by_server")) {
-          TbSync.db.addItemToChangeLog(this._abDirectory.UID, value, status);
-        }
-      }
-    }
-
-
-
-
-
-    // get the property given from all members and return it as an array (that property better be uniqe)
-    getMembersPropertyList(property) {
-      let members = [];
-      if (this._card && this._card.isMailList) {
-        // get mailListDirectory
-        let mailListDirectory = MailServices.ab.getDirectory(this._card.mailListURI);
-        for (let member of mailListDirectory.childCards) {
-          let prop = member.getProperty(property, "");
-          if (prop) members.push(prop);
-        }
-      }
-      return members;
-    }
-
-    addListMembers(property, candidates) {
-      if (this._card && this._card.isMailList) {
-        let members = this.getMembersPropertyList(property);
-        let mailListDirectory = MailServices.ab.getDirectory(this._card.mailListURI);
-
-        for (let candidate of candidates) {
-          if (members.includes(candidate))
-            continue;
-
-          let card = this._abDirectory._directory.getCardFromProperty(property, candidate, true);
-          if (card) mailListDirectory.addCard(card);
-        }
-      }
-    }
-
-    removeListMembers(property, candidates) {
-      if (this._card && this._card.isMailList) {
-        let members = this.getMembersPropertyList(property);
-        let mailListDirectory = MailServices.ab.getDirectory(this._card.mailListURI);
-
-        let cardsToRemove = [];
-        for (let candidate of candidates) {
-          if (!members.includes(candidate))
-            continue;
-
-          let card = this._abDirectory._directory.getCardFromProperty(property, candidate, true);
-          if (card) cardsToRemove.push(card);
-        }
-        if (cardsToRemove.length > 0) mailListDirectory.deleteCards(cardsToRemove);
-      }
-    }
-
-    addPhoto(photo, data, extension = "jpg", url = "") {
-      let card = this._card;
-      let bookUID = this.abDirectory.UID;
-
-      let book64 = btoa(bookUID);
-      let photo64 = btoa(photo);
-      let photoName64 = book64 + "_" + photo64 + "." + extension;
-
-      let file = new FileUtils.File(PathUtils.join(PathUtils.profileDir, "Photos", photoName64));
-      let foStream = Components.classes["@mozilla.org/network/file-output-stream;1"].createInstance(Components.interfaces.nsIFileOutputStream);
-      foStream.init(file, 0x02 | 0x08 | 0x20, 0x180, 0); // write, create, truncate
-      let binary = "";
-      try {
-        binary = atob(data.split(" ").join(""));
-      } catch (e) {
-        console.log("Failed to decode base64 string:", data);
-      }
-      foStream.write(binary, binary.length);
-      foStream.close();
-
-      let filePath = 'file:///' + file.path.replace(/\\/g, '\/').replace(/^\s*\/?/, '').replace(/\ /g, '%20');
-      card.setProperty("PhotoName", photoName64);
-      card.setProperty("PhotoType", url ? "web" : "file");
-      card.setProperty("PhotoURI", url ? url : filePath);
-      return filePath;
-    }
-
-    getPhoto() {
-      let card = this._card;
-      let photo = card.getProperty("PhotoName", "");
-      let data = "";
-
-      if (photo) {
-        try {
-          let file = new FileUtils.File(PathUtils.join(PathUtils.profileDir, "Photos", photo));
-
-          let fiStream = Components.classes["@mozilla.org/network/file-input-stream;1"].createInstance(Components.interfaces.nsIFileInputStream);
-          fiStream.init(file, -1, -1, false);
-
-          let bstream = Components.classes["@mozilla.org/binaryinputstream;1"].createInstance(Components.interfaces.nsIBinaryInputStream);
-          bstream.setInputStream(fiStream);
-
-          data = btoa(bstream.readBytes(bstream.available()));
-          fiStream.close();
-        } catch (e) { }
-      }
-      return data;
-    }
-  },
-
-  AbDirectory: class {
-    constructor(directory, folderData) {
-      this._directory = directory;
-      this._folderData = folderData;
-    }
-
-    get directory() {
-      return this._directory;
-    }
-
-    get logUserChanges() {
-      return this._folderData.targetData.logUserChanges;
-    }
-
-    get primaryKeyField() {
-      return this._folderData.targetData.primaryKeyField;
-    }
-
-    get UID() {
-      return this._directory.UID;
-    }
-
-    get URI() {
-      return this._directory.URI;
-    }
-
-    createNewCard() {
-      let card = new AddrBookCard();
-      return new TbSync.addressbook.AbItem(this, card);
-    }
-
-    createNewList() {
-      let listDirectory = Components.classes["@mozilla.org/addressbook/directoryproperty;1"].createInstance(Components.interfaces.nsIAbDirectory);
-      listDirectory.isMailList = true;
-      return new TbSync.addressbook.AbItem(this, listDirectory);
-    }
-
-    async addItem(abItem, pretagChangelogWithByServerEntry = true) {
-      if (this.primaryKeyField && !abItem.getProperty(this.primaryKeyField)) {
-        abItem.setProperty(this.primaryKeyField, this._folderData.targetData.generatePrimaryKey());
-        //Services.console.logStringMessage("[AbDirectory::addItem] Generated primary key!");
-      }
-
-      if (pretagChangelogWithByServerEntry) {
-        abItem.changelogStatus = "added_by_server";
-      }
-
-      if (abItem.isMailList && abItem._tempListDirectory) {
-        let list = this._directory.addMailList(abItem._tempListDirectory);
-        // the list has been added and we can now get the corresponding card via its UID
-        let found = await this.getItemFromProperty("UID", list.UID);
-
-        // clone and clear temporary properties
-        let props = { ...abItem._tempProperties };
-        abItem._tempListDirectory = null;
-        abItem._tempProperties = null;
-
-        // store temporary properties
-        for (const [property, value] of Object.entries(props)) {
-          found.setProperty(property, value);
-        }
-
-        abItem._card = found._card;
-      } else if (!abItem.isMailList) {
-        this._directory.addCard(abItem._card);
-
-      } else {
-        throw new Error("Cannot re-add a list to a directory.");
-      }
-    }
-
-    modifyItem(abItem, pretagChangelogWithByServerEntry = true) {
-      // only add entry if the current entry does not start with _by_user
-      let status = abItem.changelogStatus ? abItem.changelogStatus : "";
-      if (pretagChangelogWithByServerEntry && !status.endsWith("_by_user")) {
-        abItem.changelogStatus = "modified_by_server";
-      }
-
-      if (abItem.isMailList) {
-        // get mailListDirectory
-        let mailListDirectory = MailServices.ab.getDirectory(abItem._card.mailListURI);
-
-        // store
-        mailListDirectory.editMailListToDatabase(abItem._card);
-      } else {
-        this._directory.modifyCard(abItem._card);
-      }
-    }
-
-    deleteItem(abItem, pretagChangelogWithByServerEntry = true) {
-      if (pretagChangelogWithByServerEntry) {
-        abItem.changelogStatus = "deleted_by_server";
-      }
-      this._directory.deleteCards([abItem._card]);
-    }
-
-    async getItem(searchId) {
-      //use UID as fallback
-      let key = this.primaryKeyField ? this.primaryKeyField : "UID";
-      return await this.getItemFromProperty(key, searchId);
-    }
-
-    async getItemFromProperty(property, value) {
-      // try to use the standard card method first
-      let card = this._directory.getCardFromProperty(property, value, true);
-      if (card) {
-        return new TbSync.addressbook.AbItem(this, card);
-      }
-
-      // search for list cards
-      // we cannot search for the prop directly, because for mailinglists
-      // they are not part of the card (expect UID) but stored in a custom storage
-      let searchList = "(IsMailList,=,TRUE)";
-      let foundCards = await TbSync.addressbook.searchDirectory(this._directory.URI, "(or" + searchList + ")");
-      for (let aCard of foundCards) {
-        let card = new TbSync.addressbook.AbItem(this, aCard);
-        //does this list card have the req prop?
-        if (card.getProperty(property) == value) {
-          return card;
-        }
-      }
-      return null;
-    }
-
-    getAllItems() {
-      let rv = [];
-      for (let card of this._directory.childCards) {
-        rv.push(new TbSync.addressbook.AbItem(this._directory, card));
-      }
-      return rv;
-    }
-
-
-
-
-
-    getAddedItemsFromChangeLog(maxitems = 0) {
-      return TbSync.db.getItemsFromChangeLog(this._directory.UID, maxitems, "added_by_user").map(item => item.itemId);
-    }
-
-    getModifiedItemsFromChangeLog(maxitems = 0) {
-      return TbSync.db.getItemsFromChangeLog(this._directory.UID, maxitems, "modified_by_user").map(item => item.itemId);
-    }
-
-    getDeletedItemsFromChangeLog(maxitems = 0) {
-      return TbSync.db.getItemsFromChangeLog(this._directory.UID, maxitems, "deleted_by_user").map(item => item.itemId);
-    }
-
-    getItemsFromChangeLog(maxitems = 0) { // Document what this returns         
-      return TbSync.db.getItemsFromChangeLog(this._directory.UID, maxitems, "_by_user");
-    }
-
-    removeItemFromChangeLog(id, moveToEndInsteadOfDelete = false) {
-      TbSync.db.removeItemFromChangeLog(this._directory.UID, id, moveToEndInsteadOfDelete);
-    }
-
-    clearChangelog() {
-      TbSync.db.clearChangeLog(this._directory.UID);
-    }
-
-  },
-
-
-
-
-
-  // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
-  // * Internal Functions
-  // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
-
-  prepareAndCreateAddressbook: async function (folderData) {
-    let target = folderData.getFolderProperty("target");
-    let provider = folderData.accountData.getAccountProperty("provider");
-
-    // Get cached or new unique name for new address book
-    let cachedName = folderData.getFolderProperty("targetName");
-    let newname = cachedName == "" ? folderData.accountData.getAccountProperty("accountname") + " (" + folderData.getFolderProperty("foldername") + ")" : cachedName;
-
-    //Create the new book with the unique name
-    let directory = await folderData.targetData.createAddressbook(newname);
-    if (directory && directory instanceof Components.interfaces.nsIAbDirectory) {
-      directory.setStringValue("tbSyncProvider", provider);
-      directory.setStringValue("tbSyncAccountID", folderData.accountData.accountID);
-
-      // Prevent gContactSync to inject its stuff into New/EditCard dialogs
-      // https://github.com/jdgeenen/gcontactsync/pull/127
-      directory.setStringValue("gContactSyncSkipped", "true");
-
-      folderData.setFolderProperty("target", directory.UID);
-      folderData.setFolderProperty("targetName", directory.dirName);
-      //notify about new created address book
-      Services.obs.notifyObservers(null, 'tbsync.observer.addressbook.created', null)
-      return directory;
-    }
-
-    return null;
-  },
-
-  getFolderFromDirectoryUID: function (bookUID) {
-    let folders = TbSync.db.findFolders({ "target": bookUID });
-    if (folders.length == 1) {
-      let accountData = new TbSync.AccountData(folders[0].accountID);
-      return new TbSync.FolderData(accountData, folders[0].folderID);
-    }
-    return null;
-  },
-
-  getDirectoryFromDirectoryUID: function (UID) {
-    if (!UID)
-      return null;
-
-    for (let directory of MailServices.ab.directories) {
-      if (directory instanceof Components.interfaces.nsIAbDirectory) {
-        if (directory.UID == UID) return directory;
-      }
-    }
-    return null;
-  },
-
-  getListInfoFromListUID: async function (UID) {
-    for (let directory of MailServices.ab.directories) {
-      if (directory instanceof Components.interfaces.nsIAbDirectory && !directory.isRemote) {
-        let searchList = "(IsMailList,=,TRUE)";
-        let foundCards = await TbSync.addressbook.searchDirectory(directory.URI, "(and" + searchList + ")");
-        for (let listCard of foundCards) {
-          //return after first found card
-          if (listCard.UID == UID) return { directory, listCard };
-        }
-      }
-    }
-    throw new Error("List with UID <" + UID + "> does not exists");
-  },
-
-
-
-
-
-  // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
-  // * Addressbook Observer and Listener
-  // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
-
-  addressbookObserver: {
-    observe: async function (aSubject, aTopic, aData) {
-      switch (aTopic) {
-        // we do not need addrbook-created
-        case "addrbook-directory-updated":
-        case "addrbook-directory-deleted":
-          {
-            //aSubject: nsIAbDirectory (we can get URI and UID directly from the object, but the directory no longer exists)
-            aSubject.QueryInterface(Components.interfaces.nsIAbDirectory);
-            let bookUID = aSubject.UID;
-
-            let folderData = TbSync.addressbook.getFolderFromDirectoryUID(bookUID);
-            if (folderData
-              && folderData.targetData
-              && folderData.targetData.isAdvancedAddressbookTargetData) {
-
-              switch (aTopic) {
-                case "addrbook-directory-updated":
-                  {
-                    //update name of target (if changed)
-                    folderData.setFolderProperty("targetName", aSubject.dirName);
-                    //update settings window, if open
-                    Services.obs.notifyObservers(null, "tbsync.observer.manager.updateSyncstate", folderData.accountID);
-                  }
-                  break;
-
-                case "addrbook-directory-deleted":
-                  {
-                    //delete any pending changelog of the deleted book
-                    TbSync.db.clearChangeLog(bookUID);
-
-                    //unselect book if deleted by user and update settings window, if open
-                    if (folderData.getFolderProperty("selected")) {
-                      folderData.setFolderProperty("selected", false);
-                      //update settings window, if open
-                      Services.obs.notifyObservers(null, "tbsync.observer.manager.updateSyncstate", folderData.accountID);
-                    }
-
-                    folderData.resetFolderProperty("target");
-                  }
-                  break;
-              }
-
-              folderData.targetData.directoryObserver(aTopic);
-            }
-          }
-          break;
-
-        case "addrbook-contact-created":
-        case "addrbook-contact-updated":
-        case "addrbook-contact-deleted":
-          {
-            //aSubject: nsIAbCard
-            aSubject.QueryInterface(Components.interfaces.nsIAbCard);
-            //aData: 128-bit unique identifier for the parent directory
-            let bookUID = aData;
-
-            let folderData = TbSync.addressbook.getFolderFromDirectoryUID(bookUID);
-            if (folderData
-              && folderData.targetData
-              && folderData.targetData.isAdvancedAddressbookTargetData) {
-
-              let directory = TbSync.addressbook.getDirectoryFromDirectoryUID(bookUID);
-              let abDirectory = new TbSync.addressbook.AbDirectory(directory, folderData);
-              let abItem = new TbSync.addressbook.AbItem(abDirectory, aSubject);
-              let itemStatus = abItem.changelogStatus || "";
-
-              // during create the following can happen
-              // card has no primary key
-              // another process could try to mod
-              //  -> we need to identify this card with an always available ID and block any other MODS until we free it again
-              // -> store creation type
-
-              if (aTopic == "addrbook-contact-created" && itemStatus == "") {
-                // add this new card to changelog to keep track of it
-                TbSync.db.addItemToChangeLog(bookUID, aSubject.UID + "#DelayedUserCreation", Date.now());
-                // new cards must get a NEW(!) primaryKey first
-                if (abDirectory.primaryKeyField) {
-                  console.log("New primary Key generated!");
-                  abItem.setProperty(abDirectory.primaryKeyField, folderData.targetData.generatePrimaryKey());
-                }
-                // special case: do not add "modified_by_server"
-                abDirectory.modifyItem(abItem, /*pretagChangelogWithByServerEntry */ false);
-                // We will see this card again as updated but delayed created
-                return;
-              }
-
-              // during follow up MODs we can identify this card via
-              let delayedUserCreation = TbSync.db.getItemStatusFromChangeLog(bookUID, aSubject.UID + "#DelayedUserCreation");
-
-              // if we reach this point and if we have adelayedUserCreation,
-              // we can remove the delayedUserCreation marker and can 
-              // continue to process this event as an addrbook-contact-created
-              let bTopic = aTopic;
-              if (delayedUserCreation) {
-                let age = Date.now() - delayedUserCreation;
-                if (age < 1500) {
-                  bTopic = "addrbook-contact-created";
-                } else {
-                  TbSync.db.removeItemFromChangeLog(bookUID, aSubject.UID + "#DelayedUserCreation");
-                }
-              }
-
-              // if this card was created by us, it will be in the log
-              // we want to ignore any MOD for a freeze time, because
-              // gContactSync modifies our(!) contacts (GoogleID) after we added them, so they get
-              // turned into "modified_by_user" and will be send back to the server.
-              if (itemStatus && itemStatus.endsWith("_by_server")) {
-                let age = Date.now() - abItem.changelogData.timestamp;
-                if (age < 1500) {
-                  // during freeze, local modifications are not possible
-                  return;
-                } else {
-                  // remove blocking entry from changelog after freeze time is over (1.5s),
-                  // and continue evaluating this event
-                  abItem.changelogStatus = "";
-                }
-              }
-
-              // From here on, we only process user changes as server changes are self freezed            
-              // update changelog based on old status
-              switch (bTopic) {
-                case "addrbook-contact-created":
-                  {
-                    switch (itemStatus) {
-                      case "added_by_user":
-                        // late create notification
-                        break;
-
-                      case "modified_by_user":
-                        // late create notification
-                        abItem.changelogStatus = "added_by_user";
-                        break;
-
-                      case "deleted_by_user":
-                        // unprocessed delete for this card, undo the delete (moved out and back in)
-                        abItem.changelogStatus = "modified_by_user";
-                        break;
-
-                      default:
-                        // new card
-                        abItem.changelogStatus = "added_by_user";
-                    }
-                  }
-                  break;
-
-                case "addrbook-contact-updated":
-                  {
-                    switch (itemStatus) {
-                      case "added_by_user":
-                        // unprocessed add for this card, keep status
-                        break;
-
-                      case "modified_by_user":
-                        // double notification, keep status
-                        break;
-
-                      case "deleted_by_user":
-                      // race? unprocessed delete for this card, moved out and back in and modified
-                      default:
-                        abItem.changelogStatus = "modified_by_user";
-                        break;
-                    }
-                  }
-                  break;
-
-                case "addrbook-contact-deleted":
-                  {
-                    switch (itemStatus) {
-                      case "added_by_user":
-                        // unprocessed add for this card, revert
-                        abItem.changelogStatus = "";
-                        return;
-
-                      case "deleted_by_user":
-                        // double notification
-                        break;
-
-                      case "modified_by_user":
-                      // unprocessed mod for this card
-                      default:
-                        abItem.changelogStatus = "deleted_by_user";
-                        break;
-                    }
-                  }
-                  break;
-              }
-
-              if (abDirectory.logUserChanges) TbSync.core.setTargetModified(folderData);
-
-              // notify observers only if status changed
-              if (itemStatus != abItem.changelogStatus) {
-                folderData.targetData.cardObserver(bTopic, abItem);
-              }
-              return;
-            }
-          }
-          break;
-
-        case "addrbook-list-created":
-        case "addrbook-list-deleted":
-          {
-            //aSubject: nsIAbDirectory
-            aSubject.QueryInterface(Components.interfaces.nsIAbDirectory);
-            //aData: 128-bit unique identifier for the parent directory
-            let bookUID = aData;
-
-            let folderData = TbSync.addressbook.getFolderFromDirectoryUID(bookUID);
-            if (folderData
-              && folderData.targetData
-              && folderData.targetData.isAdvancedAddressbookTargetData) {
-
-              let directory = TbSync.addressbook.getDirectoryFromDirectoryUID(bookUID);
-              let abDirectory = new TbSync.addressbook.AbDirectory(directory, folderData);
-              let abItem = new TbSync.addressbook.AbItem(abDirectory, aSubject);
-
-              let itemStatus = abItem.changelogStatus;
-              if (itemStatus && itemStatus.endsWith("_by_server")) {
-                //we caused this, ignore
-                abItem.changelogStatus = "";
-                return;
-              }
-
-              // update changelog based on old status
-              switch (aTopic) {
-                case "addrbook-list-created":
-                  {
-                    if (abDirectory.primaryKeyField) {
-                      // Since we do not need to update a list, to make custom properties persistent, we do not need to use delayedUserCreation as with contacts.
-                      abItem.setProperty(abDirectory.primaryKeyField, folderData.targetData.generatePrimaryKey());
-                    }
-
-                    switch (itemStatus) {
-                      case "added_by_user":
-                        // double notification, which is probably impossible, keep status
-                        break;
-
-                      case "modified_by_user":
-                        // late create notification
-                        abItem.changelogStatus = "added_by_user";
-                        break;
-
-                      case "deleted_by_user":
-                        // unprocessed delete for this card, undo the delete (moved out and back in)
-                        abItem.changelogStatus = "modified_by_user";
-                        break;
-
-                      default:
-                        // new list
-                        abItem.changelogStatus = "added_by_user";
-                        break;
-                    }
-                  }
-                  break;
-
-                case "addrbook-list-deleted":
-                  {
-                    switch (itemStatus) {
-                      case "added_by_user":
-                        // unprocessed add for this card, revert
-                        abItem.changelogStatus = "";
-                        return;
-
-                      case "modified_by_user":
-                      // unprocessed mod for this card
-                      case "deleted_by_user":
-                      // double notification
-                      default:
-                        abItem.changelogStatus = "deleted_by_user";
-                        break;
-                    }
-                    //remove properties of this ML stored in changelog
-                    TbSync.db.clearChangeLog(abDirectory.UID + "#" + abItem.UID);
-                  }
-                  break;
-              }
-
-              if (abDirectory.logUserChanges) TbSync.core.setTargetModified(folderData);
-              folderData.targetData.listObserver(aTopic, abItem, null);
-            }
-          }
-          break;
-
-        case "addrbook-list-updated":
-          {
-            // aSubject: nsIAbDirectory
-            aSubject.QueryInterface(Components.interfaces.nsIAbDirectory);
-            // get the card representation of this list, including its parent directory
-            let listInfo = await TbSync.addressbook.getListInfoFromListUID(aSubject.UID);
-            let bookUID = listInfo.directory.UID;
-
-            let folderData = TbSync.addressbook.getFolderFromDirectoryUID(bookUID);
-            if (folderData
-              && folderData.targetData
-              && folderData.targetData.isAdvancedAddressbookTargetData) {
-
-              let abDirectory = new TbSync.addressbook.AbDirectory(listInfo.directory, folderData);
-              let abItem = new TbSync.addressbook.AbItem(abDirectory, listInfo.listCard);
-
-              let itemStatus = abItem.changelogStatus;
-              if (itemStatus && itemStatus.endsWith("_by_server")) {
-                //we caused this, ignore
-                abItem.changelogStatus = "";
-                return;
-              }
-
-              // update changelog based on old status
-              switch (aTopic) {
-                case "addrbook-list-updated":
-                  {
-                    switch (itemStatus) {
-                      case "added_by_user":
-                        // unprocessed add for this card, keep status
-                        break;
-
-                      case "modified_by_user":
-                        // double notification, keep status
-                        break;
-
-                      case "deleted_by_user":
-                      // race? unprocessed delete for this card, moved out and back in and modified
-                      default:
-                        abItem.changelogStatus = "modified_by_user";
-                        break;
-                    }
-                  }
-                  break;
-              }
-
-              if (abDirectory.logUserChanges) TbSync.core.setTargetModified(folderData);
-              folderData.targetData.listObserver(aTopic, abItem, null);
-            }
-          }
-          break;
-
-        // unknown, if called for programmatically added members as well, probably not
-        case "addrbook-list-member-added": //exclude contact without Email - notification is wrongly send
-        case "addrbook-list-member-removed":
-          {
-            //aSubject: nsIAbCard of Member
-            aSubject.QueryInterface(Components.interfaces.nsIAbCard);
-            //aData: 128-bit unique identifier for the list
-            let listInfo = await TbSync.addressbook.getListInfoFromListUID(aData);
-            let bookUID = listInfo.directory.UID;
-
-            let folderData = TbSync.addressbook.getFolderFromDirectoryUID(bookUID);
-            if (folderData
-              && folderData.targetData
-              && folderData.targetData.isAdvancedAddressbookTargetData) {
-
-              let abDirectory = new TbSync.addressbook.AbDirectory(listInfo.directory, folderData);
-              let abItem = new TbSync.addressbook.AbItem(abDirectory, listInfo.listCard);
-              let abMember = new TbSync.addressbook.AbItem(abDirectory, aSubject);
-
-              if (abDirectory.logUserChanges) TbSync.core.setTargetModified(folderData);
-              folderData.targetData.listObserver(aTopic, abItem, abMember);
-
-              // removed, added members cause the list to be changed
-              let mailListDirectory = MailServices.ab.getDirectory(listInfo.listCard.mailListURI);
-              TbSync.addressbook.addressbookObserver.observe(mailListDirectory, "addrbook-list-updated", null);
-              return;
-            }
-          }
-          break;
-
-      }
-    }
-  },
-
-}
+/*
+ * This file is part of TbSync.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. 
+ */
+
+"use strict";
+
+var { AddrBookCard } = ChromeUtils.importESModule(
+  "resource:///modules/AddrBookCard.sys.mjs"
+);
+var { ExtensionParent } = ChromeUtils.importESModule(
+  "resource://gre/modules/ExtensionParent.sys.mjs"
+);
+var { MailServices } = ChromeUtils.importESModule(
+  "resource:///modules/MailServices.sys.mjs"
+);
+
+var tbsyncExtension = ExtensionParent.GlobalManager.getExtension(
+  "tbsync at jobisoft.de"
+);
+var { TbSync } = ChromeUtils.importESModule(
+  `chrome://tbsync/content/tbsync.sys.mjs?${tbsyncExtension.manifest.version}`
+);
+
+ChromeUtils.defineESModuleGetters(this, {
+  FileUtils: "resource://gre/modules/FileUtils.sys.mjs",
+});
+
+var addressbook = {
+
+  _notifications: [
+    "addrbook-directory-updated",
+    "addrbook-directory-deleted",
+    "addrbook-contact-created",
+    "addrbook-contact-updated",
+    "addrbook-contact-deleted",
+    "addrbook-list-member-added",
+    "addrbook-list-member-removed",
+    "addrbook-list-deleted",
+    "addrbook-list-updated",
+    "addrbook-list-created"
+  ],
+
+  load: async function () {
+    for (let topic of this._notifications) {
+      Services.obs.addObserver(this.addressbookObserver, topic);
+    }
+  },
+
+  unload: async function () {
+    for (let topic of this._notifications) {
+      Services.obs.removeObserver(this.addressbookObserver, topic);
+    }
+  },
+
+  getStringValue: function (ab, value, fallback) {
+    try {
+      return ab.getStringValue(value, fallback);
+    } catch (e) {
+      return fallback;
+    }
+  },
+
+  searchDirectory: function (uri, search) {
+    return new Promise((resolve, reject) => {
+      let listener = {
+        cards: [],
+
+        onSearchFinished(aResult, aErrorMsg) {
+          resolve(this.cards);
+        },
+        onSearchFoundCard(aCard) {
+          this.cards.push(aCard.QueryInterface(Components.interfaces.nsIAbCard));
+        }
+      }
+
+      let result = MailServices.ab.getDirectory(uri).search(search, "", listener);
+    });
+  },
+
+
+  // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+  // * AdvancedTargetData, an extended TargetData implementation, providers
+  // * can use this as their own TargetData by extending it and just
+  // * defining the extra methods
+  // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+  AdvancedTargetData: class {
+    constructor(folderData) {
+      this._folderData = folderData;
+      this._targetObj = null;
+    }
+
+
+    // Check, if the target exists and return true/false.
+    hasTarget() {
+      let target = this._folderData.getFolderProperty("target");
+      let directory = TbSync.addressbook.getDirectoryFromDirectoryUID(target);
+      return directory ? true : false;
+    }
+
+    // Returns the target obj, which TbSync should return as the target. It can
+    // be whatever you want and is returned by FolderData.targetData.getTarget().
+    // If the target does not exist, it should be created. Throw a simple Error, if that
+    // failed.
+    async getTarget() {
+      let target = this._folderData.getFolderProperty("target");
+      let directory = TbSync.addressbook.getDirectoryFromDirectoryUID(target);
+
+      if (!directory) {
+        // create a new addressbook and store its UID in folderData
+        directory = await TbSync.addressbook.prepareAndCreateAddressbook(this._folderData);
+        if (!directory)
+          throw new Error("notargets");
+      }
+
+      if (!this._targetObj || this._targetObj.UID != directory.UID)
+        this._targetObj = new TbSync.addressbook.AbDirectory(directory, this._folderData);
+
+      return this._targetObj;
+    }
+
+    /**
+     * Removes the target from the local storage. If it does not exist, return
+     * silently. A call to ``hasTarget()`` should return false, after this has
+     * been executed.
+     *
+     */
+    removeTarget() {
+      let target = this._folderData.getFolderProperty("target");
+      let directory = TbSync.addressbook.getDirectoryFromDirectoryUID(target);
+      try {
+        if (directory) {
+          MailServices.ab.deleteAddressBook(directory.URI);
+        }
+      } catch (e) { }
+
+      TbSync.db.clearChangeLog(target);
+      this._folderData.resetFolderProperty("target");
+    }
+
+    /**
+     * Disconnects the target in the local storage from this TargetData, but
+     * does not delete it, so it becomes a stale "left over" . A call
+     * to ``hasTarget()`` should return false, after this has been executed.
+     * 
+     */
+    disconnectTarget() {
+      let target = this._folderData.getFolderProperty("target");
+      let directory = TbSync.addressbook.getDirectoryFromDirectoryUID(target);
+      if (directory) {
+        let changes = TbSync.db.getItemsFromChangeLog(target, 0, "_by_user");
+        if (changes.length > 0) {
+          this.targetName = this.targetName + " (*)";
+        }
+        directory.setStringValue("tbSyncIcon", "orphaned");
+        directory.setStringValue("tbSyncProvider", "orphaned");
+        directory.setStringValue("tbSyncAccountID", "");
+      }
+      TbSync.db.clearChangeLog(target);
+      this._folderData.resetFolderProperty("target");
+    }
+
+    set targetName(newName) {
+      let target = this._folderData.getFolderProperty("target");
+      let directory = TbSync.addressbook.getDirectoryFromDirectoryUID(target);
+      if (directory) {
+        directory.dirName = newName;
+      } else {
+        throw new Error("notargets");
+      }
+    }
+
+    get targetName() {
+      let target = this._folderData.getFolderProperty("target");
+      let directory = TbSync.addressbook.getDirectoryFromDirectoryUID(target);
+      if (directory) {
+        return directory.dirName;
+      } else {
+        throw new Error("notargets");
+      }
+    }
+
+    setReadOnly(value) {
+    }
+
+
+    // * * * * * * * * * * * * * * * * *
+    // * AdvancedTargetData extension  * 
+    // * * * * * * * * * * * * * * * * *
+
+    get isAdvancedAddressbookTargetData() {
+      return true;
+    }
+
+    get folderData() {
+      return this._folderData;
+    }
+
+    // define a card property, which should be used for the changelog
+    // basically your primary key for the abItem properties
+    // UID will be used, if nothing specified
+    get primaryKeyField() {
+      return "UID";
+    }
+
+    generatePrimaryKey() {
+      return TbSync.generateUUID();
+    }
+
+    // enable or disable changelog
+    get logUserChanges() {
+      return true;
+    }
+
+    directoryObserver(aTopic) {
+      switch (aTopic) {
+        case "addrbook-directory-deleted":
+        case "addrbook-directory-updated":
+          //Services.console.logStringMessage("["+ aTopic + "] " + folderData.getFolderProperty("foldername"));
+          break;
+      }
+    }
+
+    cardObserver(aTopic, abCardItem) {
+      switch (aTopic) {
+        case "addrbook-contact-updated":
+        case "addrbook-contact-deleted":
+        case "addrbook-contact-created":
+          //Services.console.logStringMessage("["+ aTopic + "] " + abCardItem.getProperty("DisplayName"));
+          break;
+      }
+    }
+
+    listObserver(aTopic, abListItem, abListMember) {
+      switch (aTopic) {
+        case "addrbook-list-member-added":
+        case "addrbook-list-member-removed":
+          //Services.console.logStringMessage("["+ aTopic + "] MemberName: " + abListMember.getProperty("DisplayName"));
+          break;
+
+        case "addrbook-list-deleted":
+        case "addrbook-list-updated":
+          //Services.console.logStringMessage("["+ aTopic + "] ListName: " + abListItem.getProperty("ListName"));
+          break;
+
+        case "addrbook-list-created":
+          //Services.console.logStringMessage("["+ aTopic + "] Created new X-DAV-UID for List <"+abListItem.getProperty("ListName")+">");
+          break;
+      }
+    }
+
+    // replace this with your own implementation to create the actual addressbook,
+    // when this class is extended
+    async createAddressbook(newname) {
+      // https://searchfox.org/comm-central/source/mailnews/addrbook/src/nsDirPrefs.h
+      let dirPrefId = MailServices.ab.newAddressBook(newname, "", 101);
+      let directory = MailServices.ab.getDirectoryFromId(dirPrefId);
+      return directory;
+    }
+  },
+
+
+
+
+
+  // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+  // * AbItem and AbDirectory Classes
+  // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+  AbItem: class {
+    constructor(abDirectory, item) {
+      if (!abDirectory)
+        throw new Error("AbItem::constructor is missing its first parameter!");
+
+      if (!item)
+        throw new Error("AbItem::constructor is missing its second parameter!");
+
+      this._abDirectory = abDirectory;
+      this._card = null;
+      this._tempListDirectory = null;
+      this._tempProperties = null;
+      this._isMailList = false;
+
+      if (item instanceof Components.interfaces.nsIAbDirectory) {
+        this._tempListDirectory = item;
+        this._isMailList = true;
+        this._tempProperties = {};
+      } else {
+        this._card = item;
+        this._isMailList = item.isMailList;
+      }
+    }
+
+    get abDirectory() {
+      return this._abDirectory;
+    }
+
+    get isMailList() {
+      return this._isMailList;
+    }
+
+
+
+
+
+    get nativeItem() {
+      return this._card;
+    }
+
+    get UID() {
+      if (this._tempListDirectory) return this._tempListDirectory.UID;
+      return this._card.UID;
+    }
+
+    get primaryKey() {
+      //use UID as fallback
+      let key = this._abDirectory.primaryKeyField;
+      return key ? this.getProperty(key) : this.UID;
+    }
+
+    set primaryKey(value) {
+      //use UID as fallback
+      let key = this._abDirectory.primaryKeyField;
+      if (key) this.setProperty(key, value)
+      else throw ("TbSync.addressbook.AbItem.set primaryKey: UID is used as primaryKeyField but changing the UID of an item is currently not supported. Please use a custom primaryKeyField.");
+    }
+
+    clone() { //no real clone ... this is just here to match the calendar target
+      return new TbSync.addressbook.AbItem(this._abDirectory, this._card);
+    }
+
+    toString() {
+      return this._card.displayName + " (" + this._card.firstName + ", " + this._card.lastName + ") <" + this._card.primaryEmail + ">";
+    }
+
+    // mailinglist aware method to get properties of cards
+    // mailinglist properties cannot be stored in mailinglists themselves, so we store them in changelog
+    getProperty(property, fallback = "") {
+      if (property == "UID")
+        return this.UID;
+
+      if (this._isMailList) {
+        const directListProperties = {
+          ListName: "dirName",
+          ListNickName: "listNickName",
+          ListDescription: "description"
+        };
+
+        let value;
+        if (directListProperties.hasOwnProperty(property)) {
+          try {
+            let mailListDirectory = this._tempListDirectory || MailServices.ab.getDirectory(this._card.mailListURI); //this._card.asDirectory
+            value = mailListDirectory[directListProperties[property]];
+          } catch (e) {
+            // list does not exists
+          }
+        } else {
+          value = this._tempProperties ? this._tempProperties[property] : TbSync.db.getItemStatusFromChangeLog(this._abDirectory.UID + "#" + this.UID, property);
+        }
+        return value || fallback;
+      } else {
+        return this._card.getProperty(property, fallback);
+      }
+    }
+
+    // mailinglist aware method to set properties of cards
+    // mailinglist properties cannot be stored in mailinglists themselves, so we store them in changelog
+    // while the list has not been added, we keep all props in an object (UID changes on adding)
+    setProperty(property, value) {
+      // UID cannot be changed (currently)
+      if (property == "UID") {
+        throw ("TbSync.addressbook.AbItem.setProperty: UID cannot be changed currently.");
+        return;
+      }
+
+      if (this._isMailList) {
+        const directListProperties = {
+          ListName: "dirName",
+          ListNickName: "listNickName",
+          ListDescription: "description"
+        };
+
+        if (directListProperties.hasOwnProperty(property)) {
+          try {
+            let mailListDirectory = this._tempListDirectory || MailServices.ab.getDirectory(this._card.mailListURI);
+            mailListDirectory[directListProperties[property]] = value;
+          } catch (e) {
+            // list does not exists
+          }
+        } else {
+          if (this._tempProperties) {
+            this._tempProperties[property] = value;
+          } else {
+            TbSync.db.addItemToChangeLog(this._abDirectory.UID + "#" + this.UID, property, value);
+          }
+        }
+      } else {
+        this._card.setProperty(property, value);
+      }
+    }
+
+    deleteProperty(property) {
+      if (this._isMailList) {
+        if (this._tempProperties) {
+          delete this._tempProperties[property];
+        } else {
+          TbSync.db.removeItemFromChangeLog(this._abDirectory.UID + "#" + this.UID, property);
+        }
+      } else {
+        this._card.deleteProperty(property);
+      }
+    }
+
+    get changelogData() {
+      return TbSync.db.getItemDataFromChangeLog(this._abDirectory.UID, this.primaryKey);
+    }
+
+    get changelogStatus() {
+      return TbSync.db.getItemStatusFromChangeLog(this._abDirectory.UID, this.primaryKey);
+    }
+
+    set changelogStatus(status) {
+      let value = this.primaryKey;
+
+      if (value) {
+        if (!status) {
+          TbSync.db.removeItemFromChangeLog(this._abDirectory.UID, value);
+          return;
+        }
+
+        if (this._abDirectory.logUserChanges || status.endsWith("_by_server")) {
+          TbSync.db.addItemToChangeLog(this._abDirectory.UID, value, status);
+        }
+      }
+    }
+
+
+
+
+
+    // get the property given from all members and return it as an array (that property better be uniqe)
+    getMembersPropertyList(property) {
+      let members = [];
+      if (this._card && this._card.isMailList) {
+        // get mailListDirectory
+        let mailListDirectory = MailServices.ab.getDirectory(this._card.mailListURI);
+        for (let member of mailListDirectory.childCards) {
+          let prop = member.getProperty(property, "");
+          if (prop) members.push(prop);
+        }
+      }
+      return members;
+    }
+
+    addListMembers(property, candidates) {
+      if (this._card && this._card.isMailList) {
+        let members = this.getMembersPropertyList(property);
+        let mailListDirectory = MailServices.ab.getDirectory(this._card.mailListURI);
+
+        for (let candidate of candidates) {
+          if (members.includes(candidate))
+            continue;
+
+          let card = this._abDirectory._directory.getCardFromProperty(property, candidate, true);
+          if (card) mailListDirectory.addCard(card);
+        }
+      }
+    }
+
+    removeListMembers(property, candidates) {
+      if (this._card && this._card.isMailList) {
+        let members = this.getMembersPropertyList(property);
+        let mailListDirectory = MailServices.ab.getDirectory(this._card.mailListURI);
+
+        let cardsToRemove = [];
+        for (let candidate of candidates) {
+          if (!members.includes(candidate))
+            continue;
+
+          let card = this._abDirectory._directory.getCardFromProperty(property, candidate, true);
+          if (card) cardsToRemove.push(card);
+        }
+        if (cardsToRemove.length > 0) mailListDirectory.deleteCards(cardsToRemove);
+      }
+    }
+
+    addPhoto(photo, data, extension = "jpg", url = "") {
+      let card = this._card;
+      let bookUID = this.abDirectory.UID;
+
+      let book64 = btoa(bookUID);
+      let photo64 = btoa(photo);
+      let photoName64 = book64 + "_" + photo64 + "." + extension;
+
+      let file = new FileUtils.File(PathUtils.join(PathUtils.profileDir, "Photos", photoName64));
+      let foStream = Components.classes["@mozilla.org/network/file-output-stream;1"].createInstance(Components.interfaces.nsIFileOutputStream);
+      foStream.init(file, 0x02 | 0x08 | 0x20, 0x180, 0); // write, create, truncate
+      let binary = "";
+      try {
+        binary = atob(data.split(" ").join(""));
+      } catch (e) {
+        console.log("Failed to decode base64 string:", data);
+      }
+      foStream.write(binary, binary.length);
+      foStream.close();
+
+      let filePath = 'file:///' + file.path.replace(/\\/g, '\/').replace(/^\s*\/?/, '').replace(/\ /g, '%20');
+      card.setProperty("PhotoName", photoName64);
+      card.setProperty("PhotoType", url ? "web" : "file");
+      card.setProperty("PhotoURI", url ? url : filePath);
+      return filePath;
+    }
+
+    getPhoto() {
+      let card = this._card;
+      let photo = card.getProperty("PhotoName", "");
+      let data = "";
+
+      if (photo) {
+        try {
+          let file = new FileUtils.File(PathUtils.join(PathUtils.profileDir, "Photos", photo));
+
+          let fiStream = Components.classes["@mozilla.org/network/file-input-stream;1"].createInstance(Components.interfaces.nsIFileInputStream);
+          fiStream.init(file, -1, -1, false);
+
+          let bstream = Components.classes["@mozilla.org/binaryinputstream;1"].createInstance(Components.interfaces.nsIBinaryInputStream);
+          bstream.setInputStream(fiStream);
+
+          data = btoa(bstream.readBytes(bstream.available()));
+          fiStream.close();
+        } catch (e) { }
+      }
+      return data;
+    }
+  },
+
+  AbDirectory: class {
+    constructor(directory, folderData) {
+      this._directory = directory;
+      this._folderData = folderData;
+    }
+
+    get directory() {
+      return this._directory;
+    }
+
+    get logUserChanges() {
+      return this._folderData.targetData.logUserChanges;
+    }
+
+    get primaryKeyField() {
+      return this._folderData.targetData.primaryKeyField;
+    }
+
+    get UID() {
+      return this._directory.UID;
+    }
+
+    get URI() {
+      return this._directory.URI;
+    }
+
+    createNewCard() {
+      let card = new AddrBookCard();
+      return new TbSync.addressbook.AbItem(this, card);
+    }
+
+    createNewList() {
+      let listDirectory = Components.classes["@mozilla.org/addressbook/directoryproperty;1"].createInstance(Components.interfaces.nsIAbDirectory);
+      listDirectory.isMailList = true;
+      return new TbSync.addressbook.AbItem(this, listDirectory);
+    }
+
+    async addItem(abItem, pretagChangelogWithByServerEntry = true) {
+      if (this.primaryKeyField && !abItem.getProperty(this.primaryKeyField)) {
+        abItem.setProperty(this.primaryKeyField, this._folderData.targetData.generatePrimaryKey());
+        //Services.console.logStringMessage("[AbDirectory::addItem] Generated primary key!");
+      }
+
+      if (pretagChangelogWithByServerEntry) {
+        abItem.changelogStatus = "added_by_server";
+      }
+
+      if (abItem.isMailList && abItem._tempListDirectory) {
+        let list = this._directory.addMailList(abItem._tempListDirectory);
+        // the list has been added and we can now get the corresponding card via its UID
+        let found = await this.getItemFromProperty("UID", list.UID);
+
+        // clone and clear temporary properties
+        let props = { ...abItem._tempProperties };
+        abItem._tempListDirectory = null;
+        abItem._tempProperties = null;
+
+        // store temporary properties
+        for (const [property, value] of Object.entries(props)) {
+          found.setProperty(property, value);
+        }
+
+        abItem._card = found._card;
+      } else if (!abItem.isMailList) {
+        this._directory.addCard(abItem._card);
+
+      } else {
+        throw new Error("Cannot re-add a list to a directory.");
+      }
+    }
+
+    modifyItem(abItem, pretagChangelogWithByServerEntry = true) {
+      // only add entry if the current entry does not start with _by_user
+      let status = abItem.changelogStatus ? abItem.changelogStatus : "";
+      if (pretagChangelogWithByServerEntry && !status.endsWith("_by_user")) {
+        abItem.changelogStatus = "modified_by_server";
+      }
+
+      if (abItem.isMailList) {
+        // get mailListDirectory
+        let mailListDirectory = MailServices.ab.getDirectory(abItem._card.mailListURI);
+
+        // store
+        mailListDirectory.editMailListToDatabase(abItem._card);
+      } else {
+        this._directory.modifyCard(abItem._card);
+      }
+    }
+
+    deleteItem(abItem, pretagChangelogWithByServerEntry = true) {
+      if (pretagChangelogWithByServerEntry) {
+        abItem.changelogStatus = "deleted_by_server";
+      }
+      this._directory.deleteCards([abItem._card]);
+    }
+
+    async getItem(searchId) {
+      //use UID as fallback
+      let key = this.primaryKeyField ? this.primaryKeyField : "UID";
+      return await this.getItemFromProperty(key, searchId);
+    }
+
+    async getItemFromProperty(property, value) {
+      // try to use the standard card method first
+      let card = this._directory.getCardFromProperty(property, value, true);
+      if (card) {
+        return new TbSync.addressbook.AbItem(this, card);
+      }
+
+      // search for list cards
+      // we cannot search for the prop directly, because for mailinglists
+      // they are not part of the card (expect UID) but stored in a custom storage
+      let searchList = "(IsMailList,=,TRUE)";
+      let foundCards = await TbSync.addressbook.searchDirectory(this._directory.URI, "(or" + searchList + ")");
+      for (let aCard of foundCards) {
+        let card = new TbSync.addressbook.AbItem(this, aCard);
+        //does this list card have the req prop?
+        if (card.getProperty(property) == value) {
+          return card;
+        }
+      }
+      return null;
+    }
+
+    getAllItems() {
+      let rv = [];
+      for (let card of this._directory.childCards) {
+        rv.push(new TbSync.addressbook.AbItem(this._directory, card));
+      }
+      return rv;
+    }
+
+
+
+
+
+    getAddedItemsFromChangeLog(maxitems = 0) {
+      return TbSync.db.getItemsFromChangeLog(this._directory.UID, maxitems, "added_by_user").map(item => item.itemId);
+    }
+
+    getModifiedItemsFromChangeLog(maxitems = 0) {
+      return TbSync.db.getItemsFromChangeLog(this._directory.UID, maxitems, "modified_by_user").map(item => item.itemId);
+    }
+
+    getDeletedItemsFromChangeLog(maxitems = 0) {
+      return TbSync.db.getItemsFromChangeLog(this._directory.UID, maxitems, "deleted_by_user").map(item => item.itemId);
+    }
+
+    getItemsFromChangeLog(maxitems = 0) { // Document what this returns         
+      return TbSync.db.getItemsFromChangeLog(this._directory.UID, maxitems, "_by_user");
+    }
+
+    removeItemFromChangeLog(id, moveToEndInsteadOfDelete = false) {
+      TbSync.db.removeItemFromChangeLog(this._directory.UID, id, moveToEndInsteadOfDelete);
+    }
+
+    clearChangelog() {
+      TbSync.db.clearChangeLog(this._directory.UID);
+    }
+
+  },
+
+
+
+
+
+  // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+  // * Internal Functions
+  // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+  prepareAndCreateAddressbook: async function (folderData) {
+    let target = folderData.getFolderProperty("target");
+    let provider = folderData.accountData.getAccountProperty("provider");
+
+    // Get cached or new unique name for new address book
+    let cachedName = folderData.getFolderProperty("targetName");
+    let newname = cachedName == "" ? folderData.accountData.getAccountProperty("accountname") + " (" + folderData.getFolderProperty("foldername") + ")" : cachedName;
+
+    //Create the new book with the unique name
+    let directory = await folderData.targetData.createAddressbook(newname);
+    if (directory && directory instanceof Components.interfaces.nsIAbDirectory) {
+      directory.setStringValue("tbSyncProvider", provider);
+      directory.setStringValue("tbSyncAccountID", folderData.accountData.accountID);
+
+      // Prevent gContactSync to inject its stuff into New/EditCard dialogs
+      // https://github.com/jdgeenen/gcontactsync/pull/127
+      directory.setStringValue("gContactSyncSkipped", "true");
+
+      folderData.setFolderProperty("target", directory.UID);
+      folderData.setFolderProperty("targetName", directory.dirName);
+      //notify about new created address book
+      Services.obs.notifyObservers(null, 'tbsync.observer.addressbook.created', null)
+      return directory;
+    }
+
+    return null;
+  },
+
+  getFolderFromDirectoryUID: function (bookUID) {
+    let folders = TbSync.db.findFolders({ "target": bookUID });
+    if (folders.length == 1) {
+      let accountData = new TbSync.AccountData(folders[0].accountID);
+      return new TbSync.FolderData(accountData, folders[0].folderID);
+    }
+    return null;
+  },
+
+  getDirectoryFromDirectoryUID: function (UID) {
+    if (!UID)
+      return null;
+
+    for (let directory of MailServices.ab.directories) {
+      if (directory instanceof Components.interfaces.nsIAbDirectory) {
+        if (directory.UID == UID) return directory;
+      }
+    }
+    return null;
+  },
+
+  getListInfoFromListUID: async function (UID) {
+    for (let directory of MailServices.ab.directories) {
+      if (directory instanceof Components.interfaces.nsIAbDirectory && !directory.isRemote) {
+        let searchList = "(IsMailList,=,TRUE)";
+        let foundCards = await TbSync.addressbook.searchDirectory(directory.URI, "(and" + searchList + ")");
+        for (let listCard of foundCards) {
+          //return after first found card
+          if (listCard.UID == UID) return { directory, listCard };
+        }
+      }
+    }
+    throw new Error("List with UID <" + UID + "> does not exists");
+  },
+
+
+
+
+
+  // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+  // * Addressbook Observer and Listener
+  // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+  addressbookObserver: {
+    observe: async function (aSubject, aTopic, aData) {
+      switch (aTopic) {
+        // we do not need addrbook-created
+        case "addrbook-directory-updated":
+        case "addrbook-directory-deleted":
+          {
+            //aSubject: nsIAbDirectory (we can get URI and UID directly from the object, but the directory no longer exists)
+            aSubject.QueryInterface(Components.interfaces.nsIAbDirectory);
+            let bookUID = aSubject.UID;
+
+            let folderData = TbSync.addressbook.getFolderFromDirectoryUID(bookUID);
+            if (folderData
+              && folderData.targetData
+              && folderData.targetData.isAdvancedAddressbookTargetData) {
+
+              switch (aTopic) {
+                case "addrbook-directory-updated":
+                  {
+                    //update name of target (if changed)
+                    folderData.setFolderProperty("targetName", aSubject.dirName);
+                    //update settings window, if open
+                    Services.obs.notifyObservers(null, "tbsync.observer.manager.updateSyncstate", folderData.accountID);
+                  }
+                  break;
+
+                case "addrbook-directory-deleted":
+                  {
+                    //delete any pending changelog of the deleted book
+                    TbSync.db.clearChangeLog(bookUID);
+
+                    //unselect book if deleted by user and update settings window, if open
+                    if (folderData.getFolderProperty("selected")) {
+                      folderData.setFolderProperty("selected", false);
+                      //update settings window, if open
+                      Services.obs.notifyObservers(null, "tbsync.observer.manager.updateSyncstate", folderData.accountID);
+                    }
+
+                    folderData.resetFolderProperty("target");
+                  }
+                  break;
+              }
+
+              folderData.targetData.directoryObserver(aTopic);
+            }
+          }
+          break;
+
+        case "addrbook-contact-created":
+        case "addrbook-contact-updated":
+        case "addrbook-contact-deleted":
+          {
+            //aSubject: nsIAbCard
+            aSubject.QueryInterface(Components.interfaces.nsIAbCard);
+            //aData: 128-bit unique identifier for the parent directory
+            let bookUID = aData;
+
+            let folderData = TbSync.addressbook.getFolderFromDirectoryUID(bookUID);
+            if (folderData
+              && folderData.targetData
+              && folderData.targetData.isAdvancedAddressbookTargetData) {
+
+              let directory = TbSync.addressbook.getDirectoryFromDirectoryUID(bookUID);
+              let abDirectory = new TbSync.addressbook.AbDirectory(directory, folderData);
+              let abItem = new TbSync.addressbook.AbItem(abDirectory, aSubject);
+              let itemStatus = abItem.changelogStatus || "";
+
+              // during create the following can happen
+              // card has no primary key
+              // another process could try to mod
+              //  -> we need to identify this card with an always available ID and block any other MODS until we free it again
+              // -> store creation type
+
+              if (aTopic == "addrbook-contact-created" && itemStatus == "") {
+                // add this new card to changelog to keep track of it
+                TbSync.db.addItemToChangeLog(bookUID, aSubject.UID + "#DelayedUserCreation", Date.now());
+                // new cards must get a NEW(!) primaryKey first
+                if (abDirectory.primaryKeyField) {
+                  console.log("New primary Key generated!");
+                  abItem.setProperty(abDirectory.primaryKeyField, folderData.targetData.generatePrimaryKey());
+                }
+                // special case: do not add "modified_by_server"
+                abDirectory.modifyItem(abItem, /*pretagChangelogWithByServerEntry */ false);
+                // We will see this card again as updated but delayed created
+                return;
+              }
+
+              // during follow up MODs we can identify this card via
+              let delayedUserCreation = TbSync.db.getItemStatusFromChangeLog(bookUID, aSubject.UID + "#DelayedUserCreation");
+
+              // if we reach this point and if we have adelayedUserCreation,
+              // we can remove the delayedUserCreation marker and can 
+              // continue to process this event as an addrbook-contact-created
+              let bTopic = aTopic;
+              if (delayedUserCreation) {
+                let age = Date.now() - delayedUserCreation;
+                if (age < 1500) {
+                  bTopic = "addrbook-contact-created";
+                } else {
+                  TbSync.db.removeItemFromChangeLog(bookUID, aSubject.UID + "#DelayedUserCreation");
+                }
+              }
+
+              // if this card was created by us, it will be in the log
+              // we want to ignore any MOD for a freeze time, because
+              // gContactSync modifies our(!) contacts (GoogleID) after we added them, so they get
+              // turned into "modified_by_user" and will be send back to the server.
+              if (itemStatus && itemStatus.endsWith("_by_server")) {
+                let age = Date.now() - abItem.changelogData.timestamp;
+                if (age < 1500) {
+                  // during freeze, local modifications are not possible
+                  return;
+                } else {
+                  // remove blocking entry from changelog after freeze time is over (1.5s),
+                  // and continue evaluating this event
+                  abItem.changelogStatus = "";
+                }
+              }
+
+              // From here on, we only process user changes as server changes are self freezed            
+              // update changelog based on old status
+              switch (bTopic) {
+                case "addrbook-contact-created":
+                  {
+                    switch (itemStatus) {
+                      case "added_by_user":
+                        // late create notification
+                        break;
+
+                      case "modified_by_user":
+                        // late create notification
+                        abItem.changelogStatus = "added_by_user";
+                        break;
+
+                      case "deleted_by_user":
+                        // unprocessed delete for this card, undo the delete (moved out and back in)
+                        abItem.changelogStatus = "modified_by_user";
+                        break;
+
+                      default:
+                        // new card
+                        abItem.changelogStatus = "added_by_user";
+                    }
+                  }
+                  break;
+
+                case "addrbook-contact-updated":
+                  {
+                    switch (itemStatus) {
+                      case "added_by_user":
+                        // unprocessed add for this card, keep status
+                        break;
+
+                      case "modified_by_user":
+                        // double notification, keep status
+                        break;
+
+                      case "deleted_by_user":
+                      // race? unprocessed delete for this card, moved out and back in and modified
+                      default:
+                        abItem.changelogStatus = "modified_by_user";
+                        break;
+                    }
+                  }
+                  break;
+
+                case "addrbook-contact-deleted":
+                  {
+                    switch (itemStatus) {
+                      case "added_by_user":
+                        // unprocessed add for this card, revert
+                        abItem.changelogStatus = "";
+                        return;
+
+                      case "deleted_by_user":
+                        // double notification
+                        break;
+
+                      case "modified_by_user":
+                      // unprocessed mod for this card
+                      default:
+                        abItem.changelogStatus = "deleted_by_user";
+                        break;
+                    }
+                  }
+                  break;
+              }
+
+              if (abDirectory.logUserChanges) TbSync.core.setTargetModified(folderData);
+
+              // notify observers only if status changed
+              if (itemStatus != abItem.changelogStatus) {
+                folderData.targetData.cardObserver(bTopic, abItem);
+              }
+              return;
+            }
+          }
+          break;
+
+        case "addrbook-list-created":
+        case "addrbook-list-deleted":
+          {
+            //aSubject: nsIAbDirectory
+            aSubject.QueryInterface(Components.interfaces.nsIAbDirectory);
+            //aData: 128-bit unique identifier for the parent directory
+            let bookUID = aData;
+
+            let folderData = TbSync.addressbook.getFolderFromDirectoryUID(bookUID);
+            if (folderData
+              && folderData.targetData
+              && folderData.targetData.isAdvancedAddressbookTargetData) {
+
+              let directory = TbSync.addressbook.getDirectoryFromDirectoryUID(bookUID);
+              let abDirectory = new TbSync.addressbook.AbDirectory(directory, folderData);
+              let abItem = new TbSync.addressbook.AbItem(abDirectory, aSubject);
+
+              let itemStatus = abItem.changelogStatus;
+              if (itemStatus && itemStatus.endsWith("_by_server")) {
+                //we caused this, ignore
+                abItem.changelogStatus = "";
+                return;
+              }
+
+              // update changelog based on old status
+              switch (aTopic) {
+                case "addrbook-list-created":
+                  {
+                    if (abDirectory.primaryKeyField) {
+                      // Since we do not need to update a list, to make custom properties persistent, we do not need to use delayedUserCreation as with contacts.
+                      abItem.setProperty(abDirectory.primaryKeyField, folderData.targetData.generatePrimaryKey());
+                    }
+
+                    switch (itemStatus) {
+                      case "added_by_user":
+                        // double notification, which is probably impossible, keep status
+                        break;
+
+                      case "modified_by_user":
+                        // late create notification
+                        abItem.changelogStatus = "added_by_user";
+                        break;
+
+                      case "deleted_by_user":
+                        // unprocessed delete for this card, undo the delete (moved out and back in)
+                        abItem.changelogStatus = "modified_by_user";
+                        break;
+
+                      default:
+                        // new list
+                        abItem.changelogStatus = "added_by_user";
+                        break;
+                    }
+                  }
+                  break;
+
+                case "addrbook-list-deleted":
+                  {
+                    switch (itemStatus) {
+                      case "added_by_user":
+                        // unprocessed add for this card, revert
+                        abItem.changelogStatus = "";
+                        return;
+
+                      case "modified_by_user":
+                      // unprocessed mod for this card
+                      case "deleted_by_user":
+                      // double notification
+                      default:
+                        abItem.changelogStatus = "deleted_by_user";
+                        break;
+                    }
+                    //remove properties of this ML stored in changelog
+                    TbSync.db.clearChangeLog(abDirectory.UID + "#" + abItem.UID);
+                  }
+                  break;
+              }
+
+              if (abDirectory.logUserChanges) TbSync.core.setTargetModified(folderData);
+              folderData.targetData.listObserver(aTopic, abItem, null);
+            }
+          }
+          break;
+
+        case "addrbook-list-updated":
+          {
+            // aSubject: nsIAbDirectory
+            aSubject.QueryInterface(Components.interfaces.nsIAbDirectory);
+            // get the card representation of this list, including its parent directory
+            let listInfo = await TbSync.addressbook.getListInfoFromListUID(aSubject.UID);
+            let bookUID = listInfo.directory.UID;
+
+            let folderData = TbSync.addressbook.getFolderFromDirectoryUID(bookUID);
+            if (folderData
+              && folderData.targetData
+              && folderData.targetData.isAdvancedAddressbookTargetData) {
+
+              let abDirectory = new TbSync.addressbook.AbDirectory(listInfo.directory, folderData);
+              let abItem = new TbSync.addressbook.AbItem(abDirectory, listInfo.listCard);
+
+              let itemStatus = abItem.changelogStatus;
+              if (itemStatus && itemStatus.endsWith("_by_server")) {
+                //we caused this, ignore
+                abItem.changelogStatus = "";
+                return;
+              }
+
+              // update changelog based on old status
+              switch (aTopic) {
+                case "addrbook-list-updated":
+                  {
+                    switch (itemStatus) {
+                      case "added_by_user":
+                        // unprocessed add for this card, keep status
+                        break;
+
+                      case "modified_by_user":
+                        // double notification, keep status
+                        break;
+
+                      case "deleted_by_user":
+                      // race? unprocessed delete for this card, moved out and back in and modified
+                      default:
+                        abItem.changelogStatus = "modified_by_user";
+                        break;
+                    }
+                  }
+                  break;
+              }
+
+              if (abDirectory.logUserChanges) TbSync.core.setTargetModified(folderData);
+              folderData.targetData.listObserver(aTopic, abItem, null);
+            }
+          }
+          break;
+
+        // unknown, if called for programmatically added members as well, probably not
+        case "addrbook-list-member-added": //exclude contact without Email - notification is wrongly send
+        case "addrbook-list-member-removed":
+          {
+            //aSubject: nsIAbCard of Member
+            aSubject.QueryInterface(Components.interfaces.nsIAbCard);
+            //aData: 128-bit unique identifier for the list
+            let listInfo = await TbSync.addressbook.getListInfoFromListUID(aData);
+            let bookUID = listInfo.directory.UID;
+
+            let folderData = TbSync.addressbook.getFolderFromDirectoryUID(bookUID);
+            if (folderData
+              && folderData.targetData
+              && folderData.targetData.isAdvancedAddressbookTargetData) {
+
+              let abDirectory = new TbSync.addressbook.AbDirectory(listInfo.directory, folderData);
+              let abItem = new TbSync.addressbook.AbItem(abDirectory, listInfo.listCard);
+              let abMember = new TbSync.addressbook.AbItem(abDirectory, aSubject);
+
+              if (abDirectory.logUserChanges) TbSync.core.setTargetModified(folderData);
+              folderData.targetData.listObserver(aTopic, abItem, abMember);
+
+              // removed, added members cause the list to be changed
+              let mailListDirectory = MailServices.ab.getDirectory(listInfo.listCard.mailListURI);
+              TbSync.addressbook.addressbookObserver.observe(mailListDirectory, "addrbook-list-updated", null);
+              return;
+            }
+          }
+          break;
+
+      }
+    }
+  },
+
+}
diff -Nru tbsync-4.12/content/modules/core.js tbsync-4.16/content/modules/core.js
--- tbsync-4.12/content/modules/core.js	2024-08-27 18:32:08.000000000 +0200
+++ tbsync-4.16/content/modules/core.js	2025-03-15 23:49:58.000000000 +0100
@@ -1,335 +1,349 @@
-/*
- * This file is part of TbSync.
- *
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. 
- */
- 
-"use strict";
-
-var core = {
-
-  syncDataObj : null,
-
-  load: async function () {
-    this.syncDataObj = {};
-  },
-
-  unload: async function () {
-  },
-
-  isSyncing: function (accountID) {
-    let status = TbSync.db.getAccountProperty(accountID, "status"); //global status of the account
-    return (status == "syncing");
-  },
-  
-  isEnabled: function (accountID) {
-    let status = TbSync.db.getAccountProperty(accountID, "status");
-    return  (status != "disabled");
-  },
-
-  isConnected: function (accountID) {
-    let status = TbSync.db.getAccountProperty(accountID, "status");
-    let validFolders = TbSync.db.findFolders({"cached": false}, {"accountID": accountID});
-    return (status != "disabled" && validFolders.length > 0);
-  },
-  
-  resetSyncDataObj: function (accountID) {
-    this.syncDataObj[accountID] = new TbSync.SyncData(accountID);          
-  },
-  
-  getSyncDataObject: function (accountID) {
-    if (!this.syncDataObj.hasOwnProperty(accountID)) {
-      this.resetSyncDataObj(accountID);
-    }
-    return this.syncDataObj[accountID];        
-  },
-  
-  getNextPendingFolder: function (syncData) {
-    let sortedFolders = TbSync.providers[syncData.accountData.getAccountProperty("provider")].Base.getSortedFolders(syncData.accountData);
-    for (let i=0; i < sortedFolders.length; i++) {
-      if (sortedFolders[i].getFolderProperty("status") != "pending") continue;
-      syncData._setCurrentFolderData(sortedFolders[i]);
-      return true;
-    }
-    syncData._clearCurrentFolderData();
-    return false;
-  },
-  
-
-  syncAllAccounts: function () {
-    //get info of all accounts
-    let accounts = TbSync.db.getAccounts();
-
-    for (let i=0; i < accounts.IDs.length; i++) {
-      // core async sync function, but we do not wait until it has finished,
-      // but return right away and initiate sync of all accounts parallel
-      this.syncAccount(accounts.IDs[i]);
-    }
-  },
-
-  syncAccount: async function (accountID, aSyncDescription = {}) {
-    let syncDescription = {};
-    Object.assign(syncDescription, aSyncDescription);
-    
-    if (!syncDescription.hasOwnProperty("maxAccountReruns")) syncDescription.maxAccountReruns = 2;
-    if (!syncDescription.hasOwnProperty("maxFolderReruns")) syncDescription.maxFolderReruns = 2;
-    if (!syncDescription.hasOwnProperty("syncList")) syncDescription.syncList = true;
-    if (!syncDescription.hasOwnProperty("syncFolders")) syncDescription.syncFolders = null; // null ( = default = sync selected folders) or (empty) Array with folderData obj to be synced
-    if (!syncDescription.hasOwnProperty("syncJob")) syncDescription.syncJob = "sync";
-
-    //do not init sync if there is a sync running or account is not enabled
-    if (!this.isEnabled(accountID) || this.isSyncing(accountID)) return;
-
-    //create syncData object for each account (to be able to have parallel XHR)
-    this.resetSyncDataObj(accountID);
-    let syncData = this.getSyncDataObject(accountID);
-    
-    //send GUI into lock mode (status == syncing)
-    TbSync.db.setAccountProperty(accountID, "status", "syncing");
-    Services.obs.notifyObservers(null, "tbsync.observer.manager.updateAccountSettingsGui", accountID);
-    
-    let overallStatusData = new TbSync.StatusData();
-    let accountRerun;
-    let accountRuns = 0;
-    
-    do {
-      accountRerun = false;
-
-      if (accountRuns > syncDescription.maxAccountReruns) {
-        overallStatusData = new TbSync.StatusData(TbSync.StatusData.ERROR, "resync-loop");
-        break;
-      }      
-      accountRuns++;
-      
-      if (syncDescription.syncList) {
-        let listStatusData;
-        try {
-          listStatusData = await TbSync.providers[syncData.accountData.getAccountProperty("provider")].Base.syncFolderList(syncData, syncDescription.syncJob, accountRuns);
-        } catch (e) {
-          listStatusData = new TbSync.StatusData(TbSync.StatusData.WARNING, "JavaScriptError", e.message + "\n\n" + e.stack);
-        }
-          
-        if (!(listStatusData instanceof TbSync.StatusData)) {
-          overallStatusData = new TbSync.StatusData(TbSync.StatusData.ERROR, "apiError", "TbSync/"+syncData.accountData.getAccountProperty("provider")+": Base.syncFolderList() must return a StatusData object");
-          break;
-        }
-        
-        //if we have an error during folderList sync, there is no need to go on
-        if (listStatusData.type != TbSync.StatusData.SUCCESS) {
-          overallStatusData = listStatusData;
-          accountRerun = (listStatusData.type == TbSync.StatusData.ACCOUNT_RERUN)
-          TbSync.eventlog.add(listStatusData.type, syncData.eventLogInfo, listStatusData.message, listStatusData.details);
-          await new Promise(r => TbSync.window.setTimeout(r, 5000));
-          continue; //jumps to the while condition check
-        } else {
-          overallStatusData = new TbSync.StatusData();
-        }
-        
-        // Removes all leftover cached folders and sets all other folders to a well defined cached = "0"
-        // which will set this account as connected (if at least one non-cached folder is present).
-        this.removeCachedFolders(syncData);
-
-        // update folder list in GUI
-        Services.obs.notifyObservers(null, "tbsync.observer.manager.updateFolderList", syncData.accountData.accountID);
-      }
-      
-      // syncDescription.syncFolders is either null ( = default = sync selected folders) or an Array.
-      // Skip folder sync if Array is empty.
-      if (!Array.isArray(syncDescription.syncFolders) || syncDescription.syncFolders.length > 0) {
-        this.prepareFoldersForSync(syncData, syncDescription);
-
-        // update folder list in GUI
-        Services.obs.notifyObservers(null, "tbsync.observer.manager.updateFolderList", syncData.accountData.accountID);
-
-        // if any folder was found, sync
-        if (syncData.accountData.isConnected()) {
-          let folderRuns = 1;
-          do {
-            if (folderRuns > syncDescription.maxFolderReruns) {
-              overallStatusData = new TbSync.StatusData(TbSync.StatusData.ERROR, "resync-loop");
-              break;
-            }
-            
-            // getNextPendingFolder will set or clear currentFolderData of syncData
-            if (!this.getNextPendingFolder(syncData)) {
-              break;
-            }
-            
-            let folderStatusData;
-            try {
-              folderStatusData = await TbSync.providers[syncData.accountData.getAccountProperty("provider")].Base.syncFolder(syncData, syncDescription.syncJob, folderRuns);
-            } catch (e) {
-              folderStatusData = new TbSync.StatusData(TbSync.StatusData.WARNING, "JavaScriptError", e.message + "\n\n" + e.stack);
-            }
-            
-            if (!(folderStatusData instanceof TbSync.StatusData)) {
-              folderStatusData = new TbSync.StatusData(TbSync.StatusData.ERROR, "apiError", "TbSync/"+syncData.accountData.getAccountProperty("provider")+": Base.syncFolder() must return a StatusData object");
-            }
-
-            // if one of the folders indicated a FOLDER_RERUN, do not finish this
-            // folder but do it again
-            if (folderStatusData.type == TbSync.StatusData.FOLDER_RERUN) {
-              TbSync.eventlog.add(folderStatusData.type, syncData.eventLogInfo, folderStatusData.message, folderStatusData.details);
-              folderRuns++;
-              continue;
-            } else {
-              folderRuns = 1;
-            }
-            
-            this.finishFolderSync(syncData, folderStatusData);
-
-            //if one of the folders indicated an ERROR, abort sync
-            if (folderStatusData.type == TbSync.StatusData.ERROR) {
-              break;
-            }
-            
-            //if the folder has send an ACCOUNT_RERUN, abort sync and rerun the entire account
-            if (folderStatusData.type == TbSync.StatusData.ACCOUNT_RERUN) {
-              syncDescription.syncList = true;
-              accountRerun = true;
-              break;
-            }
-            
-          } while (true);
-        } else {
-          overallStatusData = new TbSync.StatusData(TbSync.StatusData.ERROR, "no-folders-found-on-server");
-        }
-      }
-    
-    } while (accountRerun);
-    
-    this.finishAccountSync(syncData, overallStatusData);
-  },
-  
-  // this could be added to AccountData, but I do not want that in public
-  setTargetModified: function (folderData) {
-    if (!folderData.accountData.isSyncing() && folderData.accountData.isEnabled()) {
-      folderData.accountData.setAccountProperty("status", "notsyncronized");
-      folderData.setFolderProperty("status", "modified");
-      //notify settings gui to update status
-       Services.obs.notifyObservers(null, "tbsync.observer.manager.updateSyncstate", folderData.accountID);
-    }
-  },
-  
-  enableAccount: function(accountID) {
-    let accountData = new TbSync.AccountData(accountID);
-    TbSync.providers[accountData.getAccountProperty("provider")].Base.onEnableAccount(accountData);
-    accountData.setAccountProperty("status", "notsyncronized");
-    accountData.resetAccountProperty("lastsynctime");        
-  },
-
-  disableAccount: function(accountID) {
-    let accountData = new TbSync.AccountData(accountID);
-    TbSync.providers[accountData.getAccountProperty("provider")].Base.onDisableAccount(accountData);
-    accountData.setAccountProperty("status", "disabled");
-    
-    let folders = accountData.getAllFolders();
-    for (let folder of folders) {
-      if (folder.getFolderProperty("selected")) {
-        folder.targetData.removeTarget(); 
-        folder.setFolderProperty("selected", false);
-      }
-      folder.setFolderProperty("cached", true);
-    }
-  },
-
-  //removes all leftover cached folders and sets all other folders to a well defined cached = "0"
-  //which will set this account as connected (if at least one non-cached folder is present)
-  removeCachedFolders: function(syncData) {
-    let folders = syncData.accountData.getAllFoldersIncludingCache();
-    for (let folder of folders) {
-      //delete all leftover cached folders
-      if (folder.getFolderProperty("cached")) {
-        TbSync.db.deleteFolder(folder.accountID, folder.folderID);
-        continue;
-      } else {
-        //set well defined cache state
-        folder.setFolderProperty("cached", false);
-      }
-    }
-  },
-  
-  //set allrequested folders to "pending", so they are marked for syncing 
-  prepareFoldersForSync: function(syncData, syncDescription) {
-    let folders = syncData.accountData.getAllFolders();
-    for (let folder of folders) {
-      let requested = (Array.isArray(syncDescription.syncFolders) && syncDescription.syncFolders.filter(f => f.folderID == folder.folderID).length > 0);
-      let selected = (!Array.isArray(syncDescription.syncFolders) && folder.getFolderProperty("selected"));
-
-      //set folders to pending, so they get synced
-      if (requested || selected) {
-         folder.setFolderProperty("status", "pending");
-      }
-    }
-  },
-  
-  finishFolderSync: function(syncData, statusData) {        
-    if (statusData.type != TbSync.StatusData.SUCCESS) {
-      //report error
-      TbSync.eventlog.add(statusData.type, syncData.eventLogInfo, statusData.message, statusData.details);
-    }
-    
-    //if this is a success, prepend success to the status message, 
-    //otherwise just set the message
-    let status;
-    if (statusData.type == TbSync.StatusData.SUCCESS || statusData.message == "") {
-      status = statusData.type;
-      if (statusData.message) status = status + "." + statusData.message;
-    } else {
-      status = statusData.message;
-    }
-    
-    if (syncData.currentFolderData) {
-      syncData.currentFolderData.setFolderProperty("status", status);
-      syncData.currentFolderData.setFolderProperty("lastsynctime", Date.now());
-      //clear folderID to fall back to account-only-mode (folder is done!)
-      syncData._clearCurrentFolderData();
-    } 
-
-     syncData.setSyncState("done");        
-  },
-
-  finishAccountSync: function(syncData, statusData) {
-    // set each folder with PENDING status to ABORTED
-    let folders = TbSync.db.findFolders({"status": "pending"}, {"accountID": syncData.accountData.accountID});
-    for (let i=0; i < folders.length; i++) {
-      TbSync.db.setFolderProperty(folders[i].accountID, folders[i].folderID, "status", "aborted");
-    }
-    
-    //if this is a success, prepend success to the status message, 
-    //otherwise just set the message
-    let status;
-    if (statusData.type == TbSync.StatusData.SUCCESS || statusData.message == "") {
-      status = statusData.type;
-      if (statusData.message) status = status + "." + statusData.message;
-    } else {
-      status = statusData.message;
-    }
-
-    
-    if (statusData.type != TbSync.StatusData.SUCCESS) {
-      //report error
-      TbSync.eventlog.add("warning", syncData.eventLogInfo, statusData.message, statusData.details);
-    } else {
-      //account itself is ok, search for folders with error
-      folders = TbSync.db.findFolders({"selected": true, "cached": false}, {"accountID": syncData.accountData.accountID});
-      for (let i in folders) {
-        let folderstatus = folders[i].data.status.split(".")[0];
-        if (folderstatus != "" && folderstatus != TbSync.StatusData.SUCCESS && folderstatus != "aborted") {
-          status = "foldererror";
-          break;
-        }
-      }
-    }    
-    
-    //done
-    syncData.accountData.setAccountProperty("lastsynctime", Date.now());
-    syncData.accountData.setAccountProperty("status", status);
-    syncData.setSyncState("accountdone"); 
-    Services.obs.notifyObservers(null, "tbsync.observer.manager.updateFolderList", syncData.accountData.accountID);
-    this.resetSyncDataObj(syncData.accountData.accountID);
-  }    
-  
-}
+/*
+ * This file is part of TbSync.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. 
+ */
+ 
+"use strict";
+
+var { setTimeout } = ChromeUtils.importESModule(
+  "resource://gre/modules/Timer.sys.mjs"
+);
+var { ExtensionParent } = ChromeUtils.importESModule(
+  "resource://gre/modules/ExtensionParent.sys.mjs"
+);
+
+var tbsyncExtension = ExtensionParent.GlobalManager.getExtension(
+  "tbsync at jobisoft.de"
+);
+var { TbSync } = ChromeUtils.importESModule(
+  `chrome://tbsync/content/tbsync.sys.mjs?${tbsyncExtension.manifest.version}`
+);
+
+var core = {
+
+  syncDataObj : null,
+
+  load: async function () {
+    this.syncDataObj = {};
+  },
+
+  unload: async function () {
+  },
+
+  isSyncing: function (accountID) {
+    let status = TbSync.db.getAccountProperty(accountID, "status"); //global status of the account
+    return (status == "syncing");
+  },
+  
+  isEnabled: function (accountID) {
+    let status = TbSync.db.getAccountProperty(accountID, "status");
+    return  (status != "disabled");
+  },
+
+  isConnected: function (accountID) {
+    let status = TbSync.db.getAccountProperty(accountID, "status");
+    let validFolders = TbSync.db.findFolders({"cached": false}, {"accountID": accountID});
+    return (status != "disabled" && validFolders.length > 0);
+  },
+  
+  resetSyncDataObj: function (accountID) {
+    this.syncDataObj[accountID] = new TbSync.SyncData(accountID);          
+  },
+  
+  getSyncDataObject: function (accountID) {
+    if (!this.syncDataObj.hasOwnProperty(accountID)) {
+      this.resetSyncDataObj(accountID);
+    }
+    return this.syncDataObj[accountID];        
+  },
+  
+  getNextPendingFolder: function (syncData) {
+    let sortedFolders = TbSync.providers[syncData.accountData.getAccountProperty("provider")].Base.getSortedFolders(syncData.accountData);
+    for (let i=0; i < sortedFolders.length; i++) {
+      if (sortedFolders[i].getFolderProperty("status") != "pending") continue;
+      syncData._setCurrentFolderData(sortedFolders[i]);
+      return true;
+    }
+    syncData._clearCurrentFolderData();
+    return false;
+  },
+  
+
+  syncAllAccounts: function () {
+    //get info of all accounts
+    let accounts = TbSync.db.getAccounts();
+
+    for (let i=0; i < accounts.IDs.length; i++) {
+      // core async sync function, but we do not wait until it has finished,
+      // but return right away and initiate sync of all accounts parallel
+      this.syncAccount(accounts.IDs[i]);
+    }
+  },
+
+  syncAccount: async function (accountID, aSyncDescription = {}) {
+    let syncDescription = {};
+    Object.assign(syncDescription, aSyncDescription);
+    
+    if (!syncDescription.hasOwnProperty("maxAccountReruns")) syncDescription.maxAccountReruns = 2;
+    if (!syncDescription.hasOwnProperty("maxFolderReruns")) syncDescription.maxFolderReruns = 2;
+    if (!syncDescription.hasOwnProperty("syncList")) syncDescription.syncList = true;
+    if (!syncDescription.hasOwnProperty("syncFolders")) syncDescription.syncFolders = null; // null ( = default = sync selected folders) or (empty) Array with folderData obj to be synced
+    if (!syncDescription.hasOwnProperty("syncJob")) syncDescription.syncJob = "sync";
+
+    //do not init sync if there is a sync running or account is not enabled
+    if (!this.isEnabled(accountID) || this.isSyncing(accountID)) return;
+
+    //create syncData object for each account (to be able to have parallel XHR)
+    this.resetSyncDataObj(accountID);
+    let syncData = this.getSyncDataObject(accountID);
+    
+    //send GUI into lock mode (status == syncing)
+    TbSync.db.setAccountProperty(accountID, "status", "syncing");
+    Services.obs.notifyObservers(null, "tbsync.observer.manager.updateAccountSettingsGui", accountID);
+    
+    let overallStatusData = new TbSync.StatusData();
+    let accountRerun;
+    let accountRuns = 0;
+    
+    do {
+      accountRerun = false;
+
+      if (accountRuns > syncDescription.maxAccountReruns) {
+        overallStatusData = new TbSync.StatusData(TbSync.StatusData.ERROR, "resync-loop");
+        break;
+      }      
+      accountRuns++;
+      
+      if (syncDescription.syncList) {
+        let listStatusData;
+        try {
+          listStatusData = await TbSync.providers[syncData.accountData.getAccountProperty("provider")].Base.syncFolderList(syncData, syncDescription.syncJob, accountRuns);
+        } catch (e) {
+          listStatusData = new TbSync.StatusData(TbSync.StatusData.WARNING, "JavaScriptError", e.message + "\n\n" + e.stack);
+        }
+          
+        if (!(listStatusData instanceof TbSync.StatusData)) {
+          overallStatusData = new TbSync.StatusData(TbSync.StatusData.ERROR, "apiError", "TbSync/"+syncData.accountData.getAccountProperty("provider")+": Base.syncFolderList() must return a StatusData object");
+          break;
+        }
+        
+        //if we have an error during folderList sync, there is no need to go on
+        if (listStatusData.type != TbSync.StatusData.SUCCESS) {
+          overallStatusData = listStatusData;
+          accountRerun = (listStatusData.type == TbSync.StatusData.ACCOUNT_RERUN)
+          TbSync.eventlog.add(listStatusData.type, syncData.eventLogInfo, listStatusData.message, listStatusData.details);
+          await new Promise(r => setTimeout(r, 5000));
+          continue; //jumps to the while condition check
+        } else {
+          overallStatusData = new TbSync.StatusData();
+        }
+        
+        // Removes all leftover cached folders and sets all other folders to a well defined cached = "0"
+        // which will set this account as connected (if at least one non-cached folder is present).
+        this.removeCachedFolders(syncData);
+
+        // update folder list in GUI
+        Services.obs.notifyObservers(null, "tbsync.observer.manager.updateFolderList", syncData.accountData.accountID);
+      }
+      
+      // syncDescription.syncFolders is either null ( = default = sync selected folders) or an Array.
+      // Skip folder sync if Array is empty.
+      if (!Array.isArray(syncDescription.syncFolders) || syncDescription.syncFolders.length > 0) {
+        this.prepareFoldersForSync(syncData, syncDescription);
+
+        // update folder list in GUI
+        Services.obs.notifyObservers(null, "tbsync.observer.manager.updateFolderList", syncData.accountData.accountID);
+
+        // if any folder was found, sync
+        if (syncData.accountData.isConnected()) {
+          let folderRuns = 1;
+          do {
+            if (folderRuns > syncDescription.maxFolderReruns) {
+              overallStatusData = new TbSync.StatusData(TbSync.StatusData.ERROR, "resync-loop");
+              break;
+            }
+            
+            // getNextPendingFolder will set or clear currentFolderData of syncData
+            if (!this.getNextPendingFolder(syncData)) {
+              break;
+            }
+            
+            let folderStatusData;
+            try {
+              folderStatusData = await TbSync.providers[syncData.accountData.getAccountProperty("provider")].Base.syncFolder(syncData, syncDescription.syncJob, folderRuns);
+            } catch (e) {
+              folderStatusData = new TbSync.StatusData(TbSync.StatusData.WARNING, "JavaScriptError", e.message + "\n\n" + e.stack);
+            }
+            
+            if (!(folderStatusData instanceof TbSync.StatusData)) {
+              folderStatusData = new TbSync.StatusData(TbSync.StatusData.ERROR, "apiError", "TbSync/"+syncData.accountData.getAccountProperty("provider")+": Base.syncFolder() must return a StatusData object");
+            }
+
+            // if one of the folders indicated a FOLDER_RERUN, do not finish this
+            // folder but do it again
+            if (folderStatusData.type == TbSync.StatusData.FOLDER_RERUN) {
+              TbSync.eventlog.add(folderStatusData.type, syncData.eventLogInfo, folderStatusData.message, folderStatusData.details);
+              folderRuns++;
+              continue;
+            } else {
+              folderRuns = 1;
+            }
+            
+            this.finishFolderSync(syncData, folderStatusData);
+
+            //if one of the folders indicated an ERROR, abort sync
+            if (folderStatusData.type == TbSync.StatusData.ERROR) {
+              break;
+            }
+            
+            //if the folder has send an ACCOUNT_RERUN, abort sync and rerun the entire account
+            if (folderStatusData.type == TbSync.StatusData.ACCOUNT_RERUN) {
+              syncDescription.syncList = true;
+              accountRerun = true;
+              break;
+            }
+            
+          } while (true);
+        } else {
+          overallStatusData = new TbSync.StatusData(TbSync.StatusData.ERROR, "no-folders-found-on-server");
+        }
+      }
+    
+    } while (accountRerun);
+    
+    this.finishAccountSync(syncData, overallStatusData);
+  },
+  
+  // this could be added to AccountData, but I do not want that in public
+  setTargetModified: function (folderData) {
+    if (!folderData.accountData.isSyncing() && folderData.accountData.isEnabled()) {
+      folderData.accountData.setAccountProperty("status", "notsyncronized");
+      folderData.setFolderProperty("status", "modified");
+      //notify settings gui to update status
+       Services.obs.notifyObservers(null, "tbsync.observer.manager.updateSyncstate", folderData.accountID);
+    }
+  },
+  
+  enableAccount: function(accountID) {
+    let accountData = new TbSync.AccountData(accountID);
+    TbSync.providers[accountData.getAccountProperty("provider")].Base.onEnableAccount(accountData);
+    accountData.setAccountProperty("status", "notsyncronized");
+    accountData.resetAccountProperty("lastsynctime");        
+  },
+
+  disableAccount: function(accountID) {
+    let accountData = new TbSync.AccountData(accountID);
+    TbSync.providers[accountData.getAccountProperty("provider")].Base.onDisableAccount(accountData);
+    accountData.setAccountProperty("status", "disabled");
+    
+    let folders = accountData.getAllFolders();
+    for (let folder of folders) {
+      if (folder.getFolderProperty("selected")) {
+        folder.targetData.removeTarget(); 
+        folder.setFolderProperty("selected", false);
+      }
+      folder.setFolderProperty("cached", true);
+    }
+  },
+
+  //removes all leftover cached folders and sets all other folders to a well defined cached = "0"
+  //which will set this account as connected (if at least one non-cached folder is present)
+  removeCachedFolders: function(syncData) {
+    let folders = syncData.accountData.getAllFoldersIncludingCache();
+    for (let folder of folders) {
+      //delete all leftover cached folders
+      if (folder.getFolderProperty("cached")) {
+        TbSync.db.deleteFolder(folder.accountID, folder.folderID);
+        continue;
+      } else {
+        //set well defined cache state
+        folder.setFolderProperty("cached", false);
+      }
+    }
+  },
+  
+  //set allrequested folders to "pending", so they are marked for syncing 
+  prepareFoldersForSync: function(syncData, syncDescription) {
+    let folders = syncData.accountData.getAllFolders();
+    for (let folder of folders) {
+      let requested = (Array.isArray(syncDescription.syncFolders) && syncDescription.syncFolders.filter(f => f.folderID == folder.folderID).length > 0);
+      let selected = (!Array.isArray(syncDescription.syncFolders) && folder.getFolderProperty("selected"));
+
+      //set folders to pending, so they get synced
+      if (requested || selected) {
+         folder.setFolderProperty("status", "pending");
+      }
+    }
+  },
+  
+  finishFolderSync: function(syncData, statusData) {        
+    if (statusData.type != TbSync.StatusData.SUCCESS) {
+      //report error
+      TbSync.eventlog.add(statusData.type, syncData.eventLogInfo, statusData.message, statusData.details);
+    }
+    
+    //if this is a success, prepend success to the status message, 
+    //otherwise just set the message
+    let status;
+    if (statusData.type == TbSync.StatusData.SUCCESS || statusData.message == "") {
+      status = statusData.type;
+      if (statusData.message) status = status + "." + statusData.message;
+    } else {
+      status = statusData.message;
+    }
+    
+    if (syncData.currentFolderData) {
+      syncData.currentFolderData.setFolderProperty("status", status);
+      syncData.currentFolderData.setFolderProperty("lastsynctime", Date.now());
+      //clear folderID to fall back to account-only-mode (folder is done!)
+      syncData._clearCurrentFolderData();
+    } 
+
+     syncData.setSyncState("done");        
+  },
+
+  finishAccountSync: function(syncData, statusData) {
+    // set each folder with PENDING status to ABORTED
+    let folders = TbSync.db.findFolders({"status": "pending"}, {"accountID": syncData.accountData.accountID});
+    for (let i=0; i < folders.length; i++) {
+      TbSync.db.setFolderProperty(folders[i].accountID, folders[i].folderID, "status", "aborted");
+    }
+    
+    //if this is a success, prepend success to the status message, 
+    //otherwise just set the message
+    let status;
+    if (statusData.type == TbSync.StatusData.SUCCESS || statusData.message == "") {
+      status = statusData.type;
+      if (statusData.message) status = status + "." + statusData.message;
+    } else {
+      status = statusData.message;
+    }
+
+    
+    if (statusData.type != TbSync.StatusData.SUCCESS) {
+      //report error
+      TbSync.eventlog.add("warning", syncData.eventLogInfo, statusData.message, statusData.details);
+    } else {
+      //account itself is ok, search for folders with error
+      folders = TbSync.db.findFolders({"selected": true, "cached": false}, {"accountID": syncData.accountData.accountID});
+      for (let i in folders) {
+        let folderstatus = folders[i].data.status.split(".")[0];
+        if (folderstatus != "" && folderstatus != TbSync.StatusData.SUCCESS && folderstatus != "aborted") {
+          status = "foldererror";
+          break;
+        }
+      }
+    }    
+    
+    //done
+    syncData.accountData.setAccountProperty("lastsynctime", Date.now());
+    syncData.accountData.setAccountProperty("status", status);
+    syncData.setSyncState("accountdone"); 
+    Services.obs.notifyObservers(null, "tbsync.observer.manager.updateFolderList", syncData.accountData.accountID);
+    this.resetSyncDataObj(syncData.accountData.accountID);
+  }    
+  
+}
diff -Nru tbsync-4.12/content/modules/db.js tbsync-4.16/content/modules/db.js
--- tbsync-4.12/content/modules/db.js	2024-08-27 18:32:08.000000000 +0200
+++ tbsync-4.16/content/modules/db.js	2025-03-15 23:49:58.000000000 +0100
@@ -1,415 +1,427 @@
-/*
- * This file is part of TbSync.
- *
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. 
- */
- 
-"use strict";
-
-var { DeferredTask } = ChromeUtils.importESModule("resource://gre/modules/DeferredTask.sys.mjs");
-
-var db = {
-
-  loaded: false,
-
-  files: {
-    accounts: {
-      name: "accounts68.json", 
-      default: JSON.stringify({ sequence: 0, data : {} })
-      //data[account] = {row}
-      },
-    folders: {
-      name: "folders68.json", 
-      default: JSON.stringify({})
-      //assoziative array of assoziative array : folders[<int>accountID][<string>folderID] = {row} 
-      },
-    changelog: {
-      name: "changelog68.json", 
-      default: JSON.stringify([]),
-      },
-  },
-    
-  load: async function ()  {
-    //DB Concept:
-    //-- on application start, data is read async from json file into object
-    //-- add-on only works on object
-    //-- each time data is changed, an async write job is initiated <writeDelay>ms in the future and is resceduled, if another request arrives within that time
-
-    for (let f in this.files) {
-      this.files[f].write = new DeferredTask(() => this.writeAsync(f), 6000);
-      
-      try {
-        this[f] = await IOUtils.readJSON(TbSync.io.getAbsolutePath(this.files[f].name));
-        this.files[f].found = true;
-      } catch (e) {
-        //if there is no file, there is no file...
-        this[f] = JSON.parse(this.files[f].default);
-        this.files[f].found = false;
-        Components.utils.reportError(e);
-      }
-    }
-
-    function getNewDeviceId4Migration() {
-        //taken from https://jsfiddle.net/briguy37/2MVFd/
-        let d = new Date().getTime();
-        let uuid = 'xxxxxxxxxxxxxxxxyxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
-            let r = (d + Math.random()*16)%16 | 0;
-            d = Math.floor(d/16);
-            return (c=='x' ? r : (r&0x3|0x8)).toString(16);
-        });
-        return "MZTB" + uuid;
-    }
-    
-    this.loaded = true;
-  },
-  
-  unload: async function ()  {
-    if (this.loaded) {
-      for (let f in this.files) {
-        try{ 
-          //abort write delay timers and write current file content to disk 
-          await this.files[f].write.finalize();
-        } catch (e) {
-          Components.utils.reportError(e);
-        }                
-      }
-    }
-  },
-  
-
-  saveFile: function (f) {
-    if (this.loaded) {
-      //cancel any pending write and schedule a new delayed write
-      this.files[f].write.disarm();
-      this.files[f].write.arm();
-    }
-  },
-
-  writeAsync: async function (f) {
-    // if this file was not found/read on load, do not write default content to prevent clearing of data in case of read-errors
-    if (!this.files[f].found && JSON.stringify(this[f]) == this.files[f].default) {
-      return;
-    }
-    
-    let filepath = TbSync.io.getAbsolutePath(this.files[f].name);
-    await IOUtils.writeJSON(filepath, this[f]);
-  },
-
-
-
-  // simple convenience wrapper
-  saveAccounts: function () {
-    this.saveFile("accounts");
-  },
-
-  saveFolders: function () {
-    this.saveFile("folders");
-  },
-
-  saveChangelog: function () {
-    this.saveFile("changelog");
-  },
-
-  
-
-  // CHANGELOG FUNCTIONS
-  getItemStatusFromChangeLog: function (parentId, itemId) {   
-    for (let i=0; i<this.changelog.length; i++) {
-      if (this.changelog[i].parentId == parentId && this.changelog[i].itemId == itemId) return this.changelog[i].status;
-    }
-    return null;
-  },
-
-  getItemDataFromChangeLog: function (parentId, itemId) {   
-    for (let i=0; i<this.changelog.length; i++) {
-      if (this.changelog[i].parentId == parentId && this.changelog[i].itemId == itemId) return this.changelog[i];
-    }
-    return null;
-  },
-  
-  addItemToChangeLog: function (parentId, itemId, status) {
-    this.removeItemFromChangeLog(parentId, itemId);
-
-    //ChangelogData object
-    let row = {
-      "parentId" : parentId,
-      "itemId" : itemId,
-      "timestamp": Date.now(),
-      "status" : status};
-    
-    this.changelog.push(row);
-    this.saveChangelog();
-  },
-
-  removeItemFromChangeLog: function (parentId, itemId, moveToEnd = false) {
-    for (let i=this.changelog.length-1; i>-1; i-- ) {
-      if (this.changelog[i].parentId == parentId && this.changelog[i].itemId == itemId) {
-        let row = this.changelog.splice(i,1);
-        if (moveToEnd) this.changelog.push(row[0]);
-        this.saveChangelog();
-        return;
-      }
-    }
-  },
-
-  removeAllItemsFromChangeLogWithStatus: function (parentId, status) {
-    for (let i=this.changelog.length-1; i>-1; i-- ) {
-      if (this.changelog[i].parentId == parentId && this.changelog[i].status == status) {
-        let row = this.changelog.splice(i,1);
-      }
-    }
-    this.saveChangelog();
-  },
-
-  // Remove all cards of a parentId from ChangeLog
-  clearChangeLog: function (parentId) {
-    if (parentId) {
-      // we allow extra parameters added to a parentId, but still want to delete all items of that parent
-      // so we check for startsWith instead of equal
-      for (let i=this.changelog.length-1; i>-1; i-- ) {
-        if (this.changelog[i].parentId.startsWith(parentId)) this.changelog.splice(i,1);
-      }
-      this.saveChangelog();
-    }
-  },
-
-  getItemsFromChangeLog: function (parentId, maxnumbertosend, status = null) {        
-    //maxnumbertosend = 0 will return all results
-    let log = [];
-    let counts = 0;
-    for (let i=0; i<this.changelog.length && (log.length < maxnumbertosend || maxnumbertosend == 0); i++) {
-      if (this.changelog[i].parentId == parentId && (status === null || (typeof this.changelog[i].status == "string" && this.changelog[i].status.indexOf(status) != -1))) log.push(this.changelog[i]);
-    }
-    return log;
-  },
-
-
-
-
-
-  // ACCOUNT FUNCTIONS
-
-  addAccount: function (accountname, newAccountEntry) {
-    this.accounts.sequence++;
-    let id = this.accounts.sequence.toString();
-    newAccountEntry.accountID = id;
-    newAccountEntry.accountname = accountname;
-    
-    this.accounts.data[id] = newAccountEntry;
-    this.saveAccounts();
-    return id;
-  },
-
-  removeAccount: function (accountID) {
-    //check if accountID is known
-    if (this.accounts.data.hasOwnProperty(accountID) == false ) {
-      throw "Unknown accountID!" + "\nThrown by db.removeAccount("+accountID+ ")";
-    } else {
-      delete (this.accounts.data[accountID]);
-      delete (this.folders[accountID]);
-      this.saveAccounts();
-      this.saveFolders();
-    }
-  },
-
-  getAccounts: function () {
-    let accounts = {};
-    accounts.IDs = Object.keys(this.accounts.data).filter(accountID => TbSync.providers.loadedProviders.hasOwnProperty(this.accounts.data[accountID].provider)).sort((a, b) => a - b);
-    accounts.allIDs =  Object.keys(this.accounts.data).sort((a, b) => a - b)
-    accounts.data = this.accounts.data;
-    return accounts;
-  },
-
-  getAccount: function (accountID) {
-    //check if accountID is known
-    if (this.accounts.data.hasOwnProperty(accountID) == false ) {
-      throw "Unknown accountID!" + "\nThrown by db.getAccount("+accountID+ ")";
-    } else {
-      return this.accounts.data[accountID];
-    }
-  }, 
-
-  isValidAccountProperty: function (provider, name) {
-    if (["provider"].includes(name)) //internal properties, do not need to be defined by user/provider
-      return true;
-
-    //check if provider is installed
-    if (!TbSync.providers.loadedProviders.hasOwnProperty(provider)) {
-      TbSync.dump("Error @ isValidAccountProperty", "Unknown provider <"+provider+">!");
-      return false;
-    }
-    
-    if (TbSync.providers.getDefaultAccountEntries(provider).hasOwnProperty(name)) {
-      return true;
-    } else {
-      TbSync.dump("Error @ isValidAccountProperty", "Unknown account setting <"+name+">!");
-      return false;
-    }            
-  },
-
-  getAccountProperty: function (accountID, name) {
-    // if the requested accountID does not exist, getAccount() will fail
-    let data = this.getAccount(accountID);
-    
-    //check if field is allowed and get value or default value if setting is not set
-    if (this.isValidAccountProperty(data.provider, name)) {
-      if (data.hasOwnProperty(name)) return data[name];
-      else return TbSync.providers.getDefaultAccountEntries(data.provider)[name];
-    }
-  }, 
-
-  setAccountProperty: function (accountID , name, value) {
-    // if the requested accountID does not exist, getAccount() will fail
-    let data = this.getAccount(accountID);
-
-    //check if field is allowed, and set given value 
-    if (this.isValidAccountProperty(data.provider, name)) {
-      this.accounts.data[accountID][name] = value;
-    }
-    this.saveAccounts();
-  },
-
-  resetAccountProperty: function (accountID , name) {
-    // if the requested accountID does not exist, getAccount() will fail
-    let data = this.getAccount(accountID);
-    let defaults = TbSync.providers.getDefaultAccountEntries(data.provider);        
-
-    //check if field is allowed, and set given value 
-    if (this.isValidAccountProperty(data.provider, name)) {
-      this.accounts.data[accountID][name] = defaults[name];
-    }
-    this.saveAccounts();
-  },
-
-
-
-
-  // FOLDER FUNCTIONS
-
-  addFolder: function(accountID) {
-    let folderID = TbSync.generateUUID();
-    let provider = this.getAccountProperty(accountID, "provider");        
-    
-    if (!this.folders.hasOwnProperty(accountID)) this.folders[accountID] = {};                        
-    
-    //create folder with default settings
-    this.folders[accountID][folderID] = TbSync.providers.getDefaultFolderEntries(accountID);
-    this.saveFolders();
-    return folderID;
-  },
-
-  deleteFolder: function(accountID, folderID) {
-    delete (this.folders[accountID][folderID]);
-    //if there are no more folders, delete entire account entry
-    if (Object.keys(this.folders[accountID]).length === 0) delete (this.folders[accountID]);
-    this.saveFolders();
-  },
-
-  isValidFolderProperty: function (accountID, field) {
-    if (["cached"].includes(field)) //internal properties, do not need to be defined by user/provider
-      return true;
-    
-    //check if provider is installed
-    let provider = this.getAccountProperty(accountID, "provider");
-    if (!TbSync.providers.loadedProviders.hasOwnProperty(provider)) {
-      TbSync.dump("Error @ isValidFolderProperty", "Unknown provider <"+provider+"> for accountID <"+accountID+">!");
-      return false;
-    }
-
-    if (TbSync.providers.getDefaultFolderEntries(accountID).hasOwnProperty(field)) {
-      return true;
-    } else {
-      TbSync.dump("Error @ isValidFolderProperty", "Unknown folder setting <"+field+"> for accountID <"+accountID+">!");
-      return false;
-    }
-  },
-
-  getFolderProperty: function(accountID, folderID, field) {
-    //does the field exist?
-    let folder = (this.folders.hasOwnProperty(accountID) && this.folders[accountID].hasOwnProperty(folderID)) ? this.folders[accountID][folderID] : null;
-    
-    if (folder === null) {
-      throw "Unknown folder <"+folderID+">!";
-    }
-    
-    if (this.isValidFolderProperty(accountID, field)) {
-      if (folder.hasOwnProperty(field)) {
-        return folder[field];
-      } else {
-        let provider = this.getAccountProperty(accountID, "provider");
-        let defaultFolder = TbSync.providers.getDefaultFolderEntries(accountID);
-        //handle internal fields, that do not have a default value (see isValidFolderProperty)
-        return (defaultFolder[field] ? defaultFolder[field] : "");
-      }
-    }
-  },
-
-  setFolderProperty: function (accountID, folderID, field, value) {
-    if (this.isValidFolderProperty(accountID, field)) {
-      this.folders[accountID][folderID][field] = value;
-      this.saveFolders();
-    }
-  },
-  
-  resetFolderProperty: function (accountID, folderID, field) {
-    let provider = this.getAccountProperty(accountID, "provider");
-    let defaults = TbSync.providers.getDefaultFolderEntries(accountID);        
-    if (this.isValidFolderProperty(accountID, field)) {
-      //handle internal fields, that do not have a default value (see isValidFolderProperty)
-      this.folders[accountID][folderID][field] = defaults[field] ? defaults[field] : "";
-      this.saveFolders();
-    }
-  },
-
-  findFolders: function (folderQuery = {}, accountQuery = {}) {
-    // folderQuery is an object with one or more key:value pairs (logical AND) ::
-    // {key1: value1, key2: value2} 
-    // the value itself may be an array (logical OR)
-    let data = [];
-    let folderQueryEntries = Object.entries(folderQuery);
-    let folderFields = folderQueryEntries.map(pair => pair[0]);
-    let folderValues = folderQueryEntries.map(pair => Array.isArray(pair[1]) ? pair[1] : [pair[1]]);
-    
-    let accountQueryEntries = Object.entries(accountQuery);
-    let accountFields = accountQueryEntries.map(pair => pair[0]);
-    let accountValues = accountQueryEntries.map(pair => Array.isArray(pair[1]) ? pair[1] : [pair[1]]);
-    
-    for (let aID in this.folders) {
-      //is this a leftover folder of an account, which no longer there?
-      if (!this.accounts.data.hasOwnProperty(aID)) {
-        delete (this.folders[aID]);
-        this.saveFolders();
-        continue;
-      }
-    
-      //skip this folder, if it belongs to an account currently not supported (provider not loaded)
-      if (!TbSync.providers.loadedProviders.hasOwnProperty(this.getAccountProperty(aID, "provider"))) {
-        continue;
-      }
-
-      //does this account match account search options?
-      let accountmatch = true;
-      for (let a = 0; a < accountFields.length && accountmatch; a++) {
-        accountmatch = accountValues[a].some(item => item === this.getAccountProperty(aID, accountFields[a]));
-        //Services.console.logStringMessage("   " + accountFields[a] + ":" + this.getAccountProperty(aID, accountFields[a]) + " in " + JSON.stringify(accountValues[a]) + " ? " + accountmatch);
-      }
-      
-      if (accountmatch) {
-        for (let fID in this.folders[aID]) {
-          //does this folder match folder search options?                
-          let foldermatch = true;
-          for (let f = 0; f < folderFields.length && foldermatch; f++) {
-            foldermatch = folderValues[f].some(item => item === this.getFolderProperty(aID, fID, folderFields[f]));
-            //Services.console.logStringMessage("   " + folderFields[f] + ":" + this.getFolderProperty(aID, fID, folderFields[f]) + " in " + JSON.stringify(folderValues[f]) + " ? " + foldermatch);
-          }
-          if (foldermatch) data.push({accountID: aID, folderID: fID, data: this.folders[aID][fID]});
-        }
-      }
-    }
-
-    //still a reference to the original data
-    return data;
-  }
-};
+/*
+ * This file is part of TbSync.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. 
+ */
+ 
+"use strict";
+
+var { DeferredTask } = ChromeUtils.importESModule(
+  "resource://gre/modules/DeferredTask.sys.mjs"
+);
+var { ExtensionParent } = ChromeUtils.importESModule(
+  "resource://gre/modules/ExtensionParent.sys.mjs"
+);
+
+var tbsyncExtension = ExtensionParent.GlobalManager.getExtension(
+  "tbsync at jobisoft.de"
+);
+var { TbSync } = ChromeUtils.importESModule(
+  `chrome://tbsync/content/tbsync.sys.mjs?${tbsyncExtension.manifest.version}`
+);
+
+var db = {
+
+  loaded: false,
+
+  files: {
+    accounts: {
+      name: "accounts68.json", 
+      default: JSON.stringify({ sequence: 0, data : {} })
+      //data[account] = {row}
+      },
+    folders: {
+      name: "folders68.json", 
+      default: JSON.stringify({})
+      //assoziative array of assoziative array : folders[<int>accountID][<string>folderID] = {row} 
+      },
+    changelog: {
+      name: "changelog68.json", 
+      default: JSON.stringify([]),
+      },
+  },
+    
+  load: async function ()  {
+    //DB Concept:
+    //-- on application start, data is read async from json file into object
+    //-- add-on only works on object
+    //-- each time data is changed, an async write job is initiated <writeDelay>ms in the future and is resceduled, if another request arrives within that time
+
+    for (let f in this.files) {
+      this.files[f].write = new DeferredTask(() => this.writeAsync(f), 6000);
+      
+      try {
+        this[f] = await IOUtils.readJSON(TbSync.io.getAbsolutePath(this.files[f].name));
+        this.files[f].found = true;
+      } catch (e) {
+        //if there is no file, there is no file...
+        this[f] = JSON.parse(this.files[f].default);
+        this.files[f].found = false;
+        Components.utils.reportError(e);
+      }
+    }
+
+    function getNewDeviceId4Migration() {
+        //taken from https://jsfiddle.net/briguy37/2MVFd/
+        let d = new Date().getTime();
+        let uuid = 'xxxxxxxxxxxxxxxxyxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
+            let r = (d + Math.random()*16)%16 | 0;
+            d = Math.floor(d/16);
+            return (c=='x' ? r : (r&0x3|0x8)).toString(16);
+        });
+        return "MZTB" + uuid;
+    }
+    
+    this.loaded = true;
+  },
+  
+  unload: async function ()  {
+    if (this.loaded) {
+      for (let f in this.files) {
+        try{ 
+          //abort write delay timers and write current file content to disk 
+          await this.files[f].write.finalize();
+        } catch (e) {
+          Components.utils.reportError(e);
+        }                
+      }
+    }
+  },
+  
+
+  saveFile: function (f) {
+    if (this.loaded) {
+      //cancel any pending write and schedule a new delayed write
+      this.files[f].write.disarm();
+      this.files[f].write.arm();
+    }
+  },
+
+  writeAsync: async function (f) {
+    // if this file was not found/read on load, do not write default content to prevent clearing of data in case of read-errors
+    if (!this.files[f].found && JSON.stringify(this[f]) == this.files[f].default) {
+      return;
+    }
+    
+    let filepath = TbSync.io.getAbsolutePath(this.files[f].name);
+    await IOUtils.writeJSON(filepath, this[f]);
+  },
+
+
+
+  // simple convenience wrapper
+  saveAccounts: function () {
+    this.saveFile("accounts");
+  },
+
+  saveFolders: function () {
+    this.saveFile("folders");
+  },
+
+  saveChangelog: function () {
+    this.saveFile("changelog");
+  },
+
+  
+
+  // CHANGELOG FUNCTIONS
+  getItemStatusFromChangeLog: function (parentId, itemId) {   
+    for (let i=0; i<this.changelog.length; i++) {
+      if (this.changelog[i].parentId == parentId && this.changelog[i].itemId == itemId) return this.changelog[i].status;
+    }
+    return null;
+  },
+
+  getItemDataFromChangeLog: function (parentId, itemId) {   
+    for (let i=0; i<this.changelog.length; i++) {
+      if (this.changelog[i].parentId == parentId && this.changelog[i].itemId == itemId) return this.changelog[i];
+    }
+    return null;
+  },
+  
+  addItemToChangeLog: function (parentId, itemId, status) {
+    this.removeItemFromChangeLog(parentId, itemId);
+
+    //ChangelogData object
+    let row = {
+      "parentId" : parentId,
+      "itemId" : itemId,
+      "timestamp": Date.now(),
+      "status" : status};
+    
+    this.changelog.push(row);
+    this.saveChangelog();
+  },
+
+  removeItemFromChangeLog: function (parentId, itemId, moveToEnd = false) {
+    for (let i=this.changelog.length-1; i>-1; i-- ) {
+      if (this.changelog[i].parentId == parentId && this.changelog[i].itemId == itemId) {
+        let row = this.changelog.splice(i,1);
+        if (moveToEnd) this.changelog.push(row[0]);
+        this.saveChangelog();
+        return;
+      }
+    }
+  },
+
+  removeAllItemsFromChangeLogWithStatus: function (parentId, status) {
+    for (let i=this.changelog.length-1; i>-1; i-- ) {
+      if (this.changelog[i].parentId == parentId && this.changelog[i].status == status) {
+        let row = this.changelog.splice(i,1);
+      }
+    }
+    this.saveChangelog();
+  },
+
+  // Remove all cards of a parentId from ChangeLog
+  clearChangeLog: function (parentId) {
+    if (parentId) {
+      // we allow extra parameters added to a parentId, but still want to delete all items of that parent
+      // so we check for startsWith instead of equal
+      for (let i=this.changelog.length-1; i>-1; i-- ) {
+        if (this.changelog[i].parentId.startsWith(parentId)) this.changelog.splice(i,1);
+      }
+      this.saveChangelog();
+    }
+  },
+
+  getItemsFromChangeLog: function (parentId, maxnumbertosend, status = null) {        
+    //maxnumbertosend = 0 will return all results
+    let log = [];
+    let counts = 0;
+    for (let i=0; i<this.changelog.length && (log.length < maxnumbertosend || maxnumbertosend == 0); i++) {
+      if (this.changelog[i].parentId == parentId && (status === null || (typeof this.changelog[i].status == "string" && this.changelog[i].status.indexOf(status) != -1))) log.push(this.changelog[i]);
+    }
+    return log;
+  },
+
+
+
+
+
+  // ACCOUNT FUNCTIONS
+
+  addAccount: function (accountname, newAccountEntry) {
+    this.accounts.sequence++;
+    let id = this.accounts.sequence.toString();
+    newAccountEntry.accountID = id;
+    newAccountEntry.accountname = accountname;
+    
+    this.accounts.data[id] = newAccountEntry;
+    this.saveAccounts();
+    return id;
+  },
+
+  removeAccount: function (accountID) {
+    //check if accountID is known
+    if (this.accounts.data.hasOwnProperty(accountID) == false ) {
+      throw "Unknown accountID!" + "\nThrown by db.removeAccount("+accountID+ ")";
+    } else {
+      delete (this.accounts.data[accountID]);
+      delete (this.folders[accountID]);
+      this.saveAccounts();
+      this.saveFolders();
+    }
+  },
+
+  getAccounts: function () {
+    let accounts = {};
+    accounts.IDs = Object.keys(this.accounts.data).filter(accountID => TbSync.providers.loadedProviders.hasOwnProperty(this.accounts.data[accountID].provider)).sort((a, b) => a - b);
+    accounts.allIDs =  Object.keys(this.accounts.data).sort((a, b) => a - b)
+    accounts.data = this.accounts.data;
+    return accounts;
+  },
+
+  getAccount: function (accountID) {
+    //check if accountID is known
+    if (this.accounts.data.hasOwnProperty(accountID) == false ) {
+      throw "Unknown accountID!" + "\nThrown by db.getAccount("+accountID+ ")";
+    } else {
+      return this.accounts.data[accountID];
+    }
+  }, 
+
+  isValidAccountProperty: function (provider, name) {
+    if (["provider"].includes(name)) //internal properties, do not need to be defined by user/provider
+      return true;
+
+    //check if provider is installed
+    if (!TbSync.providers.loadedProviders.hasOwnProperty(provider)) {
+      TbSync.dump("Error @ isValidAccountProperty", "Unknown provider <"+provider+">!");
+      return false;
+    }
+    
+    if (TbSync.providers.getDefaultAccountEntries(provider).hasOwnProperty(name)) {
+      return true;
+    } else {
+      TbSync.dump("Error @ isValidAccountProperty", "Unknown account setting <"+name+">!");
+      return false;
+    }            
+  },
+
+  getAccountProperty: function (accountID, name) {
+    // if the requested accountID does not exist, getAccount() will fail
+    let data = this.getAccount(accountID);
+    
+    //check if field is allowed and get value or default value if setting is not set
+    if (this.isValidAccountProperty(data.provider, name)) {
+      if (data.hasOwnProperty(name)) return data[name];
+      else return TbSync.providers.getDefaultAccountEntries(data.provider)[name];
+    }
+  }, 
+
+  setAccountProperty: function (accountID , name, value) {
+    // if the requested accountID does not exist, getAccount() will fail
+    let data = this.getAccount(accountID);
+
+    //check if field is allowed, and set given value 
+    if (this.isValidAccountProperty(data.provider, name)) {
+      this.accounts.data[accountID][name] = value;
+    }
+    this.saveAccounts();
+  },
+
+  resetAccountProperty: function (accountID , name) {
+    // if the requested accountID does not exist, getAccount() will fail
+    let data = this.getAccount(accountID);
+    let defaults = TbSync.providers.getDefaultAccountEntries(data.provider);        
+
+    //check if field is allowed, and set given value 
+    if (this.isValidAccountProperty(data.provider, name)) {
+      this.accounts.data[accountID][name] = defaults[name];
+    }
+    this.saveAccounts();
+  },
+
+
+
+
+  // FOLDER FUNCTIONS
+
+  addFolder: function(accountID) {
+    let folderID = TbSync.generateUUID();
+    let provider = this.getAccountProperty(accountID, "provider");        
+    
+    if (!this.folders.hasOwnProperty(accountID)) this.folders[accountID] = {};                        
+    
+    //create folder with default settings
+    this.folders[accountID][folderID] = TbSync.providers.getDefaultFolderEntries(accountID);
+    this.saveFolders();
+    return folderID;
+  },
+
+  deleteFolder: function(accountID, folderID) {
+    delete (this.folders[accountID][folderID]);
+    //if there are no more folders, delete entire account entry
+    if (Object.keys(this.folders[accountID]).length === 0) delete (this.folders[accountID]);
+    this.saveFolders();
+  },
+
+  isValidFolderProperty: function (accountID, field) {
+    if (["cached"].includes(field)) //internal properties, do not need to be defined by user/provider
+      return true;
+    
+    //check if provider is installed
+    let provider = this.getAccountProperty(accountID, "provider");
+    if (!TbSync.providers.loadedProviders.hasOwnProperty(provider)) {
+      TbSync.dump("Error @ isValidFolderProperty", "Unknown provider <"+provider+"> for accountID <"+accountID+">!");
+      return false;
+    }
+
+    if (TbSync.providers.getDefaultFolderEntries(accountID).hasOwnProperty(field)) {
+      return true;
+    } else {
+      TbSync.dump("Error @ isValidFolderProperty", "Unknown folder setting <"+field+"> for accountID <"+accountID+">!");
+      return false;
+    }
+  },
+
+  getFolderProperty: function(accountID, folderID, field) {
+    //does the field exist?
+    let folder = (this.folders.hasOwnProperty(accountID) && this.folders[accountID].hasOwnProperty(folderID)) ? this.folders[accountID][folderID] : null;
+    
+    if (folder === null) {
+      throw "Unknown folder <"+folderID+">!";
+    }
+    
+    if (this.isValidFolderProperty(accountID, field)) {
+      if (folder.hasOwnProperty(field)) {
+        return folder[field];
+      } else {
+        let provider = this.getAccountProperty(accountID, "provider");
+        let defaultFolder = TbSync.providers.getDefaultFolderEntries(accountID);
+        //handle internal fields, that do not have a default value (see isValidFolderProperty)
+        return (defaultFolder[field] ? defaultFolder[field] : "");
+      }
+    }
+  },
+
+  setFolderProperty: function (accountID, folderID, field, value) {
+    if (this.isValidFolderProperty(accountID, field)) {
+      this.folders[accountID][folderID][field] = value;
+      this.saveFolders();
+    }
+  },
+  
+  resetFolderProperty: function (accountID, folderID, field) {
+    let provider = this.getAccountProperty(accountID, "provider");
+    let defaults = TbSync.providers.getDefaultFolderEntries(accountID);        
+    if (this.isValidFolderProperty(accountID, field)) {
+      //handle internal fields, that do not have a default value (see isValidFolderProperty)
+      this.folders[accountID][folderID][field] = defaults[field] ? defaults[field] : "";
+      this.saveFolders();
+    }
+  },
+
+  findFolders: function (folderQuery = {}, accountQuery = {}) {
+    // folderQuery is an object with one or more key:value pairs (logical AND) ::
+    // {key1: value1, key2: value2} 
+    // the value itself may be an array (logical OR)
+    let data = [];
+    let folderQueryEntries = Object.entries(folderQuery);
+    let folderFields = folderQueryEntries.map(pair => pair[0]);
+    let folderValues = folderQueryEntries.map(pair => Array.isArray(pair[1]) ? pair[1] : [pair[1]]);
+    
+    let accountQueryEntries = Object.entries(accountQuery);
+    let accountFields = accountQueryEntries.map(pair => pair[0]);
+    let accountValues = accountQueryEntries.map(pair => Array.isArray(pair[1]) ? pair[1] : [pair[1]]);
+    
+    for (let aID in this.folders) {
+      //is this a leftover folder of an account, which no longer there?
+      if (!this.accounts.data.hasOwnProperty(aID)) {
+        delete (this.folders[aID]);
+        this.saveFolders();
+        continue;
+      }
+    
+      //skip this folder, if it belongs to an account currently not supported (provider not loaded)
+      if (!TbSync.providers.loadedProviders.hasOwnProperty(this.getAccountProperty(aID, "provider"))) {
+        continue;
+      }
+
+      //does this account match account search options?
+      let accountmatch = true;
+      for (let a = 0; a < accountFields.length && accountmatch; a++) {
+        accountmatch = accountValues[a].some(item => item === this.getAccountProperty(aID, accountFields[a]));
+        //Services.console.logStringMessage("   " + accountFields[a] + ":" + this.getAccountProperty(aID, accountFields[a]) + " in " + JSON.stringify(accountValues[a]) + " ? " + accountmatch);
+      }
+      
+      if (accountmatch) {
+        for (let fID in this.folders[aID]) {
+          //does this folder match folder search options?                
+          let foldermatch = true;
+          for (let f = 0; f < folderFields.length && foldermatch; f++) {
+            foldermatch = folderValues[f].some(item => item === this.getFolderProperty(aID, fID, folderFields[f]));
+            //Services.console.logStringMessage("   " + folderFields[f] + ":" + this.getFolderProperty(aID, fID, folderFields[f]) + " in " + JSON.stringify(folderValues[f]) + " ? " + foldermatch);
+          }
+          if (foldermatch) data.push({accountID: aID, folderID: fID, data: this.folders[aID][fID]});
+        }
+      }
+    }
+
+    //still a reference to the original data
+    return data;
+  }
+};
diff -Nru tbsync-4.12/content/modules/eventlog.js tbsync-4.16/content/modules/eventlog.js
--- tbsync-4.12/content/modules/eventlog.js	2024-08-27 18:32:08.000000000 +0200
+++ tbsync-4.16/content/modules/eventlog.js	2025-03-15 23:49:58.000000000 +0100
@@ -1,153 +1,164 @@
-/*
- * This file is part of TbSync.
- *
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. 
- */
- 
-"use strict";
-
-/**
- *
- */
-var EventLogInfo = class {
-  /**
-   * An EventLogInfo instance is used when adding entries to the
-   * :ref:`TbSyncEventLog`. The information given here will be added as a
-   * header to the actual event.
-   *
-   * @param {string} provider     ``Optional`` A provider ID (also used as
-   *                              provider namespace). 
-   * @param {string} accountname  ``Optional`` An account name. Can be
-   *                              arbitrary but should match the accountID
-   *                              (if provided).
-   * @param {string} accountID    ``Optional`` An account ID. Used to filter
-   *                              events for a given account.
-   * @param {string} foldername   ``Optional`` A folder name.
-   *
-   */
-  constructor(provider, accountname = "", accountID = "", foldername = "") {
-    this._provider = provider;
-    this._accountname = accountname;
-    this._accountID = accountID;
-    this._foldername = foldername;
-  }
-  
-  /**
-   * Getter/Setter for the provider ID of this EventLogInfo.
-   */
-  get provider() {return this._provider};
-  /**
-   * Getter/Setter for the account ID of this EventLogInfo.
-   */
-  get accountname() {return this._accountname};
-  /**
-   * Getter/Setter for the account name of this EventLogInfo.
-   */
-  get accountID() {return this._accountID};
-  /**
-   * Getter/Setter for the folder name of this EventLogInfo.
-   */
-  get foldername() {return this._foldername};
-
-  set provider(v) {this._provider = v};
-  set accountname(v) {this._accountname = v};
-  set accountID(v) {this._accountID = v};
-  set foldername(v) {this._foldername = v};
-}
-
-
-  
-/**
- * The TbSync event log 
- */
-var eventlog = {
-  /**
-   * Adds an entry to the TbSync event log
-   *
-   * @param {StatusDataType}  type       One of the types defined in
-   *                                      :class:`StatusData`
-   * @param {EventLogInfo}    eventInfo  EventLogInfo for this event.
-   * @param {string}          message    The event message.
-   * @param {string}          details    ``Optional`` The event details.
-   *  
-   */
-  add: function (type, eventInfo, message, details = null) {
-    let entry = {
-      timestamp: Date.now(),
-      message: message, 
-      type: type,
-      link: null, 
-      //some details are just true, which is not a useful detail, ignore
-      details: details === true ? null : details,
-      provider: "",
-      accountname: "",
-      foldername: "",
-    };
-  
-    if (eventInfo) {
-      if (eventInfo.accountID) entry.accountID = eventInfo.accountID;
-      if (eventInfo.provider) entry.provider = eventInfo.provider;
-      if (eventInfo.accountname) entry.accountname = eventInfo.accountname;
-      if (eventInfo.foldername) entry.foldername = eventInfo.foldername;
-    }
-
-    let localized = "";
-    let link = "";        
-    if (entry.provider) {
-      localized = TbSync.getString("status." + message, entry.provider);
-      link = TbSync.getString("helplink." + message, entry.provider);
-    } else {
-      //try to get localized string from message from TbSync
-      localized = TbSync.getString("status." + message);
-      link = TbSync.getString("helplink." + message);
-    }
-  
-    //can we provide a localized version of the event msg?
-    if (localized != "status."+message) {
-      entry.message = localized;
-    }
-
-    //is there a help link?
-    if (link != "helplink." + message) {
-      entry.link = link;
-    }
-
-    //dump the non-localized message into debug log
-    TbSync.dump("EventLog", message + (entry.details !== null ? "\n" + entry.details : ""));
-    this.events.push(entry);
-    if (this.events.length > 100) this.events.shift();
-    Services.obs.notifyObservers(null, "tbsync.observer.eventlog.update", null);
-  },
-
-  events: null,
-  eventLogWindow: null,
-  
-  load: async function () {
-    this.clear();
-  },
-
-  unload: async function () {
-    if (this.eventLogWindow) {
-      this.eventLogWindow.close();
-    }
-  },
-
-  get: function (accountID = null) {
-    if (accountID) {
-      return this.events.filter(e => e.accountID == accountID);
-    } else {
-      return this.events;
-    }
-  },
-  
-  clear: function () {
-    this.events = [];
-  },
-  
-  
-  open: function (accountID = null, folderID = null) {
-    this.eventLogWindow = TbSync.manager.prefWindowObj.open("chrome://tbsync/content/manager/eventlog/eventlog.xhtml", "TbSyncEventLog", "centerscreen,chrome,resizable");
-  },    
-}
+/*
+ * This file is part of TbSync.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. 
+ */
+ 
+"use strict";
+
+var { ExtensionParent } = ChromeUtils.importESModule(
+  "resource://gre/modules/ExtensionParent.sys.mjs"
+);
+
+var tbsyncExtension = ExtensionParent.GlobalManager.getExtension(
+  "tbsync at jobisoft.de"
+);
+var { TbSync } = ChromeUtils.importESModule(
+  `chrome://tbsync/content/tbsync.sys.mjs?${tbsyncExtension.manifest.version}`
+);
+
+/**
+ *
+ */
+var EventLogInfo = class {
+  /**
+   * An EventLogInfo instance is used when adding entries to the
+   * :ref:`TbSyncEventLog`. The information given here will be added as a
+   * header to the actual event.
+   *
+   * @param {string} provider     ``Optional`` A provider ID (also used as
+   *                              provider namespace). 
+   * @param {string} accountname  ``Optional`` An account name. Can be
+   *                              arbitrary but should match the accountID
+   *                              (if provided).
+   * @param {string} accountID    ``Optional`` An account ID. Used to filter
+   *                              events for a given account.
+   * @param {string} foldername   ``Optional`` A folder name.
+   *
+   */
+  constructor(provider, accountname = "", accountID = "", foldername = "") {
+    this._provider = provider;
+    this._accountname = accountname;
+    this._accountID = accountID;
+    this._foldername = foldername;
+  }
+  
+  /**
+   * Getter/Setter for the provider ID of this EventLogInfo.
+   */
+  get provider() {return this._provider};
+  /**
+   * Getter/Setter for the account ID of this EventLogInfo.
+   */
+  get accountname() {return this._accountname};
+  /**
+   * Getter/Setter for the account name of this EventLogInfo.
+   */
+  get accountID() {return this._accountID};
+  /**
+   * Getter/Setter for the folder name of this EventLogInfo.
+   */
+  get foldername() {return this._foldername};
+
+  set provider(v) {this._provider = v};
+  set accountname(v) {this._accountname = v};
+  set accountID(v) {this._accountID = v};
+  set foldername(v) {this._foldername = v};
+}
+
+
+  
+/**
+ * The TbSync event log 
+ */
+var eventlog = {
+  /**
+   * Adds an entry to the TbSync event log
+   *
+   * @param {StatusDataType}  type       One of the types defined in
+   *                                      :class:`StatusData`
+   * @param {EventLogInfo}    eventInfo  EventLogInfo for this event.
+   * @param {string}          message    The event message.
+   * @param {string}          details    ``Optional`` The event details.
+   *  
+   */
+  add: function (type, eventInfo, message, details = null) {
+    let entry = {
+      timestamp: Date.now(),
+      message: message, 
+      type: type,
+      link: null, 
+      //some details are just true, which is not a useful detail, ignore
+      details: details === true ? null : details,
+      provider: "",
+      accountname: "",
+      foldername: "",
+    };
+  
+    if (eventInfo) {
+      if (eventInfo.accountID) entry.accountID = eventInfo.accountID;
+      if (eventInfo.provider) entry.provider = eventInfo.provider;
+      if (eventInfo.accountname) entry.accountname = eventInfo.accountname;
+      if (eventInfo.foldername) entry.foldername = eventInfo.foldername;
+    }
+
+    let localized = "";
+    let link = "";        
+    if (entry.provider) {
+      localized = TbSync.getString("status." + message, entry.provider);
+      link = TbSync.getString("helplink." + message, entry.provider);
+    } else {
+      //try to get localized string from message from TbSync
+      localized = TbSync.getString("status." + message);
+      link = TbSync.getString("helplink." + message);
+    }
+  
+    //can we provide a localized version of the event msg?
+    if (localized != "status."+message) {
+      entry.message = localized;
+    }
+
+    //is there a help link?
+    if (link != "helplink." + message) {
+      entry.link = link;
+    }
+
+    //dump the non-localized message into debug log
+    TbSync.dump("EventLog", message + (entry.details !== null ? "\n" + entry.details : ""));
+    this.events.push(entry);
+    if (this.events.length > 100) this.events.shift();
+    Services.obs.notifyObservers(null, "tbsync.observer.eventlog.update", null);
+  },
+
+  events: null,
+  eventLogWindow: null,
+  
+  load: async function () {
+    this.clear();
+  },
+
+  unload: async function () {
+    if (this.eventLogWindow) {
+      this.eventLogWindow.close();
+    }
+  },
+
+  get: function (accountID = null) {
+    if (accountID) {
+      return this.events.filter(e => e.accountID == accountID);
+    } else {
+      return this.events;
+    }
+  },
+  
+  clear: function () {
+    this.events = [];
+  },
+  
+  
+  open: function (accountID = null, folderID = null) {
+    this.eventLogWindow = TbSync.manager.prefWindowObj.open("chrome://tbsync/content/manager/eventlog/eventlog.xhtml", "TbSyncEventLog", "centerscreen,chrome,resizable");
+  },    
+}
diff -Nru tbsync-4.12/content/modules/io.js tbsync-4.16/content/modules/io.js
--- tbsync-4.12/content/modules/io.js	2024-08-27 18:32:08.000000000 +0200
+++ tbsync-4.16/content/modules/io.js	2025-03-15 23:49:58.000000000 +0100
@@ -1,45 +1,56 @@
-/*
- * This file is part of TbSync.
- *
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. 
- */
- 
-"use strict";
- 
-ChromeUtils.defineESModuleGetters(this, {
-  FileUtils: "resource://gre/modules/FileUtils.sys.mjs",
-});
-
-var io = {
-
-  storageDirectory : PathUtils.join(PathUtils.profileDir, "TbSync"),
-
-  load: async function () {
-  },
-
-  unload: async function () {
-  },
-
-  getAbsolutePath: function(filename) {
-    return PathUtils.join(this.storageDirectory, filename);
-  },
-  
-  initFile: function (filename) {
-    let file = new FileUtils.File(PathUtils.join(PathUtils.profileDir, "TbSync", filename));
-    //create a stream to write to that file
-    let foStream = Components.classes["@mozilla.org/network/file-output-stream;1"].createInstance(Components.interfaces.nsIFileOutputStream);
-    foStream.init(file, 0x02 | 0x08 | 0x20, parseInt("0666", 8), 0); // write, create, truncate
-    foStream.close();
-  },
-
-  appendToFile: function (filename, data) {
-    let file = new FileUtils.File(PathUtils.join(PathUtils.profileDir, "TbSync", filename));
-    //create a strem to write to that file
-    let foStream = Components.classes["@mozilla.org/network/file-output-stream;1"].createInstance(Components.interfaces.nsIFileOutputStream);
-    foStream.init(file, 0x02 | 0x08 | 0x10, parseInt("0666", 8), 0); // write, create, append
-    foStream.write(data, data.length);
-    foStream.close();
-  },    
-}
+/*
+ * This file is part of TbSync.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. 
+ */
+ 
+"use strict";
+
+var { ExtensionParent } = ChromeUtils.importESModule(
+  "resource://gre/modules/ExtensionParent.sys.mjs"
+);
+
+var tbsyncExtension = ExtensionParent.GlobalManager.getExtension(
+  "tbsync at jobisoft.de"
+);
+var { TbSync } = ChromeUtils.importESModule(
+  `chrome://tbsync/content/tbsync.sys.mjs?${tbsyncExtension.manifest.version}`
+);
+
+ChromeUtils.defineESModuleGetters(this, {
+  FileUtils: "resource://gre/modules/FileUtils.sys.mjs",
+});
+
+var io = {
+
+  storageDirectory : PathUtils.join(PathUtils.profileDir, "TbSync"),
+
+  load: async function () {
+  },
+
+  unload: async function () {
+  },
+
+  getAbsolutePath: function(filename) {
+    return PathUtils.join(this.storageDirectory, filename);
+  },
+  
+  initFile: function (filename) {
+    let file = new FileUtils.File(PathUtils.join(PathUtils.profileDir, "TbSync", filename));
+    //create a stream to write to that file
+    let foStream = Components.classes["@mozilla.org/network/file-output-stream;1"].createInstance(Components.interfaces.nsIFileOutputStream);
+    foStream.init(file, 0x02 | 0x08 | 0x20, parseInt("0666", 8), 0); // write, create, truncate
+    foStream.close();
+  },
+
+  appendToFile: function (filename, data) {
+    let file = new FileUtils.File(PathUtils.join(PathUtils.profileDir, "TbSync", filename));
+    //create a strem to write to that file
+    let foStream = Components.classes["@mozilla.org/network/file-output-stream;1"].createInstance(Components.interfaces.nsIFileOutputStream);
+    foStream.init(file, 0x02 | 0x08 | 0x10, parseInt("0666", 8), 0); // write, create, append
+    foStream.write(data, data.length);
+    foStream.close();
+  },    
+}
diff -Nru tbsync-4.12/content/modules/lightning.js tbsync-4.16/content/modules/lightning.js
--- tbsync-4.12/content/modules/lightning.js	2024-08-27 18:32:08.000000000 +0200
+++ tbsync-4.16/content/modules/lightning.js	2025-03-15 23:49:58.000000000 +0100
@@ -1,774 +1,775 @@
-/*
- * This file is part of TbSync.
- *
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. 
- */
- 
-"use strict";
-
-var { XPCOMUtils } = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
-
-XPCOMUtils.defineLazyModuleGetters(this, {
-  CalAlarm: "resource:///modules/CalAlarm.jsm",
-  CalAttachment: "resource:///modules/CalAttachment.jsm",
-  CalAttendee: "resource:///modules/CalAttendee.jsm",
-  CalEvent: "resource:///modules/CalEvent.jsm",
-  CalTodo: "resource:///modules/CalTodo.jsm",
-}); 
-  
-var lightning = {
-
-  cal: null,
-  ICAL: null,
-   
-  load: async function () {
-    try {
-      TbSync.lightning.cal = ChromeUtils.import("resource:///modules/calendar/calUtils.jsm").cal;
-      TbSync.lightning.ICAL = ChromeUtils.importESModule("resource:///modules/calendar/Ical.sys.mjs").default;
-      let manager = TbSync.lightning.cal.manager;
-      manager.addCalendarObserver(this.calendarObserver);
-      manager.addObserver(this.calendarManagerObserver);
-    } catch (e) {
-      TbSync.dump("Check4Lightning","Error during lightning module import: " + e.toString() + "\n" + e.stack);
-      Components.utils.reportError(e);
-    }
-  },
-
-  unload: async function () {
-    //removing global observer
-    let manager = TbSync.lightning.cal.manager;
-    manager.removeCalendarObserver(this.calendarObserver);
-    manager.removeObserver(this.calendarManagerObserver);
-
-    //remove listeners on global sync buttons
-    if (TbSync.window.document.getElementById("calendar-synchronize-button")) {
-      TbSync.window.document.getElementById("calendar-synchronize-button").removeEventListener("click", function(event){Services.obs.notifyObservers(null, 'tbsync.observer.sync', null);}, false);
-    }
-    if (TbSync.window.document.getElementById("task-synchronize-button")) {
-      TbSync.window.document.getElementById("task-synchronize-button").removeEventListener("click", function(event){Services.obs.notifyObservers(null, 'tbsync.observer.sync', null);}, false);
-    }
-  },
-
-
-
-
-  
-  // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
-  // * AdvancedTargetData, an extended TargetData implementation, providers
-  // * can use this as their own TargetData by extending it and just
-  // * defining the extra methods
-  // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
-  
-  AdvancedTargetData : class {
-    constructor(folderData) {            
-      this._folderData = folderData;
-      this._targetObj = null;           
-    }
-    
-    // Check, if the target exists and return true/false.
-    hasTarget() {
-      let calManager = TbSync.lightning.cal.manager;
-      let target = this._folderData.getFolderProperty("target");
-      let calendar = calManager.getCalendarById(target);
-      
-      return calendar ? true : false;
-    }
-
-    // Returns the target obj, which TbSync should return as the target. It can
-    // be whatever you want and is returned by FolderData.targetData.getTarget().
-    // If the target does not exist, it should be created. Throw a simple Error, if that
-    // failed.
-    async getTarget() {
-      let calManager = TbSync.lightning.cal.manager;
-      let target = this._folderData.getFolderProperty("target");
-      let calendar = calManager.getCalendarById(target);
-      
-      if (!calendar) {
-        calendar = await TbSync.lightning.prepareAndCreateCalendar(this._folderData);
-        if (!calendar)
-          throw new Error("notargets");
-      }
-
-      if (!this._targetObj || this._targetObj.id != calendar.id)
-        this._targetObj = new TbSync.lightning.TbCalendar(calendar, this._folderData);
-
-      return this._targetObj;
-    }
-    
-    /**
-     * Removes the target from the local storage. If it does not exist, return
-     * silently. A call to ``hasTarget()`` should return false, after this has
-     * been executed.
-     *
-     */
-    removeTarget() {
-      let calManager = TbSync.lightning.cal.manager;
-      let target = this._folderData.getFolderProperty("target");
-      let calendar = calManager.getCalendarById(target);
-
-      try {
-        if (calendar) {
-          calManager.removeCalendar(calendar);
-        }
-      } catch (e) {}
-      TbSync.db.clearChangeLog(target);
-      this._folderData.resetFolderProperty("target");             
-    }
-
-
-    /**
-     * Disconnects the target in the local storage from this TargetData, but
-     * does not delete it, so it becomes a stale "left over" . A call
-     * to ``hasTarget()`` should return false, after this has been executed.
-     * 
-     */
-    disconnectTarget() {
-      let calManager = TbSync.lightning.cal.manager;
-      let target = this._folderData.getFolderProperty("target");
-      let calendar = calManager.getCalendarById(target);
-
-      if (calendar) {
-        let changes = TbSync.db.getItemsFromChangeLog(target, 0, "_by_user");        
-        if (changes.length > 0) {
-          this.targetName = this.targetName + " (*)";
-        }
-        calendar.setProperty("disabled", true);
-        calendar.setProperty("tbSyncProvider", "orphaned");
-        calendar.setProperty("tbSyncAccountID", "");
-      }
-      TbSync.db.clearChangeLog(target);
-      this._folderData.resetFolderProperty("target");        
-    } 
-    
-    set targetName(newName) {
-      let calManager = TbSync.lightning.cal.manager;
-      let target = this._folderData.getFolderProperty("target");
-      let calendar = calManager.getCalendarById(target);
-
-      if (calendar) {
-        calendar.name = newName;
-      } else {
-        throw new Error("notargets");
-      }
-    }
-  
-    get targetName() {
-      let calManager = TbSync.lightning.cal.manager;
-      let target = this._folderData.getFolderProperty("target");
-      let calendar = calManager.getCalendarById(target);
-
-      if (calendar) {
-        return calendar.name;
-      } else {
-        throw new Error("notargets");
-      }
-    }
-
-    setReadOnly(value) {
-      // hasTarget() can throw an error, ignore that here
-      try {
-        if (this.hasTarget()) {
-          this.getTarget().then(target => target.calendar.setProperty("readOnly", value));
-        }
-      } catch (e) {
-        Components.utils.reportError(e);
-      }
-    }
-
-    
-    // * * * * * * * * * * * * * * * * *
-    // * AdvancedTargetData extension  * 
-    // * * * * * * * * * * * * * * * * *
-    
-    get isAdvancedCalendarTargetData() {
-      return true;
-    }
-    
-    get folderData() {
-      return this._folderData;
-    }
-    
-    // The calendar target does not support a custom primaryKeyField, because
-    // the lightning implementation only allows to search for items via UID.
-    // Like the addressbook target, the calendar target item element has a
-    // primaryKey getter/setter which - however - only works on the UID.
-    
-    // enable or disable changelog
-    get logUserChanges(){
-      return true;
-    }
-
-    calendarObserver(aTopic, tbCalendar, aPropertyName, aPropertyValue, aOldPropertyValue) {
-      switch (aTopic) {
-        case "onCalendarPropertyChanged":
-          //Services.console.logStringMessage("["+ aTopic + "] " + tbCalendar.calendar.name + " : " + aPropertyName);
-          break;
-
-        case "onCalendarDeleted":
-        case "onCalendarPropertyDeleted":
-          //Services.console.logStringMessage("["+ aTopic + "] " +tbCalendar.calendar.name);
-          break;
-      }
-    }
-
-    itemObserver(aTopic, tbItem, tbOldItem) {
-      switch (aTopic) {
-        case "onAddItem":
-        case "onModifyItem":
-        case "onDeleteItem":
-          //Services.console.logStringMessage("["+ aTopic + "] " + tbItem.nativeItem.title);
-          break;
-      }
-    }
-
-    // replace this with your own implementation to create the actual addressbook,
-    // when this class is extended
-    async createCalendar(newname) {
-      let calManager = TbSync.lightning.cal.manager;
-      let newCalendar = calManager.createCalendar("storage", Services.io.newURI("moz-storage-calendar://"));
-      newCalendar.id = TbSync.lightning.cal.getUUID();
-      newCalendar.name = newname;
-      return newCalendar
-    }      
-    
-  },
-
-
-
-
-  
-  // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
-  // * TbItem and TbCalendar Classes
-  // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
-  
-  TbItem : class {
-    constructor(TbCalendar, item) {
-      if (!TbCalendar)
-        throw new Error("TbItem::constructor is missing its first parameter!");
-
-      if (!item)
-        throw new Error("TbItem::constructor is missing its second parameter!");
-
-      this._tbCalendar = TbCalendar;
-      this._item = item;
-      
-      this._isTodo = item.isTodo ? item.isTodo() : (item instanceof Ci.calITodo);
-      this._isEvent = item.isEvent ? item.isEvent() :  (item instanceof Ci.calIEvent);
-    }
-    
-    get tbCalendar() {
-      return this._tbCalendar;
-    }
-
-    get isTodo() {
-      return this._isTodo;
-    }
-    
-    get isEvent() {
-      return this._isEvent;
-    }
-
-
-
-
-    
-    get nativeItem() {
-      return this._item;
-    }
-
-    get UID() {
-      return this._item.id;
-    }
-    
-    get primaryKey() {
-      // no custom key possible with lightning, must use the UID
-      return this._item.id;
-    }
-
-    set primaryKey(value) {
-      // no custom key possible with lightning, must use the UID
-      this._item.id = value;   
-    }
-
-    clone() {
-      return new TbSync.lightning.TbItem(this._tbCalendar, this._item.clone());
-    }
-
-    toString() {
-      return this._item.icalString;
-    }
-
-    getProperty(property, fallback = "") {
-      return this._item.hasProperty(property) ? this._item.getProperty(property) : fallback;
-    }
-
-    setProperty(property, value) {
-      this._item.setProperty(property, value);
-    }
-    
-    deleteProperty(property) {
-      this._item.deleteProperty(property);
-    }
-        
-    get changelogData() {         
-      return TbSync.db.getItemDataFromChangeLog(this._tbCalendar.UID, this.primaryKey);
-    }
-
-    get changelogStatus() {
-      return TbSync.db.getItemStatusFromChangeLog(this._tbCalendar.UID, this.primaryKey);
-    }
-
-    set changelogStatus(status) {
-      let value = this.primaryKey;
-      
-      if (value) {
-        if (!status) {
-          TbSync.db.removeItemFromChangeLog(this._tbCalendar.UID, value);
-          return;
-        }
-
-        if (this._tbCalendar.logUserChanges || status.endsWith("_by_server")) {
-          TbSync.db.addItemToChangeLog(this._tbCalendar.UID, value, status);
-        }
-      }
-    }
-  },
-
-
-  TbCalendar : class {
-    constructor(calendar, folderData) {
-      this._calendar = calendar;
-      this._folderData = folderData;
-     }
-
-    get calendar() {
-      return this._calendar;
-    }
-    
-    get promisifyCalendar() {
-      return this._calendar;
-    }
-
-    get logUserChanges() {
-      return this._folderData.targetData.logUserChanges;
-    }
-    
-    get primaryKeyField() {
-      // Not supported by lightning. We let the implementation sit here, it may get changed in the future.
-      // In order to support this, lightning needs to implement a proper getItemfromProperty() method.
-      return null;
-    }
-    
-    get UID() {
-      return this._calendar.id;
-    }
-
-    createNewEvent() {
-      let event = new CalEvent();
-      return new TbSync.lightning.TbItem(this, event);
-    }
-    
-    createNewTodo() {
-      let todo = new CalTodo();
-      return new TbSync.lightning.TbItem(this, todo);
-    }
-
-    
-    
-    
-    async addItem(tbItem, pretagChangelogWithByServerEntry = true) {
-      if (this.primaryKeyField && !tbItem.getProperty(this.primaryKeyField)) {
-        tbItem.setProperty(this.primaryKeyField, this._folderData.targetData.generatePrimaryKey());
-        //Services.console.logStringMessage("[TbCalendar::addItem] Generated primary key!");
-      }
-      
-      if (pretagChangelogWithByServerEntry) {
-        tbItem.changelogStatus = "added_by_server";
-      }
-      return await this._calendar.addItem(tbItem._item);
-    }
-    
-    async modifyItem(tbNewItem, tbOldItem, pretagChangelogWithByServerEntry = true) {
-      // only add entry if the current entry does not start with _by_user
-      let status = tbNewItem.changelogStatus ? tbNewItem.changelogStatus : "";
-      if (pretagChangelogWithByServerEntry && !status.endsWith("_by_user")) {
-        tbNewItem.changelogStatus = "modified_by_server";
-      }
-      
-      return await this._calendar.modifyItem(tbNewItem._item, tbOldItem._item); 
-    }        
-    
-    async deleteItem(tbItem, pretagChangelogWithByServerEntry = true) {
-      if (pretagChangelogWithByServerEntry) {
-        tbItem.changelogStatus = "deleted_by_server";
-      }
-      return await this._calendar.deleteItem(tbItem._item); 
-    }
-    
-    // searchId is interpreted as the primaryKeyField, which is the UID for this target
-    async getItem (searchId) {
-      let item = await this._calendar.getItem(searchId); 
-      if (item) {
-        return new TbSync.lightning.TbItem(this, item);
-      }
-      return null;
-    }
-
-    async getItemFromProperty(property, value) {
-      if (property == "UID") return await this.getItem(value);
-      else throw ("TbSync.lightning.getItemFromProperty: Currently onle the UID property can be used to search for items.");
-    }
-
-    async getAllItems() {
-      return await this._calendar.getItems(Ci.calICalendar.ITEM_FILTER_ALL_ITEMS, 0, null, null);
-    }
-  
-    getAddedItemsFromChangeLog(maxitems = 0) {             
-      return TbSync.db.getItemsFromChangeLog(this.calendar.id, maxitems, "added_by_user").map(item => item.itemId);
-    }
-
-    getModifiedItemsFromChangeLog(maxitems = 0) {             
-      return TbSync.db.getItemsFromChangeLog(this.calendar.id, maxitems, "modified_by_user").map(item => item.itemId);
-    }
-    
-    getDeletedItemsFromChangeLog(maxitems = 0) {             
-      return TbSync.db.getItemsFromChangeLog(this.calendar.id, maxitems, "deleted_by_user").map(item => item.itemId);
-    }
-    
-    getItemsFromChangeLog(maxitems = 0) {             
-      return TbSync.db.getItemsFromChangeLog(this.calendar.id, maxitems, "_by_user");
-    }
-
-    removeItemFromChangeLog(id, moveToEndInsteadOfDelete = false) {             
-      TbSync.db.removeItemFromChangeLog(this.calendar.id, id, moveToEndInsteadOfDelete);
-    }
-    
-    clearChangelog() {
-      TbSync.db.clearChangeLog(this.calendar.id);
-    }
-  },
-  
-
-
-
-  
-  // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
-  // * Internal Functions
-  // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
-  
-  getFolderFromCalendarUID: function(calUID) {
-    let folders = TbSync.db.findFolders({"target": calUID});
-    if (folders.length == 1) {
-      let accountData = new TbSync.AccountData(folders[0].accountID);
-      return new TbSync.FolderData(accountData, folders[0].folderID);
-    }
-    return null;
-  },
-  
-  getFolderFromCalendarURL: function(calURL) {
-    let folders = TbSync.db.findFolders({"url": calURL});
-    if (folders.length == 1) {
-      let accountData = new TbSync.AccountData(folders[0].accountID);
-      return new TbSync.FolderData(accountData, folders[0].folderID);
-    }
-    return null;
-  },  
-  
-  calendarObserver : { 
-    onStartBatch : function () {},
-    onEndBatch : function () {},
-    onLoad : function (aCalendar) {},
-    onError : function (aCalendar, aErrNo, aMessage) {},
-
-    onAddItem : function (aAddedItem) { 
-      if (!(aAddedItem && aAddedItem.calendar))
-        return;
-
-      let folderData = TbSync.lightning.getFolderFromCalendarUID(aAddedItem.calendar.id);                    
-      if (folderData 
-        && folderData.targetData 
-        && folderData.targetData.isAdvancedCalendarTargetData) {
-
-        let tbCalendar = new TbSync.lightning.TbCalendar(aAddedItem.calendar, folderData);
-        let tbItem = new TbSync.lightning.TbItem(tbCalendar, aAddedItem);          
-        let itemStatus = tbItem.changelogStatus;
-
-        // if this card was created by us, it will be in the log
-        if (itemStatus && itemStatus.endsWith("_by_server")) {
-          let age = Date.now() - tbItem.changelogData.timestamp;
-          if (age < 1500) {
-            // during freeze, local modifications are not possible
-            return;
-          } else {
-            // remove blocking entry from changelog after freeze time is over (1.5s),
-            // and continue evaluating this event
-            abItem.changelogStatus = "";
-          }
-        } 
-
-        if (itemStatus == "deleted_by_user")  {
-          // deleted ?  user moved item out and back in -> modified
-          tbItem.changelogStatus = "modified_by_user";
-        } else {
-          tbItem.changelogStatus = "added_by_user";
-        }
-        
-        if (tbCalendar.logUserChanges) TbSync.core.setTargetModified(folderData);
-        folderData.targetData.itemObserver("onAddItem", tbItem, null);                                        
-      }
-    },
-
-    onModifyItem : function (aNewItem, aOldItem) {
-      //check, if it is a pure modification within the same calendar
-      if (!(aNewItem && aNewItem.calendar && aOldItem && aOldItem.calendar && aNewItem.calendar.id == aOldItem.calendar.id))
-        return;
-
-      let folderData = TbSync.lightning.getFolderFromCalendarUID(aNewItem.calendar.id);                    
-      if (folderData 
-        && folderData.targetData 
-        && folderData.targetData.isAdvancedCalendarTargetData) {
-
-        let tbCalendar = new TbSync.lightning.TbCalendar(aNewItem.calendar, folderData);
-        let tbNewItem = new TbSync.lightning.TbItem(tbCalendar, aNewItem);          
-        let tbOldItem = new TbSync.lightning.TbItem(tbCalendar, aOldItem);          
-        let itemStatus = tbNewItem.changelogStatus;
-          
-        // if this card was created by us, it will be in the log
-        if (itemStatus && itemStatus.endsWith("_by_server")) {
-          let age = Date.now() - tbNewItem.changelogData.timestamp;
-          if (age < 1500) {
-            // during freeze, local modifications are not possible
-            return;
-          } else {
-            // remove blocking entry from changelog after freeze time is over (1.5s),
-            // and continue evaluating this event
-            tbNewItem.changelogStatus = "";
-          }
-        } 
-
-        if (itemStatus != "added_by_user") {
-          //added_by_user -> it is a local unprocessed add do not re-add it to changelog
-          tbNewItem.changelogStatus = "modified_by_user";
-        }
-
-        if (tbCalendar.logUserChanges) TbSync.core.setTargetModified(folderData);
-        folderData.targetData.itemObserver("onModifyItem", tbNewItem, tbOldItem);                                        
-      }
-    },
-
-    onDeleteItem : function (aDeletedItem) {
-      if (!(aDeletedItem && aDeletedItem.calendar))
-        return;
-
-      let folderData = TbSync.lightning.getFolderFromCalendarUID(aDeletedItem.calendar.id);                    
-      if (folderData 
-        && folderData.targetData 
-        && folderData.targetData.isAdvancedCalendarTargetData) {
-
-        let tbCalendar = new TbSync.lightning.TbCalendar(aDeletedItem.calendar, folderData);
-        let tbItem = new TbSync.lightning.TbItem(tbCalendar, aDeletedItem);
-        let itemStatus = tbItem.changelogStatus;
-
-        // if this card was created by us, it will be in the log
-        if (itemStatus && itemStatus.endsWith("_by_server")) {
-          let age = Date.now() - tbItem.changelogData.timestamp;
-          if (age < 1500) {
-            // during freeze, local modifications are not possible
-            return;
-          } else {
-            // remove blocking entry from changelog after freeze time is over (1.5s),
-            // and continue evaluating this event
-            tbItem.changelogStatus = "";
-          }
-        } 
-
-        if (itemStatus == "added_by_user") {
-          //a local add, which has not yet been processed (synced) is deleted -> remove all traces
-          tbItem.changelogStatus = "";
-        } else {
-          tbItem.changelogStatus = "deleted_by_user";
-        }
-
-        if (tbCalendar.logUserChanges) TbSync.core.setTargetModified(folderData);
-        folderData.targetData.itemObserver("onDeleteItem", tbItem, null);
-      }
-    },
-
-    //Changed properties of the calendar itself (name, color etc.)
-    onPropertyChanged : function (aCalendar, aName, aValue, aOldValue) {
-      let folderData = TbSync.lightning.getFolderFromCalendarUID(aCalendar.id);                    
-      if (folderData 
-        && folderData.targetData 
-        && folderData.targetData.isAdvancedCalendarTargetData) {
-
-        let tbCalendar = new TbSync.lightning.TbCalendar(aCalendar, folderData);
-          
-        switch (aName) {
-          case "color":
-            // update stored color to recover after disable
-            folderData.setFolderProperty("targetColor", aValue); 
-            break;
-          case "name":
-            // update stored name to recover after disable
-            folderData.setFolderProperty("targetName", aValue);                         
-            // update settings window, if open
-            Services.obs.notifyObservers(null, "tbsync.observer.manager.updateSyncstate", folderData.accountID);                    
-            break;
-        }
-        
-        folderData.targetData.calendarObserver("onCalendarPropertyChanged", tbCalendar, aName, aValue, aOldValue);                
-      }
-    },
-
-    //Deleted properties of the calendar itself (name, color etc.)
-    onPropertyDeleting : function (aCalendar, aName) {
-      let folderData = TbSync.lightning.getFolderFromCalendarUID(aCalendar.id);                    
-      if (folderData 
-        && folderData.targetData 
-        && folderData.targetData.isAdvancedCalendarTargetData) {
-
-        let tbCalendar = new TbSync.lightning.TbCalendar(aCalendar, folderData);
-          
-        switch (aName) {
-          case "color":
-          case "name":
-            //update settings window, if open
-            Services.obs.notifyObservers(null, "tbsync.observer.manager.updateSyncstate", folderData.accountID);                    
-          break;
-        }
-
-        folderData.targetData.calendarObserver("onCalendarPropertyDeleted", tbCalendar, aName);                
-      }
-    }
-  },
-
-  calendarManagerObserver : {
-    onCalendarRegistered : function (aCalendar) {              
-    },
-    
-    onCalendarUnregistering : function (aCalendar) {
-      /*let folderData = TbSync.lightning.getFolderFromCalendarUID(aCalendar.id);                    
-      if (folderData 
-        && folderData.targetData 
-        && folderData.targetData.isAdvancedCalendarTargetData) {
-
-        folderData.targetData.calendarObserver("onCalendarUnregistered", aCalendar);                
-      }*/
-    },
-      
-    onCalendarDeleting : async function (aCalendar) {
-      let folderData = TbSync.lightning.getFolderFromCalendarUID(aCalendar.id);                    
-      if (folderData 
-        && folderData.targetData 
-        && folderData.targetData.isAdvancedCalendarTargetData) {
-
-        // If the user switches "offline support", the calendar is deleted and recreated. Thus,
-        // we wait a bit and check, if the calendar is back again and ignore the delete event.
-        if (aCalendar.type == "caldav") {
-          await TbSync.tools.sleep(1500);
-          let calManager = TbSync.lightning.cal.manager;
-          for (let calendar of calManager.getCalendars({})) {
-            if (calendar.uri.spec == aCalendar.uri.spec) {
-              // update the target
-              folderData.setFolderProperty("target", calendar.id)
-              return;
-            }
-          }
-        }
-        
-        //delete any pending changelog of the deleted calendar
-        TbSync.db.clearChangeLog(aCalendar.id);			
-
-        let tbCalendar = new TbSync.lightning.TbCalendar(aCalendar, folderData);
-          
-        //unselect calendar if deleted by user and update settings window, if open
-        if (folderData.getFolderProperty("selected")) {
-          folderData.setFolderProperty("selected", false);
-          //update settings window, if open
-          Services.obs.notifyObservers(null, "tbsync.observer.manager.updateSyncstate", folderData.accountID);
-        }
-        
-        folderData.resetFolderProperty("target");
-        folderData.targetData.calendarObserver("onCalendarDeleted", tbCalendar);                
-
-      }
-    },
-  },
-
-  
-  
-  //this function actually creates a calendar if missing
-  prepareAndCreateCalendar: async function (folderData) {       
-    let calManager = TbSync.lightning.cal.manager;
-    let provider = folderData.accountData.getAccountProperty("provider");
-
-    //check if  there is a known/cached name, and use that as starting point to generate unique name for new calendar 
-    let cachedName = folderData.getFolderProperty("targetName");                         
-    let newname = cachedName == "" ? folderData.accountData.getAccountProperty("accountname") + " (" + folderData.getFolderProperty("foldername") + ")" : cachedName;
-
-    //check if there is a cached or preloaded color - if not, chose one
-    if (!folderData.getFolderProperty("targetColor")) {
-      //define color set
-      let allColors = [
-        "#3366CC",
-        "#DC3912",
-        "#FF9900",
-        "#109618",
-        "#990099",
-        "#3B3EAC",
-        "#0099C6",
-        "#DD4477",
-        "#66AA00",
-        "#B82E2E",
-        "#316395",
-        "#994499",
-        "#22AA99",
-        "#AAAA11",
-        "#6633CC",
-        "#E67300",
-        "#8B0707",
-        "#329262",
-        "#5574A6",
-        "#3B3EAC"];
-      
-      //find all used colors
-      let usedColors = [];
-      for (let calendar of calManager.getCalendars({})) {
-        if (calendar && calendar.getProperty("color")) {
-          usedColors.push(calendar.getProperty("color").toUpperCase());
-        }
-      }
-
-      //we do not want to change order of colors, we want to FILTER by counts, so we need to find the least count, filter by that and then take the first one
-      let minCount = null;
-      let statColors = [];
-      for (let i=0; i< allColors.length; i++) {
-        let count = usedColors.filter(item => item == allColors[i]).length;
-        if (minCount === null) minCount = count;
-        else if (count < minCount) minCount = count;
-
-        let obj = {};
-        obj.color = allColors[i];
-        obj.count = count;
-        statColors.push(obj);
-      }
-      
-      //filter by minCount
-      let freeColors = statColors.filter(item => (minCount == null || item.count == minCount));
-      folderData.setFolderProperty("targetColor", freeColors[0].color);        
-    }
-    
-    //create and register new calendar
-    let newCalendar = await folderData.targetData.createCalendar(newname);
-    newCalendar.setProperty("tbSyncProvider", provider);
-    newCalendar.setProperty("tbSyncAccountID", folderData.accountData.accountID);
-
-    //store id of calendar as target in DB
-    folderData.setFolderProperty("target", newCalendar.id); 
-    folderData.setFolderProperty("targetName", newCalendar.name);
-    folderData.setFolderProperty("targetColor",  newCalendar.getProperty("color"));
-    return newCalendar;        
-  }
-}
+/*
+ * This file is part of TbSync.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. 
+ */
+ 
+"use strict";
+
+var { ExtensionParent } = ChromeUtils.importESModule(
+  "resource://gre/modules/ExtensionParent.sys.mjs"
+);
+
+var tbsyncExtension = ExtensionParent.GlobalManager.getExtension(
+  "tbsync at jobisoft.de"
+);
+var { TbSync } = ChromeUtils.importESModule(
+  `chrome://tbsync/content/tbsync.sys.mjs?${tbsyncExtension.manifest.version}`
+);
+
+ChromeUtils.defineESModuleGetters(this, {  
+  CalAlarm: "resource:///modules/CalAlarm.sys.mjs",
+  CalAttachment: "resource:///modules/CalAttachment.sys.mjs",
+  CalAttendee: "resource:///modules/CalAttendee.sys.mjs",
+  CalEvent: "resource:///modules/CalEvent.sys.mjs",
+  CalTodo: "resource:///modules/CalTodo.sys.mjs",
+}); 
+  
+var lightning = {
+
+  cal: null,
+  ICAL: null,
+   
+  load: async function () {
+    try {
+      TbSync.lightning.cal = ChromeUtils.importESModule("resource:///modules/calendar/calUtils.sys.mjs").cal;
+      TbSync.lightning.ICAL = ChromeUtils.importESModule("resource:///modules/calendar/Ical.sys.mjs").default;
+      let manager = TbSync.lightning.cal.manager;
+      manager.addCalendarObserver(this.calendarObserver);
+      manager.addObserver(this.calendarManagerObserver);
+    } catch (e) {
+      TbSync.dump("Check4Lightning","Error during lightning module import: " + e.toString() + "\n" + e.stack);
+      Components.utils.reportError(e);
+    }
+  },
+
+  unload: async function () {
+    //removing global observer
+    let manager = TbSync.lightning.cal.manager;
+    manager.removeCalendarObserver(this.calendarObserver);
+    manager.removeObserver(this.calendarManagerObserver);
+  },
+
+
+
+
+  
+  // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+  // * AdvancedTargetData, an extended TargetData implementation, providers
+  // * can use this as their own TargetData by extending it and just
+  // * defining the extra methods
+  // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+  
+  AdvancedTargetData : class {
+    constructor(folderData) {            
+      this._folderData = folderData;
+      this._targetObj = null;           
+    }
+    
+    // Check, if the target exists and return true/false.
+    hasTarget() {
+      let calManager = TbSync.lightning.cal.manager;
+      let target = this._folderData.getFolderProperty("target");
+      let calendar = calManager.getCalendarById(target);
+      
+      return calendar ? true : false;
+    }
+
+    // Returns the target obj, which TbSync should return as the target. It can
+    // be whatever you want and is returned by FolderData.targetData.getTarget().
+    // If the target does not exist, it should be created. Throw a simple Error, if that
+    // failed.
+    async getTarget() {
+      let calManager = TbSync.lightning.cal.manager;
+      let target = this._folderData.getFolderProperty("target");
+      let calendar = calManager.getCalendarById(target);
+      
+      if (!calendar) {
+        calendar = await TbSync.lightning.prepareAndCreateCalendar(this._folderData);
+        if (!calendar)
+          throw new Error("notargets");
+      }
+
+      if (!this._targetObj || this._targetObj.id != calendar.id)
+        this._targetObj = new TbSync.lightning.TbCalendar(calendar, this._folderData);
+
+      return this._targetObj;
+    }
+    
+    /**
+     * Removes the target from the local storage. If it does not exist, return
+     * silently. A call to ``hasTarget()`` should return false, after this has
+     * been executed.
+     *
+     */
+    removeTarget() {
+      let calManager = TbSync.lightning.cal.manager;
+      let target = this._folderData.getFolderProperty("target");
+      let calendar = calManager.getCalendarById(target);
+
+      try {
+        if (calendar) {
+          calManager.removeCalendar(calendar);
+        }
+      } catch (e) {}
+      TbSync.db.clearChangeLog(target);
+      this._folderData.resetFolderProperty("target");             
+    }
+
+
+    /**
+     * Disconnects the target in the local storage from this TargetData, but
+     * does not delete it, so it becomes a stale "left over" . A call
+     * to ``hasTarget()`` should return false, after this has been executed.
+     * 
+     */
+    disconnectTarget() {
+      let calManager = TbSync.lightning.cal.manager;
+      let target = this._folderData.getFolderProperty("target");
+      let calendar = calManager.getCalendarById(target);
+
+      if (calendar) {
+        let changes = TbSync.db.getItemsFromChangeLog(target, 0, "_by_user");        
+        if (changes.length > 0) {
+          this.targetName = this.targetName + " (*)";
+        }
+        calendar.setProperty("disabled", true);
+        calendar.setProperty("tbSyncProvider", "orphaned");
+        calendar.setProperty("tbSyncAccountID", "");
+      }
+      TbSync.db.clearChangeLog(target);
+      this._folderData.resetFolderProperty("target");        
+    } 
+    
+    set targetName(newName) {
+      let calManager = TbSync.lightning.cal.manager;
+      let target = this._folderData.getFolderProperty("target");
+      let calendar = calManager.getCalendarById(target);
+
+      if (calendar) {
+        calendar.name = newName;
+      } else {
+        throw new Error("notargets");
+      }
+    }
+  
+    get targetName() {
+      let calManager = TbSync.lightning.cal.manager;
+      let target = this._folderData.getFolderProperty("target");
+      let calendar = calManager.getCalendarById(target);
+
+      if (calendar) {
+        return calendar.name;
+      } else {
+        throw new Error("notargets");
+      }
+    }
+
+    setReadOnly(value) {
+      // hasTarget() can throw an error, ignore that here
+      try {
+        if (this.hasTarget()) {
+          this.getTarget().then(target => target.calendar.setProperty("readOnly", value));
+        }
+      } catch (e) {
+        Components.utils.reportError(e);
+      }
+    }
+
+    
+    // * * * * * * * * * * * * * * * * *
+    // * AdvancedTargetData extension  * 
+    // * * * * * * * * * * * * * * * * *
+    
+    get isAdvancedCalendarTargetData() {
+      return true;
+    }
+    
+    get folderData() {
+      return this._folderData;
+    }
+    
+    // The calendar target does not support a custom primaryKeyField, because
+    // the lightning implementation only allows to search for items via UID.
+    // Like the addressbook target, the calendar target item element has a
+    // primaryKey getter/setter which - however - only works on the UID.
+    
+    // enable or disable changelog
+    get logUserChanges(){
+      return true;
+    }
+
+    calendarObserver(aTopic, tbCalendar, aPropertyName, aPropertyValue, aOldPropertyValue) {
+      switch (aTopic) {
+        case "onCalendarPropertyChanged":
+          //Services.console.logStringMessage("["+ aTopic + "] " + tbCalendar.calendar.name + " : " + aPropertyName);
+          break;
+
+        case "onCalendarDeleted":
+        case "onCalendarPropertyDeleted":
+          //Services.console.logStringMessage("["+ aTopic + "] " +tbCalendar.calendar.name);
+          break;
+      }
+    }
+
+    itemObserver(aTopic, tbItem, tbOldItem) {
+      switch (aTopic) {
+        case "onAddItem":
+        case "onModifyItem":
+        case "onDeleteItem":
+          //Services.console.logStringMessage("["+ aTopic + "] " + tbItem.nativeItem.title);
+          break;
+      }
+    }
+
+    // replace this with your own implementation to create the actual addressbook,
+    // when this class is extended
+    async createCalendar(newname) {
+      let calManager = TbSync.lightning.cal.manager;
+      let newCalendar = calManager.createCalendar("storage", Services.io.newURI("moz-storage-calendar://"));
+      newCalendar.id = TbSync.lightning.cal.getUUID();
+      newCalendar.name = newname;
+      return newCalendar
+    }      
+    
+  },
+
+
+
+
+  
+  // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+  // * TbItem and TbCalendar Classes
+  // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+  
+  TbItem : class {
+    constructor(TbCalendar, item) {
+      if (!TbCalendar)
+        throw new Error("TbItem::constructor is missing its first parameter!");
+
+      if (!item)
+        throw new Error("TbItem::constructor is missing its second parameter!");
+
+      this._tbCalendar = TbCalendar;
+      this._item = item;
+      
+      this._isTodo = item.isTodo ? item.isTodo() : (item instanceof Ci.calITodo);
+      this._isEvent = item.isEvent ? item.isEvent() :  (item instanceof Ci.calIEvent);
+    }
+    
+    get tbCalendar() {
+      return this._tbCalendar;
+    }
+
+    get isTodo() {
+      return this._isTodo;
+    }
+    
+    get isEvent() {
+      return this._isEvent;
+    }
+
+
+
+
+    
+    get nativeItem() {
+      return this._item;
+    }
+
+    get UID() {
+      return this._item.id;
+    }
+    
+    get primaryKey() {
+      // no custom key possible with lightning, must use the UID
+      return this._item.id;
+    }
+
+    set primaryKey(value) {
+      // no custom key possible with lightning, must use the UID
+      this._item.id = value;   
+    }
+
+    clone() {
+      return new TbSync.lightning.TbItem(this._tbCalendar, this._item.clone());
+    }
+
+    toString() {
+      return this._item.icalString;
+    }
+
+    getProperty(property, fallback = "") {
+      return this._item.hasProperty(property) ? this._item.getProperty(property) : fallback;
+    }
+
+    setProperty(property, value) {
+      this._item.setProperty(property, value);
+    }
+    
+    deleteProperty(property) {
+      this._item.deleteProperty(property);
+    }
+        
+    get changelogData() {         
+      return TbSync.db.getItemDataFromChangeLog(this._tbCalendar.UID, this.primaryKey);
+    }
+
+    get changelogStatus() {
+      return TbSync.db.getItemStatusFromChangeLog(this._tbCalendar.UID, this.primaryKey);
+    }
+
+    set changelogStatus(status) {
+      let value = this.primaryKey;
+      
+      if (value) {
+        if (!status) {
+          TbSync.db.removeItemFromChangeLog(this._tbCalendar.UID, value);
+          return;
+        }
+
+        if (this._tbCalendar.logUserChanges || status.endsWith("_by_server")) {
+          TbSync.db.addItemToChangeLog(this._tbCalendar.UID, value, status);
+        }
+      }
+    }
+  },
+
+
+  TbCalendar : class {
+    constructor(calendar, folderData) {
+      this._calendar = calendar;
+      this._folderData = folderData;
+     }
+
+    get calendar() {
+      return this._calendar;
+    }
+    
+    get promisifyCalendar() {
+      return this._calendar;
+    }
+
+    get logUserChanges() {
+      return this._folderData.targetData.logUserChanges;
+    }
+    
+    get primaryKeyField() {
+      // Not supported by lightning. We let the implementation sit here, it may get changed in the future.
+      // In order to support this, lightning needs to implement a proper getItemfromProperty() method.
+      return null;
+    }
+    
+    get UID() {
+      return this._calendar.id;
+    }
+
+    createNewEvent() {
+      let event = new CalEvent();
+      return new TbSync.lightning.TbItem(this, event);
+    }
+    
+    createNewTodo() {
+      let todo = new CalTodo();
+      return new TbSync.lightning.TbItem(this, todo);
+    }
+
+    
+    
+    
+    async addItem(tbItem, pretagChangelogWithByServerEntry = true) {
+      if (this.primaryKeyField && !tbItem.getProperty(this.primaryKeyField)) {
+        tbItem.setProperty(this.primaryKeyField, this._folderData.targetData.generatePrimaryKey());
+        //Services.console.logStringMessage("[TbCalendar::addItem] Generated primary key!");
+      }
+      
+      if (pretagChangelogWithByServerEntry) {
+        tbItem.changelogStatus = "added_by_server";
+      }
+      return await this._calendar.addItem(tbItem._item);
+    }
+    
+    async modifyItem(tbNewItem, tbOldItem, pretagChangelogWithByServerEntry = true) {
+      // only add entry if the current entry does not start with _by_user
+      let status = tbNewItem.changelogStatus ? tbNewItem.changelogStatus : "";
+      if (pretagChangelogWithByServerEntry && !status.endsWith("_by_user")) {
+        tbNewItem.changelogStatus = "modified_by_server";
+      }
+      
+      return await this._calendar.modifyItem(tbNewItem._item, tbOldItem._item); 
+    }        
+    
+    async deleteItem(tbItem, pretagChangelogWithByServerEntry = true) {
+      if (pretagChangelogWithByServerEntry) {
+        tbItem.changelogStatus = "deleted_by_server";
+      }
+      return await this._calendar.deleteItem(tbItem._item); 
+    }
+    
+    // searchId is interpreted as the primaryKeyField, which is the UID for this target
+    async getItem (searchId) {
+      let item = await this._calendar.getItem(searchId); 
+      if (item) {
+        return new TbSync.lightning.TbItem(this, item);
+      }
+      return null;
+    }
+
+    async getItemFromProperty(property, value) {
+      if (property == "UID") return await this.getItem(value);
+      else throw ("TbSync.lightning.getItemFromProperty: Currently onle the UID property can be used to search for items.");
+    }
+
+    async getAllItems() {
+      return await this._calendar.getItems(Ci.calICalendar.ITEM_FILTER_ALL_ITEMS, 0, null, null);
+    }
+  
+    getAddedItemsFromChangeLog(maxitems = 0) {             
+      return TbSync.db.getItemsFromChangeLog(this.calendar.id, maxitems, "added_by_user").map(item => item.itemId);
+    }
+
+    getModifiedItemsFromChangeLog(maxitems = 0) {             
+      return TbSync.db.getItemsFromChangeLog(this.calendar.id, maxitems, "modified_by_user").map(item => item.itemId);
+    }
+    
+    getDeletedItemsFromChangeLog(maxitems = 0) {             
+      return TbSync.db.getItemsFromChangeLog(this.calendar.id, maxitems, "deleted_by_user").map(item => item.itemId);
+    }
+    
+    getItemsFromChangeLog(maxitems = 0) {             
+      return TbSync.db.getItemsFromChangeLog(this.calendar.id, maxitems, "_by_user");
+    }
+
+    removeItemFromChangeLog(id, moveToEndInsteadOfDelete = false) {             
+      TbSync.db.removeItemFromChangeLog(this.calendar.id, id, moveToEndInsteadOfDelete);
+    }
+    
+    clearChangelog() {
+      TbSync.db.clearChangeLog(this.calendar.id);
+    }
+  },
+  
+
+
+
+  
+  // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+  // * Internal Functions
+  // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+  
+  getFolderFromCalendarUID: function(calUID) {
+    let folders = TbSync.db.findFolders({"target": calUID});
+    if (folders.length == 1) {
+      let accountData = new TbSync.AccountData(folders[0].accountID);
+      return new TbSync.FolderData(accountData, folders[0].folderID);
+    }
+    return null;
+  },
+  
+  getFolderFromCalendarURL: function(calURL) {
+    let folders = TbSync.db.findFolders({"url": calURL});
+    if (folders.length == 1) {
+      let accountData = new TbSync.AccountData(folders[0].accountID);
+      return new TbSync.FolderData(accountData, folders[0].folderID);
+    }
+    return null;
+  },  
+  
+  calendarObserver : { 
+    onStartBatch : function () {},
+    onEndBatch : function () {},
+    onLoad : function (aCalendar) {},
+    onError : function (aCalendar, aErrNo, aMessage) {},
+
+    onAddItem : function (aAddedItem) { 
+      if (!(aAddedItem && aAddedItem.calendar))
+        return;
+
+      let folderData = TbSync.lightning.getFolderFromCalendarUID(aAddedItem.calendar.id);                    
+      if (folderData 
+        && folderData.targetData 
+        && folderData.targetData.isAdvancedCalendarTargetData) {
+
+        let tbCalendar = new TbSync.lightning.TbCalendar(aAddedItem.calendar, folderData);
+        let tbItem = new TbSync.lightning.TbItem(tbCalendar, aAddedItem);          
+        let itemStatus = tbItem.changelogStatus;
+
+        // if this card was created by us, it will be in the log
+        if (itemStatus && itemStatus.endsWith("_by_server")) {
+          let age = Date.now() - tbItem.changelogData.timestamp;
+          if (age < 1500) {
+            // during freeze, local modifications are not possible
+            return;
+          } else {
+            // remove blocking entry from changelog after freeze time is over (1.5s),
+            // and continue evaluating this event
+            abItem.changelogStatus = "";
+          }
+        } 
+
+        if (itemStatus == "deleted_by_user")  {
+          // deleted ?  user moved item out and back in -> modified
+          tbItem.changelogStatus = "modified_by_user";
+        } else {
+          tbItem.changelogStatus = "added_by_user";
+        }
+        
+        if (tbCalendar.logUserChanges) TbSync.core.setTargetModified(folderData);
+        folderData.targetData.itemObserver("onAddItem", tbItem, null);                                        
+      }
+    },
+
+    onModifyItem : function (aNewItem, aOldItem) {
+      //check, if it is a pure modification within the same calendar
+      if (!(aNewItem && aNewItem.calendar && aOldItem && aOldItem.calendar && aNewItem.calendar.id == aOldItem.calendar.id))
+        return;
+
+      let folderData = TbSync.lightning.getFolderFromCalendarUID(aNewItem.calendar.id);                    
+      if (folderData 
+        && folderData.targetData 
+        && folderData.targetData.isAdvancedCalendarTargetData) {
+
+        let tbCalendar = new TbSync.lightning.TbCalendar(aNewItem.calendar, folderData);
+        let tbNewItem = new TbSync.lightning.TbItem(tbCalendar, aNewItem);          
+        let tbOldItem = new TbSync.lightning.TbItem(tbCalendar, aOldItem);          
+        let itemStatus = tbNewItem.changelogStatus;
+          
+        // if this card was created by us, it will be in the log
+        if (itemStatus && itemStatus.endsWith("_by_server")) {
+          let age = Date.now() - tbNewItem.changelogData.timestamp;
+          if (age < 1500) {
+            // during freeze, local modifications are not possible
+            return;
+          } else {
+            // remove blocking entry from changelog after freeze time is over (1.5s),
+            // and continue evaluating this event
+            tbNewItem.changelogStatus = "";
+          }
+        } 
+
+        if (itemStatus != "added_by_user") {
+          //added_by_user -> it is a local unprocessed add do not re-add it to changelog
+          tbNewItem.changelogStatus = "modified_by_user";
+        }
+
+        if (tbCalendar.logUserChanges) TbSync.core.setTargetModified(folderData);
+        folderData.targetData.itemObserver("onModifyItem", tbNewItem, tbOldItem);                                        
+      }
+    },
+
+    onDeleteItem : function (aDeletedItem) {
+      if (!(aDeletedItem && aDeletedItem.calendar))
+        return;
+
+      let folderData = TbSync.lightning.getFolderFromCalendarUID(aDeletedItem.calendar.id);                    
+      if (folderData 
+        && folderData.targetData 
+        && folderData.targetData.isAdvancedCalendarTargetData) {
+
+        let tbCalendar = new TbSync.lightning.TbCalendar(aDeletedItem.calendar, folderData);
+        let tbItem = new TbSync.lightning.TbItem(tbCalendar, aDeletedItem);
+        let itemStatus = tbItem.changelogStatus;
+
+        // if this card was created by us, it will be in the log
+        if (itemStatus && itemStatus.endsWith("_by_server")) {
+          let age = Date.now() - tbItem.changelogData.timestamp;
+          if (age < 1500) {
+            // during freeze, local modifications are not possible
+            return;
+          } else {
+            // remove blocking entry from changelog after freeze time is over (1.5s),
+            // and continue evaluating this event
+            tbItem.changelogStatus = "";
+          }
+        } 
+
+        if (itemStatus == "added_by_user") {
+          //a local add, which has not yet been processed (synced) is deleted -> remove all traces
+          tbItem.changelogStatus = "";
+        } else {
+          tbItem.changelogStatus = "deleted_by_user";
+        }
+
+        if (tbCalendar.logUserChanges) TbSync.core.setTargetModified(folderData);
+        folderData.targetData.itemObserver("onDeleteItem", tbItem, null);
+      }
+    },
+
+    //Changed properties of the calendar itself (name, color etc.)
+    onPropertyChanged : function (aCalendar, aName, aValue, aOldValue) {
+      let folderData = TbSync.lightning.getFolderFromCalendarUID(aCalendar.id);                    
+      if (folderData 
+        && folderData.targetData 
+        && folderData.targetData.isAdvancedCalendarTargetData) {
+
+        let tbCalendar = new TbSync.lightning.TbCalendar(aCalendar, folderData);
+          
+        switch (aName) {
+          case "color":
+            // update stored color to recover after disable
+            folderData.setFolderProperty("targetColor", aValue); 
+            break;
+          case "name":
+            // update stored name to recover after disable
+            folderData.setFolderProperty("targetName", aValue);                         
+            // update settings window, if open
+            Services.obs.notifyObservers(null, "tbsync.observer.manager.updateSyncstate", folderData.accountID);                    
+            break;
+        }
+        
+        folderData.targetData.calendarObserver("onCalendarPropertyChanged", tbCalendar, aName, aValue, aOldValue);                
+      }
+    },
+
+    //Deleted properties of the calendar itself (name, color etc.)
+    onPropertyDeleting : function (aCalendar, aName) {
+      let folderData = TbSync.lightning.getFolderFromCalendarUID(aCalendar.id);                    
+      if (folderData 
+        && folderData.targetData 
+        && folderData.targetData.isAdvancedCalendarTargetData) {
+
+        let tbCalendar = new TbSync.lightning.TbCalendar(aCalendar, folderData);
+          
+        switch (aName) {
+          case "color":
+          case "name":
+            //update settings window, if open
+            Services.obs.notifyObservers(null, "tbsync.observer.manager.updateSyncstate", folderData.accountID);                    
+          break;
+        }
+
+        folderData.targetData.calendarObserver("onCalendarPropertyDeleted", tbCalendar, aName);                
+      }
+    }
+  },
+
+  calendarManagerObserver : {
+    onCalendarRegistered : function (aCalendar) {              
+    },
+    
+    onCalendarUnregistering : function (aCalendar) {
+      /*let folderData = TbSync.lightning.getFolderFromCalendarUID(aCalendar.id);                    
+      if (folderData 
+        && folderData.targetData 
+        && folderData.targetData.isAdvancedCalendarTargetData) {
+
+        folderData.targetData.calendarObserver("onCalendarUnregistered", aCalendar);                
+      }*/
+    },
+      
+    onCalendarDeleting : async function (aCalendar) {
+      let folderData = TbSync.lightning.getFolderFromCalendarUID(aCalendar.id);                    
+      if (folderData 
+        && folderData.targetData 
+        && folderData.targetData.isAdvancedCalendarTargetData) {
+
+        // If the user switches "offline support", the calendar is deleted and recreated. Thus,
+        // we wait a bit and check, if the calendar is back again and ignore the delete event.
+        if (aCalendar.type == "caldav") {
+          await TbSync.tools.sleep(1500);
+          let calManager = TbSync.lightning.cal.manager;
+          for (let calendar of calManager.getCalendars({})) {
+            if (calendar.uri.spec == aCalendar.uri.spec) {
+              // update the target
+              folderData.setFolderProperty("target", calendar.id)
+              return;
+            }
+          }
+        }
+        
+        //delete any pending changelog of the deleted calendar
+        TbSync.db.clearChangeLog(aCalendar.id);			
+
+        let tbCalendar = new TbSync.lightning.TbCalendar(aCalendar, folderData);
+          
+        //unselect calendar if deleted by user and update settings window, if open
+        if (folderData.getFolderProperty("selected")) {
+          folderData.setFolderProperty("selected", false);
+          //update settings window, if open
+          Services.obs.notifyObservers(null, "tbsync.observer.manager.updateSyncstate", folderData.accountID);
+        }
+        
+        folderData.resetFolderProperty("target");
+        folderData.targetData.calendarObserver("onCalendarDeleted", tbCalendar);                
+
+      }
+    },
+  },
+
+  
+  
+  //this function actually creates a calendar if missing
+  prepareAndCreateCalendar: async function (folderData) {       
+    let calManager = TbSync.lightning.cal.manager;
+    let provider = folderData.accountData.getAccountProperty("provider");
+
+    //check if  there is a known/cached name, and use that as starting point to generate unique name for new calendar 
+    let cachedName = folderData.getFolderProperty("targetName");                         
+    let newname = cachedName == "" ? folderData.accountData.getAccountProperty("accountname") + " (" + folderData.getFolderProperty("foldername") + ")" : cachedName;
+
+    //check if there is a cached or preloaded color - if not, chose one
+    if (!folderData.getFolderProperty("targetColor")) {
+      //define color set
+      let allColors = [
+        "#3366CC",
+        "#DC3912",
+        "#FF9900",
+        "#109618",
+        "#990099",
+        "#3B3EAC",
+        "#0099C6",
+        "#DD4477",
+        "#66AA00",
+        "#B82E2E",
+        "#316395",
+        "#994499",
+        "#22AA99",
+        "#AAAA11",
+        "#6633CC",
+        "#E67300",
+        "#8B0707",
+        "#329262",
+        "#5574A6",
+        "#3B3EAC"];
+      
+      //find all used colors
+      let usedColors = [];
+      for (let calendar of calManager.getCalendars({})) {
+        if (calendar && calendar.getProperty("color")) {
+          usedColors.push(calendar.getProperty("color").toUpperCase());
+        }
+      }
+
+      //we do not want to change order of colors, we want to FILTER by counts, so we need to find the least count, filter by that and then take the first one
+      let minCount = null;
+      let statColors = [];
+      for (let i=0; i< allColors.length; i++) {
+        let count = usedColors.filter(item => item == allColors[i]).length;
+        if (minCount === null) minCount = count;
+        else if (count < minCount) minCount = count;
+
+        let obj = {};
+        obj.color = allColors[i];
+        obj.count = count;
+        statColors.push(obj);
+      }
+      
+      //filter by minCount
+      let freeColors = statColors.filter(item => (minCount == null || item.count == minCount));
+      folderData.setFolderProperty("targetColor", freeColors[0].color);        
+    }
+    
+    //create and register new calendar
+    let newCalendar = await folderData.targetData.createCalendar(newname);
+    newCalendar.setProperty("tbSyncProvider", provider);
+    newCalendar.setProperty("tbSyncAccountID", folderData.accountData.accountID);
+
+    //store id of calendar as target in DB
+    folderData.setFolderProperty("target", newCalendar.id); 
+    folderData.setFolderProperty("targetName", newCalendar.name);
+    folderData.setFolderProperty("targetColor",  newCalendar.getProperty("color"));
+    return newCalendar;        
+  }
+}
diff -Nru tbsync-4.12/content/modules/manager.js tbsync-4.16/content/modules/manager.js
--- tbsync-4.12/content/modules/manager.js	2024-08-27 18:32:08.000000000 +0200
+++ tbsync-4.16/content/modules/manager.js	2025-03-15 23:49:58.000000000 +0100
@@ -1,394 +1,407 @@
-/*
- * This file is part of TbSync.
- *
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. 
- */
- 
-"use strict";
-
-var { MailServices } = ChromeUtils.import("resource:///modules/MailServices.jsm");
-
-var manager = {
-
-  prefWindowObj: null,
-  
-  load: async function () {
-  },
-
-  unload: async function () {
-    //close window (if open)
-    if (this.prefWindowObj !== null) this.prefWindowObj.close();
-  },
-
-
-
-
-
-  openManagerWindow: function(event) {
-    if (!event.button) { //catches zero or undefined
-      if (TbSync.enabled) {
-        // check, if a window is already open and just put it in focus
-        if (this.prefWindowObj === null) {
-          this.prefWindowObj = TbSync.window.open("chrome://tbsync/content/manager/accountManager.xhtml", "TbSyncAccountManagerWindow", "chrome,centerscreen");
-        }
-        this.prefWindowObj.focus();
-      } else {
-        //this.popupNotEnabled();
-      }
-    }
-  },
-
-  popupNotEnabled: function () {
-    TbSync.dump("Oops", "Trying to open account manager, but init sequence not yet finished");
-    let msg = TbSync.getString("OopsMessage") + "\n\n";
-    let v = Services.appinfo.platformVersion; 
-    if (TbSync.prefs.getIntPref("log.userdatalevel") == 0) {
-      if (TbSync.window.confirm(msg + TbSync.getString("UnableToTraceError"))) {
-        TbSync.prefs.setIntPref("log.userdatalevel", 1);
-        TbSync.window.alert(TbSync.getString("RestartThunderbirdAndTryAgain"));
-      }
-    } else {
-      if (TbSync.window.confirm(msg + TbSync.getString("HelpFixStartupError"))) {
-        this.createBugReport("john.bieling at gmx.de", msg, "");
-      }
-    }
-  },
-  
-  openTBtab: function (url) {
-    let tabmail = TbSync.window.document.getElementById("tabmail");
-    if (TbSync.window && tabmail) {
-      TbSync.window.focus();
-      return tabmail.openTab("contentTab", {
-        url
-      });
-    }
-    return null;
-  },
-
-  openTranslatedLink: function (url) {
-    let googleCode = TbSync.getString("google.translate.code");
-    if (googleCode != "en" && googleCode != "google.translate.code") {
-      this.openLink("https://translate.google.com/translate?hl=en&sl=en&tl="+TbSync.getString("google.translate.code")+"&u="+url);
-    } else {
-      this.openLink(url);
-    }
-  },
-
-  openLink: function (url) {
-    let ioservice = Components.classes["@mozilla.org/network/io-service;1"].getService(Components.interfaces.nsIIOService);
-    let uriToOpen = ioservice.newURI(url, null, null);
-    let extps = Components.classes["@mozilla.org/uriloader/external-protocol-service;1"].getService(Components.interfaces.nsIExternalProtocolService);
-    extps.loadURI(uriToOpen, null);    
-  },
-  
-  openBugReportWizard: function () {
-    if (!TbSync.debugMode) {
-      this.prefWindowObj.alert(TbSync.getString("NoDebugLog"));
-    } else {
-      this.prefWindowObj.openDialog("chrome://tbsync/content/manager/support-wizard/support-wizard.xhtml", "support-wizard", "dialog,centerscreen,chrome,resizable=no");
-    }
-  },
-  
-  createBugReport: function (email, subject, description) {
-    let fields = Components.classes["@mozilla.org/messengercompose/composefields;1"].createInstance(Components.interfaces.nsIMsgCompFields); 
-    let params = Components.classes["@mozilla.org/messengercompose/composeparams;1"].createInstance(Components.interfaces.nsIMsgComposeParams); 
-
-    fields.to = email; 
-    fields.subject = "TbSync " + TbSync.addon.version.toString() + " bug report: " + subject; 
-    fields.body = "Hi,\n\n" +
-      "attached you find my debug.log for the following error:\n\n" + 
-      description; 
-
-    params.composeFields = fields; 
-    params.format = Components.interfaces.nsIMsgCompFormat.PlainText; 
-
-    let attachment = Components.classes["@mozilla.org/messengercompose/attachment;1"].createInstance(Components.interfaces.nsIMsgAttachment);
-    attachment.contentType = "text/plain";
-    attachment.url =  'file://' + TbSync.io.getAbsolutePath("debug.log");
-    attachment.name = "debug.log";
-    attachment.temporary = false;
-
-    params.composeFields.addAttachment(attachment);        
-    MailServices.compose.OpenComposeWindowWithParams (null, params);    
-  },
-
-  viewDebugLog: function() {
-
-    if (this.debugLogWindow && this.debugLogWindow.tabNode) {
-      let tabmail = TbSync.window.document.getElementById("tabmail");
-      try {
-        tabmail.closeTab(this.debugLogWindow);
-      } catch (e) {
-        // nope
-      }
-      this.debugLogWindow = null;
-    } 
-    this.debugLogWindow = this.openTBtab('file://' + TbSync.io.getAbsolutePath("debug.log"));
-  },
-}
-
-
-
-/**
- * Functions used by the folderlist in the main account settings tab
- */
-manager.FolderList = class {
-  /**
-   * @param {string}  provider  Identifier for the provider this FolderListView is created for.
-   */
-  constructor(provider) {
-    this.provider = provider
-  }
-  
-  /**
-   * Is called before the context menu of the folderlist is shown, allows to
-   * show/hide custom menu options based on selected folder
-   *
-   * @param document       [in] document object of the account settings window - element.ownerDocument - menuentry?
-   * @param folderData         [in] FolderData of the selected folder
-   */
-  onContextMenuShowing(window, folderData) {
-    return TbSync.providers[this.provider].StandardFolderList.onContextMenuShowing(window, folderData);
-  }
-
-
-  /**
-   * Returns an array of attribute objects, which define the number of columns 
-   * and the look of the header
-   */
-  getHeader() {
-    return [
-      {style: "font-weight:bold;", label: "", width: "93"},
-      {style: "font-weight:bold;", label: TbSync.getString("manager.resource"), width:"150"},
-      {style: "font-weight:bold;", label: TbSync.getString("manager.status"), flex :"1"},
-    ]
-  }
-
-
-  /**
-   * Is called to add a row to the folderlist. After this call, updateRow is called as well.
-   *
-   * @param document        [in] document object of the account settings window
-   * @param folderData         [in] FolderData of the folder in the row
-   */        
-  getRow(document, folderData) {
-    //create checkBox for select state
-    let itemSelCheckbox = document.createXULElement("checkbox");
-    itemSelCheckbox.setAttribute("updatefield", "selectbox");
-    itemSelCheckbox.setAttribute("style", "margin: 0px 0px 0px 3px;");
-    itemSelCheckbox.addEventListener("command", this.toggleFolder);
-
-    //icon
-    let itemType = document.createXULElement("image");
-    itemType.setAttribute("src", TbSync.providers[this.provider].StandardFolderList.getTypeImage(folderData));
-    itemType.setAttribute("style", "margin: 0px 9px 0px 3px;");
-
-    //ACL
-    let roAttributes = TbSync.providers[this.provider].StandardFolderList.getAttributesRoAcl(folderData);
-    let rwAttributes = TbSync.providers[this.provider].StandardFolderList.getAttributesRwAcl(folderData);
-    let itemACL = document.createXULElement("button");
-    itemACL.setAttribute("image", "chrome://tbsync/content/skin/acl_" + (folderData.getFolderProperty("downloadonly") ? "ro" : "rw") + ".png");
-    itemACL.setAttribute("class", "plain");
-    itemACL.setAttribute("style", "width: 35px; min-width: 35px; margin: 0; height:26px");
-    itemACL.setAttribute("updatefield", "acl");
-    if (roAttributes && rwAttributes) {
-      itemACL.setAttribute("type", "menu");
-      let menupopup = document.createXULElement("menupopup");
-      {
-        let menuitem = document.createXULElement("menuitem");
-        menuitem.downloadonly = false;
-        menuitem.setAttribute("class", "menuitem-iconic");
-        menuitem.setAttribute("image", "chrome://tbsync/content/skin/acl_rw2.png");
-        menuitem.addEventListener("command", this.updateReadOnly);
-        for (const [attr, value] of Object.entries(rwAttributes)) {
-          menuitem.setAttribute(attr, value);
-        }                    
-        menupopup.appendChild(menuitem);
-      }
-      
-      {
-        let menuitem = document.createXULElement("menuitem");
-        menuitem.downloadonly = true;
-        menuitem.setAttribute("class", "menuitem-iconic");
-        menuitem.setAttribute("image", "chrome://tbsync/content/skin/acl_ro2.png");
-        menuitem.addEventListener("command", this.updateReadOnly);
-        for (const [attr, value] of Object.entries(roAttributes)) {
-          menuitem.setAttribute(attr, value);
-        }                    
-        menupopup.appendChild(menuitem);
-      }
-      itemACL.appendChild(menupopup);
-    }
-    
-    //folder name
-    let itemLabel = document.createXULElement("description");
-    itemLabel.setAttribute("updatefield", "foldername");
-
-    //status
-    let itemStatus = document.createXULElement("description");
-    itemStatus.setAttribute("updatefield", "status");
-    
-    //group1
-    let itemHGroup1 = document.createXULElement("hbox");
-    itemHGroup1.setAttribute("align", "center");
-    itemHGroup1.appendChild(itemSelCheckbox);
-    itemHGroup1.appendChild(itemType);
-    if (itemACL) itemHGroup1.appendChild(itemACL);
-
-    let itemVGroup1 = document.createXULElement("vbox");
-    //itemVGroup1.setAttribute("width", "93");
-    itemVGroup1.setAttribute("style", "width: 93px");
-    itemVGroup1.appendChild(itemHGroup1);
-
-    //group2
-    let itemHGroup2 = document.createXULElement("hbox");
-    itemHGroup2.setAttribute("align", "center");
-    itemHGroup2.setAttribute("style", "border: 1px center");
-    itemHGroup2.appendChild(itemLabel);
-
-    let itemVGroup2 = document.createXULElement("vbox");
-    //itemVGroup2.setAttribute("width", "150");
-    itemVGroup2.setAttribute("style", "padding: 3px; width: 150px");
-    itemVGroup2.appendChild(itemHGroup2);
-
-    //group3
-    let itemHGroup3 = document.createXULElement("hbox");
-    itemHGroup3.setAttribute("align", "center");
-    itemHGroup3.appendChild(itemStatus);
-
-    let itemVGroup3 = document.createXULElement("vbox");
-    //itemVGroup3.setAttribute("width", "250");
-    itemVGroup3.setAttribute("style", "padding: 3px; width: 250px");
-    itemVGroup3.appendChild(itemHGroup3);
-
-    //final row
-    let row = document.createXULElement("hbox");
-    row.setAttribute("style", "min-height: 24px;");
-    row.appendChild(itemVGroup1);
-    row.appendChild(itemVGroup2);            
-    row.appendChild(itemVGroup3);            
-    return row;               
-  }
-
-
-  /**
-   * ToggleFolder event
-   */
-  toggleFolder(event) {
-    let element = event.target;
-    let folderList = element.ownerDocument.getElementById("tbsync.accountsettings.folderlist");
-    if (folderList.selectedItem !== null && !folderList.disabled) {
-      // the folderData obj of the selected folder is attached to its row entry
-      let folder = folderList.selectedItem.folderData;
-
-      if (!folder.accountData.isEnabled())
-        return;
-    
-      if (folder.getFolderProperty("selected")) {
-        // hasTarget() can throw an error, ignore that here
-        try {
-          if (!folder.targetData.hasTarget() || element.ownerDocument.defaultView.confirm(TbSync.getString("prompt.Unsubscribe"))) {
-            folder.targetData.removeTarget();           
-            folder.setFolderProperty("selected", false);          
-          } else {
-            if (element) {
-              //undo users action
-              element.setAttribute("checked", true);
-            }
-          }
-        } catch (e) {
-          folder.setFolderProperty("selected", false);
-          Components.utils.reportError(e);
-        }
-      } else {
-        //select and update status
-        folder.setFolderProperty("selected", true);
-        folder.setFolderProperty("status", "aborted");
-        folder.accountData.setAccountProperty("status", "notsyncronized");
-      }
-      Services.obs.notifyObservers(null, "tbsync.observer.manager.updateSyncstate", folder.accountID);
-    }
-  }
-  
-  /**
-   * updateReadOnly event
-   */
-  updateReadOnly(event) {
-    let element = event.target;
-    let folderList = element.ownerDocument.getElementById("tbsync.accountsettings.folderlist");
-    if (folderList.selectedItem !== null && !folderList.disabled) {
-      //the folderData obj of the selected folder is attached to its row entry
-      let  folder = folderList.selectedItem.folderData;
-
-      //update value
-      let value = element.downloadonly;
-      folder.setFolderProperty("downloadonly", value);
-
-      //update icon
-      let button = element.parentNode.parentNode;
-      if (value) {
-        button.setAttribute('image','chrome://tbsync/content/skin/acl_ro.png');
-      } else {
-        button.setAttribute('image','chrome://tbsync/content/skin/acl_rw.png');
-      }
-        
-      folder.targetData.setReadOnly(value);
-    }
-  }
-
-  /**
-   * Is called to update a row of the folderlist (the first cell is a select checkbox inserted by TbSync)
-   *
-   * @param document       [in] document object of the account settings window
-   * @param listItem       [in] the listitem of the row, which needs to be updated
-   * @param folderData        [in] FolderData for that row
-   */        
-  updateRow(document, listItem, folderData) {
-    let foldername = TbSync.providers[this.provider].StandardFolderList.getFolderDisplayName(folderData);
-    let status = folderData.getFolderStatus();
-    let selected = folderData.getFolderProperty("selected");
-    
-    // get updatefields
-    let fields = {}
-    for (let f of listItem.querySelectorAll("[updatefield]")) {
-      fields[f.getAttribute("updatefield")] = f;
-    }
-    
-    // update fields
-    fields.foldername.setAttribute("disabled", !selected);
-    fields.foldername.setAttribute("style", selected ? "" : "font-style:italic");
-    if (fields.foldername.textContent != foldername) {
-      fields.foldername.textContent = foldername;
-      fields.foldername.flex = "1";
-    }
-    
-    fields.status.setAttribute("style", selected ? "" : "font-style:italic");
-    if (fields.status.textContent != status) {
-      fields.status.textContent = status;
-      fields.status.flex = "1";
-    }
-    
-    if (fields.hasOwnProperty("acl")) {
-      fields.acl.setAttribute("image", "chrome://tbsync/content/skin/acl_" + (folderData.getFolderProperty("downloadonly") ? "ro" : "rw") + ".png");
-      fields.acl.setAttribute("disabled", folderData.accountData.isSyncing());
-    }
-    
-    // update selectbox
-    let selbox = fields.selectbox;
-    if (selbox) {
-      if (folderData.getFolderProperty("selected")) {
-        selbox.setAttribute("checked", true);
-      } else {
-        selbox.removeAttribute("checked");
-      }
-      
-      if (folderData.accountData.isSyncing()) {
-        selbox.setAttribute("disabled", true);
-      } else {
-        selbox.removeAttribute("disabled");
-      }
-    }
-  }
-}    
+/*
+ * This file is part of TbSync.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. 
+ */
+ 
+"use strict";
+
+var { ExtensionParent } = ChromeUtils.importESModule(
+  "resource://gre/modules/ExtensionParent.sys.mjs"
+);
+var { MailServices } = ChromeUtils.importESModule(
+  "resource:///modules/MailServices.sys.mjs"
+);
+
+var tbsyncExtension = ExtensionParent.GlobalManager.getExtension(
+  "tbsync at jobisoft.de"
+);
+var { TbSync } = ChromeUtils.importESModule(
+  `chrome://tbsync/content/tbsync.sys.mjs?${tbsyncExtension.manifest.version}`
+);
+
+var manager = {
+
+  prefWindowObj: null,
+  
+  load: async function () {
+  },
+
+  unload: async function () {
+    //close window (if open)
+    if (this.prefWindowObj !== null) this.prefWindowObj.close();
+  },
+
+
+
+
+
+  openManagerWindow: function() {
+    if (TbSync.enabled) {
+      // check, if a window is already open and just put it in focus
+      if (this.prefWindowObj === null) {
+        const window = Services.wm.getMostRecentWindow("mail:3pane");
+        this.prefWindowObj = window.open("chrome://tbsync/content/manager/accountManager.xhtml", "TbSyncAccountManagerWindow", "chrome,centerscreen");
+      }
+      this.prefWindowObj.focus();
+    } else {
+      //this.popupNotEnabled();
+    }
+  },
+
+  popupNotEnabled: function () {
+    TbSync.dump("Oops", "Trying to open account manager, but init sequence not yet finished");
+    const msg = TbSync.getString("OopsMessage") + "\n\n";
+    const window = Services.wm.getMostRecentWindow("mail:3pane");
+    if (TbSync.prefs.getIntPref("log.userdatalevel") == 0) {
+      if (window.confirm(msg + TbSync.getString("UnableToTraceError"))) {
+        TbSync.prefs.setIntPref("log.userdatalevel", 1);
+        window.alert(TbSync.getString("RestartThunderbirdAndTryAgain"));
+      }
+    } else {
+      if (window.confirm(msg + TbSync.getString("HelpFixStartupError"))) {
+        this.createBugReport("john.bieling at gmx.de", msg, "");
+      }
+    }
+  },
+  
+  openTBtab: function (url) {
+    const window = Services.wm.getMostRecentWindow("mail:3pane");
+    const tabmail = window.document.getElementById("tabmail");
+    if (window && tabmail) {
+      window.focus();
+      return tabmail.openTab("contentTab", {
+        url
+      });
+    }
+    return null;
+  },
+
+  openTranslatedLink: function (url) {
+    let googleCode = TbSync.getString("google.translate.code");
+    if (googleCode != "en" && googleCode != "google.translate.code") {
+      this.openLink("https://translate.google.com/translate?hl=en&sl=en&tl="+TbSync.getString("google.translate.code")+"&u="+url);
+    } else {
+      this.openLink(url);
+    }
+  },
+
+  openLink: function (url) {
+    let ioservice = Components.classes["@mozilla.org/network/io-service;1"].getService(Components.interfaces.nsIIOService);
+    let uriToOpen = ioservice.newURI(url, null, null);
+    let extps = Components.classes["@mozilla.org/uriloader/external-protocol-service;1"].getService(Components.interfaces.nsIExternalProtocolService);
+    extps.loadURI(uriToOpen, null);    
+  },
+  
+  openBugReportWizard: function () {
+    if (!TbSync.debugMode) {
+      this.prefWindowObj.alert(TbSync.getString("NoDebugLog"));
+    } else {
+      this.prefWindowObj.openDialog("chrome://tbsync/content/manager/support-wizard/support-wizard.xhtml", "support-wizard", "dialog,centerscreen,chrome,resizable=no");
+    }
+  },
+  
+  createBugReport: function (email, subject, description) {
+    let fields = Components.classes["@mozilla.org/messengercompose/composefields;1"].createInstance(Components.interfaces.nsIMsgCompFields); 
+    let params = Components.classes["@mozilla.org/messengercompose/composeparams;1"].createInstance(Components.interfaces.nsIMsgComposeParams); 
+
+    fields.to = email; 
+    fields.subject = "TbSync " + TbSync.addon.version.toString() + " bug report: " + subject; 
+    fields.body = "Hi,\n\n" +
+      "attached you find my debug.log for the following error:\n\n" + 
+      description; 
+
+    params.composeFields = fields; 
+    params.format = Components.interfaces.nsIMsgCompFormat.PlainText; 
+
+    let attachment = Components.classes["@mozilla.org/messengercompose/attachment;1"].createInstance(Components.interfaces.nsIMsgAttachment);
+    attachment.contentType = "text/plain";
+    attachment.url =  'file://' + TbSync.io.getAbsolutePath("debug.log");
+    attachment.name = "debug.log";
+    attachment.temporary = false;
+
+    params.composeFields.addAttachment(attachment);        
+    MailServices.compose.OpenComposeWindowWithParams (null, params);    
+  },
+
+  viewDebugLog: function() {
+
+    if (this.debugLogWindow && this.debugLogWindow.tabNode) {
+      const window = Services.wm.getMostRecentWindow("mail:3pane");
+      const tabmail = window.document.getElementById("tabmail");
+      try {
+        tabmail.closeTab(this.debugLogWindow);
+      } catch (e) {
+        // nope
+      }
+      this.debugLogWindow = null;
+    } 
+    this.debugLogWindow = this.openTBtab('file://' + TbSync.io.getAbsolutePath("debug.log"));
+  },
+}
+
+
+
+/**
+ * Functions used by the folderlist in the main account settings tab
+ */
+manager.FolderList = class {
+  /**
+   * @param {string}  provider  Identifier for the provider this FolderListView is created for.
+   */
+  constructor(provider) {
+    this.provider = provider
+  }
+  
+  /**
+   * Is called before the context menu of the folderlist is shown, allows to
+   * show/hide custom menu options based on selected folder
+   *
+   * @param document       [in] document object of the account settings window - element.ownerDocument - menuentry?
+   * @param folderData         [in] FolderData of the selected folder
+   */
+  onContextMenuShowing(window, folderData) {
+    return TbSync.providers[this.provider].StandardFolderList.onContextMenuShowing(window, folderData);
+  }
+
+
+  /**
+   * Returns an array of attribute objects, which define the number of columns 
+   * and the look of the header
+   */
+  getHeader() {
+    return [
+      {style: "font-weight:bold;", label: "", width: "93"},
+      {style: "font-weight:bold;", label: TbSync.getString("manager.resource"), width:"150"},
+      {style: "font-weight:bold;", label: TbSync.getString("manager.status"), flex :"1"},
+    ]
+  }
+
+
+  /**
+   * Is called to add a row to the folderlist. After this call, updateRow is called as well.
+   *
+   * @param document        [in] document object of the account settings window
+   * @param folderData         [in] FolderData of the folder in the row
+   */        
+  getRow(document, folderData) {
+    //create checkBox for select state
+    let itemSelCheckbox = document.createXULElement("checkbox");
+    itemSelCheckbox.setAttribute("updatefield", "selectbox");
+    itemSelCheckbox.setAttribute("style", "margin: 0px 0px 0px 3px;");
+    itemSelCheckbox.addEventListener("command", this.toggleFolder);
+
+    //icon
+    let itemType = document.createXULElement("image");
+    itemType.setAttribute("src", TbSync.providers[this.provider].StandardFolderList.getTypeImage(folderData));
+    itemType.setAttribute("style", "margin: 0px 9px 0px 3px;");
+
+    //ACL
+    let roAttributes = TbSync.providers[this.provider].StandardFolderList.getAttributesRoAcl(folderData);
+    let rwAttributes = TbSync.providers[this.provider].StandardFolderList.getAttributesRwAcl(folderData);
+    let itemACL = document.createXULElement("button");
+    itemACL.setAttribute("image", "chrome://tbsync/content/skin/acl_" + (folderData.getFolderProperty("downloadonly") ? "ro" : "rw") + ".png");
+    itemACL.setAttribute("class", "plain");
+    itemACL.setAttribute("style", "width: 35px; min-width: 35px; margin: 0; height:26px");
+    itemACL.setAttribute("updatefield", "acl");
+    if (roAttributes && rwAttributes) {
+      itemACL.setAttribute("type", "menu");
+      let menupopup = document.createXULElement("menupopup");
+      {
+        let menuitem = document.createXULElement("menuitem");
+        menuitem.downloadonly = false;
+        menuitem.setAttribute("class", "menuitem-iconic");
+        menuitem.setAttribute("image", "chrome://tbsync/content/skin/acl_rw2.png");
+        menuitem.addEventListener("command", this.updateReadOnly);
+        for (const [attr, value] of Object.entries(rwAttributes)) {
+          menuitem.setAttribute(attr, value);
+        }                    
+        menupopup.appendChild(menuitem);
+      }
+      
+      {
+        let menuitem = document.createXULElement("menuitem");
+        menuitem.downloadonly = true;
+        menuitem.setAttribute("class", "menuitem-iconic");
+        menuitem.setAttribute("image", "chrome://tbsync/content/skin/acl_ro2.png");
+        menuitem.addEventListener("command", this.updateReadOnly);
+        for (const [attr, value] of Object.entries(roAttributes)) {
+          menuitem.setAttribute(attr, value);
+        }                    
+        menupopup.appendChild(menuitem);
+      }
+      itemACL.appendChild(menupopup);
+    }
+    
+    //folder name
+    let itemLabel = document.createXULElement("description");
+    itemLabel.setAttribute("updatefield", "foldername");
+
+    //status
+    let itemStatus = document.createXULElement("description");
+    itemStatus.setAttribute("updatefield", "status");
+    
+    //group1
+    let itemHGroup1 = document.createXULElement("hbox");
+    itemHGroup1.setAttribute("align", "center");
+    itemHGroup1.appendChild(itemSelCheckbox);
+    itemHGroup1.appendChild(itemType);
+    if (itemACL) itemHGroup1.appendChild(itemACL);
+
+    let itemVGroup1 = document.createXULElement("vbox");
+    //itemVGroup1.setAttribute("width", "93");
+    itemVGroup1.setAttribute("style", "width: 93px");
+    itemVGroup1.appendChild(itemHGroup1);
+
+    //group2
+    let itemHGroup2 = document.createXULElement("hbox");
+    itemHGroup2.setAttribute("align", "center");
+    itemHGroup2.setAttribute("style", "border: 1px center");
+    itemHGroup2.appendChild(itemLabel);
+
+    let itemVGroup2 = document.createXULElement("vbox");
+    //itemVGroup2.setAttribute("width", "150");
+    itemVGroup2.setAttribute("style", "padding: 3px; width: 150px");
+    itemVGroup2.appendChild(itemHGroup2);
+
+    //group3
+    let itemHGroup3 = document.createXULElement("hbox");
+    itemHGroup3.setAttribute("align", "center");
+    itemHGroup3.appendChild(itemStatus);
+
+    let itemVGroup3 = document.createXULElement("vbox");
+    //itemVGroup3.setAttribute("width", "250");
+    itemVGroup3.setAttribute("style", "padding: 3px; width: 250px");
+    itemVGroup3.appendChild(itemHGroup3);
+
+    //final row
+    let row = document.createXULElement("hbox");
+    row.setAttribute("style", "min-height: 24px;");
+    row.appendChild(itemVGroup1);
+    row.appendChild(itemVGroup2);            
+    row.appendChild(itemVGroup3);            
+    return row;               
+  }
+
+
+  /**
+   * ToggleFolder event
+   */
+  toggleFolder(event) {
+    let element = event.target;
+    let folderList = element.ownerDocument.getElementById("tbsync.accountsettings.folderlist");
+    if (folderList.selectedItem !== null && !folderList.disabled) {
+      // the folderData obj of the selected folder is attached to its row entry
+      let folder = folderList.selectedItem.folderData;
+
+      if (!folder.accountData.isEnabled())
+        return;
+    
+      if (folder.getFolderProperty("selected")) {
+        // hasTarget() can throw an error, ignore that here
+        try {
+          if (!folder.targetData.hasTarget() || element.ownerDocument.defaultView.confirm(TbSync.getString("prompt.Unsubscribe"))) {
+            folder.targetData.removeTarget();           
+            folder.setFolderProperty("selected", false);          
+          } else {
+            if (element) {
+              //undo users action
+              element.setAttribute("checked", true);
+            }
+          }
+        } catch (e) {
+          folder.setFolderProperty("selected", false);
+          Components.utils.reportError(e);
+        }
+      } else {
+        //select and update status
+        folder.setFolderProperty("selected", true);
+        folder.setFolderProperty("status", "aborted");
+        folder.accountData.setAccountProperty("status", "notsyncronized");
+      }
+      Services.obs.notifyObservers(null, "tbsync.observer.manager.updateSyncstate", folder.accountID);
+    }
+  }
+  
+  /**
+   * updateReadOnly event
+   */
+  updateReadOnly(event) {
+    let element = event.target;
+    let folderList = element.ownerDocument.getElementById("tbsync.accountsettings.folderlist");
+    if (folderList.selectedItem !== null && !folderList.disabled) {
+      //the folderData obj of the selected folder is attached to its row entry
+      let  folder = folderList.selectedItem.folderData;
+
+      //update value
+      let value = element.downloadonly;
+      folder.setFolderProperty("downloadonly", value);
+
+      //update icon
+      let button = element.parentNode.parentNode;
+      if (value) {
+        button.setAttribute('image','chrome://tbsync/content/skin/acl_ro.png');
+      } else {
+        button.setAttribute('image','chrome://tbsync/content/skin/acl_rw.png');
+      }
+        
+      folder.targetData.setReadOnly(value);
+    }
+  }
+
+  /**
+   * Is called to update a row of the folderlist (the first cell is a select checkbox inserted by TbSync)
+   *
+   * @param document       [in] document object of the account settings window
+   * @param listItem       [in] the listitem of the row, which needs to be updated
+   * @param folderData        [in] FolderData for that row
+   */        
+  updateRow(document, listItem, folderData) {
+    let foldername = TbSync.providers[this.provider].StandardFolderList.getFolderDisplayName(folderData);
+    let status = folderData.getFolderStatus();
+    let selected = folderData.getFolderProperty("selected");
+    
+    // get updatefields
+    let fields = {}
+    for (let f of listItem.querySelectorAll("[updatefield]")) {
+      fields[f.getAttribute("updatefield")] = f;
+    }
+    
+    // update fields
+    fields.foldername.setAttribute("disabled", !selected);
+    fields.foldername.setAttribute("style", selected ? "" : "font-style:italic");
+    if (fields.foldername.textContent != foldername) {
+      fields.foldername.textContent = foldername;
+      fields.foldername.flex = "1";
+    }
+    
+    fields.status.setAttribute("style", selected ? "" : "font-style:italic");
+    if (fields.status.textContent != status) {
+      fields.status.textContent = status;
+      fields.status.flex = "1";
+    }
+    
+    if (fields.hasOwnProperty("acl")) {
+      fields.acl.setAttribute("image", "chrome://tbsync/content/skin/acl_" + (folderData.getFolderProperty("downloadonly") ? "ro" : "rw") + ".png");
+      fields.acl.setAttribute("disabled", folderData.accountData.isSyncing());
+    }
+    
+    // update selectbox
+    let selbox = fields.selectbox;
+    if (selbox) {
+      if (folderData.getFolderProperty("selected")) {
+        selbox.setAttribute("checked", true);
+      } else {
+        selbox.removeAttribute("checked");
+      }
+      
+      if (folderData.accountData.isSyncing()) {
+        selbox.setAttribute("disabled", true);
+      } else {
+        selbox.removeAttribute("disabled");
+      }
+    }
+  }
+}    
diff -Nru tbsync-4.12/content/modules/messenger.js tbsync-4.16/content/modules/messenger.js
--- tbsync-4.12/content/modules/messenger.js	2024-08-27 18:32:08.000000000 +0200
+++ tbsync-4.16/content/modules/messenger.js	2025-03-15 23:55:40.000000000 +0100
@@ -1,102 +1,115 @@
-/*
- * This file is part of TbSync.
- *
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. 
- */
- 
-"use strict";
-
-var { OverlayManager } = ChromeUtils.import("chrome://tbsync/content/OverlayManager.jsm");
-
-var messenger = {
-
-  overlayManager : null,
-  
-  load: async function () {
-    this.overlayManager = new OverlayManager(TbSync.extension, {verbose: 0});
-    await this.overlayManager.registerOverlay("chrome://messenger/content/messenger.xhtml", "chrome://tbsync/content/overlays/messenger.xhtml");
-    Services.obs.addObserver(this.initSyncObserver, "tbsync.observer.sync", false);
-    Services.obs.addObserver(this.syncstateObserver, "tbsync.observer.manager.updateSyncstate", false);
-
-    //inject overlays
-    this.overlayManager.startObserving();
-
-  },
-
-  unload: async function () {
-    //unload overlays
-    this.overlayManager.stopObserving();
-
-    Services.obs.removeObserver(this.initSyncObserver, "tbsync.observer.sync");
-    Services.obs.removeObserver(this.syncstateObserver, "tbsync.observer.manager.updateSyncstate");
-  },
-
-  // observer to catch changing syncstate and to update the status bar.
-  syncstateObserver: {
-    observe: function (aSubject, aTopic, aData) {
-      //update status bar in all main windows
-      let windows = Services.wm.getEnumerator("mail:3pane");
-      while (windows.hasMoreElements()) {
-        let domWindow = windows.getNext();
-        if (TbSync) {
-          let status = domWindow.document.getElementById("tbsync.status");
-          if (status) {
-            let label = "TbSync: ";
-            
-            if (TbSync.enabled) {
-
-              //check if any account is syncing, if not switch to idle
-              let accounts = TbSync.db.getAccounts();
-              let idle = true;
-              let err = false;
-          
-              for (let i=0; i<accounts.allIDs.length && idle; i++) {
-                if (!accounts.IDs.includes(accounts.allIDs[i])) {
-                  err = true;
-                  continue;
-                }
-          
-                //set idle to false, if at least one account is syncing
-                if (TbSync.core.isSyncing(accounts.allIDs[i])) idle = false;
-            
-                //check for errors
-                switch (TbSync.db.getAccountProperty(accounts.allIDs[i], "status")) {
-                  case "success":
-                  case "disabled":
-                  case "notsyncronized":
-                  case "syncing":
-                    break;
-                  default:
-                    err = true;
-                }
-              }
-
-              if (idle) {
-                if (err) label += TbSync.getString("info.error");   
-                else label += TbSync.getString("info.idle");   
-              } else {
-                label += TbSync.getString("status.syncing");
-              }
-            } else {
-              label += "Loading";
-            }
-            status.value = label;
-          }
-        }
-      }
-    }
-  },
-  
-  // observer to init sync
-  initSyncObserver: {
-    observe: function (aSubject, aTopic, aData) {
-      if (TbSync.enabled) {
-        TbSync.core.syncAllAccounts();
-      } else {
-        //TbSync.manager.popupNotEnabled();
-      }
-    }
-  },    
-}
+/*
+ * This file is part of TbSync.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. 
+ */
+ 
+"use strict";
+
+var { ExtensionParent } = ChromeUtils.importESModule(
+  "resource://gre/modules/ExtensionParent.sys.mjs"
+);
+
+var tbsyncExtension = ExtensionParent.GlobalManager.getExtension(
+  "tbsync at jobisoft.de"
+);
+var { TbSync } = ChromeUtils.importESModule(
+  `chrome://tbsync/content/tbsync.sys.mjs?${tbsyncExtension.manifest.version}`
+);
+
+var { OverlayManager } = ChromeUtils.importESModule(
+  `chrome://tbsync/content/OverlayManager.sys.mjs?${tbsyncExtension.manifest.version}`
+);
+
+var messenger = {
+
+  overlayManager : null,
+  
+  load: async function () {
+    this.overlayManager = new OverlayManager(TbSync.extension, {verbose: 0});
+    await this.overlayManager.registerOverlay("chrome://messenger/content/messenger.xhtml", "chrome://tbsync/content/overlays/messenger.xhtml");
+    Services.obs.addObserver(this.initSyncObserver, "tbsync.observer.sync", false);
+    Services.obs.addObserver(this.syncstateObserver, "tbsync.observer.manager.updateSyncstate", false);
+
+    //inject overlays
+    this.overlayManager.startObserving();
+
+  },
+
+  unload: async function () {
+    //unload overlays
+    this.overlayManager.stopObserving();
+
+    Services.obs.removeObserver(this.initSyncObserver, "tbsync.observer.sync");
+    Services.obs.removeObserver(this.syncstateObserver, "tbsync.observer.manager.updateSyncstate");
+  },
+
+  // observer to catch changing syncstate and to update the status bar.
+  syncstateObserver: {
+    observe: function (aSubject, aTopic, aData) {
+      //update status bar in all main windows
+      let windows = Services.wm.getEnumerator("mail:3pane");
+      while (windows.hasMoreElements()) {
+        let domWindow = windows.getNext();
+        if (TbSync) {
+          let status = domWindow.document.getElementById("tbsync.status");
+          if (status) {
+            let label = "TbSync: ";
+            
+            if (TbSync.enabled) {
+
+              //check if any account is syncing, if not switch to idle
+              let accounts = TbSync.db.getAccounts();
+              let idle = true;
+              let err = false;
+          
+              for (let i=0; i<accounts.allIDs.length && idle; i++) {
+                if (!accounts.IDs.includes(accounts.allIDs[i])) {
+                  err = true;
+                  continue;
+                }
+          
+                //set idle to false, if at least one account is syncing
+                if (TbSync.core.isSyncing(accounts.allIDs[i])) idle = false;
+            
+                //check for errors
+                switch (TbSync.db.getAccountProperty(accounts.allIDs[i], "status")) {
+                  case "success":
+                  case "disabled":
+                  case "notsyncronized":
+                  case "syncing":
+                    break;
+                  default:
+                    err = true;
+                }
+              }
+
+              if (idle) {
+                if (err) label += TbSync.getString("info.error");   
+                else label += TbSync.getString("info.idle");   
+              } else {
+                label += TbSync.getString("status.syncing");
+              }
+            } else {
+              label += "Loading";
+            }
+            status.value = label;
+          }
+        }
+      }
+    }
+  },
+  
+  // observer to init sync
+  initSyncObserver: {
+    observe: function (aSubject, aTopic, aData) {
+      if (TbSync.enabled) {
+        TbSync.core.syncAllAccounts();
+      } else {
+        //TbSync.manager.popupNotEnabled();
+      }
+    }
+  },    
+}
diff -Nru tbsync-4.12/content/modules/network.js tbsync-4.16/content/modules/network.js
--- tbsync-4.12/content/modules/network.js	2024-08-27 18:32:08.000000000 +0200
+++ tbsync-4.16/content/modules/network.js	2025-03-15 23:49:58.000000000 +0100
@@ -1,114 +1,125 @@
-/*
- * This file is part of TbSync.
- *
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. 
- */
- 
-"use strict";
- 
-var network = {
-
-  load: async function () {
-  },
-
-  unload: async function () {
-  },
-  
-  getContainerIdForUser: function(username) {
-    //define the allowed range of container ids to be used
-    let min = 10000;
-    let max = 19999;
-    
-    //we need to store the container map in the main window, so it is persistent and survives a restart of this bootstrapped addon
-    //TODO: is there a better way to store this container map globally? Can there be TWO main windows?
-    let mainWindow = Services.wm.getMostRecentWindow("mail:3pane");
-
-    //init
-    if (!(mainWindow._containers)) {
-      mainWindow._containers = [];
-    }
-    
-    //reset if adding an entry will exceed allowed range
-    if (mainWindow._containers.length > (max-min) && mainWindow._containers.indexOf(username) == -1) {
-      for (let i=0; i < mainWindow._containers.length; i++) {
-        //Services.clearData.deleteDataFromOriginAttributesPattern({ userContextId: i + min });
-        Services.obs.notifyObservers(null, "clear-origin-attributes-data", JSON.stringify({ userContextId: i + min }));
-      }
-      mainWindow._containers = [];
-    }
-    
-    let idx = mainWindow._containers.indexOf(username);
-    return (idx == -1) ? mainWindow._containers.push(username) - 1 + min : (idx + min);
-  },
-  
-  resetContainerForUser: function(username) {
-    let id = this.getContainerIdForUser(username);
-    Services.obs.notifyObservers(null, "clear-origin-attributes-data", JSON.stringify({ userContextId: id }));
-  },
-
-  createTCPErrorFromFailedXHR: function (xhr) {
-    return this.createTCPErrorFromFailedRequest(xhr.channel.QueryInterface(Components.interfaces.nsIRequest));
-  },
-  
-  createTCPErrorFromFailedRequest: function (request) {
-    //adapted from :
-    //https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/How_to_check_the_secruity_state_of_an_XMLHTTPRequest_over_SSL		
-    //codes: https://developer.mozilla.org/en-US/docs/Mozilla/Errors
-    let status = request.status;
-
-    if ((status & 0xff0000) === 0x5a0000) { // Security module
-      const nsINSSErrorsService = Components.interfaces.nsINSSErrorsService;
-      let nssErrorsService = Components.classes['@mozilla.org/nss_errors_service;1'].getService(nsINSSErrorsService);
-      
-      // NSS_SEC errors (happen below the base value because of negative vals)
-      if ((status & 0xffff) < Math.abs(nsINSSErrorsService.NSS_SEC_ERROR_BASE)) {
-
-        // The bases are actually negative, so in our positive numeric space, we
-        // need to subtract the base off our value.
-        let nssErr = Math.abs(nsINSSErrorsService.NSS_SEC_ERROR_BASE) - (status & 0xffff);
-        switch (nssErr) {
-          case 11: return 'security::SEC_ERROR_EXPIRED_CERTIFICATE';
-          case 12: return 'security::SEC_ERROR_REVOKED_CERTIFICATE';
-          case 13: return 'security::SEC_ERROR_UNKNOWN_ISSUER';
-          case 20: return 'security::SEC_ERROR_UNTRUSTED_ISSUER';
-          case 21: return 'security::SEC_ERROR_UNTRUSTED_CERT';
-          case 36: return 'security::SEC_ERROR_CA_CERT_INVALID';
-          case 90: return 'security::SEC_ERROR_INADEQUATE_KEY_USAGE';
-          case 176: return 'security::SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED';
-        }
-        return 'security::UNKNOWN_SECURITY_ERROR';
-        
-      } else {
-
-        // Calculating the difference 		  
-        let sslErr = Math.abs(nsINSSErrorsService.NSS_SSL_ERROR_BASE) - (status & 0xffff);		
-        switch (sslErr) {
-          case 3: return 'security::SSL_ERROR_NO_CERTIFICATE';
-          case 4: return 'security::SSL_ERROR_BAD_CERTIFICATE';
-          case 8: return 'security::SSL_ERROR_UNSUPPORTED_CERTIFICATE_TYPE';
-          case 9: return 'security::SSL_ERROR_UNSUPPORTED_VERSION';
-          case 12: return 'security::SSL_ERROR_BAD_CERT_DOMAIN';
-        }
-        return 'security::UNKOWN_SSL_ERROR';
-        
-      }
-
-    } else { //not the security module
-      
-      switch (status) {
-        case 0x804B000C: return 'network::NS_ERROR_CONNECTION_REFUSED';
-        case 0x804B000E: return 'network::NS_ERROR_NET_TIMEOUT';
-        case 0x804B001E: return 'network::NS_ERROR_UNKNOWN_HOST';
-        case 0x804B0047: return 'network::NS_ERROR_NET_INTERRUPT';
-        case 0x805303F4: return 'network::NS_ERROR_DOM_BAD_URI';
-        // Custom error
-        case 0x804B002F: return 'network::REJECTED_REDIRECT_FROM_HTTPS_TO_HTTP';
-      }
-      return 'network::UNKNOWN_NETWORK_ERROR';
-
-    }
-    return null;	 
-  },
-}
+/*
+ * This file is part of TbSync.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. 
+ */
+ 
+"use strict";
+ 
+var { ExtensionParent } = ChromeUtils.importESModule(
+  "resource://gre/modules/ExtensionParent.sys.mjs"
+);
+
+var tbsyncExtension = ExtensionParent.GlobalManager.getExtension(
+  "tbsync at jobisoft.de"
+);
+var { TbSync } = ChromeUtils.importESModule(
+  `chrome://tbsync/content/tbsync.sys.mjs?${tbsyncExtension.manifest.version}`
+);
+
+var network = {
+
+  load: async function () {
+  },
+
+  unload: async function () {
+  },
+  
+  getContainerIdForUser: function(username) {
+    //define the allowed range of container ids to be used
+    let min = 10000;
+    let max = 19999;
+    
+    //we need to store the container map in the main window, so it is persistent and survives a restart of this bootstrapped addon
+    //TODO: is there a better way to store this container map globally? Can there be TWO main windows?
+    let mainWindow = Services.wm.getMostRecentWindow("mail:3pane");
+
+    //init
+    if (!(mainWindow._containers)) {
+      mainWindow._containers = [];
+    }
+    
+    //reset if adding an entry will exceed allowed range
+    if (mainWindow._containers.length > (max-min) && mainWindow._containers.indexOf(username) == -1) {
+      for (let i=0; i < mainWindow._containers.length; i++) {
+        //Services.clearData.deleteDataFromOriginAttributesPattern({ userContextId: i + min });
+        Services.obs.notifyObservers(null, "clear-origin-attributes-data", JSON.stringify({ userContextId: i + min }));
+      }
+      mainWindow._containers = [];
+    }
+    
+    let idx = mainWindow._containers.indexOf(username);
+    return (idx == -1) ? mainWindow._containers.push(username) - 1 + min : (idx + min);
+  },
+  
+  resetContainerForUser: function(username) {
+    let id = this.getContainerIdForUser(username);
+    Services.obs.notifyObservers(null, "clear-origin-attributes-data", JSON.stringify({ userContextId: id }));
+  },
+
+  createTCPErrorFromFailedXHR: function (xhr) {
+    return this.createTCPErrorFromFailedRequest(xhr.channel.QueryInterface(Components.interfaces.nsIRequest));
+  },
+  
+  createTCPErrorFromFailedRequest: function (request) {
+    //adapted from :
+    //https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/How_to_check_the_secruity_state_of_an_XMLHTTPRequest_over_SSL		
+    //codes: https://developer.mozilla.org/en-US/docs/Mozilla/Errors
+    let status = request.status;
+
+    if ((status & 0xff0000) === 0x5a0000) { // Security module
+      const nsINSSErrorsService = Components.interfaces.nsINSSErrorsService;
+      let nssErrorsService = Components.classes['@mozilla.org/nss_errors_service;1'].getService(nsINSSErrorsService);
+      
+      // NSS_SEC errors (happen below the base value because of negative vals)
+      if ((status & 0xffff) < Math.abs(nsINSSErrorsService.NSS_SEC_ERROR_BASE)) {
+
+        // The bases are actually negative, so in our positive numeric space, we
+        // need to subtract the base off our value.
+        let nssErr = Math.abs(nsINSSErrorsService.NSS_SEC_ERROR_BASE) - (status & 0xffff);
+        switch (nssErr) {
+          case 11: return 'security::SEC_ERROR_EXPIRED_CERTIFICATE';
+          case 12: return 'security::SEC_ERROR_REVOKED_CERTIFICATE';
+          case 13: return 'security::SEC_ERROR_UNKNOWN_ISSUER';
+          case 20: return 'security::SEC_ERROR_UNTRUSTED_ISSUER';
+          case 21: return 'security::SEC_ERROR_UNTRUSTED_CERT';
+          case 36: return 'security::SEC_ERROR_CA_CERT_INVALID';
+          case 90: return 'security::SEC_ERROR_INADEQUATE_KEY_USAGE';
+          case 176: return 'security::SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED';
+        }
+        return 'security::UNKNOWN_SECURITY_ERROR';
+        
+      } else {
+
+        // Calculating the difference 		  
+        let sslErr = Math.abs(nsINSSErrorsService.NSS_SSL_ERROR_BASE) - (status & 0xffff);		
+        switch (sslErr) {
+          case 3: return 'security::SSL_ERROR_NO_CERTIFICATE';
+          case 4: return 'security::SSL_ERROR_BAD_CERTIFICATE';
+          case 8: return 'security::SSL_ERROR_UNSUPPORTED_CERTIFICATE_TYPE';
+          case 9: return 'security::SSL_ERROR_UNSUPPORTED_VERSION';
+          case 12: return 'security::SSL_ERROR_BAD_CERT_DOMAIN';
+        }
+        return 'security::UNKOWN_SSL_ERROR';
+        
+      }
+
+    } else { //not the security module
+      
+      switch (status) {
+        case 0x804B000C: return 'network::NS_ERROR_CONNECTION_REFUSED';
+        case 0x804B000E: return 'network::NS_ERROR_NET_TIMEOUT';
+        case 0x804B001E: return 'network::NS_ERROR_UNKNOWN_HOST';
+        case 0x804B0047: return 'network::NS_ERROR_NET_INTERRUPT';
+        case 0x805303F4: return 'network::NS_ERROR_DOM_BAD_URI';
+        // Custom error
+        case 0x804B002F: return 'network::REJECTED_REDIRECT_FROM_HTTPS_TO_HTTP';
+      }
+      return 'network::UNKNOWN_NETWORK_ERROR';
+
+    }
+    return null;	 
+  },
+}
diff -Nru tbsync-4.12/content/modules/passwordManager.js tbsync-4.16/content/modules/passwordManager.js
--- tbsync-4.12/content/modules/passwordManager.js	2024-08-27 18:32:08.000000000 +0200
+++ tbsync-4.16/content/modules/passwordManager.js	2025-03-15 23:49:58.000000000 +0100
@@ -1,78 +1,90 @@
-/*
- * This file is part of TbSync.
- *
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. 
- */
-
-"use strict";
-
-var passwordManager = {
-
-  load: async function () {
-  },
-
-  unload: async function () {
-  },
-
-  removeLoginInfos: function(origin, realm, users = null) {
-    let nsLoginInfo = new Components.Constructor("@mozilla.org/login-manager/loginInfo;1", Components.interfaces.nsILoginInfo, "init");
-
-    let logins = Services.logins.findLogins(origin, null, realm);
-    for (let i = 0; i < logins.length; i++) {
-      if (!users || users.includes(logins[i].username)) {
-        let currentLoginInfo = new nsLoginInfo(origin, null, realm, logins[i].username, logins[i].password, "", "");
-        try {
-          Services.logins.removeLogin(currentLoginInfo);
-        } catch (e) {
-          TbSync.dump("Error removing loginInfo", e);
-        }
-      }
-    }
-  },
-
-  updateLoginInfo: async function(origin, realm, oldUser, newUser, newPassword) {
-    let nsLoginInfo = new Components.Constructor("@mozilla.org/login-manager/loginInfo;1", Components.interfaces.nsILoginInfo, "init");
-    
-    this.removeLoginInfos(origin, realm, [oldUser, newUser]);
-    
-    let newLoginInfo = new nsLoginInfo(origin, null, realm, newUser, newPassword, "", "");
-    try {
-      await Services.logins.addLoginAsync(newLoginInfo);
-    } catch (e) {
-      TbSync.dump("Error adding loginInfo", e);
-    }
-  },
-  
-  getLoginInfo: function(origin, realm, user) {
-    let logins = Services.logins.findLogins(origin, null, realm);
-    for (let i = 0; i < logins.length; i++) {
-      if (logins[i].username == user) {
-        return logins[i].password;
-      }
-    }
-    return null;
-  },
-
-  
-  /** data obj
-    windowID
-    accountName
-    userName
-    userNameLocked
-  
-  reference is an object in which an entry with windowID will be placed to hold a reference to the prompt window (so it can be closed externaly)
-  */
-  asyncPasswordPrompt: async function(data, reference) {
-    if (data.windowID) {
-      let url = "chrome://tbsync/content/passwordPrompt/passwordPrompt.xhtml";
-  
-      return await new Promise(function(resolve, reject) {
-       reference[data.windowID] = TbSync.window.openDialog(url, "TbSyncPasswordPrompt:" + data.windowID, "centerscreen,chrome,resizable=no", data, resolve);
-      });
-    }
-    
-    return false;
-  }
-}
+/*
+ * This file is part of TbSync.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. 
+ */
+
+"use strict";
+
+var { ExtensionParent } = ChromeUtils.importESModule(
+  "resource://gre/modules/ExtensionParent.sys.mjs"
+);
+
+var tbsyncExtension = ExtensionParent.GlobalManager.getExtension(
+  "tbsync at jobisoft.de"
+);
+var { TbSync } = ChromeUtils.importESModule(
+  `chrome://tbsync/content/tbsync.sys.mjs?${tbsyncExtension.manifest.version}`
+);
+
+var passwordManager = {
+
+  load: async function () {
+  },
+
+  unload: async function () {
+  },
+
+  removeLoginInfos: function(origin, realm, users = null) {
+    let nsLoginInfo = new Components.Constructor("@mozilla.org/login-manager/loginInfo;1", Components.interfaces.nsILoginInfo, "init");
+
+    let logins = Services.logins.findLogins(origin, null, realm);
+    for (let i = 0; i < logins.length; i++) {
+      if (!users || users.includes(logins[i].username)) {
+        let currentLoginInfo = new nsLoginInfo(origin, null, realm, logins[i].username, logins[i].password, "", "");
+        try {
+          Services.logins.removeLogin(currentLoginInfo);
+        } catch (e) {
+          TbSync.dump("Error removing loginInfo", e);
+        }
+      }
+    }
+  },
+
+  updateLoginInfo: async function(origin, realm, oldUser, newUser, newPassword) {
+    let nsLoginInfo = new Components.Constructor("@mozilla.org/login-manager/loginInfo;1", Components.interfaces.nsILoginInfo, "init");
+    
+    this.removeLoginInfos(origin, realm, [oldUser, newUser]);
+    
+    let newLoginInfo = new nsLoginInfo(origin, null, realm, newUser, newPassword, "", "");
+    try {
+      await Services.logins.addLoginAsync(newLoginInfo);
+    } catch (e) {
+      TbSync.dump("Error adding loginInfo", e);
+    }
+  },
+  
+  getLoginInfo: function(origin, realm, user) {
+    let logins = Services.logins.findLogins(origin, null, realm);
+    for (let i = 0; i < logins.length; i++) {
+      if (logins[i].username == user) {
+        return logins[i].password;
+      }
+    }
+    return null;
+  },
+
+  
+  /** data obj
+    windowID
+    accountName
+    userName
+    userNameLocked
+  
+  reference is an object in which an entry with windowID will be placed to hold a reference to the prompt window (so it can be closed externaly)
+  */
+  asyncPasswordPrompt: async function(data, reference) {
+    if (data.windowID) {
+      const url = "chrome://tbsync/content/passwordPrompt/passwordPrompt.xhtml";
+      const window = Services.wm.getMostRecentWindow("mail:3pane");
+
+      return await new Promise(function(resolve, reject) {
+       reference[data.windowID] = window.openDialog(url, "TbSyncPasswordPrompt:" + data.windowID, "centerscreen,chrome,resizable=no", data, resolve);
+      });
+    }
+    
+    return false;
+  }
+}
diff -Nru tbsync-4.12/content/modules/providers.js tbsync-4.16/content/modules/providers.js
--- tbsync-4.12/content/modules/providers.js	2024-08-27 18:32:08.000000000 +0200
+++ tbsync-4.16/content/modules/providers.js	2025-03-15 23:49:58.000000000 +0100
@@ -1,184 +1,198 @@
-/*
- * This file is part of TbSync.
- *
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. 
- */
- 
-"use strict";
-
-var { AddonManager } = ChromeUtils.import("resource://gre/modules/AddonManager.jsm");
-var { MailServices } = ChromeUtils.import("resource:///modules/MailServices.jsm");
-
-var providers = {
-
-  //list of default providers (available in add menu, even if not installed)
-  defaultProviders: {
-    "google" : {
-      name: "Google's People API", 
-      homepageUrl: "https://addons.thunderbird.net/addon/google-4-tbsync/"},
-    "eas" : {
-      name: "Exchange ActiveSync", 
-      homepageUrl: "https://addons.thunderbird.net/addon/eas-4-tbsync/"},
-  },
-  
-  loadedProviders: null,    
-  
-  load: async function () {
-    this.loadedProviders = {};
-  },
-
-  unload: async function () {
-    for (let provider in this.loadedProviders) {
-      await this.unloadProvider(provider);
-    }
-  },
-
-
-
-  
-  
-  loadProvider:  async function (extension, provider, js) {
-    //only load, if not yet loaded and if the provider name does not shadow a fuction inside provider.js
-    if (!this.loadedProviders.hasOwnProperty(provider) && !this.hasOwnProperty(provider) && js.startsWith("chrome://")) {
-      try {
-        let addon = await AddonManager.getAddonByID(extension.id);
-
-        //load provider subscripts into TbSync
-        this[provider] = {};
-        Services.scriptloader.loadSubScript(js, this[provider], "UTF-8");
-        if (TbSync.apiVersion != this[provider].Base.getApiVersion()) {
-          throw new Error("API version mismatch, TbSync@"+TbSync.apiVersion+" vs " + provider + "@" + this[provider].Base.getApiVersion());
-        }
-        
-        this.loadedProviders[provider] = {
-          addon, extension, 
-          addonId: extension.id, 
-          version: addon.version.toString(),
-          createAccountWindow: null
-        };
-
-        addon.contributorsURL = this[provider].Base.getContributorsUrl();
-
-        // check if provider has its own implementation of folderList
-        if (!this[provider].hasOwnProperty("folderList")) this[provider].folderList = new TbSync.manager.FolderList(provider);
-        
-        //load provider
-        await this[provider].Base.load();
-
-        await TbSync.messenger.overlayManager.registerOverlay("chrome://tbsync/content/manager/editAccount.xhtml?provider=" + provider, this[provider].Base.getEditAccountOverlayUrl());        
-        TbSync.dump("Loaded provider", provider + "::" + this[provider].Base.getProviderName() + " ("+this.loadedProviders[provider].version+")");
-        
-        // reset all accounts of this provider
-        let providerData = new TbSync.ProviderData(provider);
-        let accounts = providerData.getAllAccounts();
-        for (let accountData of accounts) {
-          // reset sync objects
-          TbSync.core.resetSyncDataObj(accountData.accountID);
-          
-          // set all accounts which are syncing to notsyncronized 
-          if (accountData.getAccountProperty("status") == "syncing") accountData.setAccountProperty("status", "notsyncronized");
-
-          // set each folder with PENDING status to ABORTED
-          let folders = TbSync.db.findFolders({"status": "pending"}, {"accountID": accountData.accountID});
-
-          for (let f=0; f < folders.length; f++) {
-            TbSync.db.setFolderProperty(folders[f].accountID, folders[f].folderID, "status", "aborted");
-          }
-        }
-        
-        Services.obs.notifyObservers(null, "tbsync.observer.manager.updateProviderList", provider);
-        Services.obs.notifyObservers(null, "tbsync.observer.manager.updateSyncstate", null);
-
-        // TB60 -> TB68 migration - remove icon and rename target if stale
-        for (let addressBook of MailServices.ab.directories) {
-          if (addressBook instanceof Components.interfaces.nsIAbDirectory) {
-            let storedProvider = TbSync.addressbook.getStringValue(addressBook, "tbSyncProvider", "");
-            if (provider == storedProvider && providerData.getFolders({"target": addressBook.UID}).length == 0) {
-              let name = addressBook.dirName;
-              addressBook.dirName = TbSync.getString("target.orphaned") + ": " + name;              
-              addressBook.setStringValue("tbSyncIcon", "orphaned");
-              addressBook.setStringValue("tbSyncProvider", "orphaned");
-              addressBook.setStringValue("tbSyncAccountID", "");
-            }
-          }
-        }
-        
-        let calManager = TbSync.lightning.cal.manager;
-        for (let calendar of calManager.getCalendars({})) {
-          let storedProvider = calendar.getProperty("tbSyncProvider");
-          if (provider == storedProvider && calendar.type == "storage" && providerData.getFolders({"target": calendar.id}).length == 0) {
-            let name = calendar.name;
-            calendar.name = TbSync.getString("target.orphaned") + ": " + name;
-            calendar.setProperty("disabled", true);
-            calendar.setProperty("tbSyncProvider", "orphaned");
-            calendar.setProperty("tbSyncAccountID", "");        
-          }
-        }
-        
-      } catch (e) {
-        delete this.loadedProviders[provider];
-        delete this[provider];
-        let info = new EventLogInfo(provider);
-        TbSync.eventlog.add("error", info, "FAILED to load provider <"+provider+">", e.message);
-        Components.utils.reportError(e);        
-      }
-
-    }
-  },
-  
-  unloadProvider: async function (provider) {        
-    if (this.loadedProviders.hasOwnProperty(provider)) {
-      TbSync.dump("Unloading provider", provider);
-      
-       if (this.loadedProviders[provider].createAccountWindow) {
-         this.loadedProviders[provider].createAccountWindow.close();
-       }
-
-      await this[provider].Base.unload();
-      delete this.loadedProviders[provider];
-      delete this[provider];            
-      Services.obs.notifyObservers(null, "tbsync.observer.manager.updateProviderList", provider);
-      Services.obs.notifyObservers(null, "tbsync.observer.manager.updateSyncstate", null);
-    }
-  },
-  
-  getDefaultAccountEntries: function (provider) {
-    let defaults = TbSync.providers[provider].Base.getDefaultAccountEntries();
-    
-    // List of default system account properties. 
-    // Do not remove search marker for doc. 
-    // DefaultAccountPropsStart
-    defaults.provider = provider;
-    defaults.accountID = "";
-    defaults.lastsynctime = 0;
-    defaults.status = "disabled";
-    defaults.autosync = 0;
-    defaults.noAutosyncUntil = 0;
-    defaults.accountname = "";
-    // DefaultAccountPropsEnd
-
-    return defaults;
-  },
-  
-  getDefaultFolderEntries: function (accountID) {
-    let provider = TbSync.db.getAccountProperty(accountID, "provider");
-    let defaults = TbSync.providers[provider].Base.getDefaultFolderEntries();
-    
-    // List of default system folder properties.
-    // Do not remove search marker for doc. 
-    // DefaultFolderPropsStart
-    defaults.accountID = accountID;
-    defaults.targetType = "";
-    defaults.cached = false;
-    defaults.selected = false;
-    defaults.lastsynctime = 0;
-    defaults.status = "";
-    defaults.foldername = "";
-    defaults.downloadonly = false;
-    // DefaultFolderPropsEnd
-    
-    return defaults;
-  },
-}
+/*
+ * This file is part of TbSync.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. 
+ */
+ 
+"use strict";
+
+var { AddonManager } = ChromeUtils.importESModule(
+  "resource://gre/modules/AddonManager.sys.mjs"
+);
+var { ExtensionParent } = ChromeUtils.importESModule(
+  "resource://gre/modules/ExtensionParent.sys.mjs"
+);
+var { MailServices } = ChromeUtils.importESModule(
+  "resource:///modules/MailServices.sys.mjs"
+);
+
+var tbsyncExtension = ExtensionParent.GlobalManager.getExtension(
+  "tbsync at jobisoft.de"
+);
+var { TbSync } = ChromeUtils.importESModule(
+  `chrome://tbsync/content/tbsync.sys.mjs?${tbsyncExtension.manifest.version}`
+);
+
+var providers = {
+
+  //list of default providers (available in add menu, even if not installed)
+  defaultProviders: {
+    "google" : {
+      name: "Google's People API", 
+      homepageUrl: "https://addons.thunderbird.net/addon/google-4-tbsync/"},
+    "eas" : {
+      name: "Exchange ActiveSync", 
+      homepageUrl: "https://addons.thunderbird.net/addon/eas-4-tbsync/"},
+  },
+  
+  loadedProviders: null,    
+  
+  load: async function () {
+    this.loadedProviders = {};
+  },
+
+  unload: async function () {
+    for (let provider in this.loadedProviders) {
+      await this.unloadProvider(provider);
+    }
+  },
+
+
+
+  
+  
+  loadProvider:  async function (extension, provider, js) {
+    //only load, if not yet loaded and if the provider name does not shadow a fuction inside provider.js
+    if (!this.loadedProviders.hasOwnProperty(provider) && !this.hasOwnProperty(provider) && js.startsWith("chrome://")) {
+      try {
+        let addon = await AddonManager.getAddonByID(extension.id);
+
+        //load provider subscripts into TbSync
+        this[provider] = {};
+        Services.scriptloader.loadSubScript(js, this[provider], "UTF-8");
+        if (TbSync.apiVersion != this[provider].Base.getApiVersion()) {
+          throw new Error("API version mismatch, TbSync@"+TbSync.apiVersion+" vs " + provider + "@" + this[provider].Base.getApiVersion());
+        }
+        
+        this.loadedProviders[provider] = {
+          addon, extension, 
+          addonId: extension.id, 
+          version: addon.version.toString(),
+          createAccountWindow: null
+        };
+
+        addon.contributorsURL = this[provider].Base.getContributorsUrl();
+
+        // check if provider has its own implementation of folderList
+        if (!this[provider].hasOwnProperty("folderList")) this[provider].folderList = new TbSync.manager.FolderList(provider);
+        
+        //load provider
+        await this[provider].Base.load();
+
+        await TbSync.messenger.overlayManager.registerOverlay("chrome://tbsync/content/manager/editAccount.xhtml?provider=" + provider, this[provider].Base.getEditAccountOverlayUrl());        
+        TbSync.dump("Loaded provider", provider + "::" + this[provider].Base.getProviderName() + " ("+this.loadedProviders[provider].version+")");
+        
+        // reset all accounts of this provider
+        let providerData = new TbSync.ProviderData(provider);
+        let accounts = providerData.getAllAccounts();
+        for (let accountData of accounts) {
+          // reset sync objects
+          TbSync.core.resetSyncDataObj(accountData.accountID);
+          
+          // set all accounts which are syncing to notsyncronized 
+          if (accountData.getAccountProperty("status") == "syncing") accountData.setAccountProperty("status", "notsyncronized");
+
+          // set each folder with PENDING status to ABORTED
+          let folders = TbSync.db.findFolders({"status": "pending"}, {"accountID": accountData.accountID});
+
+          for (let f=0; f < folders.length; f++) {
+            TbSync.db.setFolderProperty(folders[f].accountID, folders[f].folderID, "status", "aborted");
+          }
+        }
+        
+        Services.obs.notifyObservers(null, "tbsync.observer.manager.updateProviderList", provider);
+        Services.obs.notifyObservers(null, "tbsync.observer.manager.updateSyncstate", null);
+
+        // TB60 -> TB68 migration - remove icon and rename target if stale
+        for (let addressBook of MailServices.ab.directories) {
+          if (addressBook instanceof Components.interfaces.nsIAbDirectory) {
+            let storedProvider = TbSync.addressbook.getStringValue(addressBook, "tbSyncProvider", "");
+            if (provider == storedProvider && providerData.getFolders({"target": addressBook.UID}).length == 0) {
+              let name = addressBook.dirName;
+              addressBook.dirName = TbSync.getString("target.orphaned") + ": " + name;              
+              addressBook.setStringValue("tbSyncIcon", "orphaned");
+              addressBook.setStringValue("tbSyncProvider", "orphaned");
+              addressBook.setStringValue("tbSyncAccountID", "");
+            }
+          }
+        }
+        
+        let calManager = TbSync.lightning.cal.manager;
+        for (let calendar of calManager.getCalendars({})) {
+          let storedProvider = calendar.getProperty("tbSyncProvider");
+          if (provider == storedProvider && calendar.type == "storage" && providerData.getFolders({"target": calendar.id}).length == 0) {
+            let name = calendar.name;
+            calendar.name = TbSync.getString("target.orphaned") + ": " + name;
+            calendar.setProperty("disabled", true);
+            calendar.setProperty("tbSyncProvider", "orphaned");
+            calendar.setProperty("tbSyncAccountID", "");        
+          }
+        }
+        
+      } catch (e) {
+        delete this.loadedProviders[provider];
+        delete this[provider];
+        let info = new EventLogInfo(provider);
+        TbSync.eventlog.add("error", info, "FAILED to load provider <"+provider+">", e.message);
+        Components.utils.reportError(e);        
+      }
+
+    }
+  },
+  
+  unloadProvider: async function (provider) {        
+    if (this.loadedProviders.hasOwnProperty(provider)) {
+      TbSync.dump("Unloading provider", provider);
+      
+       if (this.loadedProviders[provider].createAccountWindow) {
+         this.loadedProviders[provider].createAccountWindow.close();
+       }
+
+      await this[provider].Base.unload();
+      delete this.loadedProviders[provider];
+      delete this[provider];            
+      Services.obs.notifyObservers(null, "tbsync.observer.manager.updateProviderList", provider);
+      Services.obs.notifyObservers(null, "tbsync.observer.manager.updateSyncstate", null);
+    }
+  },
+  
+  getDefaultAccountEntries: function (provider) {
+    let defaults = TbSync.providers[provider].Base.getDefaultAccountEntries();
+    
+    // List of default system account properties. 
+    // Do not remove search marker for doc. 
+    // DefaultAccountPropsStart
+    defaults.provider = provider;
+    defaults.accountID = "";
+    defaults.lastsynctime = 0;
+    defaults.status = "disabled";
+    defaults.autosync = 0;
+    defaults.noAutosyncUntil = 0;
+    defaults.accountname = "";
+    // DefaultAccountPropsEnd
+
+    return defaults;
+  },
+  
+  getDefaultFolderEntries: function (accountID) {
+    let provider = TbSync.db.getAccountProperty(accountID, "provider");
+    let defaults = TbSync.providers[provider].Base.getDefaultFolderEntries();
+    
+    // List of default system folder properties.
+    // Do not remove search marker for doc. 
+    // DefaultFolderPropsStart
+    defaults.accountID = accountID;
+    defaults.targetType = "";
+    defaults.cached = false;
+    defaults.selected = false;
+    defaults.lastsynctime = 0;
+    defaults.status = "";
+    defaults.foldername = "";
+    defaults.downloadonly = false;
+    // DefaultFolderPropsEnd
+    
+    return defaults;
+  },
+}
diff -Nru tbsync-4.12/content/modules/public.js tbsync-4.16/content/modules/public.js
--- tbsync-4.12/content/modules/public.js	2024-08-27 18:32:08.000000000 +0200
+++ tbsync-4.16/content/modules/public.js	2025-03-15 23:49:58.000000000 +0100
@@ -1,757 +1,765 @@
-/*
- * This file is part of TbSync.
- *
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. 
- */
- 
-"use strict";
-
-/**
- *
- */
-var StatusData = class {
-  /**
-   * A StatusData instance must be used as return value by 
-   * :class:`Base.syncFolderList` and :class:`Base.syncFolder`.
-   * 
-   * StatusData also defines the possible StatusDataTypes used by the
-   * :ref:`TbSyncEventLog`.
-   *
-   * @param {StatusDataType} type  Status type (see const definitions below)
-   * @param {string} message  ``Optional`` A message, which will be used as
-   *                          sync status. If this is not a success, it will be
-   *                          used also in the :ref:`TbSyncEventLog` as well.
-   * @param {string} details  ``Optional``  If this is not a success, it will
-   *                          be used as description in the
-   *                          :ref:`TbSyncEventLog`.
-   *
-   */
-  constructor(type = "success", message = "", details = "") {
-    this.type = type; //success, info, warning, error
-    this.message = message;
-    this.details = details;
-  }
-  /**
-   * Successfull sync. 
-   */
-  static get SUCCESS() {return "success"};
-  /**
-   * Sync of the entire account will be aborted.
-   */
-  static get ERROR() {return "error"};
-  /**
-   * Sync of this resource will be aborted and continued with next resource.
-   */
-  static get WARNING() {return "warning"};
-  /**
-   * Successfull sync, but message and details
-   * provided will be added to the event log.
-   */
-  static get INFO() {return "info"};
-  /**
-   * Sync of the entire account will be aborted and restarted completely.
-   */
-  static get ACCOUNT_RERUN() {return "account_rerun"}; 
-  /**
-   * Sync of the current folder/resource will be restarted.
-   */
-  static get FOLDER_RERUN() {return "folder_rerun"}; 
-}
-
-
-
-/**
- * ProgressData to manage a ``done`` and a ``todo`` counter. 
- *
- * Each :class:`SyncData` instance has an associated ProgressData instance. See
- * :class:`SyncData.progressData`. The information of that ProgressData
- * instance is used, when the current syncstate is prefixed by ``send.``,
- * ``eval.`` or ``prepare.``. See :class:`SyncData.setSyncState`.
- *
- */
-var ProgressData = class {
-  /**
-   *
-   */
-  constructor() {
-    this._todo = 0;
-    this._done = 0;
-   }
-   
-  /**
-   * Reset ``done`` and ``todo`` counter.
-   *
-   * @param {integer} done  ``Optional`` Set a value for the ``done`` counter.
-   * @param {integer} todo  ``Optional`` Set a value for the ``todo`` counter.
-   *
-   */
-   reset(done = 0, todo = 0) {
-    this._todo = todo;
-    this._done = done;
-   }
-   
-  /**
-   * Increment the ``done`` counter.
-   *
-   * @param {integer} value  ``Optional`` Set incrementation value.
-   *
-   */
-   inc(value = 1) {
-     this._done += value;
-   }
-   
-  /**
-   * Getter for the ``todo`` counter.
-   *
-   */
-   get todo() {
-     return this._todo;
-   }
-   
-  /**
-   * Getter for the ``done`` counter.
-   *
-   */
-   get done() {
-     return this._done;
-   }
-}
-
-
-
-/**
- * ProviderData
- *
- */
-var ProviderData = class {
-  /**
-   * Constructor
-   *
-   * @param {FolderData} folderData    FolderData of the folder for which the
-   *                                   display name is requested.
-   *
-   */
-  constructor(provider) {
-    if (!TbSync.providers.hasOwnProperty(provider)) {
-      throw new Error("Provider <" + provider + "> has not been loaded. Failed to create ProviderData.");
-    }
-    this.provider = provider;
-  }
-  
-  /**
-   * Getter for an :class:`EventLogInfo` instance with all the information
-   * regarding this ProviderData instance.
-   *
-   */
-  get eventLogInfo() {
-    return new EventLogInfo(
-      this.getAccountProperty("provider"));
-  }
-
-  getVersion() {
-    return TbSync.providers.loadedProviders[this.provider].version;
-  }
-  
-  get extension() {
-    return TbSync.providers.loadedProviders[this.provider].extension;
-  }
-  
-  getAllAccounts() {
-    let accounts = TbSync.db.getAccounts();
-    let allAccounts = [];
-    for (let i=0; i<accounts.IDs.length; i++) {
-      let accountID = accounts.IDs[i];
-      if (accounts.data[accountID].provider == this.provider) {
-        allAccounts.push(new TbSync.AccountData(accountID));
-      }
-    }
-    return allAccounts;
-  }
-  
-  getFolders(aFolderSearchCriteria = {}) {
-    let allFolders = [];
-    let folderSearchCriteria = {};
-    Object.assign(folderSearchCriteria, aFolderSearchCriteria);
-    folderSearchCriteria.cached = false;
-    
-    let folders = TbSync.db.findFolders(folderSearchCriteria, {"provider": this.provider});
-    for (let i=0; i < folders.length; i++) {          
-      allFolders.push(new TbSync.FolderData(new TbSync.AccountData(folders[i].accountID), folders[i].folderID));
-    }
-    return allFolders;
-  }
-  
-  getDefaultAccountEntries() {
-    return  TbSync.providers.getDefaultAccountEntries(this.provider)
-  }
-  
-  addAccount(accountName, accountOptions) {
-    let newAccountID = TbSync.db.addAccount(accountName, accountOptions);
-    Services.obs.notifyObservers(null, "tbsync.observer.manager.updateAccountsList", newAccountID);
-    return new TbSync.AccountData(newAccountID);        
-  }
-}
-
-
-
-/**
- * AccountData
- *
- */
-var AccountData = class {
-  /**
-   *
-   */
-  constructor(accountID) {
-    this._accountID = accountID;
-
-    if (!TbSync.db.accounts.data.hasOwnProperty(accountID)) {
-      throw new Error("An account with ID <" + accountID + "> does not exist. Failed to create AccountData.");
-    }
-  }
-
-  /**
-   * Getter for an :class:`EventLogInfo` instance with all the information
-   * regarding this AccountData instance.
-   *
-   */
-  get eventLogInfo() {
-    return new EventLogInfo(
-      this.getAccountProperty("provider"),
-      this.getAccountProperty("accountname"),
-      this.accountID);
-  }
-
-  get accountID() {
-    return this._accountID;
-  }
-  
-  getAllFolders() {
-    let allFolders = [];
-    let folders = TbSync.db.findFolders({"cached": false}, {"accountID": this.accountID});
-    for (let i=0; i < folders.length; i++) {          
-      allFolders.push(new TbSync.FolderData(this, folders[i].folderID));
-    }
-    return allFolders;
-  }
-
-  getAllFoldersIncludingCache() {
-    let allFolders = [];
-    let folders = TbSync.db.findFolders({}, {"accountID": this.accountID});
-    for (let i=0; i < folders.length; i++) {          
-      allFolders.push(new TbSync.FolderData(this, folders[i].folderID));
-    }
-    return allFolders;
-  }
-  
-  getFolder(setting, value) {
-    // ES6 supports variable keys by putting it into brackets
-    let folders = TbSync.db.findFolders({[setting]: value, "cached": false}, {"accountID": this.accountID});
-    if (folders.length > 0) return new TbSync.FolderData(this, folders[0].folderID);
-    return null;
-  }
-
-  getFolderFromCache(setting, value) {
-    // ES6 supports variable keys by putting it into brackets
-    let folders = TbSync.db.findFolders({[setting]: value, "cached": true}, {"accountID": this.accountID});
-    if (folders.length > 0) return new TbSync.FolderData(this, folders[0].folderID);
-    return null;
-  }
-  
-  createNewFolder() {
-    return new TbSync.FolderData(this, TbSync.db.addFolder(this.accountID));
-  }
-  
-  // get data objects
-  get providerData() {
-    return new TbSync.ProviderData(
-      this.getAccountProperty("provider"),
-    );
-  }    
-
-  get syncData() {
-    return TbSync.core.getSyncDataObject(this.accountID);
-  }
-
-
-  /**
-   * Initiate a sync of this entire account by calling
-   * :class:`Base.syncFolderList`. If that succeeded, :class:`Base.syncFolder`
-   * will be called for each available folder / resource found on the server.
-   *
-   * @param {Object} syncDescription  ``Optional``
-   */
-  sync(syncDescription = {}) {
-    TbSync.core.syncAccount(this.accountID, syncDescription);
-  }
-
-  isSyncing() {
-    return TbSync.core.isSyncing(this.accountID);
-  }
-  
-  isEnabled() {
-    return TbSync.core.isEnabled(this.accountID);
-  }
-
-  isConnected() {
-    return TbSync.core.isConnected(this.accountID);
-  }
-  
-
-  getAccountProperty(field) {
-    return TbSync.db.getAccountProperty(this.accountID, field);
-  }
-
-  setAccountProperty(field, value) {
-    TbSync.db.setAccountProperty(this.accountID, field, value);
-    Services.obs.notifyObservers(null, "tbsync.observer.manager.reloadAccountSetting", JSON.stringify({accountID: this.accountID, setting: field}));
-  }
-  
-  resetAccountProperty(field) {
-    TbSync.db.resetAccountProperty(this.accountID, field);
-    Services.obs.notifyObservers(null, "tbsync.observer.manager.reloadAccountSetting", JSON.stringify({accountID: this.accountID, setting: field}));
-  }
-}
-
-
-
-/**
- * FolderData
- *
- */
-var FolderData = class {
-  /**
-   *
-   */
-  constructor(accountData, folderID) {
-    this._accountData = accountData;
-    this._folderID = folderID;
-    this._target = null;
-    
-    if (!TbSync.db.folders[accountData.accountID].hasOwnProperty(folderID)) {
-      throw new Error("A folder with ID <" + folderID + "> does not exist for the given account. Failed to create FolderData.");
-    }
-  }
-  
-  /**
-   * Getter for an :class:`EventLogInfo` instance with all the information 
-   * regarding this FolderData instance.
-   *
-   */
-  get eventLogInfo() {
-    return new EventLogInfo(
-      this.accountData.getAccountProperty("provider"),
-      this.accountData.getAccountProperty("accountname"),
-      this.accountData.accountID,
-      this.getFolderProperty("foldername"),
-    );
-  }
-
-  get folderID() {
-    return this._folderID;
-  }
-
-  get accountID() {
-    return this._accountData.accountID;
-  }
-  
-  getDefaultFolderEntries() { // remove
-    return TbSync.providers.getDefaultFolderEntries(this.accountID);
-  }
-  
-  getFolderProperty(field) {
-    return TbSync.db.getFolderProperty(this.accountID, this.folderID, field);
-  }
-  
-  setFolderProperty(field, value) {
-    TbSync.db.setFolderProperty(this.accountID, this.folderID, field, value);
-  }
-
-  resetFolderProperty(field) {
-    TbSync.db.resetFolderProperty(this.accountID, this.folderID, field);
-  }
-
-  /**
-   * Initiate a sync of this folder only by calling
-   * :class:`Base.syncFolderList` and than :class:`Base.syncFolder` for this
-   * folder / resource only.
-   *
-   * @param {Object} syncDescription  ``Optional``
-   */
-  sync(aSyncDescription = {}) {
-    let syncDescription = {};
-    Object.assign(syncDescription, aSyncDescription);
-
-    syncDescription.syncFolders = [this];
-    this.accountData.sync(syncDescription);
-  }
-  
-  isSyncing() {
-    let syncdata = this.accountData.syncData;
-    return (syncdata.currentFolderData && syncdata.currentFolderData.folderID == this.folderID);
-  }
-    
-  getFolderStatus() {
-    let status = "";
-    
-    if (this.getFolderProperty("selected")) {
-      //default
-      status = TbSync.getString("status." + this.getFolderProperty("status"), this.accountData.getAccountProperty("provider")).split("||")[0];
-
-      switch (this.getFolderProperty("status").split(".")[0]) { //the status may have a sub-decleration
-        case "modified":
-          //trigger periodic sync (TbSync.syncTimer, tbsync.jsm)
-          if (!this.isSyncing()) {
-            this.accountData.setAccountProperty("lastsynctime", 0);
-          }
-        case "success":
-          try {
-            status = status + ": " + this.targetData.targetName;
-          } catch (e) {
-            this.resetFolderProperty("target");
-            this.setFolderProperty("status","notsyncronized");
-            return TbSync.getString("status.notsyncronized");
-          }
-          break;
-          
-        case "pending":
-          //add extra info if this folder is beeing synced
-          if (this.isSyncing()) {
-            let syncdata = this.accountData.syncData;
-            status = TbSync.getString("status.syncing", this.accountData.getAccountProperty("provider"));
-            if (["send","eval","prepare"].includes(syncdata.getSyncState().state.split(".")[0]) && (syncdata.progressData.todo + syncdata.progressData.done) > 0) {
-              //add progress information
-              status = status + " (" + syncdata.progressData.done + (syncdata.progressData.todo > 0 ? "/" + syncdata.progressData.todo : "") + ")"; 
-            }
-          }
-          break;            
-      }
-    } else {
-      //remain empty if not selected
-    }        
-    return status;
-  }
-  
-  // get data objects
-  get accountData() {
-    return this._accountData;
-  }
-
-  /**
-   * Getter for the :class:`TargetData` instance associated with this
-   * FolderData. See :ref:`TbSyncTargets` for more details.
-   *
-   * @returns {TargetData}
-   *
-   */
-  get targetData() {
-    // targetData is created on demand
-    if (!this._target) {
-      let provider = this.accountData.getAccountProperty("provider");
-      let targetType = this.getFolderProperty("targetType");
-      
-      if (!targetType)
-        throw new Error("Provider <"+provider+"> has not set a proper target type for this folder.");
-      
-      if (!TbSync.providers[provider].hasOwnProperty("TargetData_" + targetType))
-        throw new Error("Provider <"+provider+"> is missing a TargetData implementation for <"+targetType+">.");
-      
-      this._target = new TbSync.providers[provider]["TargetData_" + targetType](this);
-      
-      if (!this._target)
-        throw new Error("notargets");
-    }
-    
-    return this._target;
-  }
-  
-  // Removes the folder and its target. If the target should be 
-  // kept  as a stale/unconnected item, provide a suffix, which
-  // will be added to its name, to indicate, that it is no longer
-  // managed by TbSync.
-  remove(keepStaleTargetSuffix = "") {
-    // hasTarget() can throw an error, ignore that here
-    try {
-      if (this.targetData.hasTarget()) {
-        if (keepStaleTargetSuffix) {
-          let oldName =  this.targetData.targetName;
-          this.targetData.targetName = TbSync.getString("target.orphaned") + ": " + oldName + " " + keepStaleTargetSuffix;
-          this.targetData.disconnectTarget();
-        } else {
-          this.targetData.removeTarget();
-        }
-      }
-    } catch (e) {
-        Components.utils.reportError(e);
-    }
-    this.setFolderProperty("cached", true);
-  }
-}
-
-
-
-/**
- * There is only one SyncData instance per account which contains all
- * relevant information regarding an ongoing sync. 
- *
- */
-var SyncData = class {
-  /**
-   *
-   */
-  constructor(accountID) {
-    
-    //internal (private, not to be touched by provider)
-    this._syncstate = {
-      state: "accountdone",
-      timestamp: Date.now(),
-    }
-    this._accountData = new TbSync.AccountData(accountID);
-    this._progressData = new TbSync.ProgressData();
-    this._currentFolderData = null;
-  }
-
-  //all functions provider should use should be in here
-  //providers should not modify properties directly
-  //when getSyncDataObj is used never change the folder id as a sync may be going on!
-
-  _setCurrentFolderData(folderData) {
-    this._currentFolderData = folderData;
-  }
-  _clearCurrentFolderData() {
-    this._currentFolderData = null;
-  }
-
-  /**
-   * Getter for an :class:`EventLogInfo` instance with all the information
-   * regarding this SyncData instance.
-   *
-   */  
-  get eventLogInfo() {
-    return new EventLogInfo(
-      this.accountData.getAccountProperty("provider"),
-      this.accountData.getAccountProperty("accountname"),
-      this.accountData.accountID,
-      this.currentFolderData ? this.currentFolderData.getFolderProperty("foldername") : "",
-    );
-  }
-  
-  /**
-   * Getter for the :class:`FolderData` instance of the folder being currently
-   * synced. Can be ``null`` if no folder is being synced.
-   *
-   */  
-  get currentFolderData() {
-    return this._currentFolderData;
-  }
-
-  /**
-   * Getter for the :class:`AccountData` instance of the account being
-   * currently synced.
-   *
-   */  
-  get accountData() {
-    return this._accountData;
-  }
-
-  /**
-   * Getter for the :class:`ProgressData` instance of the ongoing sync.
-   *
-   */
-  get progressData() {
-    return this._progressData;
-  }
-
-  /**
-   * Sets the syncstate of the ongoing sync, to provide feedback to the user.
-   * The selected state can trigger special UI features, if it starts with one
-   * of the following prefixes:
-   *
-   *   * ``send.``, ``eval.``, ``prepare.`` :
-   *     The status message in the UI will be appended with the current progress
-   *     stored in the :class:`ProgressData` associated with this SyncData
-   *     instance. See :class:`SyncData.progressData`. 
-   * 
-   *   * ``send.`` : 
-   *     The status message in the UI will be appended by a timeout countdown
-   *     with the timeout being defined by :class:`Base.getConnectionTimeout`.
-   *
-   * @param {string} state      A short syncstate identifier. The actual
-   *                            message to be displayed in the UI will be
-   *                            looked up in the locales of the provider
-   *                            by looking for ``syncstate.<state>``. 
-   *                            The lookup is done via :func:`getString`,
-   *                            so the same fallback rules apply. 
-   *
-   */  
-  setSyncState(state) {
-    //set new syncstate
-    let msg = "State: " + state + ", Account: " + this.accountData.getAccountProperty("accountname");
-    if (this.currentFolderData) msg += ", Folder: " + this.currentFolderData.getFolderProperty("foldername");
-
-    let syncstate = {};
-    syncstate.state = state;
-    syncstate.timestamp = Date.now();
-
-    this._syncstate = syncstate;
-    TbSync.dump("setSyncState", msg);
-
-    Services.obs.notifyObservers(null, "tbsync.observer.manager.updateSyncstate", this.accountData.accountID);
-  }
-  
-  /**
-   * Gets the current syncstate and its timestamp of the ongoing sync. The
-   * returned Object has the following attributes:
-   *
-   *   * ``state`` : the current syncstate
-   *   * ``timestamp`` : its timestamp
-   *
-   * @returns {Object}  The syncstate and its timestamp.
-   *
-   */
-  getSyncState() {
-    return this._syncstate;
-  }
-}
-
-
-
-
-
-
-
-
-
-
-// Simple dumper, who can dump to file or console
-// It is suggested to use the event log instead of dumping directly.
-var dump = function (what, aMessage) {
-  if (TbSync.prefs.getBoolPref("log.toconsole")) {
-    Services.console.logStringMessage("[TbSync] " + what + " : " + aMessage);
-  }
-  
-  if (TbSync.prefs.getIntPref("log.userdatalevel") > 0) {
-    let now = new Date();
-    TbSync.io.appendToFile("debug.log", "** " + now.toString() + " **\n[" + what + "] : " + aMessage + "\n\n");
-  }
-}
-  
-
-
-/**
- * Get a localized string.
- *
- * TODO: Explain placeholder and :: notation.
- *
- * @param {string} key       The key of the message to look up
- * @param {string} provider  ``Optional`` The provider the key belongs to.
- *
- * @returns {string} The message belonging to the key of the specified provider.
- *                   If that key is not found in the in the specified provider
- *                   or if no provider has been specified, the messages of
- *                   TbSync itself we be used as fallback. If the key could not
- *                   be found there as well, the key itself is returned.
- *
- */
-var getString = function (key, provider) {
-  let localized = null;
-  
-  //spezial treatment of strings with :: like status.httperror::403
-  let parts = key.split("::");
-
-  // if a provider is given, try to get the string from the provider  
-  if (provider && TbSync.providers.loadedProviders.hasOwnProperty(provider)) {
-    let localeData = TbSync.providers.loadedProviders[provider].extension.localeData;
-    if (localeData.messages.get(localeData.selectedLocale).has(parts[0].toLowerCase())) {
-      localized = TbSync.providers.loadedProviders[provider].extension.localeData.localizeMessage(parts[0]);
-    }
-  }
-
-  // if we did not yet succeed, check the locales of tbsync itself
-  if (!localized) {
-    localized = TbSync.extension.localeData.localizeMessage(parts[0]);
-  }
-  
-  if (!localized) {
-    localized = key;
-  } else {
-    //replace placeholders in returned string
-    for (let i = 0; i<parts.length; i++) {
-      let regex = new RegExp( "##replace\."+i+"##", "g");
-      localized = localized.replace(regex, parts[i]);
-    }
-  }
-
-  return localized;
-}
-
-
-var localizeNow = function (window, provider) {
-  let document = window.document;
-  let keyPrefix = "__" + (provider ? provider.toUpperCase() + "4" : "") + "TBSYNCMSG_";
-  
-  let localization = {
-    i18n: null,
-    
-    updateString(string) {
-      let re = new RegExp(keyPrefix + "(.+?)__", "g");
-      return string.replace(re, matched => {
-        const key = matched.slice(keyPrefix.length, -2);
-        return TbSync.getString(key, provider) || matched;
-      });
-    },
-    
-    updateDocument(node) {
-      const texts = document.evaluate(
-        'descendant::text()[contains(self::text(), "' + keyPrefix + '")]',
-        node,
-        null,
-        XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,
-        null
-      );
-      for (let i = 0, maxi = texts.snapshotLength; i < maxi; i++) {
-        const text = texts.snapshotItem(i);
-        if (text.nodeValue.includes(keyPrefix)) text.nodeValue = this.updateString(text.nodeValue);
-      }
-      
-      const attributes = document.evaluate(
-        'descendant::*/attribute::*[contains(., "' + keyPrefix + '")]',
-        node,
-        null,
-        XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,
-        null
-      );
-      for (let i = 0, maxi = attributes.snapshotLength; i < maxi; i++) {
-        const attribute = attributes.snapshotItem(i);
-        if (attribute.value.includes(keyPrefix)) attribute.value = this.updateString(attribute.value);
-      }
-    }		
-  };
-
-  localization.updateDocument(document);
-}
-
-var localizeOnLoad = function (window, provider) {
-  // standard event if loaded by a standard window
-  window.document.addEventListener('DOMContentLoaded', () => {
-    this.localizeNow(window, provider);
-  }, { once: true });
-
-  // custom event, fired by the overlay loader after it has finished loading
-    // the editAccount dialog is never called as a provider, but from tbsync itself
-  let eventId = "DOMOverlayLoaded_"
-      + (!provider || window.location.href.startsWith("chrome://tbsync/content/manager/editAccount.") ? "" : provider + "4")
-      + "tbsync at jobisoft.de";
-  window.document.addEventListener(eventId, () => {
-    TbSync.localizeNow(window, provider);
-  }, { once: true });
-}
-
-
-
-var generateUUID = function () {
-  const uuidGenerator  = Cc["@mozilla.org/uuid-generator;1"].getService(Ci.nsIUUIDGenerator);
-  return uuidGenerator.generateUUID().toString().replace(/[{}]/g, '');
-}
+/*
+ * This file is part of TbSync.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. 
+ */
+ 
+"use strict";
+
+var { ExtensionParent } = ChromeUtils.importESModule(
+  "resource://gre/modules/ExtensionParent.sys.mjs"
+);
+
+var tbsyncExtension = ExtensionParent.GlobalManager.getExtension(
+  "tbsync at jobisoft.de"
+);
+var { TbSync } = ChromeUtils.importESModule(
+  `chrome://tbsync/content/tbsync.sys.mjs?${tbsyncExtension.manifest.version}`
+);
+
+/**
+ *
+ */
+var StatusData = class {
+  /**
+   * A StatusData instance must be used as return value by 
+   * :class:`Base.syncFolderList` and :class:`Base.syncFolder`.
+   * 
+   * StatusData also defines the possible StatusDataTypes used by the
+   * :ref:`TbSyncEventLog`.
+   *
+   * @param {StatusDataType} type  Status type (see const definitions below)
+   * @param {string} message  ``Optional`` A message, which will be used as
+   *                          sync status. If this is not a success, it will be
+   *                          used also in the :ref:`TbSyncEventLog` as well.
+   * @param {string} details  ``Optional``  If this is not a success, it will
+   *                          be used as description in the
+   *                          :ref:`TbSyncEventLog`.
+   *
+   */
+  constructor(type = "success", message = "", details = "") {
+    this.type = type; //success, info, warning, error
+    this.message = message;
+    this.details = details;
+  }
+  /**
+   * Successfull sync. 
+   */
+  static get SUCCESS() {return "success"};
+  /**
+   * Sync of the entire account will be aborted.
+   */
+  static get ERROR() {return "error"};
+  /**
+   * Sync of this resource will be aborted and continued with next resource.
+   */
+  static get WARNING() {return "warning"};
+  /**
+   * Successfull sync, but message and details
+   * provided will be added to the event log.
+   */
+  static get INFO() {return "info"};
+  /**
+   * Sync of the entire account will be aborted and restarted completely.
+   */
+  static get ACCOUNT_RERUN() {return "account_rerun"}; 
+  /**
+   * Sync of the current folder/resource will be restarted.
+   */
+  static get FOLDER_RERUN() {return "folder_rerun"}; 
+}
+
+/**
+ * ProgressData to manage a ``done`` and a ``todo`` counter. 
+ *
+ * Each :class:`SyncData` instance has an associated ProgressData instance. See
+ * :class:`SyncData.progressData`. The information of that ProgressData
+ * instance is used, when the current syncstate is prefixed by ``send.``,
+ * ``eval.`` or ``prepare.``. See :class:`SyncData.setSyncState`.
+ *
+ */
+
+var ProgressData = class {
+  /**
+   *
+   */
+  constructor() {
+    this._todo = 0;
+    this._done = 0;
+   }
+   
+  /**
+   * Reset ``done`` and ``todo`` counter.
+   *
+   * @param {integer} done  ``Optional`` Set a value for the ``done`` counter.
+   * @param {integer} todo  ``Optional`` Set a value for the ``todo`` counter.
+   *
+   */
+   reset(done = 0, todo = 0) {
+    this._todo = todo;
+    this._done = done;
+   }
+   
+  /**
+   * Increment the ``done`` counter.
+   *
+   * @param {integer} value  ``Optional`` Set incrementation value.
+   *
+   */
+   inc(value = 1) {
+     this._done += value;
+   }
+   
+  /**
+   * Getter for the ``todo`` counter.
+   *
+   */
+   get todo() {
+     return this._todo;
+   }
+   
+  /**
+   * Getter for the ``done`` counter.
+   *
+   */
+   get done() {
+     return this._done;
+   }
+}
+
+/**
+ * ProviderData
+ *
+ */
+var ProviderData = class {
+  /**
+   * Constructor
+   *
+   * @param {FolderData} folderData    FolderData of the folder for which the
+   *                                   display name is requested.
+   *
+   */
+  constructor(provider) {
+    if (!TbSync.providers.hasOwnProperty(provider)) {
+      throw new Error("Provider <" + provider + "> has not been loaded. Failed to create ProviderData.");
+    }
+    this.provider = provider;
+  }
+  
+  /**
+   * Getter for an :class:`EventLogInfo` instance with all the information
+   * regarding this ProviderData instance.
+   *
+   */
+  get eventLogInfo() {
+    return new EventLogInfo(
+      this.getAccountProperty("provider"));
+  }
+
+  getVersion() {
+    return TbSync.providers.loadedProviders[this.provider].version;
+  }
+  
+  get extension() {
+    return TbSync.providers.loadedProviders[this.provider].extension;
+  }
+  
+  getAllAccounts() {
+    let accounts = TbSync.db.getAccounts();
+    let allAccounts = [];
+    for (let i=0; i<accounts.IDs.length; i++) {
+      let accountID = accounts.IDs[i];
+      if (accounts.data[accountID].provider == this.provider) {
+        allAccounts.push(new TbSync.AccountData(accountID));
+      }
+    }
+    return allAccounts;
+  }
+  
+  getFolders(aFolderSearchCriteria = {}) {
+    let allFolders = [];
+    let folderSearchCriteria = {};
+    Object.assign(folderSearchCriteria, aFolderSearchCriteria);
+    folderSearchCriteria.cached = false;
+    
+    let folders = TbSync.db.findFolders(folderSearchCriteria, {"provider": this.provider});
+    for (let i=0; i < folders.length; i++) {          
+      allFolders.push(new TbSync.FolderData(new TbSync.AccountData(folders[i].accountID), folders[i].folderID));
+    }
+    return allFolders;
+  }
+  
+  getDefaultAccountEntries() {
+    return  TbSync.providers.getDefaultAccountEntries(this.provider)
+  }
+  
+  addAccount(accountName, accountOptions) {
+    let newAccountID = TbSync.db.addAccount(accountName, accountOptions);
+    Services.obs.notifyObservers(null, "tbsync.observer.manager.updateAccountsList", newAccountID);
+    return new TbSync.AccountData(newAccountID);        
+  }
+}
+
+
+
+/**
+ * AccountData
+ *
+ */
+var AccountData = class {
+  /**
+   *
+   */
+  constructor(accountID) {
+    this._accountID = accountID;
+
+    if (!TbSync.db.accounts.data.hasOwnProperty(accountID)) {
+      throw new Error("An account with ID <" + accountID + "> does not exist. Failed to create AccountData.");
+    }
+  }
+
+  /**
+   * Getter for an :class:`EventLogInfo` instance with all the information
+   * regarding this AccountData instance.
+   *
+   */
+  get eventLogInfo() {
+    return new EventLogInfo(
+      this.getAccountProperty("provider"),
+      this.getAccountProperty("accountname"),
+      this.accountID);
+  }
+
+  get accountID() {
+    return this._accountID;
+  }
+  
+  getAllFolders() {
+    let allFolders = [];
+    let folders = TbSync.db.findFolders({"cached": false}, {"accountID": this.accountID});
+    for (let i=0; i < folders.length; i++) {          
+      allFolders.push(new TbSync.FolderData(this, folders[i].folderID));
+    }
+    return allFolders;
+  }
+
+  getAllFoldersIncludingCache() {
+    let allFolders = [];
+    let folders = TbSync.db.findFolders({}, {"accountID": this.accountID});
+    for (let i=0; i < folders.length; i++) {          
+      allFolders.push(new TbSync.FolderData(this, folders[i].folderID));
+    }
+    return allFolders;
+  }
+  
+  getFolder(setting, value) {
+    // ES6 supports variable keys by putting it into brackets
+    let folders = TbSync.db.findFolders({[setting]: value, "cached": false}, {"accountID": this.accountID});
+    if (folders.length > 0) return new TbSync.FolderData(this, folders[0].folderID);
+    return null;
+  }
+
+  getFolderFromCache(setting, value) {
+    // ES6 supports variable keys by putting it into brackets
+    let folders = TbSync.db.findFolders({[setting]: value, "cached": true}, {"accountID": this.accountID});
+    if (folders.length > 0) return new TbSync.FolderData(this, folders[0].folderID);
+    return null;
+  }
+  
+  createNewFolder() {
+    return new TbSync.FolderData(this, TbSync.db.addFolder(this.accountID));
+  }
+  
+  // get data objects
+  get providerData() {
+    return new TbSync.ProviderData(
+      this.getAccountProperty("provider"),
+    );
+  }    
+
+  get syncData() {
+    return TbSync.core.getSyncDataObject(this.accountID);
+  }
+
+
+  /**
+   * Initiate a sync of this entire account by calling
+   * :class:`Base.syncFolderList`. If that succeeded, :class:`Base.syncFolder`
+   * will be called for each available folder / resource found on the server.
+   *
+   * @param {Object} syncDescription  ``Optional``
+   */
+  sync(syncDescription = {}) {
+    TbSync.core.syncAccount(this.accountID, syncDescription);
+  }
+
+  isSyncing() {
+    return TbSync.core.isSyncing(this.accountID);
+  }
+  
+  isEnabled() {
+    return TbSync.core.isEnabled(this.accountID);
+  }
+
+  isConnected() {
+    return TbSync.core.isConnected(this.accountID);
+  }
+  
+
+  getAccountProperty(field) {
+    return TbSync.db.getAccountProperty(this.accountID, field);
+  }
+
+  setAccountProperty(field, value) {
+    TbSync.db.setAccountProperty(this.accountID, field, value);
+    Services.obs.notifyObservers(null, "tbsync.observer.manager.reloadAccountSetting", JSON.stringify({accountID: this.accountID, setting: field}));
+  }
+  
+  resetAccountProperty(field) {
+    TbSync.db.resetAccountProperty(this.accountID, field);
+    Services.obs.notifyObservers(null, "tbsync.observer.manager.reloadAccountSetting", JSON.stringify({accountID: this.accountID, setting: field}));
+  }
+}
+
+
+
+/**
+ * FolderData
+ *
+ */
+var FolderData = class {
+  /**
+   *
+   */
+  constructor(accountData, folderID) {
+    this._accountData = accountData;
+    this._folderID = folderID;
+    this._target = null;
+    
+    if (!TbSync.db.folders[accountData.accountID].hasOwnProperty(folderID)) {
+      throw new Error("A folder with ID <" + folderID + "> does not exist for the given account. Failed to create FolderData.");
+    }
+  }
+  
+  /**
+   * Getter for an :class:`EventLogInfo` instance with all the information 
+   * regarding this FolderData instance.
+   *
+   */
+  get eventLogInfo() {
+    return new EventLogInfo(
+      this.accountData.getAccountProperty("provider"),
+      this.accountData.getAccountProperty("accountname"),
+      this.accountData.accountID,
+      this.getFolderProperty("foldername"),
+    );
+  }
+
+  get folderID() {
+    return this._folderID;
+  }
+
+  get accountID() {
+    return this._accountData.accountID;
+  }
+  
+  getDefaultFolderEntries() { // remove
+    return TbSync.providers.getDefaultFolderEntries(this.accountID);
+  }
+  
+  getFolderProperty(field) {
+    return TbSync.db.getFolderProperty(this.accountID, this.folderID, field);
+  }
+  
+  setFolderProperty(field, value) {
+    TbSync.db.setFolderProperty(this.accountID, this.folderID, field, value);
+  }
+
+  resetFolderProperty(field) {
+    TbSync.db.resetFolderProperty(this.accountID, this.folderID, field);
+  }
+
+  /**
+   * Initiate a sync of this folder only by calling
+   * :class:`Base.syncFolderList` and than :class:`Base.syncFolder` for this
+   * folder / resource only.
+   *
+   * @param {Object} syncDescription  ``Optional``
+   */
+  sync(aSyncDescription = {}) {
+    let syncDescription = {};
+    Object.assign(syncDescription, aSyncDescription);
+
+    syncDescription.syncFolders = [this];
+    this.accountData.sync(syncDescription);
+  }
+  
+  isSyncing() {
+    let syncdata = this.accountData.syncData;
+    return (syncdata.currentFolderData && syncdata.currentFolderData.folderID == this.folderID);
+  }
+    
+  getFolderStatus() {
+    let status = "";
+    
+    if (this.getFolderProperty("selected")) {
+      //default
+      status = TbSync.getString("status." + this.getFolderProperty("status"), this.accountData.getAccountProperty("provider")).split("||")[0];
+
+      switch (this.getFolderProperty("status").split(".")[0]) { //the status may have a sub-decleration
+        case "modified":
+          //trigger periodic sync (TbSync.syncTimer, tbsync.sys.mjs)
+          if (!this.isSyncing()) {
+            this.accountData.setAccountProperty("lastsynctime", 0);
+          }
+        case "success":
+          try {
+            status = status + ": " + this.targetData.targetName;
+          } catch (e) {
+            this.resetFolderProperty("target");
+            this.setFolderProperty("status","notsyncronized");
+            return TbSync.getString("status.notsyncronized");
+          }
+          break;
+          
+        case "pending":
+          //add extra info if this folder is beeing synced
+          if (this.isSyncing()) {
+            let syncdata = this.accountData.syncData;
+            status = TbSync.getString("status.syncing", this.accountData.getAccountProperty("provider"));
+            if (["send","eval","prepare"].includes(syncdata.getSyncState().state.split(".")[0]) && (syncdata.progressData.todo + syncdata.progressData.done) > 0) {
+              //add progress information
+              status = status + " (" + syncdata.progressData.done + (syncdata.progressData.todo > 0 ? "/" + syncdata.progressData.todo : "") + ")"; 
+            }
+          }
+          break;            
+      }
+    } else {
+      //remain empty if not selected
+    }        
+    return status;
+  }
+  
+  // get data objects
+  get accountData() {
+    return this._accountData;
+  }
+
+  /**
+   * Getter for the :class:`TargetData` instance associated with this
+   * FolderData. See :ref:`TbSyncTargets` for more details.
+   *
+   * @returns {TargetData}
+   *
+   */
+  get targetData() {
+    // targetData is created on demand
+    if (!this._target) {
+      let provider = this.accountData.getAccountProperty("provider");
+      let targetType = this.getFolderProperty("targetType");
+      
+      if (!targetType)
+        throw new Error("Provider <"+provider+"> has not set a proper target type for this folder.");
+      
+      if (!TbSync.providers[provider].hasOwnProperty("TargetData_" + targetType))
+        throw new Error("Provider <"+provider+"> is missing a TargetData implementation for <"+targetType+">.");
+      
+      this._target = new TbSync.providers[provider]["TargetData_" + targetType](this);
+      
+      if (!this._target)
+        throw new Error("notargets");
+    }
+    
+    return this._target;
+  }
+  
+  // Removes the folder and its target. If the target should be 
+  // kept  as a stale/unconnected item, provide a suffix, which
+  // will be added to its name, to indicate, that it is no longer
+  // managed by TbSync.
+  remove(keepStaleTargetSuffix = "") {
+    // hasTarget() can throw an error, ignore that here
+    try {
+      if (this.targetData.hasTarget()) {
+        if (keepStaleTargetSuffix) {
+          let oldName =  this.targetData.targetName;
+          this.targetData.targetName = TbSync.getString("target.orphaned") + ": " + oldName + " " + keepStaleTargetSuffix;
+          this.targetData.disconnectTarget();
+        } else {
+          this.targetData.removeTarget();
+        }
+      }
+    } catch (e) {
+        Components.utils.reportError(e);
+    }
+    this.setFolderProperty("cached", true);
+  }
+}
+
+
+
+/**
+ * There is only one SyncData instance per account which contains all
+ * relevant information regarding an ongoing sync. 
+ *
+ */
+var SyncData = class {
+  /**
+   *
+   */
+  constructor(accountID) {
+    
+    //internal (private, not to be touched by provider)
+    this._syncstate = {
+      state: "accountdone",
+      timestamp: Date.now(),
+    }
+    this._accountData = new TbSync.AccountData(accountID);
+    this._progressData = new TbSync.ProgressData();
+    this._currentFolderData = null;
+  }
+
+  //all functions provider should use should be in here
+  //providers should not modify properties directly
+  //when getSyncDataObj is used never change the folder id as a sync may be going on!
+
+  _setCurrentFolderData(folderData) {
+    this._currentFolderData = folderData;
+  }
+  _clearCurrentFolderData() {
+    this._currentFolderData = null;
+  }
+
+  /**
+   * Getter for an :class:`EventLogInfo` instance with all the information
+   * regarding this SyncData instance.
+   *
+   */  
+  get eventLogInfo() {
+    return new EventLogInfo(
+      this.accountData.getAccountProperty("provider"),
+      this.accountData.getAccountProperty("accountname"),
+      this.accountData.accountID,
+      this.currentFolderData ? this.currentFolderData.getFolderProperty("foldername") : "",
+    );
+  }
+  
+  /**
+   * Getter for the :class:`FolderData` instance of the folder being currently
+   * synced. Can be ``null`` if no folder is being synced.
+   *
+   */  
+  get currentFolderData() {
+    return this._currentFolderData;
+  }
+
+  /**
+   * Getter for the :class:`AccountData` instance of the account being
+   * currently synced.
+   *
+   */  
+  get accountData() {
+    return this._accountData;
+  }
+
+  /**
+   * Getter for the :class:`ProgressData` instance of the ongoing sync.
+   *
+   */
+  get progressData() {
+    return this._progressData;
+  }
+
+  /**
+   * Sets the syncstate of the ongoing sync, to provide feedback to the user.
+   * The selected state can trigger special UI features, if it starts with one
+   * of the following prefixes:
+   *
+   *   * ``send.``, ``eval.``, ``prepare.`` :
+   *     The status message in the UI will be appended with the current progress
+   *     stored in the :class:`ProgressData` associated with this SyncData
+   *     instance. See :class:`SyncData.progressData`. 
+   * 
+   *   * ``send.`` : 
+   *     The status message in the UI will be appended by a timeout countdown
+   *     with the timeout being defined by :class:`Base.getConnectionTimeout`.
+   *
+   * @param {string} state      A short syncstate identifier. The actual
+   *                            message to be displayed in the UI will be
+   *                            looked up in the locales of the provider
+   *                            by looking for ``syncstate.<state>``. 
+   *                            The lookup is done via :func:`getString`,
+   *                            so the same fallback rules apply. 
+   *
+   */  
+  setSyncState(state) {
+    //set new syncstate
+    let msg = "State: " + state + ", Account: " + this.accountData.getAccountProperty("accountname");
+    if (this.currentFolderData) msg += ", Folder: " + this.currentFolderData.getFolderProperty("foldername");
+
+    let syncstate = {};
+    syncstate.state = state;
+    syncstate.timestamp = Date.now();
+
+    this._syncstate = syncstate;
+    TbSync.dump("setSyncState", msg);
+
+    Services.obs.notifyObservers(null, "tbsync.observer.manager.updateSyncstate", this.accountData.accountID);
+  }
+  
+  /**
+   * Gets the current syncstate and its timestamp of the ongoing sync. The
+   * returned Object has the following attributes:
+   *
+   *   * ``state`` : the current syncstate
+   *   * ``timestamp`` : its timestamp
+   *
+   * @returns {Object}  The syncstate and its timestamp.
+   *
+   */
+  getSyncState() {
+    return this._syncstate;
+  }
+}
+
+
+
+
+
+
+
+
+
+
+// Simple dumper, who can dump to file or console
+// It is suggested to use the event log instead of dumping directly.
+var dump = function (what, aMessage) {
+  if (TbSync.prefs.getBoolPref("log.toconsole")) {
+    Services.console.logStringMessage("[TbSync] " + what + " : " + aMessage);
+  }
+  
+  if (TbSync.prefs.getIntPref("log.userdatalevel") > 0) {
+    let now = new Date();
+    TbSync.io.appendToFile("debug.log", "** " + now.toString() + " **\n[" + what + "] : " + aMessage + "\n\n");
+  }
+}
+  
+
+
+/**
+ * Get a localized string.
+ *
+ * TODO: Explain placeholder and :: notation.
+ *
+ * @param {string} key       The key of the message to look up
+ * @param {string} provider  ``Optional`` The provider the key belongs to.
+ *
+ * @returns {string} The message belonging to the key of the specified provider.
+ *                   If that key is not found in the in the specified provider
+ *                   or if no provider has been specified, the messages of
+ *                   TbSync itself we be used as fallback. If the key could not
+ *                   be found there as well, the key itself is returned.
+ *
+ */
+var getString = function (key, provider) {
+  let localized = null;
+  
+  //spezial treatment of strings with :: like status.httperror::403
+  let parts = key.split("::");
+
+  // if a provider is given, try to get the string from the provider  
+  if (provider && TbSync.providers.loadedProviders.hasOwnProperty(provider)) {
+    let localeData = TbSync.providers.loadedProviders[provider].extension.localeData;
+    if (localeData.messages.get(localeData.selectedLocale).has(parts[0].toLowerCase())) {
+      localized = TbSync.providers.loadedProviders[provider].extension.localeData.localizeMessage(parts[0]);
+    }
+  }
+
+  // if we did not yet succeed, check the locales of tbsync itself
+  if (!localized) {
+    localized = TbSync.extension.localeData.localizeMessage(parts[0]);
+  }
+  
+  if (!localized) {
+    localized = key;
+  } else {
+    //replace placeholders in returned string
+    for (let i = 0; i<parts.length; i++) {
+      let regex = new RegExp( "##replace\."+i+"##", "g");
+      localized = localized.replace(regex, parts[i]);
+    }
+  }
+
+  return localized;
+}
+
+
+var localizeNow = function (window, provider) {
+  let document = window.document;
+  let keyPrefix = "__" + (provider ? provider.toUpperCase() + "4" : "") + "TBSYNCMSG_";
+  
+  let localization = {
+    i18n: null,
+    
+    updateString(string) {
+      let re = new RegExp(keyPrefix + "(.+?)__", "g");
+      return string.replace(re, matched => {
+        const key = matched.slice(keyPrefix.length, -2);
+        return TbSync.getString(key, provider) || matched;
+      });
+    },
+    
+    updateDocument(node) {
+      const texts = document.evaluate(
+        'descendant::text()[contains(self::text(), "' + keyPrefix + '")]',
+        node,
+        null,
+        XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,
+        null
+      );
+      for (let i = 0, maxi = texts.snapshotLength; i < maxi; i++) {
+        const text = texts.snapshotItem(i);
+        if (text.nodeValue.includes(keyPrefix)) text.nodeValue = this.updateString(text.nodeValue);
+      }
+      
+      const attributes = document.evaluate(
+        'descendant::*/attribute::*[contains(., "' + keyPrefix + '")]',
+        node,
+        null,
+        XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,
+        null
+      );
+      for (let i = 0, maxi = attributes.snapshotLength; i < maxi; i++) {
+        const attribute = attributes.snapshotItem(i);
+        if (attribute.value.includes(keyPrefix)) attribute.value = this.updateString(attribute.value);
+      }
+    }		
+  };
+
+  localization.updateDocument(document);
+}
+
+var localizeOnLoad = function (window, provider) {
+  // standard event if loaded by a standard window
+  window.document.addEventListener('DOMContentLoaded', () => {
+    this.localizeNow(window, provider);
+  }, { once: true });
+
+  // custom event, fired by the overlay loader after it has finished loading
+    // the editAccount dialog is never called as a provider, but from tbsync itself
+  let eventId = "DOMOverlayLoaded_"
+      + (!provider || window.location.href.startsWith("chrome://tbsync/content/manager/editAccount.") ? "" : provider + "4")
+      + "tbsync at jobisoft.de";
+  window.document.addEventListener(eventId, () => {
+    TbSync.localizeNow(window, provider);
+  }, { once: true });
+}
+
+
+
+var generateUUID = function () {
+  const uuidGenerator  = Cc["@mozilla.org/uuid-generator;1"].getService(Ci.nsIUUIDGenerator);
+  return uuidGenerator.generateUUID().toString().replace(/[{}]/g, '');
+}
diff -Nru tbsync-4.12/content/modules/tools.js tbsync-4.16/content/modules/tools.js
--- tbsync-4.12/content/modules/tools.js	2024-08-27 18:32:08.000000000 +0200
+++ tbsync-4.16/content/modules/tools.js	2025-03-16 00:25:08.000000000 +0100
@@ -1,80 +1,92 @@
-/*
- * This file is part of TbSync.
- *
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. 
- */
- 
-"use strict";
- 
-var tools = {
-
-  load: async function () {
-  },
-
-  unload: async function () {
-  },
-
-  // async sleep function using Promise to postpone actions to keep UI responsive
-  sleep : function (_delay, useRequestIdleCallback = false) {
-    let useIdleCallback = false;
-    let delay = 5;//_delay;
-    if (TbSync.window.requestIdleCallback && useRequestIdleCallback) {
-      useIdleCallback = true;
-      delay= 2;
-    }
-    let timer =  Components.classes["@mozilla.org/timer;1"].createInstance(Components.interfaces.nsITimer);
-    
-    return new Promise(function(resolve, reject) {
-      let event = {
-        notify: function(timer) {
-          if (useIdleCallback) {
-            TbSync.window.requestIdleCallback(resolve);                        
-          } else {
-            resolve();
-          }
-        }
-      }            
-      timer.initWithCallback(event, delay, Components.interfaces.nsITimer.TYPE_ONE_SHOT);
-    });
-  },
-
-  // this is derived from: http://jonisalonen.com/2012/from-utf-16-to-utf-8-in-javascript/
-  // javascript strings are utf16, btoa needs utf8 , so we need to encode
-  toUTF8: function (str) {
-    var utf8 = "";
-    for (var i=0; i < str.length; i++) {
-      var charcode = str.charCodeAt(i);
-      if (charcode < 0x80) utf8 += String.fromCharCode(charcode);
-      else if (charcode < 0x800) {
-        utf8 += String.fromCharCode(0xc0 | (charcode >> 6), 
-              0x80 | (charcode & 0x3f));
-      }
-      else if (charcode < 0xd800 || charcode >= 0xe000) {
-        utf8 += String.fromCharCode(0xe0 | (charcode >> 12), 
-              0x80 | ((charcode>>6) & 0x3f), 
-              0x80 | (charcode & 0x3f));
-      }
-
-      // surrogate pair
-      else {
-        i++;
-        // UTF-16 encodes 0x10000-0x10FFFF by
-        // subtracting 0x10000 and splitting the
-        // 20 bits of 0x0-0xFFFFF into two halves
-        charcode = 0x10000 + (((charcode & 0x3ff)<<10)
-              | (str.charCodeAt(i) & 0x3ff))
-        utf8 += String.fromCharCode(0xf0 | (charcode >>18), 
-              0x80 | ((charcode>>12) & 0x3f), 
-              0x80 | ((charcode>>6) & 0x3f), 
-              0x80 | (charcode & 0x3f));
-      }
-    }
-    return utf8;
-  },
-  
-  b64encode: function (str) {
-    return btoa(this.toUTF8(str));
-  }
-}
+/*
+ * This file is part of TbSync.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. 
+ */
+ 
+"use strict";
+
+var { ExtensionParent } = ChromeUtils.importESModule(
+  "resource://gre/modules/ExtensionParent.sys.mjs"
+);
+
+var tbsyncExtension = ExtensionParent.GlobalManager.getExtension(
+  "tbsync at jobisoft.de"
+);
+var { TbSync } = ChromeUtils.importESModule(
+  `chrome://tbsync/content/tbsync.sys.mjs?${tbsyncExtension.manifest.version}`
+);
+
+var tools = {
+
+  load: async function () {
+  },
+
+  unload: async function () {
+  },
+
+  // async sleep function using Promise to postpone actions to keep UI responsive
+  sleep : function (_delay, useRequestIdleCallback = false) {
+    const window = Services.wm.getMostRecentWindow("mail:3pane");
+    let useIdleCallback = false;
+    let delay = 5;//_delay;
+    if (window.requestIdleCallback && useRequestIdleCallback) {
+      useIdleCallback = true;
+      delay= 2;
+    }
+    let timer =  Components.classes["@mozilla.org/timer;1"].createInstance(Components.interfaces.nsITimer);
+    
+    return new Promise(function(resolve, reject) {
+      let event = {
+        notify: function(timer) {
+          if (useIdleCallback) {
+            window.requestIdleCallback(resolve);
+          } else {
+            resolve();
+          }
+        }
+      }
+      timer.initWithCallback(event, delay, Components.interfaces.nsITimer.TYPE_ONE_SHOT);
+    });
+  },
+
+  // this is derived from: http://jonisalonen.com/2012/from-utf-16-to-utf-8-in-javascript/
+  // javascript strings are utf16, btoa needs utf8 , so we need to encode
+  toUTF8: function (str) {
+    var utf8 = "";
+    for (var i=0; i < str.length; i++) {
+      var charcode = str.charCodeAt(i);
+      if (charcode < 0x80) utf8 += String.fromCharCode(charcode);
+      else if (charcode < 0x800) {
+        utf8 += String.fromCharCode(0xc0 | (charcode >> 6), 
+              0x80 | (charcode & 0x3f));
+      }
+      else if (charcode < 0xd800 || charcode >= 0xe000) {
+        utf8 += String.fromCharCode(0xe0 | (charcode >> 12), 
+              0x80 | ((charcode>>6) & 0x3f), 
+              0x80 | (charcode & 0x3f));
+      }
+
+      // surrogate pair
+      else {
+        i++;
+        // UTF-16 encodes 0x10000-0x10FFFF by
+        // subtracting 0x10000 and splitting the
+        // 20 bits of 0x0-0xFFFFF into two halves
+        charcode = 0x10000 + (((charcode & 0x3ff)<<10)
+              | (str.charCodeAt(i) & 0x3ff))
+        utf8 += String.fromCharCode(0xf0 | (charcode >>18), 
+              0x80 | ((charcode>>12) & 0x3f), 
+              0x80 | ((charcode>>6) & 0x3f), 
+              0x80 | (charcode & 0x3f));
+      }
+    }
+    return utf8;
+  },
+  
+  b64encode: function (str) {
+    return btoa(this.toUTF8(str));
+  }
+}
diff -Nru tbsync-4.12/content/OverlayManager.jsm tbsync-4.16/content/OverlayManager.jsm
--- tbsync-4.12/content/OverlayManager.jsm	2024-08-27 18:32:08.000000000 +0200
+++ tbsync-4.16/content/OverlayManager.jsm	1970-01-01 01:00:00.000000000 +0100
@@ -1,513 +0,0 @@
-/*
- * This file is part of TbSync.
- *
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. 
- */
- 
-"use strict";
-
-var EXPORTED_SYMBOLS = ["OverlayManager"];
-
-var { NetUtil } = ChromeUtils.import("resource://gre/modules/NetUtil.jsm");
-
-function OverlayManager(extension, options = {}) {
-  this.registeredOverlays = {};
-  this.overlays =  {};
-  this.stylesheets = {};
-  this.options = {verbose: 0};
-  this.extension = extension;
-  
-  let userOptions = Object.keys(options);
-  for (let i=0; i < userOptions.length; i++) {
-    this.options[userOptions[i]] = options[userOptions[i]];
-  }
-
-
-
-  this.windowListener = {
-    that: this,
-    onOpenWindow: function(xulWindow) {
-      let window = xulWindow.QueryInterface(Components.interfaces.nsIInterfaceRequestor).getInterface(Components.interfaces.nsIDOMWindow);
-      this.that.injectAllOverlays(window);
-    },
-    onCloseWindow: function(xulWindow) { },
-    onWindowTitleChange: function(xulWindow, newTitle) { }
-  };
-
-  
-
-
-  this.startObserving = function () {
-    let windows = Services.wm.getEnumerator(null);
-    while (windows.hasMoreElements()) {
-      let window = windows.getNext();
-      //inject overlays for this window
-      this.injectAllOverlays(window);
-    }
-
-    Services.wm.addListener(this.windowListener);
-  };
-
-  this.stopObserving = function () {
-    Services.wm.removeListener(this.windowListener);
-
-    let  windows = Services.wm.getEnumerator(null);
-    while (windows.hasMoreElements()) {
-      let window = windows.getNext();            
-      //remove overlays (if any)
-      this.removeAllOverlays(window);
-    }
-  };
-
-  this.hasRegisteredOverlays = function (window) {
-    return this.registeredOverlays.hasOwnProperty(window.location.href);
-  };
-
-  this.registerOverlay = async function (dst, overlay) {
-    if (overlay.startsWith("chrome://")) {
-      let xul = null;
-      try {
-        xul = await this.readChromeFile(overlay);
-      } catch (e) {
-        console.log("Error reading file <"+overlay+"> : " + e);
-        return;
-      }
-      let rootNode = this.getDataFromXULString(xul);
-  
-      if (rootNode) {
-        //get urls of stylesheets to load them
-        let styleSheetUrls = this.getStyleSheetUrls(rootNode);
-        for (let i=0; i<styleSheetUrls.length; i++) {
-        //we must replace, since we do not know, if it changed - could have been an update
-        //if (!this.stylesheets.hasOwnProperty(styleSheetUrls[i])) {
-          this.stylesheets[styleSheetUrls[i]] = await this.readChromeFile(styleSheetUrls[i]);
-        //}
-        }
-        
-        if (!this.registeredOverlays[dst]) this.registeredOverlays[dst] = [];
-        if (!this.registeredOverlays[dst].includes(overlay)) this.registeredOverlays[dst].push(overlay);
-        
-        this.overlays[overlay] = rootNode;
-      }
-    } else {
-      console.log("Only chrome:// URIs can be registered as overlays.");
-    }
-  };  
-
-  this.getDataFromXULString = function (str) {
-    let data = null;
-    let xul = "";        
-    if (str == "") {
-      if (this.options.verbose>1) Services.console.logStringMessage("[OverlayManager] BAD XUL: A provided XUL file is empty!");
-      return null;
-    }
-
-    let oParser = new DOMParser();
-    try {
-      xul = oParser.parseFromString(str, "application/xml");
-    } catch (e) {
-      //however, domparser does not throw an error, it returns an error document
-      //https://developer.mozilla.org/de/docs/Web/API/DOMParser
-      //just in case
-      if (this.options.verbose>1) Services.console.logStringMessage("[OverlayManager] BAD XUL: A provided XUL file could not be parsed correctly, something is wrong.\n" + str);
-      return null;
-    }
-
-    //check if xul is error document
-    if (xul.documentElement.nodeName == "parsererror") {
-      if (this.options.verbose>1) Services.console.logStringMessage("[OverlayManager] BAD XUL: A provided XUL file could not be parsed correctly, something is wrong.\n" + str);
-      return null;
-    }
-    
-    if (xul.documentElement.nodeName != "overlay") {
-      if (this.options.verbose>1) Services.console.logStringMessage("[OverlayManager] BAD XUL: A provided XUL file does not look like an overlay (root node is not overlay).\n" + str);
-      return null;
-    }
-    
-    return xul;
-  };
-
-
-
-
-
-  this.injectAllOverlays = async function (window, _href = null) {
-    if (window.document.readyState != "complete") {
-      // Make sure the window load has completed.
-      await new Promise(resolve => {
-      window.addEventListener("load", resolve, { once: true });
-      });
-    }
-
-    let href = (_href === null) ? window.location.href : _href;   
-    if (this.options.verbose>1) Services.console.logStringMessage("[OverlayManager] Injecting into new window: " + href);
-    let injectCount = 0;
-    for (let i=0; this.registeredOverlays[href] && i < this.registeredOverlays[href].length; i++) {
-      if (this.injectOverlay(window, this.registeredOverlays[href][i])) injectCount++;
-    }
-    if (injectCount > 0) {
-        // dispatch a custom event to indicate we finished loading the overlay
-        let event = new Event("DOMOverlayLoaded_" + this.extension.id);
-        window.document.dispatchEvent(event);
-    }
-  };
-
-  this.removeAllOverlays = function (window) {
-    if (!this.hasRegisteredOverlays(window))
-      return;
-    
-    for (let i=0; i < this.registeredOverlays[window.location.href].length; i++) {            
-      this.removeOverlay(window, this.registeredOverlays[window.location.href][i]);
-    }        
-  };
-
-
-
-
-  this.injectOverlay = function (window, overlay) {
-    if (!window.hasOwnProperty("injectedOverlays")) window.injectedOverlays = [];
-
-    if (window.injectedOverlays.includes(overlay)) {
-      if (this.options.verbose>2) Services.console.logStringMessage("[OverlayManager] NOT Injecting: " + overlay);
-      return false;
-    }            
-
-    let rootNode = this.overlays[overlay];
-
-    if (rootNode) {
-      let overlayNode = rootNode.documentElement;
-      if (overlayNode) {
-        //get and load scripts
-        let scripts = this.getScripts(rootNode, overlayNode);
-        for (let i=0; i < scripts.length; i++){
-          if (this.options.verbose>3) Services.console.logStringMessage("[OverlayManager] Loading: " + scripts[i]);
-          try {
-            Services.scriptloader.loadSubScript(scripts[i], window);
-          } catch (e) {
-            Components.utils.reportError(e);          
-          }
-        }
-        
-        let omscopename = overlayNode.hasAttribute("omscope") ? overlayNode.getAttribute("omscope") : null;
-        let omscope = omscopename ? window[omscopename] : window;
-
-        let inject = true;
-        if (omscope.hasOwnProperty("onBeforeInject")) {
-          if (this.options.verbose>3) Services.console.logStringMessage("[OverlayManager] Executing " + (omscopename ? omscopename : "window") + ".onBeforeInject()");
-          try {
-            inject = omscope.onBeforeInject(window);
-          } catch (e) {
-            Components.utils.reportError(e);          
-          }
-        }
-
-        if (inject) {
-          if (this.options.verbose>2) Services.console.logStringMessage("[OverlayManager] Injecting: " + overlay);
-          window.injectedOverlays.push(overlay);
-          
-          //get urls of stylesheets to add preloaded files
-          let styleSheetUrls = this.getStyleSheetUrls(rootNode);
-          for (let i=0; i<styleSheetUrls.length; i++) {
-            let namespace = overlayNode.lookupNamespaceURI("html");
-            let element = window.document.createElementNS(namespace, "style");
-            element.id = styleSheetUrls[i];
-            element.textContent = this.stylesheets[styleSheetUrls[i]];
-            window.document.documentElement.appendChild(element);
-            if (this.options.verbose>3) Services.console.logStringMessage("[OverlayManager] Stylesheet: " + styleSheetUrls[i]);
-          }                        
-
-          this.insertXulOverlay(window, overlayNode.children);
-          if (omscope.hasOwnProperty("onInject")) {
-            if (this.options.verbose>3) Services.console.logStringMessage("[OverlayManager] Executing " + (omscopename ? omscopename : "window") + ".onInject()");
-            try {
-              omscope.onInject(window);
-            } catch (e) {
-              Components.utils.reportError(e);          
-            }
-          }
-          
-          // add to injectCounter
-          return true;
-        }
-      }
-    }
-
-    // nothing injected, do not add to inject counter
-    return false;
-  };
-
-  this.removeOverlay = function (window, overlay) {
-    if (!window.hasOwnProperty("injectedOverlays")) window.injectedOverlays = [];
-
-    if (!window.injectedOverlays.includes(overlay)) {
-      if (this.options.verbose>2) Services.console.logStringMessage("[OverlayManager] NOT Removing: " + overlay);
-      return;
-    }
-
-    if (this.options.verbose>2) Services.console.logStringMessage("[OverlayManager] Removing: " + overlay);
-    window.injectedOverlays = window.injectedOverlays.filter(e => (e != overlay));
-    
-    let rootNode = this.overlays[overlay];
-    if (rootNode) {
-      let overlayNode = rootNode.documentElement;
-      if (overlayNode) {
-        let omscopename = overlayNode.hasAttribute("omscope") ? overlayNode.getAttribute("omscope") : null;
-        let omscope = omscopename ? window[omscopename] : window;
-        
-        if (omscope.hasOwnProperty("onRemove")) {
-          if (this.options.verbose>3) Services.console.logStringMessage("[OverlayManager] Executing " + (omscopename ? omscopename : "window") + ".onRemove()");
-          try {
-            omscope.onRemove(window);
-          } catch (e) {
-            Components.utils.reportError(e);          
-          }
-        }
-
-        this.removeXulOverlay(window, overlayNode.children);
-      }
-      
-      //get urls of stylesheets to remove styte tag
-      let styleSheetUrls = this.getStyleSheetUrls(rootNode);
-      for (let i=0; i<styleSheetUrls.length; i++) {
-        let element = window.document.getElementById(styleSheetUrls[i]);
-        if (element) {
-          element.parentNode.removeChild(element);
-        }
-      }
-    }
-  };
-  
-
-
-
-
-
-
-
-
-
-
-  this.getStyleSheetUrls = function (rootNode) {
-    let sheetsIterator = rootNode.evaluate("processing-instruction('xml-stylesheet')", rootNode, null, 0, null); //PathResult.ANY_TYPE = 0
-    let urls = [];
-    
-    let sheet;
-    while (sheet = sheetsIterator.iterateNext()) { //returns object XMLStylesheetProcessingInstruction]
-      let attr=sheet.data.split(" ");
-      for (let a=0; a < attr.length; a++) {
-        if (attr[a].startsWith("href=")) urls.push(attr[a].substring(6,attr[a].length-1));
-      }
-    }
-    return urls;
-  };
-  
-  this.getScripts = function(rootNode, overlayNode) {
-    let nodeIterator = rootNode.evaluate("./script", overlayNode, null, 0, null); //PathResult.ANY_TYPE = 0
-    let scripts = [];
-
-    let node;
-    while (node = nodeIterator.iterateNext()) {
-      if (node.hasAttribute("src") && node.hasAttribute("type") && node.getAttribute("type").toLowerCase().includes("javascript")) {
-        scripts.push(node.getAttribute("src"));
-      }
-    } 
-    return scripts;
-  };
-
-
-
-
-
-
-
-
-
-
-  this.createXulElement = function (window, node, forcedNodeName = null) {
-    //check for namespace
-    let typedef = forcedNodeName ? forcedNodeName.split(":") : node.nodeName.split(":");
-    if (typedef.length == 2) typedef[0] = node.lookupNamespaceURI(typedef[0]);
-    
-    let CE = {}
-    if (node.attributes && node.attributes.getNamedItem("is")) {
-      for  (let i=0; i <node.attributes.length; i++) {
-        if (node.attributes[i].name == "is") {
-          CE = { "is" : node.attributes[i].value };
-          break;
-        }
-      }
-    }
-
-    let element = (typedef.length==2) ? window.document.createElementNS(typedef[0], typedef[1]) : window.document.createXULElement(typedef[0], CE);
-    if  (node.attributes) {
-      for  (let i=0; i <node.attributes.length; i++) {
-        element.setAttribute(node.attributes[i].name, node.attributes[i].value);
-      }
-    }
-
-    //add text child nodes as textContent
-    if (node.hasChildNodes) {
-      let textContent = "";
-      for (let child of node.childNodes) {
-        if (child.nodeType == "3") {
-          textContent += child.nodeValue;
-        }
-      }
-      if (textContent) element.textContent = textContent
-    }
-
-    return element;
-  };
-
-  this.insertXulOverlay = function (window, nodes, parentElement = null) {
-    /*
-       The passed nodes value could be an entire window.document in a single node (type 9) or a 
-       single element node (type 1) as returned by getElementById. It could however also 
-       be an array of nodes as returned by getElementsByTagName or a nodeList as returned
-       by childNodes. In that case node.length is defined.
-     */
-    let nodeList = [];
-    if (nodes.length === undefined) nodeList.push(nodes);
-    else nodeList = nodes;
-    
-    // nodelist contains all childs
-    for (let node of nodeList) {
-      let element = null;
-      let hookMode = null;
-      let hookName = null;
-      let hookElement = null;
-      
-      if (node.nodeName == "script" && node.hasAttribute("src")) {
-        //skip, since they are handled by getScripts()
-      } else if (node.nodeType == 1) {
-
-        if (!parentElement) { //misleading: if it does not have a parentElement, it is a top level element
-          //Adding top level elements without id is not allowed, because we need to be able to remove them!
-          if (!node.hasAttribute("id")) {
-            if (this.options.verbose>1) Services.console.logStringMessage("[OverlayManager] BAD XUL: A top level <" + node.nodeName+ "> element does not have an ID. Skipped");
-            continue;
-          }
-
-          //check for inline script tags
-          if (node.nodeName == "script") {
-            let element = this.createXulElement(window, node, "html:script"); //force as html:script
-            window.document.documentElement.appendChild(element);
-            continue;                        
-          }
-          
-          //check for inline style
-          if (node.nodeName == "style") {
-            let element = this.createXulElement(window, node, "html:style"); //force as html:style
-            window.document.documentElement.appendChild(element);
-            continue;
-          }
-          
-          if (node.hasAttribute("appendto")) hookMode = "appendto";
-          if (node.hasAttribute("insertbefore")) hookMode ="insertbefore";
-          if (node.hasAttribute("insertafter")) hookMode = "insertafter";
-          
-          if (hookMode) {
-            hookName = node.getAttribute(hookMode);
-            hookElement = window.document.getElementById(hookName);
-          
-            if (!hookElement) {
-              if (this.options.verbose>1) Services.console.logStringMessage("[OverlayManager] BAD XUL: The hook element <"+hookName+"> of top level overlay element <"+ node.nodeName+"> does not exist. Skipped");
-              continue;
-            }
-          } else {
-            hookMode = "appendto";
-            hookName = "ROOT";
-            hookElement = window.document.documentElement;
-          }                    
-        }
-        
-        element = this.createXulElement(window, node);
-        if (node.hasChildNodes) this.insertXulOverlay(window, node.children, element);
-
-        if (parentElement) {
-          // this is a child level XUL element which needs to be added to to its parent
-          parentElement.appendChild(element);
-        } else {
-          // this is a toplevel element, which needs to be added at insertafter or insertbefore
-          switch (hookMode) {
-            case "appendto": 
-              hookElement.appendChild(element);
-              break;
-            case "insertbefore":
-              hookElement.parentNode.insertBefore(element, hookElement);
-              break;
-            case "insertafter":
-              hookElement.parentNode.insertBefore(element, hookElement.nextSibling);
-              break;
-            default:
-              if (this.options.verbose>1) Services.console.logStringMessage("[OverlayManager] BAD XUL: Top level overlay element <"+ node.nodeName+"> uses unknown hook type <"+hookMode+">. Skipped.");
-              continue;
-          }
-          if (this.options.verbose>3) Services.console.logStringMessage("[OverlayManager] Adding <"+element.id+"> ("+element.tagName+")  " + hookMode + " <" + hookName + ">");
-        }                
-      }            
-    }
-  };
-
-  this.removeXulOverlay = function (window, nodes, parentElement = null) {
-    //only scan toplevel elements and remove them
-    let nodeList = [];
-    if (nodes.length === undefined) nodeList.push(nodes);
-    else nodeList = nodes;
-    
-    // nodelist contains all childs
-    for (let node of nodeList) {
-      let element = null;
-      switch(node.nodeType) {
-        case 1: 
-          if (node.hasAttribute("id")) {
-            let element = window.document.getElementById(node.getAttribute("id"));
-            if (element) {
-              element.parentNode.removeChild(element);
-            }
-          } 
-          break;
-      }
-    }
-  };
-
-
-
-
-
-
-
-
-
-
-  //read file from within the XPI package
-  this.readChromeFile = function (aURL) {
-    if (this.options.verbose>3) Services.console.logStringMessage("[OverlayManager] Reading file: " + aURL);
-    return new Promise((resolve, reject) => {
-      let uri = Services.io.newURI(aURL);
-      let channel = Services.io.newChannelFromURI(uri,
-                 null,
-                 Services.scriptSecurityManager.getSystemPrincipal(),
-                 null,
-                 Ci.nsILoadInfo.SEC_REQUIRE_SAME_ORIGIN_INHERITS_SEC_CONTEXT,
-                 Ci.nsIContentPolicy.TYPE_OTHER);
-
-      NetUtil.asyncFetch(channel, (inputStream, status) => {
-        if (!Components.isSuccessCode(status)) {
-          reject(status);
-          return;
-        }
-
-        try {
-          let data = NetUtil.readInputStreamToString(inputStream, inputStream.available());
-          resolve(data);
-        } catch (ex) {
-          reject(ex);
-        }
-      });
-    });
-  };
-    
-}
diff -Nru tbsync-4.12/content/OverlayManager.sys.mjs tbsync-4.16/content/OverlayManager.sys.mjs
--- tbsync-4.12/content/OverlayManager.sys.mjs	1970-01-01 01:00:00.000000000 +0100
+++ tbsync-4.16/content/OverlayManager.sys.mjs	2025-03-15 16:42:42.000000000 +0100
@@ -0,0 +1,511 @@
+/*
+ * This file is part of TbSync.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. 
+ */
+ 
+"use strict";
+
+var { NetUtil } = ChromeUtils.importESModule("resource://gre/modules/NetUtil.sys.mjs");
+
+export function OverlayManager(extension, options = {}) {
+  this.registeredOverlays = {};
+  this.overlays =  {};
+  this.stylesheets = {};
+  this.options = {verbose: 0};
+  this.extension = extension;
+  
+  let userOptions = Object.keys(options);
+  for (let i=0; i < userOptions.length; i++) {
+    this.options[userOptions[i]] = options[userOptions[i]];
+  }
+
+
+
+  this.windowListener = {
+    that: this,
+    onOpenWindow: function(xulWindow) {
+      let window = xulWindow.QueryInterface(Components.interfaces.nsIInterfaceRequestor).getInterface(Components.interfaces.nsIDOMWindow);
+      this.that.injectAllOverlays(window);
+    },
+    onCloseWindow: function(xulWindow) { },
+    onWindowTitleChange: function(xulWindow, newTitle) { }
+  };
+
+  
+
+
+  this.startObserving = function () {
+    let windows = Services.wm.getEnumerator(null);
+    while (windows.hasMoreElements()) {
+      let window = windows.getNext();
+      //inject overlays for this window
+      this.injectAllOverlays(window);
+    }
+
+    Services.wm.addListener(this.windowListener);
+  };
+
+  this.stopObserving = function () {
+    Services.wm.removeListener(this.windowListener);
+
+    let  windows = Services.wm.getEnumerator(null);
+    while (windows.hasMoreElements()) {
+      let window = windows.getNext();            
+      //remove overlays (if any)
+      this.removeAllOverlays(window);
+    }
+  };
+
+  this.hasRegisteredOverlays = function (window) {
+    return this.registeredOverlays.hasOwnProperty(window.location.href);
+  };
+
+  this.registerOverlay = async function (dst, overlay) {
+    if (overlay.startsWith("chrome://")) {
+      let xul = null;
+      try {
+        xul = await this.readChromeFile(overlay);
+      } catch (e) {
+        console.log("Error reading file <"+overlay+"> : " + e);
+        return;
+      }
+      let rootNode = this.getDataFromXULString(xul);
+  
+      if (rootNode) {
+        //get urls of stylesheets to load them
+        let styleSheetUrls = this.getStyleSheetUrls(rootNode);
+        for (let i=0; i<styleSheetUrls.length; i++) {
+        //we must replace, since we do not know, if it changed - could have been an update
+        //if (!this.stylesheets.hasOwnProperty(styleSheetUrls[i])) {
+          this.stylesheets[styleSheetUrls[i]] = await this.readChromeFile(styleSheetUrls[i]);
+        //}
+        }
+        
+        if (!this.registeredOverlays[dst]) this.registeredOverlays[dst] = [];
+        if (!this.registeredOverlays[dst].includes(overlay)) this.registeredOverlays[dst].push(overlay);
+        
+        this.overlays[overlay] = rootNode;
+      }
+    } else {
+      console.log("Only chrome:// URIs can be registered as overlays.");
+    }
+  };  
+
+  this.getDataFromXULString = function (str) {
+    let data = null;
+    let xul = "";        
+    if (str == "") {
+      if (this.options.verbose>1) Services.console.logStringMessage("[OverlayManager] BAD XUL: A provided XUL file is empty!");
+      return null;
+    }
+
+    let oParser = new DOMParser();
+    try {
+      xul = oParser.parseFromString(str, "application/xml");
+    } catch (e) {
+      //however, domparser does not throw an error, it returns an error document
+      //https://developer.mozilla.org/de/docs/Web/API/DOMParser
+      //just in case
+      if (this.options.verbose>1) Services.console.logStringMessage("[OverlayManager] BAD XUL: A provided XUL file could not be parsed correctly, something is wrong.\n" + str);
+      return null;
+    }
+
+    //check if xul is error document
+    if (xul.documentElement.nodeName == "parsererror") {
+      if (this.options.verbose>1) Services.console.logStringMessage("[OverlayManager] BAD XUL: A provided XUL file could not be parsed correctly, something is wrong.\n" + str);
+      return null;
+    }
+    
+    if (xul.documentElement.nodeName != "overlay") {
+      if (this.options.verbose>1) Services.console.logStringMessage("[OverlayManager] BAD XUL: A provided XUL file does not look like an overlay (root node is not overlay).\n" + str);
+      return null;
+    }
+    
+    return xul;
+  };
+
+
+
+
+
+  this.injectAllOverlays = async function (window, _href = null) {
+    if (window.document.readyState != "complete") {
+      // Make sure the window load has completed.
+      await new Promise(resolve => {
+      window.addEventListener("load", resolve, { once: true });
+      });
+    }
+
+    let href = (_href === null) ? window.location.href : _href;   
+    if (this.options.verbose>1) Services.console.logStringMessage("[OverlayManager] Injecting into new window: " + href);
+    let injectCount = 0;
+    for (let i=0; this.registeredOverlays[href] && i < this.registeredOverlays[href].length; i++) {
+      if (this.injectOverlay(window, this.registeredOverlays[href][i])) injectCount++;
+    }
+    if (injectCount > 0) {
+        // dispatch a custom event to indicate we finished loading the overlay
+        let event = new Event("DOMOverlayLoaded_" + this.extension.id);
+        window.document.dispatchEvent(event);
+    }
+  };
+
+  this.removeAllOverlays = function (window) {
+    if (!this.hasRegisteredOverlays(window))
+      return;
+    
+    for (let i=0; i < this.registeredOverlays[window.location.href].length; i++) {            
+      this.removeOverlay(window, this.registeredOverlays[window.location.href][i]);
+    }        
+  };
+
+
+
+
+  this.injectOverlay = function (window, overlay) {
+    if (!window.hasOwnProperty("injectedOverlays")) window.injectedOverlays = [];
+
+    if (window.injectedOverlays.includes(overlay)) {
+      if (this.options.verbose>2) Services.console.logStringMessage("[OverlayManager] NOT Injecting: " + overlay);
+      return false;
+    }            
+
+    let rootNode = this.overlays[overlay];
+
+    if (rootNode) {
+      let overlayNode = rootNode.documentElement;
+      if (overlayNode) {
+        //get and load scripts
+        let scripts = this.getScripts(rootNode, overlayNode);
+        for (let i=0; i < scripts.length; i++){
+          if (this.options.verbose>3) Services.console.logStringMessage("[OverlayManager] Loading: " + scripts[i]);
+          try {
+            Services.scriptloader.loadSubScript(scripts[i], window);
+          } catch (e) {
+            Components.utils.reportError(e);          
+          }
+        }
+        
+        let omscopename = overlayNode.hasAttribute("omscope") ? overlayNode.getAttribute("omscope") : null;
+        let omscope = omscopename ? window[omscopename] : window;
+
+        let inject = true;
+        if (omscope.hasOwnProperty("onBeforeInject")) {
+          if (this.options.verbose>3) Services.console.logStringMessage("[OverlayManager] Executing " + (omscopename ? omscopename : "window") + ".onBeforeInject()");
+          try {
+            inject = omscope.onBeforeInject(window);
+          } catch (e) {
+            Components.utils.reportError(e);          
+          }
+        }
+
+        if (inject) {
+          if (this.options.verbose>2) Services.console.logStringMessage("[OverlayManager] Injecting: " + overlay);
+          window.injectedOverlays.push(overlay);
+          
+          //get urls of stylesheets to add preloaded files
+          let styleSheetUrls = this.getStyleSheetUrls(rootNode);
+          for (let i=0; i<styleSheetUrls.length; i++) {
+            let namespace = overlayNode.lookupNamespaceURI("html");
+            let element = window.document.createElementNS(namespace, "style");
+            element.id = styleSheetUrls[i];
+            element.textContent = this.stylesheets[styleSheetUrls[i]];
+            window.document.documentElement.appendChild(element);
+            if (this.options.verbose>3) Services.console.logStringMessage("[OverlayManager] Stylesheet: " + styleSheetUrls[i]);
+          }                        
+
+          this.insertXulOverlay(window, overlayNode.children);
+          if (omscope.hasOwnProperty("onInject")) {
+            if (this.options.verbose>3) Services.console.logStringMessage("[OverlayManager] Executing " + (omscopename ? omscopename : "window") + ".onInject()");
+            try {
+              omscope.onInject(window);
+            } catch (e) {
+              Components.utils.reportError(e);          
+            }
+          }
+          
+          // add to injectCounter
+          return true;
+        }
+      }
+    }
+
+    // nothing injected, do not add to inject counter
+    return false;
+  };
+
+  this.removeOverlay = function (window, overlay) {
+    if (!window.hasOwnProperty("injectedOverlays")) window.injectedOverlays = [];
+
+    if (!window.injectedOverlays.includes(overlay)) {
+      if (this.options.verbose>2) Services.console.logStringMessage("[OverlayManager] NOT Removing: " + overlay);
+      return;
+    }
+
+    if (this.options.verbose>2) Services.console.logStringMessage("[OverlayManager] Removing: " + overlay);
+    window.injectedOverlays = window.injectedOverlays.filter(e => (e != overlay));
+    
+    let rootNode = this.overlays[overlay];
+    if (rootNode) {
+      let overlayNode = rootNode.documentElement;
+      if (overlayNode) {
+        let omscopename = overlayNode.hasAttribute("omscope") ? overlayNode.getAttribute("omscope") : null;
+        let omscope = omscopename ? window[omscopename] : window;
+        
+        if (omscope.hasOwnProperty("onRemove")) {
+          if (this.options.verbose>3) Services.console.logStringMessage("[OverlayManager] Executing " + (omscopename ? omscopename : "window") + ".onRemove()");
+          try {
+            omscope.onRemove(window);
+          } catch (e) {
+            Components.utils.reportError(e);          
+          }
+        }
+
+        this.removeXulOverlay(window, overlayNode.children);
+      }
+      
+      //get urls of stylesheets to remove styte tag
+      let styleSheetUrls = this.getStyleSheetUrls(rootNode);
+      for (let i=0; i<styleSheetUrls.length; i++) {
+        let element = window.document.getElementById(styleSheetUrls[i]);
+        if (element) {
+          element.parentNode.removeChild(element);
+        }
+      }
+    }
+  };
+  
+
+
+
+
+
+
+
+
+
+
+  this.getStyleSheetUrls = function (rootNode) {
+    let sheetsIterator = rootNode.evaluate("processing-instruction('xml-stylesheet')", rootNode, null, 0, null); //PathResult.ANY_TYPE = 0
+    let urls = [];
+    
+    let sheet;
+    while (sheet = sheetsIterator.iterateNext()) { //returns object XMLStylesheetProcessingInstruction]
+      let attr=sheet.data.split(" ");
+      for (let a=0; a < attr.length; a++) {
+        if (attr[a].startsWith("href=")) urls.push(attr[a].substring(6,attr[a].length-1));
+      }
+    }
+    return urls;
+  };
+  
+  this.getScripts = function(rootNode, overlayNode) {
+    let nodeIterator = rootNode.evaluate("./script", overlayNode, null, 0, null); //PathResult.ANY_TYPE = 0
+    let scripts = [];
+
+    let node;
+    while (node = nodeIterator.iterateNext()) {
+      if (node.hasAttribute("src") && node.hasAttribute("type") && node.getAttribute("type").toLowerCase().includes("javascript")) {
+        scripts.push(node.getAttribute("src"));
+      }
+    } 
+    return scripts;
+  };
+
+
+
+
+
+
+
+
+
+
+  this.createXulElement = function (window, node, forcedNodeName = null) {
+    //check for namespace
+    let typedef = forcedNodeName ? forcedNodeName.split(":") : node.nodeName.split(":");
+    if (typedef.length == 2) typedef[0] = node.lookupNamespaceURI(typedef[0]);
+    
+    let CE = {}
+    if (node.attributes && node.attributes.getNamedItem("is")) {
+      for  (let i=0; i <node.attributes.length; i++) {
+        if (node.attributes[i].name == "is") {
+          CE = { "is" : node.attributes[i].value };
+          break;
+        }
+      }
+    }
+
+    let element = (typedef.length==2) ? window.document.createElementNS(typedef[0], typedef[1]) : window.document.createXULElement(typedef[0], CE);
+    if  (node.attributes) {
+      for  (let i=0; i <node.attributes.length; i++) {
+        element.setAttribute(node.attributes[i].name, node.attributes[i].value);
+      }
+    }
+
+    //add text child nodes as textContent
+    if (node.hasChildNodes) {
+      let textContent = "";
+      for (let child of node.childNodes) {
+        if (child.nodeType == "3") {
+          textContent += child.nodeValue;
+        }
+      }
+      if (textContent) element.textContent = textContent
+    }
+
+    return element;
+  };
+
+  this.insertXulOverlay = function (window, nodes, parentElement = null) {
+    /*
+       The passed nodes value could be an entire window.document in a single node (type 9) or a 
+       single element node (type 1) as returned by getElementById. It could however also 
+       be an array of nodes as returned by getElementsByTagName or a nodeList as returned
+       by childNodes. In that case node.length is defined.
+     */
+    let nodeList = [];
+    if (nodes.length === undefined) nodeList.push(nodes);
+    else nodeList = nodes;
+    
+    // nodelist contains all childs
+    for (let node of nodeList) {
+      let element = null;
+      let hookMode = null;
+      let hookName = null;
+      let hookElement = null;
+      
+      if (node.nodeName == "script" && node.hasAttribute("src")) {
+        //skip, since they are handled by getScripts()
+      } else if (node.nodeType == 1) {
+
+        if (!parentElement) { //misleading: if it does not have a parentElement, it is a top level element
+          //Adding top level elements without id is not allowed, because we need to be able to remove them!
+          if (!node.hasAttribute("id")) {
+            if (this.options.verbose>1) Services.console.logStringMessage("[OverlayManager] BAD XUL: A top level <" + node.nodeName+ "> element does not have an ID. Skipped");
+            continue;
+          }
+
+          //check for inline script tags
+          if (node.nodeName == "script") {
+            let element = this.createXulElement(window, node, "html:script"); //force as html:script
+            window.document.documentElement.appendChild(element);
+            continue;                        
+          }
+          
+          //check for inline style
+          if (node.nodeName == "style") {
+            let element = this.createXulElement(window, node, "html:style"); //force as html:style
+            window.document.documentElement.appendChild(element);
+            continue;
+          }
+          
+          if (node.hasAttribute("appendto")) hookMode = "appendto";
+          if (node.hasAttribute("insertbefore")) hookMode ="insertbefore";
+          if (node.hasAttribute("insertafter")) hookMode = "insertafter";
+          
+          if (hookMode) {
+            hookName = node.getAttribute(hookMode);
+            hookElement = window.document.getElementById(hookName);
+          
+            if (!hookElement) {
+              if (this.options.verbose>1) Services.console.logStringMessage("[OverlayManager] BAD XUL: The hook element <"+hookName+"> of top level overlay element <"+ node.nodeName+"> does not exist. Skipped");
+              continue;
+            }
+          } else {
+            hookMode = "appendto";
+            hookName = "ROOT";
+            hookElement = window.document.documentElement;
+          }                    
+        }
+        
+        element = this.createXulElement(window, node);
+        if (node.hasChildNodes) this.insertXulOverlay(window, node.children, element);
+
+        if (parentElement) {
+          // this is a child level XUL element which needs to be added to to its parent
+          parentElement.appendChild(element);
+        } else {
+          // this is a toplevel element, which needs to be added at insertafter or insertbefore
+          switch (hookMode) {
+            case "appendto": 
+              hookElement.appendChild(element);
+              break;
+            case "insertbefore":
+              hookElement.parentNode.insertBefore(element, hookElement);
+              break;
+            case "insertafter":
+              hookElement.parentNode.insertBefore(element, hookElement.nextSibling);
+              break;
+            default:
+              if (this.options.verbose>1) Services.console.logStringMessage("[OverlayManager] BAD XUL: Top level overlay element <"+ node.nodeName+"> uses unknown hook type <"+hookMode+">. Skipped.");
+              continue;
+          }
+          if (this.options.verbose>3) Services.console.logStringMessage("[OverlayManager] Adding <"+element.id+"> ("+element.tagName+")  " + hookMode + " <" + hookName + ">");
+        }                
+      }            
+    }
+  };
+
+  this.removeXulOverlay = function (window, nodes, parentElement = null) {
+    //only scan toplevel elements and remove them
+    let nodeList = [];
+    if (nodes.length === undefined) nodeList.push(nodes);
+    else nodeList = nodes;
+    
+    // nodelist contains all childs
+    for (let node of nodeList) {
+      let element = null;
+      switch(node.nodeType) {
+        case 1: 
+          if (node.hasAttribute("id")) {
+            let element = window.document.getElementById(node.getAttribute("id"));
+            if (element) {
+              element.parentNode.removeChild(element);
+            }
+          } 
+          break;
+      }
+    }
+  };
+
+
+
+
+
+
+
+
+
+
+  //read file from within the XPI package
+  this.readChromeFile = function (aURL) {
+    if (this.options.verbose>3) Services.console.logStringMessage("[OverlayManager] Reading file: " + aURL);
+    return new Promise((resolve, reject) => {
+      let uri = Services.io.newURI(aURL);
+      let channel = Services.io.newChannelFromURI(uri,
+                 null,
+                 Services.scriptSecurityManager.getSystemPrincipal(),
+                 null,
+                 Ci.nsILoadInfo.SEC_REQUIRE_SAME_ORIGIN_INHERITS_SEC_CONTEXT,
+                 Ci.nsIContentPolicy.TYPE_OTHER);
+
+      NetUtil.asyncFetch(channel, (inputStream, status) => {
+        if (!Components.isSuccessCode(status)) {
+          reject(status);
+          return;
+        }
+
+        try {
+          let data = NetUtil.readInputStreamToString(inputStream, inputStream.available());
+          resolve(data);
+        } catch (ex) {
+          reject(ex);
+        }
+      });
+    });
+  };
+    
+}
diff -Nru tbsync-4.12/content/overlays/messenger.js tbsync-4.16/content/overlays/messenger.js
--- tbsync-4.12/content/overlays/messenger.js	2024-08-27 18:32:08.000000000 +0200
+++ tbsync-4.16/content/overlays/messenger.js	2025-03-15 23:49:58.000000000 +0100
@@ -1,22 +1,31 @@
-/*
- * This file is part of TbSync.
- *
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. 
- */
- 
-"use strict";
-
-var { TbSync } = ChromeUtils.import("chrome://tbsync/content/tbsync.jsm");
-
-var tbSyncMessenger = {
-
-  onInject: function (window) {
-    Services.obs.notifyObservers(null, "tbsync.observer.manager.updateSyncstate", null);
-  },
-
-  onRemove: function (window) {
-  },
-
-};
+/*
+ * This file is part of TbSync.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. 
+ */
+ 
+"use strict";
+
+var { ExtensionParent } = ChromeUtils.importESModule(
+  "resource://gre/modules/ExtensionParent.sys.mjs"
+);
+
+var tbsyncExtension = ExtensionParent.GlobalManager.getExtension(
+  "tbsync at jobisoft.de"
+);
+var { TbSync } = ChromeUtils.importESModule(
+  `chrome://tbsync/content/tbsync.sys.mjs?${tbsyncExtension.manifest.version}`
+);
+
+var tbSyncMessenger = {
+
+  onInject: function (window) {
+    Services.obs.notifyObservers(null, "tbsync.observer.manager.updateSyncstate", null);
+  },
+
+  onRemove: function (window) {
+  },
+
+};
diff -Nru tbsync-4.12/content/overlays/messenger.xhtml tbsync-4.16/content/overlays/messenger.xhtml
--- tbsync-4.12/content/overlays/messenger.xhtml	2024-08-27 18:32:08.000000000 +0200
+++ tbsync-4.16/content/overlays/messenger.xhtml	2021-08-30 18:31:42.000000000 +0200
@@ -1,20 +1,20 @@
-<?xml version="1.0"?>
-
-<overlay 
-    id="TbSyncMessengerOverlay"
-    omscope="tbSyncMessenger"
-    xmlns:html="http://www.w3.org/1999/xhtml">
-
-    <script type="application/javascript" src="chrome://tbsync/content/overlays/messenger.js" />
-    <script type="text/javascript" src="chrome://tbsync/content/scripts/locales.js" /> 
-
-    <menupopup id="tbsync.statusmenu">
-        <menuitem label="__TBSYNCMSG_popup.opensettings__" oncommand="TbSync.manager.openManagerWindow(event);" />
-    </menupopup>
-    
-    <label  id="tbsync.status" class="statusbarpanel" value="TbSync" onclick="TbSync.manager.openManagerWindow(event);" appendto="status-bar"/>
-
-    <!--menuitem id="tbsync.taskPopupEntry" label="__TBSYNCMSG_menu.settingslabel__" appendto="taskPopup" onclick="TbSync.manager.openManagerWindow(event);" / -->
-    <menuitem id="tbsync.accountmgrEntry" label="__TBSYNCMSG_menu.settingslabel__" insertbefore="menu_accountmgr" oncommand="TbSync.manager.openManagerWindow(event);" />
-
-</overlay>        
+<?xml version="1.0"?>
+
+<overlay 
+    id="TbSyncMessengerOverlay"
+    omscope="tbSyncMessenger"
+    xmlns:html="http://www.w3.org/1999/xhtml">
+
+    <script type="application/javascript" src="chrome://tbsync/content/overlays/messenger.js" />
+    <script type="text/javascript" src="chrome://tbsync/content/scripts/locales.js" /> 
+
+    <menupopup id="tbsync.statusmenu">
+        <menuitem label="__TBSYNCMSG_popup.opensettings__" oncommand="TbSync.manager.openManagerWindow(event);" />
+    </menupopup>
+    
+    <label  id="tbsync.status" class="statusbarpanel" value="TbSync" onclick="TbSync.manager.openManagerWindow(event);" appendto="status-bar"/>
+
+    <!--menuitem id="tbsync.taskPopupEntry" label="__TBSYNCMSG_menu.settingslabel__" appendto="taskPopup" onclick="TbSync.manager.openManagerWindow(event);" / -->
+    <menuitem id="tbsync.accountmgrEntry" label="__TBSYNCMSG_menu.settingslabel__" insertbefore="menu_accountmgr" oncommand="TbSync.manager.openManagerWindow(event);" />
+
+</overlay>        
diff -Nru tbsync-4.12/content/passwordPrompt/passwordPrompt.css tbsync-4.16/content/passwordPrompt/passwordPrompt.css
--- tbsync-4.12/content/passwordPrompt/passwordPrompt.css	2024-08-27 18:32:08.000000000 +0200
+++ tbsync-4.16/content/passwordPrompt/passwordPrompt.css	2024-08-18 13:03:30.000000000 +0200
@@ -1,13 +1,13 @@
-  .grid-container {
-    display: grid;
-    grid-template-columns: auto 1fr;
-    grid-template-rows: auto auto auto;
-    gap: 1px;
-    width: 250px;
-    margin: 2ex auto;
-  }
-
-  .grid-item {
-    padding: 2px;
-    text-align: left;
-  }
+  .grid-container {
+    display: grid;
+    grid-template-columns: auto 1fr;
+    grid-template-rows: auto auto auto;
+    gap: 1px;
+    width: 250px;
+    margin: 2ex auto;
+  }
+
+  .grid-item {
+    padding: 2px;
+    text-align: left;
+  }
diff -Nru tbsync-4.12/content/passwordPrompt/passwordPrompt.js tbsync-4.16/content/passwordPrompt/passwordPrompt.js
--- tbsync-4.12/content/passwordPrompt/passwordPrompt.js	2024-08-27 18:32:08.000000000 +0200
+++ tbsync-4.16/content/passwordPrompt/passwordPrompt.js	2024-08-18 13:03:30.000000000 +0200
@@ -1,47 +1,47 @@
-/*
- * This file is part of TbSync.
- *
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. 
- */
- 
-"use strict";
-
-var tbSyncPassword = {
-  
-  onload: function () {
-    let data = window.arguments[0];
-    this.resolve = window.arguments[1];
-    this.resolved = false;
-
-    this.namefield =  document.getElementById("tbsync.account");
-    this.passfield = document.getElementById("tbsync.password");
-    this.userfield = document.getElementById("tbsync.user");
-
-    this.namefield.value = data.accountname;
-    this.userfield.value = data.username;
-    this.userfield.disabled = data.usernameLocked;
-
-    window.addEventListener("unload", tbSyncPassword.doCANCEL.bind(this));
-    document.getElementById("tbsync.password").focus();
-    document.getElementById("tbsync.password.ok").addEventListener("click", tbSyncPassword.doOK.bind(this));
-    document.getElementById("tbsync.password.cancel").addEventListener("click", () => window.close());
-  },
-
-  doOK: function (event) {
-    if (!this.resolved) {
-      this.resolved = true
-      this.resolve({username: this.userfield.value, password: this.passfield.value});
-      window.close();
-    }
-  },
-  
-  doCANCEL: function (event) {
-    if (!this.resolved) {
-      this.resolved = true
-      this.resolve(false);
-    }
-  },
-  
-};
+/*
+ * This file is part of TbSync.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. 
+ */
+ 
+"use strict";
+
+var tbSyncPassword = {
+  
+  onload: function () {
+    let data = window.arguments[0];
+    this.resolve = window.arguments[1];
+    this.resolved = false;
+
+    this.namefield =  document.getElementById("tbsync.account");
+    this.passfield = document.getElementById("tbsync.password");
+    this.userfield = document.getElementById("tbsync.user");
+
+    this.namefield.value = data.accountname;
+    this.userfield.value = data.username;
+    this.userfield.disabled = data.usernameLocked;
+
+    window.addEventListener("unload", tbSyncPassword.doCANCEL.bind(this));
+    document.getElementById("tbsync.password").focus();
+    document.getElementById("tbsync.password.ok").addEventListener("click", tbSyncPassword.doOK.bind(this));
+    document.getElementById("tbsync.password.cancel").addEventListener("click", () => window.close());
+  },
+
+  doOK: function (event) {
+    if (!this.resolved) {
+      this.resolved = true
+      this.resolve({username: this.userfield.value, password: this.passfield.value});
+      window.close();
+    }
+  },
+  
+  doCANCEL: function (event) {
+    if (!this.resolved) {
+      this.resolved = true
+      this.resolve(false);
+    }
+  },
+  
+};
diff -Nru tbsync-4.12/content/passwordPrompt/passwordPrompt.xhtml tbsync-4.16/content/passwordPrompt/passwordPrompt.xhtml
--- tbsync-4.12/content/passwordPrompt/passwordPrompt.xhtml	2024-08-27 18:32:08.000000000 +0200
+++ tbsync-4.16/content/passwordPrompt/passwordPrompt.xhtml	2024-08-18 13:03:30.000000000 +0200
@@ -1,32 +1,32 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<?xml-stylesheet href="chrome://global/skin/global.css" type="text/css"?>
-<?xml-stylesheet href="chrome://tbsync/content/passwordPrompt/passwordPrompt.css" type="text/css"?>
-
-<window
-    xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
-    xmlns:html="http://www.w3.org/1999/xhtml"
-    title="__TBSYNCMSG_password.title__"
-    onload="tbSyncPassword.onload();">
-
-    <script type="application/javascript" src="chrome://tbsync/content/passwordPrompt/passwordPrompt.js"/>
-    <script type="text/javascript" src="chrome://tbsync/content/scripts/locales.js" /> 
-
-    <vbox flex="1">
-        <description style="padding: 5px; width: 350px;">__TBSYNCMSG_password.description__</description>
-
-        <html:div class="grid-container">
-            <html:div class="grid-item"><label value="__TBSYNCMSG_password.account__"/></html:div>
-            <html:div class="grid-item"><label class="header"  id="tbsync.account" /></html:div>
-            <html:div class="grid-item"><label value="__TBSYNCMSG_password.user__"/></html:div>
-            <html:div class="grid-item"><html:input id="tbsync.user" /></html:div>
-            <html:div class="grid-item"><label value="__TBSYNCMSG_password.password__"/></html:div>
-            <html:div class="grid-item"><html:input type="password" id="tbsync.password"/></html:div>
-        </html:div>
-        <hbox style="padding: 5px">
-            <vbox flex="1"></vbox>
-            <button id="tbsync.password.ok" label="__TBSYNCMSG_password.ok__" />
-            <button id="tbsync.password.cancel" label="__TBSYNCMSG_password.cancel__" />
-        </hbox>
-    </vbox>
-
-</window>
+<?xml version="1.0" encoding="UTF-8"?>
+<?xml-stylesheet href="chrome://global/skin/global.css" type="text/css"?>
+<?xml-stylesheet href="chrome://tbsync/content/passwordPrompt/passwordPrompt.css" type="text/css"?>
+
+<window
+    xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+    xmlns:html="http://www.w3.org/1999/xhtml"
+    title="__TBSYNCMSG_password.title__"
+    onload="tbSyncPassword.onload();">
+
+    <script type="application/javascript" src="chrome://tbsync/content/passwordPrompt/passwordPrompt.js"/>
+    <script type="text/javascript" src="chrome://tbsync/content/scripts/locales.js" /> 
+
+    <vbox flex="1">
+        <description style="padding: 5px; width: 350px;">__TBSYNCMSG_password.description__</description>
+
+        <html:div class="grid-container">
+            <html:div class="grid-item"><label value="__TBSYNCMSG_password.account__"/></html:div>
+            <html:div class="grid-item"><label class="header"  id="tbsync.account" /></html:div>
+            <html:div class="grid-item"><label value="__TBSYNCMSG_password.user__"/></html:div>
+            <html:div class="grid-item"><html:input id="tbsync.user" /></html:div>
+            <html:div class="grid-item"><label value="__TBSYNCMSG_password.password__"/></html:div>
+            <html:div class="grid-item"><html:input type="password" id="tbsync.password"/></html:div>
+        </html:div>
+        <hbox style="padding: 5px">
+            <vbox flex="1"></vbox>
+            <button id="tbsync.password.ok" label="__TBSYNCMSG_password.ok__" />
+            <button id="tbsync.password.cancel" label="__TBSYNCMSG_password.cancel__" />
+        </hbox>
+    </vbox>
+
+</window>
diff -Nru tbsync-4.12/content/scripts/bootstrap.js tbsync-4.16/content/scripts/bootstrap.js
--- tbsync-4.12/content/scripts/bootstrap.js	2024-08-27 18:32:08.000000000 +0200
+++ tbsync-4.16/content/scripts/bootstrap.js	1970-01-01 01:00:00.000000000 +0100
@@ -1,87 +0,0 @@
-/*
- * This file is part of TbSync.
- *
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. 
- */
-
- 
- function startup(data, reason) {
-  // possible reasons: APP_STARTUP, ADDON_ENABLE, ADDON_INSTALL, ADDON_UPGRADE, or ADDON_DOWNGRADE.
-
-  // set default prefs
-  let defaults = Services.prefs.getDefaultBranch("extensions.tbsync.");
-  defaults.setBoolPref("debug.testoptions", false);
-  defaults.setBoolPref("log.toconsole", false);
-  defaults.setIntPref("log.userdatalevel", 0); //0 - off   1 - userdata only on errors   2 - including full userdata,  3 - extra infos
-
-  // Check if at least one main window has finished loading
-  let windows = Services.wm.getEnumerator("mail:3pane");
-  if (windows.hasMoreElements()) {
-    let domWindow = windows.getNext();
-    WindowListener.loadIntoWindow(domWindow);
-  }
-
-  // Wait for any new windows to open.
-  Services.wm.addListener(WindowListener);
-  
-  //DO NOT ADD ANYTHING HERE!
-}
-
-function shutdown(data, reason) {
-  //possible reasons: APP_SHUTDOWN, ADDON_DISABLE, ADDON_UNINSTALL, ADDON_UPGRADE, or ADDON_DOWNGRADE
-
-  // Stop listening for any new windows to open.
-  Services.wm.removeListener(WindowListener);
-
-  var { TbSync } = ChromeUtils.import("chrome://tbsync/content/tbsync.jsm");
-  TbSync.enabled = false;
-  TbSync.unload().then(function() {
-    Cu.unload("chrome://tbsync/content/tbsync.jsm");
-    Cu.unload("chrome://tbsync/content/OverlayManager.jsm");
-    // HACK WARNING:
-    //  - the Addon Manager does not properly clear all addon related caches on update;
-    //  - in order to fully update images and locales, their caches need clearing here
-    Services.obs.notifyObservers(null, "startupcache-invalidate");
-    Services.obs.notifyObservers(null, "chrome-flush-caches"); 
-  });
-}
-
-
-var WindowListener = {
-
-  async loadIntoWindow(window) {
-    if (window.document.readyState != "complete") {
-      // Make sure the window load has completed.
-      await new Promise(resolve => {
-        window.addEventListener("load", resolve, { once: true });
-      });
-    }
-
-    // Check if the opened window is the one we want to modify.
-    if (window.document.documentElement.getAttribute("windowtype") === "mail:3pane") {
-      // the main window has loaded, continue with init
-      var { TbSync } = ChromeUtils.import("chrome://tbsync/content/tbsync.jsm");
-      if (!TbSync.enabled) TbSync.load(window, addon, extension);
-    }
-  },
-
-
-  unloadFromWindow(window) {
-  },
-
-  // nsIWindowMediatorListener functions
-  onOpenWindow(xulWindow) {
-    // A new window has opened.
-    let domWindow = xulWindow.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindow);
-    // The domWindow.document.documentElement.getAttribute("windowtype") is not set before the load, so we cannot check it here
-    this.loadIntoWindow(domWindow);
-  },
-
-  onCloseWindow(xulWindow) {
-  },
-
-  onWindowTitleChange(xulWindow, newTitle) {
-  },
-};
diff -Nru tbsync-4.12/content/scripts/locales.js tbsync-4.16/content/scripts/locales.js
--- tbsync-4.12/content/scripts/locales.js	2024-08-27 18:32:08.000000000 +0200
+++ tbsync-4.16/content/scripts/locales.js	2025-03-15 23:49:58.000000000 +0100
@@ -1,3 +1,12 @@
-var { TbSync } = ChromeUtils.import("chrome://tbsync/content/tbsync.jsm");
-
-TbSync.localizeOnLoad(window);
+var { ExtensionParent } = ChromeUtils.importESModule(
+    "resource://gre/modules/ExtensionParent.sys.mjs"
+);
+
+var tbsyncExtension = ExtensionParent.GlobalManager.getExtension(
+    "tbsync at jobisoft.de"
+);
+var { TbSync } = ChromeUtils.importESModule(
+    `chrome://tbsync/content/tbsync.sys.mjs?${tbsyncExtension.manifest.version}`
+);
+
+TbSync.localizeOnLoad(window);
diff -Nru tbsync-4.12/content/skin/ab.css tbsync-4.16/content/skin/ab.css
--- tbsync-4.12/content/skin/ab.css	2024-08-27 18:32:08.000000000 +0200
+++ tbsync-4.16/content/skin/ab.css	2021-08-30 18:31:42.000000000 +0200
@@ -1,8 +1,8 @@
-treechildren::-moz-tree-image(DirCol, orphaned) {
-  margin-inline-end: 2px;
-  list-style-image: url("chrome://tbsync/content/skin/error16.png");
-}
-
-.abMenuItem[AddrBook="true"][TbSyncIcon="orphaned"] {
-  list-style-image: url("chrome://tbsync/content/skin/error16.png");
-}
+treechildren::-moz-tree-image(DirCol, orphaned) {
+  margin-inline-end: 2px;
+  list-style-image: url("chrome://tbsync/content/skin/error16.png");
+}
+
+.abMenuItem[AddrBook="true"][TbSyncIcon="orphaned"] {
+  list-style-image: url("chrome://tbsync/content/skin/error16.png");
+}
diff -Nru tbsync-4.12/content/skin/browserOverlay.css tbsync-4.16/content/skin/browserOverlay.css
--- tbsync-4.12/content/skin/browserOverlay.css	2024-08-27 18:32:08.000000000 +0200
+++ tbsync-4.16/content/skin/browserOverlay.css	2021-08-30 18:31:42.000000000 +0200
@@ -1,10 +1,10 @@
-/*  skin/toolbar-button.css  */
-
-#tbsync-toolbarbutton {
-  list-style-image: url("chrome://tbsync/content/skin/sync.png");
-}
-
-toolbar[iconsize="small"] #tbsync-toolbarbutton {
-  list-style-image: url("chrome://tbsync/content/skin/syncsmall.png");
-}
-
+/*  skin/toolbar-button.css  */
+
+#tbsync-toolbarbutton {
+  list-style-image: url("chrome://tbsync/content/skin/sync.png");
+}
+
+toolbar[iconsize="small"] #tbsync-toolbarbutton {
+  list-style-image: url("chrome://tbsync/content/skin/syncsmall.png");
+}
+
diff -Nru tbsync-4.12/content/skin/fix_dropdown_1534697.css tbsync-4.16/content/skin/fix_dropdown_1534697.css
--- tbsync-4.12/content/skin/fix_dropdown_1534697.css	2024-08-27 18:32:08.000000000 +0200
+++ tbsync-4.16/content/skin/fix_dropdown_1534697.css	2021-08-30 18:31:42.000000000 +0200
@@ -1,4 +1,4 @@
-button.plain .button-menu-dropmarker {
-  -moz-appearance: toolbarbutton-dropdown;
-  display: block;
-}
+button.plain .button-menu-dropmarker {
+  -moz-appearance: toolbarbutton-dropdown;
+  display: block;
+}
diff -Nru tbsync-4.12/content/skin/src/LICENSE tbsync-4.16/content/skin/src/LICENSE
--- tbsync-4.12/content/skin/src/LICENSE	2024-08-27 18:32:08.000000000 +0200
+++ tbsync-4.16/content/skin/src/LICENSE	2021-08-30 18:31:42.000000000 +0200
@@ -1,131 +1,131 @@
-The following files are released into PUBLIC DOMAIN.
-
-slider.xcf
-slider-on.png
-slider-off.png
-
-The png files are based on the xcf file.
-
-
-
-Creative Commons Legal Code
-
-CC0 1.0 Universal
-
-    CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE
-    LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN
-    ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS
-    INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES
-    REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS
-    PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM
-    THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED
-    HEREUNDER.
-
-Statement of Purpose
-
-The laws of most jurisdictions throughout the world automatically confer
-exclusive Copyright and Related Rights (defined below) upon the creator
-and subsequent owner(s) (each and all, an "owner") of an original work of
-authorship and/or a database (each, a "Work").
-
-Certain owners wish to permanently relinquish those rights to a Work for
-the purpose of contributing to a commons of creative, cultural and
-scientific works ("Commons") that the public can reliably and without fear
-of later claims of infringement build upon, modify, incorporate in other
-works, reuse and redistribute as freely as possible in any form whatsoever
-and for any purposes, including without limitation commercial purposes.
-These owners may contribute to the Commons to promote the ideal of a free
-culture and the further production of creative, cultural and scientific
-works, or to gain reputation or greater distribution for their Work in
-part through the use and efforts of others.
-
-For these and/or other purposes and motivations, and without any
-expectation of additional consideration or compensation, the person
-associating CC0 with a Work (the "Affirmer"), to the extent that he or she
-is an owner of Copyright and Related Rights in the Work, voluntarily
-elects to apply CC0 to the Work and publicly distribute the Work under its
-terms, with knowledge of his or her Copyright and Related Rights in the
-Work and the meaning and intended legal effect of CC0 on those rights.
-
-1. Copyright and Related Rights. A Work made available under CC0 may be
-protected by copyright and related or neighboring rights ("Copyright and
-Related Rights"). Copyright and Related Rights include, but are not
-limited to, the following:
-
-  i. the right to reproduce, adapt, distribute, perform, display,
-     communicate, and translate a Work;
- ii. moral rights retained by the original author(s) and/or performer(s);
-iii. publicity and privacy rights pertaining to a person's image or
-     likeness depicted in a Work;
- iv. rights protecting against unfair competition in regards to a Work,
-     subject to the limitations in paragraph 4(a), below;
-  v. rights protecting the extraction, dissemination, use and reuse of data
-     in a Work;
- vi. database rights (such as those arising under Directive 96/9/EC of the
-     European Parliament and of the Council of 11 March 1996 on the legal
-     protection of databases, and under any national implementation
-     thereof, including any amended or successor version of such
-     directive); and
-vii. other similar, equivalent or corresponding rights throughout the
-     world based on applicable law or treaty, and any national
-     implementations thereof.
-
-2. Waiver. To the greatest extent permitted by, but not in contravention
-of, applicable law, Affirmer hereby overtly, fully, permanently,
-irrevocably and unconditionally waives, abandons, and surrenders all of
-Affirmer's Copyright and Related Rights and associated claims and causes
-of action, whether now known or unknown (including existing as well as
-future claims and causes of action), in the Work (i) in all territories
-worldwide, (ii) for the maximum duration provided by applicable law or
-treaty (including future time extensions), (iii) in any current or future
-medium and for any number of copies, and (iv) for any purpose whatsoever,
-including without limitation commercial, advertising or promotional
-purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each
-member of the public at large and to the detriment of Affirmer's heirs and
-successors, fully intending that such Waiver shall not be subject to
-revocation, rescission, cancellation, termination, or any other legal or
-equitable action to disrupt the quiet enjoyment of the Work by the public
-as contemplated by Affirmer's express Statement of Purpose.
-
-3. Public License Fallback. Should any part of the Waiver for any reason
-be judged legally invalid or ineffective under applicable law, then the
-Waiver shall be preserved to the maximum extent permitted taking into
-account Affirmer's express Statement of Purpose. In addition, to the
-extent the Waiver is so judged Affirmer hereby grants to each affected
-person a royalty-free, non transferable, non sublicensable, non exclusive,
-irrevocable and unconditional license to exercise Affirmer's Copyright and
-Related Rights in the Work (i) in all territories worldwide, (ii) for the
-maximum duration provided by applicable law or treaty (including future
-time extensions), (iii) in any current or future medium and for any number
-of copies, and (iv) for any purpose whatsoever, including without
-limitation commercial, advertising or promotional purposes (the
-"License"). The License shall be deemed effective as of the date CC0 was
-applied by Affirmer to the Work. Should any part of the License for any
-reason be judged legally invalid or ineffective under applicable law, such
-partial invalidity or ineffectiveness shall not invalidate the remainder
-of the License, and in such case Affirmer hereby affirms that he or she
-will not (i) exercise any of his or her remaining Copyright and Related
-Rights in the Work or (ii) assert any associated claims and causes of
-action with respect to the Work, in either case contrary to Affirmer's
-express Statement of Purpose.
-
-4. Limitations and Disclaimers.
-
- a. No trademark or patent rights held by Affirmer are waived, abandoned,
-    surrendered, licensed or otherwise affected by this document.
- b. Affirmer offers the Work as-is and makes no representations or
-    warranties of any kind concerning the Work, express, implied,
-    statutory or otherwise, including without limitation warranties of
-    title, merchantability, fitness for a particular purpose, non
-    infringement, or the absence of latent or other defects, accuracy, or
-    the present or absence of errors, whether or not discoverable, all to
-    the greatest extent permissible under applicable law.
- c. Affirmer disclaims responsibility for clearing rights of other persons
-    that may apply to the Work or any use thereof, including without
-    limitation any person's Copyright and Related Rights in the Work.
-    Further, Affirmer disclaims responsibility for obtaining any necessary
-    consents, permissions or other rights required for any use of the
-    Work.
- d. Affirmer understands and acknowledges that Creative Commons is not a
-    party to this document and has no duty or obligation with respect to
+The following files are released into PUBLIC DOMAIN.
+
+slider.xcf
+slider-on.png
+slider-off.png
+
+The png files are based on the xcf file.
+
+
+
+Creative Commons Legal Code
+
+CC0 1.0 Universal
+
+    CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE
+    LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN
+    ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS
+    INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES
+    REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS
+    PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM
+    THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED
+    HEREUNDER.
+
+Statement of Purpose
+
+The laws of most jurisdictions throughout the world automatically confer
+exclusive Copyright and Related Rights (defined below) upon the creator
+and subsequent owner(s) (each and all, an "owner") of an original work of
+authorship and/or a database (each, a "Work").
+
+Certain owners wish to permanently relinquish those rights to a Work for
+the purpose of contributing to a commons of creative, cultural and
+scientific works ("Commons") that the public can reliably and without fear
+of later claims of infringement build upon, modify, incorporate in other
+works, reuse and redistribute as freely as possible in any form whatsoever
+and for any purposes, including without limitation commercial purposes.
+These owners may contribute to the Commons to promote the ideal of a free
+culture and the further production of creative, cultural and scientific
+works, or to gain reputation or greater distribution for their Work in
+part through the use and efforts of others.
+
+For these and/or other purposes and motivations, and without any
+expectation of additional consideration or compensation, the person
+associating CC0 with a Work (the "Affirmer"), to the extent that he or she
+is an owner of Copyright and Related Rights in the Work, voluntarily
+elects to apply CC0 to the Work and publicly distribute the Work under its
+terms, with knowledge of his or her Copyright and Related Rights in the
+Work and the meaning and intended legal effect of CC0 on those rights.
+
+1. Copyright and Related Rights. A Work made available under CC0 may be
+protected by copyright and related or neighboring rights ("Copyright and
+Related Rights"). Copyright and Related Rights include, but are not
+limited to, the following:
+
+  i. the right to reproduce, adapt, distribute, perform, display,
+     communicate, and translate a Work;
+ ii. moral rights retained by the original author(s) and/or performer(s);
+iii. publicity and privacy rights pertaining to a person's image or
+     likeness depicted in a Work;
+ iv. rights protecting against unfair competition in regards to a Work,
+     subject to the limitations in paragraph 4(a), below;
+  v. rights protecting the extraction, dissemination, use and reuse of data
+     in a Work;
+ vi. database rights (such as those arising under Directive 96/9/EC of the
+     European Parliament and of the Council of 11 March 1996 on the legal
+     protection of databases, and under any national implementation
+     thereof, including any amended or successor version of such
+     directive); and
+vii. other similar, equivalent or corresponding rights throughout the
+     world based on applicable law or treaty, and any national
+     implementations thereof.
+
+2. Waiver. To the greatest extent permitted by, but not in contravention
+of, applicable law, Affirmer hereby overtly, fully, permanently,
+irrevocably and unconditionally waives, abandons, and surrenders all of
+Affirmer's Copyright and Related Rights and associated claims and causes
+of action, whether now known or unknown (including existing as well as
+future claims and causes of action), in the Work (i) in all territories
+worldwide, (ii) for the maximum duration provided by applicable law or
+treaty (including future time extensions), (iii) in any current or future
+medium and for any number of copies, and (iv) for any purpose whatsoever,
+including without limitation commercial, advertising or promotional
+purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each
+member of the public at large and to the detriment of Affirmer's heirs and
+successors, fully intending that such Waiver shall not be subject to
+revocation, rescission, cancellation, termination, or any other legal or
+equitable action to disrupt the quiet enjoyment of the Work by the public
+as contemplated by Affirmer's express Statement of Purpose.
+
+3. Public License Fallback. Should any part of the Waiver for any reason
+be judged legally invalid or ineffective under applicable law, then the
+Waiver shall be preserved to the maximum extent permitted taking into
+account Affirmer's express Statement of Purpose. In addition, to the
+extent the Waiver is so judged Affirmer hereby grants to each affected
+person a royalty-free, non transferable, non sublicensable, non exclusive,
+irrevocable and unconditional license to exercise Affirmer's Copyright and
+Related Rights in the Work (i) in all territories worldwide, (ii) for the
+maximum duration provided by applicable law or treaty (including future
+time extensions), (iii) in any current or future medium and for any number
+of copies, and (iv) for any purpose whatsoever, including without
+limitation commercial, advertising or promotional purposes (the
+"License"). The License shall be deemed effective as of the date CC0 was
+applied by Affirmer to the Work. Should any part of the License for any
+reason be judged legally invalid or ineffective under applicable law, such
+partial invalidity or ineffectiveness shall not invalidate the remainder
+of the License, and in such case Affirmer hereby affirms that he or she
+will not (i) exercise any of his or her remaining Copyright and Related
+Rights in the Work or (ii) assert any associated claims and causes of
+action with respect to the Work, in either case contrary to Affirmer's
+express Statement of Purpose.
+
+4. Limitations and Disclaimers.
+
+ a. No trademark or patent rights held by Affirmer are waived, abandoned,
+    surrendered, licensed or otherwise affected by this document.
+ b. Affirmer offers the Work as-is and makes no representations or
+    warranties of any kind concerning the Work, express, implied,
+    statutory or otherwise, including without limitation warranties of
+    title, merchantability, fitness for a particular purpose, non
+    infringement, or the absence of latent or other defects, accuracy, or
+    the present or absence of errors, whether or not discoverable, all to
+    the greatest extent permissible under applicable law.
+ c. Affirmer disclaims responsibility for clearing rights of other persons
+    that may apply to the Work or any use thereof, including without
+    limitation any person's Copyright and Related Rights in the Work.
+    Further, Affirmer disclaims responsibility for obtaining any necessary
+    consents, permissions or other rights required for any use of the
+    Work.
+ d. Affirmer understands and acknowledges that Creative Commons is not a
+    party to this document and has no duty or obligation with respect to
     this CC0 or use of the Work.
\ Kein Zeilenumbruch am Dateiende.
diff -Nru tbsync-4.12/content/tbsync.jsm tbsync-4.16/content/tbsync.jsm
--- tbsync-4.12/content/tbsync.jsm	2024-08-27 18:32:08.000000000 +0200
+++ tbsync-4.16/content/tbsync.jsm	1970-01-01 01:00:00.000000000 +0100
@@ -1,156 +0,0 @@
-/*
- * This file is part of TbSync.
- *
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. 
- */
- 
-"use strict";
-
-var EXPORTED_SYMBOLS = ["TbSync"];
-
-var TbSync = {
-
-  enabled: false,
-  shutdown: false,
-  
-  window: null,
-  addon: null,
-  version: 0,
-  debugMode: false,
-  apiVersion: "2.5",
-
-  prefs: Services.prefs.getBranch("extensions.tbsync."),
-  
-  decoder: new TextDecoder(),
-  encoder: new TextEncoder(),
-
-  modules : [],
-  extension : null,
-  
-  // global load
-  load: async function (window, addon, extension) {
-	  //public module and IO module needs to be loaded beforehand
-    Services.scriptloader.loadSubScript("chrome://tbsync/content/modules/public.js", TbSync, "UTF-8");
-    Services.scriptloader.loadSubScript("chrome://tbsync/content/modules/io.js", TbSync, "UTF-8");
-
-    //clear debug log on start
-    this.io.initFile("debug.log");
-
-    this.window = window;
-    this.addon = addon;
-    this.addon.contributorsURL = "https://github.com/jobisoft/TbSync/blob/master/CONTRIBUTORS.md";
-    this.extension = extension;
-    this.dump("TbSync init","Start (" + this.addon.version.toString() + ")");
-
-    //print information about Thunderbird version and OS
-    this.dump(Services.appinfo.name, Services.appinfo.version + " on " + Services.appinfo.OS);
-
-    // register modules to be used by TbSync
-    this.modules.push({name: "db", state: 0});
-    this.modules.push({name: "addressbook", state: 0});
-    this.modules.push({name: "lightning", state: 0});
-    this.modules.push({name: "eventlog", state: 0});
-    this.modules.push({name: "core", state: 0});
-    this.modules.push({name: "passwordManager", state: 0});
-    this.modules.push({name: "network", state: 0});
-    this.modules.push({name: "tools", state: 0});
-    this.modules.push({name: "manager", state: 0});
-    this.modules.push({name: "providers", state: 0});
-    this.modules.push({name: "messenger", state: 0});
-
-    //load modules
-    for (let module of this.modules) {
-      try {
-        Services.scriptloader.loadSubScript("chrome://tbsync/content/modules/" + module.name + ".js", TbSync, "UTF-8");
-        module.state = 1;
-        this.dump("Loading module <" + module.name + ">", "OK");
-      } catch (e) {
-        this.dump("Loading module <" + module.name + ">", "FAILED!");
-        Components.utils.reportError(e);
-      }
-    }
-
-    //call init function of loaded modules
-    for (let module of this.modules) {
-      if (module.state == 1) {
-        try {
-          this.dump("Initializing module", "<" + module.name + ">");
-          await this[module.name].load();
-          module.state = 2;
-        } catch (e) {
-          this.dump("Initialization of module <" + module.name + "> FAILED", e.message + "\n" + e.stack);
-          Components.utils.reportError(e);
-        }
-      }
-    }
-    
-    //was debug mode enabled during startup?
-    this.debugMode = (this.prefs.getIntPref("log.userdatalevel") > 0);
-
-    //enable TbSync
-    this.enabled = true;
-
-    //notify about finished init of TbSync
-    Services.obs.notifyObservers(null, "tbsync.observer.manager.updateSyncstate", null);
-    Services.obs.notifyObservers(null, 'tbsync.observer.initialized', null);
-
-    //activate sync timer
-    this.syncTimer.start();
-
-    this.dump("TbSync init","Done");
-  },
-  
-  // global unload
-  unload: async function() {
-    //cancel sync timer
-    this.syncTimer.cancel();
-    
-    //unload modules in reverse order
-    this.modules.reverse();
-    for (let module of this.modules) {
-      if (module.state == 2) {
-        try {
-          await this[module.name].unload();
-          this.dump("Unloading module <" + module.name + ">", "OK");
-        } catch (e) {
-          this.dump("Unloading module <" + module.name + ">", "FAILED!");
-          Components.utils.reportError(e);
-        }
-      }
-    }
-  },
-
-  // timer for periodic sync
-  syncTimer: {
-    timer: Components.classes["@mozilla.org/timer;1"].createInstance(Components.interfaces.nsITimer),
-
-    start: function () {
-      this.timer.cancel();
-      this.timer.initWithCallback(this.event, 60000, 3); //run timer every 60s
-    },
-
-    cancel: function () {
-      this.timer.cancel();
-    },
-
-    event: {
-      notify: function (timer) {
-        if (TbSync.enabled) {
-          //get all accounts and check, which one needs sync
-          let accounts = TbSync.db.getAccounts();
-          for (let i=0; i<accounts.IDs.length; i++) {
-            let now = Date.now();
-            let syncInterval = accounts.data[accounts.IDs[i]].autosync * 60 * 1000;
-            let lastsynctime = accounts.data[accounts.IDs[i]].lastsynctime;
-            let noAutosyncUntil = accounts.data[accounts.IDs[i]].noAutosyncUntil || 0;
-            if (TbSync.core.isEnabled(accounts.IDs[i]) && (syncInterval > 0) && (now > (lastsynctime + syncInterval)) && (now > noAutosyncUntil)) {
-                TbSync.core.syncAccount(accounts.IDs[i]);
-            }
-          }
-        }
-      }
-    }
-  }
-};
diff -Nru tbsync-4.12/content/tbsync.sys.mjs tbsync-4.16/content/tbsync.sys.mjs
--- tbsync-4.12/content/tbsync.sys.mjs	1970-01-01 01:00:00.000000000 +0100
+++ tbsync-4.16/content/tbsync.sys.mjs	2025-03-16 00:17:32.000000000 +0100
@@ -0,0 +1,154 @@
+/*
+ * This file is part of TbSync.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. 
+ */
+ 
+"use strict";
+
+export var TbSync = {
+
+  enabled: false,
+  shutdown: false,
+  
+  addon: null,
+  version: 0,
+  debugMode: false,
+  apiVersion: "2.5",
+
+  prefs: Services.prefs.getBranch("extensions.tbsync."),
+  
+  decoder: new TextDecoder(),
+  encoder: new TextEncoder(),
+
+  modules : [],
+  extension : null,
+  
+  // global load
+  load: async function (addon, extension) {
+    console.log(`Loading TbSync v${extension.manifest.version}`);
+
+    //public module and IO module needs to be loaded beforehand
+    Services.scriptloader.loadSubScript("chrome://tbsync/content/modules/public.js", TbSync, "UTF-8");
+    Services.scriptloader.loadSubScript("chrome://tbsync/content/modules/io.js", TbSync, "UTF-8");
+
+    //clear debug log on start
+    this.io.initFile("debug.log");
+
+    this.addon = addon;
+    this.addon.contributorsURL = "https://github.com/jobisoft/TbSync/blob/master/CONTRIBUTORS.md";
+    this.extension = extension;
+    this.dump("TbSync init","Start (" + this.addon.version.toString() + ")");
+
+    //print information about Thunderbird version and OS
+    this.dump(Services.appinfo.name, Services.appinfo.version + " on " + Services.appinfo.OS);
+
+    // register modules to be used by TbSync
+    this.modules.push({name: "db", state: 0});
+    this.modules.push({name: "addressbook", state: 0});
+    this.modules.push({name: "lightning", state: 0});
+    this.modules.push({name: "eventlog", state: 0});
+    this.modules.push({name: "core", state: 0});
+    this.modules.push({name: "passwordManager", state: 0});
+    this.modules.push({name: "network", state: 0});
+    this.modules.push({name: "tools", state: 0});
+    this.modules.push({name: "manager", state: 0});
+    this.modules.push({name: "providers", state: 0});
+    this.modules.push({name: "messenger", state: 0});
+
+    //load modules
+    for (let module of this.modules) {
+      try {
+        Services.scriptloader.loadSubScript("chrome://tbsync/content/modules/" + module.name + ".js", TbSync, "UTF-8");
+        module.state = 1;
+        this.dump("Loading module <" + module.name + ">", "OK");
+      } catch (e) {
+        this.dump("Loading module <" + module.name + ">", "FAILED!");
+        Components.utils.reportError(e);
+      }
+    }
+
+    //call init function of loaded modules
+    for (let module of this.modules) {
+      if (module.state == 1) {
+        try {
+          this.dump("Initializing module", "<" + module.name + ">");
+          await this[module.name].load();
+          module.state = 2;
+        } catch (e) {
+          this.dump("Initialization of module <" + module.name + "> FAILED", e.message + "\n" + e.stack);
+          Components.utils.reportError(e);
+        }
+      }
+    }
+    
+    //was debug mode enabled during startup?
+    this.debugMode = (this.prefs.getIntPref("log.userdatalevel") > 0);
+
+    //enable TbSync
+    this.enabled = true;
+
+    //notify about finished init of TbSync
+    Services.obs.notifyObservers(null, "tbsync.observer.manager.updateSyncstate", null);
+    Services.obs.notifyObservers(null, 'tbsync.observer.initialized', null);
+
+    //activate sync timer
+    this.syncTimer.start();
+
+    this.dump("TbSync init","Done");
+  },
+  
+  // global unload
+  unload: async function() {
+    //cancel sync timer
+    this.syncTimer.cancel();
+    
+    //unload modules in reverse order
+    this.modules.reverse();
+    for (let module of this.modules) {
+      if (module.state == 2) {
+        try {
+          await this[module.name].unload();
+          this.dump("Unloading module <" + module.name + ">", "OK");
+        } catch (e) {
+          this.dump("Unloading module <" + module.name + ">", "FAILED!");
+          Components.utils.reportError(e);
+        }
+      }
+    }
+  },
+
+  // timer for periodic sync
+  syncTimer: {
+    timer: Components.classes["@mozilla.org/timer;1"].createInstance(Components.interfaces.nsITimer),
+
+    start: function () {
+      this.timer.cancel();
+      this.timer.initWithCallback(this.event, 60000, 3); //run timer every 60s
+    },
+
+    cancel: function () {
+      this.timer.cancel();
+    },
+
+    event: {
+      notify: function (timer) {
+        if (TbSync.enabled) {
+          //get all accounts and check, which one needs sync
+          let accounts = TbSync.db.getAccounts();
+          for (let i=0; i<accounts.IDs.length; i++) {
+            let now = Date.now();
+            let syncInterval = accounts.data[accounts.IDs[i]].autosync * 60 * 1000;
+            let lastsynctime = accounts.data[accounts.IDs[i]].lastsynctime;
+            let noAutosyncUntil = accounts.data[accounts.IDs[i]].noAutosyncUntil || 0;
+            if (TbSync.core.isEnabled(accounts.IDs[i]) && (syncInterval > 0) && (now > (lastsynctime + syncInterval)) && (now > noAutosyncUntil)) {
+                TbSync.core.syncAccount(accounts.IDs[i]);
+            }
+          }
+        }
+      }
+    }
+  }
+};
diff -Nru tbsync-4.12/CONTRIBUTORS.md tbsync-4.16/CONTRIBUTORS.md
--- tbsync-4.12/CONTRIBUTORS.md	2024-08-27 18:32:08.000000000 +0200
+++ tbsync-4.16/CONTRIBUTORS.md	2025-07-28 19:12:44.000000000 +0200
@@ -1,16 +1,17 @@
-## Creator
-* John Bieling
-
-## Contributors
-* John Bieling
-* Jan Dagefoerde
-* Nam Ldmpub
-* Fonic
-
-## Translators
-* John Bieling (de, en-US)
-* Wanderlei H?ttel (pt-BR)
-* Alessandro Menti (it)
-* ?v?ri (hu)
-* Alexey Sinitsyn (ru)
-* Daniel Wr?blewski (pl)
+## Creator
+* John Bieling
+
+## Contributors
+* John Bieling
+* Jan Dagefoerde
+* Nam Ldmpub
+* Fonic
+* Kabe2007
+
+## Translators
+* John Bieling (de, en-US)
+* Wanderlei H?ttel (pt-BR)
+* Alessandro Menti (it)
+* ?v?ri (hu)
+* Alexey Sinitsyn (ru)
+* Daniel Wr?blewski (pl)
diff -Nru tbsync-4.12/crowdin.yml tbsync-4.16/crowdin.yml
--- tbsync-4.12/crowdin.yml	2024-08-27 18:32:08.000000000 +0200
+++ tbsync-4.16/crowdin.yml	1970-01-01 01:00:00.000000000 +0100
@@ -1,5 +0,0 @@
-commit_message: https://crowdin.com/project/tbsync
-files:
-  - source: /_locales/en-US/*
-    translation: /_locales/%osx_locale%/%original_file_name%
-    escape_special_characters: 0
diff -Nru tbsync-4.12/debian/changelog tbsync-4.16/debian/changelog
--- tbsync-4.12/debian/changelog	2024-08-31 17:33:27.000000000 +0200
+++ tbsync-4.16/debian/changelog	2025-09-24 11:36:01.000000000 +0200
@@ -1,3 +1,33 @@
+tbsync (4.16-1~deb13u1) trixie; urgency=medium
+
+  * Rebuild for uploading with thunderbird>= 140.3 to trixie
+
+ -- Mechtilde Stehmann <mechtilde at debian.org>  Wed, 24 Sep 2025 11:36:01 +0200
+
+tbsync (4.16-1) unstable; urgency=medium
+
+  * Rebuild for unstable to use with thunderbird_140.3 et.
+
+ -- Mechtilde Stehmann <mechtilde at debian.org>  Sun, 21 Sep 2025 10:42:04 +0200
+
+tbsync (4.16-1~exp1) experimental; urgency=medium
+
+  [ Mechtilde ]
+  * [8a34ac6] Added d/dpb.conf to contain the information
+              when using debian-packages-scripts
+  * [aac3f2a] Improved d/watch to check against the Mozilla repo
+  * [30d34dc] New upstream version 4.16
+  * [0e1c63a] Bumped standard version - no changes needed
+  * [4fa12f7] Improved d/u/metadata
+  * [e61054c] Improved d/dpb.conf
+  * [aac3689] Improved d/gbp.conf
+  * [fc8ab02] Bumped years in d/copyright
+  * [d87ad41] Bumped versions of the dependencies.
+  +           Removed webext-dav4tbsync from recommends
+              - integrated into thunderbird
+
+ -- Mechtilde Stehmann <mechtilde at debian.org>  Sat, 23 Aug 2025 12:22:45 +0200
+
 tbsync (4.12-1) unstable; urgency=medium
 
   [ Mechtilde ]
diff -Nru tbsync-4.12/debian/control tbsync-4.16/debian/control
--- tbsync-4.12/debian/control	2024-08-31 17:25:30.000000000 +0200
+++ tbsync-4.16/debian/control	2025-08-23 10:28:43.000000000 +0200
@@ -4,7 +4,7 @@
 Maintainer: Debian Mozilla Extension Maintainers <pkg-mozext-maintainers at alioth-lists.debian.net>
 Uploaders: Mechtilde Stehmann <mechtilde at debian.org>
 Build-Depends: debhelper-compat (= 13), zip
-Standards-Version: 4.7.0
+Standards-Version: 4.7.2
 Rules-Requires-Root: no
 Vcs-Git: https://salsa.debian.org/webext-team/tbsync.git
 Vcs-Browser: https://salsa.debian.org/webext-team/tbsync
@@ -13,10 +13,9 @@
 Package: webext-tbsync
 Architecture: all
 Depends: ${misc:Depends}
- , thunderbird (>= 1:128.0)
- , thunderbird (<= 1:128.x)
-Recommends: webext-dav4tbsync (>= 4.8)
- , webext-eas4tbsync (>= 4.11)
+ , thunderbird (>= 1:140.0)
+ , thunderbird (<= 1:140.x)
+Recommends: webext-eas4tbsync (>= 4.17)
 Description: Thunderbird/Lightning Add-On to support MS Exchange Calendar etc.
  Synchronize Exchange ActiveSync accounts (contacts, tasks and
  calendars) to Thunderbird, supports Office 365, Outlook.com,
diff -Nru tbsync-4.12/debian/copyright tbsync-4.16/debian/copyright
--- tbsync-4.12/debian/copyright	2024-05-15 11:13:25.000000000 +0200
+++ tbsync-4.16/debian/copyright	2025-08-23 10:26:35.000000000 +0200
@@ -3,7 +3,7 @@
 Source: https://github.com/jobisoft/TbSync
 
 Files: *
-Copyright: 2017-2024 john.bieling at gmx.de
+Copyright: 2017-2025 john.bieling at gmx.de
 License: MPL-2.0
 
 Files: content/skin/tbsync.png
@@ -39,7 +39,7 @@
 License: CC0-1.0
 
 Files: debian/*
-Copyright: 2018-2024 Mechtilde Stehmann <mechtilde at debian.org
+Copyright: 2018-2025 Mechtilde Stehmann <mechtilde at debian.org
 License: MPL-2.0
 
 License: MPL-2.0
diff -Nru tbsync-4.12/debian/dpb.conf tbsync-4.16/debian/dpb.conf
--- tbsync-4.12/debian/dpb.conf	1970-01-01 01:00:00.000000000 +0100
+++ tbsync-4.16/debian/dpb.conf	2025-09-24 11:22:07.000000000 +0200
@@ -0,0 +1,18 @@
+#!bin/bash
+#debian/dpb.conf
+# ConfigFile for TbSync
+# This file is used by the scripts from
+# debian-package-scripts
+## General parameters
+SourceName=tbsync
+PackName=webext-tbsync
+ProjectPath=/home/mechtilde/Projekte/Git/01_Salsa
+SalsaName=webext-team/tbsync
+RecentUpstreamSuffix=.xpi
+RecentBranchD=trixie
+## Parameters for Java packages
+JavaFlag=0
+## Parameters for Webext packages
+WebextFlag=1
+## Parameters for Python3 packages
+PythonFlag=0
diff -Nru tbsync-4.12/debian/gbp.conf tbsync-4.16/debian/gbp.conf
--- tbsync-4.12/debian/gbp.conf	2023-09-12 19:11:02.000000000 +0200
+++ tbsync-4.16/debian/gbp.conf	2025-09-24 10:46:12.000000000 +0200
@@ -4,8 +4,8 @@
 # use pristine-tar:
 pristine-tar = True
 # generate gz compressed orig file
-# compression = xz
-debian-branch = debian/sid
+# compqression = xz
+debian-branch = debian/trixie
 upstream-branch = upstream
 
 [pq]
@@ -13,7 +13,6 @@
 
 [dch]
 id-length = 7
-debian-branch = debian/sid
 
 [import-orig]
 # filter out unwanted files/dirs from upstream
diff -Nru tbsync-4.12/debian/upstream/metadata tbsync-4.16/debian/upstream/metadata
--- tbsync-4.12/debian/upstream/metadata	2022-04-17 11:27:54.000000000 +0200
+++ tbsync-4.16/debian/upstream/metadata	2025-08-23 11:34:37.000000000 +0200
@@ -1,3 +1,9 @@
+# You can find a description at
+#        https://wiki.debian.org/UpstreamMetadata
 Bug-Database: https://github.com/jobisoft/TbSync/issues
+Bug-Submit: https://github.com/jobisoft/TbSync/issues
+Changelog: https://github.com/jobisoft/TbSync/commits/master/
+Documentation: https://github.com/jobisoft/TbSync/wiki
 Repository: https://github.com/jobisoft/TbSync
 Repository-Browse: https://github.com/jobisoft/TbSync
+Reference: https://addons.thunderbird.net/en-US/thunderbird/addon/tbsync/versions/
diff -Nru tbsync-4.12/debian/watch tbsync-4.16/debian/watch
--- tbsync-4.12/debian/watch	2023-09-12 18:29:32.000000000 +0200
+++ tbsync-4.16/debian/watch	2025-08-23 10:29:00.000000000 +0200
@@ -1,2 +1,6 @@
 version=4
-https://github.com/jobisoft/TbSync/tags .*/archive/refs/tags/v(\d[\d\.]+)\.tar\.gz
+opts=\
+repack,compression=xz,\
+dversionmangle=s///,\
+uversionmangle=s/-?([^\d.]+)/~$1/;tr/A-Z/a-z/ \
+https://addons.thunderbird.net/en-US/thunderbird/addon/tbsync/versions/ (\d[\d\.]+)*
diff -Nru tbsync-4.12/LICENSE tbsync-4.16/LICENSE
--- tbsync-4.12/LICENSE	2024-08-27 18:32:08.000000000 +0200
+++ tbsync-4.16/LICENSE	2021-08-30 18:31:42.000000000 +0200
@@ -1,373 +1,373 @@
-Mozilla Public License Version 2.0
-==================================
-
-1. Definitions
---------------
-
-1.1. "Contributor"
-    means each individual or legal entity that creates, contributes to
-    the creation of, or owns Covered Software.
-
-1.2. "Contributor Version"
-    means the combination of the Contributions of others (if any) used
-    by a Contributor and that particular Contributor's Contribution.
-
-1.3. "Contribution"
-    means Covered Software of a particular Contributor.
-
-1.4. "Covered Software"
-    means Source Code Form to which the initial Contributor has attached
-    the notice in Exhibit A, the Executable Form of such Source Code
-    Form, and Modifications of such Source Code Form, in each case
-    including portions thereof.
-
-1.5. "Incompatible With Secondary Licenses"
-    means
-
-    (a) that the initial Contributor has attached the notice described
-        in Exhibit B to the Covered Software; or
-
-    (b) that the Covered Software was made available under the terms of
-        version 1.1 or earlier of the License, but not also under the
-        terms of a Secondary License.
-
-1.6. "Executable Form"
-    means any form of the work other than Source Code Form.
-
-1.7. "Larger Work"
-    means a work that combines Covered Software with other material, in
-    a separate file or files, that is not Covered Software.
-
-1.8. "License"
-    means this document.
-
-1.9. "Licensable"
-    means having the right to grant, to the maximum extent possible,
-    whether at the time of the initial grant or subsequently, any and
-    all of the rights conveyed by this License.
-
-1.10. "Modifications"
-    means any of the following:
-
-    (a) any file in Source Code Form that results from an addition to,
-        deletion from, or modification of the contents of Covered
-        Software; or
-
-    (b) any new file in Source Code Form that contains any Covered
-        Software.
-
-1.11. "Patent Claims" of a Contributor
-    means any patent claim(s), including without limitation, method,
-    process, and apparatus claims, in any patent Licensable by such
-    Contributor that would be infringed, but for the grant of the
-    License, by the making, using, selling, offering for sale, having
-    made, import, or transfer of either its Contributions or its
-    Contributor Version.
-
-1.12. "Secondary License"
-    means either the GNU General Public License, Version 2.0, the GNU
-    Lesser General Public License, Version 2.1, the GNU Affero General
-    Public License, Version 3.0, or any later versions of those
-    licenses.
-
-1.13. "Source Code Form"
-    means the form of the work preferred for making modifications.
-
-1.14. "You" (or "Your")
-    means an individual or a legal entity exercising rights under this
-    License. For legal entities, "You" includes any entity that
-    controls, is controlled by, or is under common control with You. For
-    purposes of this definition, "control" means (a) the power, direct
-    or indirect, to cause the direction or management of such entity,
-    whether by contract or otherwise, or (b) ownership of more than
-    fifty percent (50%) of the outstanding shares or beneficial
-    ownership of such entity.
-
-2. License Grants and Conditions
---------------------------------
-
-2.1. Grants
-
-Each Contributor hereby grants You a world-wide, royalty-free,
-non-exclusive license:
-
-(a) under intellectual property rights (other than patent or trademark)
-    Licensable by such Contributor to use, reproduce, make available,
-    modify, display, perform, distribute, and otherwise exploit its
-    Contributions, either on an unmodified basis, with Modifications, or
-    as part of a Larger Work; and
-
-(b) under Patent Claims of such Contributor to make, use, sell, offer
-    for sale, have made, import, and otherwise transfer either its
-    Contributions or its Contributor Version.
-
-2.2. Effective Date
-
-The licenses granted in Section 2.1 with respect to any Contribution
-become effective for each Contribution on the date the Contributor first
-distributes such Contribution.
-
-2.3. Limitations on Grant Scope
-
-The licenses granted in this Section 2 are the only rights granted under
-this License. No additional rights or licenses will be implied from the
-distribution or licensing of Covered Software under this License.
-Notwithstanding Section 2.1(b) above, no patent license is granted by a
-Contributor:
-
-(a) for any code that a Contributor has removed from Covered Software;
-    or
-
-(b) for infringements caused by: (i) Your and any other third party's
-    modifications of Covered Software, or (ii) the combination of its
-    Contributions with other software (except as part of its Contributor
-    Version); or
-
-(c) under Patent Claims infringed by Covered Software in the absence of
-    its Contributions.
-
-This License does not grant any rights in the trademarks, service marks,
-or logos of any Contributor (except as may be necessary to comply with
-the notice requirements in Section 3.4).
-
-2.4. Subsequent Licenses
-
-No Contributor makes additional grants as a result of Your choice to
-distribute the Covered Software under a subsequent version of this
-License (see Section 10.2) or under the terms of a Secondary License (if
-permitted under the terms of Section 3.3).
-
-2.5. Representation
-
-Each Contributor represents that the Contributor believes its
-Contributions are its original creation(s) or it has sufficient rights
-to grant the rights to its Contributions conveyed by this License.
-
-2.6. Fair Use
-
-This License is not intended to limit any rights You have under
-applicable copyright doctrines of fair use, fair dealing, or other
-equivalents.
-
-2.7. Conditions
-
-Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
-in Section 2.1.
-
-3. Responsibilities
--------------------
-
-3.1. Distribution of Source Form
-
-All distribution of Covered Software in Source Code Form, including any
-Modifications that You create or to which You contribute, must be under
-the terms of this License. You must inform recipients that the Source
-Code Form of the Covered Software is governed by the terms of this
-License, and how they can obtain a copy of this License. You may not
-attempt to alter or restrict the recipients' rights in the Source Code
-Form.
-
-3.2. Distribution of Executable Form
-
-If You distribute Covered Software in Executable Form then:
-
-(a) such Covered Software must also be made available in Source Code
-    Form, as described in Section 3.1, and You must inform recipients of
-    the Executable Form how they can obtain a copy of such Source Code
-    Form by reasonable means in a timely manner, at a charge no more
-    than the cost of distribution to the recipient; and
-
-(b) You may distribute such Executable Form under the terms of this
-    License, or sublicense it under different terms, provided that the
-    license for the Executable Form does not attempt to limit or alter
-    the recipients' rights in the Source Code Form under this License.
-
-3.3. Distribution of a Larger Work
-
-You may create and distribute a Larger Work under terms of Your choice,
-provided that You also comply with the requirements of this License for
-the Covered Software. If the Larger Work is a combination of Covered
-Software with a work governed by one or more Secondary Licenses, and the
-Covered Software is not Incompatible With Secondary Licenses, this
-License permits You to additionally distribute such Covered Software
-under the terms of such Secondary License(s), so that the recipient of
-the Larger Work may, at their option, further distribute the Covered
-Software under the terms of either this License or such Secondary
-License(s).
-
-3.4. Notices
-
-You may not remove or alter the substance of any license notices
-(including copyright notices, patent notices, disclaimers of warranty,
-or limitations of liability) contained within the Source Code Form of
-the Covered Software, except that You may alter any license notices to
-the extent required to remedy known factual inaccuracies.
-
-3.5. Application of Additional Terms
-
-You may choose to offer, and to charge a fee for, warranty, support,
-indemnity or liability obligations to one or more recipients of Covered
-Software. However, You may do so only on Your own behalf, and not on
-behalf of any Contributor. You must make it absolutely clear that any
-such warranty, support, indemnity, or liability obligation is offered by
-You alone, and You hereby agree to indemnify every Contributor for any
-liability incurred by such Contributor as a result of warranty, support,
-indemnity or liability terms You offer. You may include additional
-disclaimers of warranty and limitations of liability specific to any
-jurisdiction.
-
-4. Inability to Comply Due to Statute or Regulation
----------------------------------------------------
-
-If it is impossible for You to comply with any of the terms of this
-License with respect to some or all of the Covered Software due to
-statute, judicial order, or regulation then You must: (a) comply with
-the terms of this License to the maximum extent possible; and (b)
-describe the limitations and the code they affect. Such description must
-be placed in a text file included with all distributions of the Covered
-Software under this License. Except to the extent prohibited by statute
-or regulation, such description must be sufficiently detailed for a
-recipient of ordinary skill to be able to understand it.
-
-5. Termination
---------------
-
-5.1. The rights granted under this License will terminate automatically
-if You fail to comply with any of its terms. However, if You become
-compliant, then the rights granted under this License from a particular
-Contributor are reinstated (a) provisionally, unless and until such
-Contributor explicitly and finally terminates Your grants, and (b) on an
-ongoing basis, if such Contributor fails to notify You of the
-non-compliance by some reasonable means prior to 60 days after You have
-come back into compliance. Moreover, Your grants from a particular
-Contributor are reinstated on an ongoing basis if such Contributor
-notifies You of the non-compliance by some reasonable means, this is the
-first time You have received notice of non-compliance with this License
-from such Contributor, and You become compliant prior to 30 days after
-Your receipt of the notice.
-
-5.2. If You initiate litigation against any entity by asserting a patent
-infringement claim (excluding declaratory judgment actions,
-counter-claims, and cross-claims) alleging that a Contributor Version
-directly or indirectly infringes any patent, then the rights granted to
-You by any and all Contributors for the Covered Software under Section
-2.1 of this License shall terminate.
-
-5.3. In the event of termination under Sections 5.1 or 5.2 above, all
-end user license agreements (excluding distributors and resellers) which
-have been validly granted by You or Your distributors under this License
-prior to termination shall survive termination.
-
-************************************************************************
-*                                                                      *
-*  6. Disclaimer of Warranty                                           *
-*  -------------------------                                           *
-*                                                                      *
-*  Covered Software is provided under this License on an "as is"       *
-*  basis, without warranty of any kind, either expressed, implied, or  *
-*  statutory, including, without limitation, warranties that the       *
-*  Covered Software is free of defects, merchantable, fit for a        *
-*  particular purpose or non-infringing. The entire risk as to the     *
-*  quality and performance of the Covered Software is with You.        *
-*  Should any Covered Software prove defective in any respect, You     *
-*  (not any Contributor) assume the cost of any necessary servicing,   *
-*  repair, or correction. This disclaimer of warranty constitutes an   *
-*  essential part of this License. No use of any Covered Software is   *
-*  authorized under this License except under this disclaimer.         *
-*                                                                      *
-************************************************************************
-
-************************************************************************
-*                                                                      *
-*  7. Limitation of Liability                                          *
-*  --------------------------                                          *
-*                                                                      *
-*  Under no circumstances and under no legal theory, whether tort      *
-*  (including negligence), contract, or otherwise, shall any           *
-*  Contributor, or anyone who distributes Covered Software as          *
-*  permitted above, be liable to You for any direct, indirect,         *
-*  special, incidental, or consequential damages of any character      *
-*  including, without limitation, damages for lost profits, loss of    *
-*  goodwill, work stoppage, computer failure or malfunction, or any    *
-*  and all other commercial damages or losses, even if such party      *
-*  shall have been informed of the possibility of such damages. This   *
-*  limitation of liability shall not apply to liability for death or   *
-*  personal injury resulting from such party's negligence to the       *
-*  extent applicable law prohibits such limitation. Some               *
-*  jurisdictions do not allow the exclusion or limitation of           *
-*  incidental or consequential damages, so this exclusion and          *
-*  limitation may not apply to You.                                    *
-*                                                                      *
-************************************************************************
-
-8. Litigation
--------------
-
-Any litigation relating to this License may be brought only in the
-courts of a jurisdiction where the defendant maintains its principal
-place of business and such litigation shall be governed by laws of that
-jurisdiction, without reference to its conflict-of-law provisions.
-Nothing in this Section shall prevent a party's ability to bring
-cross-claims or counter-claims.
-
-9. Miscellaneous
-----------------
-
-This License represents the complete agreement concerning the subject
-matter hereof. If any provision of this License is held to be
-unenforceable, such provision shall be reformed only to the extent
-necessary to make it enforceable. Any law or regulation which provides
-that the language of a contract shall be construed against the drafter
-shall not be used to construe this License against a Contributor.
-
-10. Versions of the License
----------------------------
-
-10.1. New Versions
-
-Mozilla Foundation is the license steward. Except as provided in Section
-10.3, no one other than the license steward has the right to modify or
-publish new versions of this License. Each version will be given a
-distinguishing version number.
-
-10.2. Effect of New Versions
-
-You may distribute the Covered Software under the terms of the version
-of the License under which You originally received the Covered Software,
-or under the terms of any subsequent version published by the license
-steward.
-
-10.3. Modified Versions
-
-If you create software not governed by this License, and you want to
-create a new license for such software, you may create and use a
-modified version of this License if you rename the license and remove
-any references to the name of the license steward (except to note that
-such modified license differs from this License).
-
-10.4. Distributing Source Code Form that is Incompatible With Secondary
-Licenses
-
-If You choose to distribute Source Code Form that is Incompatible With
-Secondary Licenses under the terms of this version of the License, the
-notice described in Exhibit B of this License must be attached.
-
-Exhibit A - Source Code Form License Notice
--------------------------------------------
-
-  This Source Code Form is subject to the terms of the Mozilla Public
-  License, v. 2.0. If a copy of the MPL was not distributed with this
-  file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-If it is not possible or desirable to put the notice in a particular
-file, then You may include the notice in a location (such as a LICENSE
-file in a relevant directory) where a recipient would be likely to look
-for such a notice.
-
-You may add additional accurate notices of copyright ownership.
-
-Exhibit B - "Incompatible With Secondary Licenses" Notice
----------------------------------------------------------
-
-  This Source Code Form is "Incompatible With Secondary Licenses", as
-  defined by the Mozilla Public License, v. 2.0.
+Mozilla Public License Version 2.0
+==================================
+
+1. Definitions
+--------------
+
+1.1. "Contributor"
+    means each individual or legal entity that creates, contributes to
+    the creation of, or owns Covered Software.
+
+1.2. "Contributor Version"
+    means the combination of the Contributions of others (if any) used
+    by a Contributor and that particular Contributor's Contribution.
+
+1.3. "Contribution"
+    means Covered Software of a particular Contributor.
+
+1.4. "Covered Software"
+    means Source Code Form to which the initial Contributor has attached
+    the notice in Exhibit A, the Executable Form of such Source Code
+    Form, and Modifications of such Source Code Form, in each case
+    including portions thereof.
+
+1.5. "Incompatible With Secondary Licenses"
+    means
+
+    (a) that the initial Contributor has attached the notice described
+        in Exhibit B to the Covered Software; or
+
+    (b) that the Covered Software was made available under the terms of
+        version 1.1 or earlier of the License, but not also under the
+        terms of a Secondary License.
+
+1.6. "Executable Form"
+    means any form of the work other than Source Code Form.
+
+1.7. "Larger Work"
+    means a work that combines Covered Software with other material, in
+    a separate file or files, that is not Covered Software.
+
+1.8. "License"
+    means this document.
+
+1.9. "Licensable"
+    means having the right to grant, to the maximum extent possible,
+    whether at the time of the initial grant or subsequently, any and
+    all of the rights conveyed by this License.
+
+1.10. "Modifications"
+    means any of the following:
+
+    (a) any file in Source Code Form that results from an addition to,
+        deletion from, or modification of the contents of Covered
+        Software; or
+
+    (b) any new file in Source Code Form that contains any Covered
+        Software.
+
+1.11. "Patent Claims" of a Contributor
+    means any patent claim(s), including without limitation, method,
+    process, and apparatus claims, in any patent Licensable by such
+    Contributor that would be infringed, but for the grant of the
+    License, by the making, using, selling, offering for sale, having
+    made, import, or transfer of either its Contributions or its
+    Contributor Version.
+
+1.12. "Secondary License"
+    means either the GNU General Public License, Version 2.0, the GNU
+    Lesser General Public License, Version 2.1, the GNU Affero General
+    Public License, Version 3.0, or any later versions of those
+    licenses.
+
+1.13. "Source Code Form"
+    means the form of the work preferred for making modifications.
+
+1.14. "You" (or "Your")
+    means an individual or a legal entity exercising rights under this
+    License. For legal entities, "You" includes any entity that
+    controls, is controlled by, or is under common control with You. For
+    purposes of this definition, "control" means (a) the power, direct
+    or indirect, to cause the direction or management of such entity,
+    whether by contract or otherwise, or (b) ownership of more than
+    fifty percent (50%) of the outstanding shares or beneficial
+    ownership of such entity.
+
+2. License Grants and Conditions
+--------------------------------
+
+2.1. Grants
+
+Each Contributor hereby grants You a world-wide, royalty-free,
+non-exclusive license:
+
+(a) under intellectual property rights (other than patent or trademark)
+    Licensable by such Contributor to use, reproduce, make available,
+    modify, display, perform, distribute, and otherwise exploit its
+    Contributions, either on an unmodified basis, with Modifications, or
+    as part of a Larger Work; and
+
+(b) under Patent Claims of such Contributor to make, use, sell, offer
+    for sale, have made, import, and otherwise transfer either its
+    Contributions or its Contributor Version.
+
+2.2. Effective Date
+
+The licenses granted in Section 2.1 with respect to any Contribution
+become effective for each Contribution on the date the Contributor first
+distributes such Contribution.
+
+2.3. Limitations on Grant Scope
+
+The licenses granted in this Section 2 are the only rights granted under
+this License. No additional rights or licenses will be implied from the
+distribution or licensing of Covered Software under this License.
+Notwithstanding Section 2.1(b) above, no patent license is granted by a
+Contributor:
+
+(a) for any code that a Contributor has removed from Covered Software;
+    or
+
+(b) for infringements caused by: (i) Your and any other third party's
+    modifications of Covered Software, or (ii) the combination of its
+    Contributions with other software (except as part of its Contributor
+    Version); or
+
+(c) under Patent Claims infringed by Covered Software in the absence of
+    its Contributions.
+
+This License does not grant any rights in the trademarks, service marks,
+or logos of any Contributor (except as may be necessary to comply with
+the notice requirements in Section 3.4).
+
+2.4. Subsequent Licenses
+
+No Contributor makes additional grants as a result of Your choice to
+distribute the Covered Software under a subsequent version of this
+License (see Section 10.2) or under the terms of a Secondary License (if
+permitted under the terms of Section 3.3).
+
+2.5. Representation
+
+Each Contributor represents that the Contributor believes its
+Contributions are its original creation(s) or it has sufficient rights
+to grant the rights to its Contributions conveyed by this License.
+
+2.6. Fair Use
+
+This License is not intended to limit any rights You have under
+applicable copyright doctrines of fair use, fair dealing, or other
+equivalents.
+
+2.7. Conditions
+
+Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
+in Section 2.1.
+
+3. Responsibilities
+-------------------
+
+3.1. Distribution of Source Form
+
+All distribution of Covered Software in Source Code Form, including any
+Modifications that You create or to which You contribute, must be under
+the terms of this License. You must inform recipients that the Source
+Code Form of the Covered Software is governed by the terms of this
+License, and how they can obtain a copy of this License. You may not
+attempt to alter or restrict the recipients' rights in the Source Code
+Form.
+
+3.2. Distribution of Executable Form
+
+If You distribute Covered Software in Executable Form then:
+
+(a) such Covered Software must also be made available in Source Code
+    Form, as described in Section 3.1, and You must inform recipients of
+    the Executable Form how they can obtain a copy of such Source Code
+    Form by reasonable means in a timely manner, at a charge no more
+    than the cost of distribution to the recipient; and
+
+(b) You may distribute such Executable Form under the terms of this
+    License, or sublicense it under different terms, provided that the
+    license for the Executable Form does not attempt to limit or alter
+    the recipients' rights in the Source Code Form under this License.
+
+3.3. Distribution of a Larger Work
+
+You may create and distribute a Larger Work under terms of Your choice,
+provided that You also comply with the requirements of this License for
+the Covered Software. If the Larger Work is a combination of Covered
+Software with a work governed by one or more Secondary Licenses, and the
+Covered Software is not Incompatible With Secondary Licenses, this
+License permits You to additionally distribute such Covered Software
+under the terms of such Secondary License(s), so that the recipient of
+the Larger Work may, at their option, further distribute the Covered
+Software under the terms of either this License or such Secondary
+License(s).
+
+3.4. Notices
+
+You may not remove or alter the substance of any license notices
+(including copyright notices, patent notices, disclaimers of warranty,
+or limitations of liability) contained within the Source Code Form of
+the Covered Software, except that You may alter any license notices to
+the extent required to remedy known factual inaccuracies.
+
+3.5. Application of Additional Terms
+
+You may choose to offer, and to charge a fee for, warranty, support,
+indemnity or liability obligations to one or more recipients of Covered
+Software. However, You may do so only on Your own behalf, and not on
+behalf of any Contributor. You must make it absolutely clear that any
+such warranty, support, indemnity, or liability obligation is offered by
+You alone, and You hereby agree to indemnify every Contributor for any
+liability incurred by such Contributor as a result of warranty, support,
+indemnity or liability terms You offer. You may include additional
+disclaimers of warranty and limitations of liability specific to any
+jurisdiction.
+
+4. Inability to Comply Due to Statute or Regulation
+---------------------------------------------------
+
+If it is impossible for You to comply with any of the terms of this
+License with respect to some or all of the Covered Software due to
+statute, judicial order, or regulation then You must: (a) comply with
+the terms of this License to the maximum extent possible; and (b)
+describe the limitations and the code they affect. Such description must
+be placed in a text file included with all distributions of the Covered
+Software under this License. Except to the extent prohibited by statute
+or regulation, such description must be sufficiently detailed for a
+recipient of ordinary skill to be able to understand it.
+
+5. Termination
+--------------
+
+5.1. The rights granted under this License will terminate automatically
+if You fail to comply with any of its terms. However, if You become
+compliant, then the rights granted under this License from a particular
+Contributor are reinstated (a) provisionally, unless and until such
+Contributor explicitly and finally terminates Your grants, and (b) on an
+ongoing basis, if such Contributor fails to notify You of the
+non-compliance by some reasonable means prior to 60 days after You have
+come back into compliance. Moreover, Your grants from a particular
+Contributor are reinstated on an ongoing basis if such Contributor
+notifies You of the non-compliance by some reasonable means, this is the
+first time You have received notice of non-compliance with this License
+from such Contributor, and You become compliant prior to 30 days after
+Your receipt of the notice.
+
+5.2. If You initiate litigation against any entity by asserting a patent
+infringement claim (excluding declaratory judgment actions,
+counter-claims, and cross-claims) alleging that a Contributor Version
+directly or indirectly infringes any patent, then the rights granted to
+You by any and all Contributors for the Covered Software under Section
+2.1 of this License shall terminate.
+
+5.3. In the event of termination under Sections 5.1 or 5.2 above, all
+end user license agreements (excluding distributors and resellers) which
+have been validly granted by You or Your distributors under this License
+prior to termination shall survive termination.
+
+************************************************************************
+*                                                                      *
+*  6. Disclaimer of Warranty                                           *
+*  -------------------------                                           *
+*                                                                      *
+*  Covered Software is provided under this License on an "as is"       *
+*  basis, without warranty of any kind, either expressed, implied, or  *
+*  statutory, including, without limitation, warranties that the       *
+*  Covered Software is free of defects, merchantable, fit for a        *
+*  particular purpose or non-infringing. The entire risk as to the     *
+*  quality and performance of the Covered Software is with You.        *
+*  Should any Covered Software prove defective in any respect, You     *
+*  (not any Contributor) assume the cost of any necessary servicing,   *
+*  repair, or correction. This disclaimer of warranty constitutes an   *
+*  essential part of this License. No use of any Covered Software is   *
+*  authorized under this License except under this disclaimer.         *
+*                                                                      *
+************************************************************************
+
+************************************************************************
+*                                                                      *
+*  7. Limitation of Liability                                          *
+*  --------------------------                                          *
+*                                                                      *
+*  Under no circumstances and under no legal theory, whether tort      *
+*  (including negligence), contract, or otherwise, shall any           *
+*  Contributor, or anyone who distributes Covered Software as          *
+*  permitted above, be liable to You for any direct, indirect,         *
+*  special, incidental, or consequential damages of any character      *
+*  including, without limitation, damages for lost profits, loss of    *
+*  goodwill, work stoppage, computer failure or malfunction, or any    *
+*  and all other commercial damages or losses, even if such party      *
+*  shall have been informed of the possibility of such damages. This   *
+*  limitation of liability shall not apply to liability for death or   *
+*  personal injury resulting from such party's negligence to the       *
+*  extent applicable law prohibits such limitation. Some               *
+*  jurisdictions do not allow the exclusion or limitation of           *
+*  incidental or consequential damages, so this exclusion and          *
+*  limitation may not apply to You.                                    *
+*                                                                      *
+************************************************************************
+
+8. Litigation
+-------------
+
+Any litigation relating to this License may be brought only in the
+courts of a jurisdiction where the defendant maintains its principal
+place of business and such litigation shall be governed by laws of that
+jurisdiction, without reference to its conflict-of-law provisions.
+Nothing in this Section shall prevent a party's ability to bring
+cross-claims or counter-claims.
+
+9. Miscellaneous
+----------------
+
+This License represents the complete agreement concerning the subject
+matter hereof. If any provision of this License is held to be
+unenforceable, such provision shall be reformed only to the extent
+necessary to make it enforceable. Any law or regulation which provides
+that the language of a contract shall be construed against the drafter
+shall not be used to construe this License against a Contributor.
+
+10. Versions of the License
+---------------------------
+
+10.1. New Versions
+
+Mozilla Foundation is the license steward. Except as provided in Section
+10.3, no one other than the license steward has the right to modify or
+publish new versions of this License. Each version will be given a
+distinguishing version number.
+
+10.2. Effect of New Versions
+
+You may distribute the Covered Software under the terms of the version
+of the License under which You originally received the Covered Software,
+or under the terms of any subsequent version published by the license
+steward.
+
+10.3. Modified Versions
+
+If you create software not governed by this License, and you want to
+create a new license for such software, you may create and use a
+modified version of this License if you rename the license and remove
+any references to the name of the license steward (except to note that
+such modified license differs from this License).
+
+10.4. Distributing Source Code Form that is Incompatible With Secondary
+Licenses
+
+If You choose to distribute Source Code Form that is Incompatible With
+Secondary Licenses under the terms of this version of the License, the
+notice described in Exhibit B of this License must be attached.
+
+Exhibit A - Source Code Form License Notice
+-------------------------------------------
+
+  This Source Code Form is subject to the terms of the Mozilla Public
+  License, v. 2.0. If a copy of the MPL was not distributed with this
+  file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+If it is not possible or desirable to put the notice in a particular
+file, then You may include the notice in a location (such as a LICENSE
+file in a relevant directory) where a recipient would be likely to look
+for such a notice.
+
+You may add additional accurate notices of copyright ownership.
+
+Exhibit B - "Incompatible With Secondary Licenses" Notice
+---------------------------------------------------------
+
+  This Source Code Form is "Incompatible With Secondary Licenses", as
+  defined by the Mozilla Public License, v. 2.0.
diff -Nru tbsync-4.12/_locales/bg/messages.json tbsync-4.16/_locales/bg/messages.json
--- tbsync-4.12/_locales/bg/messages.json	2024-08-27 18:32:08.000000000 +0200
+++ tbsync-4.16/_locales/bg/messages.json	2024-08-27 18:29:06.000000000 +0200
@@ -1,368 +1,368 @@
-{
-    "HelpFixStartupError": {
-        "message": "?? ???????????? ?? ???? ?????? ???? ?? ????????? ?????? ?? ????????????. ??????? ?? ?? ?? ??????? ??????? ?? ??????????"
-    },
-    "NoDebugLog": {
-        "message": "??????? ?????????? ????????????? ?????????. ???????? ?????? ?? ???????? ?????????????, ????????????? Thunderbird ? ????????? ?????? ?????? ?? ?? ?? ?????? ?????? ?? ??????."
-    },
-    "OopsMessage": {
-        "message": "????! TbSync ?? ???? ?? ?? ??????!"
-    },
-    "RestartThunderbirdAndTryAgain": {
-        "message": "??????? ?? ???????? ????????????? ?? ????????? ? ???????. ????????????? Thunderbird ? ???????? ?? ???????? ?????? TbSync."
-    },
-    "UnableToTraceError": {
-        "message": "?? ? ???????? ?? ?? ???????? ????????, ??? ???? ?? ?????? ???????? ?? ?????????????. ??????? ?? ?? ??????? ???????? ????????????? ?? ?????????, ?? ?? ???? ???????? ?? ?? ????????? ? ?????????"
-    },
-    "accountacctions.delete": {
-        "message": "????????? ?? ??????????? '##accountname##'"
-    },
-    "accountacctions.disable": {
-        "message": "?????????? ?? ??????????? '##accountname##'"
-    },
-    "accountacctions.enable": {
-        "message": "????????? ?? ??????????? '##accountname##' ? ????????? ??? ???????"
-    },
-    "accountacctions.sync": {
-        "message": "?????????????? ?? ??????????? '##accountname##'"
-    },
-    "addressbook.searchall": {
-        "message": "??????????? ?? ?????? ??????? ?????????"
-    },
-    "addressbook.searchgal": {
-        "message": "??????????? ?? ???? ??????? ???????? ? ?? ????????? ???????? ?? ??????? (##replace.1##)"
-    },
-    "addressbook.searchthis": {
-        "message": "??????????? ?? ???? ??????? ????????"
-    },
-    "eventlog.clear": {
-        "message": "??????????"
-    },
-    "eventlog.close": {
-        "message": "?????????"
-    },
-    "eventlog.title": {
-        "message": "???????? ?? ?????????"
-    },
-    "extensionDescription": {
-        "message": "TbSync ? ??????? ?? ?????????? ?? ??????????? ? ?????????????? ??? ??????? ?? ?????? ????????, ?????? ? ??????? ? Thunderbird."
-    },
-    "google.translate.code": {
-        "message": "bg"
-    },
-    "helplink.security": {
-        "message": "https://github.com/jobisoft/TbSync/wiki/How-to-use-TbSync-with-self-signed-or-otherwise-untrusted-certificates%3F"
-    },
-    "info.error": {
-        "message": "??????"
-    },
-    "info.idle": {
-        "message": "?????? ???"
-    },
-    "installProvider.header": {
-        "message": "????????? '##replace.1##' ?? TbSync ?? ? ??????????."
-    },
-    "manager.AccountActions": {
-        "message": "???????? ? ?????????????"
-    },
-    "manager.AddAccount": {
-        "message": "???????? ?? ???????????"
-    },
-    "manager.DeleteAccount": {
-        "message": "????????? ?? ?????????????"
-    },
-    "manager.DisableAccount": {
-        "message": "?????????? ?? ?????????????"
-    },
-    "manager.EnableAccount": {
-        "message": "????????? ?? ????????????? ? ????????? ??? ???????"
-    },
-    "manager.RetryConnectAccount": {
-        "message": "?????? ?????? ?? ?? ??????? ??? ???????"
-    },
-    "manager.ShowEventLog": {
-        "message": "????????? ?? ????????? ??? ?????????"
-    },
-    "manager.SyncAll": {
-        "message": "?????????????? ?? ?????? ???????? ???????????"
-    },
-    "manager.SynchronizeAccount": {
-        "message": "?????????????? ?? ?????????????"
-    },
-    "manager.accounts": {
-        "message": "???????????"
-    },
-    "manager.accountsettings": {
-        "message": "????????? ?? ?????????????"
-    },
-    "manager.catman.text": {
-        "message": "TbSync ???????????? ? ????????? ????????, ????? ?? ?????????? ?? ?????????????????? ??????? ? ???????? ?? Thunderbird. ?? ?? ????????? ????????????? ?? ???????? ???????? ?? Thunderbird, ???????????? ????????? ?Category Manager?. ?? ????????? ?????????? ?? ???????? ? ????? ????????? / ????? ? ??. ????????? ???? ?? ?? ????????? ?? ??????????? ???? ?? ??????? ?? Mozilla:"
-    },
-    "manager.community": {
-        "message": "????????/???????????"
-    },
-    "manager.connecting": {
-        "message": "????????????? ?? ??????"
-    },
-    "manager.help": {
-        "message": "?????"
-    },
-    "manager.help.createbugreport": {
-        "message": "????????? ?? ?????? ?? ??????"
-    },
-    "manager.help.createbugreportinfo": {
-        "message": "?? ?? ?????? TbSync ?????????? ????????????, ????? ?? ?????? ?? ????????, ????????????? Thunderbird, ? ????????? ????????, ?? ?? ?? ?????? ?????? ?? ??????. ?????? ???? ??? ?? ????????? ?????? ?? ????????."
-    },
-    "manager.help.debuglevel.0": {
-        "message": "?????????"
-    },
-    "manager.help.debuglevel.1": {
-        "message": "????????: ????????????? ???? ?? ??????"
-    },
-    "manager.help.debuglevel.2": {
-        "message": "????????: ????????????? ?? ?????? ????????? ? ???????? ?????"
-    },
-    "manager.help.debuglevel.3": {
-        "message": "????????: ????????????? ?? ?????? ????? ? ????? ??????????? ?? ???????????? ?? ??????"
-    },
-    "manager.help.debugmode": {
-        "message": "????? ?? ???????? ?????????????:"
-    },
-    "manager.help.fixit": {
-        "message": "???? ?? ????????? ?? ?????????????? ?, ???? ????????? ?? ???????????? ?????? ?? ????????. ?? ???? ? ?????????? ?? ???????? ?????? ?? ???????? ?????????????."
-    },
-    "manager.help.foundabug": {
-        "message": "???????? ?? ???????"
-    },
-    "manager.help.needhelp": {
-        "message": "?????? ?? ?? ??????"
-    },
-    "manager.help.viewdebuglog": {
-        "message": "?????? ????????? ????????"
-    },
-    "manager.help.wiki": {
-        "message": "???????? ???? ?????????? ?? ??????? TbSync, ?????? ??? ???????????? ??????????, ??????????? ?? ??????????? ? ???????? ???????? ?? ???????????."
-    },
-    "manager.installprovider.link": {
-        "message": "??????????? ??????????? ?? ?? ???????? ?????????? ?? ????????? TbSync ?????????. ??? ?? ???????? ???????????? ?????????? ?? ?????????? ? ???? ?? ?? ??????????? ?? ???:"
-    },
-    "manager.installprovider.warning": {
-        "message": "???? ????????? ?? ?????????? ?? ??????????? ???? ?? ??????? ?? Thunderbird ? ?? ? ??? ???????? ?? ????? ?? Thunderbird. ???? TbSync ????????? ?? ????? ?? ??????? ???????. ??????????? ?? ????????? ???????????."
-    },
-    "manager.lockedsettings.description": {
-        "message": "?? ?? ?? ???????? ?????? ?? ????? ?? ????????????????, ????? ????????? ?? ????? ?? ????? ?????????, ?????? ????????????? ? ????????."
-    },
-    "manager.missingprovider": {
-        "message": "???? ??????????? ??????? TbSync ?????????? ##provider##, ????? ?? ? ??????????."
-    },
-    "manager.noaccounts": {
-        "message": "??? ???? ????????? ???????????."
-    },
-    "manager.provider": {
-        "message": "??????????? ?? TbSync ?????????"
-    },
-    "manager.provider4tbsync": {
-        "message": "????????? ?? TbSync"
-    },
-    "manager.resource": {
-        "message": "??????"
-    },
-    "manager.shorttitle": {
-        "message": "?????????? ?? ?????????????"
-    },
-    "manager.status": {
-        "message": "??????"
-    },
-    "manager.supporter.contributors": {
-        "message": "???????????? ? ?????????"
-    },
-    "manager.supporter.details": {
-        "message": "???????????"
-    },
-    "manager.supporter.sponsors": {
-        "message": "???????????? ??????????? ?? ????????????"
-    },
-    "manager.tabs.status": {
-        "message": "????????? ?? ????????????????"
-    },
-    "manager.tabs.status.autotime": {
-        "message": "?????????? ?????????????? (? ??????)"
-    },
-    "manager.tabs.status.enableThisAccount": {
-        "message": "????????? ?? ????????????? ? ??????????????"
-    },
-    "manager.tabs.status.general": {
-        "message": "????"
-    },
-    "manager.tabs.status.never": {
-        "message": "???????? 0 ???????? ???????????? ??????????????. ????????? ?? ?????, ?????? ??? ?? ???????, ???? ?? ???? ?? ?? ??????????? ??????????? ?????????????."
-    },
-    "manager.tabs.status.resources": {
-        "message": "??????? ???????"
-    },
-    "manager.tabs.status.resources.intro": {
-        "message": "???????? ??? ?? ????????? ??????? ?? ?? ????????????? ? Thunderbird."
-    },
-    "manager.tabs.status.sync": {
-        "message": "????????????? ????"
-    },
-    "manager.tabs.status.tryagain": {
-        "message": "?????? ?????? ?? ?? ??????? ??? ???????"
-    },
-    "manager.title": {
-        "message": "TbSync ?????????? ?? ?????????????"
-    },
-    "manager.tryagain": {
-        "message": "?????? ?????? ?? ?? ??????? ??? ???????"
-    },
-    "menu.settingslabel": {
-        "message": "????????? ?? ??????????????? (TbSync)"
-    },
-    "password.account": {
-        "message": "???????????:"
-    },
-    "password.description": {
-        "message": "???? ????????? ??????? ?? ???????? TbSync ???????????:"
-    },
-    "password.password": {
-        "message": "??????:"
-    },
-    "password.title": {
-        "message": "TbSync ?????????? ?? ?????????????"
-    },
-    "password.user": {
-        "message": "????????????? ???:"
-    },
-    "popup.opensettings": {
-        "message": "?????? TbSync ???????????? ?? ?????????????"
-    },
-    "prompt.DeleteAccount": {
-        "message": "??????? ?? ???, ?? ?????? ?? ???????? ??????????? ##accountName##?"
-    },
-    "prompt.Disable": {
-        "message": "??????? ?? ???, ?? ?????? ?? ????????? ???? ???????????? ?????? ?????? ???????, ????? ??? ?? ?? ??????????????, ?? ?? ???????!"
-    },
-    "prompt.Erase": {
-        "message": "??????? ?? ???, ?? ???? ??????????? ?? ???????? ????????? ?????? ?? ? ?????????? ?? ??????? ? ????????????"
-    },
-    "prompt.Unsubscribe": {
-        "message": "??????? ?? ???, ?? ?? ???? ?????? ?? ??????? ?? ??? ?????? ????????? ?????? ?????? ???????, ????? ??? ?? ?? ??????????????, ?? ?? ???????!"
-    },
-    "status.JavaScriptError": {
-        "message": "Javascript ??????! ????????? ????????? ??? ????????? ?? ???????????."
-    },
-    "status.OAuthAbortError": {
-        "message": "???????? ?? OAuth 2.0 ??????????????? ???? ????????? ?? ???????????."
-    },
-    "status.OAuthHttpError": {
-        "message": "???????????????? ?? OAuth 2.0 ?? ????? (HTTP ?????? ##replace.1##)."
-    },
-    "status.OAuthNetworkError": {
-        "message": "?? ????? ?? ?? ?????? ? OAuth 2.0 ???????."
-    },
-    "status.OAuthServerError": {
-        "message": " OAuth 2.0 ???????? ??????? ? ##replace.1##"
-    },
-    "status.aborted": {
-        "message": "?? ? ?????????????"
-    },
-    "status.apiError": {
-        "message": "API ?????? ??? ??????????????"
-    },
-    "status.disabled": {
-        "message": "????????????? ? ??????????????? ?? ?????????."
-    },
-    "status.foldererror": {
-        "message": "???? ??? ???? ?????? ?? ????? ?????? ??? ????????????????. ????????? ????????? ??? ??????? ?? ???????????."
-    },
-    "status.modified": {
-        "message": "?????? ???????"
-    },
-    "status.network": {
-        "message": "?? ?????? ?? ?? ???????? ?????? ??? ??????? (##replace.1##)."
-    },
-    "status.no-folders-found-on-server": {
-        "message": "?? ??????? ?? ???? ???????? ???????."
-    },
-    "status.notargets": {
-        "message": "???????????????? ????????, ??? ???? ?? ????????? ?? ?? ?????? ?? ?? ???????? ???? ???????."
-    },
-    "status.notsyncronized": {
-        "message": "????????????? ?????? ?? ???? ????????????."
-    },
-    "status.pending": {
-        "message": "?????? ?? ?????????????"
-    },
-    "status.security": {
-        "message": "?????? ??? ??????????????? ?? ???????? ??????. ?????????? ?? ?????????????? ???????? ?????????? ??? ??????????, ?? ????? Thunderbird ???? ???????? (##replace.1##)"
-    },
-    "status.skipped": {
-        "message": "?? ?? ????????, ??????????"
-    },
-    "status.success": {
-        "message": "?????"
-    },
-    "status.syncing": {
-        "message": "??????????????"
-    },
-    "status.451": {
-        "message": "Server issued redirect, retry in 5 seconds."
-    },
-    "supportwizard.footer": {
-        "message": "?? ???? ?????????? ?? ?????????? ?????? ?? ?? ?????? ??????????? ?????, ????? ?????? ?? ????????? (???????? ?? ???????? ?????? ?? ??????). ???? ???? ????????? ?? ???????, ???????? ?? ?????? ?? ??????."
-    },
-    "supportwizard.label.description": {
-        "message": "???????? ???????? ?? ????????:"
-    },
-    "supportwizard.label.faultycomponent": {
-        "message": "?????????? ?? TbSync, ??? ????? ???????????? ????????:"
-    },
-    "supportwizard.label.selectcomponent": {
-        "message": "???????? ???????????"
-    },
-    "supportwizard.label.summary": {
-        "message": "????????? ?? ????????:"
-    },
-    "supportwizard.pagetitle": {
-        "message": "???????? ?? ???????? ?????????? ?? ?? ???? ?? ???? ?? ??????? ?? ?????? ?? ?? ??????? ????? ????."
-    },
-    "supportwizard.provider": {
-        "message": "?????????: ##replace.1##"
-    },
-    "supportwizard.title": {
-        "message": "????????? ?? ?????? ?? ??????"
-    },
-    "syncstate.accountdone": {
-        "message": "???????????????? ?? ????????????? ????????"
-    },
-    "syncstate.done": {
-        "message": "?????????? ?? ????????? ?????? ?? ?????????????"
-    },
-    "syncstate.oauthprompt": {
-        "message": "OAuth 2.0 ??????????????"
-    },
-    "syncstate.passwordprompt": {
-        "message": "??????? ?? ????????? ?? ?????????? ?? ???????????"
-    },
-    "syncstate.preparing": {
-        "message": "?????????? ?? ????????? ?????? ?? ?????????????"
-    },
-    "syncstate.syncing": {
-        "message": "????????? ?? ???????????????"
-    },
-    "target.orphaned": {
-        "message": "?????????? ??????"
-    },
-    "toolbar.label": {
-        "message": "????????????? ?????? TbSync ???????????"
-    },
-    "toolbar.tooltiptext": {
-        "message": "????????????? ???????????? ?? ?????? TbSync ??????????? ??? ?????????"
-    },
-    "password.ok": {
-        "message": "?????"
-    },
-    "password.cancel": {
-        "message": "?????"
-    }
-}
+{
+    "HelpFixStartupError": {
+        "message": "?? ???????????? ?? ???? ?????? ???? ?? ????????? ?????? ?? ????????????. ??????? ?? ?? ?? ??????? ??????? ?? ??????????"
+    },
+    "NoDebugLog": {
+        "message": "??????? ?????????? ????????????? ?????????. ???????? ?????? ?? ???????? ?????????????, ????????????? Thunderbird ? ????????? ?????? ?????? ?? ?? ?? ?????? ?????? ?? ??????."
+    },
+    "OopsMessage": {
+        "message": "????! TbSync ?? ???? ?? ?? ??????!"
+    },
+    "RestartThunderbirdAndTryAgain": {
+        "message": "??????? ?? ???????? ????????????? ?? ????????? ? ???????. ????????????? Thunderbird ? ???????? ?? ???????? ?????? TbSync."
+    },
+    "UnableToTraceError": {
+        "message": "?? ? ???????? ?? ?? ???????? ????????, ??? ???? ?? ?????? ???????? ?? ?????????????. ??????? ?? ?? ??????? ???????? ????????????? ?? ?????????, ?? ?? ???? ???????? ?? ?? ????????? ? ?????????"
+    },
+    "accountacctions.delete": {
+        "message": "????????? ?? ??????????? '##accountname##'"
+    },
+    "accountacctions.disable": {
+        "message": "?????????? ?? ??????????? '##accountname##'"
+    },
+    "accountacctions.enable": {
+        "message": "????????? ?? ??????????? '##accountname##' ? ????????? ??? ???????"
+    },
+    "accountacctions.sync": {
+        "message": "?????????????? ?? ??????????? '##accountname##'"
+    },
+    "addressbook.searchall": {
+        "message": "??????????? ?? ?????? ??????? ?????????"
+    },
+    "addressbook.searchgal": {
+        "message": "??????????? ?? ???? ??????? ???????? ? ?? ????????? ???????? ?? ??????? (##replace.1##)"
+    },
+    "addressbook.searchthis": {
+        "message": "??????????? ?? ???? ??????? ????????"
+    },
+    "eventlog.clear": {
+        "message": "??????????"
+    },
+    "eventlog.close": {
+        "message": "?????????"
+    },
+    "eventlog.title": {
+        "message": "???????? ?? ?????????"
+    },
+    "extensionDescription": {
+        "message": "TbSync ? ??????? ?? ?????????? ?? ??????????? ? ?????????????? ??? ??????? ?? ?????? ????????, ?????? ? ??????? ? Thunderbird."
+    },
+    "google.translate.code": {
+        "message": "bg"
+    },
+    "helplink.security": {
+        "message": "https://github.com/jobisoft/TbSync/wiki/How-to-use-TbSync-with-self-signed-or-otherwise-untrusted-certificates%3F"
+    },
+    "info.error": {
+        "message": "??????"
+    },
+    "info.idle": {
+        "message": "?????? ???"
+    },
+    "installProvider.header": {
+        "message": "????????? '##replace.1##' ?? TbSync ?? ? ??????????."
+    },
+    "manager.AccountActions": {
+        "message": "???????? ? ?????????????"
+    },
+    "manager.AddAccount": {
+        "message": "???????? ?? ???????????"
+    },
+    "manager.DeleteAccount": {
+        "message": "????????? ?? ?????????????"
+    },
+    "manager.DisableAccount": {
+        "message": "?????????? ?? ?????????????"
+    },
+    "manager.EnableAccount": {
+        "message": "????????? ?? ????????????? ? ????????? ??? ???????"
+    },
+    "manager.RetryConnectAccount": {
+        "message": "?????? ?????? ?? ?? ??????? ??? ???????"
+    },
+    "manager.ShowEventLog": {
+        "message": "????????? ?? ????????? ??? ?????????"
+    },
+    "manager.SyncAll": {
+        "message": "?????????????? ?? ?????? ???????? ???????????"
+    },
+    "manager.SynchronizeAccount": {
+        "message": "?????????????? ?? ?????????????"
+    },
+    "manager.accounts": {
+        "message": "???????????"
+    },
+    "manager.accountsettings": {
+        "message": "????????? ?? ?????????????"
+    },
+    "manager.catman.text": {
+        "message": "TbSync ???????????? ? ????????? ????????, ????? ?? ?????????? ?? ?????????????????? ??????? ? ???????? ?? Thunderbird. ?? ?? ????????? ????????????? ?? ???????? ???????? ?? Thunderbird, ???????????? ????????? ?Category Manager?. ?? ????????? ?????????? ?? ???????? ? ????? ????????? / ????? ? ??. ????????? ???? ?? ?? ????????? ?? ??????????? ???? ?? ??????? ?? Mozilla:"
+    },
+    "manager.community": {
+        "message": "????????/???????????"
+    },
+    "manager.connecting": {
+        "message": "????????????? ?? ??????"
+    },
+    "manager.help": {
+        "message": "?????"
+    },
+    "manager.help.createbugreport": {
+        "message": "????????? ?? ?????? ?? ??????"
+    },
+    "manager.help.createbugreportinfo": {
+        "message": "?? ?? ?????? TbSync ?????????? ????????????, ????? ?? ?????? ?? ????????, ????????????? Thunderbird, ? ????????? ????????, ?? ?? ?? ?????? ?????? ?? ??????. ?????? ???? ??? ?? ????????? ?????? ?? ????????."
+    },
+    "manager.help.debuglevel.0": {
+        "message": "?????????"
+    },
+    "manager.help.debuglevel.1": {
+        "message": "????????: ????????????? ???? ?? ??????"
+    },
+    "manager.help.debuglevel.2": {
+        "message": "????????: ????????????? ?? ?????? ????????? ? ???????? ?????"
+    },
+    "manager.help.debuglevel.3": {
+        "message": "????????: ????????????? ?? ?????? ????? ? ????? ??????????? ?? ???????????? ?? ??????"
+    },
+    "manager.help.debugmode": {
+        "message": "????? ?? ???????? ?????????????:"
+    },
+    "manager.help.fixit": {
+        "message": "???? ?? ????????? ?? ?????????????? ?, ???? ????????? ?? ???????????? ?????? ?? ????????. ?? ???? ? ?????????? ?? ???????? ?????? ?? ???????? ?????????????."
+    },
+    "manager.help.foundabug": {
+        "message": "???????? ?? ???????"
+    },
+    "manager.help.needhelp": {
+        "message": "?????? ?? ?? ??????"
+    },
+    "manager.help.viewdebuglog": {
+        "message": "?????? ????????? ????????"
+    },
+    "manager.help.wiki": {
+        "message": "???????? ???? ?????????? ?? ??????? TbSync, ?????? ??? ???????????? ??????????, ??????????? ?? ??????????? ? ???????? ???????? ?? ???????????."
+    },
+    "manager.installprovider.link": {
+        "message": "??????????? ??????????? ?? ?? ???????? ?????????? ?? ????????? TbSync ?????????. ??? ?? ???????? ???????????? ?????????? ?? ?????????? ? ???? ?? ?? ??????????? ?? ???:"
+    },
+    "manager.installprovider.warning": {
+        "message": "???? ????????? ?? ?????????? ?? ??????????? ???? ?? ??????? ?? Thunderbird ? ?? ? ??? ???????? ?? ????? ?? Thunderbird. ???? TbSync ????????? ?? ????? ?? ??????? ???????. ??????????? ?? ????????? ???????????."
+    },
+    "manager.lockedsettings.description": {
+        "message": "?? ?? ?? ???????? ?????? ?? ????? ?? ????????????????, ????? ????????? ?? ????? ?? ????? ?????????, ?????? ????????????? ? ????????."
+    },
+    "manager.missingprovider": {
+        "message": "???? ??????????? ??????? TbSync ?????????? ##provider##, ????? ?? ? ??????????."
+    },
+    "manager.noaccounts": {
+        "message": "??? ???? ????????? ???????????."
+    },
+    "manager.provider": {
+        "message": "??????????? ?? TbSync ?????????"
+    },
+    "manager.provider4tbsync": {
+        "message": "????????? ?? TbSync"
+    },
+    "manager.resource": {
+        "message": "??????"
+    },
+    "manager.shorttitle": {
+        "message": "?????????? ?? ?????????????"
+    },
+    "manager.status": {
+        "message": "??????"
+    },
+    "manager.supporter.contributors": {
+        "message": "???????????? ? ?????????"
+    },
+    "manager.supporter.details": {
+        "message": "???????????"
+    },
+    "manager.supporter.sponsors": {
+        "message": "???????????? ??????????? ?? ????????????"
+    },
+    "manager.tabs.status": {
+        "message": "????????? ?? ????????????????"
+    },
+    "manager.tabs.status.autotime": {
+        "message": "?????????? ?????????????? (? ??????)"
+    },
+    "manager.tabs.status.enableThisAccount": {
+        "message": "????????? ?? ????????????? ? ??????????????"
+    },
+    "manager.tabs.status.general": {
+        "message": "????"
+    },
+    "manager.tabs.status.never": {
+        "message": "???????? 0 ???????? ???????????? ??????????????. ????????? ?? ?????, ?????? ??? ?? ???????, ???? ?? ???? ?? ?? ??????????? ??????????? ?????????????."
+    },
+    "manager.tabs.status.resources": {
+        "message": "??????? ???????"
+    },
+    "manager.tabs.status.resources.intro": {
+        "message": "???????? ??? ?? ????????? ??????? ?? ?? ????????????? ? Thunderbird."
+    },
+    "manager.tabs.status.sync": {
+        "message": "????????????? ????"
+    },
+    "manager.tabs.status.tryagain": {
+        "message": "?????? ?????? ?? ?? ??????? ??? ???????"
+    },
+    "manager.title": {
+        "message": "TbSync ?????????? ?? ?????????????"
+    },
+    "manager.tryagain": {
+        "message": "?????? ?????? ?? ?? ??????? ??? ???????"
+    },
+    "menu.settingslabel": {
+        "message": "????????? ?? ??????????????? (TbSync)"
+    },
+    "password.account": {
+        "message": "???????????:"
+    },
+    "password.description": {
+        "message": "???? ????????? ??????? ?? ???????? TbSync ???????????:"
+    },
+    "password.password": {
+        "message": "??????:"
+    },
+    "password.title": {
+        "message": "TbSync ?????????? ?? ?????????????"
+    },
+    "password.user": {
+        "message": "????????????? ???:"
+    },
+    "popup.opensettings": {
+        "message": "?????? TbSync ???????????? ?? ?????????????"
+    },
+    "prompt.DeleteAccount": {
+        "message": "??????? ?? ???, ?? ?????? ?? ???????? ??????????? ##accountName##?"
+    },
+    "prompt.Disable": {
+        "message": "??????? ?? ???, ?? ?????? ?? ????????? ???? ???????????? ?????? ?????? ???????, ????? ??? ?? ?? ??????????????, ?? ?? ???????!"
+    },
+    "prompt.Erase": {
+        "message": "??????? ?? ???, ?? ???? ??????????? ?? ???????? ????????? ?????? ?? ? ?????????? ?? ??????? ? ????????????"
+    },
+    "prompt.Unsubscribe": {
+        "message": "??????? ?? ???, ?? ?? ???? ?????? ?? ??????? ?? ??? ?????? ????????? ?????? ?????? ???????, ????? ??? ?? ?? ??????????????, ?? ?? ???????!"
+    },
+    "status.JavaScriptError": {
+        "message": "Javascript ??????! ????????? ????????? ??? ????????? ?? ???????????."
+    },
+    "status.OAuthAbortError": {
+        "message": "???????? ?? OAuth 2.0 ??????????????? ???? ????????? ?? ???????????."
+    },
+    "status.OAuthHttpError": {
+        "message": "???????????????? ?? OAuth 2.0 ?? ????? (HTTP ?????? ##replace.1##)."
+    },
+    "status.OAuthNetworkError": {
+        "message": "?? ????? ?? ?? ?????? ? OAuth 2.0 ???????."
+    },
+    "status.OAuthServerError": {
+        "message": " OAuth 2.0 ???????? ??????? ? ##replace.1##"
+    },
+    "status.aborted": {
+        "message": "?? ? ?????????????"
+    },
+    "status.apiError": {
+        "message": "API ?????? ??? ??????????????"
+    },
+    "status.disabled": {
+        "message": "????????????? ? ??????????????? ?? ?????????."
+    },
+    "status.foldererror": {
+        "message": "???? ??? ???? ?????? ?? ????? ?????? ??? ????????????????. ????????? ????????? ??? ??????? ?? ???????????."
+    },
+    "status.modified": {
+        "message": "?????? ???????"
+    },
+    "status.network": {
+        "message": "?? ?????? ?? ?? ???????? ?????? ??? ??????? (##replace.1##)."
+    },
+    "status.no-folders-found-on-server": {
+        "message": "?? ??????? ?? ???? ???????? ???????."
+    },
+    "status.notargets": {
+        "message": "???????????????? ????????, ??? ???? ?? ????????? ?? ?? ?????? ?? ?? ???????? ???? ???????."
+    },
+    "status.notsyncronized": {
+        "message": "????????????? ?????? ?? ???? ????????????."
+    },
+    "status.pending": {
+        "message": "?????? ?? ?????????????"
+    },
+    "status.security": {
+        "message": "?????? ??? ??????????????? ?? ???????? ??????. ?????????? ?? ?????????????? ???????? ?????????? ??? ??????????, ?? ????? Thunderbird ???? ???????? (##replace.1##)"
+    },
+    "status.skipped": {
+        "message": "?? ?? ????????, ??????????"
+    },
+    "status.success": {
+        "message": "?????"
+    },
+    "status.syncing": {
+        "message": "??????????????"
+    },
+    "status.451": {
+        "message": "Server issued redirect, retry in 5 seconds."
+    },
+    "supportwizard.footer": {
+        "message": "?? ???? ?????????? ?? ?????????? ?????? ?? ?? ?????? ??????????? ?????, ????? ?????? ?? ????????? (???????? ?? ???????? ?????? ?? ??????). ???? ???? ????????? ?? ???????, ???????? ?? ?????? ?? ??????."
+    },
+    "supportwizard.label.description": {
+        "message": "???????? ???????? ?? ????????:"
+    },
+    "supportwizard.label.faultycomponent": {
+        "message": "?????????? ?? TbSync, ??? ????? ???????????? ????????:"
+    },
+    "supportwizard.label.selectcomponent": {
+        "message": "???????? ???????????"
+    },
+    "supportwizard.label.summary": {
+        "message": "????????? ?? ????????:"
+    },
+    "supportwizard.pagetitle": {
+        "message": "???????? ?? ???????? ?????????? ?? ?? ???? ?? ???? ?? ??????? ?? ?????? ?? ?? ??????? ????? ????."
+    },
+    "supportwizard.provider": {
+        "message": "?????????: ##replace.1##"
+    },
+    "supportwizard.title": {
+        "message": "????????? ?? ?????? ?? ??????"
+    },
+    "syncstate.accountdone": {
+        "message": "???????????????? ?? ????????????? ????????"
+    },
+    "syncstate.done": {
+        "message": "?????????? ?? ????????? ?????? ?? ?????????????"
+    },
+    "syncstate.oauthprompt": {
+        "message": "OAuth 2.0 ??????????????"
+    },
+    "syncstate.passwordprompt": {
+        "message": "??????? ?? ????????? ?? ?????????? ?? ???????????"
+    },
+    "syncstate.preparing": {
+        "message": "?????????? ?? ????????? ?????? ?? ?????????????"
+    },
+    "syncstate.syncing": {
+        "message": "????????? ?? ???????????????"
+    },
+    "target.orphaned": {
+        "message": "?????????? ??????"
+    },
+    "toolbar.label": {
+        "message": "????????????? ?????? TbSync ???????????"
+    },
+    "toolbar.tooltiptext": {
+        "message": "????????????? ???????????? ?? ?????? TbSync ??????????? ??? ?????????"
+    },
+    "password.ok": {
+        "message": "?????"
+    },
+    "password.cancel": {
+        "message": "?????"
+    }
+}
diff -Nru tbsync-4.12/_locales/cs/messages.json tbsync-4.16/_locales/cs/messages.json
--- tbsync-4.12/_locales/cs/messages.json	2024-08-27 18:32:08.000000000 +0200
+++ tbsync-4.16/_locales/cs/messages.json	2024-08-27 18:29:06.000000000 +0200
@@ -1,368 +1,368 @@
-{
-    "HelpFixStartupError": {
-        "message": "Abyste usnadnili opraven? chyby, m??ete v?voj??i dopl?ku TbSync odeslat lad?c? informace. Chcete nyn? p?ipravit email?"
-    },
-    "NoDebugLog": {
-        "message": "Nebyly nalezeny ??dn? u?ite?n? lad?c? zpr?vy. Pros?m, aktivujte re?im lad?n?, restartujte Thunderbird a zopakujte kroky, kter? vedly k t?to chyb?."
-    },
-    "OopsMessage": {
-        "message": "Jejda! TbSync se nepoda?ilo spustit!"
-    },
-    "RestartThunderbirdAndTryAgain": {
-        "message": "Ukl?d?n? lad?c?ch informac? TbSync bylo povoleno. Pros?m, restartujte Thunderbird a zkuste znovu otev??t TbSync."
-    },
-    "UnableToTraceError": {
-        "message": "Nen? mo?n? vysledovat tuto chybu, proto?e nen? povoleno ukl?d?n? lad?c?ch informac?. Chcete ho nyn? povolit?"
-    },
-    "accountacctions.delete": {
-        "message": "Smazat ??et ?##accountname##?"
-    },
-    "accountacctions.disable": {
-        "message": "Zak?zat ??et ?##accountname##?"
-    },
-    "accountacctions.enable": {
-        "message": "Povolit ??et ?##accountname##? a pokusit se p?ipojit k serveru"
-    },
-    "accountacctions.sync": {
-        "message": "Synchronizovat ??et ?##accountname##?"
-    },
-    "addressbook.searchall": {
-        "message": "Prohledat v?echny adres??e"
-    },
-    "addressbook.searchgal": {
-        "message": "Prohledat tento adres?? a glob?ln? adres?? (##replace.1##)"
-    },
-    "addressbook.searchthis": {
-        "message": "Prohledat tento adres??"
-    },
-    "eventlog.clear": {
-        "message": "Vypr?zdnit"
-    },
-    "eventlog.close": {
-        "message": "Zav??t"
-    },
-    "eventlog.title": {
-        "message": "Protokol ud?lost?"
-    },
-    "extensionDescription": {
-        "message": "TbSync je spole?n? rozhran? pro spr?vu cloudov?ch ??t? a synchronizaci jejich kontakt?, ?kol? a kalend??? s Thunderbirdem."
-    },
-    "google.translate.code": {
-        "message": "cs"
-    },
-    "helplink.security": {
-        "message": "https://github.com/jobisoft/TbSync/wiki/How-to-use-TbSync-with-self-signed-or-otherwise-untrusted-certificates%3F"
-    },
-    "info.error": {
-        "message": "Chyba"
-    },
-    "info.idle": {
-        "message": "Ne?inn?"
-    },
-    "installProvider.header": {
-        "message": "Modul poskytovatele ?##replace.1##? pro TbSync nen? nainstalov?n."
-    },
-    "manager.AccountActions": {
-        "message": "Akce s ??ty"
-    },
-    "manager.AddAccount": {
-        "message": "P?idat nov? ??et"
-    },
-    "manager.DeleteAccount": {
-        "message": "Odstranit ??et"
-    },
-    "manager.DisableAccount": {
-        "message": "Deaktivovat ??et"
-    },
-    "manager.EnableAccount": {
-        "message": "Povolit ??et a pokusit se p?ipojit k serveru"
-    },
-    "manager.RetryConnectAccount": {
-        "message": "Zkusit znovu p?ipojit k serveru"
-    },
-    "manager.ShowEventLog": {
-        "message": "Otev??t log"
-    },
-    "manager.SyncAll": {
-        "message": "Synchronizovat povolen? ??ty"
-    },
-    "manager.SynchronizeAccount": {
-        "message": "Synchronizovat ??et"
-    },
-    "manager.accounts": {
-        "message": "??ty"
-    },
-    "manager.accountsettings": {
-        "message": "Nastaven? ??tu"
-    },
-    "manager.catman.text": {
-        "message": "TbSync tak? synchronizuje kategorie kontakt?, kter? jsou u?ite?nou n?hradou za seznamy kontakt?. Chcete-li je pou??vat v adres??i Thunderbird, m??ete nainstalovat dopln?k Spr?vce kategori?. Umo??uje spravovat p?ekr?vaj?c? se skupiny kontakt? s kategoriemi a poskytuje spoustu dal??ch funkc? souvisej?c?ch s kategoriemi. Dopln?k je v ofici?ln?m ?lo?i?ti dopl?k? Mozilla:"
-    },
-    "manager.community": {
-        "message": "Komunita"
-    },
-    "manager.connecting": {
-        "message": "P?ipojuji se na server"
-    },
-    "manager.help": {
-        "message": "N?pov?da"
-    },
-    "manager.help.createbugreport": {
-        "message": "Vytvo?it hl??en? o chyb?"
-    },
-    "manager.help.createbugreportinfo": {
-        "message": "Aby TbSync shroma??oval pouze data o lad?n?, kter? jsou relevantn? pro Va?? zpr?vu o chyb?, pros?m restartujte Thunderbird a pak opakujte p?esn? kroky, kter? reprodukuj? chybov? chov?n?. Pak zde m??ete vytvo?it hl??en? o chyb?."
-    },
-    "manager.help.debuglevel.0": {
-        "message": "Zak?z?n"
-    },
-    "manager.help.debuglevel.1": {
-        "message": "Povoleno: pouze chyby"
-    },
-    "manager.help.debuglevel.2": {
-        "message": "Povoleno: Z?znam v?ech odeslan?ch a p?ijat?ch dat"
-    },
-    "manager.help.debuglevel.3": {
-        "message": "Povoleno: Z?znam v?ech dat a n?kter?ch intern?ch hodnot lad?n?"
-    },
-    "manager.help.debugmode": {
-        "message": "Re?im lad?n?:"
-    },
-    "manager.help.fixit": {
-        "message": "M??ete pomoci ji opravit zasl?n?m hl??en? o chyb?. K tomu je pot?eba aktivace re?imu lad?n?."
-    },
-    "manager.help.foundabug": {
-        "message": "Na?li jste chybu?"
-    },
-    "manager.help.needhelp": {
-        "message": "Pot?ebujete pomoc?"
-    },
-    "manager.help.viewdebuglog": {
-        "message": "Zobrazit debug log"
-    },
-    "manager.help.wiki": {
-        "message": "Otev?ete wiki str?nky projektu TbSync, kde najdete dal?? informace, n?vody a detailn? popisy konfigurace."
-    },
-    "manager.installprovider.link": {
-        "message": "Klikn?te na n?sleduj?c? odkaz pro otev?en? str?nky chyb?j?c?ho poskytovatele synchronizace. Zde naleznete dal?? informace o poskytovateli a budete m?t mo?nost jej nainstalovat:"
-    },
-    "manager.installprovider.warning": {
-        "message": "Tento poskytovatel synchronizace nen? hostov?n v ofici?ln?m ?lo?i?ti dopl?k? Thunderbird, a proto nebyl zkontrolov?n zam?stnanci Thunderbirdu. Poskytovatel by mohl d?lat ?patn? v?ci ve va?em syst?mu. Pou?ijte na vlastn? riziko."
-    },
-    "manager.lockedsettings.description": {
-        "message": "Aby se zabr?nilo chyb?m synchronizace, n?kter? nastaven? nelze upravit u aktivn?ho ??tu."
-    },
-    "manager.missingprovider": {
-        "message": "Tento ??et vy?aduje synchroniza?n?ho poskytovatele ##provider##, kter? moment?ln? nen? nainstalov?n."
-    },
-    "manager.noaccounts": {
-        "message": "Zat?m nejsou definov?ny ??dn? ??ty."
-    },
-    "manager.provider": {
-        "message": "Instalovat poskytovatele"
-    },
-    "manager.provider4tbsync": {
-        "message": "Poskytovatel pro TbSync"
-    },
-    "manager.resource": {
-        "message": "Zdroj"
-    },
-    "manager.shorttitle": {
-        "message": "Spr?vce ??t?"
-    },
-    "manager.status": {
-        "message": "Stav"
-    },
-    "manager.supporter.contributors": {
-        "message": "P?isp?vatel? a p?ekladatel?"
-    },
-    "manager.supporter.details": {
-        "message": "Podrobnosti"
-    },
-    "manager.supporter.sponsors": {
-        "message": "Sponzo?i testovac?ch ??t?"
-    },
-    "manager.tabs.status": {
-        "message": "Stav synchronizace"
-    },
-    "manager.tabs.status.autotime": {
-        "message": "Periodick? synchronizace (v minut?ch)"
-    },
-    "manager.tabs.status.enableThisAccount": {
-        "message": "Povolit a synchronizovat ??et"
-    },
-    "manager.tabs.status.general": {
-        "message": "Obecn?"
-    },
-    "manager.tabs.status.never": {
-        "message": "Hodnota 0 zak??e periodick? synchronizace. Push synchronizace zat?m nen? implementov?na."
-    },
-    "manager.tabs.status.resources": {
-        "message": "Dostupn? zdroje"
-    },
-    "manager.tabs.status.resources.intro": {
-        "message": "Vyberte, kter? z nalezen?ch skupin by m?ly b?t synchronizov?ny s Thunderbirdem."
-    },
-    "manager.tabs.status.sync": {
-        "message": "Synchronizovat"
-    },
-    "manager.tabs.status.tryagain": {
-        "message": "Zkusit znovu p?ipojit k serveru"
-    },
-    "manager.title": {
-        "message": "Spr?vce ??t? TbSync"
-    },
-    "manager.tryagain": {
-        "message": "Zkusit znovu p?ipojit k serveru"
-    },
-    "menu.settingslabel": {
-        "message": "Nastaven? synchronizace (TbSync)"
-    },
-    "password.account": {
-        "message": "??et:"
-    },
-    "password.description": {
-        "message": "Pros?m aktualizujte p?ihla?ovac? ?daje pro n?sleduj?c? ??et TbSync:"
-    },
-    "password.password": {
-        "message": "Heslo:"
-    },
-    "password.title": {
-        "message": "TbSync ??dost o pov??en?"
-    },
-    "password.user": {
-        "message": "U?ivatel:"
-    },
-    "popup.opensettings": {
-        "message": "Spr?vce ??t? TbSync"
-    },
-    "prompt.DeleteAccount": {
-        "message": "Opravdu chcete smazat ??et ##accountName##?"
-    },
-    "prompt.Disable": {
-        "message": "Opravdu chcete zak?zat tento ??et? V?echny m?stn? zm?ny, kter? je?t? nebyly synchronizov?ny, budou ztraceny!"
-    },
-    "prompt.Erase": {
-        "message": "Opravdu chcete odstranit tento nezn?m? ??et ze seznamu ??t??"
-    },
-    "prompt.Unsubscribe": {
-        "message": "Opravdu chcete zru?it synchronizaci t?to polo?ky? V?echny m?stn? zm?ny, kter? je?t? nebyly synchronizov?ny, budou ztraceny!"
-    },
-    "status.JavaScriptError": {
-        "message": "Chyba Javascriptu! Pro v?ce informac? zkontrolujte protokol ud?lost?."
-    },
-    "status.OAuthAbortError": {
-        "message": "Proces ov??ov?n? OAuth 2.0 byl zru?en u?ivatelem."
-    },
-    "status.OAuthHttpError": {
-        "message": "Proces ov??ov?n? OAuth 2.0 selhal (HTTP chyba ##replace.1##)."
-    },
-    "status.OAuthNetworkError": {
-        "message": "Nelze se p?ipojit k ov??ovac?mu serveru OAuth 2.0."
-    },
-    "status.OAuthServerError": {
-        "message": " Ov??ovac? server OAuth 2.0 hl?s?: ##replace.1##"
-    },
-    "status.aborted": {
-        "message": "Nesynchronizov?no"
-    },
-    "status.apiError": {
-        "message": "Chyba implementace API"
-    },
-    "status.disabled": {
-        "message": "??et nen? povolen, synchronizace je zak?z?na."
-    },
-    "status.foldererror": {
-        "message": "Nejm?n? u jednoho zdroje se vyskytla chyba synchronizace. Pro v?ce informac? zkontrolujte protokol ud?lost?."
-    },
-    "status.modified": {
-        "message": "M?stn? zm?ny"
-    },
-    "status.network": {
-        "message": "Nelze se p?ipojit k serveru (##replace.1##)."
-    },
-    "status.no-folders-found-on-server": {
-        "message": "Na serveru nebyly nalezeny ??dn? zdroje pro synchronizaci."
-    },
-    "status.notargets": {
-        "message": "Synchronizace byla p?eru?ena, proto?e nebylo mo?n? vytvo?it c?le pro synchronizaci."
-    },
-    "status.notsyncronized": {
-        "message": "??et mus? b?t synchronizov?n, alespo? jedna polo?ka nen? synchronizov?na."
-    },
-    "status.pending": {
-        "message": "?ek? se na synchronizaci"
-    },
-    "status.security": {
-        "message": "Nelze nav?zat zabezpe?en? spojen?. Pou??v?te samopodepsan? nebo jinak ned?v?ryhodn? certifik?t, ani? byste jej importovali do Thunderbirdu? (##replace.1##)"
-    },
-    "status.skipped": {
-        "message": "Je?t? nen? podporov?no, p?esko?eno"
-    },
-    "status.success": {
-        "message": "OK"
-    },
-    "status.syncing": {
-        "message": "Prob?h? synchronizace"
-    },
-    "status.451": {
-        "message": "Server issued redirect, retry in 5 seconds."
-    },
-    "supportwizard.footer": {
-        "message": "Z informac? zde uveden?ch bude v dal??m kroku vygenerov?n e-mail, kter? m??ete n?sledn? upravit (nap??klad p?id?n? screenshot?). Zasl?n?m e-mailu bude teprve zasl?na chybov? zpr?va."
-    },
-    "supportwizard.label.description": {
-        "message": "Podrobn? popis chyby:"
-    },
-    "supportwizard.label.faultycomponent": {
-        "message": "Komponenta TbSync, kde jste zaznamenali chybu:"
-    },
-    "supportwizard.label.selectcomponent": {
-        "message": "Vyberte komponentu?"
-    },
-    "supportwizard.label.summary": {
-        "message": "Kr?tk? shrnut? chyby:"
-    },
-    "supportwizard.pagetitle": {
-        "message": "Shroma??ov?n? v?ech informac? pro efektivn? zpracov?n? hl??en? o chyb?."
-    },
-    "supportwizard.provider": {
-        "message": "Modul poskytovatele: ##replace.1##"
-    },
-    "supportwizard.title": {
-        "message": "Vytvo?it hl??en? o chyb?"
-    },
-    "syncstate.accountdone": {
-        "message": "Synchronizace ??tu dokon?ena"
-    },
-    "syncstate.done": {
-        "message": "P??prava dal?? polo?ky na synchronizaci"
-    },
-    "syncstate.oauthprompt": {
-        "message": "Ov??en? OAuth 2.0"
-    },
-    "syncstate.passwordprompt": {
-        "message": "Jsou vy?adov?ny p?ihla?ovac? ?daje"
-    },
-    "syncstate.preparing": {
-        "message": "P??prava dal?? polo?ky na synchronizaci"
-    },
-    "syncstate.syncing": {
-        "message": "Inicializuji synchronizaci"
-    },
-    "target.orphaned": {
-        "message": "Odpojeno"
-    },
-    "toolbar.label": {
-        "message": "Synchronizovat v?echny TbSync ??ty"
-    },
-    "toolbar.tooltiptext": {
-        "message": "Synchronizovat posledn? zm?ny"
-    },
-    "password.ok": {
-        "message": "OK"
-    },
-    "password.cancel": {
-        "message": "Zru?it"
-    }
-}
+{
+    "HelpFixStartupError": {
+        "message": "Abyste usnadnili opraven? chyby, m??ete v?voj??i dopl?ku TbSync odeslat lad?c? informace. Chcete nyn? p?ipravit email?"
+    },
+    "NoDebugLog": {
+        "message": "Nebyly nalezeny ??dn? u?ite?n? lad?c? zpr?vy. Pros?m, aktivujte re?im lad?n?, restartujte Thunderbird a zopakujte kroky, kter? vedly k t?to chyb?."
+    },
+    "OopsMessage": {
+        "message": "Jejda! TbSync se nepoda?ilo spustit!"
+    },
+    "RestartThunderbirdAndTryAgain": {
+        "message": "Ukl?d?n? lad?c?ch informac? TbSync bylo povoleno. Pros?m, restartujte Thunderbird a zkuste znovu otev??t TbSync."
+    },
+    "UnableToTraceError": {
+        "message": "Nen? mo?n? vysledovat tuto chybu, proto?e nen? povoleno ukl?d?n? lad?c?ch informac?. Chcete ho nyn? povolit?"
+    },
+    "accountacctions.delete": {
+        "message": "Smazat ??et ?##accountname##?"
+    },
+    "accountacctions.disable": {
+        "message": "Zak?zat ??et ?##accountname##?"
+    },
+    "accountacctions.enable": {
+        "message": "Povolit ??et ?##accountname##? a pokusit se p?ipojit k serveru"
+    },
+    "accountacctions.sync": {
+        "message": "Synchronizovat ??et ?##accountname##?"
+    },
+    "addressbook.searchall": {
+        "message": "Prohledat v?echny adres??e"
+    },
+    "addressbook.searchgal": {
+        "message": "Prohledat tento adres?? a glob?ln? adres?? (##replace.1##)"
+    },
+    "addressbook.searchthis": {
+        "message": "Prohledat tento adres??"
+    },
+    "eventlog.clear": {
+        "message": "Vypr?zdnit"
+    },
+    "eventlog.close": {
+        "message": "Zav??t"
+    },
+    "eventlog.title": {
+        "message": "Protokol ud?lost?"
+    },
+    "extensionDescription": {
+        "message": "TbSync je spole?n? rozhran? pro spr?vu cloudov?ch ??t? a synchronizaci jejich kontakt?, ?kol? a kalend??? s Thunderbirdem."
+    },
+    "google.translate.code": {
+        "message": "cs"
+    },
+    "helplink.security": {
+        "message": "https://github.com/jobisoft/TbSync/wiki/How-to-use-TbSync-with-self-signed-or-otherwise-untrusted-certificates%3F"
+    },
+    "info.error": {
+        "message": "Chyba"
+    },
+    "info.idle": {
+        "message": "Ne?inn?"
+    },
+    "installProvider.header": {
+        "message": "Modul poskytovatele ?##replace.1##? pro TbSync nen? nainstalov?n."
+    },
+    "manager.AccountActions": {
+        "message": "Akce s ??ty"
+    },
+    "manager.AddAccount": {
+        "message": "P?idat nov? ??et"
+    },
+    "manager.DeleteAccount": {
+        "message": "Odstranit ??et"
+    },
+    "manager.DisableAccount": {
+        "message": "Deaktivovat ??et"
+    },
+    "manager.EnableAccount": {
+        "message": "Povolit ??et a pokusit se p?ipojit k serveru"
+    },
+    "manager.RetryConnectAccount": {
+        "message": "Zkusit znovu p?ipojit k serveru"
+    },
+    "manager.ShowEventLog": {
+        "message": "Otev??t log"
+    },
+    "manager.SyncAll": {
+        "message": "Synchronizovat povolen? ??ty"
+    },
+    "manager.SynchronizeAccount": {
+        "message": "Synchronizovat ??et"
+    },
+    "manager.accounts": {
+        "message": "??ty"
+    },
+    "manager.accountsettings": {
+        "message": "Nastaven? ??tu"
+    },
+    "manager.catman.text": {
+        "message": "TbSync tak? synchronizuje kategorie kontakt?, kter? jsou u?ite?nou n?hradou za seznamy kontakt?. Chcete-li je pou??vat v adres??i Thunderbird, m??ete nainstalovat dopln?k Spr?vce kategori?. Umo??uje spravovat p?ekr?vaj?c? se skupiny kontakt? s kategoriemi a poskytuje spoustu dal??ch funkc? souvisej?c?ch s kategoriemi. Dopln?k je v ofici?ln?m ?lo?i?ti dopl?k? Mozilla:"
+    },
+    "manager.community": {
+        "message": "Komunita"
+    },
+    "manager.connecting": {
+        "message": "P?ipojuji se na server"
+    },
+    "manager.help": {
+        "message": "N?pov?da"
+    },
+    "manager.help.createbugreport": {
+        "message": "Vytvo?it hl??en? o chyb?"
+    },
+    "manager.help.createbugreportinfo": {
+        "message": "Aby TbSync shroma??oval pouze data o lad?n?, kter? jsou relevantn? pro Va?? zpr?vu o chyb?, pros?m restartujte Thunderbird a pak opakujte p?esn? kroky, kter? reprodukuj? chybov? chov?n?. Pak zde m??ete vytvo?it hl??en? o chyb?."
+    },
+    "manager.help.debuglevel.0": {
+        "message": "Zak?z?n"
+    },
+    "manager.help.debuglevel.1": {
+        "message": "Povoleno: pouze chyby"
+    },
+    "manager.help.debuglevel.2": {
+        "message": "Povoleno: Z?znam v?ech odeslan?ch a p?ijat?ch dat"
+    },
+    "manager.help.debuglevel.3": {
+        "message": "Povoleno: Z?znam v?ech dat a n?kter?ch intern?ch hodnot lad?n?"
+    },
+    "manager.help.debugmode": {
+        "message": "Re?im lad?n?:"
+    },
+    "manager.help.fixit": {
+        "message": "M??ete pomoci ji opravit zasl?n?m hl??en? o chyb?. K tomu je pot?eba aktivace re?imu lad?n?."
+    },
+    "manager.help.foundabug": {
+        "message": "Na?li jste chybu?"
+    },
+    "manager.help.needhelp": {
+        "message": "Pot?ebujete pomoc?"
+    },
+    "manager.help.viewdebuglog": {
+        "message": "Zobrazit debug log"
+    },
+    "manager.help.wiki": {
+        "message": "Otev?ete wiki str?nky projektu TbSync, kde najdete dal?? informace, n?vody a detailn? popisy konfigurace."
+    },
+    "manager.installprovider.link": {
+        "message": "Klikn?te na n?sleduj?c? odkaz pro otev?en? str?nky chyb?j?c?ho poskytovatele synchronizace. Zde naleznete dal?? informace o poskytovateli a budete m?t mo?nost jej nainstalovat:"
+    },
+    "manager.installprovider.warning": {
+        "message": "Tento poskytovatel synchronizace nen? hostov?n v ofici?ln?m ?lo?i?ti dopl?k? Thunderbird, a proto nebyl zkontrolov?n zam?stnanci Thunderbirdu. Poskytovatel by mohl d?lat ?patn? v?ci ve va?em syst?mu. Pou?ijte na vlastn? riziko."
+    },
+    "manager.lockedsettings.description": {
+        "message": "Aby se zabr?nilo chyb?m synchronizace, n?kter? nastaven? nelze upravit u aktivn?ho ??tu."
+    },
+    "manager.missingprovider": {
+        "message": "Tento ??et vy?aduje synchroniza?n?ho poskytovatele ##provider##, kter? moment?ln? nen? nainstalov?n."
+    },
+    "manager.noaccounts": {
+        "message": "Zat?m nejsou definov?ny ??dn? ??ty."
+    },
+    "manager.provider": {
+        "message": "Instalovat poskytovatele"
+    },
+    "manager.provider4tbsync": {
+        "message": "Poskytovatel pro TbSync"
+    },
+    "manager.resource": {
+        "message": "Zdroj"
+    },
+    "manager.shorttitle": {
+        "message": "Spr?vce ??t?"
+    },
+    "manager.status": {
+        "message": "Stav"
+    },
+    "manager.supporter.contributors": {
+        "message": "P?isp?vatel? a p?ekladatel?"
+    },
+    "manager.supporter.details": {
+        "message": "Podrobnosti"
+    },
+    "manager.supporter.sponsors": {
+        "message": "Sponzo?i testovac?ch ??t?"
+    },
+    "manager.tabs.status": {
+        "message": "Stav synchronizace"
+    },
+    "manager.tabs.status.autotime": {
+        "message": "Periodick? synchronizace (v minut?ch)"
+    },
+    "manager.tabs.status.enableThisAccount": {
+        "message": "Povolit a synchronizovat ??et"
+    },
+    "manager.tabs.status.general": {
+        "message": "Obecn?"
+    },
+    "manager.tabs.status.never": {
+        "message": "Hodnota 0 zak??e periodick? synchronizace. Push synchronizace zat?m nen? implementov?na."
+    },
+    "manager.tabs.status.resources": {
+        "message": "Dostupn? zdroje"
+    },
+    "manager.tabs.status.resources.intro": {
+        "message": "Vyberte, kter? z nalezen?ch skupin by m?ly b?t synchronizov?ny s Thunderbirdem."
+    },
+    "manager.tabs.status.sync": {
+        "message": "Synchronizovat"
+    },
+    "manager.tabs.status.tryagain": {
+        "message": "Zkusit znovu p?ipojit k serveru"
+    },
+    "manager.title": {
+        "message": "Spr?vce ??t? TbSync"
+    },
+    "manager.tryagain": {
+        "message": "Zkusit znovu p?ipojit k serveru"
+    },
+    "menu.settingslabel": {
+        "message": "Nastaven? synchronizace (TbSync)"
+    },
+    "password.account": {
+        "message": "??et:"
+    },
+    "password.description": {
+        "message": "Pros?m aktualizujte p?ihla?ovac? ?daje pro n?sleduj?c? ??et TbSync:"
+    },
+    "password.password": {
+        "message": "Heslo:"
+    },
+    "password.title": {
+        "message": "TbSync ??dost o pov??en?"
+    },
+    "password.user": {
+        "message": "U?ivatel:"
+    },
+    "popup.opensettings": {
+        "message": "Spr?vce ??t? TbSync"
+    },
+    "prompt.DeleteAccount": {
+        "message": "Opravdu chcete smazat ??et ##accountName##?"
+    },
+    "prompt.Disable": {
+        "message": "Opravdu chcete zak?zat tento ??et? V?echny m?stn? zm?ny, kter? je?t? nebyly synchronizov?ny, budou ztraceny!"
+    },
+    "prompt.Erase": {
+        "message": "Opravdu chcete odstranit tento nezn?m? ??et ze seznamu ??t??"
+    },
+    "prompt.Unsubscribe": {
+        "message": "Opravdu chcete zru?it synchronizaci t?to polo?ky? V?echny m?stn? zm?ny, kter? je?t? nebyly synchronizov?ny, budou ztraceny!"
+    },
+    "status.JavaScriptError": {
+        "message": "Chyba Javascriptu! Pro v?ce informac? zkontrolujte protokol ud?lost?."
+    },
+    "status.OAuthAbortError": {
+        "message": "Proces ov??ov?n? OAuth 2.0 byl zru?en u?ivatelem."
+    },
+    "status.OAuthHttpError": {
+        "message": "Proces ov??ov?n? OAuth 2.0 selhal (HTTP chyba ##replace.1##)."
+    },
+    "status.OAuthNetworkError": {
+        "message": "Nelze se p?ipojit k ov??ovac?mu serveru OAuth 2.0."
+    },
+    "status.OAuthServerError": {
+        "message": " Ov??ovac? server OAuth 2.0 hl?s?: ##replace.1##"
+    },
+    "status.aborted": {
+        "message": "Nesynchronizov?no"
+    },
+    "status.apiError": {
+        "message": "Chyba implementace API"
+    },
+    "status.disabled": {
+        "message": "??et nen? povolen, synchronizace je zak?z?na."
+    },
+    "status.foldererror": {
+        "message": "Nejm?n? u jednoho zdroje se vyskytla chyba synchronizace. Pro v?ce informac? zkontrolujte protokol ud?lost?."
+    },
+    "status.modified": {
+        "message": "M?stn? zm?ny"
+    },
+    "status.network": {
+        "message": "Nelze se p?ipojit k serveru (##replace.1##)."
+    },
+    "status.no-folders-found-on-server": {
+        "message": "Na serveru nebyly nalezeny ??dn? zdroje pro synchronizaci."
+    },
+    "status.notargets": {
+        "message": "Synchronizace byla p?eru?ena, proto?e nebylo mo?n? vytvo?it c?le pro synchronizaci."
+    },
+    "status.notsyncronized": {
+        "message": "??et mus? b?t synchronizov?n, alespo? jedna polo?ka nen? synchronizov?na."
+    },
+    "status.pending": {
+        "message": "?ek? se na synchronizaci"
+    },
+    "status.security": {
+        "message": "Nelze nav?zat zabezpe?en? spojen?. Pou??v?te samopodepsan? nebo jinak ned?v?ryhodn? certifik?t, ani? byste jej importovali do Thunderbirdu? (##replace.1##)"
+    },
+    "status.skipped": {
+        "message": "Je?t? nen? podporov?no, p?esko?eno"
+    },
+    "status.success": {
+        "message": "OK"
+    },
+    "status.syncing": {
+        "message": "Prob?h? synchronizace"
+    },
+    "status.451": {
+        "message": "Server issued redirect, retry in 5 seconds."
+    },
+    "supportwizard.footer": {
+        "message": "Z informac? zde uveden?ch bude v dal??m kroku vygenerov?n e-mail, kter? m??ete n?sledn? upravit (nap??klad p?id?n? screenshot?). Zasl?n?m e-mailu bude teprve zasl?na chybov? zpr?va."
+    },
+    "supportwizard.label.description": {
+        "message": "Podrobn? popis chyby:"
+    },
+    "supportwizard.label.faultycomponent": {
+        "message": "Komponenta TbSync, kde jste zaznamenali chybu:"
+    },
+    "supportwizard.label.selectcomponent": {
+        "message": "Vyberte komponentu?"
+    },
+    "supportwizard.label.summary": {
+        "message": "Kr?tk? shrnut? chyby:"
+    },
+    "supportwizard.pagetitle": {
+        "message": "Shroma??ov?n? v?ech informac? pro efektivn? zpracov?n? hl??en? o chyb?."
+    },
+    "supportwizard.provider": {
+        "message": "Modul poskytovatele: ##replace.1##"
+    },
+    "supportwizard.title": {
+        "message": "Vytvo?it hl??en? o chyb?"
+    },
+    "syncstate.accountdone": {
+        "message": "Synchronizace ??tu dokon?ena"
+    },
+    "syncstate.done": {
+        "message": "P??prava dal?? polo?ky na synchronizaci"
+    },
+    "syncstate.oauthprompt": {
+        "message": "Ov??en? OAuth 2.0"
+    },
+    "syncstate.passwordprompt": {
+        "message": "Jsou vy?adov?ny p?ihla?ovac? ?daje"
+    },
+    "syncstate.preparing": {
+        "message": "P??prava dal?? polo?ky na synchronizaci"
+    },
+    "syncstate.syncing": {
+        "message": "Inicializuji synchronizaci"
+    },
+    "target.orphaned": {
+        "message": "Odpojeno"
+    },
+    "toolbar.label": {
+        "message": "Synchronizovat v?echny TbSync ??ty"
+    },
+    "toolbar.tooltiptext": {
+        "message": "Synchronizovat posledn? zm?ny"
+    },
+    "password.ok": {
+        "message": "OK"
+    },
+    "password.cancel": {
+        "message": "Zru?it"
+    }
+}
diff -Nru tbsync-4.12/_locales/de/messages.json tbsync-4.16/_locales/de/messages.json
--- tbsync-4.12/_locales/de/messages.json	2024-08-27 18:32:08.000000000 +0200
+++ tbsync-4.16/_locales/de/messages.json	2024-08-27 18:28:52.000000000 +0200
@@ -1,368 +1,368 @@
-{
-    "HelpFixStartupError": {
-        "message": "Um diesen Fehler zu beheben, k?nnen Sie einen Fehlerbericht an den Entwickler von TbSync schicken. Soll der Fehlerbericht jetzt angefertigt werden?"
-    },
-    "NoDebugLog": {
-        "message": "Es liegen keine aussagekr?ftigen Debug-Meldungen vor. Bitte aktivieren Sie den Debug-Modus, starten Thunderbird neu und wiederholen dann alle Schritte, um das fehlerhafte Verhalten zu reproduzieren."
-    },
-    "OopsMessage": {
-        "message": "Hoppla! TbSync konnte nicht starten!"
-    },
-    "RestartThunderbirdAndTryAgain": {
-        "message": "Das TbSync-Debug-Protokoll wurde eingeschaltet. Bitte starten Sie Thunderbird neu, und versuchen Sie dann noch einmal, TbSync zu ?ffnen!"
-    },
-    "UnableToTraceError": {
-        "message": "Dieser Fehler kann nicht untersucht werden, solange das Debug-Protokoll deaktiviert ist. Soll das Protokoll jetzt aktiviert werden, damit dieser Fehler untersucht und behoben werden kann?"
-    },
-    "accountacctions.delete": {
-        "message": "Konto ?##accountname##? l?schen"
-    },
-    "accountacctions.disable": {
-        "message": "Konto '##accountname##' deaktivieren"
-    },
-    "accountacctions.enable": {
-        "message": "Konto ?##accountname##? aktivieren und Server kontaktieren"
-    },
-    "accountacctions.sync": {
-        "message": "Konto ?##accountname##? synchronisieren"
-    },
-    "addressbook.searchall": {
-        "message": "Alle Adressb?cher durchsuchen"
-    },
-    "addressbook.searchgal": {
-        "message": "Dieses Adressbuch und das globale Serververzeichnis durchsuchen (##replace.1##)"
-    },
-    "addressbook.searchthis": {
-        "message": "Dieses Adressbuch durchsuchen"
-    },
-    "eventlog.clear": {
-        "message": "Leeren"
-    },
-    "eventlog.close": {
-        "message": "Schlie?en"
-    },
-    "eventlog.title": {
-        "message": "Ereignisprotokoll"
-    },
-    "extensionDescription": {
-        "message": "TbSync ist eine zentrale Benutzeroberfl?che zur Verwaltung von Cloud-Konten und zur Synchronisierung ihrer Kontakt-, Aufgaben- und Kalenderinformationen mit Thunderbird."
-    },
-    "google.translate.code": {
-        "message": "de"
-    },
-    "helplink.security": {
-        "message": "https://github.com/jobisoft/TbSync/wiki/How-to-use-TbSync-with-self-signed-or-otherwise-untrusted-certificates%3F"
-    },
-    "info.error": {
-        "message": "Fehler"
-    },
-    "info.idle": {
-        "message": "Leerlauf"
-    },
-    "installProvider.header": {
-        "message": "Provider ?##replace.1##? f?r TbSync ist noch nicht installiert."
-    },
-    "manager.AccountActions": {
-        "message": "Konto-Aktionen"
-    },
-    "manager.AddAccount": {
-        "message": "Konto hinzuf?gen"
-    },
-    "manager.DeleteAccount": {
-        "message": "Konto entfernen"
-    },
-    "manager.DisableAccount": {
-        "message": "Konto deaktivieren"
-    },
-    "manager.EnableAccount": {
-        "message": "Konto aktivieren und mit dem Server verbinden"
-    },
-    "manager.RetryConnectAccount": {
-        "message": "Erneut versuchen, mit dem Server zu verbinden"
-    },
-    "manager.ShowEventLog": {
-        "message": "Ereignisprotokoll anzeigen"
-    },
-    "manager.SyncAll": {
-        "message": "Synchronisiere alle aktivierten Konten"
-    },
-    "manager.SynchronizeAccount": {
-        "message": "Konto synchronisieren"
-    },
-    "manager.accounts": {
-        "message": "Konten"
-    },
-    "manager.accountsettings": {
-        "message": "Kontoeinstellungen"
-    },
-    "manager.catman.text": {
-        "message": "TbSync synchronisiert auch Kontaktkategorien, die einen effizienten Ersatz f?r die nicht synchronisierbaren Kontaktlisten darstellen. Um diese im Thunderbird-Adressbuch zu nutzen, k?nnen Sie das Add-On ?Category Manager? installieren. Dieses Add-On erm?glicht die Verwaltung ?berlappender kategoriebasierter Kontaktgruppen und stellt eine Reihe anderer kategoriespezifischer Funktionen bereit. Es kann aus dem offiziellen Mozilla Add-On Repository heruntergeladen werden:"
-    },
-    "manager.community": {
-        "message": "Nutzergemeinschaft"
-    },
-    "manager.connecting": {
-        "message": "Verbindung wird hergestellt"
-    },
-    "manager.help": {
-        "message": "Hilfe"
-    },
-    "manager.help.createbugreport": {
-        "message": "Fehlerbericht erstellen"
-    },
-    "manager.help.createbugreportinfo": {
-        "message": "Damit TbSync nur die f?r Ihren Fehlerbericht relevanten Debug-Daten sammelt, starten Sie Thunderbird bitte neu und wiederholen dann genau die Schritte, die das fehlerhafte Verhalten reproduzieren. Anschlie?end k?nnen Sie hier Ihren Fehlerbericht erstellen."
-    },
-    "manager.help.debuglevel.0": {
-        "message": "Deaktiviert"
-    },
-    "manager.help.debuglevel.1": {
-        "message": "Aktiviert: Protokolliert alle Fehler"
-    },
-    "manager.help.debuglevel.2": {
-        "message": "Aktiviert: Protokolliert alle gesendeten und empfangenen Daten"
-    },
-    "manager.help.debuglevel.3": {
-        "message": "Aktiviert: Protokolliert alle Daten und einige interne Debug-Werte"
-    },
-    "manager.help.debugmode": {
-        "message": "Debug-Modus:"
-    },
-    "manager.help.fixit": {
-        "message": "Sie k?nnen helfen den Fehler zu korrigieren, indem Sie dem Entwickler einen Fehlerbericht zusenden. Bitte aktivieren Sie dazu den Debug-Modus."
-    },
-    "manager.help.foundabug": {
-        "message": "Sie haben einen Fehler gefunden?"
-    },
-    "manager.help.needhelp": {
-        "message": "Ben?tigen Sie Hilfe?"
-    },
-    "manager.help.viewdebuglog": {
-        "message": "Debug-Protokoll anzeigen"
-    },
-    "manager.help.wiki": {
-        "message": "Besuchen Sie die Wikiseiten des TbSync-Projekts, diese enthalten zus?tzliche Informationen, Benutzeranleitungen und detaillierte Konfigurationsbeschreibungen."
-    },
-    "manager.installprovider.link": {
-        "message": "Klicken Sie auf den folgenden Link, um die Informationsseite des fehlenden Synchronisations-Providers aufzurufen. Dort finden Sie weitere Informationen dazu und haben die M?glichkeit, diesen zu installieren:"
-    },
-    "manager.installprovider.warning": {
-        "message": "Dieser Provider stammt nicht aus der offiziellen Thunderbird-Add-On-Sammlung und wurde demnach nicht von Thunderbird-Mitarbeitern ?berpr?ft. Es k?nnte sich um Schad-Software handeln, deshalb verwenden Sie es auf eigene Gefahr."
-    },
-    "manager.lockedsettings.description": {
-        "message": "Um Synchronisierungsfehler zu vermeiden, k?nnen einige Einstellungen nicht bearbeitet werden, w?hrend das Konto aktiviert ist."
-    },
-    "manager.missingprovider": {
-        "message": "Dieses Konto ben?tigt den ##provider##-Synchronisations-Provider, noch nicht installiert ist."
-    },
-    "manager.noaccounts": {
-        "message": "Es sind noch keine Konten definiert."
-    },
-    "manager.provider": {
-        "message": "Provider installieren"
-    },
-    "manager.provider4tbsync": {
-        "message": "Provider f?r TbSync"
-    },
-    "manager.resource": {
-        "message": "Ressource"
-    },
-    "manager.shorttitle": {
-        "message": "Kontoverwaltung"
-    },
-    "manager.status": {
-        "message": "Status"
-    },
-    "manager.supporter.contributors": {
-        "message": "Mitwirkende und ?bersetzer"
-    },
-    "manager.supporter.details": {
-        "message": "Details"
-    },
-    "manager.supporter.sponsors": {
-        "message": "Sponsoren von Testkonten"
-    },
-    "manager.tabs.status": {
-        "message": "Synchronisationsstatus"
-    },
-    "manager.tabs.status.autotime": {
-        "message": "Periodische Synchronisation (in Minuten)"
-    },
-    "manager.tabs.status.enableThisAccount": {
-        "message": "Konto aktivieren und synchronisieren"
-    },
-    "manager.tabs.status.general": {
-        "message": "Allgemein"
-    },
-    "manager.tabs.status.never": {
-        "message": "Eine Einstellung von 0 deaktiviert periodische Synchronisation. Push-Synchronisation wird noch nicht unterst?tzt."
-    },
-    "manager.tabs.status.resources": {
-        "message": "Verf?gbare Ressourcen"
-    },
-    "manager.tabs.status.resources.intro": {
-        "message": "W?hlen Sie aus, welche der gefundenen Ressourcen mit Thunderbird synchronisiert werden sollen."
-    },
-    "manager.tabs.status.sync": {
-        "message": "Jetzt synchronisieren"
-    },
-    "manager.tabs.status.tryagain": {
-        "message": "Erneut versuchen, mit dem Server zu verbinden"
-    },
-    "manager.title": {
-        "message": "TbSync Kontoverwaltung"
-    },
-    "manager.tryagain": {
-        "message": "Erneut versuchen, mit dem Server zu verbinden"
-    },
-    "menu.settingslabel": {
-        "message": "Synchronisationseinstellungen (TbSync)"
-    },
-    "password.account": {
-        "message": "Konto:"
-    },
-    "password.description": {
-        "message": "Bitte aktualisieren Sie die Anmeldeinformationen f?r das folgende TbSync-Konto:"
-    },
-    "password.password": {
-        "message": "Passwort:"
-    },
-    "password.title": {
-        "message": "TbSync-Anmeldeinformationen"
-    },
-    "password.user": {
-        "message": "Nutzer:"
-    },
-    "popup.opensettings": {
-        "message": "TbSync-Kontoverwaltung ?ffnen"
-    },
-    "prompt.DeleteAccount": {
-        "message": "Sind Sie sicher, dass Sie das Konto ##accountName## l?schen m?chten?"
-    },
-    "prompt.Disable": {
-        "message": "Sind Sie sicher, dass Sie dieses Konto deaktivieren m?chten? Alle lokalen Ver?nderungen, die noch nicht synchronisiert wurden, gehen dabei verloren!"
-    },
-    "prompt.Erase": {
-        "message": "Sind Sie sicher, dass Sie dieses Konto eines unbekannten Anbieters aus der Kontoliste entfernen m?chten?"
-    },
-    "prompt.Unsubscribe": {
-        "message": "Sind Sie sicher, dass Sie dieses Element nicht l?nger abonnieren m?chten? Alle lokalen Ver?nderungen, die noch nicht synchronisiert wurden, gehen dabei verloren!"
-    },
-    "status.JavaScriptError": {
-        "message": "Javascript-Fehler! Bitte pr?fen Sie das Ereignisprotokoll f?r weitere Details!"
-    },
-    "status.OAuthAbortError": {
-        "message": "OAuth 2.0-Authentifizierungsprozess vom Nutzer abgebrochen."
-    },
-    "status.OAuthHttpError": {
-        "message": "OAuth-2.0-Authentifizierungsprozess fehlgeschlagen (HTTP Error ##replace.1##)."
-    },
-    "status.OAuthNetworkError": {
-        "message": "Verbindung zum OAuth-2.0-Authentifizierungsserver nicht m?glich."
-    },
-    "status.OAuthServerError": {
-        "message": " OAuth-2.0-Authentifizierungsserver meldet: ##replace.1##"
-    },
-    "status.aborted": {
-        "message": "Nicht synchronisiert"
-    },
-    "status.apiError": {
-        "message": "API-Implementierungsfehler"
-    },
-    "status.disabled": {
-        "message": "Konto ist deaktiviert, Synchronisation ist ausgeschaltet."
-    },
-    "status.foldererror": {
-        "message": "Bei mindestens einer Ressource trat ein Synchronisationsfehler auf. Bitte pr?fen Sie das Ereignisprotokoll f?r weitere Details!"
-    },
-    "status.modified": {
-        "message": "Lokale ?nderungen"
-    },
-    "status.network": {
-        "message": "Verbindung zum Server fehlgeschlagen (##replace.1##)."
-    },
-    "status.no-folders-found-on-server": {
-        "message": "Auf dem Server wurden keine Ressourcen gefunden."
-    },
-    "status.notargets": {
-        "message": "Synchronisation abgebrochen, da die Elemente zum Synchronisieren nicht erstellt werden konnten."
-    },
-    "status.notsyncronized": {
-        "message": "Konto muss synchronisiert werden."
-    },
-    "status.pending": {
-        "message": "Warten auf Synchronisation"
-    },
-    "status.security": {
-        "message": "Fehler beim Aufbau einer sicheren Verbindung. Benutzen Sie eventuell ein selbst signiertes oder anderweitig nicht vertrauensw?rdiges Zertifikat, das nicht in Thunderbird importiert ist? (##replace.1##)"
-    },
-    "status.skipped": {
-        "message": "Nicht unterst?tzt"
-    },
-    "status.success": {
-        "message": "Ok"
-    },
-    "status.syncing": {
-        "message": "Synchronisierung"
-    },
-    "status.451": {
-        "message": "Server meldet Weiterleitung. Erneuter Versuch in 5 Sekunden."
-    },
-    "supportwizard.footer": {
-        "message": "Aus den hier angegebenen Informationen wird im n?chsten Schritt eine E-Mail erzeugt, die Sie nachtr?glich noch bearbeiten k?nnen (z.B. Bildschirmfotos o.?. hinzuf?gen). Erst durch das Absenden der E-Mail, wird der Fehlerbericht verschickt."
-    },
-    "supportwizard.label.description": {
-        "message": "Ausf?hrliche Fehlerbeschreibung:"
-    },
-    "supportwizard.label.faultycomponent": {
-        "message": "Komponente von TbSync, bei der Sie den Fehler beobachtet haben:"
-    },
-    "supportwizard.label.selectcomponent": {
-        "message": "Komponente ausw?hlen ..."
-    },
-    "supportwizard.label.summary": {
-        "message": "Kurze Zusammenfassung des Fehlers:"
-    },
-    "supportwizard.pagetitle": {
-        "message": "Erfassung aller Informationen zur effektiven Bearbeitung des Fehlerberichtes."
-    },
-    "supportwizard.provider": {
-        "message": "Provider: ##replace.1##"
-    },
-    "supportwizard.title": {
-        "message": "Fehlerbericht erstellen"
-    },
-    "syncstate.accountdone": {
-        "message": "Kontosynchronisation abgeschlossen"
-    },
-    "syncstate.done": {
-        "message": "Bereite das n?chste Element f?r die Synchronisation vor"
-    },
-    "syncstate.oauthprompt": {
-        "message": "OAuth 2.0 Authentifizierung"
-    },
-    "syncstate.passwordprompt": {
-        "message": "Aufforderung zur Eingabe der Anmeldeinformationen"
-    },
-    "syncstate.preparing": {
-        "message": "Bereite das n?chste Element f?r die Synchronisation vor"
-    },
-    "syncstate.syncing": {
-        "message": "Initiiere Synchronisation"
-    },
-    "target.orphaned": {
-        "message": "Verbindung getrennt"
-    },
-    "toolbar.label": {
-        "message": "Synchronisiere alle TbSync Konten"
-    },
-    "toolbar.tooltiptext": {
-        "message": "Gleiche alle TbSync-Konten mit den Servern ab"
-    },
-    "password.ok": {
-        "message": "Ok"
-    },
-    "password.cancel": {
-        "message": "Abbrechen"
-    }
-}
+{
+    "HelpFixStartupError": {
+        "message": "Um diesen Fehler zu beheben, k?nnen Sie einen Fehlerbericht an den Entwickler von TbSync schicken. Soll der Fehlerbericht jetzt angefertigt werden?"
+    },
+    "NoDebugLog": {
+        "message": "Es liegen keine aussagekr?ftigen Debug-Meldungen vor. Bitte aktivieren Sie den Debug-Modus, starten Thunderbird neu und wiederholen dann alle Schritte, um das fehlerhafte Verhalten zu reproduzieren."
+    },
+    "OopsMessage": {
+        "message": "Hoppla! TbSync konnte nicht starten!"
+    },
+    "RestartThunderbirdAndTryAgain": {
+        "message": "Das TbSync-Debug-Protokoll wurde eingeschaltet. Bitte starten Sie Thunderbird neu, und versuchen Sie dann noch einmal, TbSync zu ?ffnen!"
+    },
+    "UnableToTraceError": {
+        "message": "Dieser Fehler kann nicht untersucht werden, solange das Debug-Protokoll deaktiviert ist. Soll das Protokoll jetzt aktiviert werden, damit dieser Fehler untersucht und behoben werden kann?"
+    },
+    "accountacctions.delete": {
+        "message": "Konto ?##accountname##? l?schen"
+    },
+    "accountacctions.disable": {
+        "message": "Konto '##accountname##' deaktivieren"
+    },
+    "accountacctions.enable": {
+        "message": "Konto ?##accountname##? aktivieren und Server kontaktieren"
+    },
+    "accountacctions.sync": {
+        "message": "Konto ?##accountname##? synchronisieren"
+    },
+    "addressbook.searchall": {
+        "message": "Alle Adressb?cher durchsuchen"
+    },
+    "addressbook.searchgal": {
+        "message": "Dieses Adressbuch und das globale Serververzeichnis durchsuchen (##replace.1##)"
+    },
+    "addressbook.searchthis": {
+        "message": "Dieses Adressbuch durchsuchen"
+    },
+    "eventlog.clear": {
+        "message": "Leeren"
+    },
+    "eventlog.close": {
+        "message": "Schlie?en"
+    },
+    "eventlog.title": {
+        "message": "Ereignisprotokoll"
+    },
+    "extensionDescription": {
+        "message": "TbSync ist eine zentrale Benutzeroberfl?che zur Verwaltung von Cloud-Konten und zur Synchronisierung ihrer Kontakt-, Aufgaben- und Kalenderinformationen mit Thunderbird."
+    },
+    "google.translate.code": {
+        "message": "de"
+    },
+    "helplink.security": {
+        "message": "https://github.com/jobisoft/TbSync/wiki/How-to-use-TbSync-with-self-signed-or-otherwise-untrusted-certificates%3F"
+    },
+    "info.error": {
+        "message": "Fehler"
+    },
+    "info.idle": {
+        "message": "Leerlauf"
+    },
+    "installProvider.header": {
+        "message": "Provider ?##replace.1##? f?r TbSync ist noch nicht installiert."
+    },
+    "manager.AccountActions": {
+        "message": "Konto-Aktionen"
+    },
+    "manager.AddAccount": {
+        "message": "Konto hinzuf?gen"
+    },
+    "manager.DeleteAccount": {
+        "message": "Konto entfernen"
+    },
+    "manager.DisableAccount": {
+        "message": "Konto deaktivieren"
+    },
+    "manager.EnableAccount": {
+        "message": "Konto aktivieren und mit dem Server verbinden"
+    },
+    "manager.RetryConnectAccount": {
+        "message": "Erneut versuchen, mit dem Server zu verbinden"
+    },
+    "manager.ShowEventLog": {
+        "message": "Ereignisprotokoll anzeigen"
+    },
+    "manager.SyncAll": {
+        "message": "Synchronisiere alle aktivierten Konten"
+    },
+    "manager.SynchronizeAccount": {
+        "message": "Konto synchronisieren"
+    },
+    "manager.accounts": {
+        "message": "Konten"
+    },
+    "manager.accountsettings": {
+        "message": "Kontoeinstellungen"
+    },
+    "manager.catman.text": {
+        "message": "TbSync synchronisiert auch Kontaktkategorien, die einen effizienten Ersatz f?r die nicht synchronisierbaren Kontaktlisten darstellen. Um diese im Thunderbird-Adressbuch zu nutzen, k?nnen Sie das Add-On ?Category Manager? installieren. Dieses Add-On erm?glicht die Verwaltung ?berlappender kategoriebasierter Kontaktgruppen und stellt eine Reihe anderer kategoriespezifischer Funktionen bereit. Es kann aus dem offiziellen Mozilla Add-On Repository heruntergeladen werden:"
+    },
+    "manager.community": {
+        "message": "Nutzergemeinschaft"
+    },
+    "manager.connecting": {
+        "message": "Verbindung wird hergestellt"
+    },
+    "manager.help": {
+        "message": "Hilfe"
+    },
+    "manager.help.createbugreport": {
+        "message": "Fehlerbericht erstellen"
+    },
+    "manager.help.createbugreportinfo": {
+        "message": "Damit TbSync nur die f?r Ihren Fehlerbericht relevanten Debug-Daten sammelt, starten Sie Thunderbird bitte neu und wiederholen dann genau die Schritte, die das fehlerhafte Verhalten reproduzieren. Anschlie?end k?nnen Sie hier Ihren Fehlerbericht erstellen."
+    },
+    "manager.help.debuglevel.0": {
+        "message": "Deaktiviert"
+    },
+    "manager.help.debuglevel.1": {
+        "message": "Aktiviert: Protokolliert alle Fehler"
+    },
+    "manager.help.debuglevel.2": {
+        "message": "Aktiviert: Protokolliert alle gesendeten und empfangenen Daten"
+    },
+    "manager.help.debuglevel.3": {
+        "message": "Aktiviert: Protokolliert alle Daten und einige interne Debug-Werte"
+    },
+    "manager.help.debugmode": {
+        "message": "Debug-Modus:"
+    },
+    "manager.help.fixit": {
+        "message": "Sie k?nnen helfen den Fehler zu korrigieren, indem Sie dem Entwickler einen Fehlerbericht zusenden. Bitte aktivieren Sie dazu den Debug-Modus."
+    },
+    "manager.help.foundabug": {
+        "message": "Sie haben einen Fehler gefunden?"
+    },
+    "manager.help.needhelp": {
+        "message": "Ben?tigen Sie Hilfe?"
+    },
+    "manager.help.viewdebuglog": {
+        "message": "Debug-Protokoll anzeigen"
+    },
+    "manager.help.wiki": {
+        "message": "Besuchen Sie die Wikiseiten des TbSync-Projekts, diese enthalten zus?tzliche Informationen, Benutzeranleitungen und detaillierte Konfigurationsbeschreibungen."
+    },
+    "manager.installprovider.link": {
+        "message": "Klicken Sie auf den folgenden Link, um die Informationsseite des fehlenden Synchronisations-Providers aufzurufen. Dort finden Sie weitere Informationen dazu und haben die M?glichkeit, diesen zu installieren:"
+    },
+    "manager.installprovider.warning": {
+        "message": "Dieser Provider stammt nicht aus der offiziellen Thunderbird-Add-On-Sammlung und wurde demnach nicht von Thunderbird-Mitarbeitern ?berpr?ft. Es k?nnte sich um Schad-Software handeln, deshalb verwenden Sie es auf eigene Gefahr."
+    },
+    "manager.lockedsettings.description": {
+        "message": "Um Synchronisierungsfehler zu vermeiden, k?nnen einige Einstellungen nicht bearbeitet werden, w?hrend das Konto aktiviert ist."
+    },
+    "manager.missingprovider": {
+        "message": "Dieses Konto ben?tigt den ##provider##-Synchronisations-Provider, noch nicht installiert ist."
+    },
+    "manager.noaccounts": {
+        "message": "Es sind noch keine Konten definiert."
+    },
+    "manager.provider": {
+        "message": "Provider installieren"
+    },
+    "manager.provider4tbsync": {
+        "message": "Provider f?r TbSync"
+    },
+    "manager.resource": {
+        "message": "Ressource"
+    },
+    "manager.shorttitle": {
+        "message": "Kontoverwaltung"
+    },
+    "manager.status": {
+        "message": "Status"
+    },
+    "manager.supporter.contributors": {
+        "message": "Mitwirkende und ?bersetzer"
+    },
+    "manager.supporter.details": {
+        "message": "Details"
+    },
+    "manager.supporter.sponsors": {
+        "message": "Sponsoren von Testkonten"
+    },
+    "manager.tabs.status": {
+        "message": "Synchronisationsstatus"
+    },
+    "manager.tabs.status.autotime": {
+        "message": "Periodische Synchronisation (in Minuten)"
+    },
+    "manager.tabs.status.enableThisAccount": {
+        "message": "Konto aktivieren und synchronisieren"
+    },
+    "manager.tabs.status.general": {
+        "message": "Allgemein"
+    },
+    "manager.tabs.status.never": {
+        "message": "Eine Einstellung von 0 deaktiviert periodische Synchronisation. Push-Synchronisation wird noch nicht unterst?tzt."
+    },
+    "manager.tabs.status.resources": {
+        "message": "Verf?gbare Ressourcen"
+    },
+    "manager.tabs.status.resources.intro": {
+        "message": "W?hlen Sie aus, welche der gefundenen Ressourcen mit Thunderbird synchronisiert werden sollen."
+    },
+    "manager.tabs.status.sync": {
+        "message": "Jetzt synchronisieren"
+    },
+    "manager.tabs.status.tryagain": {
+        "message": "Erneut versuchen, mit dem Server zu verbinden"
+    },
+    "manager.title": {
+        "message": "TbSync Kontoverwaltung"
+    },
+    "manager.tryagain": {
+        "message": "Erneut versuchen, mit dem Server zu verbinden"
+    },
+    "menu.settingslabel": {
+        "message": "Synchronisationseinstellungen (TbSync)"
+    },
+    "password.account": {
+        "message": "Konto:"
+    },
+    "password.description": {
+        "message": "Bitte aktualisieren Sie die Anmeldeinformationen f?r das folgende TbSync-Konto:"
+    },
+    "password.password": {
+        "message": "Passwort:"
+    },
+    "password.title": {
+        "message": "TbSync-Anmeldeinformationen"
+    },
+    "password.user": {
+        "message": "Nutzer:"
+    },
+    "popup.opensettings": {
+        "message": "TbSync-Kontoverwaltung ?ffnen"
+    },
+    "prompt.DeleteAccount": {
+        "message": "Sind Sie sicher, dass Sie das Konto ##accountName## l?schen m?chten?"
+    },
+    "prompt.Disable": {
+        "message": "Sind Sie sicher, dass Sie dieses Konto deaktivieren m?chten? Alle lokalen Ver?nderungen, die noch nicht synchronisiert wurden, gehen dabei verloren!"
+    },
+    "prompt.Erase": {
+        "message": "Sind Sie sicher, dass Sie dieses Konto eines unbekannten Anbieters aus der Kontoliste entfernen m?chten?"
+    },
+    "prompt.Unsubscribe": {
+        "message": "Sind Sie sicher, dass Sie dieses Element nicht l?nger abonnieren m?chten? Alle lokalen Ver?nderungen, die noch nicht synchronisiert wurden, gehen dabei verloren!"
+    },
+    "status.JavaScriptError": {
+        "message": "Javascript-Fehler! Bitte pr?fen Sie das Ereignisprotokoll f?r weitere Details!"
+    },
+    "status.OAuthAbortError": {
+        "message": "OAuth 2.0-Authentifizierungsprozess vom Nutzer abgebrochen."
+    },
+    "status.OAuthHttpError": {
+        "message": "OAuth-2.0-Authentifizierungsprozess fehlgeschlagen (HTTP Error ##replace.1##)."
+    },
+    "status.OAuthNetworkError": {
+        "message": "Verbindung zum OAuth-2.0-Authentifizierungsserver nicht m?glich."
+    },
+    "status.OAuthServerError": {
+        "message": " OAuth-2.0-Authentifizierungsserver meldet: ##replace.1##"
+    },
+    "status.aborted": {
+        "message": "Nicht synchronisiert"
+    },
+    "status.apiError": {
+        "message": "API-Implementierungsfehler"
+    },
+    "status.disabled": {
+        "message": "Konto ist deaktiviert, Synchronisation ist ausgeschaltet."
+    },
+    "status.foldererror": {
+        "message": "Bei mindestens einer Ressource trat ein Synchronisationsfehler auf. Bitte pr?fen Sie das Ereignisprotokoll f?r weitere Details!"
+    },
+    "status.modified": {
+        "message": "Lokale ?nderungen"
+    },
+    "status.network": {
+        "message": "Verbindung zum Server fehlgeschlagen (##replace.1##)."
+    },
+    "status.no-folders-found-on-server": {
+        "message": "Auf dem Server wurden keine Ressourcen gefunden."
+    },
+    "status.notargets": {
+        "message": "Synchronisation abgebrochen, da die Elemente zum Synchronisieren nicht erstellt werden konnten."
+    },
+    "status.notsyncronized": {
+        "message": "Konto muss synchronisiert werden."
+    },
+    "status.pending": {
+        "message": "Warten auf Synchronisation"
+    },
+    "status.security": {
+        "message": "Fehler beim Aufbau einer sicheren Verbindung. Benutzen Sie eventuell ein selbst signiertes oder anderweitig nicht vertrauensw?rdiges Zertifikat, das nicht in Thunderbird importiert ist? (##replace.1##)"
+    },
+    "status.skipped": {
+        "message": "Nicht unterst?tzt"
+    },
+    "status.success": {
+        "message": "Ok"
+    },
+    "status.syncing": {
+        "message": "Synchronisierung"
+    },
+    "status.451": {
+        "message": "Server meldet Weiterleitung. Erneuter Versuch in 5 Sekunden."
+    },
+    "supportwizard.footer": {
+        "message": "Aus den hier angegebenen Informationen wird im n?chsten Schritt eine E-Mail erzeugt, die Sie nachtr?glich noch bearbeiten k?nnen (z.B. Bildschirmfotos o.?. hinzuf?gen). Erst durch das Absenden der E-Mail, wird der Fehlerbericht verschickt."
+    },
+    "supportwizard.label.description": {
+        "message": "Ausf?hrliche Fehlerbeschreibung:"
+    },
+    "supportwizard.label.faultycomponent": {
+        "message": "Komponente von TbSync, bei der Sie den Fehler beobachtet haben:"
+    },
+    "supportwizard.label.selectcomponent": {
+        "message": "Komponente ausw?hlen ..."
+    },
+    "supportwizard.label.summary": {
+        "message": "Kurze Zusammenfassung des Fehlers:"
+    },
+    "supportwizard.pagetitle": {
+        "message": "Erfassung aller Informationen zur effektiven Bearbeitung des Fehlerberichtes."
+    },
+    "supportwizard.provider": {
+        "message": "Provider: ##replace.1##"
+    },
+    "supportwizard.title": {
+        "message": "Fehlerbericht erstellen"
+    },
+    "syncstate.accountdone": {
+        "message": "Kontosynchronisation abgeschlossen"
+    },
+    "syncstate.done": {
+        "message": "Bereite das n?chste Element f?r die Synchronisation vor"
+    },
+    "syncstate.oauthprompt": {
+        "message": "OAuth 2.0 Authentifizierung"
+    },
+    "syncstate.passwordprompt": {
+        "message": "Aufforderung zur Eingabe der Anmeldeinformationen"
+    },
+    "syncstate.preparing": {
+        "message": "Bereite das n?chste Element f?r die Synchronisation vor"
+    },
+    "syncstate.syncing": {
+        "message": "Initiiere Synchronisation"
+    },
+    "target.orphaned": {
+        "message": "Verbindung getrennt"
+    },
+    "toolbar.label": {
+        "message": "Synchronisiere alle TbSync Konten"
+    },
+    "toolbar.tooltiptext": {
+        "message": "Gleiche alle TbSync-Konten mit den Servern ab"
+    },
+    "password.ok": {
+        "message": "Ok"
+    },
+    "password.cancel": {
+        "message": "Abbrechen"
+    }
+}
diff -Nru tbsync-4.12/_locales/en-US/messages.json tbsync-4.16/_locales/en-US/messages.json
--- tbsync-4.12/_locales/en-US/messages.json	2024-08-27 18:32:08.000000000 +0200
+++ tbsync-4.16/_locales/en-US/messages.json	2024-08-27 18:29:06.000000000 +0200
@@ -1,368 +1,368 @@
-{
-    "HelpFixStartupError": {
-        "message": "To help fix this error, you could send a debug log to the TbSync developer. Prepare that email now?"
-    },
-    "NoDebugLog": {
-        "message": "Could not find any useful debug messages. Please activate debug mode, restart Thunderbird and repeat all the steps needed to trigger the erroneous behavior."
-    },
-    "OopsMessage": {
-        "message": "Oops! TbSync was not able to start!"
-    },
-    "RestartThunderbirdAndTryAgain": {
-        "message": "TbSync debug log has been enabled, please restart Thunderbird and again try to open TbSync."
-    },
-    "UnableToTraceError": {
-        "message": "It is not possible to trace this error, because debug log is currently not enabled. Do you want to enable debug log now, to help fix this error?"
-    },
-    "accountacctions.delete": {
-        "message": "Delete account ?##accountname##?"
-    },
-    "accountacctions.disable": {
-        "message": "Disable account ?##accountname##?"
-    },
-    "accountacctions.enable": {
-        "message": "Enable account ?##accountname##? & try to connect to server"
-    },
-    "accountacctions.sync": {
-        "message": "Synchronize account ?##accountname##?"
-    },
-    "addressbook.searchall": {
-        "message": "Search all address books"
-    },
-    "addressbook.searchgal": {
-        "message": "Search this address book and the global directory (##replace.1##)"
-    },
-    "addressbook.searchthis": {
-        "message": "Search this address book"
-    },
-    "eventlog.clear": {
-        "message": "Clear"
-    },
-    "eventlog.close": {
-        "message": "Close"
-    },
-    "eventlog.title": {
-        "message": "Event log"
-    },
-    "extensionDescription": {
-        "message": "TbSync is a central user interface to manage cloud accounts and to synchronize their contact, task and calendar information with Thunderbird."
-    },
-    "google.translate.code": {
-        "message": "en"
-    },
-    "helplink.security": {
-        "message": "https://github.com/jobisoft/TbSync/wiki/How-to-use-TbSync-with-self-signed-or-otherwise-untrusted-certificates%3F"
-    },
-    "info.error": {
-        "message": "Error"
-    },
-    "info.idle": {
-        "message": "Idle"
-    },
-    "installProvider.header": {
-        "message": "Provider ?##replace.1##? for TbSync is not yet installed."
-    },
-    "manager.AccountActions": {
-        "message": "Account actions"
-    },
-    "manager.AddAccount": {
-        "message": "Add new account"
-    },
-    "manager.DeleteAccount": {
-        "message": "Delete account"
-    },
-    "manager.DisableAccount": {
-        "message": "Disable account"
-    },
-    "manager.EnableAccount": {
-        "message": "Enable account & try to connect to server"
-    },
-    "manager.RetryConnectAccount": {
-        "message": "Try again to connect to server"
-    },
-    "manager.ShowEventLog": {
-        "message": "Open event log"
-    },
-    "manager.SyncAll": {
-        "message": "Synchronize all enabled accounts"
-    },
-    "manager.SynchronizeAccount": {
-        "message": "Synchronize account"
-    },
-    "manager.accounts": {
-        "message": "Accounts"
-    },
-    "manager.accountsettings": {
-        "message": "Account Settings"
-    },
-    "manager.catman.text": {
-        "message": "TbSync also syncs contact categories, which are a powerful replacement for the non-synchronizable contact lists. To be able to use them in the Thunderbird address book you can install the Category Manager add-on. It allows to manage overlapping category based contact groups and provides a bunch of other category-related features. It can be found in the official Mozilla add-on repository:"
-    },
-    "manager.community": {
-        "message": "Community"
-    },
-    "manager.connecting": {
-        "message": "Connecting to server"
-    },
-    "manager.help": {
-        "message": "Help"
-    },
-    "manager.help.createbugreport": {
-        "message": "Create bug report"
-    },
-    "manager.help.createbugreportinfo": {
-        "message": "In order for TbSync to collect only the debug data relevant to your bug report, please restart Thunderbird and then repeat exactly the steps that reproduce the buggy behavior. Then you can create your bug report here."
-    },
-    "manager.help.debuglevel.0": {
-        "message": "Disabled"
-    },
-    "manager.help.debuglevel.1": {
-        "message": "Enabled: Logging of errors only"
-    },
-    "manager.help.debuglevel.2": {
-        "message": "Enabled: Logging of all sent and received data"
-    },
-    "manager.help.debuglevel.3": {
-        "message": "Enabled: Logging of all data and some internal debug values"
-    },
-    "manager.help.debugmode": {
-        "message": "Debug mode:"
-    },
-    "manager.help.fixit": {
-        "message": "You can help to fix it by sending in a bug report. This requires the activation of debug mode."
-    },
-    "manager.help.foundabug": {
-        "message": "Found a bug?"
-    },
-    "manager.help.needhelp": {
-        "message": "Need Help?"
-    },
-    "manager.help.viewdebuglog": {
-        "message": "View debug log"
-    },
-    "manager.help.wiki": {
-        "message": "Open the wiki pages of the TbSync project, they provide additional information, guides and detailed configuration descriptions."
-    },
-    "manager.installprovider.link": {
-        "message": "Click on the following link to open the info page of the missing synchronization provider. There you will find further information about the provider and you will have the option to install it:"
-    },
-    "manager.installprovider.warning": {
-        "message": "This synchronization provider is not hosted in the official Thunderbird add-on repository and thus has not been reviewed by Thunderbird staff. The provider could do bad things to your system. Use it at your own risk."
-    },
-    "manager.lockedsettings.description": {
-        "message": "To prevent synchronization errors, some settings cannot be edited while the account is enabled."
-    },
-    "manager.missingprovider": {
-        "message": "This account requires the ##provider## synchronization provider, which is currently not installed."
-    },
-    "manager.noaccounts": {
-        "message": "There are not yet any accounts defined."
-    },
-    "manager.provider": {
-        "message": "Install Provider"
-    },
-    "manager.provider4tbsync": {
-        "message": "Provider for TbSync"
-    },
-    "manager.resource": {
-        "message": "Resource"
-    },
-    "manager.shorttitle": {
-        "message": "Account manager"
-    },
-    "manager.status": {
-        "message": "Status"
-    },
-    "manager.supporter.contributors": {
-        "message": "Contributors & Translators"
-    },
-    "manager.supporter.details": {
-        "message": "Details"
-    },
-    "manager.supporter.sponsors": {
-        "message": "Sponsors of test accounts"
-    },
-    "manager.tabs.status": {
-        "message": "Synchronization status"
-    },
-    "manager.tabs.status.autotime": {
-        "message": "Periodic synchronization (in minutes)"
-    },
-    "manager.tabs.status.enableThisAccount": {
-        "message": "Enable and synchronize this account"
-    },
-    "manager.tabs.status.general": {
-        "message": "General"
-    },
-    "manager.tabs.status.never": {
-        "message": "A setting of 0 disables periodic sync. Push sync is not yet implemented."
-    },
-    "manager.tabs.status.resources": {
-        "message": "Available resources"
-    },
-    "manager.tabs.status.resources.intro": {
-        "message": "Select which of the found resources should be synchronized with Thunderbird."
-    },
-    "manager.tabs.status.sync": {
-        "message": "Synchronize now"
-    },
-    "manager.tabs.status.tryagain": {
-        "message": "Try again to connect server"
-    },
-    "manager.title": {
-        "message": "TbSync account manager"
-    },
-    "manager.tryagain": {
-        "message": "Try again to connect server"
-    },
-    "menu.settingslabel": {
-        "message": "Synchronization Settings (TbSync)"
-    },
-    "password.account": {
-        "message": "Account:"
-    },
-    "password.description": {
-        "message": "Please update the credentials for the following TbSync account:"
-    },
-    "password.password": {
-        "message": "Password:"
-    },
-    "password.title": {
-        "message": "TbSync Credential Request"
-    },
-    "password.user": {
-        "message": "User:"
-    },
-    "popup.opensettings": {
-        "message": "Open TbSync account manager"
-    },
-    "prompt.DeleteAccount": {
-        "message": "Are you sure you want to delete account ##accountName##?"
-    },
-    "prompt.Disable": {
-        "message": "Are you sure you want to disable this account? All local modifications, which have not been synced yet, will be lost!"
-    },
-    "prompt.Erase": {
-        "message": "Are you sure you want to remove this account of an unknown provider from the accounts lists?"
-    },
-    "prompt.Unsubscribe": {
-        "message": "Are you sure you want to unsubscribe this item? All local modifications, which have not been synced yet, will be lost!"
-    },
-    "status.JavaScriptError": {
-        "message": "Javascript Error! Please check the event log for more details."
-    },
-    "status.OAuthAbortError": {
-        "message": "OAuth 2.0 authentication process aborted by user."
-    },
-    "status.OAuthHttpError": {
-        "message": "OAuth 2.0 authentication process failed (HTTP error ##replace.1##)."
-    },
-    "status.OAuthNetworkError": {
-        "message": "Could not connect to OAuth 2.0 authentication server."
-    },
-    "status.OAuthServerError": {
-        "message": " OAuth 2.0 authentication server returned: ##replace.1##"
-    },
-    "status.aborted": {
-        "message": "Not synchronized"
-    },
-    "status.apiError": {
-        "message": "API implementation error"
-    },
-    "status.disabled": {
-        "message": "Account is not enabled, synchronization is disabled."
-    },
-    "status.foldererror": {
-        "message": "At least one resource encountered a synchronization error. Please check the event log for more details."
-    },
-    "status.modified": {
-        "message": "Local modifications"
-    },
-    "status.network": {
-        "message": "Could not connect to server (##replace.1##)."
-    },
-    "status.no-folders-found-on-server": {
-        "message": "Could not find any resources on the server."
-    },
-    "status.notargets": {
-        "message": "Aborting synchronization, because sync targets could not be created."
-    },
-    "status.notsyncronized": {
-        "message": "Account needs to be synchronized, at least one item is out of sync."
-    },
-    "status.pending": {
-        "message": "Waiting to be synchronized"
-    },
-    "status.security": {
-        "message": "Could not establish a secure connection. Are you using a self-signed or otherwise untrusted certificate without importing it into Thunderbird? (##replace.1##)"
-    },
-    "status.skipped": {
-        "message": "Not yet supported, skipped"
-    },
-    "status.success": {
-        "message": "OK"
-    },
-    "status.syncing": {
-        "message": "Synchronizing"
-    },
-    "status.451": {
-        "message": "Server issued redirect, retry in 5 seconds."
-    },
-    "supportwizard.footer": {
-        "message": "From the information given here, an e-mail will be generated in the next step, which you can subsequently edit (for example, adding screenshots or similar). Only by actually sending that e-mail, the error report will be sent."
-    },
-    "supportwizard.label.description": {
-        "message": "Detailed error description:"
-    },
-    "supportwizard.label.faultycomponent": {
-        "message": "Component of TbSync where you have observed the error:"
-    },
-    "supportwizard.label.selectcomponent": {
-        "message": "Select component?"
-    },
-    "supportwizard.label.summary": {
-        "message": "Short summary of the error:"
-    },
-    "supportwizard.pagetitle": {
-        "message": "Gathering of all information to effectively process the bug report."
-    },
-    "supportwizard.provider": {
-        "message": "Provider: ##replace.1##"
-    },
-    "supportwizard.title": {
-        "message": "Create bug report"
-    },
-    "syncstate.accountdone": {
-        "message": "Finished account"
-    },
-    "syncstate.done": {
-        "message": "Preparing next item for synchronization"
-    },
-    "syncstate.oauthprompt": {
-        "message": "OAuth 2.0 authentication"
-    },
-    "syncstate.passwordprompt": {
-        "message": "Prompting for credentials"
-    },
-    "syncstate.preparing": {
-        "message": "Preparing next item for synchronization"
-    },
-    "syncstate.syncing": {
-        "message": "Initialize synchronization"
-    },
-    "target.orphaned": {
-        "message": "Disconnected"
-    },
-    "toolbar.label": {
-        "message": "Synchronize all TbSync accounts"
-    },
-    "toolbar.tooltiptext": {
-        "message": "Synchronize latest changes"
-    },
-    "password.ok": {
-        "message": "OK"
-    },
-    "password.cancel": {
-        "message": "Cancel"
-    }
-}
+{
+    "HelpFixStartupError": {
+        "message": "To help fix this error, you could send a debug log to the TbSync developer. Prepare that email now?"
+    },
+    "NoDebugLog": {
+        "message": "Could not find any useful debug messages. Please activate debug mode, restart Thunderbird and repeat all the steps needed to trigger the erroneous behavior."
+    },
+    "OopsMessage": {
+        "message": "Oops! TbSync was not able to start!"
+    },
+    "RestartThunderbirdAndTryAgain": {
+        "message": "TbSync debug log has been enabled, please restart Thunderbird and again try to open TbSync."
+    },
+    "UnableToTraceError": {
+        "message": "It is not possible to trace this error, because debug log is currently not enabled. Do you want to enable debug log now, to help fix this error?"
+    },
+    "accountacctions.delete": {
+        "message": "Delete account ?##accountname##?"
+    },
+    "accountacctions.disable": {
+        "message": "Disable account ?##accountname##?"
+    },
+    "accountacctions.enable": {
+        "message": "Enable account ?##accountname##? & try to connect to server"
+    },
+    "accountacctions.sync": {
+        "message": "Synchronize account ?##accountname##?"
+    },
+    "addressbook.searchall": {
+        "message": "Search all address books"
+    },
+    "addressbook.searchgal": {
+        "message": "Search this address book and the global directory (##replace.1##)"
+    },
+    "addressbook.searchthis": {
+        "message": "Search this address book"
+    },
+    "eventlog.clear": {
+        "message": "Clear"
+    },
+    "eventlog.close": {
+        "message": "Close"
+    },
+    "eventlog.title": {
+        "message": "Event log"
+    },
+    "extensionDescription": {
+        "message": "TbSync is a central user interface to manage cloud accounts and to synchronize their contact, task and calendar information with Thunderbird."
+    },
+    "google.translate.code": {
+        "message": "en"
+    },
+    "helplink.security": {
+        "message": "https://github.com/jobisoft/TbSync/wiki/How-to-use-TbSync-with-self-signed-or-otherwise-untrusted-certificates%3F"
+    },
+    "info.error": {
+        "message": "Error"
+    },
+    "info.idle": {
+        "message": "Idle"
+    },
+    "installProvider.header": {
+        "message": "Provider ?##replace.1##? for TbSync is not yet installed."
+    },
+    "manager.AccountActions": {
+        "message": "Account actions"
+    },
+    "manager.AddAccount": {
+        "message": "Add new account"
+    },
+    "manager.DeleteAccount": {
+        "message": "Delete account"
+    },
+    "manager.DisableAccount": {
+        "message": "Disable account"
+    },
+    "manager.EnableAccount": {
+        "message": "Enable account & try to connect to server"
+    },
+    "manager.RetryConnectAccount": {
+        "message": "Try again to connect to server"
+    },
+    "manager.ShowEventLog": {
+        "message": "Open event log"
+    },
+    "manager.SyncAll": {
+        "message": "Synchronize all enabled accounts"
+    },
+    "manager.SynchronizeAccount": {
+        "message": "Synchronize account"
+    },
+    "manager.accounts": {
+        "message": "Accounts"
+    },
+    "manager.accountsettings": {
+        "message": "Account Settings"
+    },
+    "manager.catman.text": {
+        "message": "TbSync also syncs contact categories, which are a powerful replacement for the non-synchronizable contact lists. To be able to use them in the Thunderbird address book you can install the Category Manager add-on. It allows to manage overlapping category based contact groups and provides a bunch of other category-related features. It can be found in the official Mozilla add-on repository:"
+    },
+    "manager.community": {
+        "message": "Community"
+    },
+    "manager.connecting": {
+        "message": "Connecting to server"
+    },
+    "manager.help": {
+        "message": "Help"
+    },
+    "manager.help.createbugreport": {
+        "message": "Create bug report"
+    },
+    "manager.help.createbugreportinfo": {
+        "message": "In order for TbSync to collect only the debug data relevant to your bug report, please restart Thunderbird and then repeat exactly the steps that reproduce the buggy behavior. Then you can create your bug report here."
+    },
+    "manager.help.debuglevel.0": {
+        "message": "Disabled"
+    },
+    "manager.help.debuglevel.1": {
+        "message": "Enabled: Logging of errors only"
+    },
+    "manager.help.debuglevel.2": {
+        "message": "Enabled: Logging of all sent and received data"
+    },
+    "manager.help.debuglevel.3": {
+        "message": "Enabled: Logging of all data and some internal debug values"
+    },
+    "manager.help.debugmode": {
+        "message": "Debug mode:"
+    },
+    "manager.help.fixit": {
+        "message": "You can help to fix it by sending in a bug report. This requires the activation of debug mode."
+    },
+    "manager.help.foundabug": {
+        "message": "Found a bug?"
+    },
+    "manager.help.needhelp": {
+        "message": "Need Help?"
+    },
+    "manager.help.viewdebuglog": {
+        "message": "View debug log"
+    },
+    "manager.help.wiki": {
+        "message": "Open the wiki pages of the TbSync project, they provide additional information, guides and detailed configuration descriptions."
+    },
+    "manager.installprovider.link": {
+        "message": "Click on the following link to open the info page of the missing synchronization provider. There you will find further information about the provider and you will have the option to install it:"
+    },
+    "manager.installprovider.warning": {
+        "message": "This synchronization provider is not hosted in the official Thunderbird add-on repository and thus has not been reviewed by Thunderbird staff. The provider could do bad things to your system. Use it at your own risk."
+    },
+    "manager.lockedsettings.description": {
+        "message": "To prevent synchronization errors, some settings cannot be edited while the account is enabled."
+    },
+    "manager.missingprovider": {
+        "message": "This account requires the ##provider## synchronization provider, which is currently not installed."
+    },
+    "manager.noaccounts": {
+        "message": "There are not yet any accounts defined."
+    },
+    "manager.provider": {
+        "message": "Install Provider"
+    },
+    "manager.provider4tbsync": {
+        "message": "Provider for TbSync"
+    },
+    "manager.resource": {
+        "message": "Resource"
+    },
+    "manager.shorttitle": {
+        "message": "Account manager"
+    },
+    "manager.status": {
+        "message": "Status"
+    },
+    "manager.supporter.contributors": {
+        "message": "Contributors & Translators"
+    },
+    "manager.supporter.details": {
+        "message": "Details"
+    },
+    "manager.supporter.sponsors": {
+        "message": "Sponsors of test accounts"
+    },
+    "manager.tabs.status": {
+        "message": "Synchronization status"
+    },
+    "manager.tabs.status.autotime": {
+        "message": "Periodic synchronization (in minutes)"
+    },
+    "manager.tabs.status.enableThisAccount": {
+        "message": "Enable and synchronize this account"
+    },
+    "manager.tabs.status.general": {
+        "message": "General"
+    },
+    "manager.tabs.status.never": {
+        "message": "A setting of 0 disables periodic sync. Push sync is not yet implemented."
+    },
+    "manager.tabs.status.resources": {
+        "message": "Available resources"
+    },
+    "manager.tabs.status.resources.intro": {
+        "message": "Select which of the found resources should be synchronized with Thunderbird."
+    },
+    "manager.tabs.status.sync": {
+        "message": "Synchronize now"
+    },
+    "manager.tabs.status.tryagain": {
+        "message": "Try again to connect server"
+    },
+    "manager.title": {
+        "message": "TbSync account manager"
+    },
+    "manager.tryagain": {
+        "message": "Try again to connect server"
+    },
+    "menu.settingslabel": {
+        "message": "Synchronization Settings (TbSync)"
+    },
+    "password.account": {
+        "message": "Account:"
+    },
+    "password.description": {
+        "message": "Please update the credentials for the following TbSync account:"
+    },
+    "password.password": {
+        "message": "Password:"
+    },
+    "password.title": {
+        "message": "TbSync Credential Request"
+    },
+    "password.user": {
+        "message": "User:"
+    },
+    "popup.opensettings": {
+        "message": "Open TbSync account manager"
+    },
+    "prompt.DeleteAccount": {
+        "message": "Are you sure you want to delete account ##accountName##?"
+    },
+    "prompt.Disable": {
+        "message": "Are you sure you want to disable this account? All local modifications, which have not been synced yet, will be lost!"
+    },
+    "prompt.Erase": {
+        "message": "Are you sure you want to remove this account of an unknown provider from the accounts lists?"
+    },
+    "prompt.Unsubscribe": {
+        "message": "Are you sure you want to unsubscribe this item? All local modifications, which have not been synced yet, will be lost!"
+    },
+    "status.JavaScriptError": {
+        "message": "Javascript Error! Please check the event log for more details."
+    },
+    "status.OAuthAbortError": {
+        "message": "OAuth 2.0 authentication process aborted by user."
+    },
+    "status.OAuthHttpError": {
+        "message": "OAuth 2.0 authentication process failed (HTTP error ##replace.1##)."
+    },
+    "status.OAuthNetworkError": {
+        "message": "Could not connect to OAuth 2.0 authentication server."
+    },
+    "status.OAuthServerError": {
+        "message": " OAuth 2.0 authentication server returned: ##replace.1##"
+    },
+    "status.aborted": {
+        "message": "Not synchronized"
+    },
+    "status.apiError": {
+        "message": "API implementation error"
+    },
+    "status.disabled": {
+        "message": "Account is not enabled, synchronization is disabled."
+    },
+    "status.foldererror": {
+        "message": "At least one resource encountered a synchronization error. Please check the event log for more details."
+    },
+    "status.modified": {
+        "message": "Local modifications"
+    },
+    "status.network": {
+        "message": "Could not connect to server (##replace.1##)."
+    },
+    "status.no-folders-found-on-server": {
+        "message": "Could not find any resources on the server."
+    },
+    "status.notargets": {
+        "message": "Aborting synchronization, because sync targets could not be created."
+    },
+    "status.notsyncronized": {
+        "message": "Account needs to be synchronized, at least one item is out of sync."
+    },
+    "status.pending": {
+        "message": "Waiting to be synchronized"
+    },
+    "status.security": {
+        "message": "Could not establish a secure connection. Are you using a self-signed or otherwise untrusted certificate without importing it into Thunderbird? (##replace.1##)"
+    },
+    "status.skipped": {
+        "message": "Not yet supported, skipped"
+    },
+    "status.success": {
+        "message": "OK"
+    },
+    "status.syncing": {
+        "message": "Synchronizing"
+    },
+    "status.451": {
+        "message": "Server issued redirect, retry in 5 seconds."
+    },
+    "supportwizard.footer": {
+        "message": "From the information given here, an e-mail will be generated in the next step, which you can subsequently edit (for example, adding screenshots or similar). Only by actually sending that e-mail, the error report will be sent."
+    },
+    "supportwizard.label.description": {
+        "message": "Detailed error description:"
+    },
+    "supportwizard.label.faultycomponent": {
+        "message": "Component of TbSync where you have observed the error:"
+    },
+    "supportwizard.label.selectcomponent": {
+        "message": "Select component?"
+    },
+    "supportwizard.label.summary": {
+        "message": "Short summary of the error:"
+    },
+    "supportwizard.pagetitle": {
+        "message": "Gathering of all information to effectively process the bug report."
+    },
+    "supportwizard.provider": {
+        "message": "Provider: ##replace.1##"
+    },
+    "supportwizard.title": {
+        "message": "Create bug report"
+    },
+    "syncstate.accountdone": {
+        "message": "Finished account"
+    },
+    "syncstate.done": {
+        "message": "Preparing next item for synchronization"
+    },
+    "syncstate.oauthprompt": {
+        "message": "OAuth 2.0 authentication"
+    },
+    "syncstate.passwordprompt": {
+        "message": "Prompting for credentials"
+    },
+    "syncstate.preparing": {
+        "message": "Preparing next item for synchronization"
+    },
+    "syncstate.syncing": {
+        "message": "Initialize synchronization"
+    },
+    "target.orphaned": {
+        "message": "Disconnected"
+    },
+    "toolbar.label": {
+        "message": "Synchronize all TbSync accounts"
+    },
+    "toolbar.tooltiptext": {
+        "message": "Synchronize latest changes"
+    },
+    "password.ok": {
+        "message": "OK"
+    },
+    "password.cancel": {
+        "message": "Cancel"
+    }
+}
diff -Nru tbsync-4.12/_locales/es/messages.json tbsync-4.16/_locales/es/messages.json
--- tbsync-4.12/_locales/es/messages.json	2024-08-27 18:32:08.000000000 +0200
+++ tbsync-4.16/_locales/es/messages.json	2024-08-27 18:29:06.000000000 +0200
@@ -1,368 +1,368 @@
-{
-    "HelpFixStartupError": {
-        "message": "Puede enviar un registro de depuraci?n al desarrollador de TbSync para ayudar a corregir este error. ?Quiere hacerlo ahora?"
-    },
-    "NoDebugLog": {
-        "message": "No se ha encontrado ning?n mensaje de depuraci?n ?til. Active el modo de depuraci?n, reinicie Thunderbird y repita los pasos que provocaron el comportamiento err?neo."
-    },
-    "OopsMessage": {
-        "message": "?TbSync no se ha podido iniciar!"
-    },
-    "RestartThunderbirdAndTryAgain": {
-        "message": "Se ha habilitado el registro de depuraci?n de TbSync. Reinicie Thunderbird y vuelva a abrir TbSync."
-    },
-    "UnableToTraceError": {
-        "message": "No es posible rastrear este error porque el registro de depuraci?n no est? habilitado. ?Quiere habilitarlo ahora para ayudar a corregir el error?"
-    },
-    "accountacctions.delete": {
-        "message": "Eliminar la cuenta ?##accountname##?"
-    },
-    "accountacctions.disable": {
-        "message": "Desactivar la cuenta ?##accountname##?"
-    },
-    "accountacctions.enable": {
-        "message": "Activar la cuenta ?##accountname##? y conectarse al servidor"
-    },
-    "accountacctions.sync": {
-        "message": "Sincronizar la cuenta ?##accountname##?"
-    },
-    "addressbook.searchall": {
-        "message": "Buscar en todas las libretas de direcciones"
-    },
-    "addressbook.searchgal": {
-        "message": "Buscar en esta libreta de direcciones y en el directorio global (##replace.1##)"
-    },
-    "addressbook.searchthis": {
-        "message": "Buscar en esta libreta de direcciones"
-    },
-    "eventlog.clear": {
-        "message": "Borrar"
-    },
-    "eventlog.close": {
-        "message": "Cerrar"
-    },
-    "eventlog.title": {
-        "message": "Registro de eventos"
-    },
-    "extensionDescription": {
-        "message": "TbSync es una interfaz para administrar cuentas en la nube de forma centralizada y sincronizar los datos de contactos, tareas y calendarios con Thunderbird."
-    },
-    "google.translate.code": {
-        "message": "es-ES"
-    },
-    "helplink.security": {
-        "message": "https://github.com/jobisoft/TbSync/wiki/How-to-use-TbSync-with-self-signed-or-otherwise-untrusted-certificates%3F"
-    },
-    "info.error": {
-        "message": "Error"
-    },
-    "info.idle": {
-        "message": "Inactivo"
-    },
-    "installProvider.header": {
-        "message": "A?n no est? instalado el proveedor ?##replace.1##? para TbSync."
-    },
-    "manager.AccountActions": {
-        "message": "Acciones de cuenta"
-    },
-    "manager.AddAccount": {
-        "message": "A?adir una cuenta"
-    },
-    "manager.DeleteAccount": {
-        "message": "Eliminar la cuenta"
-    },
-    "manager.DisableAccount": {
-        "message": "Desactivar la cuenta"
-    },
-    "manager.EnableAccount": {
-        "message": "Activar la cuenta y conectarse al servidor"
-    },
-    "manager.RetryConnectAccount": {
-        "message": "Volver a intentar conectarse al servidor"
-    },
-    "manager.ShowEventLog": {
-        "message": "Abrir registro de eventos"
-    },
-    "manager.SyncAll": {
-        "message": "Sincronizar todas las cuentas activadas"
-    },
-    "manager.SynchronizeAccount": {
-        "message": "Sincronizar la cuenta"
-    },
-    "manager.accounts": {
-        "message": "Cuentas"
-    },
-    "manager.accountsettings": {
-        "message": "Configuraci?n de cuentas"
-    },
-    "manager.catman.text": {
-        "message": "TbSync tambi?n sincroniza categor?as de contactos, un sustituto eficaz de las listas de contactos, que no son sincronizables. Para usar las categor?as en la libreta de direcciones de Thunderbird, puede instalar el complemento Category Manager. Permite gestionar grupos de contactos con categor?as superpuestas y ofrece diversas funciones relacionadas con las categor?as. Est? disponible en el repositorio oficial de complementos de Mozilla:"
-    },
-    "manager.community": {
-        "message": "Comunidad"
-    },
-    "manager.connecting": {
-        "message": "Conectando al servidor"
-    },
-    "manager.help": {
-        "message": "Ayuda"
-    },
-    "manager.help.createbugreport": {
-        "message": "Crear informe de error"
-    },
-    "manager.help.createbugreportinfo": {
-        "message": "Para que TbSync recopile ?nicamente los datos de depuraci?n relevantes para su informe de error, reinicie Thunderbird y repita exactamente los pasos que reproducen el comportamiento err?neo. Despu?s podr? crear su informe de error aqu?."
-    },
-    "manager.help.debuglevel.0": {
-        "message": "Desactivado"
-    },
-    "manager.help.debuglevel.1": {
-        "message": "Activado: solo registro de errores"
-    },
-    "manager.help.debuglevel.2": {
-        "message": "Activado: registro de todos los datos enviados y recibidos"
-    },
-    "manager.help.debuglevel.3": {
-        "message": "Activado: registro de todos los datos y ciertos valores de depuraci?n internos"
-    },
-    "manager.help.debugmode": {
-        "message": "Modo de depuraci?n:"
-    },
-    "manager.help.fixit": {
-        "message": "Puede ayudar a solucionarlo enviando un informe de error. Para ello, el modo de depuraci?n debe estar activo."
-    },
-    "manager.help.foundabug": {
-        "message": "?Ha encontrado un fallo?"
-    },
-    "manager.help.needhelp": {
-        "message": "?Necesita ayuda?"
-    },
-    "manager.help.viewdebuglog": {
-        "message": "Ver registro"
-    },
-    "manager.help.wiki": {
-        "message": "Visite el wiki del proyecto TbSync, que proporciona m?s informaci?n, gu?as y descripciones detalladas de la configuraci?n."
-    },
-    "manager.installprovider.link": {
-        "message": "Haga clic en el siguiente enlace para abrir la p?gina de informaci?n del proveedor de sincronizaci?n que falta. En ella encontrar? m?s informaci?n sobre el proveedor y tendr? la opci?n de instalarlo:"
-    },
-    "manager.installprovider.warning": {
-        "message": "Este proveedor de sincronizaci?n no est? alojado en el repositorio oficial de complementos de Thunderbird y, por tanto, el personal de Thunderbird no lo ha revisado. El proveedor podr?a perjudicar su sistema. Util?celo bajo su responsabilidad."
-    },
-    "manager.lockedsettings.description": {
-        "message": "Para evitar errores de sincronizaci?n, ciertos ajustes no se pueden modificar mientras la cuenta est? activada."
-    },
-    "manager.missingprovider": {
-        "message": "Esta cuenta requiere el proveedor de sincronizaci?n ##provider##, que no est? instalado actualmente."
-    },
-    "manager.noaccounts": {
-        "message": "A?n no se ha definido ninguna cuenta."
-    },
-    "manager.provider": {
-        "message": "Instalar proveedor"
-    },
-    "manager.provider4tbsync": {
-        "message": "Proveedor de TbSync"
-    },
-    "manager.resource": {
-        "message": "Recurso"
-    },
-    "manager.shorttitle": {
-        "message": "Administrador de cuentas"
-    },
-    "manager.status": {
-        "message": "Estado"
-    },
-    "manager.supporter.contributors": {
-        "message": "Colaboradores y traductores"
-    },
-    "manager.supporter.details": {
-        "message": "Detalles"
-    },
-    "manager.supporter.sponsors": {
-        "message": "Patrocinadores de cuentas de prueba"
-    },
-    "manager.tabs.status": {
-        "message": "Estado de sincronizaci?n"
-    },
-    "manager.tabs.status.autotime": {
-        "message": "Sincronizaci?n peri?dica (en minutos)"
-    },
-    "manager.tabs.status.enableThisAccount": {
-        "message": "Activar y sincronizar esta cuenta"
-    },
-    "manager.tabs.status.general": {
-        "message": "General"
-    },
-    "manager.tabs.status.never": {
-        "message": "Un 0 desactiva la sincronizaci?n peri?dica. La sincronizaci?n push a?n no est? incluida."
-    },
-    "manager.tabs.status.resources": {
-        "message": "Recursos disponibles"
-    },
-    "manager.tabs.status.resources.intro": {
-        "message": "Seleccione cu?les de los recursos detectados quiere sincronizar con Thunderbird."
-    },
-    "manager.tabs.status.sync": {
-        "message": "Sincronizar ahora"
-    },
-    "manager.tabs.status.tryagain": {
-        "message": "Volver a intentar conectar al servidor"
-    },
-    "manager.title": {
-        "message": "Administrador de cuentas TbSync"
-    },
-    "manager.tryagain": {
-        "message": "Volver a intentar conectar al servidor"
-    },
-    "menu.settingslabel": {
-        "message": "Ajustes de sincronizaci?n (TbSync)"
-    },
-    "password.account": {
-        "message": "Cuenta:"
-    },
-    "password.description": {
-        "message": "Actualice las credenciales de la siguiente cuenta de TbSync:"
-    },
-    "password.password": {
-        "message": "Contrase?a:"
-    },
-    "password.title": {
-        "message": "TbSync solicita credenciales"
-    },
-    "password.user": {
-        "message": "Usuario:"
-    },
-    "popup.opensettings": {
-        "message": "Abrir el administrador de cuentas TbSync"
-    },
-    "prompt.DeleteAccount": {
-        "message": "?Realmente quiere eliminar la cuenta ##accountName##?"
-    },
-    "prompt.Disable": {
-        "message": "?Realmente quiere desactivar esta cuenta? ?Se perder?n todas las modificaciones locales que no se hayan sincronizado a?n!"
-    },
-    "prompt.Erase": {
-        "message": "?Realmente quiere quitar de las listas de cuentas esta cuenta de un proveedor desconocido?"
-    },
-    "prompt.Unsubscribe": {
-        "message": "?Realmente quiere cancelar la suscripci?n a este elemento? ?Se perder?n todas las modificaciones locales que no se hayan sincronizado a?n!"
-    },
-    "status.JavaScriptError": {
-        "message": "?Error de JavaScript! Examine el registro de eventos para ver detalles."
-    },
-    "status.OAuthAbortError": {
-        "message": "El usuario interrumpi? el proceso de autenticaci?n OAuth 2.0."
-    },
-    "status.OAuthHttpError": {
-        "message": "Ha fallado el proceso de autenticaci?n OAuth 2.0 (error HTTP ##replace.1##)."
-    },
-    "status.OAuthNetworkError": {
-        "message": "No ha sido posible conectar al servidor de autenticaci?n OAuth 2.0."
-    },
-    "status.OAuthServerError": {
-        "message": " El servidor de autenticaci?n OAuth 2.0 ha respondido: ##replace.1##"
-    },
-    "status.aborted": {
-        "message": "Sin sincronizar"
-    },
-    "status.apiError": {
-        "message": "Error de implementaci?n de API"
-    },
-    "status.disabled": {
-        "message": "La cuenta no est? activada, la sincronizaci?n est? desactivada."
-    },
-    "status.foldererror": {
-        "message": "Uno o varios recursos tuvieron errores de sincronizaci?n. Examine el registro de eventos para ver m?s detalles."
-    },
-    "status.modified": {
-        "message": "Modificaciones locales"
-    },
-    "status.network": {
-        "message": "No ha sido posible conectar al servidor (##replace.1##)."
-    },
-    "status.no-folders-found-on-server": {
-        "message": "No se ha encontrado ning?n recurso en el servidor."
-    },
-    "status.notargets": {
-        "message": "Sincronizaci?n interrumpida porque no se han podido crear los destinos de la sincronizaci?n."
-    },
-    "status.notsyncronized": {
-        "message": "Es necesario sincronizar la cuenta: uno o varios elementos est?n sin sincronizar."
-    },
-    "status.pending": {
-        "message": "Esperando sincronizaci?n"
-    },
-    "status.security": {
-        "message": "No ha sido posible establecer una conexi?n segura. ?Est?s usando un certificado autofirmado, o que no es de confianza, sin importarlo a Thunderbird? (##replace.1##)"
-    },
-    "status.skipped": {
-        "message": "No se admite a?n; omitido"
-    },
-    "status.success": {
-        "message": "OK"
-    },
-    "status.syncing": {
-        "message": "Sincronizando"
-    },
-    "status.451": {
-        "message": "Server issued redirect, retry in 5 seconds."
-    },
-    "supportwizard.footer": {
-        "message": "En el paso siguiente, la informaci?n proporcionada aqu? se incluir? en un mensaje de correo electr?nico que podr? modificar (por ejemplo, para a?adir capturas de pantalla). El informe de error no se enviar? hasta que env?e ese mensaje de correo."
-    },
-    "supportwizard.label.description": {
-        "message": "Descripci?n detallada del error:"
-    },
-    "supportwizard.label.faultycomponent": {
-        "message": "Componente de TbSync en el que ha observado el error:"
-    },
-    "supportwizard.label.selectcomponent": {
-        "message": "Seleccionar componente?"
-    },
-    "supportwizard.label.summary": {
-        "message": "Resumen breve del error:"
-    },
-    "supportwizard.pagetitle": {
-        "message": "Recopilaci?n de todos los datos para procesar eficazmente el informe de error."
-    },
-    "supportwizard.provider": {
-        "message": "Proveedor: ##replace.1##"
-    },
-    "supportwizard.title": {
-        "message": "Crear informe de error"
-    },
-    "syncstate.accountdone": {
-        "message": "Cuenta finalizada"
-    },
-    "syncstate.done": {
-        "message": "Preparando el siguiente elemento para la sincronizaci?n"
-    },
-    "syncstate.oauthprompt": {
-        "message": "Autenticaci?n OAuth 2.0"
-    },
-    "syncstate.passwordprompt": {
-        "message": "Solicitando credenciales"
-    },
-    "syncstate.preparing": {
-        "message": "Preparando el siguiente elemento para la sincronizaci?n"
-    },
-    "syncstate.syncing": {
-        "message": "Iniciar sincronizaci?n"
-    },
-    "target.orphaned": {
-        "message": "Desconectado"
-    },
-    "toolbar.label": {
-        "message": "Sincronizar todas las cuentas de TbSync"
-    },
-    "toolbar.tooltiptext": {
-        "message": "Sincronizar los ?ltimos cambios"
-    },
-    "password.ok": {
-        "message": "Aceptar"
-    },
-    "password.cancel": {
-        "message": "Cancelar"
-    }
-}
+{
+    "HelpFixStartupError": {
+        "message": "Puede enviar un registro de depuraci?n al desarrollador de TbSync para ayudar a corregir este error. ?Quiere hacerlo ahora?"
+    },
+    "NoDebugLog": {
+        "message": "No se ha encontrado ning?n mensaje de depuraci?n ?til. Active el modo de depuraci?n, reinicie Thunderbird y repita los pasos que provocaron el comportamiento err?neo."
+    },
+    "OopsMessage": {
+        "message": "?TbSync no se ha podido iniciar!"
+    },
+    "RestartThunderbirdAndTryAgain": {
+        "message": "Se ha habilitado el registro de depuraci?n de TbSync. Reinicie Thunderbird y vuelva a abrir TbSync."
+    },
+    "UnableToTraceError": {
+        "message": "No es posible rastrear este error porque el registro de depuraci?n no est? habilitado. ?Quiere habilitarlo ahora para ayudar a corregir el error?"
+    },
+    "accountacctions.delete": {
+        "message": "Eliminar la cuenta ?##accountname##?"
+    },
+    "accountacctions.disable": {
+        "message": "Desactivar la cuenta ?##accountname##?"
+    },
+    "accountacctions.enable": {
+        "message": "Activar la cuenta ?##accountname##? y conectarse al servidor"
+    },
+    "accountacctions.sync": {
+        "message": "Sincronizar la cuenta ?##accountname##?"
+    },
+    "addressbook.searchall": {
+        "message": "Buscar en todas las libretas de direcciones"
+    },
+    "addressbook.searchgal": {
+        "message": "Buscar en esta libreta de direcciones y en el directorio global (##replace.1##)"
+    },
+    "addressbook.searchthis": {
+        "message": "Buscar en esta libreta de direcciones"
+    },
+    "eventlog.clear": {
+        "message": "Borrar"
+    },
+    "eventlog.close": {
+        "message": "Cerrar"
+    },
+    "eventlog.title": {
+        "message": "Registro de eventos"
+    },
+    "extensionDescription": {
+        "message": "TbSync es una interfaz para administrar cuentas en la nube de forma centralizada y sincronizar los datos de contactos, tareas y calendarios con Thunderbird."
+    },
+    "google.translate.code": {
+        "message": "es-ES"
+    },
+    "helplink.security": {
+        "message": "https://github.com/jobisoft/TbSync/wiki/How-to-use-TbSync-with-self-signed-or-otherwise-untrusted-certificates%3F"
+    },
+    "info.error": {
+        "message": "Error"
+    },
+    "info.idle": {
+        "message": "Inactivo"
+    },
+    "installProvider.header": {
+        "message": "A?n no est? instalado el proveedor ?##replace.1##? para TbSync."
+    },
+    "manager.AccountActions": {
+        "message": "Acciones de cuenta"
+    },
+    "manager.AddAccount": {
+        "message": "A?adir una cuenta"
+    },
+    "manager.DeleteAccount": {
+        "message": "Eliminar la cuenta"
+    },
+    "manager.DisableAccount": {
+        "message": "Desactivar la cuenta"
+    },
+    "manager.EnableAccount": {
+        "message": "Activar la cuenta y conectarse al servidor"
+    },
+    "manager.RetryConnectAccount": {
+        "message": "Volver a intentar conectarse al servidor"
+    },
+    "manager.ShowEventLog": {
+        "message": "Abrir registro de eventos"
+    },
+    "manager.SyncAll": {
+        "message": "Sincronizar todas las cuentas activadas"
+    },
+    "manager.SynchronizeAccount": {
+        "message": "Sincronizar la cuenta"
+    },
+    "manager.accounts": {
+        "message": "Cuentas"
+    },
+    "manager.accountsettings": {
+        "message": "Configuraci?n de cuentas"
+    },
+    "manager.catman.text": {
+        "message": "TbSync tambi?n sincroniza categor?as de contactos, un sustituto eficaz de las listas de contactos, que no son sincronizables. Para usar las categor?as en la libreta de direcciones de Thunderbird, puede instalar el complemento Category Manager. Permite gestionar grupos de contactos con categor?as superpuestas y ofrece diversas funciones relacionadas con las categor?as. Est? disponible en el repositorio oficial de complementos de Mozilla:"
+    },
+    "manager.community": {
+        "message": "Comunidad"
+    },
+    "manager.connecting": {
+        "message": "Conectando al servidor"
+    },
+    "manager.help": {
+        "message": "Ayuda"
+    },
+    "manager.help.createbugreport": {
+        "message": "Crear informe de error"
+    },
+    "manager.help.createbugreportinfo": {
+        "message": "Para que TbSync recopile ?nicamente los datos de depuraci?n relevantes para su informe de error, reinicie Thunderbird y repita exactamente los pasos que reproducen el comportamiento err?neo. Despu?s podr? crear su informe de error aqu?."
+    },
+    "manager.help.debuglevel.0": {
+        "message": "Desactivado"
+    },
+    "manager.help.debuglevel.1": {
+        "message": "Activado: solo registro de errores"
+    },
+    "manager.help.debuglevel.2": {
+        "message": "Activado: registro de todos los datos enviados y recibidos"
+    },
+    "manager.help.debuglevel.3": {
+        "message": "Activado: registro de todos los datos y ciertos valores de depuraci?n internos"
+    },
+    "manager.help.debugmode": {
+        "message": "Modo de depuraci?n:"
+    },
+    "manager.help.fixit": {
+        "message": "Puede ayudar a solucionarlo enviando un informe de error. Para ello, el modo de depuraci?n debe estar activo."
+    },
+    "manager.help.foundabug": {
+        "message": "?Ha encontrado un fallo?"
+    },
+    "manager.help.needhelp": {
+        "message": "?Necesita ayuda?"
+    },
+    "manager.help.viewdebuglog": {
+        "message": "Ver registro"
+    },
+    "manager.help.wiki": {
+        "message": "Visite el wiki del proyecto TbSync, que proporciona m?s informaci?n, gu?as y descripciones detalladas de la configuraci?n."
+    },
+    "manager.installprovider.link": {
+        "message": "Haga clic en el siguiente enlace para abrir la p?gina de informaci?n del proveedor de sincronizaci?n que falta. En ella encontrar? m?s informaci?n sobre el proveedor y tendr? la opci?n de instalarlo:"
+    },
+    "manager.installprovider.warning": {
+        "message": "Este proveedor de sincronizaci?n no est? alojado en el repositorio oficial de complementos de Thunderbird y, por tanto, el personal de Thunderbird no lo ha revisado. El proveedor podr?a perjudicar su sistema. Util?celo bajo su responsabilidad."
+    },
+    "manager.lockedsettings.description": {
+        "message": "Para evitar errores de sincronizaci?n, ciertos ajustes no se pueden modificar mientras la cuenta est? activada."
+    },
+    "manager.missingprovider": {
+        "message": "Esta cuenta requiere el proveedor de sincronizaci?n ##provider##, que no est? instalado actualmente."
+    },
+    "manager.noaccounts": {
+        "message": "A?n no se ha definido ninguna cuenta."
+    },
+    "manager.provider": {
+        "message": "Instalar proveedor"
+    },
+    "manager.provider4tbsync": {
+        "message": "Proveedor de TbSync"
+    },
+    "manager.resource": {
+        "message": "Recurso"
+    },
+    "manager.shorttitle": {
+        "message": "Administrador de cuentas"
+    },
+    "manager.status": {
+        "message": "Estado"
+    },
+    "manager.supporter.contributors": {
+        "message": "Colaboradores y traductores"
+    },
+    "manager.supporter.details": {
+        "message": "Detalles"
+    },
+    "manager.supporter.sponsors": {
+        "message": "Patrocinadores de cuentas de prueba"
+    },
+    "manager.tabs.status": {
+        "message": "Estado de sincronizaci?n"
+    },
+    "manager.tabs.status.autotime": {
+        "message": "Sincronizaci?n peri?dica (en minutos)"
+    },
+    "manager.tabs.status.enableThisAccount": {
+        "message": "Activar y sincronizar esta cuenta"
+    },
+    "manager.tabs.status.general": {
+        "message": "General"
+    },
+    "manager.tabs.status.never": {
+        "message": "Un 0 desactiva la sincronizaci?n peri?dica. La sincronizaci?n push a?n no est? incluida."
+    },
+    "manager.tabs.status.resources": {
+        "message": "Recursos disponibles"
+    },
+    "manager.tabs.status.resources.intro": {
+        "message": "Seleccione cu?les de los recursos detectados quiere sincronizar con Thunderbird."
+    },
+    "manager.tabs.status.sync": {
+        "message": "Sincronizar ahora"
+    },
+    "manager.tabs.status.tryagain": {
+        "message": "Volver a intentar conectar al servidor"
+    },
+    "manager.title": {
+        "message": "Administrador de cuentas TbSync"
+    },
+    "manager.tryagain": {
+        "message": "Volver a intentar conectar al servidor"
+    },
+    "menu.settingslabel": {
+        "message": "Ajustes de sincronizaci?n (TbSync)"
+    },
+    "password.account": {
+        "message": "Cuenta:"
+    },
+    "password.description": {
+        "message": "Actualice las credenciales de la siguiente cuenta de TbSync:"
+    },
+    "password.password": {
+        "message": "Contrase?a:"
+    },
+    "password.title": {
+        "message": "TbSync solicita credenciales"
+    },
+    "password.user": {
+        "message": "Usuario:"
+    },
+    "popup.opensettings": {
+        "message": "Abrir el administrador de cuentas TbSync"
+    },
+    "prompt.DeleteAccount": {
+        "message": "?Realmente quiere eliminar la cuenta ##accountName##?"
+    },
+    "prompt.Disable": {
+        "message": "?Realmente quiere desactivar esta cuenta? ?Se perder?n todas las modificaciones locales que no se hayan sincronizado a?n!"
+    },
+    "prompt.Erase": {
+        "message": "?Realmente quiere quitar de las listas de cuentas esta cuenta de un proveedor desconocido?"
+    },
+    "prompt.Unsubscribe": {
+        "message": "?Realmente quiere cancelar la suscripci?n a este elemento? ?Se perder?n todas las modificaciones locales que no se hayan sincronizado a?n!"
+    },
+    "status.JavaScriptError": {
+        "message": "?Error de JavaScript! Examine el registro de eventos para ver detalles."
+    },
+    "status.OAuthAbortError": {
+        "message": "El usuario interrumpi? el proceso de autenticaci?n OAuth 2.0."
+    },
+    "status.OAuthHttpError": {
+        "message": "Ha fallado el proceso de autenticaci?n OAuth 2.0 (error HTTP ##replace.1##)."
+    },
+    "status.OAuthNetworkError": {
+        "message": "No ha sido posible conectar al servidor de autenticaci?n OAuth 2.0."
+    },
+    "status.OAuthServerError": {
+        "message": " El servidor de autenticaci?n OAuth 2.0 ha respondido: ##replace.1##"
+    },
+    "status.aborted": {
+        "message": "Sin sincronizar"
+    },
+    "status.apiError": {
+        "message": "Error de implementaci?n de API"
+    },
+    "status.disabled": {
+        "message": "La cuenta no est? activada, la sincronizaci?n est? desactivada."
+    },
+    "status.foldererror": {
+        "message": "Uno o varios recursos tuvieron errores de sincronizaci?n. Examine el registro de eventos para ver m?s detalles."
+    },
+    "status.modified": {
+        "message": "Modificaciones locales"
+    },
+    "status.network": {
+        "message": "No ha sido posible conectar al servidor (##replace.1##)."
+    },
+    "status.no-folders-found-on-server": {
+        "message": "No se ha encontrado ning?n recurso en el servidor."
+    },
+    "status.notargets": {
+        "message": "Sincronizaci?n interrumpida porque no se han podido crear los destinos de la sincronizaci?n."
+    },
+    "status.notsyncronized": {
+        "message": "Es necesario sincronizar la cuenta: uno o varios elementos est?n sin sincronizar."
+    },
+    "status.pending": {
+        "message": "Esperando sincronizaci?n"
+    },
+    "status.security": {
+        "message": "No ha sido posible establecer una conexi?n segura. ?Est?s usando un certificado autofirmado, o que no es de confianza, sin importarlo a Thunderbird? (##replace.1##)"
+    },
+    "status.skipped": {
+        "message": "No se admite a?n; omitido"
+    },
+    "status.success": {
+        "message": "OK"
+    },
+    "status.syncing": {
+        "message": "Sincronizando"
+    },
+    "status.451": {
+        "message": "Server issued redirect, retry in 5 seconds."
+    },
+    "supportwizard.footer": {
+        "message": "En el paso siguiente, la informaci?n proporcionada aqu? se incluir? en un mensaje de correo electr?nico que podr? modificar (por ejemplo, para a?adir capturas de pantalla). El informe de error no se enviar? hasta que env?e ese mensaje de correo."
+    },
+    "supportwizard.label.description": {
+        "message": "Descripci?n detallada del error:"
+    },
+    "supportwizard.label.faultycomponent": {
+        "message": "Componente de TbSync en el que ha observado el error:"
+    },
+    "supportwizard.label.selectcomponent": {
+        "message": "Seleccionar componente?"
+    },
+    "supportwizard.label.summary": {
+        "message": "Resumen breve del error:"
+    },
+    "supportwizard.pagetitle": {
+        "message": "Recopilaci?n de todos los datos para procesar eficazmente el informe de error."
+    },
+    "supportwizard.provider": {
+        "message": "Proveedor: ##replace.1##"
+    },
+    "supportwizard.title": {
+        "message": "Crear informe de error"
+    },
+    "syncstate.accountdone": {
+        "message": "Cuenta finalizada"
+    },
+    "syncstate.done": {
+        "message": "Preparando el siguiente elemento para la sincronizaci?n"
+    },
+    "syncstate.oauthprompt": {
+        "message": "Autenticaci?n OAuth 2.0"
+    },
+    "syncstate.passwordprompt": {
+        "message": "Solicitando credenciales"
+    },
+    "syncstate.preparing": {
+        "message": "Preparando el siguiente elemento para la sincronizaci?n"
+    },
+    "syncstate.syncing": {
+        "message": "Iniciar sincronizaci?n"
+    },
+    "target.orphaned": {
+        "message": "Desconectado"
+    },
+    "toolbar.label": {
+        "message": "Sincronizar todas las cuentas de TbSync"
+    },
+    "toolbar.tooltiptext": {
+        "message": "Sincronizar los ?ltimos cambios"
+    },
+    "password.ok": {
+        "message": "Aceptar"
+    },
+    "password.cancel": {
+        "message": "Cancelar"
+    }
+}
diff -Nru tbsync-4.12/_locales/et/messages.json tbsync-4.16/_locales/et/messages.json
--- tbsync-4.12/_locales/et/messages.json	2024-08-27 18:32:08.000000000 +0200
+++ tbsync-4.16/_locales/et/messages.json	2024-08-27 18:29:06.000000000 +0200
@@ -1,368 +1,368 @@
-{
-    "HelpFixStartupError": {
-        "message": "To help fix this error, you could send a debug log to the TbSync developer. Prepare that email now?"
-    },
-    "NoDebugLog": {
-        "message": "Could not find any useful debug messages. Please activate debug mode, restart Thunderbird and repeat all the steps needed to trigger the erroneous behavior."
-    },
-    "OopsMessage": {
-        "message": "Oops! TbSync was not able to start!"
-    },
-    "RestartThunderbirdAndTryAgain": {
-        "message": "TbSync debug log has been enabled, please restart Thunderbird and again try to open TbSync."
-    },
-    "UnableToTraceError": {
-        "message": "It is not possible to trace this error, because debug log is currently not enabled. Do you want to enable debug log now, to help fix this error?"
-    },
-    "accountacctions.delete": {
-        "message": "Delete account ?##accountname##?"
-    },
-    "accountacctions.disable": {
-        "message": "Disable account ?##accountname##?"
-    },
-    "accountacctions.enable": {
-        "message": "Enable account ?##accountname##? & try to connect to server"
-    },
-    "accountacctions.sync": {
-        "message": "Synchronize account ?##accountname##?"
-    },
-    "addressbook.searchall": {
-        "message": "Search all address books"
-    },
-    "addressbook.searchgal": {
-        "message": "Search this address book and the global directory (##replace.1##)"
-    },
-    "addressbook.searchthis": {
-        "message": "Search this address book"
-    },
-    "eventlog.clear": {
-        "message": "Clear"
-    },
-    "eventlog.close": {
-        "message": "Close"
-    },
-    "eventlog.title": {
-        "message": "Event log"
-    },
-    "extensionDescription": {
-        "message": "TbSync is a central user interface to manage cloud accounts and to synchronize their contact, task and calendar information with Thunderbird."
-    },
-    "google.translate.code": {
-        "message": "en"
-    },
-    "helplink.security": {
-        "message": "https://github.com/jobisoft/TbSync/wiki/How-to-use-TbSync-with-self-signed-or-otherwise-untrusted-certificates%3F"
-    },
-    "info.error": {
-        "message": "Error"
-    },
-    "info.idle": {
-        "message": "Idle"
-    },
-    "installProvider.header": {
-        "message": "Provider ?##replace.1##? for TbSync is not yet installed."
-    },
-    "manager.AccountActions": {
-        "message": "Account actions"
-    },
-    "manager.AddAccount": {
-        "message": "Add new account"
-    },
-    "manager.DeleteAccount": {
-        "message": "Delete account"
-    },
-    "manager.DisableAccount": {
-        "message": "Disable account"
-    },
-    "manager.EnableAccount": {
-        "message": "Enable account & try to connect to server"
-    },
-    "manager.RetryConnectAccount": {
-        "message": "Try again to connect to server"
-    },
-    "manager.ShowEventLog": {
-        "message": "Open event log"
-    },
-    "manager.SyncAll": {
-        "message": "Synchronize all enabled accounts"
-    },
-    "manager.SynchronizeAccount": {
-        "message": "Synchronize account"
-    },
-    "manager.accounts": {
-        "message": "Accounts"
-    },
-    "manager.accountsettings": {
-        "message": "Account Settings"
-    },
-    "manager.catman.text": {
-        "message": "TbSync also syncs contact categories, which are a powerful replacement for the non-synchronizable contact lists. To be able to use them in the Thunderbird address book you can install the Category Manager add-on. It allows to manage overlapping category based contact groups and provides a bunch of other category-related features. It can be found in the official Mozilla add-on repository:"
-    },
-    "manager.community": {
-        "message": "Community"
-    },
-    "manager.connecting": {
-        "message": "Connecting to server"
-    },
-    "manager.help": {
-        "message": "Help"
-    },
-    "manager.help.createbugreport": {
-        "message": "Create bug report"
-    },
-    "manager.help.createbugreportinfo": {
-        "message": "In order for TbSync to collect only the debug data relevant to your bug report, please restart Thunderbird and then repeat exactly the steps that reproduce the buggy behavior. Then you can create your bug report here."
-    },
-    "manager.help.debuglevel.0": {
-        "message": "Disabled"
-    },
-    "manager.help.debuglevel.1": {
-        "message": "Enabled: Logging of errors only"
-    },
-    "manager.help.debuglevel.2": {
-        "message": "Enabled: Logging of all sent and received data"
-    },
-    "manager.help.debuglevel.3": {
-        "message": "Enabled: Logging of all data and some internal debug values"
-    },
-    "manager.help.debugmode": {
-        "message": "Debug mode:"
-    },
-    "manager.help.fixit": {
-        "message": "You can help to fix it by sending in a bug report. This requires the activation of debug mode."
-    },
-    "manager.help.foundabug": {
-        "message": "Found a bug?"
-    },
-    "manager.help.needhelp": {
-        "message": "Need Help?"
-    },
-    "manager.help.viewdebuglog": {
-        "message": "View debug log"
-    },
-    "manager.help.wiki": {
-        "message": "Open the wiki pages of the TbSync project, they provide additional information, guides and detailed configuration descriptions."
-    },
-    "manager.installprovider.link": {
-        "message": "Click on the following link to open the info page of the missing synchronization provider. There you will find further information about the provider and you will have the option to install it:"
-    },
-    "manager.installprovider.warning": {
-        "message": "This synchronization provider is not hosted in the official Thunderbird add-on repository and thus has not been reviewed by Thunderbird staff. The provider could do bad things to your system. Use it at your own risk."
-    },
-    "manager.lockedsettings.description": {
-        "message": "To prevent synchronization errors, some settings cannot be edited while the account is enabled."
-    },
-    "manager.missingprovider": {
-        "message": "This account requires the ##provider## synchronization provider, which is currently not installed."
-    },
-    "manager.noaccounts": {
-        "message": "There are not yet any accounts defined."
-    },
-    "manager.provider": {
-        "message": "Install Provider"
-    },
-    "manager.provider4tbsync": {
-        "message": "Provider for TbSync"
-    },
-    "manager.resource": {
-        "message": "Resource"
-    },
-    "manager.shorttitle": {
-        "message": "Account manager"
-    },
-    "manager.status": {
-        "message": "Status"
-    },
-    "manager.supporter.contributors": {
-        "message": "Contributors & Translators"
-    },
-    "manager.supporter.details": {
-        "message": "Details"
-    },
-    "manager.supporter.sponsors": {
-        "message": "Sponsors of test accounts"
-    },
-    "manager.tabs.status": {
-        "message": "Synchronization status"
-    },
-    "manager.tabs.status.autotime": {
-        "message": "Periodic synchronization (in minutes)"
-    },
-    "manager.tabs.status.enableThisAccount": {
-        "message": "Enable and synchronize this account"
-    },
-    "manager.tabs.status.general": {
-        "message": "General"
-    },
-    "manager.tabs.status.never": {
-        "message": "A setting of 0 disables periodic sync. Push sync is not yet implemented."
-    },
-    "manager.tabs.status.resources": {
-        "message": "Available resources"
-    },
-    "manager.tabs.status.resources.intro": {
-        "message": "Select which of the found resources should be synchronized with Thunderbird."
-    },
-    "manager.tabs.status.sync": {
-        "message": "Synchronize now"
-    },
-    "manager.tabs.status.tryagain": {
-        "message": "Try again to connect server"
-    },
-    "manager.title": {
-        "message": "TbSync account manager"
-    },
-    "manager.tryagain": {
-        "message": "Try again to connect server"
-    },
-    "menu.settingslabel": {
-        "message": "Synchronization Settings (TbSync)"
-    },
-    "password.account": {
-        "message": "Account:"
-    },
-    "password.description": {
-        "message": "Please update the credentials for the following TbSync account:"
-    },
-    "password.password": {
-        "message": "Password:"
-    },
-    "password.title": {
-        "message": "TbSync Credential Request"
-    },
-    "password.user": {
-        "message": "User:"
-    },
-    "popup.opensettings": {
-        "message": "Open TbSync account manager"
-    },
-    "prompt.DeleteAccount": {
-        "message": "Are you sure you want to delete account ##accountName##?"
-    },
-    "prompt.Disable": {
-        "message": "Are you sure you want to disable this account? All local modifications, which have not been synced yet, will be lost!"
-    },
-    "prompt.Erase": {
-        "message": "Are you sure you want to remove this account of an unknown provider from the accounts lists?"
-    },
-    "prompt.Unsubscribe": {
-        "message": "Are you sure you want to unsubscribe this item? All local modifications, which have not been synced yet, will be lost!"
-    },
-    "status.JavaScriptError": {
-        "message": "Javascript Error! Please check the event log for more details."
-    },
-    "status.OAuthAbortError": {
-        "message": "OAuth 2.0 authentication process aborted by user."
-    },
-    "status.OAuthHttpError": {
-        "message": "OAuth 2.0 authentication process failed (HTTP error ##replace.1##)."
-    },
-    "status.OAuthNetworkError": {
-        "message": "Could not connect to OAuth 2.0 authentication server."
-    },
-    "status.OAuthServerError": {
-        "message": " OAuth 2.0 authentication server returned: ##replace.1##"
-    },
-    "status.aborted": {
-        "message": "Not synchronized"
-    },
-    "status.apiError": {
-        "message": "API implementation error"
-    },
-    "status.disabled": {
-        "message": "Account is not enabled, synchronization is disabled."
-    },
-    "status.foldererror": {
-        "message": "At least one resource encountered a synchronization error. Please check the event log for more details."
-    },
-    "status.modified": {
-        "message": "Local modifications"
-    },
-    "status.network": {
-        "message": "Could not connect to server (##replace.1##)."
-    },
-    "status.no-folders-found-on-server": {
-        "message": "Could not find any resources on the server."
-    },
-    "status.notargets": {
-        "message": "Aborting synchronization, because sync targets could not be created."
-    },
-    "status.notsyncronized": {
-        "message": "Account needs to be synchronized, at least one item is out of sync."
-    },
-    "status.pending": {
-        "message": "Waiting to be synchronized"
-    },
-    "status.security": {
-        "message": "Could not establish a secure connection. Are you using a self-signed or otherwise untrusted certificate without importing it into Thunderbird? (##replace.1##)"
-    },
-    "status.skipped": {
-        "message": "Not yet supported, skipped"
-    },
-    "status.success": {
-        "message": "OK"
-    },
-    "status.syncing": {
-        "message": "Synchronizing"
-    },
-    "status.451": {
-        "message": "Server issued redirect, retry in 5 seconds."
-    },
-    "supportwizard.footer": {
-        "message": "From the information given here, an e-mail will be generated in the next step, which you can subsequently edit (for example, adding screenshots or similar). Only by actually sending that e-mail, the error report will be sent."
-    },
-    "supportwizard.label.description": {
-        "message": "Detailed error description:"
-    },
-    "supportwizard.label.faultycomponent": {
-        "message": "Component of TbSync where you have observed the error:"
-    },
-    "supportwizard.label.selectcomponent": {
-        "message": "Select component?"
-    },
-    "supportwizard.label.summary": {
-        "message": "Short summary of the error:"
-    },
-    "supportwizard.pagetitle": {
-        "message": "Gathering of all information to effectively process the bug report."
-    },
-    "supportwizard.provider": {
-        "message": "Provider: ##replace.1##"
-    },
-    "supportwizard.title": {
-        "message": "Create bug report"
-    },
-    "syncstate.accountdone": {
-        "message": "Finished account"
-    },
-    "syncstate.done": {
-        "message": "Preparing next item for synchronization"
-    },
-    "syncstate.oauthprompt": {
-        "message": "OAuth 2.0 authentication"
-    },
-    "syncstate.passwordprompt": {
-        "message": "Prompting for credentials"
-    },
-    "syncstate.preparing": {
-        "message": "Preparing next item for synchronization"
-    },
-    "syncstate.syncing": {
-        "message": "Initialize synchronization"
-    },
-    "target.orphaned": {
-        "message": "Disconnected"
-    },
-    "toolbar.label": {
-        "message": "Synchronize all TbSync accounts"
-    },
-    "toolbar.tooltiptext": {
-        "message": "Synchronize latest changes"
-    },
-    "password.ok": {
-        "message": "OK"
-    },
-    "password.cancel": {
-        "message": "T?hista"
-    }
-}
+{
+    "HelpFixStartupError": {
+        "message": "To help fix this error, you could send a debug log to the TbSync developer. Prepare that email now?"
+    },
+    "NoDebugLog": {
+        "message": "Could not find any useful debug messages. Please activate debug mode, restart Thunderbird and repeat all the steps needed to trigger the erroneous behavior."
+    },
+    "OopsMessage": {
+        "message": "Oops! TbSync was not able to start!"
+    },
+    "RestartThunderbirdAndTryAgain": {
+        "message": "TbSync debug log has been enabled, please restart Thunderbird and again try to open TbSync."
+    },
+    "UnableToTraceError": {
+        "message": "It is not possible to trace this error, because debug log is currently not enabled. Do you want to enable debug log now, to help fix this error?"
+    },
+    "accountacctions.delete": {
+        "message": "Delete account ?##accountname##?"
+    },
+    "accountacctions.disable": {
+        "message": "Disable account ?##accountname##?"
+    },
+    "accountacctions.enable": {
+        "message": "Enable account ?##accountname##? & try to connect to server"
+    },
+    "accountacctions.sync": {
+        "message": "Synchronize account ?##accountname##?"
+    },
+    "addressbook.searchall": {
+        "message": "Search all address books"
+    },
+    "addressbook.searchgal": {
+        "message": "Search this address book and the global directory (##replace.1##)"
+    },
+    "addressbook.searchthis": {
+        "message": "Search this address book"
+    },
+    "eventlog.clear": {
+        "message": "Clear"
+    },
+    "eventlog.close": {
+        "message": "Close"
+    },
+    "eventlog.title": {
+        "message": "Event log"
+    },
+    "extensionDescription": {
+        "message": "TbSync is a central user interface to manage cloud accounts and to synchronize their contact, task and calendar information with Thunderbird."
+    },
+    "google.translate.code": {
+        "message": "en"
+    },
+    "helplink.security": {
+        "message": "https://github.com/jobisoft/TbSync/wiki/How-to-use-TbSync-with-self-signed-or-otherwise-untrusted-certificates%3F"
+    },
+    "info.error": {
+        "message": "Error"
+    },
+    "info.idle": {
+        "message": "Idle"
+    },
+    "installProvider.header": {
+        "message": "Provider ?##replace.1##? for TbSync is not yet installed."
+    },
+    "manager.AccountActions": {
+        "message": "Account actions"
+    },
+    "manager.AddAccount": {
+        "message": "Add new account"
+    },
+    "manager.DeleteAccount": {
+        "message": "Delete account"
+    },
+    "manager.DisableAccount": {
+        "message": "Disable account"
+    },
+    "manager.EnableAccount": {
+        "message": "Enable account & try to connect to server"
+    },
+    "manager.RetryConnectAccount": {
+        "message": "Try again to connect to server"
+    },
+    "manager.ShowEventLog": {
+        "message": "Open event log"
+    },
+    "manager.SyncAll": {
+        "message": "Synchronize all enabled accounts"
+    },
+    "manager.SynchronizeAccount": {
+        "message": "Synchronize account"
+    },
+    "manager.accounts": {
+        "message": "Accounts"
+    },
+    "manager.accountsettings": {
+        "message": "Account Settings"
+    },
+    "manager.catman.text": {
+        "message": "TbSync also syncs contact categories, which are a powerful replacement for the non-synchronizable contact lists. To be able to use them in the Thunderbird address book you can install the Category Manager add-on. It allows to manage overlapping category based contact groups and provides a bunch of other category-related features. It can be found in the official Mozilla add-on repository:"
+    },
+    "manager.community": {
+        "message": "Community"
+    },
+    "manager.connecting": {
+        "message": "Connecting to server"
+    },
+    "manager.help": {
+        "message": "Help"
+    },
+    "manager.help.createbugreport": {
+        "message": "Create bug report"
+    },
+    "manager.help.createbugreportinfo": {
+        "message": "In order for TbSync to collect only the debug data relevant to your bug report, please restart Thunderbird and then repeat exactly the steps that reproduce the buggy behavior. Then you can create your bug report here."
+    },
+    "manager.help.debuglevel.0": {
+        "message": "Disabled"
+    },
+    "manager.help.debuglevel.1": {
+        "message": "Enabled: Logging of errors only"
+    },
+    "manager.help.debuglevel.2": {
+        "message": "Enabled: Logging of all sent and received data"
+    },
+    "manager.help.debuglevel.3": {
+        "message": "Enabled: Logging of all data and some internal debug values"
+    },
+    "manager.help.debugmode": {
+        "message": "Debug mode:"
+    },
+    "manager.help.fixit": {
+        "message": "You can help to fix it by sending in a bug report. This requires the activation of debug mode."
+    },
+    "manager.help.foundabug": {
+        "message": "Found a bug?"
+    },
+    "manager.help.needhelp": {
+        "message": "Need Help?"
+    },
+    "manager.help.viewdebuglog": {
+        "message": "View debug log"
+    },
+    "manager.help.wiki": {
+        "message": "Open the wiki pages of the TbSync project, they provide additional information, guides and detailed configuration descriptions."
+    },
+    "manager.installprovider.link": {
+        "message": "Click on the following link to open the info page of the missing synchronization provider. There you will find further information about the provider and you will have the option to install it:"
+    },
+    "manager.installprovider.warning": {
+        "message": "This synchronization provider is not hosted in the official Thunderbird add-on repository and thus has not been reviewed by Thunderbird staff. The provider could do bad things to your system. Use it at your own risk."
+    },
+    "manager.lockedsettings.description": {
+        "message": "To prevent synchronization errors, some settings cannot be edited while the account is enabled."
+    },
+    "manager.missingprovider": {
+        "message": "This account requires the ##provider## synchronization provider, which is currently not installed."
+    },
+    "manager.noaccounts": {
+        "message": "There are not yet any accounts defined."
+    },
+    "manager.provider": {
+        "message": "Install Provider"
+    },
+    "manager.provider4tbsync": {
+        "message": "Provider for TbSync"
+    },
+    "manager.resource": {
+        "message": "Resource"
+    },
+    "manager.shorttitle": {
+        "message": "Account manager"
+    },
+    "manager.status": {
+        "message": "Status"
+    },
+    "manager.supporter.contributors": {
+        "message": "Contributors & Translators"
+    },
+    "manager.supporter.details": {
+        "message": "Details"
+    },
+    "manager.supporter.sponsors": {
+        "message": "Sponsors of test accounts"
+    },
+    "manager.tabs.status": {
+        "message": "Synchronization status"
+    },
+    "manager.tabs.status.autotime": {
+        "message": "Periodic synchronization (in minutes)"
+    },
+    "manager.tabs.status.enableThisAccount": {
+        "message": "Enable and synchronize this account"
+    },
+    "manager.tabs.status.general": {
+        "message": "General"
+    },
+    "manager.tabs.status.never": {
+        "message": "A setting of 0 disables periodic sync. Push sync is not yet implemented."
+    },
+    "manager.tabs.status.resources": {
+        "message": "Available resources"
+    },
+    "manager.tabs.status.resources.intro": {
+        "message": "Select which of the found resources should be synchronized with Thunderbird."
+    },
+    "manager.tabs.status.sync": {
+        "message": "Synchronize now"
+    },
+    "manager.tabs.status.tryagain": {
+        "message": "Try again to connect server"
+    },
+    "manager.title": {
+        "message": "TbSync account manager"
+    },
+    "manager.tryagain": {
+        "message": "Try again to connect server"
+    },
+    "menu.settingslabel": {
+        "message": "Synchronization Settings (TbSync)"
+    },
+    "password.account": {
+        "message": "Account:"
+    },
+    "password.description": {
+        "message": "Please update the credentials for the following TbSync account:"
+    },
+    "password.password": {
+        "message": "Password:"
+    },
+    "password.title": {
+        "message": "TbSync Credential Request"
+    },
+    "password.user": {
+        "message": "User:"
+    },
+    "popup.opensettings": {
+        "message": "Open TbSync account manager"
+    },
+    "prompt.DeleteAccount": {
+        "message": "Are you sure you want to delete account ##accountName##?"
+    },
+    "prompt.Disable": {
+        "message": "Are you sure you want to disable this account? All local modifications, which have not been synced yet, will be lost!"
+    },
+    "prompt.Erase": {
+        "message": "Are you sure you want to remove this account of an unknown provider from the accounts lists?"
+    },
+    "prompt.Unsubscribe": {
+        "message": "Are you sure you want to unsubscribe this item? All local modifications, which have not been synced yet, will be lost!"
+    },
+    "status.JavaScriptError": {
+        "message": "Javascript Error! Please check the event log for more details."
+    },
+    "status.OAuthAbortError": {
+        "message": "OAuth 2.0 authentication process aborted by user."
+    },
+    "status.OAuthHttpError": {
+        "message": "OAuth 2.0 authentication process failed (HTTP error ##replace.1##)."
+    },
+    "status.OAuthNetworkError": {
+        "message": "Could not connect to OAuth 2.0 authentication server."
+    },
+    "status.OAuthServerError": {
+        "message": " OAuth 2.0 authentication server returned: ##replace.1##"
+    },
+    "status.aborted": {
+        "message": "Not synchronized"
+    },
+    "status.apiError": {
+        "message": "API implementation error"
+    },
+    "status.disabled": {
+        "message": "Account is not enabled, synchronization is disabled."
+    },
+    "status.foldererror": {
+        "message": "At least one resource encountered a synchronization error. Please check the event log for more details."
+    },
+    "status.modified": {
+        "message": "Local modifications"
+    },
+    "status.network": {
+        "message": "Could not connect to server (##replace.1##)."
+    },
+    "status.no-folders-found-on-server": {
+        "message": "Could not find any resources on the server."
+    },
+    "status.notargets": {
+        "message": "Aborting synchronization, because sync targets could not be created."
+    },
+    "status.notsyncronized": {
+        "message": "Account needs to be synchronized, at least one item is out of sync."
+    },
+    "status.pending": {
+        "message": "Waiting to be synchronized"
+    },
+    "status.security": {
+        "message": "Could not establish a secure connection. Are you using a self-signed or otherwise untrusted certificate without importing it into Thunderbird? (##replace.1##)"
+    },
+    "status.skipped": {
+        "message": "Not yet supported, skipped"
+    },
+    "status.success": {
+        "message": "OK"
+    },
+    "status.syncing": {
+        "message": "Synchronizing"
+    },
+    "status.451": {
+        "message": "Server issued redirect, retry in 5 seconds."
+    },
+    "supportwizard.footer": {
+        "message": "From the information given here, an e-mail will be generated in the next step, which you can subsequently edit (for example, adding screenshots or similar). Only by actually sending that e-mail, the error report will be sent."
+    },
+    "supportwizard.label.description": {
+        "message": "Detailed error description:"
+    },
+    "supportwizard.label.faultycomponent": {
+        "message": "Component of TbSync where you have observed the error:"
+    },
+    "supportwizard.label.selectcomponent": {
+        "message": "Select component?"
+    },
+    "supportwizard.label.summary": {
+        "message": "Short summary of the error:"
+    },
+    "supportwizard.pagetitle": {
+        "message": "Gathering of all information to effectively process the bug report."
+    },
+    "supportwizard.provider": {
+        "message": "Provider: ##replace.1##"
+    },
+    "supportwizard.title": {
+        "message": "Create bug report"
+    },
+    "syncstate.accountdone": {
+        "message": "Finished account"
+    },
+    "syncstate.done": {
+        "message": "Preparing next item for synchronization"
+    },
+    "syncstate.oauthprompt": {
+        "message": "OAuth 2.0 authentication"
+    },
+    "syncstate.passwordprompt": {
+        "message": "Prompting for credentials"
+    },
+    "syncstate.preparing": {
+        "message": "Preparing next item for synchronization"
+    },
+    "syncstate.syncing": {
+        "message": "Initialize synchronization"
+    },
+    "target.orphaned": {
+        "message": "Disconnected"
+    },
+    "toolbar.label": {
+        "message": "Synchronize all TbSync accounts"
+    },
+    "toolbar.tooltiptext": {
+        "message": "Synchronize latest changes"
+    },
+    "password.ok": {
+        "message": "OK"
+    },
+    "password.cancel": {
+        "message": "T?hista"
+    }
+}
diff -Nru tbsync-4.12/_locales/fr/messages.json tbsync-4.16/_locales/fr/messages.json
--- tbsync-4.12/_locales/fr/messages.json	2024-08-27 18:32:08.000000000 +0200
+++ tbsync-4.16/_locales/fr/messages.json	2024-08-27 18:29:06.000000000 +0200
@@ -1,368 +1,368 @@
-{
-    "HelpFixStartupError": {
-        "message": "Pour aider ? la r?solution de cette erreur, vous pourriez envoyer le journal de d?bogage au d?veloppeur de TbSync. Voulez-vous qu'on pr?pare un courriel ? cette fin ?"
-    },
-    "NoDebugLog": {
-        "message": "Il n'a pas ?t? possible de trouver un message de d?bogage utile. Merci d'activer le mode de d?bogage, de red?marrer Thunderbird puis de r?p?ter les ?tapes qui ont men?es au comportement anormal du programme."
-    },
-    "OopsMessage": {
-        "message": "Oups! TbSync n'a pas r?ussi ? d?marrer !"
-    },
-    "RestartThunderbirdAndTryAgain": {
-        "message": "Le journal de d?bogage de TbSync a ?t? activ?. Veuillez red?marrer Thunderbird et essayer ? nouveau d'ouvrir TbSync."
-    },
-    "UnableToTraceError": {
-        "message": "Il n'est pas possible de localiser cette erreur, parce que le journal de d?bogage n'est actuellement pas activ?. D?sirez-vous activer le journal de d?bogage maintenant, afin d'aider ? r?soudre cette erreur ?"
-    },
-    "accountacctions.delete": {
-        "message": "Supprimer le compte '##accountname##'"
-    },
-    "accountacctions.disable": {
-        "message": "D?sactiver le compte '##accountname##'"
-    },
-    "accountacctions.enable": {
-        "message": "Activer le compte '##accountname##' et tenter de se connecter au serveur"
-    },
-    "accountacctions.sync": {
-        "message": "Synchroniser le compte '##accountname##'"
-    },
-    "addressbook.searchall": {
-        "message": "Rechercher dans tous les carnets d'adresses"
-    },
-    "addressbook.searchgal": {
-        "message": "Recherche dans ce carnet d'adresse et dans l'annuaire global (##replace.1##)"
-    },
-    "addressbook.searchthis": {
-        "message": "Rechercher dans ce carnet d'adresse"
-    },
-    "eventlog.clear": {
-        "message": "Effacer"
-    },
-    "eventlog.close": {
-        "message": "Fermer"
-    },
-    "eventlog.title": {
-        "message": "Journal d'?v?nements"
-    },
-    "extensionDescription": {
-        "message": "TbSync est une interface permettant de g?rer de mani?re centralis?e ses comptes cloud et d'en synchroniser les contacts, t?ches et agendas avec Thunderbird."
-    },
-    "google.translate.code": {
-        "message": "fr"
-    },
-    "helplink.security": {
-        "message": "https://github.com/jobisoft/TbSync/wiki/How-to-use-TbSync-with-self-signed-or-otherwise-non-rusted-certificats%3F"
-    },
-    "info.error": {
-        "message": "Erreur"
-    },
-    "info.idle": {
-        "message": "Inactif"
-    },
-    "installProvider.header": {
-        "message": "Le provider TbSync '##replace.1##' n'est pas encore install?."
-    },
-    "manager.AccountActions": {
-        "message": "Actions sur les comptes"
-    },
-    "manager.AddAccount": {
-        "message": "Ajouter un nouveau compte"
-    },
-    "manager.DeleteAccount": {
-        "message": "Supprimer le compte"
-    },
-    "manager.DisableAccount": {
-        "message": "D?sactiver le compte"
-    },
-    "manager.EnableAccount": {
-        "message": "Activer le compte et tester la connexion au serveur"
-    },
-    "manager.RetryConnectAccount": {
-        "message": "Essayer ? nouveau de se connecter au serveur"
-    },
-    "manager.ShowEventLog": {
-        "message": "Montrer le journal d'?v?nements (log)"
-    },
-    "manager.SyncAll": {
-        "message": "Synchroniser tous les comptes activ?s"
-    },
-    "manager.SynchronizeAccount": {
-        "message": "Synchroniser le compte"
-    },
-    "manager.accounts": {
-        "message": "Comptes"
-    },
-    "manager.accountsettings": {
-        "message": "Param?tres du compte"
-    },
-    "manager.catman.text": {
-        "message": "TbSync synchronise ?galement les cat?gories de contacts, ce qui remplace avantageusement les listes de contacts, qui ne peuvent ?tre synchronis?es. Afin de pouvoir les utiliser dans le carnet d'adresses de Thunderbird, vous pouvez installer le module compl?mentaire Category Manager. Celui-ci vous permet de g?rer les contacts sur base de cat?gories (un contact pouvant en avoir plusieurs) et qui fournit d'autres fonctionnalit?s li?es aux cat?gories. Ce module peut ?tre trouv? sur le d?p?t officiel de Mozilla:"
-    },
-    "manager.community": {
-        "message": "Communaut?"
-    },
-    "manager.connecting": {
-        "message": "Connexion au serveur en cours"
-    },
-    "manager.help": {
-        "message": "Aide"
-    },
-    "manager.help.createbugreport": {
-        "message": "Cr?er un rapport d'erreur"
-    },
-    "manager.help.createbugreportinfo": {
-        "message": "Afin que TbSync ne collecte que les donn?es de d?bogages pertinentes pour r?soudre votre bogue, veuillez red?marrer Thunderbird et ensuite r?p?ter exactement les ?tapes qui causent le comportement ind?sir?. Ensuite, vous pourrez cr?er un rapport d'erreur depuis cette fen?tre-ci."
-    },
-    "manager.help.debuglevel.0": {
-        "message": "D?sactiv?"
-    },
-    "manager.help.debuglevel.1": {
-        "message": "Activ? : Seules les erreurs seront journalis?es"
-    },
-    "manager.help.debuglevel.2": {
-        "message": "Activ? : Toutes les donn?es re?ues et envoy?es seront journalis?es"
-    },
-    "manager.help.debuglevel.3": {
-        "message": "Activ?: Toutes les donn?es ainsi que certaines valeurs de d?bogages internes seront journalis?es"
-    },
-    "manager.help.debugmode": {
-        "message": "Mode de d?bogage :"
-    },
-    "manager.help.fixit": {
-        "message": "Vous pouvez nous aider ? la corriger en nous envoyant un rapport d'erreur. Cette op?ration n?cessite l'activation du mode de d?bogage."
-    },
-    "manager.help.foundabug": {
-        "message": "Vous avez trouv? un bogue ?"
-    },
-    "manager.help.needhelp": {
-        "message": "Besoin d'aide ?"
-    },
-    "manager.help.viewdebuglog": {
-        "message": "Voir le journal de d?bogage"
-    },
-    "manager.help.wiki": {
-        "message": "Ouvrez la page du wiki du projet TbSync; celle-ci fournit des informations compl?mentaire, un guide d'utilisation ainsi qu'une description d?taill? de la configuration du programme."
-    },
-    "manager.installprovider.link": {
-        "message": "Cliquez sur le lien ci-dessous pour ouvrir la page d'information sur le provider de synchronisation manquant. Vous y trouverez de plus amples informations sur le provider et aurez la possibilit? de l'installer :"
-    },
-    "manager.installprovider.warning": {
-        "message": "Ce provider de synchronisation n'est pas h?berg? sur le d?p?t Thunderbird officiel et n'a donc pas ?t? valid? par l'?quipe de Thunderbird. Il se peut donc qu'il ait un comportement n?faste pour votre syst?me. Utilisez-le ? vos propres risques."
-    },
-    "manager.lockedsettings.description": {
-        "message": "Afin d'?viter des erreurs de synchronisation, certains param?tres ne peuvent ?tre modifi? tant que ce compte est activ?."
-    },
-    "manager.missingprovider": {
-        "message": "Ce compte n?cessite le provider de synchronisation (##provider##), lequel n'est pas install?."
-    },
-    "manager.noaccounts": {
-        "message": "Aucun compte n'a encore ?t? configur?."
-    },
-    "manager.provider": {
-        "message": "Installer un provider"
-    },
-    "manager.provider4tbsync": {
-        "message": "Provider pour TbSync"
-    },
-    "manager.resource": {
-        "message": "Ressource"
-    },
-    "manager.shorttitle": {
-        "message": "Gestionnaire de comptes"
-    },
-    "manager.status": {
-        "message": "?tat"
-    },
-    "manager.supporter.contributors": {
-        "message": "Contributeurs et traducteurs"
-    },
-    "manager.supporter.details": {
-        "message": "D?tails"
-    },
-    "manager.supporter.sponsors": {
-        "message": "Sponsors fournissant des comptes de test"
-    },
-    "manager.tabs.status": {
-        "message": "Statut de synchronisation"
-    },
-    "manager.tabs.status.autotime": {
-        "message": "Synchronisation p?riodique (minutes)"
-    },
-    "manager.tabs.status.enableThisAccount": {
-        "message": "Activer et synchroniser ce compte"
-    },
-    "manager.tabs.status.general": {
-        "message": "G?n?ral"
-    },
-    "manager.tabs.status.never": {
-        "message": "Fixer ce param?tre ? 0 d?sactive la synchronisation p?riodique. La synchronisation push n'est pas encore impl?ment?e."
-    },
-    "manager.tabs.status.resources": {
-        "message": "Ressources disponibles"
-    },
-    "manager.tabs.status.resources.intro": {
-        "message": "Choisissez, parmi les ressources disponibles, celles que vous d?sirez synchroniser avec Thunderbird."
-    },
-    "manager.tabs.status.sync": {
-        "message": "Synchroniser maintenant"
-    },
-    "manager.tabs.status.tryagain": {
-        "message": "Essayer ? nouveau de se connecter au serveur"
-    },
-    "manager.title": {
-        "message": "Gestionnaire de comptes TbSync"
-    },
-    "manager.tryagain": {
-        "message": "Essayer ? nouveau de se connecter au serveur"
-    },
-    "menu.settingslabel": {
-        "message": "Param?tres de synchronisation (TbSync)"
-    },
-    "password.account": {
-        "message": "Compte :"
-    },
-    "password.description": {
-        "message": "Veuillez mettre ? jour le mot de passe pour le compte TbSync suivant :"
-    },
-    "password.password": {
-        "message": "Mot de passe :"
-    },
-    "password.title": {
-        "message": "Demande de mots de passe TbSync"
-    },
-    "password.user": {
-        "message": "Utilisateur :"
-    },
-    "popup.opensettings": {
-        "message": "Ouvrir le gestionnaire de comptes TbSync"
-    },
-    "prompt.DeleteAccount": {
-        "message": "?tes-vous certain de vouloir supprimer le compte ##accountName## ?"
-    },
-    "prompt.Disable": {
-        "message": "?tes-vous certain de vouloir d?sactiver ce compte ? Toutes les modifications locales non encore synchronis?es seront perdues !"
-    },
-    "prompt.Erase": {
-        "message": "?tes-vous certain de vouloir supprimer ce compte d'un provider inconnu de la liste des comptes ?"
-    },
-    "prompt.Unsubscribe": {
-        "message": "?tes-vous certain de vouloir supprimer l'abonnement ? cet ?l?ment ? Toutes les modifications locales non encore synchronis?es seront perdues !"
-    },
-    "status.JavaScriptError": {
-        "message": "Erreur Javascript ! Veuillez lire le journal de d?bogage pour plus de d?tails."
-    },
-    "status.OAuthAbortError": {
-        "message": "Processus d'authentification OAuth 2.0 abandonn? par l'utilisateur."
-    },
-    "status.OAuthHttpError": {
-        "message": "Le processus d'authentification OAuth 2.0 a ?chou? (erreur HTTP ##replace.1##)."
-    },
-    "status.OAuthNetworkError": {
-        "message": "Impossible de se connecter au serveur d'authentification OAuth 2.0."
-    },
-    "status.OAuthServerError": {
-        "message": " Le serveur d?authentification OAuth?2.0 a retourn??: ##replace.1##"
-    },
-    "status.aborted": {
-        "message": "Non synchronis?"
-    },
-    "status.apiError": {
-        "message": "Erreur dans l'impl?mentation de l'API"
-    },
-    "status.disabled": {
-        "message": "Le compte n'est pas activ?, la synchronisation est d?sactiv?e."
-    },
-    "status.foldererror": {
-        "message": "Au moins une ressource a rencontr? une erreur de synchronisation. Veuillez lire le journal de d?bogage pour plus de d?tails."
-    },
-    "status.modified": {
-        "message": "Modifications locales pr?sentes"
-    },
-    "status.network": {
-        "message": "Impossible de se connecter au serveur (##replace.1##)."
-    },
-    "status.no-folders-found-on-server": {
-        "message": "Impossible de trouver les ressources sur le serveur."
-    },
-    "status.notargets": {
-        "message": "Annulation de la synchronisation en cours : il est impossible de cr?er les destinations de synchronisation."
-    },
-    "status.notsyncronized": {
-        "message": "Le compte doit ?tre synchronis? : au moins un ?l?ments n'est pas synchronis?."
-    },
-    "status.pending": {
-        "message": "En attente de synchronisation"
-    },
-    "status.security": {
-        "message": "Impossible d'?tablir une connexion s?curis?e. Votre serveur utilise-t-il un certificat auto-sign? ou non certifi? de confiance, que vous n'avez pas import? dans Thunderbird ? (##replace.1##)"
-    },
-    "status.skipped": {
-        "message": "Pas encore pris en charge, ignor?"
-    },
-    "status.success": {
-        "message": "OK"
-    },
-    "status.syncing": {
-        "message": "Synchronisation en cours"
-    },
-    "status.451": {
-        "message": "Server issued redirect, retry in 5 seconds."
-    },
-    "supportwizard.footer": {
-        "message": "Un courriel sera g?n?r? ? partir des informations fournies ici. Vous aurez la possibilit? de le modifier par la suite (par exemple, pour y ajouter des captures d'?crans). Ce n'est que lorsque vous aurez envoy? l'e-mail que le rapport d'erreur nous sera envoy?."
-    },
-    "supportwizard.label.description": {
-        "message": "Description d?taill?e de l'erreur :"
-    },
-    "supportwizard.label.faultycomponent": {
-        "message": "Composant de TbSync o? vous avez observ? l'erreur :"
-    },
-    "supportwizard.label.selectcomponent": {
-        "message": "S?lectionnez un composant?"
-    },
-    "supportwizard.label.summary": {
-        "message": "Bref r?sum? de l'erreur :"
-    },
-    "supportwizard.pagetitle": {
-        "message": "R?colte de toutes les informations n?cessaires pour g?rer efficacement le rapport d'erreur."
-    },
-    "supportwizard.provider": {
-        "message": "Fournisseur?: ##replace.1##"
-    },
-    "supportwizard.title": {
-        "message": "Cr?er un rapport d'erreur"
-    },
-    "syncstate.accountdone": {
-        "message": "Synchronisation du compte termin?e"
-    },
-    "syncstate.done": {
-        "message": "Pr?paration de la synchronisation du prochain ?l?ment"
-    },
-    "syncstate.oauthprompt": {
-        "message": "Authentification OAuth 2.0"
-    },
-    "syncstate.passwordprompt": {
-        "message": "Demande d'insertion du mot de passe"
-    },
-    "syncstate.preparing": {
-        "message": "Pr?paration de la synchronisation du prochain ?l?ment"
-    },
-    "syncstate.syncing": {
-        "message": "Initialisation de la synchronisation"
-    },
-    "target.orphaned": {
-        "message": "Connexion rompue"
-    },
-    "toolbar.label": {
-        "message": "Synchroniser tous les comptes TbSync"
-    },
-    "toolbar.tooltiptext": {
-        "message": "Synchroniser les derni?res modifications"
-    },
-    "password.ok": {
-        "message": "OK"
-    },
-    "password.cancel": {
-        "message": "Annuler"
-    }
-}
+{
+    "HelpFixStartupError": {
+        "message": "Pour aider ? la r?solution de cette erreur, vous pourriez envoyer le journal de d?bogage au d?veloppeur de TbSync. Voulez-vous qu'on pr?pare un courriel ? cette fin ?"
+    },
+    "NoDebugLog": {
+        "message": "Il n'a pas ?t? possible de trouver un message de d?bogage utile. Merci d'activer le mode de d?bogage, de red?marrer Thunderbird puis de r?p?ter les ?tapes qui ont men?es au comportement anormal du programme."
+    },
+    "OopsMessage": {
+        "message": "Oups! TbSync n'a pas r?ussi ? d?marrer !"
+    },
+    "RestartThunderbirdAndTryAgain": {
+        "message": "Le journal de d?bogage de TbSync a ?t? activ?. Veuillez red?marrer Thunderbird et essayer ? nouveau d'ouvrir TbSync."
+    },
+    "UnableToTraceError": {
+        "message": "Il n'est pas possible de localiser cette erreur, parce que le journal de d?bogage n'est actuellement pas activ?. D?sirez-vous activer le journal de d?bogage maintenant, afin d'aider ? r?soudre cette erreur ?"
+    },
+    "accountacctions.delete": {
+        "message": "Supprimer le compte '##accountname##'"
+    },
+    "accountacctions.disable": {
+        "message": "D?sactiver le compte '##accountname##'"
+    },
+    "accountacctions.enable": {
+        "message": "Activer le compte '##accountname##' et tenter de se connecter au serveur"
+    },
+    "accountacctions.sync": {
+        "message": "Synchroniser le compte '##accountname##'"
+    },
+    "addressbook.searchall": {
+        "message": "Rechercher dans tous les carnets d'adresses"
+    },
+    "addressbook.searchgal": {
+        "message": "Recherche dans ce carnet d'adresse et dans l'annuaire global (##replace.1##)"
+    },
+    "addressbook.searchthis": {
+        "message": "Rechercher dans ce carnet d'adresse"
+    },
+    "eventlog.clear": {
+        "message": "Effacer"
+    },
+    "eventlog.close": {
+        "message": "Fermer"
+    },
+    "eventlog.title": {
+        "message": "Journal d'?v?nements"
+    },
+    "extensionDescription": {
+        "message": "TbSync est une interface permettant de g?rer de mani?re centralis?e ses comptes cloud et d'en synchroniser les contacts, t?ches et agendas avec Thunderbird."
+    },
+    "google.translate.code": {
+        "message": "fr"
+    },
+    "helplink.security": {
+        "message": "https://github.com/jobisoft/TbSync/wiki/How-to-use-TbSync-with-self-signed-or-otherwise-non-rusted-certificats%3F"
+    },
+    "info.error": {
+        "message": "Erreur"
+    },
+    "info.idle": {
+        "message": "Inactif"
+    },
+    "installProvider.header": {
+        "message": "Le provider TbSync '##replace.1##' n'est pas encore install?."
+    },
+    "manager.AccountActions": {
+        "message": "Actions sur les comptes"
+    },
+    "manager.AddAccount": {
+        "message": "Ajouter un nouveau compte"
+    },
+    "manager.DeleteAccount": {
+        "message": "Supprimer le compte"
+    },
+    "manager.DisableAccount": {
+        "message": "D?sactiver le compte"
+    },
+    "manager.EnableAccount": {
+        "message": "Activer le compte et tester la connexion au serveur"
+    },
+    "manager.RetryConnectAccount": {
+        "message": "Essayer ? nouveau de se connecter au serveur"
+    },
+    "manager.ShowEventLog": {
+        "message": "Montrer le journal d'?v?nements (log)"
+    },
+    "manager.SyncAll": {
+        "message": "Synchroniser tous les comptes activ?s"
+    },
+    "manager.SynchronizeAccount": {
+        "message": "Synchroniser le compte"
+    },
+    "manager.accounts": {
+        "message": "Comptes"
+    },
+    "manager.accountsettings": {
+        "message": "Param?tres du compte"
+    },
+    "manager.catman.text": {
+        "message": "TbSync synchronise ?galement les cat?gories de contacts, ce qui remplace avantageusement les listes de contacts, qui ne peuvent ?tre synchronis?es. Afin de pouvoir les utiliser dans le carnet d'adresses de Thunderbird, vous pouvez installer le module compl?mentaire Category Manager. Celui-ci vous permet de g?rer les contacts sur base de cat?gories (un contact pouvant en avoir plusieurs) et qui fournit d'autres fonctionnalit?s li?es aux cat?gories. Ce module peut ?tre trouv? sur le d?p?t officiel de Mozilla:"
+    },
+    "manager.community": {
+        "message": "Communaut?"
+    },
+    "manager.connecting": {
+        "message": "Connexion au serveur en cours"
+    },
+    "manager.help": {
+        "message": "Aide"
+    },
+    "manager.help.createbugreport": {
+        "message": "Cr?er un rapport d'erreur"
+    },
+    "manager.help.createbugreportinfo": {
+        "message": "Afin que TbSync ne collecte que les donn?es de d?bogages pertinentes pour r?soudre votre bogue, veuillez red?marrer Thunderbird et ensuite r?p?ter exactement les ?tapes qui causent le comportement ind?sir?. Ensuite, vous pourrez cr?er un rapport d'erreur depuis cette fen?tre-ci."
+    },
+    "manager.help.debuglevel.0": {
+        "message": "D?sactiv?"
+    },
+    "manager.help.debuglevel.1": {
+        "message": "Activ? : Seules les erreurs seront journalis?es"
+    },
+    "manager.help.debuglevel.2": {
+        "message": "Activ? : Toutes les donn?es re?ues et envoy?es seront journalis?es"
+    },
+    "manager.help.debuglevel.3": {
+        "message": "Activ?: Toutes les donn?es ainsi que certaines valeurs de d?bogages internes seront journalis?es"
+    },
+    "manager.help.debugmode": {
+        "message": "Mode de d?bogage :"
+    },
+    "manager.help.fixit": {
+        "message": "Vous pouvez nous aider ? la corriger en nous envoyant un rapport d'erreur. Cette op?ration n?cessite l'activation du mode de d?bogage."
+    },
+    "manager.help.foundabug": {
+        "message": "Vous avez trouv? un bogue ?"
+    },
+    "manager.help.needhelp": {
+        "message": "Besoin d'aide ?"
+    },
+    "manager.help.viewdebuglog": {
+        "message": "Voir le journal de d?bogage"
+    },
+    "manager.help.wiki": {
+        "message": "Ouvrez la page du wiki du projet TbSync; celle-ci fournit des informations compl?mentaire, un guide d'utilisation ainsi qu'une description d?taill? de la configuration du programme."
+    },
+    "manager.installprovider.link": {
+        "message": "Cliquez sur le lien ci-dessous pour ouvrir la page d'information sur le provider de synchronisation manquant. Vous y trouverez de plus amples informations sur le provider et aurez la possibilit? de l'installer :"
+    },
+    "manager.installprovider.warning": {
+        "message": "Ce provider de synchronisation n'est pas h?berg? sur le d?p?t Thunderbird officiel et n'a donc pas ?t? valid? par l'?quipe de Thunderbird. Il se peut donc qu'il ait un comportement n?faste pour votre syst?me. Utilisez-le ? vos propres risques."
+    },
+    "manager.lockedsettings.description": {
+        "message": "Afin d'?viter des erreurs de synchronisation, certains param?tres ne peuvent ?tre modifi? tant que ce compte est activ?."
+    },
+    "manager.missingprovider": {
+        "message": "Ce compte n?cessite le provider de synchronisation (##provider##), lequel n'est pas install?."
+    },
+    "manager.noaccounts": {
+        "message": "Aucun compte n'a encore ?t? configur?."
+    },
+    "manager.provider": {
+        "message": "Installer un provider"
+    },
+    "manager.provider4tbsync": {
+        "message": "Provider pour TbSync"
+    },
+    "manager.resource": {
+        "message": "Ressource"
+    },
+    "manager.shorttitle": {
+        "message": "Gestionnaire de comptes"
+    },
+    "manager.status": {
+        "message": "?tat"
+    },
+    "manager.supporter.contributors": {
+        "message": "Contributeurs et traducteurs"
+    },
+    "manager.supporter.details": {
+        "message": "D?tails"
+    },
+    "manager.supporter.sponsors": {
+        "message": "Sponsors fournissant des comptes de test"
+    },
+    "manager.tabs.status": {
+        "message": "Statut de synchronisation"
+    },
+    "manager.tabs.status.autotime": {
+        "message": "Synchronisation p?riodique (minutes)"
+    },
+    "manager.tabs.status.enableThisAccount": {
+        "message": "Activer et synchroniser ce compte"
+    },
+    "manager.tabs.status.general": {
+        "message": "G?n?ral"
+    },
+    "manager.tabs.status.never": {
+        "message": "Fixer ce param?tre ? 0 d?sactive la synchronisation p?riodique. La synchronisation push n'est pas encore impl?ment?e."
+    },
+    "manager.tabs.status.resources": {
+        "message": "Ressources disponibles"
+    },
+    "manager.tabs.status.resources.intro": {
+        "message": "Choisissez, parmi les ressources disponibles, celles que vous d?sirez synchroniser avec Thunderbird."
+    },
+    "manager.tabs.status.sync": {
+        "message": "Synchroniser maintenant"
+    },
+    "manager.tabs.status.tryagain": {
+        "message": "Essayer ? nouveau de se connecter au serveur"
+    },
+    "manager.title": {
+        "message": "Gestionnaire de comptes TbSync"
+    },
+    "manager.tryagain": {
+        "message": "Essayer ? nouveau de se connecter au serveur"
+    },
+    "menu.settingslabel": {
+        "message": "Param?tres de synchronisation (TbSync)"
+    },
+    "password.account": {
+        "message": "Compte :"
+    },
+    "password.description": {
+        "message": "Veuillez mettre ? jour le mot de passe pour le compte TbSync suivant :"
+    },
+    "password.password": {
+        "message": "Mot de passe :"
+    },
+    "password.title": {
+        "message": "Demande de mots de passe TbSync"
+    },
+    "password.user": {
+        "message": "Utilisateur :"
+    },
+    "popup.opensettings": {
+        "message": "Ouvrir le gestionnaire de comptes TbSync"
+    },
+    "prompt.DeleteAccount": {
+        "message": "?tes-vous certain de vouloir supprimer le compte ##accountName## ?"
+    },
+    "prompt.Disable": {
+        "message": "?tes-vous certain de vouloir d?sactiver ce compte ? Toutes les modifications locales non encore synchronis?es seront perdues !"
+    },
+    "prompt.Erase": {
+        "message": "?tes-vous certain de vouloir supprimer ce compte d'un provider inconnu de la liste des comptes ?"
+    },
+    "prompt.Unsubscribe": {
+        "message": "?tes-vous certain de vouloir supprimer l'abonnement ? cet ?l?ment ? Toutes les modifications locales non encore synchronis?es seront perdues !"
+    },
+    "status.JavaScriptError": {
+        "message": "Erreur Javascript ! Veuillez lire le journal de d?bogage pour plus de d?tails."
+    },
+    "status.OAuthAbortError": {
+        "message": "Processus d'authentification OAuth 2.0 abandonn? par l'utilisateur."
+    },
+    "status.OAuthHttpError": {
+        "message": "Le processus d'authentification OAuth 2.0 a ?chou? (erreur HTTP ##replace.1##)."
+    },
+    "status.OAuthNetworkError": {
+        "message": "Impossible de se connecter au serveur d'authentification OAuth 2.0."
+    },
+    "status.OAuthServerError": {
+        "message": " Le serveur d?authentification OAuth?2.0 a retourn??: ##replace.1##"
+    },
+    "status.aborted": {
+        "message": "Non synchronis?"
+    },
+    "status.apiError": {
+        "message": "Erreur dans l'impl?mentation de l'API"
+    },
+    "status.disabled": {
+        "message": "Le compte n'est pas activ?, la synchronisation est d?sactiv?e."
+    },
+    "status.foldererror": {
+        "message": "Au moins une ressource a rencontr? une erreur de synchronisation. Veuillez lire le journal de d?bogage pour plus de d?tails."
+    },
+    "status.modified": {
+        "message": "Modifications locales pr?sentes"
+    },
+    "status.network": {
+        "message": "Impossible de se connecter au serveur (##replace.1##)."
+    },
+    "status.no-folders-found-on-server": {
+        "message": "Impossible de trouver les ressources sur le serveur."
+    },
+    "status.notargets": {
+        "message": "Annulation de la synchronisation en cours : il est impossible de cr?er les destinations de synchronisation."
+    },
+    "status.notsyncronized": {
+        "message": "Le compte doit ?tre synchronis? : au moins un ?l?ments n'est pas synchronis?."
+    },
+    "status.pending": {
+        "message": "En attente de synchronisation"
+    },
+    "status.security": {
+        "message": "Impossible d'?tablir une connexion s?curis?e. Votre serveur utilise-t-il un certificat auto-sign? ou non certifi? de confiance, que vous n'avez pas import? dans Thunderbird ? (##replace.1##)"
+    },
+    "status.skipped": {
+        "message": "Pas encore pris en charge, ignor?"
+    },
+    "status.success": {
+        "message": "OK"
+    },
+    "status.syncing": {
+        "message": "Synchronisation en cours"
+    },
+    "status.451": {
+        "message": "Server issued redirect, retry in 5 seconds."
+    },
+    "supportwizard.footer": {
+        "message": "Un courriel sera g?n?r? ? partir des informations fournies ici. Vous aurez la possibilit? de le modifier par la suite (par exemple, pour y ajouter des captures d'?crans). Ce n'est que lorsque vous aurez envoy? l'e-mail que le rapport d'erreur nous sera envoy?."
+    },
+    "supportwizard.label.description": {
+        "message": "Description d?taill?e de l'erreur :"
+    },
+    "supportwizard.label.faultycomponent": {
+        "message": "Composant de TbSync o? vous avez observ? l'erreur :"
+    },
+    "supportwizard.label.selectcomponent": {
+        "message": "S?lectionnez un composant?"
+    },
+    "supportwizard.label.summary": {
+        "message": "Bref r?sum? de l'erreur :"
+    },
+    "supportwizard.pagetitle": {
+        "message": "R?colte de toutes les informations n?cessaires pour g?rer efficacement le rapport d'erreur."
+    },
+    "supportwizard.provider": {
+        "message": "Fournisseur?: ##replace.1##"
+    },
+    "supportwizard.title": {
+        "message": "Cr?er un rapport d'erreur"
+    },
+    "syncstate.accountdone": {
+        "message": "Synchronisation du compte termin?e"
+    },
+    "syncstate.done": {
+        "message": "Pr?paration de la synchronisation du prochain ?l?ment"
+    },
+    "syncstate.oauthprompt": {
+        "message": "Authentification OAuth 2.0"
+    },
+    "syncstate.passwordprompt": {
+        "message": "Demande d'insertion du mot de passe"
+    },
+    "syncstate.preparing": {
+        "message": "Pr?paration de la synchronisation du prochain ?l?ment"
+    },
+    "syncstate.syncing": {
+        "message": "Initialisation de la synchronisation"
+    },
+    "target.orphaned": {
+        "message": "Connexion rompue"
+    },
+    "toolbar.label": {
+        "message": "Synchroniser tous les comptes TbSync"
+    },
+    "toolbar.tooltiptext": {
+        "message": "Synchroniser les derni?res modifications"
+    },
+    "password.ok": {
+        "message": "OK"
+    },
+    "password.cancel": {
+        "message": "Annuler"
+    }
+}
diff -Nru tbsync-4.12/_locales/gl/messages.json tbsync-4.16/_locales/gl/messages.json
--- tbsync-4.12/_locales/gl/messages.json	2024-08-27 18:32:08.000000000 +0200
+++ tbsync-4.16/_locales/gl/messages.json	2024-08-27 18:29:06.000000000 +0200
@@ -1,368 +1,368 @@
-{
-    "HelpFixStartupError": {
-        "message": "Para axudar a corrixir este erro podes enviar un rexistro de depuraci?n ao desenvolvedor de TbSync. Queres preparar a mensaxe de correo agora?"
-    },
-    "NoDebugLog": {
-        "message": "Non se puideron atopar mensaxes de depuraci?n ?tiles. Por favor, activa o modo de depuraci?n, reinicia Thunderbird e repite todos os pasos necesarios para reproducir o comportamento err?neo."
-    },
-    "OopsMessage": {
-        "message": "Ou! TbSync non puido iniciar!"
-    },
-    "RestartThunderbirdAndTryAgain": {
-        "message": "Activouse o rexistro de depuraci?n de TbSync. Por favor, reinicia Thunderbird e trata de abrir TbSync outra vez."
-    },
-    "UnableToTraceError": {
-        "message": "Non ? posible obter rastrexar este erro porque o rexistro de depuraci?n non est? activado. Queres activalo agora para axudar a corrixir este erro?"
-    },
-    "accountacctions.delete": {
-        "message": "Eliminar a conta ?##accountname##?"
-    },
-    "accountacctions.disable": {
-        "message": "Desactivar a conta ?##accountname##?"
-    },
-    "accountacctions.enable": {
-        "message": "Activar a conta ?##accountname##? e intentar conectar ao servidor"
-    },
-    "accountacctions.sync": {
-        "message": "Sincronizar a conta ?##accountname##?"
-    },
-    "addressbook.searchall": {
-        "message": "Buscar en todos os cadernos de enderezos"
-    },
-    "addressbook.searchgal": {
-        "message": "Buscar neste caderno de enderezos e no directorio global (##replace.1##)"
-    },
-    "addressbook.searchthis": {
-        "message": "Buscar neste caderno de enderezos"
-    },
-    "eventlog.clear": {
-        "message": "Limpar"
-    },
-    "eventlog.close": {
-        "message": "Pechar"
-    },
-    "eventlog.title": {
-        "message": "Rexistro de eventos"
-    },
-    "extensionDescription": {
-        "message": "TbSync ? unha interface de usuario central para xestionar contas na nube e sincronizar os seus contactos, tarefas e calendarios con Thunderbird."
-    },
-    "google.translate.code": {
-        "message": "gl"
-    },
-    "helplink.security": {
-        "message": "https://github.com/jobisoft/TbSync/wiki/How-to-use-TbSync-with-self-signed-or-otherwise-untrusted-certificates%3F"
-    },
-    "info.error": {
-        "message": "Erro"
-    },
-    "info.idle": {
-        "message": "Inactivo"
-    },
-    "installProvider.header": {
-        "message": "O provedor ?##replace.1##? para TbSync a?nda non est? instalado."
-    },
-    "manager.AccountActions": {
-        "message": "Acci?ns da conta"
-    },
-    "manager.AddAccount": {
-        "message": "Engadir conta nova"
-    },
-    "manager.DeleteAccount": {
-        "message": "Eliminar conta"
-    },
-    "manager.DisableAccount": {
-        "message": "Desactivar conta"
-    },
-    "manager.EnableAccount": {
-        "message": "Activar a conta e conectar ao servidor"
-    },
-    "manager.RetryConnectAccount": {
-        "message": "Volver a intentar conectar ao servidor"
-    },
-    "manager.ShowEventLog": {
-        "message": "Abrir rexistro de eventos"
-    },
-    "manager.SyncAll": {
-        "message": "Sincronizar todas as contas activadas"
-    },
-    "manager.SynchronizeAccount": {
-        "message": "Sincronizar conta"
-    },
-    "manager.accounts": {
-        "message": "Contas"
-    },
-    "manager.accountsettings": {
-        "message": "Axustes da conta"
-    },
-    "manager.catman.text": {
-        "message": "TbSync tam?n sincroniza categor?as de contactos, que son un substituto moi pr?ctico para as listas de contactos non sincronizables. Para poder usalas no caderno de enderezos de Thunderbird tes que instalar o complemento Category Manager. Este complemento permite manexar categor?as que se superpo?en baseadas en grupos de contactos e aporta unha morea de caracter?sticas relacionadas coas categor?as. Podes atopalo no repositorio oficial de complementos de Mozilla:"
-    },
-    "manager.community": {
-        "message": "Comunidade"
-    },
-    "manager.connecting": {
-        "message": "Conectando ao servidor"
-    },
-    "manager.help": {
-        "message": "Axuda"
-    },
-    "manager.help.createbugreport": {
-        "message": "Crear informe de erro"
-    },
-    "manager.help.createbugreportinfo": {
-        "message": "Para que TbSync recolla s? os datos de depuraci?n relevantes ao teu informe de erro, por favor, reinicia Thunderbird e repite exactamente os pasos para reproducir o comportamento err?neo. A continuaci?n xa podes crear o teu informe de erro aqu?."
-    },
-    "manager.help.debuglevel.0": {
-        "message": "Desactivado"
-    },
-    "manager.help.debuglevel.1": {
-        "message": "Activado: s? rexistro de erros"
-    },
-    "manager.help.debuglevel.2": {
-        "message": "Activado: rexistro de todos os datos enviados e recibidos"
-    },
-    "manager.help.debuglevel.3": {
-        "message": "Activado: rexistro de todos os datos e algunhas variables internas de depuraci?n"
-    },
-    "manager.help.debugmode": {
-        "message": "Modo de depuraci?n:"
-    },
-    "manager.help.fixit": {
-        "message": "Podes axudar a corrixilo enviando un informe de depuraci?n. Isto precisa da activaci?n do modo de depuraci?n."
-    },
-    "manager.help.foundabug": {
-        "message": "Atopaches un erro?"
-    },
-    "manager.help.needhelp": {
-        "message": "Precisas de axuda?"
-    },
-    "manager.help.viewdebuglog": {
-        "message": "Ver rexistro de depuraci?n"
-    },
-    "manager.help.wiki": {
-        "message": "Abre o wiki do proxecto TbSync no que se facilita informaci?n adicional, gu?as e descrici?ns detalladas da configuraci?n."
-    },
-    "manager.installprovider.link": {
-        "message": "Preme no seguinte enlace para abrir a p?xina de informaci?n do provedor de sincronizaci?n que falta. A? atopar?s m?is informaci?n sobre o provedor e ter?s a opci?n de instalalo:"
-    },
-    "manager.installprovider.warning": {
-        "message": "Este provedor de sincronizaci?n non est? aloxado no repositorio oficial de complementos de Thunderbird e, polo tanto, non foi revisado polo persoal de Thunderbird. O provedor poder?a causar dano ao teu sistema. ?sao baixo a t?a responsabilidade."
-    },
-    "manager.lockedsettings.description": {
-        "message": "Para evitar erros de sincronizaci?n alg?ns axustes non se poden editar coa conta activada."
-    },
-    "manager.missingprovider": {
-        "message": "Esta conta precisa do provedor de sincronizaci?n ##provider## que non est? instalado."
-    },
-    "manager.noaccounts": {
-        "message": "A?nda non hai contas definidas."
-    },
-    "manager.provider": {
-        "message": "Instalar provedor"
-    },
-    "manager.provider4tbsync": {
-        "message": "Provedor para TbSync"
-    },
-    "manager.resource": {
-        "message": "Recurso"
-    },
-    "manager.shorttitle": {
-        "message": "Xestor de contas"
-    },
-    "manager.status": {
-        "message": "Estado"
-    },
-    "manager.supporter.contributors": {
-        "message": "Colaboradores e tradutores"
-    },
-    "manager.supporter.details": {
-        "message": "Detalles"
-    },
-    "manager.supporter.sponsors": {
-        "message": "Patrocinadores de contas de proba"
-    },
-    "manager.tabs.status": {
-        "message": "Estado da sincronizaci?n"
-    },
-    "manager.tabs.status.autotime": {
-        "message": "Sincronizaci?n peri?dica (en minutos)"
-    },
-    "manager.tabs.status.enableThisAccount": {
-        "message": "Activar e sincronizar esta conta"
-    },
-    "manager.tabs.status.general": {
-        "message": "Xeral"
-    },
-    "manager.tabs.status.never": {
-        "message": "Un 0 desactiva a sincronizaci?n peri?dica. A sincronizaci?n push a?nda non est? implementada."
-    },
-    "manager.tabs.status.resources": {
-        "message": "Recursos dispo?ibles"
-    },
-    "manager.tabs.status.resources.intro": {
-        "message": "Selecciona cal dos recursos atopados queres sincronizar con Thunderbird."
-    },
-    "manager.tabs.status.sync": {
-        "message": "Sincronizar agora"
-    },
-    "manager.tabs.status.tryagain": {
-        "message": "Volver a intentar conectar ao servidor"
-    },
-    "manager.title": {
-        "message": "Xestor de contas de TbSync"
-    },
-    "manager.tryagain": {
-        "message": "Volver a intentar conectar ao servidor"
-    },
-    "menu.settingslabel": {
-        "message": "Axustes de sincronizaci?n (TbSync)"
-    },
-    "password.account": {
-        "message": "Conta:"
-    },
-    "password.description": {
-        "message": "Por favor, actualiza as credenciais da seguinte conta de TbSync:"
-    },
-    "password.password": {
-        "message": "Contrasinal:"
-    },
-    "password.title": {
-        "message": "Solicitude de credenciais de TbSync"
-    },
-    "password.user": {
-        "message": "Usuario:"
-    },
-    "popup.opensettings": {
-        "message": "Abrir o xestor de contas de TbSync"
-    },
-    "prompt.DeleteAccount": {
-        "message": "Seguro que queres eliminar a conta ##accountName##?"
-    },
-    "prompt.Disable": {
-        "message": "Seguro que queres desactivar esta conta? Perderanse todas as modificaci?ns locais que a?nda non foran sincronizadas!"
-    },
-    "prompt.Erase": {
-        "message": "Seguro que queres eliminar esta conta dun provedor desco?ecido da lista de contas?"
-    },
-    "prompt.Unsubscribe": {
-        "message": "Seguro que queres cancelar a subscrici?n a este elemento? Perderanse todas as modificaci?ns locais que a?nda non foran sincronizadas!"
-    },
-    "status.JavaScriptError": {
-        "message": "Erro de Javascript! Por favor, comproba o rexistro de eventos para dispor de m?is detalles."
-    },
-    "status.OAuthAbortError": {
-        "message": "Proceso de autenticaci?n OAuth 2.0 cancelado polo usuario."
-    },
-    "status.OAuthHttpError": {
-        "message": "O proceso de autenticaci?n OAuth 2.0 fallou (erro HTTP ##replace.1##)."
-    },
-    "status.OAuthNetworkError": {
-        "message": "Non se puido conectar ao servidor de autenticaci?n OAuth 2.0."
-    },
-    "status.OAuthServerError": {
-        "message": " O servidor de autenticaci?n OAuth 2.0 respondeu: ##replace.1##"
-    },
-    "status.aborted": {
-        "message": "Sen sincronizar"
-    },
-    "status.apiError": {
-        "message": "Erro de implementaci?n da API"
-    },
-    "status.disabled": {
-        "message": "A conta non est? activada, a sincronizaci?n est? desactivada."
-    },
-    "status.foldererror": {
-        "message": "Hai alg?n que recurso tivo un erro de sincronizaci?n. Por favor, revisa o rexistro de eventos para dispor de m?is detalles."
-    },
-    "status.modified": {
-        "message": "Modificaci?ns locais"
-    },
-    "status.network": {
-        "message": "Non se puido conectar ao servidor (##replace.1##)."
-    },
-    "status.no-folders-found-on-server": {
-        "message": "Non se atopou ning?n recurso no servidor."
-    },
-    "status.notargets": {
-        "message": "Cancelando a sincronizaci?n porque non se puideron crear os destinos da sincronizaci?n."
-    },
-    "status.notsyncronized": {
-        "message": "? preciso sincronizar a conta porque hai alg?n elemento sen sincronizar."
-    },
-    "status.pending": {
-        "message": "Esperando pola sincronizaci?n"
-    },
-    "status.security": {
-        "message": "Non se puido establecer unha conexi?n segura. Est?s a usar alg?n certificado autofirmado, ou que non sexa de confianza, sen telo importado a Thunderbird? (##replace.1##)"
-    },
-    "status.skipped": {
-        "message": "A?nda non soportado, omitido"
-    },
-    "status.success": {
-        "message": "OK"
-    },
-    "status.syncing": {
-        "message": "Sincronizando"
-    },
-    "supportwizard.footer": {
-        "message": "No seguinte paso, coa informaci?n facilitada aqu?, xerarase unha mensaxe de correo que poder?s editar (por exemplo, engadindo capturas de pantalla ou algo parecido). O informe de erro s? ser? enviando cando env?es esa mensaxe de correo."
-    },
-    "status.451": {
-        "message": "Server issued redirect, retry in 5 seconds."
-    },
-    "supportwizard.label.description": {
-        "message": "Descrici?n detallada do erro:"
-    },
-    "supportwizard.label.faultycomponent": {
-        "message": "Compo?ente de TbSync no que observaches o erro:"
-    },
-    "supportwizard.label.selectcomponent": {
-        "message": "Seleccionar compo?ente?"
-    },
-    "supportwizard.label.summary": {
-        "message": "Resumo curto do erro:"
-    },
-    "supportwizard.pagetitle": {
-        "message": "Recompilaci?n de toda a informaci?n para procesar de forma efectiva o informe de erro."
-    },
-    "supportwizard.provider": {
-        "message": "Provedor: ##replace.1##"
-    },
-    "supportwizard.title": {
-        "message": "Crear informe de erro"
-    },
-    "syncstate.accountdone": {
-        "message": "Conta rematada"
-    },
-    "syncstate.done": {
-        "message": "Preparando o seguinte elemento para a sincronizaci?n"
-    },
-    "syncstate.oauthprompt": {
-        "message": "Autenticaci?n OAuth 2.0"
-    },
-    "syncstate.passwordprompt": {
-        "message": "Solicitude de credenciais"
-    },
-    "syncstate.preparing": {
-        "message": "Preparando o seguinte elemento para a sincronizaci?n"
-    },
-    "syncstate.syncing": {
-        "message": "Iniciar sincronizaci?n"
-    },
-    "target.orphaned": {
-        "message": "Desconectado"
-    },
-    "toolbar.label": {
-        "message": "Sincronizar todas as contas de TbSync"
-    },
-    "toolbar.tooltiptext": {
-        "message": "Sincronizar os ?ltimos cambios"
-    },
-    "password.ok": {
-        "message": "Aceptar"
-    },
-    "password.cancel": {
-        "message": "Cancelar"
-    }
-}
+{
+    "HelpFixStartupError": {
+        "message": "Para axudar a corrixir este erro podes enviar un rexistro de depuraci?n ao desenvolvedor de TbSync. Queres preparar a mensaxe de correo agora?"
+    },
+    "NoDebugLog": {
+        "message": "Non se puideron atopar mensaxes de depuraci?n ?tiles. Por favor, activa o modo de depuraci?n, reinicia Thunderbird e repite todos os pasos necesarios para reproducir o comportamento err?neo."
+    },
+    "OopsMessage": {
+        "message": "Ou! TbSync non puido iniciar!"
+    },
+    "RestartThunderbirdAndTryAgain": {
+        "message": "Activouse o rexistro de depuraci?n de TbSync. Por favor, reinicia Thunderbird e trata de abrir TbSync outra vez."
+    },
+    "UnableToTraceError": {
+        "message": "Non ? posible obter rastrexar este erro porque o rexistro de depuraci?n non est? activado. Queres activalo agora para axudar a corrixir este erro?"
+    },
+    "accountacctions.delete": {
+        "message": "Eliminar a conta ?##accountname##?"
+    },
+    "accountacctions.disable": {
+        "message": "Desactivar a conta ?##accountname##?"
+    },
+    "accountacctions.enable": {
+        "message": "Activar a conta ?##accountname##? e intentar conectar ao servidor"
+    },
+    "accountacctions.sync": {
+        "message": "Sincronizar a conta ?##accountname##?"
+    },
+    "addressbook.searchall": {
+        "message": "Buscar en todos os cadernos de enderezos"
+    },
+    "addressbook.searchgal": {
+        "message": "Buscar neste caderno de enderezos e no directorio global (##replace.1##)"
+    },
+    "addressbook.searchthis": {
+        "message": "Buscar neste caderno de enderezos"
+    },
+    "eventlog.clear": {
+        "message": "Limpar"
+    },
+    "eventlog.close": {
+        "message": "Pechar"
+    },
+    "eventlog.title": {
+        "message": "Rexistro de eventos"
+    },
+    "extensionDescription": {
+        "message": "TbSync ? unha interface de usuario central para xestionar contas na nube e sincronizar os seus contactos, tarefas e calendarios con Thunderbird."
+    },
+    "google.translate.code": {
+        "message": "gl"
+    },
+    "helplink.security": {
+        "message": "https://github.com/jobisoft/TbSync/wiki/How-to-use-TbSync-with-self-signed-or-otherwise-untrusted-certificates%3F"
+    },
+    "info.error": {
+        "message": "Erro"
+    },
+    "info.idle": {
+        "message": "Inactivo"
+    },
+    "installProvider.header": {
+        "message": "O provedor ?##replace.1##? para TbSync a?nda non est? instalado."
+    },
+    "manager.AccountActions": {
+        "message": "Acci?ns da conta"
+    },
+    "manager.AddAccount": {
+        "message": "Engadir conta nova"
+    },
+    "manager.DeleteAccount": {
+        "message": "Eliminar conta"
+    },
+    "manager.DisableAccount": {
+        "message": "Desactivar conta"
+    },
+    "manager.EnableAccount": {
+        "message": "Activar a conta e conectar ao servidor"
+    },
+    "manager.RetryConnectAccount": {
+        "message": "Volver a intentar conectar ao servidor"
+    },
+    "manager.ShowEventLog": {
+        "message": "Abrir rexistro de eventos"
+    },
+    "manager.SyncAll": {
+        "message": "Sincronizar todas as contas activadas"
+    },
+    "manager.SynchronizeAccount": {
+        "message": "Sincronizar conta"
+    },
+    "manager.accounts": {
+        "message": "Contas"
+    },
+    "manager.accountsettings": {
+        "message": "Axustes da conta"
+    },
+    "manager.catman.text": {
+        "message": "TbSync tam?n sincroniza categor?as de contactos, que son un substituto moi pr?ctico para as listas de contactos non sincronizables. Para poder usalas no caderno de enderezos de Thunderbird tes que instalar o complemento Category Manager. Este complemento permite manexar categor?as que se superpo?en baseadas en grupos de contactos e aporta unha morea de caracter?sticas relacionadas coas categor?as. Podes atopalo no repositorio oficial de complementos de Mozilla:"
+    },
+    "manager.community": {
+        "message": "Comunidade"
+    },
+    "manager.connecting": {
+        "message": "Conectando ao servidor"
+    },
+    "manager.help": {
+        "message": "Axuda"
+    },
+    "manager.help.createbugreport": {
+        "message": "Crear informe de erro"
+    },
+    "manager.help.createbugreportinfo": {
+        "message": "Para que TbSync recolla s? os datos de depuraci?n relevantes ao teu informe de erro, por favor, reinicia Thunderbird e repite exactamente os pasos para reproducir o comportamento err?neo. A continuaci?n xa podes crear o teu informe de erro aqu?."
+    },
+    "manager.help.debuglevel.0": {
+        "message": "Desactivado"
+    },
+    "manager.help.debuglevel.1": {
+        "message": "Activado: s? rexistro de erros"
+    },
+    "manager.help.debuglevel.2": {
+        "message": "Activado: rexistro de todos os datos enviados e recibidos"
+    },
+    "manager.help.debuglevel.3": {
+        "message": "Activado: rexistro de todos os datos e algunhas variables internas de depuraci?n"
+    },
+    "manager.help.debugmode": {
+        "message": "Modo de depuraci?n:"
+    },
+    "manager.help.fixit": {
+        "message": "Podes axudar a corrixilo enviando un informe de depuraci?n. Isto precisa da activaci?n do modo de depuraci?n."
+    },
+    "manager.help.foundabug": {
+        "message": "Atopaches un erro?"
+    },
+    "manager.help.needhelp": {
+        "message": "Precisas de axuda?"
+    },
+    "manager.help.viewdebuglog": {
+        "message": "Ver rexistro de depuraci?n"
+    },
+    "manager.help.wiki": {
+        "message": "Abre o wiki do proxecto TbSync no que se facilita informaci?n adicional, gu?as e descrici?ns detalladas da configuraci?n."
+    },
+    "manager.installprovider.link": {
+        "message": "Preme no seguinte enlace para abrir a p?xina de informaci?n do provedor de sincronizaci?n que falta. A? atopar?s m?is informaci?n sobre o provedor e ter?s a opci?n de instalalo:"
+    },
+    "manager.installprovider.warning": {
+        "message": "Este provedor de sincronizaci?n non est? aloxado no repositorio oficial de complementos de Thunderbird e, polo tanto, non foi revisado polo persoal de Thunderbird. O provedor poder?a causar dano ao teu sistema. ?sao baixo a t?a responsabilidade."
+    },
+    "manager.lockedsettings.description": {
+        "message": "Para evitar erros de sincronizaci?n alg?ns axustes non se poden editar coa conta activada."
+    },
+    "manager.missingprovider": {
+        "message": "Esta conta precisa do provedor de sincronizaci?n ##provider## que non est? instalado."
+    },
+    "manager.noaccounts": {
+        "message": "A?nda non hai contas definidas."
+    },
+    "manager.provider": {
+        "message": "Instalar provedor"
+    },
+    "manager.provider4tbsync": {
+        "message": "Provedor para TbSync"
+    },
+    "manager.resource": {
+        "message": "Recurso"
+    },
+    "manager.shorttitle": {
+        "message": "Xestor de contas"
+    },
+    "manager.status": {
+        "message": "Estado"
+    },
+    "manager.supporter.contributors": {
+        "message": "Colaboradores e tradutores"
+    },
+    "manager.supporter.details": {
+        "message": "Detalles"
+    },
+    "manager.supporter.sponsors": {
+        "message": "Patrocinadores de contas de proba"
+    },
+    "manager.tabs.status": {
+        "message": "Estado da sincronizaci?n"
+    },
+    "manager.tabs.status.autotime": {
+        "message": "Sincronizaci?n peri?dica (en minutos)"
+    },
+    "manager.tabs.status.enableThisAccount": {
+        "message": "Activar e sincronizar esta conta"
+    },
+    "manager.tabs.status.general": {
+        "message": "Xeral"
+    },
+    "manager.tabs.status.never": {
+        "message": "Un 0 desactiva a sincronizaci?n peri?dica. A sincronizaci?n push a?nda non est? implementada."
+    },
+    "manager.tabs.status.resources": {
+        "message": "Recursos dispo?ibles"
+    },
+    "manager.tabs.status.resources.intro": {
+        "message": "Selecciona cal dos recursos atopados queres sincronizar con Thunderbird."
+    },
+    "manager.tabs.status.sync": {
+        "message": "Sincronizar agora"
+    },
+    "manager.tabs.status.tryagain": {
+        "message": "Volver a intentar conectar ao servidor"
+    },
+    "manager.title": {
+        "message": "Xestor de contas de TbSync"
+    },
+    "manager.tryagain": {
+        "message": "Volver a intentar conectar ao servidor"
+    },
+    "menu.settingslabel": {
+        "message": "Axustes de sincronizaci?n (TbSync)"
+    },
+    "password.account": {
+        "message": "Conta:"
+    },
+    "password.description": {
+        "message": "Por favor, actualiza as credenciais da seguinte conta de TbSync:"
+    },
+    "password.password": {
+        "message": "Contrasinal:"
+    },
+    "password.title": {
+        "message": "Solicitude de credenciais de TbSync"
+    },
+    "password.user": {
+        "message": "Usuario:"
+    },
+    "popup.opensettings": {
+        "message": "Abrir o xestor de contas de TbSync"
+    },
+    "prompt.DeleteAccount": {
+        "message": "Seguro que queres eliminar a conta ##accountName##?"
+    },
+    "prompt.Disable": {
+        "message": "Seguro que queres desactivar esta conta? Perderanse todas as modificaci?ns locais que a?nda non foran sincronizadas!"
+    },
+    "prompt.Erase": {
+        "message": "Seguro que queres eliminar esta conta dun provedor desco?ecido da lista de contas?"
+    },
+    "prompt.Unsubscribe": {
+        "message": "Seguro que queres cancelar a subscrici?n a este elemento? Perderanse todas as modificaci?ns locais que a?nda non foran sincronizadas!"
+    },
+    "status.JavaScriptError": {
+        "message": "Erro de Javascript! Por favor, comproba o rexistro de eventos para dispor de m?is detalles."
+    },
+    "status.OAuthAbortError": {
+        "message": "Proceso de autenticaci?n OAuth 2.0 cancelado polo usuario."
+    },
+    "status.OAuthHttpError": {
+        "message": "O proceso de autenticaci?n OAuth 2.0 fallou (erro HTTP ##replace.1##)."
+    },
+    "status.OAuthNetworkError": {
+        "message": "Non se puido conectar ao servidor de autenticaci?n OAuth 2.0."
+    },
+    "status.OAuthServerError": {
+        "message": " O servidor de autenticaci?n OAuth 2.0 respondeu: ##replace.1##"
+    },
+    "status.aborted": {
+        "message": "Sen sincronizar"
+    },
+    "status.apiError": {
+        "message": "Erro de implementaci?n da API"
+    },
+    "status.disabled": {
+        "message": "A conta non est? activada, a sincronizaci?n est? desactivada."
+    },
+    "status.foldererror": {
+        "message": "Hai alg?n que recurso tivo un erro de sincronizaci?n. Por favor, revisa o rexistro de eventos para dispor de m?is detalles."
+    },
+    "status.modified": {
+        "message": "Modificaci?ns locais"
+    },
+    "status.network": {
+        "message": "Non se puido conectar ao servidor (##replace.1##)."
+    },
+    "status.no-folders-found-on-server": {
+        "message": "Non se atopou ning?n recurso no servidor."
+    },
+    "status.notargets": {
+        "message": "Cancelando a sincronizaci?n porque non se puideron crear os destinos da sincronizaci?n."
+    },
+    "status.notsyncronized": {
+        "message": "? preciso sincronizar a conta porque hai alg?n elemento sen sincronizar."
+    },
+    "status.pending": {
+        "message": "Esperando pola sincronizaci?n"
+    },
+    "status.security": {
+        "message": "Non se puido establecer unha conexi?n segura. Est?s a usar alg?n certificado autofirmado, ou que non sexa de confianza, sen telo importado a Thunderbird? (##replace.1##)"
+    },
+    "status.skipped": {
+        "message": "A?nda non soportado, omitido"
+    },
+    "status.success": {
+        "message": "OK"
+    },
+    "status.syncing": {
+        "message": "Sincronizando"
+    },
+    "supportwizard.footer": {
+        "message": "No seguinte paso, coa informaci?n facilitada aqu?, xerarase unha mensaxe de correo que poder?s editar (por exemplo, engadindo capturas de pantalla ou algo parecido). O informe de erro s? ser? enviando cando env?es esa mensaxe de correo."
+    },
+    "status.451": {
+        "message": "Server issued redirect, retry in 5 seconds."
+    },
+    "supportwizard.label.description": {
+        "message": "Descrici?n detallada do erro:"
+    },
+    "supportwizard.label.faultycomponent": {
+        "message": "Compo?ente de TbSync no que observaches o erro:"
+    },
+    "supportwizard.label.selectcomponent": {
+        "message": "Seleccionar compo?ente?"
+    },
+    "supportwizard.label.summary": {
+        "message": "Resumo curto do erro:"
+    },
+    "supportwizard.pagetitle": {
+        "message": "Recompilaci?n de toda a informaci?n para procesar de forma efectiva o informe de erro."
+    },
+    "supportwizard.provider": {
+        "message": "Provedor: ##replace.1##"
+    },
+    "supportwizard.title": {
+        "message": "Crear informe de erro"
+    },
+    "syncstate.accountdone": {
+        "message": "Conta rematada"
+    },
+    "syncstate.done": {
+        "message": "Preparando o seguinte elemento para a sincronizaci?n"
+    },
+    "syncstate.oauthprompt": {
+        "message": "Autenticaci?n OAuth 2.0"
+    },
+    "syncstate.passwordprompt": {
+        "message": "Solicitude de credenciais"
+    },
+    "syncstate.preparing": {
+        "message": "Preparando o seguinte elemento para a sincronizaci?n"
+    },
+    "syncstate.syncing": {
+        "message": "Iniciar sincronizaci?n"
+    },
+    "target.orphaned": {
+        "message": "Desconectado"
+    },
+    "toolbar.label": {
+        "message": "Sincronizar todas as contas de TbSync"
+    },
+    "toolbar.tooltiptext": {
+        "message": "Sincronizar os ?ltimos cambios"
+    },
+    "password.ok": {
+        "message": "Aceptar"
+    },
+    "password.cancel": {
+        "message": "Cancelar"
+    }
+}
diff -Nru tbsync-4.12/_locales/hu/messages.json tbsync-4.16/_locales/hu/messages.json
--- tbsync-4.12/_locales/hu/messages.json	2024-08-27 18:32:08.000000000 +0200
+++ tbsync-4.16/_locales/hu/messages.json	2024-08-27 18:29:06.000000000 +0200
@@ -1,368 +1,368 @@
-{
-    "HelpFixStartupError": {
-        "message": "A hiba jav?t?s?hoz hibakeres?si napl?t k?ldhet a TbSync fejleszt?j?nek. El?k?sz?ti most azt az e-mailt?"
-    },
-    "NoDebugLog": {
-        "message": "Nem tal?lhat? hasznos hibaelh?r?t? ?zenet. Enged?lyezze a hibakeres?si m?dot, ind?tsa ?jra a Thunderbird?t ?s ism?telje meg a hib?s viselked?st el?id?z? l?p?seket."
-    },
-    "OopsMessage": {
-        "message": "Hopp?! A TbSync nem tudott elindulni."
-    },
-    "RestartThunderbirdAndTryAgain": {
-        "message": "A TbSync hibakeres?si napl? enged?lyezett, ind?tsa ?jra a Thunderbird?t, ?s pr?b?lja ?jra megnyitni a TbSyncet."
-    },
-    "UnableToTraceError": {
-        "message": "Nem lehet nyomon k?vetni ezt a hib?t, mert a hibakeres?si napl? jelenleg nincs enged?lyezve. Szeretn? enged?lyezni a hibakeres?si napl?t, hogy seg?tsen jav?tani a hib?t?"
-    },
-    "accountacctions.delete": {
-        "message": "A(z) ?##accountname##? fi?k t?rl?se"
-    },
-    "accountacctions.disable": {
-        "message": "A(z) ?##accountname##? fi?k letilt?sa"
-    },
-    "accountacctions.enable": {
-        "message": "A(z) ?##accountname##? fi?k enged?lyez?se ?s ?jrakapcsol?d?s a kiszolg?l?hoz"
-    },
-    "accountacctions.sync": {
-        "message": "A(z) ?##accountname##? fi?k szinkroniz?l?sa"
-    },
-    "addressbook.searchall": {
-        "message": "Keres?se az ?sszes n?vjegyz?kben"
-    },
-    "addressbook.searchgal": {
-        "message": "Keres?s ebben a n?vjegyz?kben ?s a glob?lis k?nyvt?rban (##replace.1##)"
-    },
-    "addressbook.searchthis": {
-        "message": "Keres?s ebben a c?mjegyz?kben"
-    },
-    "eventlog.clear": {
-        "message": "T?rl?s"
-    },
-    "eventlog.close": {
-        "message": "Bez?r?s"
-    },
-    "eventlog.title": {
-        "message": "Esem?nynapl?"
-    },
-    "extensionDescription": {
-        "message": "A TbSync egy k?zponti felhaszn?l?i fel?let a felh?fi?kok kezel?s?hez, ?s a n?vjegyek, feladatok ?s napt?radatok Thunderbirddel t?rt?n? szinkroniz?s?hoz."
-    },
-    "google.translate.code": {
-        "message": "hu"
-    },
-    "helplink.security": {
-        "message": "https://github.com/jobisoft/TbSync/wiki/How-to-use-TbSync-with-self-signed-or-otherwise-untrusted-certificates%3F"
-    },
-    "info.error": {
-        "message": "Hiba"
-    },
-    "info.idle": {
-        "message": "T?tlen"
-    },
-    "installProvider.header": {
-        "message": "A(z) ?##replace.1##? TbSync szolg?ltat? m?g nincs telep?tve."
-    },
-    "manager.AccountActions": {
-        "message": "Fi?km?veletek"
-    },
-    "manager.AddAccount": {
-        "message": "?j fi?k hozz?ad?sa"
-    },
-    "manager.DeleteAccount": {
-        "message": "Fi?k t?rl?se"
-    },
-    "manager.DisableAccount": {
-        "message": "Fi?k letilt?sa"
-    },
-    "manager.EnableAccount": {
-        "message": "Fi?k enged?lyez?se ?s ?jrakapcsol?d?s a kiszolg?l?hoz"
-    },
-    "manager.RetryConnectAccount": {
-        "message": "Pr?b?ljon ?jrakapcsol?dni a kiszolg?l?hoz"
-    },
-    "manager.ShowEventLog": {
-        "message": "Esem?nynapl? megnyit?sa"
-    },
-    "manager.SyncAll": {
-        "message": "Az ?sszes enged?lyezett fi?k szinkroniz?l?sa"
-    },
-    "manager.SynchronizeAccount": {
-        "message": "Fi?k szinkroniz?l?sa"
-    },
-    "manager.accounts": {
-        "message": "Fi?kok"
-    },
-    "manager.accountsettings": {
-        "message": "Fi?kbe?ll?t?sok"
-    },
-    "manager.catman.text": {
-        "message": "A TbSync szinkroniz?lja a n?vjegykateg?ri?kat is, amelyek hat?konyan helyettes?tik a nem szinkroniz?lhat? n?vjegylist?kat. A Thunderbird n?vjegyz?kben val? haszn?lathoz telep?theti a Kateg?riakezel? kieg?sz?t?t. Lehet?v? teszi az ?tfed? kateg?ri?kon alapul? n?vjegycsoportok kezel?s?t, ?s egy sor m?s kateg?ri?val kapcsolatos funkci?t. Ez megtal?lhat? a hivatalos Thunderbird-kieg?sz?t?k weboldalon:"
-    },
-    "manager.community": {
-        "message": "K?z?ss?g"
-    },
-    "manager.connecting": {
-        "message": "Kapcsol?d?s a kiszolg?l?hoz"
-    },
-    "manager.help": {
-        "message": "S?g?"
-    },
-    "manager.help.createbugreport": {
-        "message": "Hibajelent?s l?trehoz?sa"
-    },
-    "manager.help.createbugreportinfo": {
-        "message": "Hogy a TbSync csak a hibajelent?shez relev?ns adatokat gy?jtse be, ind?tsa ?jra a Thunderbird?t, majd ism?telje meg a pontos l?p?seket a hiba reproduk?l?s?hoz. Ezut?n itt l?trehozhatja a hibajelent?s?t."
-    },
-    "manager.help.debuglevel.0": {
-        "message": "Tiltva"
-    },
-    "manager.help.debuglevel.1": {
-        "message": "Enged?lyezve: Csak a hib?k napl?z?sa"
-    },
-    "manager.help.debuglevel.2": {
-        "message": "Enged?lyezve: Az ?sszes k?ld?tt ?s fogadott adat napl?z?sa"
-    },
-    "manager.help.debuglevel.3": {
-        "message": "Enged?lyezve: Az ?sszes adat ?s n?h?ny bels? hibakeres?si ?rt?k napl?z?sa"
-    },
-    "manager.help.debugmode": {
-        "message": "Hibakeres?si m?d:"
-    },
-    "manager.help.fixit": {
-        "message": "Seg?thet a jav?t?sban egy hibajelent?s k?ld?s?vel. Ehhez a hibakeres?si m?d bekapcsol?sa sz?ks?ges."
-    },
-    "manager.help.foundabug": {
-        "message": "Hib?t tal?lt?"
-    },
-    "manager.help.needhelp": {
-        "message": "Seg?ts?gre van sz?ks?ge?"
-    },
-    "manager.help.viewdebuglog": {
-        "message": "Hibakeres?si napl? megtekint?se"
-    },
-    "manager.help.wiki": {
-        "message": "Nyissa meg a TbSync projekt wiki oldalait, amely tov?bbi inform?ci?kat, ?tmutat?kat ?s r?szletes be?ll?t?si le?r?sokat biztos?t."
-    },
-    "manager.installprovider.link": {
-        "message": "Kattintson a k?vetkez? hivatkoz?sra a hi?nyz? szinkroniz?ci?s szolg?ltat?k inform?ci?s oldal?nak megnyit?s?hoz. Ott tov?bbi inform?ci?kat tal?l a szolg?ltat?r?l, ?s lehet?s?ge van a telep?t?sre:"
-    },
-    "manager.installprovider.warning": {
-        "message": "Ez az szinkroniz?l?si szolg?ltat? nem a hivatalos Thunderbird-kieg?sz?t?t?rban tal?lhat?, ?gy a Thunderbird st?bja nem ellen?rizte. A szolg?ltat? rossz dolgokat tehet a rendszer?vel. A saj?t felel?ss?g?re haszn?lja."
-    },
-    "manager.lockedsettings.description": {
-        "message": "A szinkroniz?l?si hib?k elker?l?se ?rdek?ben egyes be?ll?t?sok nem szerkeszthet?k, am?g a fi?k enged?lyezett."
-    },
-    "manager.missingprovider": {
-        "message": "Ehhez a fi?khoz a(z) ##provider## szinkroniz?l?si szolg?ltat? sz?ks?ges, amely jelenleg nincs telep?tve."
-    },
-    "manager.noaccounts": {
-        "message": "M?g nincsenek fi?kok megadva."
-    },
-    "manager.provider": {
-        "message": "Szolg?ltat? telep?t?se"
-    },
-    "manager.provider4tbsync": {
-        "message": "Szolg?ltat? a TbSynchez"
-    },
-    "manager.resource": {
-        "message": "Er?forr?s"
-    },
-    "manager.shorttitle": {
-        "message": "Fi?kkezel?"
-    },
-    "manager.status": {
-        "message": "?llapot"
-    },
-    "manager.supporter.contributors": {
-        "message": "K?zrem?k?d?k ?s ford?t?k"
-    },
-    "manager.supporter.details": {
-        "message": "R?szletek"
-    },
-    "manager.supporter.sponsors": {
-        "message": "A tesztfi?kok t?mogat?i"
-    },
-    "manager.tabs.status": {
-        "message": "Szinkroniz?l?s ?llapota"
-    },
-    "manager.tabs.status.autotime": {
-        "message": "Id?szakos szinkroniz?l?s (perc)"
-    },
-    "manager.tabs.status.enableThisAccount": {
-        "message": "Fi?k enged?lyez?se ?s szinkroniz?l?sa"
-    },
-    "manager.tabs.status.general": {
-        "message": "?ltal?nos"
-    },
-    "manager.tabs.status.never": {
-        "message": "A 0 be?ll?t?sa letiltja az id?szakos szinkroniz?l?sa. A lek?ld?ses szinkroniz?ci? m?g nincs megval?s?tva."
-    },
-    "manager.tabs.status.resources": {
-        "message": "El?rhet? er?forr?sok"
-    },
-    "manager.tabs.status.resources.intro": {
-        "message": "V?lasszon, hogy mely er?forr?sokat kell szinkroniz?lni a Thunderbirddel."
-    },
-    "manager.tabs.status.sync": {
-        "message": "Szinkroniz?l?s most"
-    },
-    "manager.tabs.status.tryagain": {
-        "message": "Pr?b?ljon ?jrakapcsol?dni a kiszolg?l?hoz"
-    },
-    "manager.title": {
-        "message": "TbSync fi?kkezel?"
-    },
-    "manager.tryagain": {
-        "message": "Pr?b?ljon ?jrakapcsol?dni a kiszolg?l?hoz"
-    },
-    "menu.settingslabel": {
-        "message": "Szinkroniz?l?si be?ll?t?sok (TbSync)"
-    },
-    "password.account": {
-        "message": "Fi?k:"
-    },
-    "password.description": {
-        "message": "Friss?tse a k?vetkez? TbSync-fi?k hiteles?t? adatait:"
-    },
-    "password.password": {
-        "message": "Jelsz?:"
-    },
-    "password.title": {
-        "message": "TbSync hiteles?t?si k?r?s"
-    },
-    "password.user": {
-        "message": "Felhaszn?l?:"
-    },
-    "popup.opensettings": {
-        "message": "TbSync fi?kkezel? megnyit?sa"
-    },
-    "prompt.DeleteAccount": {
-        "message": "Biztos, hogy t?r?lni szeretn? a(z) ##accountName## fi?kot?"
-    },
-    "prompt.Disable": {
-        "message": "Biztos, hogy letiltja ezt a fi?kot? Minden helyi m?dos?t?s, amely m?g nincs szinkroniz?lva, elv?sz."
-    },
-    "prompt.Erase": {
-        "message": "Biztos, hogy elt?vol?tja ezt az ismeretlen szolg?ltat?i fi?kot a fi?kok k?z?l?"
-    },
-    "prompt.Unsubscribe": {
-        "message": "Biztos, hogy le szeretne iratkozni err?l az elemr?l? Minden helyi m?dos?t?s, amely m?g nincs szinkroniz?lva, elv?sz."
-    },
-    "status.JavaScriptError": {
-        "message": "JavaScript hiba! Tov?bbi r?szletek?rt n?zze meg az esem?nynapl?t."
-    },
-    "status.OAuthAbortError": {
-        "message": "Az OAuth 2.0 hiteles?t?si folyamatot a felhaszn?l? megszak?totta."
-    },
-    "status.OAuthHttpError": {
-        "message": "Az OAuth 2.0 hiteles?t?si folyamat sikertelen (HTTP hibak?d: ##replace.1##)."
-    },
-    "status.OAuthNetworkError": {
-        "message": "Nem siker?lt csatlakozni az OAuth 2.0 hiteles?t?si kiszolg?l?hoz."
-    },
-    "status.OAuthServerError": {
-        "message": " Az OAuth 2.0 hiteles?t?si kiszolg?l? v?lasza: ##replace.1##"
-    },
-    "status.aborted": {
-        "message": "Nincs szinkroniz?lva"
-    },
-    "status.apiError": {
-        "message": "API megval?s?t?si hiba"
-    },
-    "status.disabled": {
-        "message": "A fi?k nem enged?lyezett, a szinkroniz?l?s tiltott."
-    },
-    "status.foldererror": {
-        "message": "Legal?bb egy er?forr?s szinkroniz?l?si hib?t ?szlelt. Tov?bbi r?szletek?rt n?zze meg az esem?nynapl?t."
-    },
-    "status.modified": {
-        "message": "Helyi m?dos?t?sok"
-    },
-    "status.network": {
-        "message": "Nem siker?lt kapcsol?dni a kiszolg?l?hoz (##replace.1##)."
-    },
-    "status.no-folders-found-on-server": {
-        "message": "A kiszolg?l?n nem tal?lhat? er?forr?s."
-    },
-    "status.notargets": {
-        "message": "A szinkroniz?l?s abbahagy?sa, mert a szinkroniz?l?si c?lokat nem lehetett l?trehozni."
-    },
-    "status.notsyncronized": {
-        "message": "A fi?kot szinkroniz?lni kell, legal?bb egy nincs szinkroniz?lva."
-    },
-    "status.pending": {
-        "message": "V?rakoz?s a szinkroniz?l?sra"
-    },
-    "status.security": {
-        "message": "A biztons?gos kapcsolat l?trehoz?sa nem siker?lt. ?nal??rt vagy m?s, nem megb?zhat? tan?s?tv?nyt import?lt a Thunderbirdbe? (##replace.1##)"
-    },
-    "status.skipped": {
-        "message": "M?g nem t?mogatott, kihagyva"
-    },
-    "status.success": {
-        "message": "OK"
-    },
-    "status.syncing": {
-        "message": "Szinkroniz?l?s"
-    },
-    "supportwizard.footer": {
-        "message": "Az itt megadott inform?ci?b?l e-mail k?sz?l, amelyet azt?n szerkeszthet (p?ld?ul k?perny?k?peket adhat hozz?). Csak akkor lesz elk?ldve hibajelent?s, ha t?nyleg elk?ldi azt az e-mailt."
-    },
-    "status.451": {
-        "message": "Server issued redirect, retry in 5 seconds."
-    },
-    "supportwizard.label.description": {
-        "message": "Hiba r?szletes le?r?sa:"
-    },
-    "supportwizard.label.faultycomponent": {
-        "message": "A TbSync-?sszetev?, ahol hiba t?rt?nt:"
-    },
-    "supportwizard.label.selectcomponent": {
-        "message": "?sszetev? kiv?laszt?sa?"
-    },
-    "supportwizard.label.summary": {
-        "message": "A hiba r?vid ?sszefoglal?sa:"
-    },
-    "supportwizard.pagetitle": {
-        "message": "Inform?ci?gy?jt?s a hibajelent?s feldolgoz?s?hoz."
-    },
-    "supportwizard.provider": {
-        "message": "Szolg?ltat?: ##replace.1##"
-    },
-    "supportwizard.title": {
-        "message": "Hibajelent?s l?trehoz?sa"
-    },
-    "syncstate.accountdone": {
-        "message": "Fi?k k?sz"
-    },
-    "syncstate.done": {
-        "message": "A k?vetkez? elem el?k?sz?t?se szinkroniz?l?sra"
-    },
-    "syncstate.oauthprompt": {
-        "message": "OAuth 2.0 hiteles?t?s"
-    },
-    "syncstate.passwordprompt": {
-        "message": "Hiteles?t? adatok k?r?se"
-    },
-    "syncstate.preparing": {
-        "message": "A k?vetkez? elem el?k?sz?t?se szinkroniz?l?sra"
-    },
-    "syncstate.syncing": {
-        "message": "Szinkroniz?l?s el?k?sz?t?se"
-    },
-    "target.orphaned": {
-        "message": "Lev?lasztva"
-    },
-    "toolbar.label": {
-        "message": "Az ?sszes TbSync-fi?k szinkroniz?l?sa"
-    },
-    "toolbar.tooltiptext": {
-        "message": "A leg?jabb v?ltoztat?sok szinkroniz?l?sa"
-    },
-    "password.ok": {
-        "message": "Rendben"
-    },
-    "password.cancel": {
-        "message": "M?gse"
-    }
-}
+{
+    "HelpFixStartupError": {
+        "message": "A hiba jav?t?s?hoz hibakeres?si napl?t k?ldhet a TbSync fejleszt?j?nek. El?k?sz?ti most azt az e-mailt?"
+    },
+    "NoDebugLog": {
+        "message": "Nem tal?lhat? hasznos hibaelh?r?t? ?zenet. Enged?lyezze a hibakeres?si m?dot, ind?tsa ?jra a Thunderbird?t ?s ism?telje meg a hib?s viselked?st el?id?z? l?p?seket."
+    },
+    "OopsMessage": {
+        "message": "Hopp?! A TbSync nem tudott elindulni."
+    },
+    "RestartThunderbirdAndTryAgain": {
+        "message": "A TbSync hibakeres?si napl? enged?lyezett, ind?tsa ?jra a Thunderbird?t, ?s pr?b?lja ?jra megnyitni a TbSyncet."
+    },
+    "UnableToTraceError": {
+        "message": "Nem lehet nyomon k?vetni ezt a hib?t, mert a hibakeres?si napl? jelenleg nincs enged?lyezve. Szeretn? enged?lyezni a hibakeres?si napl?t, hogy seg?tsen jav?tani a hib?t?"
+    },
+    "accountacctions.delete": {
+        "message": "A(z) ?##accountname##? fi?k t?rl?se"
+    },
+    "accountacctions.disable": {
+        "message": "A(z) ?##accountname##? fi?k letilt?sa"
+    },
+    "accountacctions.enable": {
+        "message": "A(z) ?##accountname##? fi?k enged?lyez?se ?s ?jrakapcsol?d?s a kiszolg?l?hoz"
+    },
+    "accountacctions.sync": {
+        "message": "A(z) ?##accountname##? fi?k szinkroniz?l?sa"
+    },
+    "addressbook.searchall": {
+        "message": "Keres?se az ?sszes n?vjegyz?kben"
+    },
+    "addressbook.searchgal": {
+        "message": "Keres?s ebben a n?vjegyz?kben ?s a glob?lis k?nyvt?rban (##replace.1##)"
+    },
+    "addressbook.searchthis": {
+        "message": "Keres?s ebben a c?mjegyz?kben"
+    },
+    "eventlog.clear": {
+        "message": "T?rl?s"
+    },
+    "eventlog.close": {
+        "message": "Bez?r?s"
+    },
+    "eventlog.title": {
+        "message": "Esem?nynapl?"
+    },
+    "extensionDescription": {
+        "message": "A TbSync egy k?zponti felhaszn?l?i fel?let a felh?fi?kok kezel?s?hez, ?s a n?vjegyek, feladatok ?s napt?radatok Thunderbirddel t?rt?n? szinkroniz?s?hoz."
+    },
+    "google.translate.code": {
+        "message": "hu"
+    },
+    "helplink.security": {
+        "message": "https://github.com/jobisoft/TbSync/wiki/How-to-use-TbSync-with-self-signed-or-otherwise-untrusted-certificates%3F"
+    },
+    "info.error": {
+        "message": "Hiba"
+    },
+    "info.idle": {
+        "message": "T?tlen"
+    },
+    "installProvider.header": {
+        "message": "A(z) ?##replace.1##? TbSync szolg?ltat? m?g nincs telep?tve."
+    },
+    "manager.AccountActions": {
+        "message": "Fi?km?veletek"
+    },
+    "manager.AddAccount": {
+        "message": "?j fi?k hozz?ad?sa"
+    },
+    "manager.DeleteAccount": {
+        "message": "Fi?k t?rl?se"
+    },
+    "manager.DisableAccount": {
+        "message": "Fi?k letilt?sa"
+    },
+    "manager.EnableAccount": {
+        "message": "Fi?k enged?lyez?se ?s ?jrakapcsol?d?s a kiszolg?l?hoz"
+    },
+    "manager.RetryConnectAccount": {
+        "message": "Pr?b?ljon ?jrakapcsol?dni a kiszolg?l?hoz"
+    },
+    "manager.ShowEventLog": {
+        "message": "Esem?nynapl? megnyit?sa"
+    },
+    "manager.SyncAll": {
+        "message": "Az ?sszes enged?lyezett fi?k szinkroniz?l?sa"
+    },
+    "manager.SynchronizeAccount": {
+        "message": "Fi?k szinkroniz?l?sa"
+    },
+    "manager.accounts": {
+        "message": "Fi?kok"
+    },
+    "manager.accountsettings": {
+        "message": "Fi?kbe?ll?t?sok"
+    },
+    "manager.catman.text": {
+        "message": "A TbSync szinkroniz?lja a n?vjegykateg?ri?kat is, amelyek hat?konyan helyettes?tik a nem szinkroniz?lhat? n?vjegylist?kat. A Thunderbird n?vjegyz?kben val? haszn?lathoz telep?theti a Kateg?riakezel? kieg?sz?t?t. Lehet?v? teszi az ?tfed? kateg?ri?kon alapul? n?vjegycsoportok kezel?s?t, ?s egy sor m?s kateg?ri?val kapcsolatos funkci?t. Ez megtal?lhat? a hivatalos Thunderbird-kieg?sz?t?k weboldalon:"
+    },
+    "manager.community": {
+        "message": "K?z?ss?g"
+    },
+    "manager.connecting": {
+        "message": "Kapcsol?d?s a kiszolg?l?hoz"
+    },
+    "manager.help": {
+        "message": "S?g?"
+    },
+    "manager.help.createbugreport": {
+        "message": "Hibajelent?s l?trehoz?sa"
+    },
+    "manager.help.createbugreportinfo": {
+        "message": "Hogy a TbSync csak a hibajelent?shez relev?ns adatokat gy?jtse be, ind?tsa ?jra a Thunderbird?t, majd ism?telje meg a pontos l?p?seket a hiba reproduk?l?s?hoz. Ezut?n itt l?trehozhatja a hibajelent?s?t."
+    },
+    "manager.help.debuglevel.0": {
+        "message": "Tiltva"
+    },
+    "manager.help.debuglevel.1": {
+        "message": "Enged?lyezve: Csak a hib?k napl?z?sa"
+    },
+    "manager.help.debuglevel.2": {
+        "message": "Enged?lyezve: Az ?sszes k?ld?tt ?s fogadott adat napl?z?sa"
+    },
+    "manager.help.debuglevel.3": {
+        "message": "Enged?lyezve: Az ?sszes adat ?s n?h?ny bels? hibakeres?si ?rt?k napl?z?sa"
+    },
+    "manager.help.debugmode": {
+        "message": "Hibakeres?si m?d:"
+    },
+    "manager.help.fixit": {
+        "message": "Seg?thet a jav?t?sban egy hibajelent?s k?ld?s?vel. Ehhez a hibakeres?si m?d bekapcsol?sa sz?ks?ges."
+    },
+    "manager.help.foundabug": {
+        "message": "Hib?t tal?lt?"
+    },
+    "manager.help.needhelp": {
+        "message": "Seg?ts?gre van sz?ks?ge?"
+    },
+    "manager.help.viewdebuglog": {
+        "message": "Hibakeres?si napl? megtekint?se"
+    },
+    "manager.help.wiki": {
+        "message": "Nyissa meg a TbSync projekt wiki oldalait, amely tov?bbi inform?ci?kat, ?tmutat?kat ?s r?szletes be?ll?t?si le?r?sokat biztos?t."
+    },
+    "manager.installprovider.link": {
+        "message": "Kattintson a k?vetkez? hivatkoz?sra a hi?nyz? szinkroniz?ci?s szolg?ltat?k inform?ci?s oldal?nak megnyit?s?hoz. Ott tov?bbi inform?ci?kat tal?l a szolg?ltat?r?l, ?s lehet?s?ge van a telep?t?sre:"
+    },
+    "manager.installprovider.warning": {
+        "message": "Ez az szinkroniz?l?si szolg?ltat? nem a hivatalos Thunderbird-kieg?sz?t?t?rban tal?lhat?, ?gy a Thunderbird st?bja nem ellen?rizte. A szolg?ltat? rossz dolgokat tehet a rendszer?vel. A saj?t felel?ss?g?re haszn?lja."
+    },
+    "manager.lockedsettings.description": {
+        "message": "A szinkroniz?l?si hib?k elker?l?se ?rdek?ben egyes be?ll?t?sok nem szerkeszthet?k, am?g a fi?k enged?lyezett."
+    },
+    "manager.missingprovider": {
+        "message": "Ehhez a fi?khoz a(z) ##provider## szinkroniz?l?si szolg?ltat? sz?ks?ges, amely jelenleg nincs telep?tve."
+    },
+    "manager.noaccounts": {
+        "message": "M?g nincsenek fi?kok megadva."
+    },
+    "manager.provider": {
+        "message": "Szolg?ltat? telep?t?se"
+    },
+    "manager.provider4tbsync": {
+        "message": "Szolg?ltat? a TbSynchez"
+    },
+    "manager.resource": {
+        "message": "Er?forr?s"
+    },
+    "manager.shorttitle": {
+        "message": "Fi?kkezel?"
+    },
+    "manager.status": {
+        "message": "?llapot"
+    },
+    "manager.supporter.contributors": {
+        "message": "K?zrem?k?d?k ?s ford?t?k"
+    },
+    "manager.supporter.details": {
+        "message": "R?szletek"
+    },
+    "manager.supporter.sponsors": {
+        "message": "A tesztfi?kok t?mogat?i"
+    },
+    "manager.tabs.status": {
+        "message": "Szinkroniz?l?s ?llapota"
+    },
+    "manager.tabs.status.autotime": {
+        "message": "Id?szakos szinkroniz?l?s (perc)"
+    },
+    "manager.tabs.status.enableThisAccount": {
+        "message": "Fi?k enged?lyez?se ?s szinkroniz?l?sa"
+    },
+    "manager.tabs.status.general": {
+        "message": "?ltal?nos"
+    },
+    "manager.tabs.status.never": {
+        "message": "A 0 be?ll?t?sa letiltja az id?szakos szinkroniz?l?sa. A lek?ld?ses szinkroniz?ci? m?g nincs megval?s?tva."
+    },
+    "manager.tabs.status.resources": {
+        "message": "El?rhet? er?forr?sok"
+    },
+    "manager.tabs.status.resources.intro": {
+        "message": "V?lasszon, hogy mely er?forr?sokat kell szinkroniz?lni a Thunderbirddel."
+    },
+    "manager.tabs.status.sync": {
+        "message": "Szinkroniz?l?s most"
+    },
+    "manager.tabs.status.tryagain": {
+        "message": "Pr?b?ljon ?jrakapcsol?dni a kiszolg?l?hoz"
+    },
+    "manager.title": {
+        "message": "TbSync fi?kkezel?"
+    },
+    "manager.tryagain": {
+        "message": "Pr?b?ljon ?jrakapcsol?dni a kiszolg?l?hoz"
+    },
+    "menu.settingslabel": {
+        "message": "Szinkroniz?l?si be?ll?t?sok (TbSync)"
+    },
+    "password.account": {
+        "message": "Fi?k:"
+    },
+    "password.description": {
+        "message": "Friss?tse a k?vetkez? TbSync-fi?k hiteles?t? adatait:"
+    },
+    "password.password": {
+        "message": "Jelsz?:"
+    },
+    "password.title": {
+        "message": "TbSync hiteles?t?si k?r?s"
+    },
+    "password.user": {
+        "message": "Felhaszn?l?:"
+    },
+    "popup.opensettings": {
+        "message": "TbSync fi?kkezel? megnyit?sa"
+    },
+    "prompt.DeleteAccount": {
+        "message": "Biztos, hogy t?r?lni szeretn? a(z) ##accountName## fi?kot?"
+    },
+    "prompt.Disable": {
+        "message": "Biztos, hogy letiltja ezt a fi?kot? Minden helyi m?dos?t?s, amely m?g nincs szinkroniz?lva, elv?sz."
+    },
+    "prompt.Erase": {
+        "message": "Biztos, hogy elt?vol?tja ezt az ismeretlen szolg?ltat?i fi?kot a fi?kok k?z?l?"
+    },
+    "prompt.Unsubscribe": {
+        "message": "Biztos, hogy le szeretne iratkozni err?l az elemr?l? Minden helyi m?dos?t?s, amely m?g nincs szinkroniz?lva, elv?sz."
+    },
+    "status.JavaScriptError": {
+        "message": "JavaScript hiba! Tov?bbi r?szletek?rt n?zze meg az esem?nynapl?t."
+    },
+    "status.OAuthAbortError": {
+        "message": "Az OAuth 2.0 hiteles?t?si folyamatot a felhaszn?l? megszak?totta."
+    },
+    "status.OAuthHttpError": {
+        "message": "Az OAuth 2.0 hiteles?t?si folyamat sikertelen (HTTP hibak?d: ##replace.1##)."
+    },
+    "status.OAuthNetworkError": {
+        "message": "Nem siker?lt csatlakozni az OAuth 2.0 hiteles?t?si kiszolg?l?hoz."
+    },
+    "status.OAuthServerError": {
+        "message": " Az OAuth 2.0 hiteles?t?si kiszolg?l? v?lasza: ##replace.1##"
+    },
+    "status.aborted": {
+        "message": "Nincs szinkroniz?lva"
+    },
+    "status.apiError": {
+        "message": "API megval?s?t?si hiba"
+    },
+    "status.disabled": {
+        "message": "A fi?k nem enged?lyezett, a szinkroniz?l?s tiltott."
+    },
+    "status.foldererror": {
+        "message": "Legal?bb egy er?forr?s szinkroniz?l?si hib?t ?szlelt. Tov?bbi r?szletek?rt n?zze meg az esem?nynapl?t."
+    },
+    "status.modified": {
+        "message": "Helyi m?dos?t?sok"
+    },
+    "status.network": {
+        "message": "Nem siker?lt kapcsol?dni a kiszolg?l?hoz (##replace.1##)."
+    },
+    "status.no-folders-found-on-server": {
+        "message": "A kiszolg?l?n nem tal?lhat? er?forr?s."
+    },
+    "status.notargets": {
+        "message": "A szinkroniz?l?s abbahagy?sa, mert a szinkroniz?l?si c?lokat nem lehetett l?trehozni."
+    },
+    "status.notsyncronized": {
+        "message": "A fi?kot szinkroniz?lni kell, legal?bb egy nincs szinkroniz?lva."
+    },
+    "status.pending": {
+        "message": "V?rakoz?s a szinkroniz?l?sra"
+    },
+    "status.security": {
+        "message": "A biztons?gos kapcsolat l?trehoz?sa nem siker?lt. ?nal??rt vagy m?s, nem megb?zhat? tan?s?tv?nyt import?lt a Thunderbirdbe? (##replace.1##)"
+    },
+    "status.skipped": {
+        "message": "M?g nem t?mogatott, kihagyva"
+    },
+    "status.success": {
+        "message": "OK"
+    },
+    "status.syncing": {
+        "message": "Szinkroniz?l?s"
+    },
+    "supportwizard.footer": {
+        "message": "Az itt megadott inform?ci?b?l e-mail k?sz?l, amelyet azt?n szerkeszthet (p?ld?ul k?perny?k?peket adhat hozz?). Csak akkor lesz elk?ldve hibajelent?s, ha t?nyleg elk?ldi azt az e-mailt."
+    },
+    "status.451": {
+        "message": "Server issued redirect, retry in 5 seconds."
+    },
+    "supportwizard.label.description": {
+        "message": "Hiba r?szletes le?r?sa:"
+    },
+    "supportwizard.label.faultycomponent": {
+        "message": "A TbSync-?sszetev?, ahol hiba t?rt?nt:"
+    },
+    "supportwizard.label.selectcomponent": {
+        "message": "?sszetev? kiv?laszt?sa?"
+    },
+    "supportwizard.label.summary": {
+        "message": "A hiba r?vid ?sszefoglal?sa:"
+    },
+    "supportwizard.pagetitle": {
+        "message": "Inform?ci?gy?jt?s a hibajelent?s feldolgoz?s?hoz."
+    },
+    "supportwizard.provider": {
+        "message": "Szolg?ltat?: ##replace.1##"
+    },
+    "supportwizard.title": {
+        "message": "Hibajelent?s l?trehoz?sa"
+    },
+    "syncstate.accountdone": {
+        "message": "Fi?k k?sz"
+    },
+    "syncstate.done": {
+        "message": "A k?vetkez? elem el?k?sz?t?se szinkroniz?l?sra"
+    },
+    "syncstate.oauthprompt": {
+        "message": "OAuth 2.0 hiteles?t?s"
+    },
+    "syncstate.passwordprompt": {
+        "message": "Hiteles?t? adatok k?r?se"
+    },
+    "syncstate.preparing": {
+        "message": "A k?vetkez? elem el?k?sz?t?se szinkroniz?l?sra"
+    },
+    "syncstate.syncing": {
+        "message": "Szinkroniz?l?s el?k?sz?t?se"
+    },
+    "target.orphaned": {
+        "message": "Lev?lasztva"
+    },
+    "toolbar.label": {
+        "message": "Az ?sszes TbSync-fi?k szinkroniz?l?sa"
+    },
+    "toolbar.tooltiptext": {
+        "message": "A leg?jabb v?ltoztat?sok szinkroniz?l?sa"
+    },
+    "password.ok": {
+        "message": "Rendben"
+    },
+    "password.cancel": {
+        "message": "M?gse"
+    }
+}
diff -Nru tbsync-4.12/_locales/it/messages.json tbsync-4.16/_locales/it/messages.json
--- tbsync-4.12/_locales/it/messages.json	2024-08-27 18:32:08.000000000 +0200
+++ tbsync-4.16/_locales/it/messages.json	2024-08-27 18:29:06.000000000 +0200
@@ -1,368 +1,368 @@
-{
-    "HelpFixStartupError": {
-        "message": "Per contribuire a correggere quest'errore potresti inviare un log di debug allo sviluppatore di TbSync. Preparare tale messaggio di posta elettronica ora?"
-    },
-    "NoDebugLog": {
-        "message": "Non ? stato possibile trovare alcun messaggio di debug utile. Attiva la modalit? di debug, riavvia Thunderbird e ripeti tutti i passaggi richiesti per scatenare il comportamento errato."
-    },
-    "OopsMessage": {
-        "message": "Oops! TbSync non ? stato in grado di avviarsi!"
-    },
-    "RestartThunderbirdAndTryAgain": {
-        "message": "Il log di debug di TbSync ? stato abilitato, riavviare Thunderbird e riprovare ad aprire TbSync."
-    },
-    "UnableToTraceError": {
-        "message": "Non ? possibile localizzare quest'errore perch? i log di debug non sono attualmente abilitati. Abilitare ora il log di debug per contribuire a correggere quest'errore?"
-    },
-    "accountacctions.delete": {
-        "message": "Elimina l'account '##accountname##'"
-    },
-    "accountacctions.disable": {
-        "message": "Disabilita l'account '##accountname##'"
-    },
-    "accountacctions.enable": {
-        "message": "Abilita l'account '##accountname##' e tenta la connessione al server"
-    },
-    "accountacctions.sync": {
-        "message": "Sincronizza l'account '##accountname##'"
-    },
-    "addressbook.searchall": {
-        "message": "Cerca in tutte le rubriche"
-    },
-    "addressbook.searchgal": {
-        "message": "Cerca in questa rubrica e nella directory globale (##replace.1##)"
-    },
-    "addressbook.searchthis": {
-        "message": "Cerca in questa rubrica"
-    },
-    "eventlog.clear": {
-        "message": "Svuota"
-    },
-    "eventlog.close": {
-        "message": "Chiudi"
-    },
-    "eventlog.title": {
-        "message": "Registro eventi"
-    },
-    "extensionDescription": {
-        "message": "TbSync ? un'interfaccia utente che consente di gestire in modo centralizzato account cloud e di sincronizzare i loro contatti, attivit? e calendari con Thunderbird."
-    },
-    "google.translate.code": {
-        "message": "it"
-    },
-    "helplink.security": {
-        "message": "https://github.com/jobisoft/TbSync/wiki/How-to-use-TbSync-with-self-signed-or-otherwise-untrusted-certificates%3F"
-    },
-    "info.error": {
-        "message": "Errore"
-    },
-    "info.idle": {
-        "message": "Inattivo"
-    },
-    "installProvider.header": {
-        "message": "Il provider '##replace.1##' per TbSync non ? ancora installato."
-    },
-    "manager.AccountActions": {
-        "message": "Azioni account"
-    },
-    "manager.AddAccount": {
-        "message": "Aggiungi nuovo account"
-    },
-    "manager.DeleteAccount": {
-        "message": "Elimina account"
-    },
-    "manager.DisableAccount": {
-        "message": "Disabilita account"
-    },
-    "manager.EnableAccount": {
-        "message": "Abilita account e testa la connessione al server"
-    },
-    "manager.RetryConnectAccount": {
-        "message": "Riprova a collegarti al server"
-    },
-    "manager.ShowEventLog": {
-        "message": "Mostra registro eventi"
-    },
-    "manager.SyncAll": {
-        "message": "Sincronizza tutti gli account abilitati"
-    },
-    "manager.SynchronizeAccount": {
-        "message": "Sincronizza account"
-    },
-    "manager.accounts": {
-        "message": "Account"
-    },
-    "manager.accountsettings": {
-        "message": "Impostazioni account"
-    },
-    "manager.catman.text": {
-        "message": "TbSync sincronizza anche le categorie dei contatti, che sono un potente sostituto degli elenchi contatti (non sincronizzabili). Per poterle utilizzare nella Rubrica di Thunderbird ? possibile installare il componente aggiuntivo Category Manager, che consente di gestire gruppi di contatti basati su categorie (anche sovrapposte) e che fornisce altre funzionalit? legate alle categorie. Lo si pu? trovare nel repository ufficiale Mozilla dei componenti aggiuntivi:"
-    },
-    "manager.community": {
-        "message": "Comunit?"
-    },
-    "manager.connecting": {
-        "message": "Connessione al server in corso"
-    },
-    "manager.help": {
-        "message": "Aiuto"
-    },
-    "manager.help.createbugreport": {
-        "message": "Crea segnalazione d'errore"
-    },
-    "manager.help.createbugreportinfo": {
-        "message": "Per far s? che TbSync raccolga solo i messaggi di debug significativi per la segnalazione d'errore, riavvia Thunderbird e ripeti esattamente i passaggi necessari per riprodurre il comportamento errato. In seguito puoi creare qui la segnalazione d'errore."
-    },
-    "manager.help.debuglevel.0": {
-        "message": "Disabilitata"
-    },
-    "manager.help.debuglevel.1": {
-        "message": "Abilitata: registra solo gli errori"
-    },
-    "manager.help.debuglevel.2": {
-        "message": "Abilitata: registra tutti i dati inviati e ricevuti"
-    },
-    "manager.help.debuglevel.3": {
-        "message": "Abilitata: registra tutti i dati e alcuni valori interni di debug"
-    },
-    "manager.help.debugmode": {
-        "message": "Modalit? debug:"
-    },
-    "manager.help.fixit": {
-        "message": "Puoi contribuire a correggerlo inviando una segnalazione d'errore. Quest'operazione richiede di attivare la modalit? di debug."
-    },
-    "manager.help.foundabug": {
-        "message": "Hai trovato un bug?"
-    },
-    "manager.help.needhelp": {
-        "message": "Serve aiuto?"
-    },
-    "manager.help.viewdebuglog": {
-        "message": "Visualizza log di debug"
-    },
-    "manager.help.wiki": {
-        "message": "Apri le pagine del wiki del progetto TbSync; queste forniscono informazioni aggiuntive, guide e descrizioni dettagliate sulla configurazione."
-    },
-    "manager.installprovider.link": {
-        "message": "Clicca sul collegamento seguente per aprire la pagina informativa del provider di sincronizzazione mancante. In essa sar? possibile trovare ulteriori informazioni sul provider e si avr? la possibilit? di installarlo:"
-    },
-    "manager.installprovider.warning": {
-        "message": "Questo provider di sincronizzazione non ? ospitato nel repository ufficiale componenti aggiuntivi di Thunderbird e quindi non ? stato esaminato dallo staff di Thunderbird. Il provider potrebbe eseguire azioni malevole sul proprio sistema. Lo si utilizzi a proprio rischio."
-    },
-    "manager.lockedsettings.description": {
-        "message": "Per prevenire errori di sincronizzazione, alcune impostazioni non possono essere modificate quando l'account ? abilitato."
-    },
-    "manager.missingprovider": {
-        "message": "Il provider di sincronizzazione a cui ? associato quest'account (##provider##) non ? installato."
-    },
-    "manager.noaccounts": {
-        "message": "Non sono stati definiti ancora account."
-    },
-    "manager.provider": {
-        "message": "Installa provider"
-    },
-    "manager.provider4tbsync": {
-        "message": "Provider per TbSync"
-    },
-    "manager.resource": {
-        "message": "Cartella"
-    },
-    "manager.shorttitle": {
-        "message": "Gestore account"
-    },
-    "manager.status": {
-        "message": "Stato"
-    },
-    "manager.supporter.contributors": {
-        "message": "Collaboratori e traduttori"
-    },
-    "manager.supporter.details": {
-        "message": "Dettagli"
-    },
-    "manager.supporter.sponsors": {
-        "message": "Sponsor per account di test"
-    },
-    "manager.tabs.status": {
-        "message": "Stato sincronizzazione"
-    },
-    "manager.tabs.status.autotime": {
-        "message": "Sincronizza periodicamente ogni (minuti)"
-    },
-    "manager.tabs.status.enableThisAccount": {
-        "message": "Abilita e sincronizza quest'account"
-    },
-    "manager.tabs.status.general": {
-        "message": "Generale"
-    },
-    "manager.tabs.status.never": {
-        "message": "Se l'impostazione ? a 0, la sincronizzazione periodica ? disabilitata. La sincronizzazione push non ? ancora stata implementata."
-    },
-    "manager.tabs.status.resources": {
-        "message": "Risorse disponibili"
-    },
-    "manager.tabs.status.resources.intro": {
-        "message": "Selezionare le risorse fra quelle trovate che devono essere sincronizzate con Thunderbird."
-    },
-    "manager.tabs.status.sync": {
-        "message": "Sincronizza ora"
-    },
-    "manager.tabs.status.tryagain": {
-        "message": "Riprova a collegarti al server"
-    },
-    "manager.title": {
-        "message": "Gestore account TbSync"
-    },
-    "manager.tryagain": {
-        "message": "Riprova a collegarti al server"
-    },
-    "menu.settingslabel": {
-        "message": "Impostazioni sincronizzazione (TbSync)"
-    },
-    "password.account": {
-        "message": "Account:"
-    },
-    "password.description": {
-        "message": "Aggiorna le credenziali per il seguente account TbSync:"
-    },
-    "password.password": {
-        "message": "Password:"
-    },
-    "password.title": {
-        "message": "Richiesta credenziali TbSync"
-    },
-    "password.user": {
-        "message": "Utente:"
-    },
-    "popup.opensettings": {
-        "message": "Apri il Gestore account TbSync"
-    },
-    "prompt.DeleteAccount": {
-        "message": "Eliminare l'account ##accountName##?"
-    },
-    "prompt.Disable": {
-        "message": "Disabilitare quest'account? Tutte le modifiche locali non ancora sincronizzate andranno perse!"
-    },
-    "prompt.Erase": {
-        "message": "Rimuovere quest'account di un provider sconosciuto dall'elenco degli account?"
-    },
-    "prompt.Unsubscribe": {
-        "message": "Annullare la sottoscrizione a questo elemento? Tutte le modifiche locali non ancora sincronizzate andranno perse!"
-    },
-    "status.JavaScriptError": {
-        "message": "Errore Javascript! Si prega di controllare il registro eventi per maggiori dettagli."
-    },
-    "status.OAuthAbortError": {
-        "message": "Processo di autenticazione OAuth 2.0 interrotto dall'utente."
-    },
-    "status.OAuthHttpError": {
-        "message": "Processo di autenticazione OAuth 2.0 non riuscito (errore HTTP ##replace.1##)."
-    },
-    "status.OAuthNetworkError": {
-        "message": "Impossibile connettersi al server di autenticazione OAuth 2.0."
-    },
-    "status.OAuthServerError": {
-        "message": " Il server di autenticazione OAuth 2.0 ha restituito: ##replace.1##"
-    },
-    "status.aborted": {
-        "message": "Non sincronizzato"
-    },
-    "status.apiError": {
-        "message": "Errore di implementazione dell'API"
-    },
-    "status.disabled": {
-        "message": "L'account non ? abilitato, la sincronizzazione ? disabilitata."
-    },
-    "status.foldererror": {
-        "message": "Almeno una risorsa ha riscontrato un errore di sincronizzazione. Si prega di controllare il registro eventi per maggiori dettagli."
-    },
-    "status.modified": {
-        "message": "Modifiche locali presenti"
-    },
-    "status.network": {
-        "message": "Impossibile collegarsi al server (##replace.1##)."
-    },
-    "status.no-folders-found-on-server": {
-        "message": "Impossibile trovare risorse sul server."
-    },
-    "status.notargets": {
-        "message": "Interruzione sincronizzazione in corso: non ? possibile creare le destinazioni sincronizzazione."
-    },
-    "status.notsyncronized": {
-        "message": "L'account deve essere sincronizzato, almeno un elemento non ? sincronizzato."
-    },
-    "status.pending": {
-        "message": "In attesa di sincronizzazione"
-    },
-    "status.security": {
-        "message": "Impossibile stabilire una connessione sicura. Si sta utilizzando un certificato autofirmato o non affidabile senza averlo importato in Thunderbird? (##replace.1##)"
-    },
-    "status.skipped": {
-        "message": "Non ancora supportato, omesso"
-    },
-    "status.success": {
-        "message": "OK"
-    },
-    "status.syncing": {
-        "message": "Sincronizzazione in corso"
-    },
-    "supportwizard.footer": {
-        "message": "Nel prossimo passaggio sar? generato un messaggio di posta elettronica a partire dalle informazioni fornite qui; puoi modificarlo in seguito (ad esempio, aggiungendo schermate o simili). La segnalazione d'errore verr? inviata solo inviando tale messaggio."
-    },
-    "status.451": {
-        "message": "Server issued redirect, retry in 5 seconds."
-    },
-    "supportwizard.label.description": {
-        "message": "Descrizione dettagliata dell'errore:'"
-    },
-    "supportwizard.label.faultycomponent": {
-        "message": "Componente di TbSync dove hai osservato l'errore:"
-    },
-    "supportwizard.label.selectcomponent": {
-        "message": "Seleziona componente..."
-    },
-    "supportwizard.label.summary": {
-        "message": "Breve riassunto dell'errore:'"
-    },
-    "supportwizard.pagetitle": {
-        "message": "Raccolta di tutte le informazioni necessarie per gestire efficacemente la segnalazione d'errore."
-    },
-    "supportwizard.provider": {
-        "message": "Provider: ##replace.1##"
-    },
-    "supportwizard.title": {
-        "message": "Crea segnalazione d'errore"
-    },
-    "syncstate.accountdone": {
-        "message": "Sincronizzazione account completata"
-    },
-    "syncstate.done": {
-        "message": "Preparazione prossimo elemento per la sincronizzazione in corso"
-    },
-    "syncstate.oauthprompt": {
-        "message": "Autenticazione OAuth 2.0"
-    },
-    "syncstate.passwordprompt": {
-        "message": "Richiesta di inserire le credenziali"
-    },
-    "syncstate.preparing": {
-        "message": "Preparazione prossimo elemento per la sincronizzazione in corso"
-    },
-    "syncstate.syncing": {
-        "message": "Inizializzazione sincronizzazione in corso"
-    },
-    "target.orphaned": {
-        "message": "Connessione disconnessa"
-    },
-    "toolbar.label": {
-        "message": "Sincronizza tutti gli account TbSync"
-    },
-    "toolbar.tooltiptext": {
-        "message": "Sincronizza le ultime modifiche"
-    },
-    "password.ok": {
-        "message": "OK"
-    },
-    "password.cancel": {
-        "message": "Annulla"
-    }
-}
+{
+    "HelpFixStartupError": {
+        "message": "Per contribuire a correggere quest'errore potresti inviare un log di debug allo sviluppatore di TbSync. Preparare tale messaggio di posta elettronica ora?"
+    },
+    "NoDebugLog": {
+        "message": "Non ? stato possibile trovare alcun messaggio di debug utile. Attiva la modalit? di debug, riavvia Thunderbird e ripeti tutti i passaggi richiesti per scatenare il comportamento errato."
+    },
+    "OopsMessage": {
+        "message": "Oops! TbSync non ? stato in grado di avviarsi!"
+    },
+    "RestartThunderbirdAndTryAgain": {
+        "message": "Il log di debug di TbSync ? stato abilitato, riavviare Thunderbird e riprovare ad aprire TbSync."
+    },
+    "UnableToTraceError": {
+        "message": "Non ? possibile localizzare quest'errore perch? i log di debug non sono attualmente abilitati. Abilitare ora il log di debug per contribuire a correggere quest'errore?"
+    },
+    "accountacctions.delete": {
+        "message": "Elimina l'account '##accountname##'"
+    },
+    "accountacctions.disable": {
+        "message": "Disabilita l'account '##accountname##'"
+    },
+    "accountacctions.enable": {
+        "message": "Abilita l'account '##accountname##' e tenta la connessione al server"
+    },
+    "accountacctions.sync": {
+        "message": "Sincronizza l'account '##accountname##'"
+    },
+    "addressbook.searchall": {
+        "message": "Cerca in tutte le rubriche"
+    },
+    "addressbook.searchgal": {
+        "message": "Cerca in questa rubrica e nella directory globale (##replace.1##)"
+    },
+    "addressbook.searchthis": {
+        "message": "Cerca in questa rubrica"
+    },
+    "eventlog.clear": {
+        "message": "Svuota"
+    },
+    "eventlog.close": {
+        "message": "Chiudi"
+    },
+    "eventlog.title": {
+        "message": "Registro eventi"
+    },
+    "extensionDescription": {
+        "message": "TbSync ? un'interfaccia utente che consente di gestire in modo centralizzato account cloud e di sincronizzare i loro contatti, attivit? e calendari con Thunderbird."
+    },
+    "google.translate.code": {
+        "message": "it"
+    },
+    "helplink.security": {
+        "message": "https://github.com/jobisoft/TbSync/wiki/How-to-use-TbSync-with-self-signed-or-otherwise-untrusted-certificates%3F"
+    },
+    "info.error": {
+        "message": "Errore"
+    },
+    "info.idle": {
+        "message": "Inattivo"
+    },
+    "installProvider.header": {
+        "message": "Il provider '##replace.1##' per TbSync non ? ancora installato."
+    },
+    "manager.AccountActions": {
+        "message": "Azioni account"
+    },
+    "manager.AddAccount": {
+        "message": "Aggiungi nuovo account"
+    },
+    "manager.DeleteAccount": {
+        "message": "Elimina account"
+    },
+    "manager.DisableAccount": {
+        "message": "Disabilita account"
+    },
+    "manager.EnableAccount": {
+        "message": "Abilita account e testa la connessione al server"
+    },
+    "manager.RetryConnectAccount": {
+        "message": "Riprova a collegarti al server"
+    },
+    "manager.ShowEventLog": {
+        "message": "Mostra registro eventi"
+    },
+    "manager.SyncAll": {
+        "message": "Sincronizza tutti gli account abilitati"
+    },
+    "manager.SynchronizeAccount": {
+        "message": "Sincronizza account"
+    },
+    "manager.accounts": {
+        "message": "Account"
+    },
+    "manager.accountsettings": {
+        "message": "Impostazioni account"
+    },
+    "manager.catman.text": {
+        "message": "TbSync sincronizza anche le categorie dei contatti, che sono un potente sostituto degli elenchi contatti (non sincronizzabili). Per poterle utilizzare nella Rubrica di Thunderbird ? possibile installare il componente aggiuntivo Category Manager, che consente di gestire gruppi di contatti basati su categorie (anche sovrapposte) e che fornisce altre funzionalit? legate alle categorie. Lo si pu? trovare nel repository ufficiale Mozilla dei componenti aggiuntivi:"
+    },
+    "manager.community": {
+        "message": "Comunit?"
+    },
+    "manager.connecting": {
+        "message": "Connessione al server in corso"
+    },
+    "manager.help": {
+        "message": "Aiuto"
+    },
+    "manager.help.createbugreport": {
+        "message": "Crea segnalazione d'errore"
+    },
+    "manager.help.createbugreportinfo": {
+        "message": "Per far s? che TbSync raccolga solo i messaggi di debug significativi per la segnalazione d'errore, riavvia Thunderbird e ripeti esattamente i passaggi necessari per riprodurre il comportamento errato. In seguito puoi creare qui la segnalazione d'errore."
+    },
+    "manager.help.debuglevel.0": {
+        "message": "Disabilitata"
+    },
+    "manager.help.debuglevel.1": {
+        "message": "Abilitata: registra solo gli errori"
+    },
+    "manager.help.debuglevel.2": {
+        "message": "Abilitata: registra tutti i dati inviati e ricevuti"
+    },
+    "manager.help.debuglevel.3": {
+        "message": "Abilitata: registra tutti i dati e alcuni valori interni di debug"
+    },
+    "manager.help.debugmode": {
+        "message": "Modalit? debug:"
+    },
+    "manager.help.fixit": {
+        "message": "Puoi contribuire a correggerlo inviando una segnalazione d'errore. Quest'operazione richiede di attivare la modalit? di debug."
+    },
+    "manager.help.foundabug": {
+        "message": "Hai trovato un bug?"
+    },
+    "manager.help.needhelp": {
+        "message": "Serve aiuto?"
+    },
+    "manager.help.viewdebuglog": {
+        "message": "Visualizza log di debug"
+    },
+    "manager.help.wiki": {
+        "message": "Apri le pagine del wiki del progetto TbSync; queste forniscono informazioni aggiuntive, guide e descrizioni dettagliate sulla configurazione."
+    },
+    "manager.installprovider.link": {
+        "message": "Clicca sul collegamento seguente per aprire la pagina informativa del provider di sincronizzazione mancante. In essa sar? possibile trovare ulteriori informazioni sul provider e si avr? la possibilit? di installarlo:"
+    },
+    "manager.installprovider.warning": {
+        "message": "Questo provider di sincronizzazione non ? ospitato nel repository ufficiale componenti aggiuntivi di Thunderbird e quindi non ? stato esaminato dallo staff di Thunderbird. Il provider potrebbe eseguire azioni malevole sul proprio sistema. Lo si utilizzi a proprio rischio."
+    },
+    "manager.lockedsettings.description": {
+        "message": "Per prevenire errori di sincronizzazione, alcune impostazioni non possono essere modificate quando l'account ? abilitato."
+    },
+    "manager.missingprovider": {
+        "message": "Il provider di sincronizzazione a cui ? associato quest'account (##provider##) non ? installato."
+    },
+    "manager.noaccounts": {
+        "message": "Non sono stati definiti ancora account."
+    },
+    "manager.provider": {
+        "message": "Installa provider"
+    },
+    "manager.provider4tbsync": {
+        "message": "Provider per TbSync"
+    },
+    "manager.resource": {
+        "message": "Cartella"
+    },
+    "manager.shorttitle": {
+        "message": "Gestore account"
+    },
+    "manager.status": {
+        "message": "Stato"
+    },
+    "manager.supporter.contributors": {
+        "message": "Collaboratori e traduttori"
+    },
+    "manager.supporter.details": {
+        "message": "Dettagli"
+    },
+    "manager.supporter.sponsors": {
+        "message": "Sponsor per account di test"
+    },
+    "manager.tabs.status": {
+        "message": "Stato sincronizzazione"
+    },
+    "manager.tabs.status.autotime": {
+        "message": "Sincronizza periodicamente ogni (minuti)"
+    },
+    "manager.tabs.status.enableThisAccount": {
+        "message": "Abilita e sincronizza quest'account"
+    },
+    "manager.tabs.status.general": {
+        "message": "Generale"
+    },
+    "manager.tabs.status.never": {
+        "message": "Se l'impostazione ? a 0, la sincronizzazione periodica ? disabilitata. La sincronizzazione push non ? ancora stata implementata."
+    },
+    "manager.tabs.status.resources": {
+        "message": "Risorse disponibili"
+    },
+    "manager.tabs.status.resources.intro": {
+        "message": "Selezionare le risorse fra quelle trovate che devono essere sincronizzate con Thunderbird."
+    },
+    "manager.tabs.status.sync": {
+        "message": "Sincronizza ora"
+    },
+    "manager.tabs.status.tryagain": {
+        "message": "Riprova a collegarti al server"
+    },
+    "manager.title": {
+        "message": "Gestore account TbSync"
+    },
+    "manager.tryagain": {
+        "message": "Riprova a collegarti al server"
+    },
+    "menu.settingslabel": {
+        "message": "Impostazioni sincronizzazione (TbSync)"
+    },
+    "password.account": {
+        "message": "Account:"
+    },
+    "password.description": {
+        "message": "Aggiorna le credenziali per il seguente account TbSync:"
+    },
+    "password.password": {
+        "message": "Password:"
+    },
+    "password.title": {
+        "message": "Richiesta credenziali TbSync"
+    },
+    "password.user": {
+        "message": "Utente:"
+    },
+    "popup.opensettings": {
+        "message": "Apri il Gestore account TbSync"
+    },
+    "prompt.DeleteAccount": {
+        "message": "Eliminare l'account ##accountName##?"
+    },
+    "prompt.Disable": {
+        "message": "Disabilitare quest'account? Tutte le modifiche locali non ancora sincronizzate andranno perse!"
+    },
+    "prompt.Erase": {
+        "message": "Rimuovere quest'account di un provider sconosciuto dall'elenco degli account?"
+    },
+    "prompt.Unsubscribe": {
+        "message": "Annullare la sottoscrizione a questo elemento? Tutte le modifiche locali non ancora sincronizzate andranno perse!"
+    },
+    "status.JavaScriptError": {
+        "message": "Errore Javascript! Si prega di controllare il registro eventi per maggiori dettagli."
+    },
+    "status.OAuthAbortError": {
+        "message": "Processo di autenticazione OAuth 2.0 interrotto dall'utente."
+    },
+    "status.OAuthHttpError": {
+        "message": "Processo di autenticazione OAuth 2.0 non riuscito (errore HTTP ##replace.1##)."
+    },
+    "status.OAuthNetworkError": {
+        "message": "Impossibile connettersi al server di autenticazione OAuth 2.0."
+    },
+    "status.OAuthServerError": {
+        "message": " Il server di autenticazione OAuth 2.0 ha restituito: ##replace.1##"
+    },
+    "status.aborted": {
+        "message": "Non sincronizzato"
+    },
+    "status.apiError": {
+        "message": "Errore di implementazione dell'API"
+    },
+    "status.disabled": {
+        "message": "L'account non ? abilitato, la sincronizzazione ? disabilitata."
+    },
+    "status.foldererror": {
+        "message": "Almeno una risorsa ha riscontrato un errore di sincronizzazione. Si prega di controllare il registro eventi per maggiori dettagli."
+    },
+    "status.modified": {
+        "message": "Modifiche locali presenti"
+    },
+    "status.network": {
+        "message": "Impossibile collegarsi al server (##replace.1##)."
+    },
+    "status.no-folders-found-on-server": {
+        "message": "Impossibile trovare risorse sul server."
+    },
+    "status.notargets": {
+        "message": "Interruzione sincronizzazione in corso: non ? possibile creare le destinazioni sincronizzazione."
+    },
+    "status.notsyncronized": {
+        "message": "L'account deve essere sincronizzato, almeno un elemento non ? sincronizzato."
+    },
+    "status.pending": {
+        "message": "In attesa di sincronizzazione"
+    },
+    "status.security": {
+        "message": "Impossibile stabilire una connessione sicura. Si sta utilizzando un certificato autofirmato o non affidabile senza averlo importato in Thunderbird? (##replace.1##)"
+    },
+    "status.skipped": {
+        "message": "Non ancora supportato, omesso"
+    },
+    "status.success": {
+        "message": "OK"
+    },
+    "status.syncing": {
+        "message": "Sincronizzazione in corso"
+    },
+    "supportwizard.footer": {
+        "message": "Nel prossimo passaggio sar? generato un messaggio di posta elettronica a partire dalle informazioni fornite qui; puoi modificarlo in seguito (ad esempio, aggiungendo schermate o simili). La segnalazione d'errore verr? inviata solo inviando tale messaggio."
+    },
+    "status.451": {
+        "message": "Server issued redirect, retry in 5 seconds."
+    },
+    "supportwizard.label.description": {
+        "message": "Descrizione dettagliata dell'errore:'"
+    },
+    "supportwizard.label.faultycomponent": {
+        "message": "Componente di TbSync dove hai osservato l'errore:"
+    },
+    "supportwizard.label.selectcomponent": {
+        "message": "Seleziona componente..."
+    },
+    "supportwizard.label.summary": {
+        "message": "Breve riassunto dell'errore:'"
+    },
+    "supportwizard.pagetitle": {
+        "message": "Raccolta di tutte le informazioni necessarie per gestire efficacemente la segnalazione d'errore."
+    },
+    "supportwizard.provider": {
+        "message": "Provider: ##replace.1##"
+    },
+    "supportwizard.title": {
+        "message": "Crea segnalazione d'errore"
+    },
+    "syncstate.accountdone": {
+        "message": "Sincronizzazione account completata"
+    },
+    "syncstate.done": {
+        "message": "Preparazione prossimo elemento per la sincronizzazione in corso"
+    },
+    "syncstate.oauthprompt": {
+        "message": "Autenticazione OAuth 2.0"
+    },
+    "syncstate.passwordprompt": {
+        "message": "Richiesta di inserire le credenziali"
+    },
+    "syncstate.preparing": {
+        "message": "Preparazione prossimo elemento per la sincronizzazione in corso"
+    },
+    "syncstate.syncing": {
+        "message": "Inizializzazione sincronizzazione in corso"
+    },
+    "target.orphaned": {
+        "message": "Connessione disconnessa"
+    },
+    "toolbar.label": {
+        "message": "Sincronizza tutti gli account TbSync"
+    },
+    "toolbar.tooltiptext": {
+        "message": "Sincronizza le ultime modifiche"
+    },
+    "password.ok": {
+        "message": "OK"
+    },
+    "password.cancel": {
+        "message": "Annulla"
+    }
+}
diff -Nru tbsync-4.12/_locales/ja/messages.json tbsync-4.16/_locales/ja/messages.json
--- tbsync-4.12/_locales/ja/messages.json	2024-08-27 18:32:08.000000000 +0200
+++ tbsync-4.16/_locales/ja/messages.json	2024-08-27 18:29:06.000000000 +0200
@@ -1,368 +1,368 @@
-{
-    "HelpFixStartupError": {
-        "message": "?????????????? TbSync ???????????????????????????????????"
-    },
-    "NoDebugLog": {
-        "message": "?????????????????????????????????????????? Thunderbird ??????????????????????????????????????"
-    },
-    "OopsMessage": {
-        "message": "????? TbSync ????????????"
-    },
-    "RestartThunderbirdAndTryAgain": {
-        "message": "TbSync ?????????????????Thunderbird ?????????? TbSync ???????????"
-    },
-    "UnableToTraceError": {
-        "message": "????????????????????????????????????? ????????????????????????????????"
-    },
-    "accountacctions.delete": {
-        "message": "????? ?##accountname##? ???"
-    },
-    "accountacctions.disable": {
-        "message": "????? ?##accountname##? ????"
-    },
-    "accountacctions.enable": {
-        "message": "????? ?##accountname##? ??????????????????"
-    },
-    "accountacctions.sync": {
-        "message": "????? ?##accountname##? ???"
-    },
-    "addressbook.searchall": {
-        "message": "???????????"
-    },
-    "addressbook.searchgal": {
-        "message": "????????????????????????? (##replace.1##)"
-    },
-    "addressbook.searchthis": {
-        "message": "??????????"
-    },
-    "eventlog.clear": {
-        "message": "???"
-    },
-    "eventlog.close": {
-        "message": "???"
-    },
-    "eventlog.title": {
-        "message": "??????"
-    },
-    "extensionDescription": {
-        "message": "TbSync ? Thunderbird ????????????????????????????????????????????????????????????????"
-    },
-    "google.translate.code": {
-        "message": "ja"
-    },
-    "helplink.security": {
-        "message": "https://github.com/jobisoft/TbSync/wiki/How-to-use-TbSync-with-self-signed-or-otherwise-untrusted-certificates%3F"
-    },
-    "info.error": {
-        "message": "???"
-    },
-    "info.idle": {
-        "message": "???"
-    },
-    "installProvider.header": {
-        "message": "TbSync ?????? ?##replace.1##? ??????????????????"
-    },
-    "manager.AccountActions": {
-        "message": "???????"
-    },
-    "manager.AddAccount": {
-        "message": "??????????"
-    },
-    "manager.DeleteAccount": {
-        "message": "????????"
-    },
-    "manager.DisableAccount": {
-        "message": "?????????"
-    },
-    "manager.EnableAccount": {
-        "message": "???????????????????????"
-    },
-    "manager.RetryConnectAccount": {
-        "message": "????????????"
-    },
-    "manager.ShowEventLog": {
-        "message": "?????????"
-    },
-    "manager.SyncAll": {
-        "message": "???????????????????"
-    },
-    "manager.SynchronizeAccount": {
-        "message": "????????"
-    },
-    "manager.accounts": {
-        "message": "?????"
-    },
-    "manager.accountsettings": {
-        "message": "???????"
-    },
-    "manager.catman.text": {
-        "message": "TbSync ???????????????????????????????????? Thunderbird ????????????????????????Category Manager ????????????????????? ?????????????????????????????????????????????????  Mozilla ?????????????????:"
-    },
-    "manager.community": {
-        "message": "??????"
-    },
-    "manager.connecting": {
-        "message": "????????"
-    },
-    "manager.help": {
-        "message": "???"
-    },
-    "manager.help.createbugreport": {
-        "message": "?????????"
-    },
-    "manager.help.createbugreportinfo": {
-        "message": "TbSync ???????????????????????????????Thunderbird ?????????????????????????????????????????????????????????????????"
-    },
-    "manager.help.debuglevel.0": {
-        "message": "??"
-    },
-    "manager.help.debuglevel.1": {
-        "message": "??: ???????"
-    },
-    "manager.help.debuglevel.2": {
-        "message": "??: ???????????"
-    },
-    "manager.help.debuglevel.3": {
-        "message": "??: ??????????????????????"
-    },
-    "manager.help.debugmode": {
-        "message": "???? ???:"
-    },
-    "manager.help.fixit": {
-        "message": "???????????????????????????????????????????????????????"
-    },
-    "manager.help.foundabug": {
-        "message": "??????????"
-    },
-    "manager.help.needhelp": {
-        "message": "???????"
-    },
-    "manager.help.viewdebuglog": {
-        "message": "???? ?????"
-    },
-    "manager.help.wiki": {
-        "message": "TbSync ??????? Wiki ??????????????????????????????????????????????"
-    },
-    "manager.installprovider.link": {
-        "message": "????????????????????????????????????????????????????????????????????????????????????"
-    },
-    "manager.installprovider.warning": {
-        "message": "?????????????? Thunderbird ??????????????????????? Thunderbird ?????????????????? ?????????????????????????????????????????"
-    },
-    "manager.lockedsettings.description": {
-        "message": "??????????????????????????????????????????????"
-    },
-    "manager.missingprovider": {
-        "message": "????????? ##provider## ????????????????????????????????"
-    },
-    "manager.noaccounts": {
-        "message": "??????????????????"
-    },
-    "manager.provider": {
-        "message": "????????????"
-    },
-    "manager.provider4tbsync": {
-        "message": "TbSync ??????"
-    },
-    "manager.resource": {
-        "message": "????"
-    },
-    "manager.shorttitle": {
-        "message": "???????????"
-    },
-    "manager.status": {
-        "message": "??"
-    },
-    "manager.supporter.contributors": {
-        "message": "???????"
-    },
-    "manager.supporter.details": {
-        "message": "??"
-    },
-    "manager.supporter.sponsors": {
-        "message": "??????????????"
-    },
-    "manager.tabs.status": {
-        "message": "????"
-    },
-    "manager.tabs.status.autotime": {
-        "message": "???????? (?)"
-    },
-    "manager.tabs.status.enableThisAccount": {
-        "message": "??????????????"
-    },
-    "manager.tabs.status.general": {
-        "message": "????"
-    },
-    "manager.tabs.status.never": {
-        "message": "0???????????????????????????????????????"
-    },
-    "manager.tabs.status.resources": {
-        "message": "?????????"
-    },
-    "manager.tabs.status.resources.intro": {
-        "message": "Thunderbird ?????????????????"
-    },
-    "manager.tabs.status.sync": {
-        "message": "?????"
-    },
-    "manager.tabs.status.tryagain": {
-        "message": "????????????"
-    },
-    "manager.title": {
-        "message": "TbSync ???????????"
-    },
-    "manager.tryagain": {
-        "message": "????????????"
-    },
-    "menu.settingslabel": {
-        "message": "???? (TbSync)"
-    },
-    "password.account": {
-        "message": "?????:"
-    },
-    "password.description": {
-        "message": "?? TbSync ???????????????????:"
-    },
-    "password.password": {
-        "message": "?????:"
-    },
-    "password.title": {
-        "message": "TbSync ?????????"
-    },
-    "password.user": {
-        "message": "????:"
-    },
-    "popup.opensettings": {
-        "message": "TbSync ??????????????"
-    },
-    "prompt.DeleteAccount": {
-        "message": "????? ##accountName## ????????"
-    },
-    "prompt.Disable": {
-        "message": "???????????????? ????????????????????????!"
-    },
-    "prompt.Erase": {
-        "message": "??????????????????????????????????????"
-    },
-    "prompt.Unsubscribe": {
-        "message": "??????????????? ????????????????????????!"
-    },
-    "status.JavaScriptError": {
-        "message": "Javascript ???! ???????????????????"
-    },
-    "status.OAuthAbortError": {
-        "message": "OAuth 2.0 ??????????????????????????"
-    },
-    "status.OAuthHttpError": {
-        "message": "OAuth 2.0 ????????????? (HTTP ??? ##replace.1##) ?"
-    },
-    "status.OAuthNetworkError": {
-        "message": "OAuth 2.0 ???????????????"
-    },
-    "status.OAuthServerError": {
-        "message": " OAuth 2.0 ?????????????: ##replace.1##"
-    },
-    "status.aborted": {
-        "message": "?????????"
-    },
-    "status.apiError": {
-        "message": "API ?????"
-    },
-    "status.disabled": {
-        "message": "?????????????????????????????"
-    },
-    "status.foldererror": {
-        "message": "????????????????????????????????????????"
-    },
-    "status.modified": {
-        "message": "???????"
-    },
-    "status.network": {
-        "message": "???????????? (##replace.1##)?"
-    },
-    "status.no-folders-found-on-server": {
-        "message": "??????????????????????"
-    },
-    "status.notargets": {
-        "message": "????????????????????????????"
-    },
-    "status.notsyncronized": {
-        "message": "??????????????????????????????????????"
-    },
-    "status.pending": {
-        "message": "????"
-    },
-    "status.security": {
-        "message": "????????????????????????????????????Thunderbird??????????????????(##replace.1##)"
-    },
-    "status.skipped": {
-        "message": "????????????????????"
-    },
-    "status.success": {
-        "message": "OK"
-    },
-    "status.syncing": {
-        "message": "???"
-    },
-    "status.451": {
-        "message": "Server issued redirect, retry in 5 seconds."
-    },
-    "supportwizard.footer": {
-        "message": "??????????????????????????????????????????????? (???????????????????????????)? ?????????????????????????????????????"
-    },
-    "supportwizard.label.description": {
-        "message": "?????????:"
-    },
-    "supportwizard.label.faultycomponent": {
-        "message": "????????TbSync????????:"
-    },
-    "supportwizard.label.selectcomponent": {
-        "message": "???????????"
-    },
-    "supportwizard.label.summary": {
-        "message": "??????:"
-    },
-    "supportwizard.pagetitle": {
-        "message": "????????????????????????????????"
-    },
-    "supportwizard.provider": {
-        "message": "?????: ##replace.1##"
-    },
-    "supportwizard.title": {
-        "message": "?????????"
-    },
-    "syncstate.accountdone": {
-        "message": "?????????"
-    },
-    "syncstate.done": {
-        "message": "????????????????"
-    },
-    "syncstate.oauthprompt": {
-        "message": "OAuth 2.0 ??"
-    },
-    "syncstate.passwordprompt": {
-        "message": "????????????"
-    },
-    "syncstate.preparing": {
-        "message": "????????????????"
-    },
-    "syncstate.syncing": {
-        "message": "??????"
-    },
-    "target.orphaned": {
-        "message": "???????"
-    },
-    "toolbar.label": {
-        "message": "??? TbSync ????????"
-    },
-    "toolbar.tooltiptext": {
-        "message": "????????"
-    },
-    "password.ok": {
-        "message": "OK"
-    },
-    "password.cancel": {
-        "message": "?????"
-    }
-}
+{
+    "HelpFixStartupError": {
+        "message": "?????????????? TbSync ???????????????????????????????????"
+    },
+    "NoDebugLog": {
+        "message": "?????????????????????????????????????????? Thunderbird ??????????????????????????????????????"
+    },
+    "OopsMessage": {
+        "message": "????? TbSync ????????????"
+    },
+    "RestartThunderbirdAndTryAgain": {
+        "message": "TbSync ?????????????????Thunderbird ?????????? TbSync ???????????"
+    },
+    "UnableToTraceError": {
+        "message": "????????????????????????????????????? ????????????????????????????????"
+    },
+    "accountacctions.delete": {
+        "message": "????? ?##accountname##? ???"
+    },
+    "accountacctions.disable": {
+        "message": "????? ?##accountname##? ????"
+    },
+    "accountacctions.enable": {
+        "message": "????? ?##accountname##? ??????????????????"
+    },
+    "accountacctions.sync": {
+        "message": "????? ?##accountname##? ???"
+    },
+    "addressbook.searchall": {
+        "message": "???????????"
+    },
+    "addressbook.searchgal": {
+        "message": "????????????????????????? (##replace.1##)"
+    },
+    "addressbook.searchthis": {
+        "message": "??????????"
+    },
+    "eventlog.clear": {
+        "message": "???"
+    },
+    "eventlog.close": {
+        "message": "???"
+    },
+    "eventlog.title": {
+        "message": "??????"
+    },
+    "extensionDescription": {
+        "message": "TbSync ? Thunderbird ????????????????????????????????????????????????????????????????"
+    },
+    "google.translate.code": {
+        "message": "ja"
+    },
+    "helplink.security": {
+        "message": "https://github.com/jobisoft/TbSync/wiki/How-to-use-TbSync-with-self-signed-or-otherwise-untrusted-certificates%3F"
+    },
+    "info.error": {
+        "message": "???"
+    },
+    "info.idle": {
+        "message": "???"
+    },
+    "installProvider.header": {
+        "message": "TbSync ?????? ?##replace.1##? ??????????????????"
+    },
+    "manager.AccountActions": {
+        "message": "???????"
+    },
+    "manager.AddAccount": {
+        "message": "??????????"
+    },
+    "manager.DeleteAccount": {
+        "message": "????????"
+    },
+    "manager.DisableAccount": {
+        "message": "?????????"
+    },
+    "manager.EnableAccount": {
+        "message": "???????????????????????"
+    },
+    "manager.RetryConnectAccount": {
+        "message": "????????????"
+    },
+    "manager.ShowEventLog": {
+        "message": "?????????"
+    },
+    "manager.SyncAll": {
+        "message": "???????????????????"
+    },
+    "manager.SynchronizeAccount": {
+        "message": "????????"
+    },
+    "manager.accounts": {
+        "message": "?????"
+    },
+    "manager.accountsettings": {
+        "message": "???????"
+    },
+    "manager.catman.text": {
+        "message": "TbSync ???????????????????????????????????? Thunderbird ????????????????????????Category Manager ????????????????????? ?????????????????????????????????????????????????  Mozilla ?????????????????:"
+    },
+    "manager.community": {
+        "message": "??????"
+    },
+    "manager.connecting": {
+        "message": "????????"
+    },
+    "manager.help": {
+        "message": "???"
+    },
+    "manager.help.createbugreport": {
+        "message": "?????????"
+    },
+    "manager.help.createbugreportinfo": {
+        "message": "TbSync ???????????????????????????????Thunderbird ?????????????????????????????????????????????????????????????????"
+    },
+    "manager.help.debuglevel.0": {
+        "message": "??"
+    },
+    "manager.help.debuglevel.1": {
+        "message": "??: ???????"
+    },
+    "manager.help.debuglevel.2": {
+        "message": "??: ???????????"
+    },
+    "manager.help.debuglevel.3": {
+        "message": "??: ??????????????????????"
+    },
+    "manager.help.debugmode": {
+        "message": "???? ???:"
+    },
+    "manager.help.fixit": {
+        "message": "???????????????????????????????????????????????????????"
+    },
+    "manager.help.foundabug": {
+        "message": "??????????"
+    },
+    "manager.help.needhelp": {
+        "message": "???????"
+    },
+    "manager.help.viewdebuglog": {
+        "message": "???? ?????"
+    },
+    "manager.help.wiki": {
+        "message": "TbSync ??????? Wiki ??????????????????????????????????????????????"
+    },
+    "manager.installprovider.link": {
+        "message": "????????????????????????????????????????????????????????????????????????????????????"
+    },
+    "manager.installprovider.warning": {
+        "message": "?????????????? Thunderbird ??????????????????????? Thunderbird ?????????????????? ?????????????????????????????????????????"
+    },
+    "manager.lockedsettings.description": {
+        "message": "??????????????????????????????????????????????"
+    },
+    "manager.missingprovider": {
+        "message": "????????? ##provider## ????????????????????????????????"
+    },
+    "manager.noaccounts": {
+        "message": "??????????????????"
+    },
+    "manager.provider": {
+        "message": "????????????"
+    },
+    "manager.provider4tbsync": {
+        "message": "TbSync ??????"
+    },
+    "manager.resource": {
+        "message": "????"
+    },
+    "manager.shorttitle": {
+        "message": "???????????"
+    },
+    "manager.status": {
+        "message": "??"
+    },
+    "manager.supporter.contributors": {
+        "message": "???????"
+    },
+    "manager.supporter.details": {
+        "message": "??"
+    },
+    "manager.supporter.sponsors": {
+        "message": "??????????????"
+    },
+    "manager.tabs.status": {
+        "message": "????"
+    },
+    "manager.tabs.status.autotime": {
+        "message": "???????? (?)"
+    },
+    "manager.tabs.status.enableThisAccount": {
+        "message": "??????????????"
+    },
+    "manager.tabs.status.general": {
+        "message": "????"
+    },
+    "manager.tabs.status.never": {
+        "message": "0???????????????????????????????????????"
+    },
+    "manager.tabs.status.resources": {
+        "message": "?????????"
+    },
+    "manager.tabs.status.resources.intro": {
+        "message": "Thunderbird ?????????????????"
+    },
+    "manager.tabs.status.sync": {
+        "message": "?????"
+    },
+    "manager.tabs.status.tryagain": {
+        "message": "????????????"
+    },
+    "manager.title": {
+        "message": "TbSync ???????????"
+    },
+    "manager.tryagain": {
+        "message": "????????????"
+    },
+    "menu.settingslabel": {
+        "message": "???? (TbSync)"
+    },
+    "password.account": {
+        "message": "?????:"
+    },
+    "password.description": {
+        "message": "?? TbSync ???????????????????:"
+    },
+    "password.password": {
+        "message": "?????:"
+    },
+    "password.title": {
+        "message": "TbSync ?????????"
+    },
+    "password.user": {
+        "message": "????:"
+    },
+    "popup.opensettings": {
+        "message": "TbSync ??????????????"
+    },
+    "prompt.DeleteAccount": {
+        "message": "????? ##accountName## ????????"
+    },
+    "prompt.Disable": {
+        "message": "???????????????? ????????????????????????!"
+    },
+    "prompt.Erase": {
+        "message": "??????????????????????????????????????"
+    },
+    "prompt.Unsubscribe": {
+        "message": "??????????????? ????????????????????????!"
+    },
+    "status.JavaScriptError": {
+        "message": "Javascript ???! ???????????????????"
+    },
+    "status.OAuthAbortError": {
+        "message": "OAuth 2.0 ??????????????????????????"
+    },
+    "status.OAuthHttpError": {
+        "message": "OAuth 2.0 ????????????? (HTTP ??? ##replace.1##) ?"
+    },
+    "status.OAuthNetworkError": {
+        "message": "OAuth 2.0 ???????????????"
+    },
+    "status.OAuthServerError": {
+        "message": " OAuth 2.0 ?????????????: ##replace.1##"
+    },
+    "status.aborted": {
+        "message": "?????????"
+    },
+    "status.apiError": {
+        "message": "API ?????"
+    },
+    "status.disabled": {
+        "message": "?????????????????????????????"
+    },
+    "status.foldererror": {
+        "message": "????????????????????????????????????????"
+    },
+    "status.modified": {
+        "message": "???????"
+    },
+    "status.network": {
+        "message": "???????????? (##replace.1##)?"
+    },
+    "status.no-folders-found-on-server": {
+        "message": "??????????????????????"
+    },
+    "status.notargets": {
+        "message": "????????????????????????????"
+    },
+    "status.notsyncronized": {
+        "message": "??????????????????????????????????????"
+    },
+    "status.pending": {
+        "message": "????"
+    },
+    "status.security": {
+        "message": "????????????????????????????????????Thunderbird??????????????????(##replace.1##)"
+    },
+    "status.skipped": {
+        "message": "????????????????????"
+    },
+    "status.success": {
+        "message": "OK"
+    },
+    "status.syncing": {
+        "message": "???"
+    },
+    "status.451": {
+        "message": "Server issued redirect, retry in 5 seconds."
+    },
+    "supportwizard.footer": {
+        "message": "??????????????????????????????????????????????? (???????????????????????????)? ?????????????????????????????????????"
+    },
+    "supportwizard.label.description": {
+        "message": "?????????:"
+    },
+    "supportwizard.label.faultycomponent": {
+        "message": "????????TbSync????????:"
+    },
+    "supportwizard.label.selectcomponent": {
+        "message": "???????????"
+    },
+    "supportwizard.label.summary": {
+        "message": "??????:"
+    },
+    "supportwizard.pagetitle": {
+        "message": "????????????????????????????????"
+    },
+    "supportwizard.provider": {
+        "message": "?????: ##replace.1##"
+    },
+    "supportwizard.title": {
+        "message": "?????????"
+    },
+    "syncstate.accountdone": {
+        "message": "?????????"
+    },
+    "syncstate.done": {
+        "message": "????????????????"
+    },
+    "syncstate.oauthprompt": {
+        "message": "OAuth 2.0 ??"
+    },
+    "syncstate.passwordprompt": {
+        "message": "????????????"
+    },
+    "syncstate.preparing": {
+        "message": "????????????????"
+    },
+    "syncstate.syncing": {
+        "message": "??????"
+    },
+    "target.orphaned": {
+        "message": "???????"
+    },
+    "toolbar.label": {
+        "message": "??? TbSync ????????"
+    },
+    "toolbar.tooltiptext": {
+        "message": "????????"
+    },
+    "password.ok": {
+        "message": "OK"
+    },
+    "password.cancel": {
+        "message": "?????"
+    }
+}
diff -Nru tbsync-4.12/_locales/ko/messages.json tbsync-4.16/_locales/ko/messages.json
--- tbsync-4.12/_locales/ko/messages.json	2024-08-27 18:32:08.000000000 +0200
+++ tbsync-4.16/_locales/ko/messages.json	2024-08-27 18:29:06.000000000 +0200
@@ -1,368 +1,368 @@
-{
-    "HelpFixStartupError": {
-        "message": "To help fix this error, you could send a debug log to the TbSync developer. Prepare that email now?"
-    },
-    "NoDebugLog": {
-        "message": "Could not find any useful debug messages. Please activate debug mode, restart Thunderbird and repeat all the steps needed to trigger the erroneous behavior."
-    },
-    "OopsMessage": {
-        "message": "Oops! TbSync was not able to start!"
-    },
-    "RestartThunderbirdAndTryAgain": {
-        "message": "TbSync debug log has been enabled, please restart Thunderbird and again try to open TbSync."
-    },
-    "UnableToTraceError": {
-        "message": "It is not possible to trace this error, because debug log is currently not enabled. Do you want to enable debug log now, to help fix this error?"
-    },
-    "accountacctions.delete": {
-        "message": "Delete account ?##accountname##?"
-    },
-    "accountacctions.disable": {
-        "message": "Disable account ?##accountname##?"
-    },
-    "accountacctions.enable": {
-        "message": "Enable account ?##accountname##? & try to connect to server"
-    },
-    "accountacctions.sync": {
-        "message": "Synchronize account ?##accountname##?"
-    },
-    "addressbook.searchall": {
-        "message": "Search all address books"
-    },
-    "addressbook.searchgal": {
-        "message": "Search this address book and the global directory (##replace.1##)"
-    },
-    "addressbook.searchthis": {
-        "message": "Search this address book"
-    },
-    "eventlog.clear": {
-        "message": "Clear"
-    },
-    "eventlog.close": {
-        "message": "Close"
-    },
-    "eventlog.title": {
-        "message": "Event log"
-    },
-    "extensionDescription": {
-        "message": "TbSync is a central user interface to manage cloud accounts and to synchronize their contact, task and calendar information with Thunderbird."
-    },
-    "google.translate.code": {
-        "message": "en"
-    },
-    "helplink.security": {
-        "message": "https://github.com/jobisoft/TbSync/wiki/How-to-use-TbSync-with-self-signed-or-otherwise-untrusted-certificates%3F"
-    },
-    "info.error": {
-        "message": "Error"
-    },
-    "info.idle": {
-        "message": "Idle"
-    },
-    "installProvider.header": {
-        "message": "Provider ?##replace.1##? for TbSync is not yet installed."
-    },
-    "manager.AccountActions": {
-        "message": "Account actions"
-    },
-    "manager.AddAccount": {
-        "message": "Add new account"
-    },
-    "manager.DeleteAccount": {
-        "message": "Delete account"
-    },
-    "manager.DisableAccount": {
-        "message": "Disable account"
-    },
-    "manager.EnableAccount": {
-        "message": "Enable account & try to connect to server"
-    },
-    "manager.RetryConnectAccount": {
-        "message": "Try again to connect to server"
-    },
-    "manager.ShowEventLog": {
-        "message": "Open event log"
-    },
-    "manager.SyncAll": {
-        "message": "Synchronize all enabled accounts"
-    },
-    "manager.SynchronizeAccount": {
-        "message": "Synchronize account"
-    },
-    "manager.accounts": {
-        "message": "Accounts"
-    },
-    "manager.accountsettings": {
-        "message": "Account Settings"
-    },
-    "manager.catman.text": {
-        "message": "TbSync also syncs contact categories, which are a powerful replacement for the non-synchronizable contact lists. To be able to use them in the Thunderbird address book you can install the Category Manager add-on. It allows to manage overlapping category based contact groups and provides a bunch of other category-related features. It can be found in the official Mozilla add-on repository:"
-    },
-    "manager.community": {
-        "message": "Community"
-    },
-    "manager.connecting": {
-        "message": "Connecting to server"
-    },
-    "manager.help": {
-        "message": "Help"
-    },
-    "manager.help.createbugreport": {
-        "message": "Create bug report"
-    },
-    "manager.help.createbugreportinfo": {
-        "message": "In order for TbSync to collect only the debug data relevant to your bug report, please restart Thunderbird and then repeat exactly the steps that reproduce the buggy behavior. Then you can create your bug report here."
-    },
-    "manager.help.debuglevel.0": {
-        "message": "Disabled"
-    },
-    "manager.help.debuglevel.1": {
-        "message": "Enabled: Logging of errors only"
-    },
-    "manager.help.debuglevel.2": {
-        "message": "Enabled: Logging of all sent and received data"
-    },
-    "manager.help.debuglevel.3": {
-        "message": "Enabled: Logging of all data and some internal debug values"
-    },
-    "manager.help.debugmode": {
-        "message": "Debug mode:"
-    },
-    "manager.help.fixit": {
-        "message": "You can help to fix it by sending in a bug report. This requires the activation of debug mode."
-    },
-    "manager.help.foundabug": {
-        "message": "Found a bug?"
-    },
-    "manager.help.needhelp": {
-        "message": "Need Help?"
-    },
-    "manager.help.viewdebuglog": {
-        "message": "View debug log"
-    },
-    "manager.help.wiki": {
-        "message": "Open the wiki pages of the TbSync project, they provide additional information, guides and detailed configuration descriptions."
-    },
-    "manager.installprovider.link": {
-        "message": "Click on the following link to open the info page of the missing synchronization provider. There you will find further information about the provider and you will have the option to install it:"
-    },
-    "manager.installprovider.warning": {
-        "message": "This synchronization provider is not hosted in the official Thunderbird add-on repository and thus has not been reviewed by Thunderbird staff. The provider could do bad things to your system. Use it at your own risk."
-    },
-    "manager.lockedsettings.description": {
-        "message": "To prevent synchronization errors, some settings cannot be edited while the account is enabled."
-    },
-    "manager.missingprovider": {
-        "message": "This account requires the ##provider## synchronization provider, which is currently not installed."
-    },
-    "manager.noaccounts": {
-        "message": "There are not yet any accounts defined."
-    },
-    "manager.provider": {
-        "message": "Install Provider"
-    },
-    "manager.provider4tbsync": {
-        "message": "Provider for TbSync"
-    },
-    "manager.resource": {
-        "message": "Resource"
-    },
-    "manager.shorttitle": {
-        "message": "Account manager"
-    },
-    "manager.status": {
-        "message": "Status"
-    },
-    "manager.supporter.contributors": {
-        "message": "Contributors & Translators"
-    },
-    "manager.supporter.details": {
-        "message": "Details"
-    },
-    "manager.supporter.sponsors": {
-        "message": "Sponsors of test accounts"
-    },
-    "manager.tabs.status": {
-        "message": "Synchronization status"
-    },
-    "manager.tabs.status.autotime": {
-        "message": "Periodic synchronization (in minutes)"
-    },
-    "manager.tabs.status.enableThisAccount": {
-        "message": "Enable and synchronize this account"
-    },
-    "manager.tabs.status.general": {
-        "message": "General"
-    },
-    "manager.tabs.status.never": {
-        "message": "A setting of 0 disables periodic sync. Push sync is not yet implemented."
-    },
-    "manager.tabs.status.resources": {
-        "message": "Available resources"
-    },
-    "manager.tabs.status.resources.intro": {
-        "message": "Select which of the found resources should be synchronized with Thunderbird."
-    },
-    "manager.tabs.status.sync": {
-        "message": "Synchronize now"
-    },
-    "manager.tabs.status.tryagain": {
-        "message": "Try again to connect server"
-    },
-    "manager.title": {
-        "message": "TbSync account manager"
-    },
-    "manager.tryagain": {
-        "message": "Try again to connect server"
-    },
-    "menu.settingslabel": {
-        "message": "Synchronization Settings (TbSync)"
-    },
-    "password.account": {
-        "message": "Account:"
-    },
-    "password.description": {
-        "message": "Please update the credentials for the following TbSync account:"
-    },
-    "password.password": {
-        "message": "Password:"
-    },
-    "password.title": {
-        "message": "TbSync Credential Request"
-    },
-    "password.user": {
-        "message": "User:"
-    },
-    "popup.opensettings": {
-        "message": "Open TbSync account manager"
-    },
-    "prompt.DeleteAccount": {
-        "message": "Are you sure you want to delete account ##accountName##?"
-    },
-    "prompt.Disable": {
-        "message": "Are you sure you want to disable this account? All local modifications, which have not been synced yet, will be lost!"
-    },
-    "prompt.Erase": {
-        "message": "Are you sure you want to remove this account of an unknown provider from the accounts lists?"
-    },
-    "prompt.Unsubscribe": {
-        "message": "Are you sure you want to unsubscribe this item? All local modifications, which have not been synced yet, will be lost!"
-    },
-    "status.JavaScriptError": {
-        "message": "Javascript Error! Please check the event log for more details."
-    },
-    "status.OAuthAbortError": {
-        "message": "OAuth 2.0 authentication process aborted by user."
-    },
-    "status.OAuthHttpError": {
-        "message": "OAuth 2.0 authentication process failed (HTTP error ##replace.1##)."
-    },
-    "status.OAuthNetworkError": {
-        "message": "Could not connect to OAuth 2.0 authentication server."
-    },
-    "status.OAuthServerError": {
-        "message": " OAuth 2.0 authentication server returned: ##replace.1##"
-    },
-    "status.aborted": {
-        "message": "Not synchronized"
-    },
-    "status.apiError": {
-        "message": "API implementation error"
-    },
-    "status.disabled": {
-        "message": "Account is not enabled, synchronization is disabled."
-    },
-    "status.foldererror": {
-        "message": "At least one resource encountered a synchronization error. Please check the event log for more details."
-    },
-    "status.modified": {
-        "message": "Local modifications"
-    },
-    "status.network": {
-        "message": "Could not connect to server (##replace.1##)."
-    },
-    "status.no-folders-found-on-server": {
-        "message": "Could not find any resources on the server."
-    },
-    "status.notargets": {
-        "message": "Aborting synchronization, because sync targets could not be created."
-    },
-    "status.notsyncronized": {
-        "message": "Account needs to be synchronized, at least one item is out of sync."
-    },
-    "status.pending": {
-        "message": "Waiting to be synchronized"
-    },
-    "status.security": {
-        "message": "Could not establish a secure connection. Are you using a self-signed or otherwise untrusted certificate without importing it into Thunderbird? (##replace.1##)"
-    },
-    "status.skipped": {
-        "message": "Not yet supported, skipped"
-    },
-    "status.success": {
-        "message": "OK"
-    },
-    "status.syncing": {
-        "message": "Synchronizing"
-    },
-    "status.451": {
-        "message": "Server issued redirect, retry in 5 seconds."
-    },
-    "supportwizard.footer": {
-        "message": "From the information given here, an e-mail will be generated in the next step, which you can subsequently edit (for example, adding screenshots or similar). Only by actually sending that e-mail, the error report will be sent."
-    },
-    "supportwizard.label.description": {
-        "message": "Detailed error description:"
-    },
-    "supportwizard.label.faultycomponent": {
-        "message": "Component of TbSync where you have observed the error:"
-    },
-    "supportwizard.label.selectcomponent": {
-        "message": "Select component?"
-    },
-    "supportwizard.label.summary": {
-        "message": "Short summary of the error:"
-    },
-    "supportwizard.pagetitle": {
-        "message": "Gathering of all information to effectively process the bug report."
-    },
-    "supportwizard.provider": {
-        "message": "Provider: ##replace.1##"
-    },
-    "supportwizard.title": {
-        "message": "Create bug report"
-    },
-    "syncstate.accountdone": {
-        "message": "Finished account"
-    },
-    "syncstate.done": {
-        "message": "Preparing next item for synchronization"
-    },
-    "syncstate.oauthprompt": {
-        "message": "OAuth 2.0 authentication"
-    },
-    "syncstate.passwordprompt": {
-        "message": "Prompting for credentials"
-    },
-    "syncstate.preparing": {
-        "message": "Preparing next item for synchronization"
-    },
-    "syncstate.syncing": {
-        "message": "Initialize synchronization"
-    },
-    "target.orphaned": {
-        "message": "Disconnected"
-    },
-    "toolbar.label": {
-        "message": "Synchronize all TbSync accounts"
-    },
-    "toolbar.tooltiptext": {
-        "message": "Synchronize latest changes"
-    },
-    "password.ok": {
-        "message": "??"
-    },
-    "password.cancel": {
-        "message": "??"
-    }
-}
+{
+    "HelpFixStartupError": {
+        "message": "To help fix this error, you could send a debug log to the TbSync developer. Prepare that email now?"
+    },
+    "NoDebugLog": {
+        "message": "Could not find any useful debug messages. Please activate debug mode, restart Thunderbird and repeat all the steps needed to trigger the erroneous behavior."
+    },
+    "OopsMessage": {
+        "message": "Oops! TbSync was not able to start!"
+    },
+    "RestartThunderbirdAndTryAgain": {
+        "message": "TbSync debug log has been enabled, please restart Thunderbird and again try to open TbSync."
+    },
+    "UnableToTraceError": {
+        "message": "It is not possible to trace this error, because debug log is currently not enabled. Do you want to enable debug log now, to help fix this error?"
+    },
+    "accountacctions.delete": {
+        "message": "Delete account ?##accountname##?"
+    },
+    "accountacctions.disable": {
+        "message": "Disable account ?##accountname##?"
+    },
+    "accountacctions.enable": {
+        "message": "Enable account ?##accountname##? & try to connect to server"
+    },
+    "accountacctions.sync": {
+        "message": "Synchronize account ?##accountname##?"
+    },
+    "addressbook.searchall": {
+        "message": "Search all address books"
+    },
+    "addressbook.searchgal": {
+        "message": "Search this address book and the global directory (##replace.1##)"
+    },
+    "addressbook.searchthis": {
+        "message": "Search this address book"
+    },
+    "eventlog.clear": {
+        "message": "Clear"
+    },
+    "eventlog.close": {
+        "message": "Close"
+    },
+    "eventlog.title": {
+        "message": "Event log"
+    },
+    "extensionDescription": {
+        "message": "TbSync is a central user interface to manage cloud accounts and to synchronize their contact, task and calendar information with Thunderbird."
+    },
+    "google.translate.code": {
+        "message": "en"
+    },
+    "helplink.security": {
+        "message": "https://github.com/jobisoft/TbSync/wiki/How-to-use-TbSync-with-self-signed-or-otherwise-untrusted-certificates%3F"
+    },
+    "info.error": {
+        "message": "Error"
+    },
+    "info.idle": {
+        "message": "Idle"
+    },
+    "installProvider.header": {
+        "message": "Provider ?##replace.1##? for TbSync is not yet installed."
+    },
+    "manager.AccountActions": {
+        "message": "Account actions"
+    },
+    "manager.AddAccount": {
+        "message": "Add new account"
+    },
+    "manager.DeleteAccount": {
+        "message": "Delete account"
+    },
+    "manager.DisableAccount": {
+        "message": "Disable account"
+    },
+    "manager.EnableAccount": {
+        "message": "Enable account & try to connect to server"
+    },
+    "manager.RetryConnectAccount": {
+        "message": "Try again to connect to server"
+    },
+    "manager.ShowEventLog": {
+        "message": "Open event log"
+    },
+    "manager.SyncAll": {
+        "message": "Synchronize all enabled accounts"
+    },
+    "manager.SynchronizeAccount": {
+        "message": "Synchronize account"
+    },
+    "manager.accounts": {
+        "message": "Accounts"
+    },
+    "manager.accountsettings": {
+        "message": "Account Settings"
+    },
+    "manager.catman.text": {
+        "message": "TbSync also syncs contact categories, which are a powerful replacement for the non-synchronizable contact lists. To be able to use them in the Thunderbird address book you can install the Category Manager add-on. It allows to manage overlapping category based contact groups and provides a bunch of other category-related features. It can be found in the official Mozilla add-on repository:"
+    },
+    "manager.community": {
+        "message": "Community"
+    },
+    "manager.connecting": {
+        "message": "Connecting to server"
+    },
+    "manager.help": {
+        "message": "Help"
+    },
+    "manager.help.createbugreport": {
+        "message": "Create bug report"
+    },
+    "manager.help.createbugreportinfo": {
+        "message": "In order for TbSync to collect only the debug data relevant to your bug report, please restart Thunderbird and then repeat exactly the steps that reproduce the buggy behavior. Then you can create your bug report here."
+    },
+    "manager.help.debuglevel.0": {
+        "message": "Disabled"
+    },
+    "manager.help.debuglevel.1": {
+        "message": "Enabled: Logging of errors only"
+    },
+    "manager.help.debuglevel.2": {
+        "message": "Enabled: Logging of all sent and received data"
+    },
+    "manager.help.debuglevel.3": {
+        "message": "Enabled: Logging of all data and some internal debug values"
+    },
+    "manager.help.debugmode": {
+        "message": "Debug mode:"
+    },
+    "manager.help.fixit": {
+        "message": "You can help to fix it by sending in a bug report. This requires the activation of debug mode."
+    },
+    "manager.help.foundabug": {
+        "message": "Found a bug?"
+    },
+    "manager.help.needhelp": {
+        "message": "Need Help?"
+    },
+    "manager.help.viewdebuglog": {
+        "message": "View debug log"
+    },
+    "manager.help.wiki": {
+        "message": "Open the wiki pages of the TbSync project, they provide additional information, guides and detailed configuration descriptions."
+    },
+    "manager.installprovider.link": {
+        "message": "Click on the following link to open the info page of the missing synchronization provider. There you will find further information about the provider and you will have the option to install it:"
+    },
+    "manager.installprovider.warning": {
+        "message": "This synchronization provider is not hosted in the official Thunderbird add-on repository and thus has not been reviewed by Thunderbird staff. The provider could do bad things to your system. Use it at your own risk."
+    },
+    "manager.lockedsettings.description": {
+        "message": "To prevent synchronization errors, some settings cannot be edited while the account is enabled."
+    },
+    "manager.missingprovider": {
+        "message": "This account requires the ##provider## synchronization provider, which is currently not installed."
+    },
+    "manager.noaccounts": {
+        "message": "There are not yet any accounts defined."
+    },
+    "manager.provider": {
+        "message": "Install Provider"
+    },
+    "manager.provider4tbsync": {
+        "message": "Provider for TbSync"
+    },
+    "manager.resource": {
+        "message": "Resource"
+    },
+    "manager.shorttitle": {
+        "message": "Account manager"
+    },
+    "manager.status": {
+        "message": "Status"
+    },
+    "manager.supporter.contributors": {
+        "message": "Contributors & Translators"
+    },
+    "manager.supporter.details": {
+        "message": "Details"
+    },
+    "manager.supporter.sponsors": {
+        "message": "Sponsors of test accounts"
+    },
+    "manager.tabs.status": {
+        "message": "Synchronization status"
+    },
+    "manager.tabs.status.autotime": {
+        "message": "Periodic synchronization (in minutes)"
+    },
+    "manager.tabs.status.enableThisAccount": {
+        "message": "Enable and synchronize this account"
+    },
+    "manager.tabs.status.general": {
+        "message": "General"
+    },
+    "manager.tabs.status.never": {
+        "message": "A setting of 0 disables periodic sync. Push sync is not yet implemented."
+    },
+    "manager.tabs.status.resources": {
+        "message": "Available resources"
+    },
+    "manager.tabs.status.resources.intro": {
+        "message": "Select which of the found resources should be synchronized with Thunderbird."
+    },
+    "manager.tabs.status.sync": {
+        "message": "Synchronize now"
+    },
+    "manager.tabs.status.tryagain": {
+        "message": "Try again to connect server"
+    },
+    "manager.title": {
+        "message": "TbSync account manager"
+    },
+    "manager.tryagain": {
+        "message": "Try again to connect server"
+    },
+    "menu.settingslabel": {
+        "message": "Synchronization Settings (TbSync)"
+    },
+    "password.account": {
+        "message": "Account:"
+    },
+    "password.description": {
+        "message": "Please update the credentials for the following TbSync account:"
+    },
+    "password.password": {
+        "message": "Password:"
+    },
+    "password.title": {
+        "message": "TbSync Credential Request"
+    },
+    "password.user": {
+        "message": "User:"
+    },
+    "popup.opensettings": {
+        "message": "Open TbSync account manager"
+    },
+    "prompt.DeleteAccount": {
+        "message": "Are you sure you want to delete account ##accountName##?"
+    },
+    "prompt.Disable": {
+        "message": "Are you sure you want to disable this account? All local modifications, which have not been synced yet, will be lost!"
+    },
+    "prompt.Erase": {
+        "message": "Are you sure you want to remove this account of an unknown provider from the accounts lists?"
+    },
+    "prompt.Unsubscribe": {
+        "message": "Are you sure you want to unsubscribe this item? All local modifications, which have not been synced yet, will be lost!"
+    },
+    "status.JavaScriptError": {
+        "message": "Javascript Error! Please check the event log for more details."
+    },
+    "status.OAuthAbortError": {
+        "message": "OAuth 2.0 authentication process aborted by user."
+    },
+    "status.OAuthHttpError": {
+        "message": "OAuth 2.0 authentication process failed (HTTP error ##replace.1##)."
+    },
+    "status.OAuthNetworkError": {
+        "message": "Could not connect to OAuth 2.0 authentication server."
+    },
+    "status.OAuthServerError": {
+        "message": " OAuth 2.0 authentication server returned: ##replace.1##"
+    },
+    "status.aborted": {
+        "message": "Not synchronized"
+    },
+    "status.apiError": {
+        "message": "API implementation error"
+    },
+    "status.disabled": {
+        "message": "Account is not enabled, synchronization is disabled."
+    },
+    "status.foldererror": {
+        "message": "At least one resource encountered a synchronization error. Please check the event log for more details."
+    },
+    "status.modified": {
+        "message": "Local modifications"
+    },
+    "status.network": {
+        "message": "Could not connect to server (##replace.1##)."
+    },
+    "status.no-folders-found-on-server": {
+        "message": "Could not find any resources on the server."
+    },
+    "status.notargets": {
+        "message": "Aborting synchronization, because sync targets could not be created."
+    },
+    "status.notsyncronized": {
+        "message": "Account needs to be synchronized, at least one item is out of sync."
+    },
+    "status.pending": {
+        "message": "Waiting to be synchronized"
+    },
+    "status.security": {
+        "message": "Could not establish a secure connection. Are you using a self-signed or otherwise untrusted certificate without importing it into Thunderbird? (##replace.1##)"
+    },
+    "status.skipped": {
+        "message": "Not yet supported, skipped"
+    },
+    "status.success": {
+        "message": "OK"
+    },
+    "status.syncing": {
+        "message": "Synchronizing"
+    },
+    "status.451": {
+        "message": "Server issued redirect, retry in 5 seconds."
+    },
+    "supportwizard.footer": {
+        "message": "From the information given here, an e-mail will be generated in the next step, which you can subsequently edit (for example, adding screenshots or similar). Only by actually sending that e-mail, the error report will be sent."
+    },
+    "supportwizard.label.description": {
+        "message": "Detailed error description:"
+    },
+    "supportwizard.label.faultycomponent": {
+        "message": "Component of TbSync where you have observed the error:"
+    },
+    "supportwizard.label.selectcomponent": {
+        "message": "Select component?"
+    },
+    "supportwizard.label.summary": {
+        "message": "Short summary of the error:"
+    },
+    "supportwizard.pagetitle": {
+        "message": "Gathering of all information to effectively process the bug report."
+    },
+    "supportwizard.provider": {
+        "message": "Provider: ##replace.1##"
+    },
+    "supportwizard.title": {
+        "message": "Create bug report"
+    },
+    "syncstate.accountdone": {
+        "message": "Finished account"
+    },
+    "syncstate.done": {
+        "message": "Preparing next item for synchronization"
+    },
+    "syncstate.oauthprompt": {
+        "message": "OAuth 2.0 authentication"
+    },
+    "syncstate.passwordprompt": {
+        "message": "Prompting for credentials"
+    },
+    "syncstate.preparing": {
+        "message": "Preparing next item for synchronization"
+    },
+    "syncstate.syncing": {
+        "message": "Initialize synchronization"
+    },
+    "target.orphaned": {
+        "message": "Disconnected"
+    },
+    "toolbar.label": {
+        "message": "Synchronize all TbSync accounts"
+    },
+    "toolbar.tooltiptext": {
+        "message": "Synchronize latest changes"
+    },
+    "password.ok": {
+        "message": "??"
+    },
+    "password.cancel": {
+        "message": "??"
+    }
+}
diff -Nru tbsync-4.12/_locales/pl/messages.json tbsync-4.16/_locales/pl/messages.json
--- tbsync-4.12/_locales/pl/messages.json	2024-08-27 18:32:08.000000000 +0200
+++ tbsync-4.16/_locales/pl/messages.json	2024-08-27 18:29:06.000000000 +0200
@@ -1,368 +1,368 @@
-{
-    "HelpFixStartupError": {
-        "message": "Aby naprawi? ten b??d, mo?esz wys?a? dziennik debugowania do programisty TbSync. Przygotowa? ten e-mail teraz?"
-    },
-    "NoDebugLog": {
-        "message": "Nie mo?na znale?? ?adnych przydatnych wiadomo?ci debugowania. Aktywuj tryb debugowania, uruchom ponownie Thunderbirda i powt?rz wszystkie kroki potrzebne do wywo?ania b??dnego zachowania."
-    },
-    "OopsMessage": {
-        "message": "Ups! TbSync nie m?g? si? uruchomi?!"
-    },
-    "RestartThunderbirdAndTryAgain": {
-        "message": "Dziennik debugowania TbSync zosta? w??czony, zrestartuj Thunderbirda i ponownie spr?buj otworzy? TbSync."
-    },
-    "UnableToTraceError": {
-        "message": "Nie mo?na prze?ledzi? tego b??du, poniewa? dziennik debugowania nie jest obecnie w??czony. Czy chcesz teraz w??czy? dziennik debugowania, aby pom?c naprawi? ten b??d?"
-    },
-    "accountacctions.delete": {
-        "message": "Usu? konto ?##accountname##?"
-    },
-    "accountacctions.disable": {
-        "message": "Wy??cz konto ?##accountname##?"
-    },
-    "accountacctions.enable": {
-        "message": "W??cz konto ?##accountname##? i spr?buj po??czy? si? z serwerem"
-    },
-    "accountacctions.sync": {
-        "message": "Synchronizuj konto ?##accountname##?"
-    },
-    "addressbook.searchall": {
-        "message": "Wyszukuj we wszystkich ksi??kach adresowych"
-    },
-    "addressbook.searchgal": {
-        "message": "Wyszukuj w tej ksi??ce adresowej i w katalogu globalnym (##replace.1##)"
-    },
-    "addressbook.searchthis": {
-        "message": "Wyszukuj w tej ksi??ce adresowej"
-    },
-    "eventlog.clear": {
-        "message": "Wyczy??"
-    },
-    "eventlog.close": {
-        "message": "Zamknij"
-    },
-    "eventlog.title": {
-        "message": "Dziennik zdarze?"
-    },
-    "extensionDescription": {
-        "message": "TbSync to centralny interfejs u?ytkownika do zarz?dzania kontami w chmurze i synchronizowania ich danych kontaktowych, zada? i kalendarza z Thunderbird."
-    },
-    "google.translate.code": {
-        "message": "pl"
-    },
-    "helplink.security": {
-        "message": "https://github.com/jobisoft/TbSync/wiki/How-to-use-TbSync-with-self-signed-or-otherwise-untrusted-certificates%3F"
-    },
-    "info.error": {
-        "message": "B??d"
-    },
-    "info.idle": {
-        "message": "Bezczynny"
-    },
-    "installProvider.header": {
-        "message": "Dostawca ?##replace.1##? dla TbSync nie jest jeszcze zainstalowany."
-    },
-    "manager.AccountActions": {
-        "message": "Akcje konta"
-    },
-    "manager.AddAccount": {
-        "message": "Dodaj nowe konto"
-    },
-    "manager.DeleteAccount": {
-        "message": "Usu? konto"
-    },
-    "manager.DisableAccount": {
-        "message": "Wy??cz konto"
-    },
-    "manager.EnableAccount": {
-        "message": "W??cz konto i spr?buj po??czy? si? z serwerem"
-    },
-    "manager.RetryConnectAccount": {
-        "message": "Spr?buj ponownie po??czy? do serwera"
-    },
-    "manager.ShowEventLog": {
-        "message": "Otw?rz dziennik zdarze?"
-    },
-    "manager.SyncAll": {
-        "message": "Synchronizuj wszystkie w??czone konta"
-    },
-    "manager.SynchronizeAccount": {
-        "message": "Synchronizuj konto"
-    },
-    "manager.accounts": {
-        "message": "Konta"
-    },
-    "manager.accountsettings": {
-        "message": "Ustawienia konta"
-    },
-    "manager.catman.text": {
-        "message": "TbSync synchronizuje r?wnie? kategorie kontakt?w, kt?re s? pot??nym zamiennikiem dla niesynchronizowanych list kontakt?w. Aby m?c z nich korzysta? w ksi??ce adresowej Thunderbird, mo?esz zainstalowa? dodatek Category Manager. Pozwala zarz?dza? nak?adaj?cymi si? grupami kontakt?w opartymi na kategoriach i zapewnia szereg innych funkcji zwi?zanych z kategoriami. Mo?na go znale?? w oficjalnym repozytorium dodatk?w Mozilla:"
-    },
-    "manager.community": {
-        "message": "Spo?eczno??"
-    },
-    "manager.connecting": {
-        "message": "??czenie z serwerem"
-    },
-    "manager.help": {
-        "message": "Pomoc"
-    },
-    "manager.help.createbugreport": {
-        "message": "Utw?rz raport o b??dzie"
-    },
-    "manager.help.createbugreportinfo": {
-        "message": "Aby TbSync zbiera? tylko dane debugowania istotne dla Twojego zg?oszenia b??du, uruchom ponownie Thunderbirda, a nast?pnie powt?rz dok?adnie kroki, kt?re odtworz? b??dne zachowanie. Nast?pnie mo?esz tutaj utworzy? raport o b??dzie."
-    },
-    "manager.help.debuglevel.0": {
-        "message": "Wy??czony"
-    },
-    "manager.help.debuglevel.1": {
-        "message": "W??czony: Rejestrowanie tylko b??d?w"
-    },
-    "manager.help.debuglevel.2": {
-        "message": "W??czony: Rejestrowanie wszystkich wys?anych i odebranych danych"
-    },
-    "manager.help.debuglevel.3": {
-        "message": "W??czone: Rejestrowanie wszystkich danych i niekt?rych wewn?trznych warto?ci debugowania"
-    },
-    "manager.help.debugmode": {
-        "message": "Tryb debugowania:"
-    },
-    "manager.help.fixit": {
-        "message": "Mo?esz pom?c to naprawi?, wysy?aj?c raport o b??dzie. Wymaga to w??czenia trybu debugowania."
-    },
-    "manager.help.foundabug": {
-        "message": "Znalaz?e? b??d?"
-    },
-    "manager.help.needhelp": {
-        "message": "Potrzebujesz pomocy?"
-    },
-    "manager.help.viewdebuglog": {
-        "message": "Zobacz log debugowania"
-    },
-    "manager.help.wiki": {
-        "message": "Otw?rz strony wiki projektu TbSync, zawieraj? one dodatkowe informacje, przewodniki i szczeg??owe opisy konfiguracji."
-    },
-    "manager.installprovider.link": {
-        "message": "Kliknij poni?szy link, aby otworzy? stron? informacyjn? brakuj?cego dostawcy synchronizacji. Znajdziesz tam dodatkowe informacje na temat dostawcy i b?dziesz m?g? go zainstalowa?:"
-    },
-    "manager.installprovider.warning": {
-        "message": "Ten dostawca synchronizacji nie jest udost?pniony w oficjalnym repozytorium dodatk?w Thunderbird, a zatem nie zosta? sprawdzony przez pracownik?w Thunderbirda. Dostawca mo?e wyrz?dzi? szkody w Twoim systemie. U?ywaj go na w?asne ryzyko."
-    },
-    "manager.lockedsettings.description": {
-        "message": "Aby zapobiec b??dom synchronizacji, niekt?rych ustawie? nie mo?na edytowa?, gdy konto jest w??czone."
-    },
-    "manager.missingprovider": {
-        "message": "To konto wymaga dostawcy synchronizacji ##provider##, kt?ry obecnie nie jest zainstalowany."
-    },
-    "manager.noaccounts": {
-        "message": "Nie ma jeszcze zdefiniowanych kont."
-    },
-    "manager.provider": {
-        "message": "Zainstaluj dostawc?"
-    },
-    "manager.provider4tbsync": {
-        "message": "Dostawca dla TbSync"
-    },
-    "manager.resource": {
-        "message": "Zas?b"
-    },
-    "manager.shorttitle": {
-        "message": "Mened?er konta"
-    },
-    "manager.status": {
-        "message": "Status"
-    },
-    "manager.supporter.contributors": {
-        "message": "Wsp??pracownicy i T?umacze"
-    },
-    "manager.supporter.details": {
-        "message": "Szczeg??y"
-    },
-    "manager.supporter.sponsors": {
-        "message": "Sponsorzy kont testowych"
-    },
-    "manager.tabs.status": {
-        "message": "Status synchronizacji"
-    },
-    "manager.tabs.status.autotime": {
-        "message": "Okresowa synchronizacja (w minutach)"
-    },
-    "manager.tabs.status.enableThisAccount": {
-        "message": "W??cz i synchronizuj to konto"
-    },
-    "manager.tabs.status.general": {
-        "message": "Og?lne"
-    },
-    "manager.tabs.status.never": {
-        "message": "Ustawienie 0 wy??cza okresow? synchronizacj?. Synchronizacja push nie jest jeszcze zaimplementowana."
-    },
-    "manager.tabs.status.resources": {
-        "message": "Dost?pne zasoby"
-    },
-    "manager.tabs.status.resources.intro": {
-        "message": "Wybierz, kt?re ze znalezionych zasob?w powinny by? zsynchronizowane z Thunderbirdem."
-    },
-    "manager.tabs.status.sync": {
-        "message": "Synchronizuj teraz"
-    },
-    "manager.tabs.status.tryagain": {
-        "message": "Spr?buj ponownie po??czy? z serwerem"
-    },
-    "manager.title": {
-        "message": "Mened?er konta TbSync"
-    },
-    "manager.tryagain": {
-        "message": "Spr?buj ponownie po??czy? z serwerem"
-    },
-    "menu.settingslabel": {
-        "message": "Ustawienia synchronizacji (TbSync)"
-    },
-    "password.account": {
-        "message": "Konto:"
-    },
-    "password.description": {
-        "message": "Zaktualizuj dane logowania dla nast?puj?cego konta TbSync:"
-    },
-    "password.password": {
-        "message": "Has?o:"
-    },
-    "password.title": {
-        "message": "??danie Danych Logowania TbSync"
-    },
-    "password.user": {
-        "message": "U?ytkownik:"
-    },
-    "popup.opensettings": {
-        "message": "Otw?rz mened?er konta TbSync"
-    },
-    "prompt.DeleteAccount": {
-        "message": "Czy na pewno chcesz usun?? konto ##accountName##?"
-    },
-    "prompt.Disable": {
-        "message": "Czy na pewno chcesz wy??czy? to konto? Wszystkie lokalne modyfikacje, kt?re nie zosta?y jeszcze zsynchronizowane, zostan? utracone!"
-    },
-    "prompt.Erase": {
-        "message": "Czy jeste? pewien, ?e chcesz usun?? to konto nieznanego dostawcy z list kont?"
-    },
-    "prompt.Unsubscribe": {
-        "message": "Czy na pewno chcesz anulowa? subskrypcj? tego elementu? Wszystkie lokalne modyfikacje, kt?re nie zosta?y jeszcze zsynchronizowane, zostan? utracone!"
-    },
-    "status.JavaScriptError": {
-        "message": "B??d Javascript! Sprawd? dziennik zdarze?, aby uzyska? wi?cej informacji."
-    },
-    "status.OAuthAbortError": {
-        "message": "Proces uwierzytelniania OAuth 2.0 przerwany przez u?ytkownika."
-    },
-    "status.OAuthHttpError": {
-        "message": "Proces uwierzytelniania OAuth 2.0 nie powi?d? si? (b??d HTTP ##replace.1##)."
-    },
-    "status.OAuthNetworkError": {
-        "message": "Nie mo?na po??czy? si? z serwerem uwierzytelniania OAuth 2.0."
-    },
-    "status.OAuthServerError": {
-        "message": " Serwer uwierzytelniania OAuth 2.0 zwr?ci?: ##replace.1##"
-    },
-    "status.aborted": {
-        "message": "Nie zsynchronizowane"
-    },
-    "status.apiError": {
-        "message": "B??d implementacji API"
-    },
-    "status.disabled": {
-        "message": "Konto nie jest w??czone, synchronizacja jest wy??czona."
-    },
-    "status.foldererror": {
-        "message": "Przynajmniej jeden zas?b napotka? b??d synchronizacji. Sprawd? dziennik zdarze?, aby uzyska? wi?cej informacji."
-    },
-    "status.modified": {
-        "message": "Zmiany lokalne"
-    },
-    "status.network": {
-        "message": "Nie mo?na po??czy? z serwerem (##replace.1##)."
-    },
-    "status.no-folders-found-on-server": {
-        "message": "Nie mo?na znale?? ?adnych zasob?w na serwerze."
-    },
-    "status.notargets": {
-        "message": "Przerywanie synchronizacji, poniewa? nie mo?na utworzy? cel?w synchronizacji."
-    },
-    "status.notsyncronized": {
-        "message": "Konto musi zosta? zsynchronizowane, co najmniej jeden element nie jest zsynchronizowany."
-    },
-    "status.pending": {
-        "message": "Oczekiwanie na synchronizacj?"
-    },
-    "status.security": {
-        "message": "Nie mo?na ustanowi? bezpiecznego po??czenia. Czy u?ywasz certyfikatu self-signed lub innego niezaufanego certyfikatu bez importowania go do Thunderbirda? (##replace.1##)"
-    },
-    "status.skipped": {
-        "message": "Jeszcze nie wspierane, pomini?to"
-    },
-    "status.success": {
-        "message": "OK"
-    },
-    "status.syncing": {
-        "message": "Synchronizuj?"
-    },
-    "status.451": {
-        "message": "Server issued redirect, retry in 5 seconds."
-    },
-    "supportwizard.footer": {
-        "message": "Z podanych tutaj informacji w nast?pnym kroku zostanie wygenerowany e-mail, kt?ry mo?esz nast?pnie edytowa? (na przyk?ad dodaj?c zrzuty ekranu lub podobne). Tylko poprzez faktyczne wys?anie tej wiadomo?ci zostanie wys?any raport o b??dzie."
-    },
-    "supportwizard.label.description": {
-        "message": "Szczeg??owy opis b??du:"
-    },
-    "supportwizard.label.faultycomponent": {
-        "message": "Sk?adnik TbSync, w kt?rym zaobserwowano b??d:"
-    },
-    "supportwizard.label.selectcomponent": {
-        "message": "Wybierz sk?adnik?"
-    },
-    "supportwizard.label.summary": {
-        "message": "Kr?tkie podsumowanie b??du:"
-    },
-    "supportwizard.pagetitle": {
-        "message": "Zbieranie wszystkich informacji w celu skutecznego przetworzenia zg?oszenia b??du."
-    },
-    "supportwizard.provider": {
-        "message": "Dostawca: ##replace.1##"
-    },
-    "supportwizard.title": {
-        "message": "Utw?rz raport o b??dzie"
-    },
-    "syncstate.accountdone": {
-        "message": "Konto gotowe"
-    },
-    "syncstate.done": {
-        "message": "Przygotowuj? nast?pny element do synchronizacji"
-    },
-    "syncstate.oauthprompt": {
-        "message": "Uwierzytelnianie OAuth 2.0"
-    },
-    "syncstate.passwordprompt": {
-        "message": "Monitowanie o dane logowania"
-    },
-    "syncstate.preparing": {
-        "message": "Przygotowuj? nast?pny element do synchronizacji"
-    },
-    "syncstate.syncing": {
-        "message": "Zainicjuj synchronizacj?"
-    },
-    "target.orphaned": {
-        "message": "Roz??czony"
-    },
-    "toolbar.label": {
-        "message": "Synchronizuj wszystkie konta TbSync"
-    },
-    "toolbar.tooltiptext": {
-        "message": "Synchronizuj najnowsze zmiany"
-    },
-    "password.ok": {
-        "message": "OK"
-    },
-    "password.cancel": {
-        "message": "Anuluj"
-    }
-}
+{
+    "HelpFixStartupError": {
+        "message": "Aby naprawi? ten b??d, mo?esz wys?a? dziennik debugowania do programisty TbSync. Przygotowa? ten e-mail teraz?"
+    },
+    "NoDebugLog": {
+        "message": "Nie mo?na znale?? ?adnych przydatnych wiadomo?ci debugowania. Aktywuj tryb debugowania, uruchom ponownie Thunderbirda i powt?rz wszystkie kroki potrzebne do wywo?ania b??dnego zachowania."
+    },
+    "OopsMessage": {
+        "message": "Ups! TbSync nie m?g? si? uruchomi?!"
+    },
+    "RestartThunderbirdAndTryAgain": {
+        "message": "Dziennik debugowania TbSync zosta? w??czony, zrestartuj Thunderbirda i ponownie spr?buj otworzy? TbSync."
+    },
+    "UnableToTraceError": {
+        "message": "Nie mo?na prze?ledzi? tego b??du, poniewa? dziennik debugowania nie jest obecnie w??czony. Czy chcesz teraz w??czy? dziennik debugowania, aby pom?c naprawi? ten b??d?"
+    },
+    "accountacctions.delete": {
+        "message": "Usu? konto ?##accountname##?"
+    },
+    "accountacctions.disable": {
+        "message": "Wy??cz konto ?##accountname##?"
+    },
+    "accountacctions.enable": {
+        "message": "W??cz konto ?##accountname##? i spr?buj po??czy? si? z serwerem"
+    },
+    "accountacctions.sync": {
+        "message": "Synchronizuj konto ?##accountname##?"
+    },
+    "addressbook.searchall": {
+        "message": "Wyszukuj we wszystkich ksi??kach adresowych"
+    },
+    "addressbook.searchgal": {
+        "message": "Wyszukuj w tej ksi??ce adresowej i w katalogu globalnym (##replace.1##)"
+    },
+    "addressbook.searchthis": {
+        "message": "Wyszukuj w tej ksi??ce adresowej"
+    },
+    "eventlog.clear": {
+        "message": "Wyczy??"
+    },
+    "eventlog.close": {
+        "message": "Zamknij"
+    },
+    "eventlog.title": {
+        "message": "Dziennik zdarze?"
+    },
+    "extensionDescription": {
+        "message": "TbSync to centralny interfejs u?ytkownika do zarz?dzania kontami w chmurze i synchronizowania ich danych kontaktowych, zada? i kalendarza z Thunderbird."
+    },
+    "google.translate.code": {
+        "message": "pl"
+    },
+    "helplink.security": {
+        "message": "https://github.com/jobisoft/TbSync/wiki/How-to-use-TbSync-with-self-signed-or-otherwise-untrusted-certificates%3F"
+    },
+    "info.error": {
+        "message": "B??d"
+    },
+    "info.idle": {
+        "message": "Bezczynny"
+    },
+    "installProvider.header": {
+        "message": "Dostawca ?##replace.1##? dla TbSync nie jest jeszcze zainstalowany."
+    },
+    "manager.AccountActions": {
+        "message": "Akcje konta"
+    },
+    "manager.AddAccount": {
+        "message": "Dodaj nowe konto"
+    },
+    "manager.DeleteAccount": {
+        "message": "Usu? konto"
+    },
+    "manager.DisableAccount": {
+        "message": "Wy??cz konto"
+    },
+    "manager.EnableAccount": {
+        "message": "W??cz konto i spr?buj po??czy? si? z serwerem"
+    },
+    "manager.RetryConnectAccount": {
+        "message": "Spr?buj ponownie po??czy? do serwera"
+    },
+    "manager.ShowEventLog": {
+        "message": "Otw?rz dziennik zdarze?"
+    },
+    "manager.SyncAll": {
+        "message": "Synchronizuj wszystkie w??czone konta"
+    },
+    "manager.SynchronizeAccount": {
+        "message": "Synchronizuj konto"
+    },
+    "manager.accounts": {
+        "message": "Konta"
+    },
+    "manager.accountsettings": {
+        "message": "Ustawienia konta"
+    },
+    "manager.catman.text": {
+        "message": "TbSync synchronizuje r?wnie? kategorie kontakt?w, kt?re s? pot??nym zamiennikiem dla niesynchronizowanych list kontakt?w. Aby m?c z nich korzysta? w ksi??ce adresowej Thunderbird, mo?esz zainstalowa? dodatek Category Manager. Pozwala zarz?dza? nak?adaj?cymi si? grupami kontakt?w opartymi na kategoriach i zapewnia szereg innych funkcji zwi?zanych z kategoriami. Mo?na go znale?? w oficjalnym repozytorium dodatk?w Mozilla:"
+    },
+    "manager.community": {
+        "message": "Spo?eczno??"
+    },
+    "manager.connecting": {
+        "message": "??czenie z serwerem"
+    },
+    "manager.help": {
+        "message": "Pomoc"
+    },
+    "manager.help.createbugreport": {
+        "message": "Utw?rz raport o b??dzie"
+    },
+    "manager.help.createbugreportinfo": {
+        "message": "Aby TbSync zbiera? tylko dane debugowania istotne dla Twojego zg?oszenia b??du, uruchom ponownie Thunderbirda, a nast?pnie powt?rz dok?adnie kroki, kt?re odtworz? b??dne zachowanie. Nast?pnie mo?esz tutaj utworzy? raport o b??dzie."
+    },
+    "manager.help.debuglevel.0": {
+        "message": "Wy??czony"
+    },
+    "manager.help.debuglevel.1": {
+        "message": "W??czony: Rejestrowanie tylko b??d?w"
+    },
+    "manager.help.debuglevel.2": {
+        "message": "W??czony: Rejestrowanie wszystkich wys?anych i odebranych danych"
+    },
+    "manager.help.debuglevel.3": {
+        "message": "W??czone: Rejestrowanie wszystkich danych i niekt?rych wewn?trznych warto?ci debugowania"
+    },
+    "manager.help.debugmode": {
+        "message": "Tryb debugowania:"
+    },
+    "manager.help.fixit": {
+        "message": "Mo?esz pom?c to naprawi?, wysy?aj?c raport o b??dzie. Wymaga to w??czenia trybu debugowania."
+    },
+    "manager.help.foundabug": {
+        "message": "Znalaz?e? b??d?"
+    },
+    "manager.help.needhelp": {
+        "message": "Potrzebujesz pomocy?"
+    },
+    "manager.help.viewdebuglog": {
+        "message": "Zobacz log debugowania"
+    },
+    "manager.help.wiki": {
+        "message": "Otw?rz strony wiki projektu TbSync, zawieraj? one dodatkowe informacje, przewodniki i szczeg??owe opisy konfiguracji."
+    },
+    "manager.installprovider.link": {
+        "message": "Kliknij poni?szy link, aby otworzy? stron? informacyjn? brakuj?cego dostawcy synchronizacji. Znajdziesz tam dodatkowe informacje na temat dostawcy i b?dziesz m?g? go zainstalowa?:"
+    },
+    "manager.installprovider.warning": {
+        "message": "Ten dostawca synchronizacji nie jest udost?pniony w oficjalnym repozytorium dodatk?w Thunderbird, a zatem nie zosta? sprawdzony przez pracownik?w Thunderbirda. Dostawca mo?e wyrz?dzi? szkody w Twoim systemie. U?ywaj go na w?asne ryzyko."
+    },
+    "manager.lockedsettings.description": {
+        "message": "Aby zapobiec b??dom synchronizacji, niekt?rych ustawie? nie mo?na edytowa?, gdy konto jest w??czone."
+    },
+    "manager.missingprovider": {
+        "message": "To konto wymaga dostawcy synchronizacji ##provider##, kt?ry obecnie nie jest zainstalowany."
+    },
+    "manager.noaccounts": {
+        "message": "Nie ma jeszcze zdefiniowanych kont."
+    },
+    "manager.provider": {
+        "message": "Zainstaluj dostawc?"
+    },
+    "manager.provider4tbsync": {
+        "message": "Dostawca dla TbSync"
+    },
+    "manager.resource": {
+        "message": "Zas?b"
+    },
+    "manager.shorttitle": {
+        "message": "Mened?er konta"
+    },
+    "manager.status": {
+        "message": "Status"
+    },
+    "manager.supporter.contributors": {
+        "message": "Wsp??pracownicy i T?umacze"
+    },
+    "manager.supporter.details": {
+        "message": "Szczeg??y"
+    },
+    "manager.supporter.sponsors": {
+        "message": "Sponsorzy kont testowych"
+    },
+    "manager.tabs.status": {
+        "message": "Status synchronizacji"
+    },
+    "manager.tabs.status.autotime": {
+        "message": "Okresowa synchronizacja (w minutach)"
+    },
+    "manager.tabs.status.enableThisAccount": {
+        "message": "W??cz i synchronizuj to konto"
+    },
+    "manager.tabs.status.general": {
+        "message": "Og?lne"
+    },
+    "manager.tabs.status.never": {
+        "message": "Ustawienie 0 wy??cza okresow? synchronizacj?. Synchronizacja push nie jest jeszcze zaimplementowana."
+    },
+    "manager.tabs.status.resources": {
+        "message": "Dost?pne zasoby"
+    },
+    "manager.tabs.status.resources.intro": {
+        "message": "Wybierz, kt?re ze znalezionych zasob?w powinny by? zsynchronizowane z Thunderbirdem."
+    },
+    "manager.tabs.status.sync": {
+        "message": "Synchronizuj teraz"
+    },
+    "manager.tabs.status.tryagain": {
+        "message": "Spr?buj ponownie po??czy? z serwerem"
+    },
+    "manager.title": {
+        "message": "Mened?er konta TbSync"
+    },
+    "manager.tryagain": {
+        "message": "Spr?buj ponownie po??czy? z serwerem"
+    },
+    "menu.settingslabel": {
+        "message": "Ustawienia synchronizacji (TbSync)"
+    },
+    "password.account": {
+        "message": "Konto:"
+    },
+    "password.description": {
+        "message": "Zaktualizuj dane logowania dla nast?puj?cego konta TbSync:"
+    },
+    "password.password": {
+        "message": "Has?o:"
+    },
+    "password.title": {
+        "message": "??danie Danych Logowania TbSync"
+    },
+    "password.user": {
+        "message": "U?ytkownik:"
+    },
+    "popup.opensettings": {
+        "message": "Otw?rz mened?er konta TbSync"
+    },
+    "prompt.DeleteAccount": {
+        "message": "Czy na pewno chcesz usun?? konto ##accountName##?"
+    },
+    "prompt.Disable": {
+        "message": "Czy na pewno chcesz wy??czy? to konto? Wszystkie lokalne modyfikacje, kt?re nie zosta?y jeszcze zsynchronizowane, zostan? utracone!"
+    },
+    "prompt.Erase": {
+        "message": "Czy jeste? pewien, ?e chcesz usun?? to konto nieznanego dostawcy z list kont?"
+    },
+    "prompt.Unsubscribe": {
+        "message": "Czy na pewno chcesz anulowa? subskrypcj? tego elementu? Wszystkie lokalne modyfikacje, kt?re nie zosta?y jeszcze zsynchronizowane, zostan? utracone!"
+    },
+    "status.JavaScriptError": {
+        "message": "B??d Javascript! Sprawd? dziennik zdarze?, aby uzyska? wi?cej informacji."
+    },
+    "status.OAuthAbortError": {
+        "message": "Proces uwierzytelniania OAuth 2.0 przerwany przez u?ytkownika."
+    },
+    "status.OAuthHttpError": {
+        "message": "Proces uwierzytelniania OAuth 2.0 nie powi?d? si? (b??d HTTP ##replace.1##)."
+    },
+    "status.OAuthNetworkError": {
+        "message": "Nie mo?na po??czy? si? z serwerem uwierzytelniania OAuth 2.0."
+    },
+    "status.OAuthServerError": {
+        "message": " Serwer uwierzytelniania OAuth 2.0 zwr?ci?: ##replace.1##"
+    },
+    "status.aborted": {
+        "message": "Nie zsynchronizowane"
+    },
+    "status.apiError": {
+        "message": "B??d implementacji API"
+    },
+    "status.disabled": {
+        "message": "Konto nie jest w??czone, synchronizacja jest wy??czona."
+    },
+    "status.foldererror": {
+        "message": "Przynajmniej jeden zas?b napotka? b??d synchronizacji. Sprawd? dziennik zdarze?, aby uzyska? wi?cej informacji."
+    },
+    "status.modified": {
+        "message": "Zmiany lokalne"
+    },
+    "status.network": {
+        "message": "Nie mo?na po??czy? z serwerem (##replace.1##)."
+    },
+    "status.no-folders-found-on-server": {
+        "message": "Nie mo?na znale?? ?adnych zasob?w na serwerze."
+    },
+    "status.notargets": {
+        "message": "Przerywanie synchronizacji, poniewa? nie mo?na utworzy? cel?w synchronizacji."
+    },
+    "status.notsyncronized": {
+        "message": "Konto musi zosta? zsynchronizowane, co najmniej jeden element nie jest zsynchronizowany."
+    },
+    "status.pending": {
+        "message": "Oczekiwanie na synchronizacj?"
+    },
+    "status.security": {
+        "message": "Nie mo?na ustanowi? bezpiecznego po??czenia. Czy u?ywasz certyfikatu self-signed lub innego niezaufanego certyfikatu bez importowania go do Thunderbirda? (##replace.1##)"
+    },
+    "status.skipped": {
+        "message": "Jeszcze nie wspierane, pomini?to"
+    },
+    "status.success": {
+        "message": "OK"
+    },
+    "status.syncing": {
+        "message": "Synchronizuj?"
+    },
+    "status.451": {
+        "message": "Server issued redirect, retry in 5 seconds."
+    },
+    "supportwizard.footer": {
+        "message": "Z podanych tutaj informacji w nast?pnym kroku zostanie wygenerowany e-mail, kt?ry mo?esz nast?pnie edytowa? (na przyk?ad dodaj?c zrzuty ekranu lub podobne). Tylko poprzez faktyczne wys?anie tej wiadomo?ci zostanie wys?any raport o b??dzie."
+    },
+    "supportwizard.label.description": {
+        "message": "Szczeg??owy opis b??du:"
+    },
+    "supportwizard.label.faultycomponent": {
+        "message": "Sk?adnik TbSync, w kt?rym zaobserwowano b??d:"
+    },
+    "supportwizard.label.selectcomponent": {
+        "message": "Wybierz sk?adnik?"
+    },
+    "supportwizard.label.summary": {
+        "message": "Kr?tkie podsumowanie b??du:"
+    },
+    "supportwizard.pagetitle": {
+        "message": "Zbieranie wszystkich informacji w celu skutecznego przetworzenia zg?oszenia b??du."
+    },
+    "supportwizard.provider": {
+        "message": "Dostawca: ##replace.1##"
+    },
+    "supportwizard.title": {
+        "message": "Utw?rz raport o b??dzie"
+    },
+    "syncstate.accountdone": {
+        "message": "Konto gotowe"
+    },
+    "syncstate.done": {
+        "message": "Przygotowuj? nast?pny element do synchronizacji"
+    },
+    "syncstate.oauthprompt": {
+        "message": "Uwierzytelnianie OAuth 2.0"
+    },
+    "syncstate.passwordprompt": {
+        "message": "Monitowanie o dane logowania"
+    },
+    "syncstate.preparing": {
+        "message": "Przygotowuj? nast?pny element do synchronizacji"
+    },
+    "syncstate.syncing": {
+        "message": "Zainicjuj synchronizacj?"
+    },
+    "target.orphaned": {
+        "message": "Roz??czony"
+    },
+    "toolbar.label": {
+        "message": "Synchronizuj wszystkie konta TbSync"
+    },
+    "toolbar.tooltiptext": {
+        "message": "Synchronizuj najnowsze zmiany"
+    },
+    "password.ok": {
+        "message": "OK"
+    },
+    "password.cancel": {
+        "message": "Anuluj"
+    }
+}
diff -Nru tbsync-4.12/_locales/pt_BR/messages.json tbsync-4.16/_locales/pt_BR/messages.json
--- tbsync-4.12/_locales/pt_BR/messages.json	2024-08-27 18:32:08.000000000 +0200
+++ tbsync-4.16/_locales/pt_BR/messages.json	2024-08-27 18:29:06.000000000 +0200
@@ -1,368 +1,368 @@
-{
-    "HelpFixStartupError": {
-        "message": "Para ajudar a corrigir esse erro, voc? poderia enviar um log de depura??o para o desenvolvedor do TbSync. Enviar esse email agora?"
-    },
-    "NoDebugLog": {
-        "message": "N?o foi poss?vel encontrar nenhuma mensagem de depura??o ?til. Por favor, ative o modo de depura??o, reinicie o Thunderbird e repita todas as etapas necess?rias para acionar o comportamento errado."
-    },
-    "OopsMessage": {
-        "message": "Erro! O TbSync n?o pode iniciar!"
-    },
-    "RestartThunderbirdAndTryAgain": {
-        "message": "O log de depura??o do TbSync foi ativado, reinicie o Thunderbird e tente abrir novamente o TbSync."
-    },
-    "UnableToTraceError": {
-        "message": "N?o ? poss?vel rastrear este erro, porque o log de depura??o n?o est? habilitado no momento. Deseja ativar o log de depura??o agora para ajudar a corrigir esse erro?"
-    },
-    "accountacctions.delete": {
-        "message": "Excluir conta '##accountname##'"
-    },
-    "accountacctions.disable": {
-        "message": "Desativar conta '##accountname##'"
-    },
-    "accountacctions.enable": {
-        "message": "Ativar conta '##accountname##' e tentar conectar-se ao servidor"
-    },
-    "accountacctions.sync": {
-        "message": "Sincronizar conta '##accountname##'"
-    },
-    "addressbook.searchall": {
-        "message": "Pesquisar todos os cat?logos de endere?os"
-    },
-    "addressbook.searchgal": {
-        "message": "Pesquisar este cat?logo de endere?os e o diret?rio global (##replace.1##)"
-    },
-    "addressbook.searchthis": {
-        "message": "Pesquisar este cat?logo de endere?os"
-    },
-    "eventlog.clear": {
-        "message": "Limpar"
-    },
-    "eventlog.close": {
-        "message": "Fechar"
-    },
-    "eventlog.title": {
-        "message": "log de eventos"
-    },
-    "extensionDescription": {
-        "message": "O TbSync ? uma central para gerenciar contas em nuvem e para sincronizar as informa??es de contatos, tarefas e calend?rios com o Thunderbird."
-    },
-    "google.translate.code": {
-        "message": "pt"
-    },
-    "helplink.security": {
-        "message": "https://github.com/jobisoft/TbSync/wiki/How-to-use-TbSync-with-self-signed-or-otherwise-untrusted-certificates%3F"
-    },
-    "info.error": {
-        "message": "Erro"
-    },
-    "info.idle": {
-        "message": "Ocioso"
-    },
-    "installProvider.header": {
-        "message": "O provedor '##replace.1##' para o TbSync ainda n?o est? instalado."
-    },
-    "manager.AccountActions": {
-        "message": "A??es da conta"
-    },
-    "manager.AddAccount": {
-        "message": "Adicionar nova conta"
-    },
-    "manager.DeleteAccount": {
-        "message": "Excluir conta"
-    },
-    "manager.DisableAccount": {
-        "message": "Desativar conta"
-    },
-    "manager.EnableAccount": {
-        "message": "Ativar conta e tentar conectar ao servidor"
-    },
-    "manager.RetryConnectAccount": {
-        "message": "Tentar conectar no servidor novamente"
-    },
-    "manager.ShowEventLog": {
-        "message": "Mostrar log de eventos"
-    },
-    "manager.SyncAll": {
-        "message": "Sincronizar todas as contas ativadas"
-    },
-    "manager.SynchronizeAccount": {
-        "message": "Sincronizar conta"
-    },
-    "manager.accounts": {
-        "message": "Contas"
-    },
-    "manager.accountsettings": {
-        "message": "Configura??es da conta"
-    },
-    "manager.catman.text": {
-        "message": "O TbSync tamb?m sincroniza as categorias de contatos, que s?o um poderoso substituto para as listas de contatos n?o sincroniz?veis. Para poder us?-los no cat?logo de endere?os do Thunderbird, voc? pode instalar o complemento do ?Category Manager?. Ele permite gerenciar grupos de contatos com base em categorias sobrepostas e fornece v?rios outros recursos relacionados a categorias. Pode ser encontrado no reposit?rio oficial do Mozilla:"
-    },
-    "manager.community": {
-        "message": "Comunidade"
-    },
-    "manager.connecting": {
-        "message": "Conectando ao servidor"
-    },
-    "manager.help": {
-        "message": "Ajuda"
-    },
-    "manager.help.createbugreport": {
-        "message": "Criar relat?rio de bug"
-    },
-    "manager.help.createbugreportinfo": {
-        "message": "Para que o TbSync colete apenas os dados de depura??o relevantes para o seu relat?rio de erros, reinicie o Thunderbird e repita exatamente as etapas que reproduzem o comportamento de bugs. Ent?o voc? pode criar seu relat?rio de bug aqui."
-    },
-    "manager.help.debuglevel.0": {
-        "message": "Desabilitado"
-    },
-    "manager.help.debuglevel.1": {
-        "message": "Habilitado: Somente registro de erros"
-    },
-    "manager.help.debuglevel.2": {
-        "message": "Habilitado: Registro de todos os dados enviados e recebidos"
-    },
-    "manager.help.debuglevel.3": {
-        "message": "Habilitado: Log de todos os dados e alguns valores de depura??o internos"
-    },
-    "manager.help.debugmode": {
-        "message": "Modo de depura??o:"
-    },
-    "manager.help.fixit": {
-        "message": "Voc? pode ajudar a consert?-lo enviando um relat?rio de bug. Isso requer a ativa??o do modo de depura??o."
-    },
-    "manager.help.foundabug": {
-        "message": "Encontrou um bug?"
-    },
-    "manager.help.needhelp": {
-        "message": "Precisa de ajuda?"
-    },
-    "manager.help.viewdebuglog": {
-        "message": "Exibir log de depura??o"
-    },
-    "manager.help.wiki": {
-        "message": "Abra as p?ginas wiki do projeto TbSync, eles fornecem informa??es adicionais, guias e descri??es detalhadas da configura??o."
-    },
-    "manager.installprovider.link": {
-        "message": "Clique no link a seguir para abrir a p?gina de informa??es do provedor de sincroniza??o ausente. L? voc? encontrar? mais informa??es sobre o provedor e ter? a op??o de instal?-lo:"
-    },
-    "manager.installprovider.warning": {
-        "message": "Este provedor de sincroniza??o n?o ? hospedado no reposit?rio oficial do Thunderbird e, portanto, n?o foi revisado pela equipe do Thunderbird. O provedor pode prejudicar o seu sistema. Use por sua conta e risco."
-    },
-    "manager.lockedsettings.description": {
-        "message": "Para evitar erros de sincroniza??o, algumas configura??es n?o podem ser editadas enquanto a conta est? ativada."
-    },
-    "manager.missingprovider": {
-        "message": "Essa conta requer o provedor de sincroniza??o ##provider##, que atualmente n?o est? instalado."
-    },
-    "manager.noaccounts": {
-        "message": "N?o existem contas definidas."
-    },
-    "manager.provider": {
-        "message": "Instalar provedor"
-    },
-    "manager.provider4tbsync": {
-        "message": "Provedor para o TbSync"
-    },
-    "manager.resource": {
-        "message": "Recurso"
-    },
-    "manager.shorttitle": {
-        "message": "Gerenciar conta"
-    },
-    "manager.status": {
-        "message": "Status"
-    },
-    "manager.supporter.contributors": {
-        "message": "Contribuidores e Tradutores"
-    },
-    "manager.supporter.details": {
-        "message": "Detalhes"
-    },
-    "manager.supporter.sponsors": {
-        "message": "Patrocinadores de contas de teste"
-    },
-    "manager.tabs.status": {
-        "message": "Status de sincroniza??o"
-    },
-    "manager.tabs.status.autotime": {
-        "message": "Sincroniza??o peri?dica (em minutos)"
-    },
-    "manager.tabs.status.enableThisAccount": {
-        "message": "Ativar e sincronizar esta conta"
-    },
-    "manager.tabs.status.general": {
-        "message": "Geral"
-    },
-    "manager.tabs.status.never": {
-        "message": "Deixar a configura??o como 0 desabilita a sincroniza??o peri?dica. A sincroniza??o push ainda n?o est? implementada."
-    },
-    "manager.tabs.status.resources": {
-        "message": "Recursos dispon?veis"
-    },
-    "manager.tabs.status.resources.intro": {
-        "message": "Selecione qual dos recursos encontrados deve ser sincronizado com o Thunderbird."
-    },
-    "manager.tabs.status.sync": {
-        "message": "Sincronizar agora"
-    },
-    "manager.tabs.status.tryagain": {
-        "message": "Tente conectar no servidor novamente"
-    },
-    "manager.title": {
-        "message": "Gerenciador de contas do TbSync"
-    },
-    "manager.tryagain": {
-        "message": "Tente conectar no servidor novamente"
-    },
-    "menu.settingslabel": {
-        "message": "Configura??es de sincroniza??o (TbSync)"
-    },
-    "password.account": {
-        "message": "Conta:"
-    },
-    "password.description": {
-        "message": "Por favor, atualize as credenciais para a seguinte conta TbSync:"
-    },
-    "password.password": {
-        "message": "Senha:"
-    },
-    "password.title": {
-        "message": "Solicita??o de Credencial do TbSync"
-    },
-    "password.user": {
-        "message": "Usu?rio:"
-    },
-    "popup.opensettings": {
-        "message": "Abra o gerenciador de contas do TbSync"
-    },
-    "prompt.DeleteAccount": {
-        "message": "Tem certeza de que deseja excluir a conta ##accountName##?"
-    },
-    "prompt.Disable": {
-        "message": "Tem certeza de que deseja desativar esta conta? Todas as modifica??es locais, que ainda n?o foram sincronizadas, ser?o perdidas!"
-    },
-    "prompt.Erase": {
-        "message": "Tem certeza de que deseja remover essa conta de um provedor desconhecido das listas de contas?"
-    },
-    "prompt.Unsubscribe": {
-        "message": "Tem certeza de que deseja cancelar a inscri??o deste item? Todas as modifica??es locais, que ainda n?o foram sincronizadas, ser?o perdidas!"
-    },
-    "status.JavaScriptError": {
-        "message": "Erro de Javascript! Por favor, verifique o log de eventos para mais detalhes."
-    },
-    "status.OAuthAbortError": {
-        "message": "Processo de autentica??o OAuth 2.0 abortado pelo usu?rio."
-    },
-    "status.OAuthHttpError": {
-        "message": "O processo de autentica??o OAuth 2.0 falhou (HTTP error ##replace.1##)."
-    },
-    "status.OAuthNetworkError": {
-        "message": "N?o foi poss?vel conectar ao servidor de autentica??o OAuth 2.0."
-    },
-    "status.OAuthServerError": {
-        "message": " O servidor de autentica??o OAuth 2.0 retornou: ##replace.1##"
-    },
-    "status.aborted": {
-        "message": "N?o sincronizado"
-    },
-    "status.apiError": {
-        "message": "Erro de implementa??o da API"
-    },
-    "status.disabled": {
-        "message": "A conta n?o est? ativada, a sincroniza??o est? desativada."
-    },
-    "status.foldererror": {
-        "message": "Pelo menos um recurso encontrou um erro de sincroniza??o. Por favor, verifique o log de eventos para mais detalhes."
-    },
-    "status.modified": {
-        "message": "Modifica??es locais"
-    },
-    "status.network": {
-        "message": "N?o foi poss?vel conectar-se ao servidor (##replace.1##)."
-    },
-    "status.no-folders-found-on-server": {
-        "message": "N?o foi poss?vel encontrar nenhum recurso no servidor."
-    },
-    "status.notargets": {
-        "message": "Anulando a sincroniza??o, porque os destinos de sincroniza??o n?o puderam ser criados."
-    },
-    "status.notsyncronized": {
-        "message": "Conta precisa ser sincronizada, pelo menos, um item n?o est? sincronizado."
-    },
-    "status.pending": {
-        "message": "Aguardando para ser sincronizado"
-    },
-    "status.security": {
-        "message": "N?o foi poss?vel estabelecer uma conex?o segura. Voc? est? usando um certificado autoassinado ou n?o confi?vel sem import?-lo para o Thunderbird? (##replace.1##)"
-    },
-    "status.skipped": {
-        "message": "Ainda n?o suportado, ignorado"
-    },
-    "status.success": {
-        "message": "OK"
-    },
-    "status.syncing": {
-        "message": "Sincronizando"
-    },
-    "status.451": {
-        "message": "Server issued redirect, retry in 5 seconds."
-    },
-    "supportwizard.footer": {
-        "message": "A partir das informa??es fornecidas aqui, um e-mail ser? gerado na pr?xima etapa, que voc? pode editar posteriormente (por exemplo, adicionando capturas de tela ou similar). Apenas enviando esse e-mail, o relat?rio de erro ser? enviado."
-    },
-    "supportwizard.label.description": {
-        "message": "Descri??o detalhada do erro:"
-    },
-    "supportwizard.label.faultycomponent": {
-        "message": "Componente do TbSync onde voc? observou o erro:"
-    },
-    "supportwizard.label.selectcomponent": {
-        "message": "Selecione o componente..."
-    },
-    "supportwizard.label.summary": {
-        "message": "Breve resumo do erro:"
-    },
-    "supportwizard.pagetitle": {
-        "message": "Coletar todas as informa??es para processar efetivamente o relat?rio de erros."
-    },
-    "supportwizard.provider": {
-        "message": "Provedor: ##replace.1##"
-    },
-    "supportwizard.title": {
-        "message": "Criar relat?rio de bug"
-    },
-    "syncstate.accountdone": {
-        "message": "Conta finalizada"
-    },
-    "syncstate.done": {
-        "message": "Preparando o pr?ximo item para sincroniza??o"
-    },
-    "syncstate.oauthprompt": {
-        "message": "Autentica??o OAuth 2.0"
-    },
-    "syncstate.passwordprompt": {
-        "message": "Solicita??o para inserir credenciais"
-    },
-    "syncstate.preparing": {
-        "message": "Preparando o pr?ximo item para sincroniza??o"
-    },
-    "syncstate.syncing": {
-        "message": "Inicializar sincroniza??o"
-    },
-    "target.orphaned": {
-        "message": "Conex?o desconectada"
-    },
-    "toolbar.label": {
-        "message": "Sincronizar todas as contas do TbSync"
-    },
-    "toolbar.tooltiptext": {
-        "message": "Sincronizar as altera??es mais recentes"
-    },
-    "password.ok": {
-        "message": "OK"
-    },
-    "password.cancel": {
-        "message": "Cancelar"
-    }
-}
+{
+    "HelpFixStartupError": {
+        "message": "Para ajudar a corrigir esse erro, voc? poderia enviar um log de depura??o para o desenvolvedor do TbSync. Enviar esse email agora?"
+    },
+    "NoDebugLog": {
+        "message": "N?o foi poss?vel encontrar nenhuma mensagem de depura??o ?til. Por favor, ative o modo de depura??o, reinicie o Thunderbird e repita todas as etapas necess?rias para acionar o comportamento errado."
+    },
+    "OopsMessage": {
+        "message": "Erro! O TbSync n?o pode iniciar!"
+    },
+    "RestartThunderbirdAndTryAgain": {
+        "message": "O log de depura??o do TbSync foi ativado, reinicie o Thunderbird e tente abrir novamente o TbSync."
+    },
+    "UnableToTraceError": {
+        "message": "N?o ? poss?vel rastrear este erro, porque o log de depura??o n?o est? habilitado no momento. Deseja ativar o log de depura??o agora para ajudar a corrigir esse erro?"
+    },
+    "accountacctions.delete": {
+        "message": "Excluir conta '##accountname##'"
+    },
+    "accountacctions.disable": {
+        "message": "Desativar conta '##accountname##'"
+    },
+    "accountacctions.enable": {
+        "message": "Ativar conta '##accountname##' e tentar conectar-se ao servidor"
+    },
+    "accountacctions.sync": {
+        "message": "Sincronizar conta '##accountname##'"
+    },
+    "addressbook.searchall": {
+        "message": "Pesquisar todos os cat?logos de endere?os"
+    },
+    "addressbook.searchgal": {
+        "message": "Pesquisar este cat?logo de endere?os e o diret?rio global (##replace.1##)"
+    },
+    "addressbook.searchthis": {
+        "message": "Pesquisar este cat?logo de endere?os"
+    },
+    "eventlog.clear": {
+        "message": "Limpar"
+    },
+    "eventlog.close": {
+        "message": "Fechar"
+    },
+    "eventlog.title": {
+        "message": "log de eventos"
+    },
+    "extensionDescription": {
+        "message": "O TbSync ? uma central para gerenciar contas em nuvem e para sincronizar as informa??es de contatos, tarefas e calend?rios com o Thunderbird."
+    },
+    "google.translate.code": {
+        "message": "pt"
+    },
+    "helplink.security": {
+        "message": "https://github.com/jobisoft/TbSync/wiki/How-to-use-TbSync-with-self-signed-or-otherwise-untrusted-certificates%3F"
+    },
+    "info.error": {
+        "message": "Erro"
+    },
+    "info.idle": {
+        "message": "Ocioso"
+    },
+    "installProvider.header": {
+        "message": "O provedor '##replace.1##' para o TbSync ainda n?o est? instalado."
+    },
+    "manager.AccountActions": {
+        "message": "A??es da conta"
+    },
+    "manager.AddAccount": {
+        "message": "Adicionar nova conta"
+    },
+    "manager.DeleteAccount": {
+        "message": "Excluir conta"
+    },
+    "manager.DisableAccount": {
+        "message": "Desativar conta"
+    },
+    "manager.EnableAccount": {
+        "message": "Ativar conta e tentar conectar ao servidor"
+    },
+    "manager.RetryConnectAccount": {
+        "message": "Tentar conectar no servidor novamente"
+    },
+    "manager.ShowEventLog": {
+        "message": "Mostrar log de eventos"
+    },
+    "manager.SyncAll": {
+        "message": "Sincronizar todas as contas ativadas"
+    },
+    "manager.SynchronizeAccount": {
+        "message": "Sincronizar conta"
+    },
+    "manager.accounts": {
+        "message": "Contas"
+    },
+    "manager.accountsettings": {
+        "message": "Configura??es da conta"
+    },
+    "manager.catman.text": {
+        "message": "O TbSync tamb?m sincroniza as categorias de contatos, que s?o um poderoso substituto para as listas de contatos n?o sincroniz?veis. Para poder us?-los no cat?logo de endere?os do Thunderbird, voc? pode instalar o complemento do ?Category Manager?. Ele permite gerenciar grupos de contatos com base em categorias sobrepostas e fornece v?rios outros recursos relacionados a categorias. Pode ser encontrado no reposit?rio oficial do Mozilla:"
+    },
+    "manager.community": {
+        "message": "Comunidade"
+    },
+    "manager.connecting": {
+        "message": "Conectando ao servidor"
+    },
+    "manager.help": {
+        "message": "Ajuda"
+    },
+    "manager.help.createbugreport": {
+        "message": "Criar relat?rio de bug"
+    },
+    "manager.help.createbugreportinfo": {
+        "message": "Para que o TbSync colete apenas os dados de depura??o relevantes para o seu relat?rio de erros, reinicie o Thunderbird e repita exatamente as etapas que reproduzem o comportamento de bugs. Ent?o voc? pode criar seu relat?rio de bug aqui."
+    },
+    "manager.help.debuglevel.0": {
+        "message": "Desabilitado"
+    },
+    "manager.help.debuglevel.1": {
+        "message": "Habilitado: Somente registro de erros"
+    },
+    "manager.help.debuglevel.2": {
+        "message": "Habilitado: Registro de todos os dados enviados e recebidos"
+    },
+    "manager.help.debuglevel.3": {
+        "message": "Habilitado: Log de todos os dados e alguns valores de depura??o internos"
+    },
+    "manager.help.debugmode": {
+        "message": "Modo de depura??o:"
+    },
+    "manager.help.fixit": {
+        "message": "Voc? pode ajudar a consert?-lo enviando um relat?rio de bug. Isso requer a ativa??o do modo de depura??o."
+    },
+    "manager.help.foundabug": {
+        "message": "Encontrou um bug?"
+    },
+    "manager.help.needhelp": {
+        "message": "Precisa de ajuda?"
+    },
+    "manager.help.viewdebuglog": {
+        "message": "Exibir log de depura??o"
+    },
+    "manager.help.wiki": {
+        "message": "Abra as p?ginas wiki do projeto TbSync, eles fornecem informa??es adicionais, guias e descri??es detalhadas da configura??o."
+    },
+    "manager.installprovider.link": {
+        "message": "Clique no link a seguir para abrir a p?gina de informa??es do provedor de sincroniza??o ausente. L? voc? encontrar? mais informa??es sobre o provedor e ter? a op??o de instal?-lo:"
+    },
+    "manager.installprovider.warning": {
+        "message": "Este provedor de sincroniza??o n?o ? hospedado no reposit?rio oficial do Thunderbird e, portanto, n?o foi revisado pela equipe do Thunderbird. O provedor pode prejudicar o seu sistema. Use por sua conta e risco."
+    },
+    "manager.lockedsettings.description": {
+        "message": "Para evitar erros de sincroniza??o, algumas configura??es n?o podem ser editadas enquanto a conta est? ativada."
+    },
+    "manager.missingprovider": {
+        "message": "Essa conta requer o provedor de sincroniza??o ##provider##, que atualmente n?o est? instalado."
+    },
+    "manager.noaccounts": {
+        "message": "N?o existem contas definidas."
+    },
+    "manager.provider": {
+        "message": "Instalar provedor"
+    },
+    "manager.provider4tbsync": {
+        "message": "Provedor para o TbSync"
+    },
+    "manager.resource": {
+        "message": "Recurso"
+    },
+    "manager.shorttitle": {
+        "message": "Gerenciar conta"
+    },
+    "manager.status": {
+        "message": "Status"
+    },
+    "manager.supporter.contributors": {
+        "message": "Contribuidores e Tradutores"
+    },
+    "manager.supporter.details": {
+        "message": "Detalhes"
+    },
+    "manager.supporter.sponsors": {
+        "message": "Patrocinadores de contas de teste"
+    },
+    "manager.tabs.status": {
+        "message": "Status de sincroniza??o"
+    },
+    "manager.tabs.status.autotime": {
+        "message": "Sincroniza??o peri?dica (em minutos)"
+    },
+    "manager.tabs.status.enableThisAccount": {
+        "message": "Ativar e sincronizar esta conta"
+    },
+    "manager.tabs.status.general": {
+        "message": "Geral"
+    },
+    "manager.tabs.status.never": {
+        "message": "Deixar a configura??o como 0 desabilita a sincroniza??o peri?dica. A sincroniza??o push ainda n?o est? implementada."
+    },
+    "manager.tabs.status.resources": {
+        "message": "Recursos dispon?veis"
+    },
+    "manager.tabs.status.resources.intro": {
+        "message": "Selecione qual dos recursos encontrados deve ser sincronizado com o Thunderbird."
+    },
+    "manager.tabs.status.sync": {
+        "message": "Sincronizar agora"
+    },
+    "manager.tabs.status.tryagain": {
+        "message": "Tente conectar no servidor novamente"
+    },
+    "manager.title": {
+        "message": "Gerenciador de contas do TbSync"
+    },
+    "manager.tryagain": {
+        "message": "Tente conectar no servidor novamente"
+    },
+    "menu.settingslabel": {
+        "message": "Configura??es de sincroniza??o (TbSync)"
+    },
+    "password.account": {
+        "message": "Conta:"
+    },
+    "password.description": {
+        "message": "Por favor, atualize as credenciais para a seguinte conta TbSync:"
+    },
+    "password.password": {
+        "message": "Senha:"
+    },
+    "password.title": {
+        "message": "Solicita??o de Credencial do TbSync"
+    },
+    "password.user": {
+        "message": "Usu?rio:"
+    },
+    "popup.opensettings": {
+        "message": "Abra o gerenciador de contas do TbSync"
+    },
+    "prompt.DeleteAccount": {
+        "message": "Tem certeza de que deseja excluir a conta ##accountName##?"
+    },
+    "prompt.Disable": {
+        "message": "Tem certeza de que deseja desativar esta conta? Todas as modifica??es locais, que ainda n?o foram sincronizadas, ser?o perdidas!"
+    },
+    "prompt.Erase": {
+        "message": "Tem certeza de que deseja remover essa conta de um provedor desconhecido das listas de contas?"
+    },
+    "prompt.Unsubscribe": {
+        "message": "Tem certeza de que deseja cancelar a inscri??o deste item? Todas as modifica??es locais, que ainda n?o foram sincronizadas, ser?o perdidas!"
+    },
+    "status.JavaScriptError": {
+        "message": "Erro de Javascript! Por favor, verifique o log de eventos para mais detalhes."
+    },
+    "status.OAuthAbortError": {
+        "message": "Processo de autentica??o OAuth 2.0 abortado pelo usu?rio."
+    },
+    "status.OAuthHttpError": {
+        "message": "O processo de autentica??o OAuth 2.0 falhou (HTTP error ##replace.1##)."
+    },
+    "status.OAuthNetworkError": {
+        "message": "N?o foi poss?vel conectar ao servidor de autentica??o OAuth 2.0."
+    },
+    "status.OAuthServerError": {
+        "message": " O servidor de autentica??o OAuth 2.0 retornou: ##replace.1##"
+    },
+    "status.aborted": {
+        "message": "N?o sincronizado"
+    },
+    "status.apiError": {
+        "message": "Erro de implementa??o da API"
+    },
+    "status.disabled": {
+        "message": "A conta n?o est? ativada, a sincroniza??o est? desativada."
+    },
+    "status.foldererror": {
+        "message": "Pelo menos um recurso encontrou um erro de sincroniza??o. Por favor, verifique o log de eventos para mais detalhes."
+    },
+    "status.modified": {
+        "message": "Modifica??es locais"
+    },
+    "status.network": {
+        "message": "N?o foi poss?vel conectar-se ao servidor (##replace.1##)."
+    },
+    "status.no-folders-found-on-server": {
+        "message": "N?o foi poss?vel encontrar nenhum recurso no servidor."
+    },
+    "status.notargets": {
+        "message": "Anulando a sincroniza??o, porque os destinos de sincroniza??o n?o puderam ser criados."
+    },
+    "status.notsyncronized": {
+        "message": "Conta precisa ser sincronizada, pelo menos, um item n?o est? sincronizado."
+    },
+    "status.pending": {
+        "message": "Aguardando para ser sincronizado"
+    },
+    "status.security": {
+        "message": "N?o foi poss?vel estabelecer uma conex?o segura. Voc? est? usando um certificado autoassinado ou n?o confi?vel sem import?-lo para o Thunderbird? (##replace.1##)"
+    },
+    "status.skipped": {
+        "message": "Ainda n?o suportado, ignorado"
+    },
+    "status.success": {
+        "message": "OK"
+    },
+    "status.syncing": {
+        "message": "Sincronizando"
+    },
+    "status.451": {
+        "message": "Server issued redirect, retry in 5 seconds."
+    },
+    "supportwizard.footer": {
+        "message": "A partir das informa??es fornecidas aqui, um e-mail ser? gerado na pr?xima etapa, que voc? pode editar posteriormente (por exemplo, adicionando capturas de tela ou similar). Apenas enviando esse e-mail, o relat?rio de erro ser? enviado."
+    },
+    "supportwizard.label.description": {
+        "message": "Descri??o detalhada do erro:"
+    },
+    "supportwizard.label.faultycomponent": {
+        "message": "Componente do TbSync onde voc? observou o erro:"
+    },
+    "supportwizard.label.selectcomponent": {
+        "message": "Selecione o componente..."
+    },
+    "supportwizard.label.summary": {
+        "message": "Breve resumo do erro:"
+    },
+    "supportwizard.pagetitle": {
+        "message": "Coletar todas as informa??es para processar efetivamente o relat?rio de erros."
+    },
+    "supportwizard.provider": {
+        "message": "Provedor: ##replace.1##"
+    },
+    "supportwizard.title": {
+        "message": "Criar relat?rio de bug"
+    },
+    "syncstate.accountdone": {
+        "message": "Conta finalizada"
+    },
+    "syncstate.done": {
+        "message": "Preparando o pr?ximo item para sincroniza??o"
+    },
+    "syncstate.oauthprompt": {
+        "message": "Autentica??o OAuth 2.0"
+    },
+    "syncstate.passwordprompt": {
+        "message": "Solicita??o para inserir credenciais"
+    },
+    "syncstate.preparing": {
+        "message": "Preparando o pr?ximo item para sincroniza??o"
+    },
+    "syncstate.syncing": {
+        "message": "Inicializar sincroniza??o"
+    },
+    "target.orphaned": {
+        "message": "Conex?o desconectada"
+    },
+    "toolbar.label": {
+        "message": "Sincronizar todas as contas do TbSync"
+    },
+    "toolbar.tooltiptext": {
+        "message": "Sincronizar as altera??es mais recentes"
+    },
+    "password.ok": {
+        "message": "OK"
+    },
+    "password.cancel": {
+        "message": "Cancelar"
+    }
+}
diff -Nru tbsync-4.12/_locales/Readme.txt tbsync-4.16/_locales/Readme.txt
--- tbsync-4.12/_locales/Readme.txt	2024-08-27 18:32:08.000000000 +0200
+++ tbsync-4.16/_locales/Readme.txt	2021-08-30 18:31:42.000000000 +0200
@@ -1,8 +1,8 @@
-Want to add or fix a localization?
-
-To help translating this project, please visit 
-
-	https://crowdin.com/profile/jobisoft
-
-where the localizations are managed. If you want to add
-a new language, just contact me and I will set it up.
+Want to add or fix a localization?
+
+To help translating this project, please visit 
+
+	https://crowdin.com/profile/jobisoft
+
+where the localizations are managed. If you want to add
+a new language, just contact me and I will set it up.
diff -Nru tbsync-4.12/_locales/ro/messages.json tbsync-4.16/_locales/ro/messages.json
--- tbsync-4.12/_locales/ro/messages.json	2024-08-27 18:32:08.000000000 +0200
+++ tbsync-4.16/_locales/ro/messages.json	2024-08-27 18:29:06.000000000 +0200
@@ -1,368 +1,368 @@
-{
-    "HelpFixStartupError": {
-        "message": "To help fix this error, you could send a debug log to the TbSync developer. Prepare that email now?"
-    },
-    "NoDebugLog": {
-        "message": "Could not find any useful debug messages. Please activate debug mode, restart Thunderbird and repeat all the steps needed to trigger the erroneous behavior."
-    },
-    "OopsMessage": {
-        "message": "Oops! TbSync was not able to start!"
-    },
-    "RestartThunderbirdAndTryAgain": {
-        "message": "TbSync debug log has been enabled, please restart Thunderbird and again try to open TbSync."
-    },
-    "UnableToTraceError": {
-        "message": "It is not possible to trace this error, because debug log is currently not enabled. Do you want to enable debug log now, to help fix this error?"
-    },
-    "accountacctions.delete": {
-        "message": "Delete account ?##accountname##?"
-    },
-    "accountacctions.disable": {
-        "message": "Disable account ?##accountname##?"
-    },
-    "accountacctions.enable": {
-        "message": "Enable account ?##accountname##? & try to connect to server"
-    },
-    "accountacctions.sync": {
-        "message": "Synchronize account ?##accountname##?"
-    },
-    "addressbook.searchall": {
-        "message": "Search all address books"
-    },
-    "addressbook.searchgal": {
-        "message": "Search this address book and the global directory (##replace.1##)"
-    },
-    "addressbook.searchthis": {
-        "message": "Search this address book"
-    },
-    "eventlog.clear": {
-        "message": "Clear"
-    },
-    "eventlog.close": {
-        "message": "Close"
-    },
-    "eventlog.title": {
-        "message": "Event log"
-    },
-    "extensionDescription": {
-        "message": "TbSync is a central user interface to manage cloud accounts and to synchronize their contact, task and calendar information with Thunderbird."
-    },
-    "google.translate.code": {
-        "message": "en"
-    },
-    "helplink.security": {
-        "message": "https://github.com/jobisoft/TbSync/wiki/How-to-use-TbSync-with-self-signed-or-otherwise-untrusted-certificates%3F"
-    },
-    "info.error": {
-        "message": "Error"
-    },
-    "info.idle": {
-        "message": "Idle"
-    },
-    "installProvider.header": {
-        "message": "Provider ?##replace.1##? for TbSync is not yet installed."
-    },
-    "manager.AccountActions": {
-        "message": "Account actions"
-    },
-    "manager.AddAccount": {
-        "message": "Add new account"
-    },
-    "manager.DeleteAccount": {
-        "message": "Delete account"
-    },
-    "manager.DisableAccount": {
-        "message": "Disable account"
-    },
-    "manager.EnableAccount": {
-        "message": "Enable account & try to connect to server"
-    },
-    "manager.RetryConnectAccount": {
-        "message": "Try again to connect to server"
-    },
-    "manager.ShowEventLog": {
-        "message": "Open event log"
-    },
-    "manager.SyncAll": {
-        "message": "Synchronize all enabled accounts"
-    },
-    "manager.SynchronizeAccount": {
-        "message": "Synchronize account"
-    },
-    "manager.accounts": {
-        "message": "Accounts"
-    },
-    "manager.accountsettings": {
-        "message": "Account Settings"
-    },
-    "manager.catman.text": {
-        "message": "TbSync also syncs contact categories, which are a powerful replacement for the non-synchronizable contact lists. To be able to use them in the Thunderbird address book you can install the Category Manager add-on. It allows to manage overlapping category based contact groups and provides a bunch of other category-related features. It can be found in the official Mozilla add-on repository:"
-    },
-    "manager.community": {
-        "message": "Community"
-    },
-    "manager.connecting": {
-        "message": "Connecting to server"
-    },
-    "manager.help": {
-        "message": "Help"
-    },
-    "manager.help.createbugreport": {
-        "message": "Create bug report"
-    },
-    "manager.help.createbugreportinfo": {
-        "message": "In order for TbSync to collect only the debug data relevant to your bug report, please restart Thunderbird and then repeat exactly the steps that reproduce the buggy behavior. Then you can create your bug report here."
-    },
-    "manager.help.debuglevel.0": {
-        "message": "Disabled"
-    },
-    "manager.help.debuglevel.1": {
-        "message": "Enabled: Logging of errors only"
-    },
-    "manager.help.debuglevel.2": {
-        "message": "Enabled: Logging of all sent and received data"
-    },
-    "manager.help.debuglevel.3": {
-        "message": "Enabled: Logging of all data and some internal debug values"
-    },
-    "manager.help.debugmode": {
-        "message": "Debug mode:"
-    },
-    "manager.help.fixit": {
-        "message": "You can help to fix it by sending in a bug report. This requires the activation of debug mode."
-    },
-    "manager.help.foundabug": {
-        "message": "Found a bug?"
-    },
-    "manager.help.needhelp": {
-        "message": "Need Help?"
-    },
-    "manager.help.viewdebuglog": {
-        "message": "View debug log"
-    },
-    "manager.help.wiki": {
-        "message": "Open the wiki pages of the TbSync project, they provide additional information, guides and detailed configuration descriptions."
-    },
-    "manager.installprovider.link": {
-        "message": "Click on the following link to open the info page of the missing synchronization provider. There you will find further information about the provider and you will have the option to install it:"
-    },
-    "manager.installprovider.warning": {
-        "message": "This synchronization provider is not hosted in the official Thunderbird add-on repository and thus has not been reviewed by Thunderbird staff. The provider could do bad things to your system. Use it at your own risk."
-    },
-    "manager.lockedsettings.description": {
-        "message": "To prevent synchronization errors, some settings cannot be edited while the account is enabled."
-    },
-    "manager.missingprovider": {
-        "message": "This account requires the ##provider## synchronization provider, which is currently not installed."
-    },
-    "manager.noaccounts": {
-        "message": "There are not yet any accounts defined."
-    },
-    "manager.provider": {
-        "message": "Install Provider"
-    },
-    "manager.provider4tbsync": {
-        "message": "Provider for TbSync"
-    },
-    "manager.resource": {
-        "message": "Resource"
-    },
-    "manager.shorttitle": {
-        "message": "Account manager"
-    },
-    "manager.status": {
-        "message": "Status"
-    },
-    "manager.supporter.contributors": {
-        "message": "Contributors & Translators"
-    },
-    "manager.supporter.details": {
-        "message": "Details"
-    },
-    "manager.supporter.sponsors": {
-        "message": "Sponsors of test accounts"
-    },
-    "manager.tabs.status": {
-        "message": "Synchronization status"
-    },
-    "manager.tabs.status.autotime": {
-        "message": "Periodic synchronization (in minutes)"
-    },
-    "manager.tabs.status.enableThisAccount": {
-        "message": "Enable and synchronize this account"
-    },
-    "manager.tabs.status.general": {
-        "message": "General"
-    },
-    "manager.tabs.status.never": {
-        "message": "A setting of 0 disables periodic sync. Push sync is not yet implemented."
-    },
-    "manager.tabs.status.resources": {
-        "message": "Available resources"
-    },
-    "manager.tabs.status.resources.intro": {
-        "message": "Select which of the found resources should be synchronized with Thunderbird."
-    },
-    "manager.tabs.status.sync": {
-        "message": "Synchronize now"
-    },
-    "manager.tabs.status.tryagain": {
-        "message": "Try again to connect server"
-    },
-    "manager.title": {
-        "message": "TbSync account manager"
-    },
-    "manager.tryagain": {
-        "message": "Try again to connect server"
-    },
-    "menu.settingslabel": {
-        "message": "Synchronization Settings (TbSync)"
-    },
-    "password.account": {
-        "message": "Account:"
-    },
-    "password.description": {
-        "message": "Please update the credentials for the following TbSync account:"
-    },
-    "password.password": {
-        "message": "Password:"
-    },
-    "password.title": {
-        "message": "TbSync Credential Request"
-    },
-    "password.user": {
-        "message": "User:"
-    },
-    "popup.opensettings": {
-        "message": "Open TbSync account manager"
-    },
-    "prompt.DeleteAccount": {
-        "message": "Are you sure you want to delete account ##accountName##?"
-    },
-    "prompt.Disable": {
-        "message": "Are you sure you want to disable this account? All local modifications, which have not been synced yet, will be lost!"
-    },
-    "prompt.Erase": {
-        "message": "Are you sure you want to remove this account of an unknown provider from the accounts lists?"
-    },
-    "prompt.Unsubscribe": {
-        "message": "Are you sure you want to unsubscribe this item? All local modifications, which have not been synced yet, will be lost!"
-    },
-    "status.JavaScriptError": {
-        "message": "Javascript Error! Please check the event log for more details."
-    },
-    "status.OAuthAbortError": {
-        "message": "OAuth 2.0 authentication process aborted by user."
-    },
-    "status.OAuthHttpError": {
-        "message": "OAuth 2.0 authentication process failed (HTTP error ##replace.1##)."
-    },
-    "status.OAuthNetworkError": {
-        "message": "Could not connect to OAuth 2.0 authentication server."
-    },
-    "status.OAuthServerError": {
-        "message": " OAuth 2.0 authentication server returned: ##replace.1##"
-    },
-    "status.aborted": {
-        "message": "Not synchronized"
-    },
-    "status.apiError": {
-        "message": "API implementation error"
-    },
-    "status.disabled": {
-        "message": "Account is not enabled, synchronization is disabled."
-    },
-    "status.foldererror": {
-        "message": "At least one resource encountered a synchronization error. Please check the event log for more details."
-    },
-    "status.modified": {
-        "message": "Local modifications"
-    },
-    "status.network": {
-        "message": "Could not connect to server (##replace.1##)."
-    },
-    "status.no-folders-found-on-server": {
-        "message": "Could not find any resources on the server."
-    },
-    "status.notargets": {
-        "message": "Aborting synchronization, because sync targets could not be created."
-    },
-    "status.notsyncronized": {
-        "message": "Account needs to be synchronized, at least one item is out of sync."
-    },
-    "status.pending": {
-        "message": "Waiting to be synchronized"
-    },
-    "status.security": {
-        "message": "Could not establish a secure connection. Are you using a self-signed or otherwise untrusted certificate without importing it into Thunderbird? (##replace.1##)"
-    },
-    "status.skipped": {
-        "message": "Not yet supported, skipped"
-    },
-    "status.success": {
-        "message": "OK"
-    },
-    "status.syncing": {
-        "message": "Synchronizing"
-    },
-    "status.451": {
-        "message": "Server issued redirect, retry in 5 seconds."
-    },
-    "supportwizard.footer": {
-        "message": "From the information given here, an e-mail will be generated in the next step, which you can subsequently edit (for example, adding screenshots or similar). Only by actually sending that e-mail, the error report will be sent."
-    },
-    "supportwizard.label.description": {
-        "message": "Detailed error description:"
-    },
-    "supportwizard.label.faultycomponent": {
-        "message": "Component of TbSync where you have observed the error:"
-    },
-    "supportwizard.label.selectcomponent": {
-        "message": "Select component?"
-    },
-    "supportwizard.label.summary": {
-        "message": "Short summary of the error:"
-    },
-    "supportwizard.pagetitle": {
-        "message": "Gathering of all information to effectively process the bug report."
-    },
-    "supportwizard.provider": {
-        "message": "Provider: ##replace.1##"
-    },
-    "supportwizard.title": {
-        "message": "Create bug report"
-    },
-    "syncstate.accountdone": {
-        "message": "Finished account"
-    },
-    "syncstate.done": {
-        "message": "Preparing next item for synchronization"
-    },
-    "syncstate.oauthprompt": {
-        "message": "OAuth 2.0 authentication"
-    },
-    "syncstate.passwordprompt": {
-        "message": "Prompting for credentials"
-    },
-    "syncstate.preparing": {
-        "message": "Preparing next item for synchronization"
-    },
-    "syncstate.syncing": {
-        "message": "Initialize synchronization"
-    },
-    "target.orphaned": {
-        "message": "Disconnected"
-    },
-    "toolbar.label": {
-        "message": "Synchronize all TbSync accounts"
-    },
-    "toolbar.tooltiptext": {
-        "message": "Synchronize latest changes"
-    },
-    "password.ok": {
-        "message": "OK"
-    },
-    "password.cancel": {
-        "message": "Anulare"
-    }
-}
+{
+    "HelpFixStartupError": {
+        "message": "To help fix this error, you could send a debug log to the TbSync developer. Prepare that email now?"
+    },
+    "NoDebugLog": {
+        "message": "Could not find any useful debug messages. Please activate debug mode, restart Thunderbird and repeat all the steps needed to trigger the erroneous behavior."
+    },
+    "OopsMessage": {
+        "message": "Oops! TbSync was not able to start!"
+    },
+    "RestartThunderbirdAndTryAgain": {
+        "message": "TbSync debug log has been enabled, please restart Thunderbird and again try to open TbSync."
+    },
+    "UnableToTraceError": {
+        "message": "It is not possible to trace this error, because debug log is currently not enabled. Do you want to enable debug log now, to help fix this error?"
+    },
+    "accountacctions.delete": {
+        "message": "Delete account ?##accountname##?"
+    },
+    "accountacctions.disable": {
+        "message": "Disable account ?##accountname##?"
+    },
+    "accountacctions.enable": {
+        "message": "Enable account ?##accountname##? & try to connect to server"
+    },
+    "accountacctions.sync": {
+        "message": "Synchronize account ?##accountname##?"
+    },
+    "addressbook.searchall": {
+        "message": "Search all address books"
+    },
+    "addressbook.searchgal": {
+        "message": "Search this address book and the global directory (##replace.1##)"
+    },
+    "addressbook.searchthis": {
+        "message": "Search this address book"
+    },
+    "eventlog.clear": {
+        "message": "Clear"
+    },
+    "eventlog.close": {
+        "message": "Close"
+    },
+    "eventlog.title": {
+        "message": "Event log"
+    },
+    "extensionDescription": {
+        "message": "TbSync is a central user interface to manage cloud accounts and to synchronize their contact, task and calendar information with Thunderbird."
+    },
+    "google.translate.code": {
+        "message": "en"
+    },
+    "helplink.security": {
+        "message": "https://github.com/jobisoft/TbSync/wiki/How-to-use-TbSync-with-self-signed-or-otherwise-untrusted-certificates%3F"
+    },
+    "info.error": {
+        "message": "Error"
+    },
+    "info.idle": {
+        "message": "Idle"
+    },
+    "installProvider.header": {
+        "message": "Provider ?##replace.1##? for TbSync is not yet installed."
+    },
+    "manager.AccountActions": {
+        "message": "Account actions"
+    },
+    "manager.AddAccount": {
+        "message": "Add new account"
+    },
+    "manager.DeleteAccount": {
+        "message": "Delete account"
+    },
+    "manager.DisableAccount": {
+        "message": "Disable account"
+    },
+    "manager.EnableAccount": {
+        "message": "Enable account & try to connect to server"
+    },
+    "manager.RetryConnectAccount": {
+        "message": "Try again to connect to server"
+    },
+    "manager.ShowEventLog": {
+        "message": "Open event log"
+    },
+    "manager.SyncAll": {
+        "message": "Synchronize all enabled accounts"
+    },
+    "manager.SynchronizeAccount": {
+        "message": "Synchronize account"
+    },
+    "manager.accounts": {
+        "message": "Accounts"
+    },
+    "manager.accountsettings": {
+        "message": "Account Settings"
+    },
+    "manager.catman.text": {
+        "message": "TbSync also syncs contact categories, which are a powerful replacement for the non-synchronizable contact lists. To be able to use them in the Thunderbird address book you can install the Category Manager add-on. It allows to manage overlapping category based contact groups and provides a bunch of other category-related features. It can be found in the official Mozilla add-on repository:"
+    },
+    "manager.community": {
+        "message": "Community"
+    },
+    "manager.connecting": {
+        "message": "Connecting to server"
+    },
+    "manager.help": {
+        "message": "Help"
+    },
+    "manager.help.createbugreport": {
+        "message": "Create bug report"
+    },
+    "manager.help.createbugreportinfo": {
+        "message": "In order for TbSync to collect only the debug data relevant to your bug report, please restart Thunderbird and then repeat exactly the steps that reproduce the buggy behavior. Then you can create your bug report here."
+    },
+    "manager.help.debuglevel.0": {
+        "message": "Disabled"
+    },
+    "manager.help.debuglevel.1": {
+        "message": "Enabled: Logging of errors only"
+    },
+    "manager.help.debuglevel.2": {
+        "message": "Enabled: Logging of all sent and received data"
+    },
+    "manager.help.debuglevel.3": {
+        "message": "Enabled: Logging of all data and some internal debug values"
+    },
+    "manager.help.debugmode": {
+        "message": "Debug mode:"
+    },
+    "manager.help.fixit": {
+        "message": "You can help to fix it by sending in a bug report. This requires the activation of debug mode."
+    },
+    "manager.help.foundabug": {
+        "message": "Found a bug?"
+    },
+    "manager.help.needhelp": {
+        "message": "Need Help?"
+    },
+    "manager.help.viewdebuglog": {
+        "message": "View debug log"
+    },
+    "manager.help.wiki": {
+        "message": "Open the wiki pages of the TbSync project, they provide additional information, guides and detailed configuration descriptions."
+    },
+    "manager.installprovider.link": {
+        "message": "Click on the following link to open the info page of the missing synchronization provider. There you will find further information about the provider and you will have the option to install it:"
+    },
+    "manager.installprovider.warning": {
+        "message": "This synchronization provider is not hosted in the official Thunderbird add-on repository and thus has not been reviewed by Thunderbird staff. The provider could do bad things to your system. Use it at your own risk."
+    },
+    "manager.lockedsettings.description": {
+        "message": "To prevent synchronization errors, some settings cannot be edited while the account is enabled."
+    },
+    "manager.missingprovider": {
+        "message": "This account requires the ##provider## synchronization provider, which is currently not installed."
+    },
+    "manager.noaccounts": {
+        "message": "There are not yet any accounts defined."
+    },
+    "manager.provider": {
+        "message": "Install Provider"
+    },
+    "manager.provider4tbsync": {
+        "message": "Provider for TbSync"
+    },
+    "manager.resource": {
+        "message": "Resource"
+    },
+    "manager.shorttitle": {
+        "message": "Account manager"
+    },
+    "manager.status": {
+        "message": "Status"
+    },
+    "manager.supporter.contributors": {
+        "message": "Contributors & Translators"
+    },
+    "manager.supporter.details": {
+        "message": "Details"
+    },
+    "manager.supporter.sponsors": {
+        "message": "Sponsors of test accounts"
+    },
+    "manager.tabs.status": {
+        "message": "Synchronization status"
+    },
+    "manager.tabs.status.autotime": {
+        "message": "Periodic synchronization (in minutes)"
+    },
+    "manager.tabs.status.enableThisAccount": {
+        "message": "Enable and synchronize this account"
+    },
+    "manager.tabs.status.general": {
+        "message": "General"
+    },
+    "manager.tabs.status.never": {
+        "message": "A setting of 0 disables periodic sync. Push sync is not yet implemented."
+    },
+    "manager.tabs.status.resources": {
+        "message": "Available resources"
+    },
+    "manager.tabs.status.resources.intro": {
+        "message": "Select which of the found resources should be synchronized with Thunderbird."
+    },
+    "manager.tabs.status.sync": {
+        "message": "Synchronize now"
+    },
+    "manager.tabs.status.tryagain": {
+        "message": "Try again to connect server"
+    },
+    "manager.title": {
+        "message": "TbSync account manager"
+    },
+    "manager.tryagain": {
+        "message": "Try again to connect server"
+    },
+    "menu.settingslabel": {
+        "message": "Synchronization Settings (TbSync)"
+    },
+    "password.account": {
+        "message": "Account:"
+    },
+    "password.description": {
+        "message": "Please update the credentials for the following TbSync account:"
+    },
+    "password.password": {
+        "message": "Password:"
+    },
+    "password.title": {
+        "message": "TbSync Credential Request"
+    },
+    "password.user": {
+        "message": "User:"
+    },
+    "popup.opensettings": {
+        "message": "Open TbSync account manager"
+    },
+    "prompt.DeleteAccount": {
+        "message": "Are you sure you want to delete account ##accountName##?"
+    },
+    "prompt.Disable": {
+        "message": "Are you sure you want to disable this account? All local modifications, which have not been synced yet, will be lost!"
+    },
+    "prompt.Erase": {
+        "message": "Are you sure you want to remove this account of an unknown provider from the accounts lists?"
+    },
+    "prompt.Unsubscribe": {
+        "message": "Are you sure you want to unsubscribe this item? All local modifications, which have not been synced yet, will be lost!"
+    },
+    "status.JavaScriptError": {
+        "message": "Javascript Error! Please check the event log for more details."
+    },
+    "status.OAuthAbortError": {
+        "message": "OAuth 2.0 authentication process aborted by user."
+    },
+    "status.OAuthHttpError": {
+        "message": "OAuth 2.0 authentication process failed (HTTP error ##replace.1##)."
+    },
+    "status.OAuthNetworkError": {
+        "message": "Could not connect to OAuth 2.0 authentication server."
+    },
+    "status.OAuthServerError": {
+        "message": " OAuth 2.0 authentication server returned: ##replace.1##"
+    },
+    "status.aborted": {
+        "message": "Not synchronized"
+    },
+    "status.apiError": {
+        "message": "API implementation error"
+    },
+    "status.disabled": {
+        "message": "Account is not enabled, synchronization is disabled."
+    },
+    "status.foldererror": {
+        "message": "At least one resource encountered a synchronization error. Please check the event log for more details."
+    },
+    "status.modified": {
+        "message": "Local modifications"
+    },
+    "status.network": {
+        "message": "Could not connect to server (##replace.1##)."
+    },
+    "status.no-folders-found-on-server": {
+        "message": "Could not find any resources on the server."
+    },
+    "status.notargets": {
+        "message": "Aborting synchronization, because sync targets could not be created."
+    },
+    "status.notsyncronized": {
+        "message": "Account needs to be synchronized, at least one item is out of sync."
+    },
+    "status.pending": {
+        "message": "Waiting to be synchronized"
+    },
+    "status.security": {
+        "message": "Could not establish a secure connection. Are you using a self-signed or otherwise untrusted certificate without importing it into Thunderbird? (##replace.1##)"
+    },
+    "status.skipped": {
+        "message": "Not yet supported, skipped"
+    },
+    "status.success": {
+        "message": "OK"
+    },
+    "status.syncing": {
+        "message": "Synchronizing"
+    },
+    "status.451": {
+        "message": "Server issued redirect, retry in 5 seconds."
+    },
+    "supportwizard.footer": {
+        "message": "From the information given here, an e-mail will be generated in the next step, which you can subsequently edit (for example, adding screenshots or similar). Only by actually sending that e-mail, the error report will be sent."
+    },
+    "supportwizard.label.description": {
+        "message": "Detailed error description:"
+    },
+    "supportwizard.label.faultycomponent": {
+        "message": "Component of TbSync where you have observed the error:"
+    },
+    "supportwizard.label.selectcomponent": {
+        "message": "Select component?"
+    },
+    "supportwizard.label.summary": {
+        "message": "Short summary of the error:"
+    },
+    "supportwizard.pagetitle": {
+        "message": "Gathering of all information to effectively process the bug report."
+    },
+    "supportwizard.provider": {
+        "message": "Provider: ##replace.1##"
+    },
+    "supportwizard.title": {
+        "message": "Create bug report"
+    },
+    "syncstate.accountdone": {
+        "message": "Finished account"
+    },
+    "syncstate.done": {
+        "message": "Preparing next item for synchronization"
+    },
+    "syncstate.oauthprompt": {
+        "message": "OAuth 2.0 authentication"
+    },
+    "syncstate.passwordprompt": {
+        "message": "Prompting for credentials"
+    },
+    "syncstate.preparing": {
+        "message": "Preparing next item for synchronization"
+    },
+    "syncstate.syncing": {
+        "message": "Initialize synchronization"
+    },
+    "target.orphaned": {
+        "message": "Disconnected"
+    },
+    "toolbar.label": {
+        "message": "Synchronize all TbSync accounts"
+    },
+    "toolbar.tooltiptext": {
+        "message": "Synchronize latest changes"
+    },
+    "password.ok": {
+        "message": "OK"
+    },
+    "password.cancel": {
+        "message": "Anulare"
+    }
+}
diff -Nru tbsync-4.12/_locales/ru/messages.json tbsync-4.16/_locales/ru/messages.json
--- tbsync-4.12/_locales/ru/messages.json	2024-08-27 18:32:08.000000000 +0200
+++ tbsync-4.16/_locales/ru/messages.json	2024-08-27 18:29:06.000000000 +0200
@@ -1,368 +1,368 @@
-{
-    "HelpFixStartupError": {
-        "message": "????? ????????? ??? ??????, ?? ?????? ????????? ?????? ??????? ???????????? TbSync. ??????????? ??? ?????? ???????"
-    },
-    "NoDebugLog": {
-        "message": "?? ??????? ????? ????????? ?????????? ?????????. ???????? ????? ???????, ????????????? Thunderbird ? ????????? ??? ????, ??????????? ??? ??????? ?????????? ?????????."
-    },
-    "OopsMessage": {
-        "message": "???????! TbSync ?? ???? ???????????!"
-    },
-    "RestartThunderbirdAndTryAgain": {
-        "message": "?????? ??????? TbSync ???????, ????????????? Thunderbird ? ????? ??????????? ??????? TbSync."
-    },
-    "UnableToTraceError": {
-        "message": "?????????? ?????????? ??? ??????, ????????? ?????? ??????? ? ?????? ?????? ?? ???????. ?? ?????? ???????? ?????? ??????? ??????, ????? ????????? ??? ???????"
-    },
-    "accountacctions.delete": {
-        "message": "??????? ??????? ?##accountname##?"
-    },
-    "accountacctions.disable": {
-        "message": "????????? ??????? ?##accountname##?"
-    },
-    "accountacctions.enable": {
-        "message": "????????? ??????? ?##accountname##? ? ???????????? ? ???????"
-    },
-    "accountacctions.sync": {
-        "message": "???????????????? ??????? ?##accountname##?"
-    },
-    "addressbook.searchall": {
-        "message": "????? ?? ???? ???????? ??????"
-    },
-    "addressbook.searchgal": {
-        "message": "????? ? ???? ???????? ????? ? ? ?????????? ???????? (##replace.1##)"
-    },
-    "addressbook.searchthis": {
-        "message": "????? ? ???? ???????? ?????"
-    },
-    "eventlog.clear": {
-        "message": "???????"
-    },
-    "eventlog.close": {
-        "message": "?????? ????"
-    },
-    "eventlog.title": {
-        "message": "?????? ???????"
-    },
-    "extensionDescription": {
-        "message": "TbSync - ??? ??????????? ???????????????? ????????? ??? ?????????? ????????? ???????? ???????? ? ????????????? ?????? ?????????, ????? ? ????????? ? Thunderbird."
-    },
-    "google.translate.code": {
-        "message": "ru"
-    },
-    "helplink.security": {
-        "message": "https://github.com/jobisoft/TbSync/wiki/How-to-use-TbSync-with-self-signed-or-otherwise-untrusted-certificates%3F"
-    },
-    "info.error": {
-        "message": "??????"
-    },
-    "info.idle": {
-        "message": "????????"
-    },
-    "installProvider.header": {
-        "message": "????????? ?##replace.1##? ??? TbSync ?? ??????????."
-    },
-    "manager.AccountActions": {
-        "message": "???????? ??? ????????"
-    },
-    "manager.AddAccount": {
-        "message": "???????? ????? ???????"
-    },
-    "manager.DeleteAccount": {
-        "message": "??????? ???????"
-    },
-    "manager.DisableAccount": {
-        "message": "????????? ???????"
-    },
-    "manager.EnableAccount": {
-        "message": "????????? ??????? & ?????????? ? ???????"
-    },
-    "manager.RetryConnectAccount": {
-        "message": "????????? ??????????? ? ???????"
-    },
-    "manager.ShowEventLog": {
-        "message": "???????? ?????? ???????"
-    },
-    "manager.SyncAll": {
-        "message": "???????????????? ??? ??????????? ????????"
-    },
-    "manager.SynchronizeAccount": {
-        "message": "???????????????? ???????"
-    },
-    "manager.accounts": {
-        "message": "????????"
-    },
-    "manager.accountsettings": {
-        "message": "????????? ????????"
-    },
-    "manager.catman.text": {
-        "message": "TbSync ????? ?????????????? ????????? ?????????, ??????? ???????? ?????? ??????? ?????????????????? ??????? ?????????. ????? ????? ??????????? ???????????? ?? ? ???????? ????? Thunderbird, ?? ?????? ?????????? ?????????? ????????? ?????????. ?? ????????? ????????? ???????????????? ??????????? ???????? ?? ?????? ????????? ? ????????????? ????? ?????? ???????, ????????? ? ??????????. ??? ????? ????? ? ??????????? ??????????? Mozilla Add-On:"
-    },
-    "manager.community": {
-        "message": "??????????"
-    },
-    "manager.connecting": {
-        "message": "?????????????? ? ???????"
-    },
-    "manager.help": {
-        "message": "??????"
-    },
-    "manager.help.createbugreport": {
-        "message": "??????? ????? ?? ??????"
-    },
-    "manager.help.createbugreportinfo": {
-        "message": "????? TbSync ??????? ?????? ?????????? ?????????, ??????????? ? ?????? ?????? ?? ??????, ????????????? Thunderbird, ? ????? ????????? ????, ??????? ????????????? ????????? ??????. ????? ?? ?????? ??????? ???? ????? ?? ??????? ?????."
-    },
-    "manager.help.debuglevel.0": {
-        "message": "Disabled"
-    },
-    "manager.help.debuglevel.1": {
-        "message": "Enabled: Logging of errors only"
-    },
-    "manager.help.debuglevel.2": {
-        "message": "Enabled: Logging of all sent and received data"
-    },
-    "manager.help.debuglevel.3": {
-        "message": "Enabled: Logging of all data and some internal debug values"
-    },
-    "manager.help.debugmode": {
-        "message": "Debug mode:"
-    },
-    "manager.help.fixit": {
-        "message": "?? ?????? ?????? ????????? ??? ??????????, ???????? ????????? ?? ??????. ??? ????? ????????? ????????? ?????? ???????."
-    },
-    "manager.help.foundabug": {
-        "message": "????? ???????"
-    },
-    "manager.help.needhelp": {
-        "message": "????? ????????"
-    },
-    "manager.help.viewdebuglog": {
-        "message": "View debug log"
-    },
-    "manager.help.wiki": {
-        "message": "???????? wiki-???????? ??????? TbSync, ??? ??????????? ?????????????? ??????????, ??????????? ? ????????? ???????? ????????????."
-    },
-    "manager.installprovider.link": {
-        "message": "??????? ?? ????????? ??????, ????? ??????? ?????????????? ???????? ?????????????? ?????????? ?????????????. ??? ?? ??????? ?????????????? ?????????? ? ??????????, ? ? ??? ????? ??????????? ?????????? ???:"
-    },
-    "manager.installprovider.warning": {
-        "message": "???? ????????? ????????????? ?? ???????? ? ??????????? ??????????? Thunderbird AddOn ?, ????? ???????, ?? ??? ?????????? ???????????? Thunderbird. ????????? ????????????? ????? ??????? ????????????? ???????? ? ????? ???????. ??????????? ??? ?? ???? ????? ? ????."
-    },
-    "manager.lockedsettings.description": {
-        "message": "????? ????????????? ?????? ?????????????, ????????? ????????? ?????? ?????????????, ???? ??????? ?????? ????????."
-    },
-    "manager.missingprovider": {
-        "message": "????????? ????????????? (## provider ##), ? ??????? ??????? ??? ??????? ??????, ?? ??????????."
-    },
-    "manager.noaccounts": {
-        "message": "???????????? ????????? ???? ???."
-    },
-    "manager.provider": {
-        "message": "?????????? ??????????"
-    },
-    "manager.provider4tbsync": {
-        "message": "????????? ??? TbSync"
-    },
-    "manager.resource": {
-        "message": "?????"
-    },
-    "manager.shorttitle": {
-        "message": "???????? ????????"
-    },
-    "manager.status": {
-        "message": "??????"
-    },
-    "manager.supporter.contributors": {
-        "message": "????????? & ???????????"
-    },
-    "manager.supporter.details": {
-        "message": "???????????"
-    },
-    "manager.supporter.sponsors": {
-        "message": "???????? ???????? ?????????"
-    },
-    "manager.tabs.status": {
-        "message": "?????? ?????????????"
-    },
-    "manager.tabs.status.autotime": {
-        "message": "????????????? ????????????? (? ???????)"
-    },
-    "manager.tabs.status.enableThisAccount": {
-        "message": "????????? ? ???????????????? ???? ???????"
-    },
-    "manager.tabs.status.general": {
-        "message": "???????"
-    },
-    "manager.tabs.status.never": {
-        "message": "????????? 0 ????????? ????????????? ?????????????. Push-????????????? ??? ?? ???????????."
-    },
-    "manager.tabs.status.resources": {
-        "message": "????????? ???????"
-    },
-    "manager.tabs.status.resources.intro": {
-        "message": "????????, ????? ?? ????????? ???????? ??????? ???????????????? ? Thunderbird."
-    },
-    "manager.tabs.status.sync": {
-        "message": "???????????????? ??????"
-    },
-    "manager.tabs.status.tryagain": {
-        "message": "????????? ????????????? ? ???????"
-    },
-    "manager.title": {
-        "message": "???????? ???????? TbSync"
-    },
-    "manager.tryagain": {
-        "message": "????????? ????????????? ? ???????"
-    },
-    "menu.settingslabel": {
-        "message": "????????? ????????????? (TbSync)"
-    },
-    "password.account": {
-        "message": "??????? ??????:"
-    },
-    "password.description": {
-        "message": "???????? ??????? ?????? ??? ????????? ??????? ?????? TbSync:"
-    },
-    "password.password": {
-        "message": "??????:"
-    },
-    "password.title": {
-        "message": "?????? ??????? ?????? TbSync"
-    },
-    "password.user": {
-        "message": "????????????:"
-    },
-    "popup.opensettings": {
-        "message": "??????? ???????? ???????? TbSync"
-    },
-    "prompt.DeleteAccount": {
-        "message": "?? ???????, ??? ?????? ??????? ??????? ##accountName##?"
-    },
-    "prompt.Disable": {
-        "message": "?? ????????????? ?????? ????????? ???? ???????? ??? ????????? ?????????, ??????? ??? ?? ????????????????, ????? ????????!"
-    },
-    "prompt.Erase": {
-        "message": "?? ????????????? ?????? ??????? ???? ??????? ???????????? ?????????? ?? ?????? ??????????"
-    },
-    "prompt.Unsubscribe": {
-        "message": "?? ????????????? ?????? ???????? ???????? ?? ???? ???????? ??? ????????? ?????????, ??????? ??? ?? ????????????????, ????? ????????!"
-    },
-    "status.JavaScriptError": {
-        "message": "?????? JavaScript! ??????????, ????????? ?????? ??????? ??? ????? ????????? ??????????."
-    },
-    "status.OAuthAbortError": {
-        "message": "OAuth 2.0 authentication process aborted by user."
-    },
-    "status.OAuthHttpError": {
-        "message": "OAuth 2.0 authentication process failed (HTTP error ##replace.1##)."
-    },
-    "status.OAuthNetworkError": {
-        "message": "Could not connect to OAuth 2.0 authentication server."
-    },
-    "status.OAuthServerError": {
-        "message": " OAuth 2.0 authentication server returned: ##replace.1##"
-    },
-    "status.aborted": {
-        "message": "?? ????????????????"
-    },
-    "status.apiError": {
-        "message": "?????? ?????????? API"
-    },
-    "status.disabled": {
-        "message": "??????? ?? ???????, ????????????? ?????????."
-    },
-    "status.foldererror": {
-        "message": "?? ??????? ???? ???? ?????? ????????? ?????? ?????????????. ??????????, ????????? ?????? ??????? ??? ????? ????????? ??????????."
-    },
-    "status.modified": {
-        "message": "????????? ?????????"
-    },
-    "status.network": {
-        "message": "?? ??????? ???????????? ? ??????? (##replace.1##)."
-    },
-    "status.no-folders-found-on-server": {
-        "message": "?? ??????? ????? ?????-???? ??????? ?? ???????."
-    },
-    "status.notargets": {
-        "message": "?????? ?????????????, ????????? ???? ????????????? ?? ????? ???? ???????."
-    },
-    "status.notsyncronized": {
-        "message": "??????? ?????? ???? ???????????????, ?? ??????? ???? ???? ??????? ?? ???????????????."
-    },
-    "status.pending": {
-        "message": "???????? ???? ????????????????"
-    },
-    "status.security": {
-        "message": "?? ??????? ?????????? ?????????? ??????????. ?? ??????????? ??????????????? ??? ?????????? ?????????? ??? ??????? ??? ? Thunderbird? (##replace.1##)"
-    },
-    "status.skipped": {
-        "message": "???? ?? ??????????????, ?????????"
-    },
-    "status.success": {
-        "message": "??????"
-    },
-    "status.syncing": {
-        "message": "?????????????"
-    },
-    "status.451": {
-        "message": "Server issued redirect, retry in 5 seconds."
-    },
-    "supportwizard.footer": {
-        "message": "?? ??????????? ????? ?????????? ?? ????????? ???? ????? ??????? ??????????? ??????, ??????? ?? ?????? ???????????? ????????????? (????????, ????????? ????????? ??? ???????????). ?????? ??? ???????? ????? ???????????? ?????? ????? ????????? ? ??? ????? ?? ??????."
-    },
-    "supportwizard.label.description": {
-        "message": "????????? ???????? ??????:"
-    },
-    "supportwizard.label.faultycomponent": {
-        "message": "????????? TbSync, ??? ?? ???????? ??????:"
-    },
-    "supportwizard.label.selectcomponent": {
-        "message": "??????? ????????? ..."
-    },
-    "supportwizard.label.summary": {
-        "message": "??????? ???????? ??????:"
-    },
-    "supportwizard.pagetitle": {
-        "message": "???? ???? ?????????? ??? ??????????? ????????? ?????? ?? ??????."
-    },
-    "supportwizard.provider": {
-        "message": "?????????: ##replace.1##"
-    },
-    "supportwizard.title": {
-        "message": "??????? ????? ?? ??????"
-    },
-    "syncstate.accountdone": {
-        "message": "??????????? ???????"
-    },
-    "syncstate.done": {
-        "message": "?????????? ?????????? ???????? ??? ?????????????"
-    },
-    "syncstate.oauthprompt": {
-        "message": "OAuth 2.0 authentication"
-    },
-    "syncstate.passwordprompt": {
-        "message": "?????? ?? ???? ??????? ??????"
-    },
-    "syncstate.preparing": {
-        "message": "?????????? ?????????? ???????? ??? ?????????????"
-    },
-    "syncstate.syncing": {
-        "message": "????????????? ?????????????"
-    },
-    "target.orphaned": {
-        "message": "?????????? ?????????"
-    },
-    "toolbar.label": {
-        "message": "???????????????? ??? ???????? TbSync"
-    },
-    "toolbar.tooltiptext": {
-        "message": "???????????????? ????????? ?????????"
-    },
-    "password.ok": {
-        "message": "??"
-    },
-    "password.cancel": {
-        "message": "??????"
-    }
-}
+{
+    "HelpFixStartupError": {
+        "message": "????? ????????? ??? ??????, ?? ?????? ????????? ?????? ??????? ???????????? TbSync. ??????????? ??? ?????? ???????"
+    },
+    "NoDebugLog": {
+        "message": "?? ??????? ????? ????????? ?????????? ?????????. ???????? ????? ???????, ????????????? Thunderbird ? ????????? ??? ????, ??????????? ??? ??????? ?????????? ?????????."
+    },
+    "OopsMessage": {
+        "message": "???????! TbSync ?? ???? ???????????!"
+    },
+    "RestartThunderbirdAndTryAgain": {
+        "message": "?????? ??????? TbSync ???????, ????????????? Thunderbird ? ????? ??????????? ??????? TbSync."
+    },
+    "UnableToTraceError": {
+        "message": "?????????? ?????????? ??? ??????, ????????? ?????? ??????? ? ?????? ?????? ?? ???????. ?? ?????? ???????? ?????? ??????? ??????, ????? ????????? ??? ???????"
+    },
+    "accountacctions.delete": {
+        "message": "??????? ??????? ?##accountname##?"
+    },
+    "accountacctions.disable": {
+        "message": "????????? ??????? ?##accountname##?"
+    },
+    "accountacctions.enable": {
+        "message": "????????? ??????? ?##accountname##? ? ???????????? ? ???????"
+    },
+    "accountacctions.sync": {
+        "message": "???????????????? ??????? ?##accountname##?"
+    },
+    "addressbook.searchall": {
+        "message": "????? ?? ???? ???????? ??????"
+    },
+    "addressbook.searchgal": {
+        "message": "????? ? ???? ???????? ????? ? ? ?????????? ???????? (##replace.1##)"
+    },
+    "addressbook.searchthis": {
+        "message": "????? ? ???? ???????? ?????"
+    },
+    "eventlog.clear": {
+        "message": "???????"
+    },
+    "eventlog.close": {
+        "message": "?????? ????"
+    },
+    "eventlog.title": {
+        "message": "?????? ???????"
+    },
+    "extensionDescription": {
+        "message": "TbSync - ??? ??????????? ???????????????? ????????? ??? ?????????? ????????? ???????? ???????? ? ????????????? ?????? ?????????, ????? ? ????????? ? Thunderbird."
+    },
+    "google.translate.code": {
+        "message": "ru"
+    },
+    "helplink.security": {
+        "message": "https://github.com/jobisoft/TbSync/wiki/How-to-use-TbSync-with-self-signed-or-otherwise-untrusted-certificates%3F"
+    },
+    "info.error": {
+        "message": "??????"
+    },
+    "info.idle": {
+        "message": "????????"
+    },
+    "installProvider.header": {
+        "message": "????????? ?##replace.1##? ??? TbSync ?? ??????????."
+    },
+    "manager.AccountActions": {
+        "message": "???????? ??? ????????"
+    },
+    "manager.AddAccount": {
+        "message": "???????? ????? ???????"
+    },
+    "manager.DeleteAccount": {
+        "message": "??????? ???????"
+    },
+    "manager.DisableAccount": {
+        "message": "????????? ???????"
+    },
+    "manager.EnableAccount": {
+        "message": "????????? ??????? & ?????????? ? ???????"
+    },
+    "manager.RetryConnectAccount": {
+        "message": "????????? ??????????? ? ???????"
+    },
+    "manager.ShowEventLog": {
+        "message": "???????? ?????? ???????"
+    },
+    "manager.SyncAll": {
+        "message": "???????????????? ??? ??????????? ????????"
+    },
+    "manager.SynchronizeAccount": {
+        "message": "???????????????? ???????"
+    },
+    "manager.accounts": {
+        "message": "????????"
+    },
+    "manager.accountsettings": {
+        "message": "????????? ????????"
+    },
+    "manager.catman.text": {
+        "message": "TbSync ????? ?????????????? ????????? ?????????, ??????? ???????? ?????? ??????? ?????????????????? ??????? ?????????. ????? ????? ??????????? ???????????? ?? ? ???????? ????? Thunderbird, ?? ?????? ?????????? ?????????? ????????? ?????????. ?? ????????? ????????? ???????????????? ??????????? ???????? ?? ?????? ????????? ? ????????????? ????? ?????? ???????, ????????? ? ??????????. ??? ????? ????? ? ??????????? ??????????? Mozilla Add-On:"
+    },
+    "manager.community": {
+        "message": "??????????"
+    },
+    "manager.connecting": {
+        "message": "?????????????? ? ???????"
+    },
+    "manager.help": {
+        "message": "??????"
+    },
+    "manager.help.createbugreport": {
+        "message": "??????? ????? ?? ??????"
+    },
+    "manager.help.createbugreportinfo": {
+        "message": "????? TbSync ??????? ?????? ?????????? ?????????, ??????????? ? ?????? ?????? ?? ??????, ????????????? Thunderbird, ? ????? ????????? ????, ??????? ????????????? ????????? ??????. ????? ?? ?????? ??????? ???? ????? ?? ??????? ?????."
+    },
+    "manager.help.debuglevel.0": {
+        "message": "Disabled"
+    },
+    "manager.help.debuglevel.1": {
+        "message": "Enabled: Logging of errors only"
+    },
+    "manager.help.debuglevel.2": {
+        "message": "Enabled: Logging of all sent and received data"
+    },
+    "manager.help.debuglevel.3": {
+        "message": "Enabled: Logging of all data and some internal debug values"
+    },
+    "manager.help.debugmode": {
+        "message": "Debug mode:"
+    },
+    "manager.help.fixit": {
+        "message": "?? ?????? ?????? ????????? ??? ??????????, ???????? ????????? ?? ??????. ??? ????? ????????? ????????? ?????? ???????."
+    },
+    "manager.help.foundabug": {
+        "message": "????? ???????"
+    },
+    "manager.help.needhelp": {
+        "message": "????? ????????"
+    },
+    "manager.help.viewdebuglog": {
+        "message": "View debug log"
+    },
+    "manager.help.wiki": {
+        "message": "???????? wiki-???????? ??????? TbSync, ??? ??????????? ?????????????? ??????????, ??????????? ? ????????? ???????? ????????????."
+    },
+    "manager.installprovider.link": {
+        "message": "??????? ?? ????????? ??????, ????? ??????? ?????????????? ???????? ?????????????? ?????????? ?????????????. ??? ?? ??????? ?????????????? ?????????? ? ??????????, ? ? ??? ????? ??????????? ?????????? ???:"
+    },
+    "manager.installprovider.warning": {
+        "message": "???? ????????? ????????????? ?? ???????? ? ??????????? ??????????? Thunderbird AddOn ?, ????? ???????, ?? ??? ?????????? ???????????? Thunderbird. ????????? ????????????? ????? ??????? ????????????? ???????? ? ????? ???????. ??????????? ??? ?? ???? ????? ? ????."
+    },
+    "manager.lockedsettings.description": {
+        "message": "????? ????????????? ?????? ?????????????, ????????? ????????? ?????? ?????????????, ???? ??????? ?????? ????????."
+    },
+    "manager.missingprovider": {
+        "message": "????????? ????????????? (## provider ##), ? ??????? ??????? ??? ??????? ??????, ?? ??????????."
+    },
+    "manager.noaccounts": {
+        "message": "???????????? ????????? ???? ???."
+    },
+    "manager.provider": {
+        "message": "?????????? ??????????"
+    },
+    "manager.provider4tbsync": {
+        "message": "????????? ??? TbSync"
+    },
+    "manager.resource": {
+        "message": "?????"
+    },
+    "manager.shorttitle": {
+        "message": "???????? ????????"
+    },
+    "manager.status": {
+        "message": "??????"
+    },
+    "manager.supporter.contributors": {
+        "message": "????????? & ???????????"
+    },
+    "manager.supporter.details": {
+        "message": "???????????"
+    },
+    "manager.supporter.sponsors": {
+        "message": "???????? ???????? ?????????"
+    },
+    "manager.tabs.status": {
+        "message": "?????? ?????????????"
+    },
+    "manager.tabs.status.autotime": {
+        "message": "????????????? ????????????? (? ???????)"
+    },
+    "manager.tabs.status.enableThisAccount": {
+        "message": "????????? ? ???????????????? ???? ???????"
+    },
+    "manager.tabs.status.general": {
+        "message": "???????"
+    },
+    "manager.tabs.status.never": {
+        "message": "????????? 0 ????????? ????????????? ?????????????. Push-????????????? ??? ?? ???????????."
+    },
+    "manager.tabs.status.resources": {
+        "message": "????????? ???????"
+    },
+    "manager.tabs.status.resources.intro": {
+        "message": "????????, ????? ?? ????????? ???????? ??????? ???????????????? ? Thunderbird."
+    },
+    "manager.tabs.status.sync": {
+        "message": "???????????????? ??????"
+    },
+    "manager.tabs.status.tryagain": {
+        "message": "????????? ????????????? ? ???????"
+    },
+    "manager.title": {
+        "message": "???????? ???????? TbSync"
+    },
+    "manager.tryagain": {
+        "message": "????????? ????????????? ? ???????"
+    },
+    "menu.settingslabel": {
+        "message": "????????? ????????????? (TbSync)"
+    },
+    "password.account": {
+        "message": "??????? ??????:"
+    },
+    "password.description": {
+        "message": "???????? ??????? ?????? ??? ????????? ??????? ?????? TbSync:"
+    },
+    "password.password": {
+        "message": "??????:"
+    },
+    "password.title": {
+        "message": "?????? ??????? ?????? TbSync"
+    },
+    "password.user": {
+        "message": "????????????:"
+    },
+    "popup.opensettings": {
+        "message": "??????? ???????? ???????? TbSync"
+    },
+    "prompt.DeleteAccount": {
+        "message": "?? ???????, ??? ?????? ??????? ??????? ##accountName##?"
+    },
+    "prompt.Disable": {
+        "message": "?? ????????????? ?????? ????????? ???? ???????? ??? ????????? ?????????, ??????? ??? ?? ????????????????, ????? ????????!"
+    },
+    "prompt.Erase": {
+        "message": "?? ????????????? ?????? ??????? ???? ??????? ???????????? ?????????? ?? ?????? ??????????"
+    },
+    "prompt.Unsubscribe": {
+        "message": "?? ????????????? ?????? ???????? ???????? ?? ???? ???????? ??? ????????? ?????????, ??????? ??? ?? ????????????????, ????? ????????!"
+    },
+    "status.JavaScriptError": {
+        "message": "?????? JavaScript! ??????????, ????????? ?????? ??????? ??? ????? ????????? ??????????."
+    },
+    "status.OAuthAbortError": {
+        "message": "OAuth 2.0 authentication process aborted by user."
+    },
+    "status.OAuthHttpError": {
+        "message": "OAuth 2.0 authentication process failed (HTTP error ##replace.1##)."
+    },
+    "status.OAuthNetworkError": {
+        "message": "Could not connect to OAuth 2.0 authentication server."
+    },
+    "status.OAuthServerError": {
+        "message": " OAuth 2.0 authentication server returned: ##replace.1##"
+    },
+    "status.aborted": {
+        "message": "?? ????????????????"
+    },
+    "status.apiError": {
+        "message": "?????? ?????????? API"
+    },
+    "status.disabled": {
+        "message": "??????? ?? ???????, ????????????? ?????????."
+    },
+    "status.foldererror": {
+        "message": "?? ??????? ???? ???? ?????? ????????? ?????? ?????????????. ??????????, ????????? ?????? ??????? ??? ????? ????????? ??????????."
+    },
+    "status.modified": {
+        "message": "????????? ?????????"
+    },
+    "status.network": {
+        "message": "?? ??????? ???????????? ? ??????? (##replace.1##)."
+    },
+    "status.no-folders-found-on-server": {
+        "message": "?? ??????? ????? ?????-???? ??????? ?? ???????."
+    },
+    "status.notargets": {
+        "message": "?????? ?????????????, ????????? ???? ????????????? ?? ????? ???? ???????."
+    },
+    "status.notsyncronized": {
+        "message": "??????? ?????? ???? ???????????????, ?? ??????? ???? ???? ??????? ?? ???????????????."
+    },
+    "status.pending": {
+        "message": "???????? ???? ????????????????"
+    },
+    "status.security": {
+        "message": "?? ??????? ?????????? ?????????? ??????????. ?? ??????????? ??????????????? ??? ?????????? ?????????? ??? ??????? ??? ? Thunderbird? (##replace.1##)"
+    },
+    "status.skipped": {
+        "message": "???? ?? ??????????????, ?????????"
+    },
+    "status.success": {
+        "message": "??????"
+    },
+    "status.syncing": {
+        "message": "?????????????"
+    },
+    "status.451": {
+        "message": "Server issued redirect, retry in 5 seconds."
+    },
+    "supportwizard.footer": {
+        "message": "?? ??????????? ????? ?????????? ?? ????????? ???? ????? ??????? ??????????? ??????, ??????? ?? ?????? ???????????? ????????????? (????????, ????????? ????????? ??? ???????????). ?????? ??? ???????? ????? ???????????? ?????? ????? ????????? ? ??? ????? ?? ??????."
+    },
+    "supportwizard.label.description": {
+        "message": "????????? ???????? ??????:"
+    },
+    "supportwizard.label.faultycomponent": {
+        "message": "????????? TbSync, ??? ?? ???????? ??????:"
+    },
+    "supportwizard.label.selectcomponent": {
+        "message": "??????? ????????? ..."
+    },
+    "supportwizard.label.summary": {
+        "message": "??????? ???????? ??????:"
+    },
+    "supportwizard.pagetitle": {
+        "message": "???? ???? ?????????? ??? ??????????? ????????? ?????? ?? ??????."
+    },
+    "supportwizard.provider": {
+        "message": "?????????: ##replace.1##"
+    },
+    "supportwizard.title": {
+        "message": "??????? ????? ?? ??????"
+    },
+    "syncstate.accountdone": {
+        "message": "??????????? ???????"
+    },
+    "syncstate.done": {
+        "message": "?????????? ?????????? ???????? ??? ?????????????"
+    },
+    "syncstate.oauthprompt": {
+        "message": "OAuth 2.0 authentication"
+    },
+    "syncstate.passwordprompt": {
+        "message": "?????? ?? ???? ??????? ??????"
+    },
+    "syncstate.preparing": {
+        "message": "?????????? ?????????? ???????? ??? ?????????????"
+    },
+    "syncstate.syncing": {
+        "message": "????????????? ?????????????"
+    },
+    "target.orphaned": {
+        "message": "?????????? ?????????"
+    },
+    "toolbar.label": {
+        "message": "???????????????? ??? ???????? TbSync"
+    },
+    "toolbar.tooltiptext": {
+        "message": "???????????????? ????????? ?????????"
+    },
+    "password.ok": {
+        "message": "??"
+    },
+    "password.cancel": {
+        "message": "??????"
+    }
+}
diff -Nru tbsync-4.12/_locales/sv/messages.json tbsync-4.16/_locales/sv/messages.json
--- tbsync-4.12/_locales/sv/messages.json	2024-08-27 18:32:08.000000000 +0200
+++ tbsync-4.16/_locales/sv/messages.json	2024-08-27 18:29:06.000000000 +0200
@@ -1,368 +1,368 @@
-{
-    "HelpFixStartupError": {
-        "message": "To help fix this error, you could send a debug log to the TbSync developer. Prepare that email now?"
-    },
-    "NoDebugLog": {
-        "message": "Could not find any useful debug messages. Please activate debug mode, restart Thunderbird and repeat all the steps needed to trigger the erroneous behavior."
-    },
-    "OopsMessage": {
-        "message": "Oops! TbSync was not able to start!"
-    },
-    "RestartThunderbirdAndTryAgain": {
-        "message": "TbSync debug log has been enabled, please restart Thunderbird and again try to open TbSync."
-    },
-    "UnableToTraceError": {
-        "message": "It is not possible to trace this error, because debug log is currently not enabled. Do you want to enable debug log now, to help fix this error?"
-    },
-    "accountacctions.delete": {
-        "message": "Delete account ?##accountname##?"
-    },
-    "accountacctions.disable": {
-        "message": "Disable account ?##accountname##?"
-    },
-    "accountacctions.enable": {
-        "message": "Enable account ?##accountname##? & try to connect to server"
-    },
-    "accountacctions.sync": {
-        "message": "Synchronize account ?##accountname##?"
-    },
-    "addressbook.searchall": {
-        "message": "Search all address books"
-    },
-    "addressbook.searchgal": {
-        "message": "Search this address book and the global directory (##replace.1##)"
-    },
-    "addressbook.searchthis": {
-        "message": "Search this address book"
-    },
-    "eventlog.clear": {
-        "message": "Clear"
-    },
-    "eventlog.close": {
-        "message": "Close"
-    },
-    "eventlog.title": {
-        "message": "Event log"
-    },
-    "extensionDescription": {
-        "message": "TbSync is a central user interface to manage cloud accounts and to synchronize their contact, task and calendar information with Thunderbird."
-    },
-    "google.translate.code": {
-        "message": "en"
-    },
-    "helplink.security": {
-        "message": "https://github.com/jobisoft/TbSync/wiki/How-to-use-TbSync-with-self-signed-or-otherwise-untrusted-certificates%3F"
-    },
-    "info.error": {
-        "message": "Error"
-    },
-    "info.idle": {
-        "message": "Idle"
-    },
-    "installProvider.header": {
-        "message": "Provider ?##replace.1##? for TbSync is not yet installed."
-    },
-    "manager.AccountActions": {
-        "message": "Account actions"
-    },
-    "manager.AddAccount": {
-        "message": "Add new account"
-    },
-    "manager.DeleteAccount": {
-        "message": "Delete account"
-    },
-    "manager.DisableAccount": {
-        "message": "Disable account"
-    },
-    "manager.EnableAccount": {
-        "message": "Enable account & try to connect to server"
-    },
-    "manager.RetryConnectAccount": {
-        "message": "Try again to connect to server"
-    },
-    "manager.ShowEventLog": {
-        "message": "Open event log"
-    },
-    "manager.SyncAll": {
-        "message": "Synchronize all enabled accounts"
-    },
-    "manager.SynchronizeAccount": {
-        "message": "Synchronize account"
-    },
-    "manager.accounts": {
-        "message": "Accounts"
-    },
-    "manager.accountsettings": {
-        "message": "Account Settings"
-    },
-    "manager.catman.text": {
-        "message": "TbSync also syncs contact categories, which are a powerful replacement for the non-synchronizable contact lists. To be able to use them in the Thunderbird address book you can install the Category Manager add-on. It allows to manage overlapping category based contact groups and provides a bunch of other category-related features. It can be found in the official Mozilla add-on repository:"
-    },
-    "manager.community": {
-        "message": "Community"
-    },
-    "manager.connecting": {
-        "message": "Connecting to server"
-    },
-    "manager.help": {
-        "message": "Help"
-    },
-    "manager.help.createbugreport": {
-        "message": "Create bug report"
-    },
-    "manager.help.createbugreportinfo": {
-        "message": "In order for TbSync to collect only the debug data relevant to your bug report, please restart Thunderbird and then repeat exactly the steps that reproduce the buggy behavior. Then you can create your bug report here."
-    },
-    "manager.help.debuglevel.0": {
-        "message": "Disabled"
-    },
-    "manager.help.debuglevel.1": {
-        "message": "Enabled: Logging of errors only"
-    },
-    "manager.help.debuglevel.2": {
-        "message": "Enabled: Logging of all sent and received data"
-    },
-    "manager.help.debuglevel.3": {
-        "message": "Enabled: Logging of all data and some internal debug values"
-    },
-    "manager.help.debugmode": {
-        "message": "Debug mode:"
-    },
-    "manager.help.fixit": {
-        "message": "You can help to fix it by sending in a bug report. This requires the activation of debug mode."
-    },
-    "manager.help.foundabug": {
-        "message": "Found a bug?"
-    },
-    "manager.help.needhelp": {
-        "message": "Need Help?"
-    },
-    "manager.help.viewdebuglog": {
-        "message": "View debug log"
-    },
-    "manager.help.wiki": {
-        "message": "Open the wiki pages of the TbSync project, they provide additional information, guides and detailed configuration descriptions."
-    },
-    "manager.installprovider.link": {
-        "message": "Click on the following link to open the info page of the missing synchronization provider. There you will find further information about the provider and you will have the option to install it:"
-    },
-    "manager.installprovider.warning": {
-        "message": "This synchronization provider is not hosted in the official Thunderbird add-on repository and thus has not been reviewed by Thunderbird staff. The provider could do bad things to your system. Use it at your own risk."
-    },
-    "manager.lockedsettings.description": {
-        "message": "To prevent synchronization errors, some settings cannot be edited while the account is enabled."
-    },
-    "manager.missingprovider": {
-        "message": "This account requires the ##provider## synchronization provider, which is currently not installed."
-    },
-    "manager.noaccounts": {
-        "message": "There are not yet any accounts defined."
-    },
-    "manager.provider": {
-        "message": "Install Provider"
-    },
-    "manager.provider4tbsync": {
-        "message": "Provider for TbSync"
-    },
-    "manager.resource": {
-        "message": "Resource"
-    },
-    "manager.shorttitle": {
-        "message": "Account manager"
-    },
-    "manager.status": {
-        "message": "Status"
-    },
-    "manager.supporter.contributors": {
-        "message": "Contributors & Translators"
-    },
-    "manager.supporter.details": {
-        "message": "Details"
-    },
-    "manager.supporter.sponsors": {
-        "message": "Sponsors of test accounts"
-    },
-    "manager.tabs.status": {
-        "message": "Synchronization status"
-    },
-    "manager.tabs.status.autotime": {
-        "message": "Periodic synchronization (in minutes)"
-    },
-    "manager.tabs.status.enableThisAccount": {
-        "message": "Enable and synchronize this account"
-    },
-    "manager.tabs.status.general": {
-        "message": "General"
-    },
-    "manager.tabs.status.never": {
-        "message": "A setting of 0 disables periodic sync. Push sync is not yet implemented."
-    },
-    "manager.tabs.status.resources": {
-        "message": "Available resources"
-    },
-    "manager.tabs.status.resources.intro": {
-        "message": "Select which of the found resources should be synchronized with Thunderbird."
-    },
-    "manager.tabs.status.sync": {
-        "message": "Synchronize now"
-    },
-    "manager.tabs.status.tryagain": {
-        "message": "Try again to connect server"
-    },
-    "manager.title": {
-        "message": "TbSync account manager"
-    },
-    "manager.tryagain": {
-        "message": "Try again to connect server"
-    },
-    "menu.settingslabel": {
-        "message": "Synchronization Settings (TbSync)"
-    },
-    "password.account": {
-        "message": "Account:"
-    },
-    "password.description": {
-        "message": "Please update the credentials for the following TbSync account:"
-    },
-    "password.password": {
-        "message": "Password:"
-    },
-    "password.title": {
-        "message": "TbSync Credential Request"
-    },
-    "password.user": {
-        "message": "User:"
-    },
-    "popup.opensettings": {
-        "message": "Open TbSync account manager"
-    },
-    "prompt.DeleteAccount": {
-        "message": "Are you sure you want to delete account ##accountName##?"
-    },
-    "prompt.Disable": {
-        "message": "Are you sure you want to disable this account? All local modifications, which have not been synced yet, will be lost!"
-    },
-    "prompt.Erase": {
-        "message": "Are you sure you want to remove this account of an unknown provider from the accounts lists?"
-    },
-    "prompt.Unsubscribe": {
-        "message": "Are you sure you want to unsubscribe this item? All local modifications, which have not been synced yet, will be lost!"
-    },
-    "status.JavaScriptError": {
-        "message": "Javascript Error! Please check the event log for more details."
-    },
-    "status.OAuthAbortError": {
-        "message": "OAuth 2.0 authentication process aborted by user."
-    },
-    "status.OAuthHttpError": {
-        "message": "OAuth 2.0 authentication process failed (HTTP error ##replace.1##)."
-    },
-    "status.OAuthNetworkError": {
-        "message": "Could not connect to OAuth 2.0 authentication server."
-    },
-    "status.OAuthServerError": {
-        "message": " OAuth 2.0 authentication server returned: ##replace.1##"
-    },
-    "status.aborted": {
-        "message": "Not synchronized"
-    },
-    "status.apiError": {
-        "message": "API implementation error"
-    },
-    "status.disabled": {
-        "message": "Account is not enabled, synchronization is disabled."
-    },
-    "status.foldererror": {
-        "message": "At least one resource encountered a synchronization error. Please check the event log for more details."
-    },
-    "status.modified": {
-        "message": "Local modifications"
-    },
-    "status.network": {
-        "message": "Could not connect to server (##replace.1##)."
-    },
-    "status.no-folders-found-on-server": {
-        "message": "Could not find any resources on the server."
-    },
-    "status.notargets": {
-        "message": "Aborting synchronization, because sync targets could not be created."
-    },
-    "status.notsyncronized": {
-        "message": "Account needs to be synchronized, at least one item is out of sync."
-    },
-    "status.pending": {
-        "message": "Waiting to be synchronized"
-    },
-    "status.security": {
-        "message": "Could not establish a secure connection. Are you using a self-signed or otherwise untrusted certificate without importing it into Thunderbird? (##replace.1##)"
-    },
-    "status.skipped": {
-        "message": "Not yet supported, skipped"
-    },
-    "status.success": {
-        "message": "OK"
-    },
-    "status.syncing": {
-        "message": "Synchronizing"
-    },
-    "status.451": {
-        "message": "Server issued redirect, retry in 5 seconds."
-    },
-    "supportwizard.footer": {
-        "message": "From the information given here, an e-mail will be generated in the next step, which you can subsequently edit (for example, adding screenshots or similar). Only by actually sending that e-mail, the error report will be sent."
-    },
-    "supportwizard.label.description": {
-        "message": "Detailed error description:"
-    },
-    "supportwizard.label.faultycomponent": {
-        "message": "Component of TbSync where you have observed the error:"
-    },
-    "supportwizard.label.selectcomponent": {
-        "message": "Select component?"
-    },
-    "supportwizard.label.summary": {
-        "message": "Short summary of the error:"
-    },
-    "supportwizard.pagetitle": {
-        "message": "Gathering of all information to effectively process the bug report."
-    },
-    "supportwizard.provider": {
-        "message": "Provider: ##replace.1##"
-    },
-    "supportwizard.title": {
-        "message": "Create bug report"
-    },
-    "syncstate.accountdone": {
-        "message": "Finished account"
-    },
-    "syncstate.done": {
-        "message": "Preparing next item for synchronization"
-    },
-    "syncstate.oauthprompt": {
-        "message": "OAuth 2.0 authentication"
-    },
-    "syncstate.passwordprompt": {
-        "message": "Prompting for credentials"
-    },
-    "syncstate.preparing": {
-        "message": "Preparing next item for synchronization"
-    },
-    "syncstate.syncing": {
-        "message": "Initialize synchronization"
-    },
-    "target.orphaned": {
-        "message": "Disconnected"
-    },
-    "toolbar.label": {
-        "message": "Synchronize all TbSync accounts"
-    },
-    "toolbar.tooltiptext": {
-        "message": "Synchronize latest changes"
-    },
-    "password.ok": {
-        "message": "OK"
-    },
-    "password.cancel": {
-        "message": "Avbryt"
-    }
-}
+{
+    "HelpFixStartupError": {
+        "message": "To help fix this error, you could send a debug log to the TbSync developer. Prepare that email now?"
+    },
+    "NoDebugLog": {
+        "message": "Could not find any useful debug messages. Please activate debug mode, restart Thunderbird and repeat all the steps needed to trigger the erroneous behavior."
+    },
+    "OopsMessage": {
+        "message": "Oops! TbSync was not able to start!"
+    },
+    "RestartThunderbirdAndTryAgain": {
+        "message": "TbSync debug log has been enabled, please restart Thunderbird and again try to open TbSync."
+    },
+    "UnableToTraceError": {
+        "message": "It is not possible to trace this error, because debug log is currently not enabled. Do you want to enable debug log now, to help fix this error?"
+    },
+    "accountacctions.delete": {
+        "message": "Delete account ?##accountname##?"
+    },
+    "accountacctions.disable": {
+        "message": "Disable account ?##accountname##?"
+    },
+    "accountacctions.enable": {
+        "message": "Enable account ?##accountname##? & try to connect to server"
+    },
+    "accountacctions.sync": {
+        "message": "Synchronize account ?##accountname##?"
+    },
+    "addressbook.searchall": {
+        "message": "Search all address books"
+    },
+    "addressbook.searchgal": {
+        "message": "Search this address book and the global directory (##replace.1##)"
+    },
+    "addressbook.searchthis": {
+        "message": "Search this address book"
+    },
+    "eventlog.clear": {
+        "message": "Clear"
+    },
+    "eventlog.close": {
+        "message": "Close"
+    },
+    "eventlog.title": {
+        "message": "Event log"
+    },
+    "extensionDescription": {
+        "message": "TbSync is a central user interface to manage cloud accounts and to synchronize their contact, task and calendar information with Thunderbird."
+    },
+    "google.translate.code": {
+        "message": "en"
+    },
+    "helplink.security": {
+        "message": "https://github.com/jobisoft/TbSync/wiki/How-to-use-TbSync-with-self-signed-or-otherwise-untrusted-certificates%3F"
+    },
+    "info.error": {
+        "message": "Error"
+    },
+    "info.idle": {
+        "message": "Idle"
+    },
+    "installProvider.header": {
+        "message": "Provider ?##replace.1##? for TbSync is not yet installed."
+    },
+    "manager.AccountActions": {
+        "message": "Account actions"
+    },
+    "manager.AddAccount": {
+        "message": "Add new account"
+    },
+    "manager.DeleteAccount": {
+        "message": "Delete account"
+    },
+    "manager.DisableAccount": {
+        "message": "Disable account"
+    },
+    "manager.EnableAccount": {
+        "message": "Enable account & try to connect to server"
+    },
+    "manager.RetryConnectAccount": {
+        "message": "Try again to connect to server"
+    },
+    "manager.ShowEventLog": {
+        "message": "Open event log"
+    },
+    "manager.SyncAll": {
+        "message": "Synchronize all enabled accounts"
+    },
+    "manager.SynchronizeAccount": {
+        "message": "Synchronize account"
+    },
+    "manager.accounts": {
+        "message": "Accounts"
+    },
+    "manager.accountsettings": {
+        "message": "Account Settings"
+    },
+    "manager.catman.text": {
+        "message": "TbSync also syncs contact categories, which are a powerful replacement for the non-synchronizable contact lists. To be able to use them in the Thunderbird address book you can install the Category Manager add-on. It allows to manage overlapping category based contact groups and provides a bunch of other category-related features. It can be found in the official Mozilla add-on repository:"
+    },
+    "manager.community": {
+        "message": "Community"
+    },
+    "manager.connecting": {
+        "message": "Connecting to server"
+    },
+    "manager.help": {
+        "message": "Help"
+    },
+    "manager.help.createbugreport": {
+        "message": "Create bug report"
+    },
+    "manager.help.createbugreportinfo": {
+        "message": "In order for TbSync to collect only the debug data relevant to your bug report, please restart Thunderbird and then repeat exactly the steps that reproduce the buggy behavior. Then you can create your bug report here."
+    },
+    "manager.help.debuglevel.0": {
+        "message": "Disabled"
+    },
+    "manager.help.debuglevel.1": {
+        "message": "Enabled: Logging of errors only"
+    },
+    "manager.help.debuglevel.2": {
+        "message": "Enabled: Logging of all sent and received data"
+    },
+    "manager.help.debuglevel.3": {
+        "message": "Enabled: Logging of all data and some internal debug values"
+    },
+    "manager.help.debugmode": {
+        "message": "Debug mode:"
+    },
+    "manager.help.fixit": {
+        "message": "You can help to fix it by sending in a bug report. This requires the activation of debug mode."
+    },
+    "manager.help.foundabug": {
+        "message": "Found a bug?"
+    },
+    "manager.help.needhelp": {
+        "message": "Need Help?"
+    },
+    "manager.help.viewdebuglog": {
+        "message": "View debug log"
+    },
+    "manager.help.wiki": {
+        "message": "Open the wiki pages of the TbSync project, they provide additional information, guides and detailed configuration descriptions."
+    },
+    "manager.installprovider.link": {
+        "message": "Click on the following link to open the info page of the missing synchronization provider. There you will find further information about the provider and you will have the option to install it:"
+    },
+    "manager.installprovider.warning": {
+        "message": "This synchronization provider is not hosted in the official Thunderbird add-on repository and thus has not been reviewed by Thunderbird staff. The provider could do bad things to your system. Use it at your own risk."
+    },
+    "manager.lockedsettings.description": {
+        "message": "To prevent synchronization errors, some settings cannot be edited while the account is enabled."
+    },
+    "manager.missingprovider": {
+        "message": "This account requires the ##provider## synchronization provider, which is currently not installed."
+    },
+    "manager.noaccounts": {
+        "message": "There are not yet any accounts defined."
+    },
+    "manager.provider": {
+        "message": "Install Provider"
+    },
+    "manager.provider4tbsync": {
+        "message": "Provider for TbSync"
+    },
+    "manager.resource": {
+        "message": "Resource"
+    },
+    "manager.shorttitle": {
+        "message": "Account manager"
+    },
+    "manager.status": {
+        "message": "Status"
+    },
+    "manager.supporter.contributors": {
+        "message": "Contributors & Translators"
+    },
+    "manager.supporter.details": {
+        "message": "Details"
+    },
+    "manager.supporter.sponsors": {
+        "message": "Sponsors of test accounts"
+    },
+    "manager.tabs.status": {
+        "message": "Synchronization status"
+    },
+    "manager.tabs.status.autotime": {
+        "message": "Periodic synchronization (in minutes)"
+    },
+    "manager.tabs.status.enableThisAccount": {
+        "message": "Enable and synchronize this account"
+    },
+    "manager.tabs.status.general": {
+        "message": "General"
+    },
+    "manager.tabs.status.never": {
+        "message": "A setting of 0 disables periodic sync. Push sync is not yet implemented."
+    },
+    "manager.tabs.status.resources": {
+        "message": "Available resources"
+    },
+    "manager.tabs.status.resources.intro": {
+        "message": "Select which of the found resources should be synchronized with Thunderbird."
+    },
+    "manager.tabs.status.sync": {
+        "message": "Synchronize now"
+    },
+    "manager.tabs.status.tryagain": {
+        "message": "Try again to connect server"
+    },
+    "manager.title": {
+        "message": "TbSync account manager"
+    },
+    "manager.tryagain": {
+        "message": "Try again to connect server"
+    },
+    "menu.settingslabel": {
+        "message": "Synchronization Settings (TbSync)"
+    },
+    "password.account": {
+        "message": "Account:"
+    },
+    "password.description": {
+        "message": "Please update the credentials for the following TbSync account:"
+    },
+    "password.password": {
+        "message": "Password:"
+    },
+    "password.title": {
+        "message": "TbSync Credential Request"
+    },
+    "password.user": {
+        "message": "User:"
+    },
+    "popup.opensettings": {
+        "message": "Open TbSync account manager"
+    },
+    "prompt.DeleteAccount": {
+        "message": "Are you sure you want to delete account ##accountName##?"
+    },
+    "prompt.Disable": {
+        "message": "Are you sure you want to disable this account? All local modifications, which have not been synced yet, will be lost!"
+    },
+    "prompt.Erase": {
+        "message": "Are you sure you want to remove this account of an unknown provider from the accounts lists?"
+    },
+    "prompt.Unsubscribe": {
+        "message": "Are you sure you want to unsubscribe this item? All local modifications, which have not been synced yet, will be lost!"
+    },
+    "status.JavaScriptError": {
+        "message": "Javascript Error! Please check the event log for more details."
+    },
+    "status.OAuthAbortError": {
+        "message": "OAuth 2.0 authentication process aborted by user."
+    },
+    "status.OAuthHttpError": {
+        "message": "OAuth 2.0 authentication process failed (HTTP error ##replace.1##)."
+    },
+    "status.OAuthNetworkError": {
+        "message": "Could not connect to OAuth 2.0 authentication server."
+    },
+    "status.OAuthServerError": {
+        "message": " OAuth 2.0 authentication server returned: ##replace.1##"
+    },
+    "status.aborted": {
+        "message": "Not synchronized"
+    },
+    "status.apiError": {
+        "message": "API implementation error"
+    },
+    "status.disabled": {
+        "message": "Account is not enabled, synchronization is disabled."
+    },
+    "status.foldererror": {
+        "message": "At least one resource encountered a synchronization error. Please check the event log for more details."
+    },
+    "status.modified": {
+        "message": "Local modifications"
+    },
+    "status.network": {
+        "message": "Could not connect to server (##replace.1##)."
+    },
+    "status.no-folders-found-on-server": {
+        "message": "Could not find any resources on the server."
+    },
+    "status.notargets": {
+        "message": "Aborting synchronization, because sync targets could not be created."
+    },
+    "status.notsyncronized": {
+        "message": "Account needs to be synchronized, at least one item is out of sync."
+    },
+    "status.pending": {
+        "message": "Waiting to be synchronized"
+    },
+    "status.security": {
+        "message": "Could not establish a secure connection. Are you using a self-signed or otherwise untrusted certificate without importing it into Thunderbird? (##replace.1##)"
+    },
+    "status.skipped": {
+        "message": "Not yet supported, skipped"
+    },
+    "status.success": {
+        "message": "OK"
+    },
+    "status.syncing": {
+        "message": "Synchronizing"
+    },
+    "status.451": {
+        "message": "Server issued redirect, retry in 5 seconds."
+    },
+    "supportwizard.footer": {
+        "message": "From the information given here, an e-mail will be generated in the next step, which you can subsequently edit (for example, adding screenshots or similar). Only by actually sending that e-mail, the error report will be sent."
+    },
+    "supportwizard.label.description": {
+        "message": "Detailed error description:"
+    },
+    "supportwizard.label.faultycomponent": {
+        "message": "Component of TbSync where you have observed the error:"
+    },
+    "supportwizard.label.selectcomponent": {
+        "message": "Select component?"
+    },
+    "supportwizard.label.summary": {
+        "message": "Short summary of the error:"
+    },
+    "supportwizard.pagetitle": {
+        "message": "Gathering of all information to effectively process the bug report."
+    },
+    "supportwizard.provider": {
+        "message": "Provider: ##replace.1##"
+    },
+    "supportwizard.title": {
+        "message": "Create bug report"
+    },
+    "syncstate.accountdone": {
+        "message": "Finished account"
+    },
+    "syncstate.done": {
+        "message": "Preparing next item for synchronization"
+    },
+    "syncstate.oauthprompt": {
+        "message": "OAuth 2.0 authentication"
+    },
+    "syncstate.passwordprompt": {
+        "message": "Prompting for credentials"
+    },
+    "syncstate.preparing": {
+        "message": "Preparing next item for synchronization"
+    },
+    "syncstate.syncing": {
+        "message": "Initialize synchronization"
+    },
+    "target.orphaned": {
+        "message": "Disconnected"
+    },
+    "toolbar.label": {
+        "message": "Synchronize all TbSync accounts"
+    },
+    "toolbar.tooltiptext": {
+        "message": "Synchronize latest changes"
+    },
+    "password.ok": {
+        "message": "OK"
+    },
+    "password.cancel": {
+        "message": "Avbryt"
+    }
+}
diff -Nru tbsync-4.12/Makebeta tbsync-4.16/Makebeta
--- tbsync-4.12/Makebeta	2024-08-27 18:32:08.000000000 +0200
+++ tbsync-4.16/Makebeta	1970-01-01 01:00:00.000000000 +0100
@@ -1,37 +0,0 @@
-#!/bin/bash
-# This file is part of TbSync.
-#
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-# $1 link to base web server       : https://tbsync.jobisoft.de/beta
-# $2 local path of base web server : /var/www/jobisoft.de/tbsync/beta
-# $3 name of XPI                   : TbSync.xpi
-
-git clean -df
-git checkout -- .
-git pull
-
-version=$(cat manifest.json | jq -r .version)
-updatefile=update-tbsync.json
-
-sed -i "s/%VERSION%/$version/g" "beta-release-channel-update.json"
-sed -i "s|%LINK%|$1/$3|g" "beta-release-channel-update.json"
-sed -i "s/apiVersion: \"/apiVersion: \"Beta /g" "content/tbsync.jsm"
-sed -i "s|https://addons.thunderbird.net/addon/dav-4-tbsync/|$1/DAV-4-TbSync.xpi|g" "content/modules/providers.js"
-sed -i "s|https://addons.thunderbird.net/addon/eas-4-tbsync/|$1/EAS-4-TbSync.xpi|g" "content/modules/providers.js"
-
-
-echo "Releasing version $version via beta release channel (will include updateURL)"
-sed -i "s|\"name\": \"TbSync\",|\"name\": \"TbSync [Beta Release Channel]\",|g" "manifest.json"
-sed -i "s|\"gecko\": {|\"gecko\": {\n  \"update_url\": \"$1/$updatefile\",|g" "manifest.json"
-
-cp beta-release-channel-update.json $2/$updatefile
-
-rm -f $3
-rm -f $3.tar.gz
-zip -r $3 content _locales manifest.json background.js LICENSE CONTRIBUTORS.md
-tar cfvz $3.tar.gz content _locales manifest.json background.js LICENSE CONTRIBUTORS.md
-cp $3 $2/$3
-cp $3.tar.gz $2/$3.tar.gz
diff -Nru tbsync-4.12/Makefile.bat tbsync-4.16/Makefile.bat
--- tbsync-4.12/Makefile.bat	2024-08-27 18:32:08.000000000 +0200
+++ tbsync-4.16/Makefile.bat	1970-01-01 01:00:00.000000000 +0100
@@ -1,19 +0,0 @@
- at echo off
-REM  This file is part of TbSync.
-REM 
-REM This Source Code Form is subject to the terms of the Mozilla Public
-REM License, v. 2.0. If a copy of the MPL was not distributed with this
-REM file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-del TbSync-beta.xpi
-"C:\Program Files\7-Zip\7zG.exe" a -tzip TbSync-beta.xpi content _locales manifest.json LICENSE README.md background.js CONTRIBUTORS.md
-
-
-REM Copy sources to doc repository
-REM rd /s /q ..\Provider-4-TbSync\docs\sources 
-REM mkdir ..\Provider-4-TbSync\docs\sources 
-
-REM copy content\OverlayManager.jsm ..\Provider-4-TbSync\docs\sources\
-
-REM Xcopy /E /I content\passwordPrompt ..\Provider-4-TbSync\docs\sources\passwordPrompt\
-REM Xcopy /E /I content\modules ..\Provider-4-TbSync\docs\sources\modules\
diff -Nru tbsync-4.12/manifest.json tbsync-4.16/manifest.json
--- tbsync-4.12/manifest.json	2024-08-27 18:32:08.000000000 +0200
+++ tbsync-4.16/manifest.json	2025-07-28 19:34:08.000000000 +0200
@@ -1,45 +1,54 @@
-{
-  "applications": {
-    "gecko": {
-      "id": "tbsync at jobisoft.de",
-      "strict_min_version": "128.0",
-      "strict_max_version": "128.*"
-    }
-  },
-  "manifest_version": 2,
-  "name": "TbSync",
-  "version": "4.12",
-  "author": "John Bieling",
-  "homepage_url": "https://github.com/jobisoft/TbSync",
-  "default_locale": "en-US",
-  "description": "__MSG_extensionDescription__",
-  "icons": {
-    "32": "content/skin/tbsync.png"
-  },
-  "browser_action": {
-    "default_title": "TbSync",
-    "default_label": "",
-    "default_icon": {
-      "32": "content/skin/tbsync.png"
-    },
-    "allowed_spaces": [
-      "mail",
-      "calendar",
-      "addressbook",
-      "tasks"
-    ]
-  }, 
-  "background": {
-    "scripts": ["background.js"]
-  },
-  "experiment_apis": {
-    "BootstrapLoader": {
-      "schema": "content/api/BootstrapLoader/schema.json",
-      "parent": {
-        "scopes": ["addon_parent"],
-        "paths": [["BootstrapLoader"]],
-        "script": "content/api/BootstrapLoader/implementation.js"
-      }
-    }
-  }
-}
+{
+  "applications": {
+    "gecko": {
+      "id": "tbsync at jobisoft.de",
+      "strict_min_version": "136.0",
+      "strict_max_version": "140.*"
+    }
+  },
+  "manifest_version": 2,
+  "name": "TbSync",
+  "version": "4.16",
+  "author": "John Bieling",
+  "homepage_url": "https://github.com/jobisoft/TbSync",
+  "default_locale": "en-US",
+  "description": "__MSG_extensionDescription__",
+  "icons": {
+    "32": "content/skin/tbsync.png"
+  },
+  "browser_action": {
+    "default_title": "TbSync",
+    "default_label": "",
+    "default_icon": {
+      "32": "content/skin/tbsync.png"
+    },
+    "allowed_spaces": [
+      "mail",
+      "calendar",
+      "addressbook",
+      "tasks"
+    ]
+  }, 
+  "background": {
+    "type": "module",
+    "scripts": ["background.js"]
+  },
+  "experiment_apis": {
+    "LegacyHelper": {
+      "schema": "api/LegacyHelper/schema.json",
+      "parent": {
+        "scopes": ["addon_parent"],
+        "paths": [["LegacyHelper"]],
+        "script": "api/LegacyHelper/implementation.js"
+      }
+    },
+    "TbSync": {
+      "schema": "api/TbSync/schema.json",
+      "parent": {
+        "scopes": ["addon_parent"],
+        "paths": [["TbSync"]],
+        "script": "api/TbSync/implementation.js"
+      }
+    }
+  }
+}
diff -Nru tbsync-4.12/README.md tbsync-4.16/README.md
--- tbsync-4.12/README.md	2024-08-27 18:32:08.000000000 +0200
+++ tbsync-4.16/README.md	2025-03-15 17:20:52.000000000 +0100
@@ -1,44 +1,44 @@
-# TbSync
-
-[TbSync](https://addons.thunderbird.net/addon/tbsync/) was a central user interface to manage cloud accounts and to synchronize their contact, task and calendar information with [Thunderbird](https://www.thunderbird.net/). Its main objective was to simplify the setup process for such accounts. Thunderbird is working on a new account-hub UI, which will make TbSync obsolete.
-
-## Icon sources and attributions
-
-#### WTFPL
-* [spinner.gif] by [Yannick Croissant](http://www.ajaxload.info/)
-
-#### CC0-1.0
-* [add16.png] by [Jean Victor Balin](https://openclipart.org/detail/16950/add)
-* [del16.png] by [Jean Victor Balin](https://openclipart.org/detail/16982/cross)
-* [tick16.png] by [Jean Victor Balin](https://openclipart.org/detail/17056/tick)
-* [sync16.png] by [Willleam](https://openclipart.org/detail/287463/circular-arrow-blue)
-* [slider-on.png] by [John Bieling](https://github.com/jobisoft/TbSync/blob/master/content/skin/src/LICENSE)
-* [slider-off.png] by [John Bieling](https://github.com/jobisoft/TbSync/blob/master/content/skin/src/LICENSE)
-
-#### CC-BY 3.0
-* [contacts16.png] by [Yusuke Kamiyamane](https://www.iconfinder.com/icons/25910/)
-* [todo16.png] by [Yusuke Kamiyamane](https://www.iconfinder.com/icons/45913/)
-* [error16.png] by [Yusuke Kamiyamane](https://www.iconfinder.com/icons/46013/exclamation_frame_icon)
-* [connect16.png] by [Yusuke Kamiyamane](https://www.iconfinder.com/icons/58341/connect_plug_icon)
-* [info16.png] by [FatCow Web Hosting](https://www.iconfinder.com/icons/64363/info_rhombus_icon)
-* [warning16.png] by [FatCow Web Hosting](https://www.iconfinder.com/icons/36026/)
-* [calendar16.png] by [FatCow Web Hosting](https://www.iconfinder.com/icons/35805/)
-* [calendar/contacts16_shared.png] by [FatCow Web Hosting](https://www.iconfinder.com/icons/64490/network_share_icon)
-* [trash16.png] by [FatCow Web Hosting](https://www.iconfinder.com/icons/35727/bin_empty_metal_icon)
-* [acl_rw.png] by [FatCow Web Hosting](https://www.iconfinder.com/icons/36322/pencil_icon)
-* [acl_ro.png] by [FatCow Web Hosting](https://www.iconfinder.com/icons/36324/delete_pencil_icon)
-* [provider16.png] by [FatCow Web Hosting](https://www.iconfinder.com/icons/64634)
-* [report_send.png] based on work by FatCow Web Hosting [#1](https://www.iconfinder.com/icons/36365/) and [#2](https://www.iconfinder.com/icons/93180)
-* [report_open.png] by [FatCow Web Hosting](https://www.iconfinder.com/icons/36373)
-* [lock24.png] by [Paomedia](https://www.iconfinder.com/icons/285646/lock_icon)
-* [tbsync.png] by [Paomedia](https://www.iconfinder.com/icons/299097)
-* [settings32.png] by [Paomedia](https://www.iconfinder.com/icons/299098/cogs_icon)
-* [update32.png] by [Google](https://www.iconfinder.com/icons/352158/)
-* [group32.png] by [Dumitriu Robert](https://www.iconfinder.com/icons/3289557/clan_group_partners_peers_people_icon)
-* [catman32.png] based on 'Venn Diagram' by [WARPAINT Media Inc., CA](https://thenounproject.com/search/?q=three%20circles&i=31898#) from Noun Project ([info](https://github.com/jobisoft/CategoryManager/tree/master/sendtocategory/skin/catman))
-
-#### Apache Software License 2.0
-* [disabled16.png] by [Google](https://github.com/google/material-design-icons/blob/master/notification/1x_web/ic_do_not_disturb_alt_black_18dp.png)
-
-#### GPL
-* [help32.png] by [WooThemes](https://www.iconfinder.com/icons/58495/button_help_white_icon)
+# TbSync
+
+[TbSync](https://addons.thunderbird.net/addon/tbsync/) is a central user interface to manage cloud accounts and to synchronize their contact, task and calendar information with [Thunderbird](https://www.thunderbird.net/). Its main objective is to simplify the setup process for such accounts. Thunderbird is working on a new account-hub UI, which will make TbSync obsolete.
+
+## Icon sources and attributions
+
+#### WTFPL
+* [spinner.gif] by [Yannick Croissant](http://www.ajaxload.info/)
+
+#### CC0-1.0
+* [add16.png] by [Jean Victor Balin](https://openclipart.org/detail/16950/add)
+* [del16.png] by [Jean Victor Balin](https://openclipart.org/detail/16982/cross)
+* [tick16.png] by [Jean Victor Balin](https://openclipart.org/detail/17056/tick)
+* [sync16.png] by [Willleam](https://openclipart.org/detail/287463/circular-arrow-blue)
+* [slider-on.png] by [John Bieling](https://github.com/jobisoft/TbSync/blob/master/content/skin/src/LICENSE)
+* [slider-off.png] by [John Bieling](https://github.com/jobisoft/TbSync/blob/master/content/skin/src/LICENSE)
+
+#### CC-BY 3.0
+* [contacts16.png] by [Yusuke Kamiyamane](https://www.iconfinder.com/icons/25910/)
+* [todo16.png] by [Yusuke Kamiyamane](https://www.iconfinder.com/icons/45913/)
+* [error16.png] by [Yusuke Kamiyamane](https://www.iconfinder.com/icons/46013/exclamation_frame_icon)
+* [connect16.png] by [Yusuke Kamiyamane](https://www.iconfinder.com/icons/58341/connect_plug_icon)
+* [info16.png] by [FatCow Web Hosting](https://www.iconfinder.com/icons/64363/info_rhombus_icon)
+* [warning16.png] by [FatCow Web Hosting](https://www.iconfinder.com/icons/36026/)
+* [calendar16.png] by [FatCow Web Hosting](https://www.iconfinder.com/icons/35805/)
+* [calendar/contacts16_shared.png] by [FatCow Web Hosting](https://www.iconfinder.com/icons/64490/network_share_icon)
+* [trash16.png] by [FatCow Web Hosting](https://www.iconfinder.com/icons/35727/bin_empty_metal_icon)
+* [acl_rw.png] by [FatCow Web Hosting](https://www.iconfinder.com/icons/36322/pencil_icon)
+* [acl_ro.png] by [FatCow Web Hosting](https://www.iconfinder.com/icons/36324/delete_pencil_icon)
+* [provider16.png] by [FatCow Web Hosting](https://www.iconfinder.com/icons/64634)
+* [report_send.png] based on work by FatCow Web Hosting [#1](https://www.iconfinder.com/icons/36365/) and [#2](https://www.iconfinder.com/icons/93180)
+* [report_open.png] by [FatCow Web Hosting](https://www.iconfinder.com/icons/36373)
+* [lock24.png] by [Paomedia](https://www.iconfinder.com/icons/285646/lock_icon)
+* [tbsync.png] by [Paomedia](https://www.iconfinder.com/icons/299097)
+* [settings32.png] by [Paomedia](https://www.iconfinder.com/icons/299098/cogs_icon)
+* [update32.png] by [Google](https://www.iconfinder.com/icons/352158/)
+* [group32.png] by [Dumitriu Robert](https://www.iconfinder.com/icons/3289557/clan_group_partners_peers_people_icon)
+* [catman32.png] based on 'Venn Diagram' by [WARPAINT Media Inc., CA](https://thenounproject.com/search/?q=three%20circles&i=31898#) from Noun Project ([info](https://github.com/jobisoft/CategoryManager/tree/master/sendtocategory/skin/catman))
+
+#### Apache Software License 2.0
+* [disabled16.png] by [Google](https://github.com/google/material-design-icons/blob/master/notification/1x_web/ic_do_not_disturb_alt_black_18dp.png)
+
+#### GPL
+* [help32.png] by [WooThemes](https://www.iconfinder.com/icons/58495/button_help_white_icon)
Bin?rdateien /tmp/jcTTWHCE8O/tbsync-4.12/screenshots/AdvancedConfig.png und /tmp/oCHOIKSGhA/tbsync-4.16/screenshots/AdvancedConfig.png sind verschieden.
Bin?rdateien /tmp/jcTTWHCE8O/tbsync-4.12/screenshots/beta-release-channel.PNG und /tmp/oCHOIKSGhA/tbsync-4.16/screenshots/beta-release-channel.PNG sind verschieden.
Bin?rdateien /tmp/jcTTWHCE8O/tbsync-4.12/screenshots/CalDAV-UserName.png und /tmp/oCHOIKSGhA/tbsync-4.16/screenshots/CalDAV-UserName.png sind verschieden.
Bin?rdateien /tmp/jcTTWHCE8O/tbsync-4.12/screenshots/custom_provider.PNG und /tmp/oCHOIKSGhA/tbsync-4.16/screenshots/custom_provider.PNG sind verschieden.
Bin?rdateien /tmp/jcTTWHCE8O/tbsync-4.12/screenshots/de/acl_sharing.png und /tmp/oCHOIKSGhA/tbsync-4.16/screenshots/de/acl_sharing.png sind verschieden.
Bin?rdateien /tmp/jcTTWHCE8O/tbsync-4.12/screenshots/de/add_dav_1.png und /tmp/oCHOIKSGhA/tbsync-4.16/screenshots/de/add_dav_1.png sind verschieden.
Bin?rdateien /tmp/jcTTWHCE8O/tbsync-4.12/screenshots/de/add_dav_2.png und /tmp/oCHOIKSGhA/tbsync-4.16/screenshots/de/add_dav_2.png sind verschieden.
Bin?rdateien /tmp/jcTTWHCE8O/tbsync-4.12/screenshots/de/add_eas_1.png und /tmp/oCHOIKSGhA/tbsync-4.16/screenshots/de/add_eas_1.png sind verschieden.
Bin?rdateien /tmp/jcTTWHCE8O/tbsync-4.12/screenshots/de/add_eas_2.png und /tmp/oCHOIKSGhA/tbsync-4.16/screenshots/de/add_eas_2.png sind verschieden.
Bin?rdateien /tmp/jcTTWHCE8O/tbsync-4.12/screenshots/de/custom.png und /tmp/oCHOIKSGhA/tbsync-4.16/screenshots/de/custom.png sind verschieden.
Bin?rdateien /tmp/jcTTWHCE8O/tbsync-4.12/screenshots/de/eas_done.png und /tmp/oCHOIKSGhA/tbsync-4.16/screenshots/de/eas_done.png sind verschieden.
Bin?rdateien /tmp/jcTTWHCE8O/tbsync-4.12/screenshots/de/emails.PNG und /tmp/oCHOIKSGhA/tbsync-4.16/screenshots/de/emails.PNG sind verschieden.
Bin?rdateien /tmp/jcTTWHCE8O/tbsync-4.12/screenshots/de/TbSync.PNG und /tmp/oCHOIKSGhA/tbsync-4.16/screenshots/de/TbSync.PNG sind verschieden.
Bin?rdateien /tmp/jcTTWHCE8O/tbsync-4.12/screenshots/ExportImport_001.PNG und /tmp/oCHOIKSGhA/tbsync-4.16/screenshots/ExportImport_001.PNG sind verschieden.
Bin?rdateien /tmp/jcTTWHCE8O/tbsync-4.12/screenshots/ExportImport_002.PNG und /tmp/oCHOIKSGhA/tbsync-4.16/screenshots/ExportImport_002.PNG sind verschieden.
Bin?rdateien /tmp/jcTTWHCE8O/tbsync-4.12/screenshots/ExportImport_005.PNG und /tmp/oCHOIKSGhA/tbsync-4.16/screenshots/ExportImport_005.PNG sind verschieden.
Bin?rdateien /tmp/jcTTWHCE8O/tbsync-4.12/screenshots/install-from-file.PNG und /tmp/oCHOIKSGhA/tbsync-4.16/screenshots/install-from-file.PNG sind verschieden.
Bin?rdateien /tmp/jcTTWHCE8O/tbsync-4.12/screenshots/missing_provider.PNG und /tmp/oCHOIKSGhA/tbsync-4.16/screenshots/missing_provider.PNG sind verschieden.
Bin?rdateien /tmp/jcTTWHCE8O/tbsync-4.12/screenshots/TbSync_000b.png und /tmp/oCHOIKSGhA/tbsync-4.16/screenshots/TbSync_000b.png sind verschieden.
Bin?rdateien /tmp/jcTTWHCE8O/tbsync-4.12/screenshots/TbSync_000.png und /tmp/oCHOIKSGhA/tbsync-4.16/screenshots/TbSync_000.png sind verschieden.
Bin?rdateien /tmp/jcTTWHCE8O/tbsync-4.12/screenshots/TbSync_001.png und /tmp/oCHOIKSGhA/tbsync-4.16/screenshots/TbSync_001.png sind verschieden.
Bin?rdateien /tmp/jcTTWHCE8O/tbsync-4.12/screenshots/TbSync_004.png und /tmp/oCHOIKSGhA/tbsync-4.16/screenshots/TbSync_004.png sind verschieden.
Bin?rdateien /tmp/jcTTWHCE8O/tbsync-4.12/screenshots/TbSync_005.png und /tmp/oCHOIKSGhA/tbsync-4.16/screenshots/TbSync_005.png sind verschieden.
Bin?rdateien /tmp/jcTTWHCE8O/tbsync-4.12/screenshots/TbSync_Enable_debug_logging.png und /tmp/oCHOIKSGhA/tbsync-4.16/screenshots/TbSync_Enable_debug_logging.png sind verschieden.
Bin?rdateien /tmp/jcTTWHCE8O/tbsync-4.12/screenshots/TbSync_Send_logs_by_mail.png und /tmp/oCHOIKSGhA/tbsync-4.16/screenshots/TbSync_Send_logs_by_mail.png sind verschieden.
Bin?rdateien /tmp/jcTTWHCE8O/tbsync-4.12/screenshots/update-addon.PNG und /tmp/oCHOIKSGhA/tbsync-4.16/screenshots/update-addon.PNG sind verschieden.
Bin?rdateien /tmp/jcTTWHCE8O/tbsync-4.12/screenshots/update_notification_statusbar.png und /tmp/oCHOIKSGhA/tbsync-4.16/screenshots/update_notification_statusbar.png sind verschieden.
diff -Nru tbsync-4.12/UPDATE68.md tbsync-4.16/UPDATE68.md
--- tbsync-4.12/UPDATE68.md	2024-08-27 18:32:08.000000000 +0200
+++ tbsync-4.16/UPDATE68.md	1970-01-01 01:00:00.000000000 +0100
@@ -1,24 +0,0 @@
-# Update instructions for Thunderbird 68
-
-TbSync has been mostly rewritten for Thunderbird 68 (the next major release being due in a few weeks). To ensure a seamless transition from Thunderbird 60 to Thunderbird 68, I recommend to do the following **before** upgrading to Thunderbird 68:
-
-* synchronize all your TbSync accounts
-* disable all your TbSync accounts
-
-After the upgrade to Thunderbird 68 has completed, your TbSync accounts can be enabled again.
-
-## How to disable TbSync accounts
-
-Each TbSync account can be disabled by unchecking the box shown in the following image:
-
-![](https://user-images.githubusercontent.com/5830621/63053657-9a2c6d80-bee2-11e9-9019-7035830a873b.png)]
-
-## Why is this necessary ?
-
-It could happen, that after the upgrade your synchronized address books and calendars still exists in Thunderbird and can be used as before, but are no longer connected to your servers. If you make local changes, they will never make it to your servers. So these changes will be lost.
-
-That is why I ask to disable all accounts during the upgrade from Thunderbird 60 to Thunderbird 68. After re-enabling your accounts in Thunderbird 68, they will start a clean sync which ensures a proper connection between Thunderbird and your servers.
-
-## System-specific tips
-
-On Arch Linux and derivatives, you can add a `pacman` hook [like this one](https://gist.github.com/MayeulC/400adbfba72effc29fca4d8666fc4571) to print a reminder and cancel the thunderbird upgrade when it becomes available.


More information about the Pkg-mozext-maintainers mailing list